diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/designware_i2c.c | 18 | ||||
-rw-r--r-- | drivers/i2c/designware_i2c.h | 9 | ||||
-rw-r--r-- | drivers/i2c/i2c-gpio.c | 170 | ||||
-rw-r--r-- | drivers/i2c/i2c-uclass.c | 44 | ||||
-rw-r--r-- | drivers/i2c/stm32f7_i2c.c | 105 |
5 files changed, 213 insertions, 133 deletions
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 0b5e70af59..088a6f3efb 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -203,14 +203,16 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk, const struct dw_scl_sda_cfg *scl_sda_cfg = NULL; struct i2c_regs *regs = priv->regs; enum i2c_speed_mode i2c_spd; + u32 comp_param1; int spk_cnt; int ret; + comp_param1 = readl(®s->comp_param1); + if (priv) scl_sda_cfg = priv->scl_sda_cfg; /* Allow high speed if there is no config, or the config allows it */ - if (speed >= I2C_SPEED_HIGH_RATE && - (!scl_sda_cfg || scl_sda_cfg->has_high_speed)) + if (speed >= I2C_SPEED_HIGH_RATE) i2c_spd = IC_SPEED_MODE_HIGH; else if (speed >= I2C_SPEED_FAST_PLUS_RATE) i2c_spd = IC_SPEED_MODE_FAST_PLUS; @@ -219,6 +221,13 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk, else i2c_spd = IC_SPEED_MODE_STANDARD; + /* Check is high speed possible and fall back to fast mode if not */ + if (i2c_spd == IC_SPEED_MODE_HIGH) { + if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) + != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) + i2c_spd = IC_SPEED_MODE_FAST; + } + /* Get the proper spike-suppression count based on target speed */ if (!priv || !priv->has_spk_cnt) spk_cnt = 0; @@ -231,6 +240,9 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk, if (i2c_spd == IC_SPEED_MODE_STANDARD) { config->scl_hcnt = scl_sda_cfg->ss_hcnt; config->scl_lcnt = scl_sda_cfg->ss_lcnt; + } else if (i2c_spd == IC_SPEED_MODE_HIGH) { + config->scl_hcnt = scl_sda_cfg->hs_hcnt; + config->scl_lcnt = scl_sda_cfg->hs_lcnt; } else { config->scl_hcnt = scl_sda_cfg->fs_hcnt; config->scl_lcnt = scl_sda_cfg->fs_lcnt; @@ -274,7 +286,7 @@ static int _dw_i2c_set_bus_speed(struct dw_i2c *priv, struct i2c_regs *i2c_base, switch (config.speed_mode) { case IC_SPEED_MODE_HIGH: - cntl |= IC_CON_SPD_SS; + cntl |= IC_CON_SPD_HS; writel(config.scl_hcnt, &i2c_base->ic_hs_scl_hcnt); writel(config.scl_lcnt, &i2c_base->ic_hs_scl_lcnt); break; diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h index 61a882cb65..7ee236193d 100644 --- a/drivers/i2c/designware_i2c.h +++ b/drivers/i2c/designware_i2c.h @@ -138,22 +138,27 @@ struct i2c_regs { #define IC_STATUS_TFNF 0x0002 #define IC_STATUS_ACT 0x0001 +#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) +#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK (BIT(2) | BIT(3)) + /** * struct dw_scl_sda_cfg - I2C timing configuration * - * @has_high_speed: Support high speed (3.4Mbps) * @ss_hcnt: Standard speed high time in ns * @fs_hcnt: Fast speed high time in ns + * @hs_hcnt: High speed high time in ns * @ss_lcnt: Standard speed low time in ns * @fs_lcnt: Fast speed low time in ns + * @hs_lcnt: High speed low time in ns * @sda_hold: SDA hold time */ struct dw_scl_sda_cfg { - bool has_high_speed; u32 ss_hcnt; u32 fs_hcnt; + u32 hs_hcnt; u32 ss_lcnt; u32 fs_lcnt; + u32 hs_lcnt; u32 sda_hold; }; diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c index 4e8fa21473..07fdd343f2 100644 --- a/drivers/i2c/i2c-gpio.c +++ b/drivers/i2c/i2c-gpio.c @@ -32,23 +32,50 @@ struct i2c_gpio_bus { int udelay; /* sda, scl */ struct gpio_desc gpios[PIN_COUNT]; + + int (*get_sda)(struct i2c_gpio_bus *bus); + void (*set_sda)(struct i2c_gpio_bus *bus, int bit); + void (*set_scl)(struct i2c_gpio_bus *bus, int bit); }; -static int i2c_gpio_sda_get(struct gpio_desc *sda) +static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus) { + struct gpio_desc *sda = &bus->gpios[PIN_SDA]; + return dm_gpio_get_value(sda); } -static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit) +static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit) { + struct gpio_desc *sda = &bus->gpios[PIN_SDA]; + if (bit) dm_gpio_set_dir_flags(sda, GPIOD_IS_IN); else dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT); } -static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit) +static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit) { + struct gpio_desc *scl = &bus->gpios[PIN_SCL]; + int count = 0; + + if (bit) { + dm_gpio_set_dir_flags(scl, GPIOD_IS_IN); + while (!dm_gpio_get_value(scl) && count++ < 100000) + udelay(1); + + if (!dm_gpio_get_value(scl)) + pr_err("timeout waiting on slave to release scl\n"); + } else { + dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT); + } +} + +/* variant for output only gpios which cannot support clock stretching */ +static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit) +{ + struct gpio_desc *scl = &bus->gpios[PIN_SCL]; ulong flags = GPIOD_IS_OUT; if (bit) @@ -56,65 +83,60 @@ static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit) dm_gpio_set_dir_flags(scl, flags); } -static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda, - int delay, uchar bit) +static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit) { - i2c_gpio_scl_set(scl, 0); + bus->set_scl(bus, 0); udelay(delay); - i2c_gpio_sda_set(sda, bit); + bus->set_sda(bus, bit); udelay(delay); - i2c_gpio_scl_set(scl, 1); + bus->set_scl(bus, 1); udelay(2 * delay); } -static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda, - int delay) +static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay) { int value; - i2c_gpio_scl_set(scl, 1); + bus->set_scl(bus, 1); udelay(delay); - value = i2c_gpio_sda_get(sda); + value = bus->get_sda(bus); udelay(delay); - i2c_gpio_scl_set(scl, 0); + bus->set_scl(bus, 0); udelay(2 * delay); return value; } /* START: High -> Low on SDA while SCL is High */ -static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda, - int delay) +static void i2c_gpio_send_start(struct i2c_gpio_bus *bus, int delay) { udelay(delay); - i2c_gpio_sda_set(sda, 1); + bus->set_sda(bus, 1); udelay(delay); - i2c_gpio_scl_set(scl, 1); + bus->set_scl(bus, 1); udelay(delay); - i2c_gpio_sda_set(sda, 0); + bus->set_sda(bus, 0); udelay(delay); } /* STOP: Low -> High on SDA while SCL is High */ -static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda, - int delay) +static void i2c_gpio_send_stop(struct i2c_gpio_bus *bus, int delay) { - i2c_gpio_scl_set(scl, 0); + bus->set_scl(bus, 0); udelay(delay); - i2c_gpio_sda_set(sda, 0); + bus->set_sda(bus, 0); udelay(delay); - i2c_gpio_scl_set(scl, 1); + bus->set_scl(bus, 1); udelay(delay); - i2c_gpio_sda_set(sda, 1); + bus->set_sda(bus, 1); udelay(delay); } /* ack should be I2C_ACK or I2C_NOACK */ -static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda, - int delay, int ack) +static void i2c_gpio_send_ack(struct i2c_gpio_bus *bus, int delay, int ack) { - i2c_gpio_write_bit(scl, sda, delay, ack); - i2c_gpio_scl_set(scl, 0); + i2c_gpio_write_bit(bus, delay, ack); + bus->set_scl(bus, 0); udelay(delay); } @@ -123,44 +145,41 @@ static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda, * to clock any confused device back into an idle state. Also send a * <stop> at the end of the sequence for belts & suspenders. */ -static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda, - int delay) +static void i2c_gpio_send_reset(struct i2c_gpio_bus *bus, int delay) { int j; for (j = 0; j < 9; j++) - i2c_gpio_write_bit(scl, sda, delay, 1); + i2c_gpio_write_bit(bus, delay, 1); - i2c_gpio_send_stop(scl, sda, delay); + i2c_gpio_send_stop(bus, delay); } /* Set sda high with low clock, before reading slave data */ -static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda, - int delay) +static void i2c_gpio_sda_high(struct i2c_gpio_bus *bus, int delay) { - i2c_gpio_scl_set(scl, 0); + bus->set_scl(bus, 0); udelay(delay); - i2c_gpio_sda_set(sda, 1); + bus->set_sda(bus, 1); udelay(delay); } /* Send 8 bits and look for an acknowledgement */ -static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda, - int delay, uchar data) +static int i2c_gpio_write_byte(struct i2c_gpio_bus *bus, int delay, uchar data) { int j; int nack; for (j = 0; j < 8; j++) { - i2c_gpio_write_bit(scl, sda, delay, data & 0x80); + i2c_gpio_write_bit(bus, delay, data & 0x80); data <<= 1; } udelay(delay); /* Look for an <ACK>(negative logic) and return it */ - i2c_gpio_sda_high(scl, sda, delay); - nack = i2c_gpio_read_bit(scl, sda, delay); + i2c_gpio_sda_high(bus, delay); + nack = i2c_gpio_read_bit(bus, delay); return nack; /* not a nack is an ack */ } @@ -169,31 +188,29 @@ static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda, * if ack == I2C_ACK, ACK the byte so can continue reading, else * send I2C_NOACK to end the read. */ -static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda, - int delay, int ack) +static uchar i2c_gpio_read_byte(struct i2c_gpio_bus *bus, int delay, int ack) { int data; int j; - i2c_gpio_sda_high(scl, sda, delay); + i2c_gpio_sda_high(bus, delay); data = 0; for (j = 0; j < 8; j++) { data <<= 1; - data |= i2c_gpio_read_bit(scl, sda, delay); + data |= i2c_gpio_read_bit(bus, delay); } - i2c_gpio_send_ack(scl, sda, delay, ack); + i2c_gpio_send_ack(bus, delay, ack); return data; } /* send start and the slave chip address */ -int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay, - uchar chip) +int i2c_send_slave_addr(struct i2c_gpio_bus *bus, int delay, uchar chip) { - i2c_gpio_send_start(scl, sda, delay); + i2c_gpio_send_start(bus, delay); - if (i2c_gpio_write_byte(scl, sda, delay, chip)) { - i2c_gpio_send_stop(scl, sda, delay); + if (i2c_gpio_write_byte(bus, delay, chip)) { + i2c_gpio_send_stop(bus, delay); return -EIO; } @@ -204,29 +221,27 @@ static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip, uchar *buffer, int len, bool end_with_repeated_start) { - struct gpio_desc *scl = &bus->gpios[PIN_SCL]; - struct gpio_desc *sda = &bus->gpios[PIN_SDA]; unsigned int delay = bus->udelay; int failures = 0; debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len); - if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) { + if (i2c_send_slave_addr(bus, delay, chip << 1)) { debug("i2c_write, no chip responded %02X\n", chip); return -EIO; } while (len-- > 0) { - if (i2c_gpio_write_byte(scl, sda, delay, *buffer++)) + if (i2c_gpio_write_byte(bus, delay, *buffer++)) failures++; } if (!end_with_repeated_start) { - i2c_gpio_send_stop(scl, sda, delay); + i2c_gpio_send_stop(bus, delay); return failures; } - if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) { + if (i2c_send_slave_addr(bus, delay, (chip << 1) | 0x1)) { debug("i2c_write, no chip responded %02X\n", chip); return -EIO; } @@ -237,16 +252,14 @@ static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip, static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip, uchar *buffer, int len) { - struct gpio_desc *scl = &bus->gpios[PIN_SCL]; - struct gpio_desc *sda = &bus->gpios[PIN_SDA]; unsigned int delay = bus->udelay; debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len); while (len-- > 0) - *buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0); + *buffer++ = i2c_gpio_read_byte(bus, delay, len == 0); - i2c_gpio_send_stop(scl, sda, delay); + i2c_gpio_send_stop(bus, delay); return 0; } @@ -277,14 +290,12 @@ static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags) { struct i2c_gpio_bus *bus = dev_get_priv(dev); - struct gpio_desc *scl = &bus->gpios[PIN_SCL]; - struct gpio_desc *sda = &bus->gpios[PIN_SDA]; unsigned int delay = bus->udelay; int ret; - i2c_gpio_send_start(scl, sda, delay); - ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0); - i2c_gpio_send_stop(scl, sda, delay); + i2c_gpio_send_start(bus, delay); + ret = i2c_gpio_write_byte(bus, delay, (chip << 1) | 0); + i2c_gpio_send_stop(bus, delay); debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n", __func__, dev->seq, dev->name, chip, chip_flags, ret); @@ -295,12 +306,25 @@ static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags) static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz) { struct i2c_gpio_bus *bus = dev_get_priv(dev); - struct gpio_desc *scl = &bus->gpios[PIN_SCL]; - struct gpio_desc *sda = &bus->gpios[PIN_SDA]; bus->udelay = 1000000 / (speed_hz << 2); - i2c_gpio_send_reset(scl, sda, bus->udelay); + i2c_gpio_send_reset(bus, bus->udelay); + + return 0; +} + +static int i2c_gpio_drv_probe(struct udevice *dev) +{ + if (dev_read_bool(dev, "i2c-gpio,deblock")) { + /* @200kHz 9 clocks = 44us, 62us is ok */ + const unsigned int DELAY_ABORT_SEQ = 62; + struct i2c_gpio_bus *bus = dev_get_priv(dev); + + return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA], + &bus->gpios[PIN_SCL], + 16, 5, DELAY_ABORT_SEQ); + } return 0; } @@ -320,6 +344,13 @@ static int i2c_gpio_ofdata_to_platdata(struct udevice *dev) bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us", DEFAULT_UDELAY); + bus->get_sda = i2c_gpio_sda_get; + bus->set_sda = i2c_gpio_sda_set; + if (fdtdec_get_bool(blob, node, "i2c-gpio,scl-output-only")) + bus->set_scl = i2c_gpio_scl_set_output_only; + else + bus->set_scl = i2c_gpio_scl_set; + return 0; error: pr_err("Can't get %s gpios! Error: %d", dev->name, ret); @@ -341,6 +372,7 @@ U_BOOT_DRIVER(i2c_gpio) = { .name = "i2c-gpio", .id = UCLASS_I2C, .of_match = i2c_gpio_ids, + .probe = i2c_gpio_drv_probe, .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus), .ops = &i2c_gpio_ops, diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 2aa3efe8aa..e9ec388576 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -501,35 +501,53 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin) return dm_gpio_get_value(pin); } -static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, - struct gpio_desc *scl_pin) +int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin, + struct gpio_desc *scl_pin, + unsigned int scl_count, + unsigned int start_count, + unsigned int delay) { - int counter = 9; - int ret = 0; + int i, ret = -EREMOTEIO; i2c_gpio_set_pin(sda_pin, 1); i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay); /* Toggle SCL until slave release SDA */ - while (counter-- >= 0) { + while (scl_count-- >= 0) { i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay); i2c_gpio_set_pin(scl_pin, 0); - udelay(5); - if (i2c_gpio_get_pin(sda_pin)) + udelay(delay); + if (i2c_gpio_get_pin(sda_pin)) { + ret = 0; break; + } + } + + if (!ret && start_count) { + for (i = 0; i < start_count; i++) { + /* Send start condition */ + udelay(delay); + i2c_gpio_set_pin(sda_pin, 1); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 1); + udelay(delay); + i2c_gpio_set_pin(sda_pin, 0); + udelay(delay); + i2c_gpio_set_pin(scl_pin, 0); + } } /* Then, send I2C stop */ i2c_gpio_set_pin(sda_pin, 0); - udelay(5); + udelay(delay); i2c_gpio_set_pin(scl_pin, 1); - udelay(5); + udelay(delay); i2c_gpio_set_pin(sda_pin, 1); - udelay(5); + udelay(delay); if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin)) ret = -EREMOTEIO; @@ -561,7 +579,7 @@ static int i2c_deblock_gpio(struct udevice *bus) goto out_no_pinctrl; } - ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]); + ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5); ret = pinctrl_select_state(bus, "default"); if (ret) { diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 7d046c1a1e..fc5c1221e1 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -7,10 +7,10 @@ #include <clk.h> #include <dm.h> #include <i2c.h> -#include <malloc.h> #include <reset.h> #include <dm/device.h> +#include <linux/err.h> #include <linux/io.h> /* STM32 I2C registers */ @@ -145,7 +145,6 @@ struct stm32_i2c_spec { /** * struct stm32_i2c_setup - private I2C timing setup parameters - * @speed: I2C speed mode (standard, Fast Plus) * @speed_freq: I2C speed frequency (Hz) * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) @@ -154,7 +153,6 @@ struct stm32_i2c_spec { * @analog_filter: Analog filter delay (On/Off) */ struct stm32_i2c_setup { - enum i2c_speed_mode speed; u32 speed_freq; u32 clock_src; u32 rise_time; @@ -184,10 +182,11 @@ struct stm32_i2c_priv { struct stm32_i2c_regs *regs; struct clk clk; struct stm32_i2c_setup *setup; - int speed; + u32 speed; }; static const struct stm32_i2c_spec i2c_specs[] = { + /* Standard speed - 100 KHz */ [IC_SPEED_MODE_STANDARD] = { .rate = I2C_SPEED_STANDARD_RATE, .rate_min = 8000, @@ -200,6 +199,7 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 4700, .h_min = 4000, }, + /* Fast speed - 400 KHz */ [IC_SPEED_MODE_FAST] = { .rate = I2C_SPEED_FAST_RATE, .rate_min = 320000, @@ -212,6 +212,7 @@ static const struct stm32_i2c_spec i2c_specs[] = { .l_min = 1300, .h_min = 600, }, + /* Fast Plus Speed - 1 MHz */ [IC_SPEED_MODE_FAST_PLUS] = { .rate = I2C_SPEED_FAST_PLUS_RATE, .rate_min = 800000, @@ -474,6 +475,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, } static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions) { struct stm32_i2c_timings *v; @@ -490,13 +492,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, af_delay_max = setup->analog_filter ? STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0; - sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - + sdadel_min = specs->hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; - sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - + sdadel_max = specs->vddat_max - setup->rise_time - af_delay_max - (setup->dnf + 4) * i2cclk; - scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min; + scldel_min = setup->rise_time + specs->sudat_min; if (sdadel_min < 0) sdadel_min = 0; @@ -548,6 +550,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, } static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, + const struct stm32_i2c_spec *specs, struct list_head *solutions, struct stm32_i2c_timings *s) { @@ -570,8 +573,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, dnf_delay = setup->dnf * i2cclk; tsync = af_delay_min + dnf_delay + (2 * i2cclk); - clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; - clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; + clk_max = STM32_NSEC_PER_SEC / specs->rate_min; + clk_min = STM32_NSEC_PER_SEC / specs->rate_max; /* * Among Prescaler possibilities discovered above figures out SCL Low @@ -589,7 +592,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, for (l = 0; l < STM32_SCLL_MAX; l++) { u32 tscl_l = (l + 1) * prescaler + tsync; - if ((tscl_l < i2c_specs[setup->speed].l_min) || + if (tscl_l < specs->l_min || (i2cclk >= ((tscl_l - af_delay_min - dnf_delay) / 4))) { continue; @@ -601,7 +604,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, setup->rise_time + setup->fall_time; if ((tscl >= clk_min) && (tscl <= clk_max) && - (tscl_h >= i2c_specs[setup->speed].h_min) && + (tscl_h >= specs->h_min) && (i2cclk < tscl_h)) { u32 clk_error; @@ -630,26 +633,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, return ret; } +static const struct stm32_i2c_spec *get_specs(u32 rate) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) + if (rate <= i2c_specs[i].rate) + return &i2c_specs[i]; + + /* NOT REACHED */ + return ERR_PTR(-EINVAL); +} + static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_setup *setup, struct stm32_i2c_timings *output) { + const struct stm32_i2c_spec *specs; struct stm32_i2c_timings *v, *_v; struct list_head solutions; int ret; - if (setup->speed >= ARRAY_SIZE(i2c_specs)) { - pr_err("%s: speed out of bound {%d/%d}\n", __func__, - setup->speed, ARRAY_SIZE(i2c_specs) - 1); + specs = get_specs(setup->speed_freq); + if (specs == ERR_PTR(-EINVAL)) { + pr_err("%s: speed out of bound {%d}\n", __func__, + setup->speed_freq); return -EINVAL; } - if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || - (setup->fall_time > i2c_specs[setup->speed].fall_max)) { + if (setup->rise_time > specs->rise_max || + setup->fall_time > specs->fall_max) { pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", __func__, - setup->rise_time, i2c_specs[setup->speed].rise_max, - setup->fall_time, i2c_specs[setup->speed].fall_max); + setup->rise_time, specs->rise_max, + setup->fall_time, specs->fall_max); return -EINVAL; } @@ -659,18 +676,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, return -EINVAL; } - if (setup->speed_freq > i2c_specs[setup->speed].rate) { - pr_err("%s: Freq {%d/%d}\n", __func__, - setup->speed_freq, i2c_specs[setup->speed].rate); - return -EINVAL; - } - INIT_LIST_HEAD(&solutions); - ret = stm32_i2c_compute_solutions(setup, &solutions); + ret = stm32_i2c_compute_solutions(setup, specs, &solutions); if (ret) goto exit; - ret = stm32_i2c_choose_solution(setup, &solutions, output); + ret = stm32_i2c_choose_solution(setup, specs, &solutions, output); if (ret) goto exit; @@ -689,14 +700,24 @@ exit: return ret; } +static u32 get_lower_rate(u32 rate) +{ + int i; + + for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) + if (rate > i2c_specs[i].rate) + return i2c_specs[i].rate; + + return i2c_specs[0].rate; +} + static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_timings *timing) { struct stm32_i2c_setup *setup = i2c_priv->setup; int ret = 0; - setup->speed = i2c_priv->speed; - setup->speed_freq = i2c_specs[setup->speed].rate; + setup->speed_freq = i2c_priv->speed; setup->clock_src = clk_get_rate(&i2c_priv->clk); if (!setup->clock_src) { @@ -709,13 +730,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, if (ret) { debug("%s: failed to compute I2C timings.\n", __func__); - if (i2c_priv->speed > IC_SPEED_MODE_STANDARD) { - i2c_priv->speed--; - setup->speed = i2c_priv->speed; + if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) { setup->speed_freq = - i2c_specs[setup->speed].rate; + get_lower_rate(setup->speed_freq); debug("%s: downgrade I2C Speed Freq to (%i)\n", - __func__, i2c_specs[setup->speed].rate); + __func__, setup->speed_freq); } else { break; } @@ -727,13 +746,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, return ret; } - debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__, - setup->speed, setup->speed_freq, setup->clock_src); + debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__, + setup->speed_freq, setup->clock_src); debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__, setup->rise_time, setup->fall_time); debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__, setup->analog_filter ? "On" : "Off", setup->dnf); + i2c_priv->speed = setup->speed_freq; + return 0; } @@ -773,21 +794,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus); - switch (speed) { - case I2C_SPEED_STANDARD_RATE: - i2c_priv->speed = IC_SPEED_MODE_STANDARD; - break; - case I2C_SPEED_FAST_RATE: - i2c_priv->speed = IC_SPEED_MODE_FAST; - break; - case I2C_SPEED_FAST_PLUS_RATE: - i2c_priv->speed = IC_SPEED_MODE_FAST_PLUS; - break; - default: + if (speed > I2C_SPEED_FAST_PLUS_RATE) { debug("%s: Speed %d not supported\n", __func__, speed); return -EINVAL; } + i2c_priv->speed = speed; + return stm32_i2c_hw_config(i2c_priv); } |