Merge tag '20200316-for-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-i2c into next

i2c: for next
- i2c-gpio: make it possible to run deblock sequence on driver probe
- i2c-gpio: add clock stretching support
- updates the Designware I2C driver for high speed mode,
  fix a bug and add some improvements.
- add DM support for memory based bootcounter driver
This commit is contained in:
Tom Rini 2020-03-17 11:33:59 -04:00
commit b180e32ea3
12 changed files with 315 additions and 109 deletions

View file

@ -16,6 +16,10 @@ Optional:
The resulting transfer speed can be adjusted by setting the delay[us]
between gpio-toggle operations. Speed [Hz] = 1000000 / 4 * udelay[us],
It not defined, then default is 5us (~50KHz).
* i2c-gpio,deblock
Run deblocking sequence when the driver gets probed.
* i2c-gpio,scl-output-only;
Set if SCL is an output only
Example:

View file

@ -0,0 +1,21 @@
U-Boot bootcounter Devicetree Binding
=====================================
The device tree node describes the U-Boot bootcounter
memory based device binding.
Required properties :
- compatible : "u-boot,bootcount";
- single-word : set this, if you have only one word space
for storing the bootcounter.
Example
-------
MPC83xx based board:
bootcount@0x13ff8 {
compatible = "u-boot,bootcount";
reg = <0x13ff8 0x08>;
};

View file

@ -106,6 +106,13 @@ config DM_BOOTCOUNT_I2C_EEPROM
pointing to the underlying i2c eeprom device) and an optional 'offset'
property are supported.
config BOOTCOUNT_MEM
bool "Support memory based bootcounter"
help
Enabling Memory based bootcount, typically in a SoC register which
is not cleared on softreset.
compatible = "u-boot,bootcount";
endmenu
endif

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_BOOTCOUNT_GENERIC) += bootcount.o
obj-$(CONFIG_BOOTCOUNT_MEM) += bootcount.o
obj-$(CONFIG_BOOTCOUNT_AT91) += bootcount_at91.o
obj-$(CONFIG_BOOTCOUNT_AM33XX) += bootcount_davinci.o
obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o

View file

@ -8,6 +8,7 @@
#include <cpu_func.h>
#include <linux/compiler.h>
#if !defined(CONFIG_DM_BOOTCOUNT)
/* Now implement the generic default functions */
__weak void bootcount_store(ulong a)
{
@ -49,3 +50,94 @@ __weak ulong bootcount_load(void)
return raw_bootcount_load(reg);
#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */
}
#else
#include <dm.h>
/*
* struct bootcount_mem_priv - private bootcount mem driver data
*
* @base: base address used for bootcounter
* @singleword: if true use only one 32 bit word for bootcounter
*/
struct bootcount_mem_priv {
phys_addr_t base;
bool singleword;
};
static int bootcount_mem_get(struct udevice *dev, u32 *a)
{
struct bootcount_mem_priv *priv = dev_get_priv(dev);
void *reg = (void *)priv->base;
u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
if (priv->singleword) {
u32 tmp = raw_bootcount_load(reg);
if ((tmp & 0xffff0000) != (magic & 0xffff0000))
return -ENODEV;
*a = (tmp & 0x0000ffff);
} else {
if (raw_bootcount_load(reg + 4) != magic)
return -ENODEV;
*a = raw_bootcount_load(reg);
}
return 0;
};
static int bootcount_mem_set(struct udevice *dev, const u32 a)
{
struct bootcount_mem_priv *priv = dev_get_priv(dev);
void *reg = (void *)priv->base;
u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
uintptr_t flush_start = rounddown(priv->base,
CONFIG_SYS_CACHELINE_SIZE);
uintptr_t flush_end;
if (priv->singleword) {
raw_bootcount_store(reg, (magic & 0xffff0000) | a);
flush_end = roundup(priv->base + 4,
CONFIG_SYS_CACHELINE_SIZE);
} else {
raw_bootcount_store(reg, a);
raw_bootcount_store(reg + 4, magic);
flush_end = roundup(priv->base + 8,
CONFIG_SYS_CACHELINE_SIZE);
}
flush_dcache_range(flush_start, flush_end);
return 0;
};
static const struct bootcount_ops bootcount_mem_ops = {
.get = bootcount_mem_get,
.set = bootcount_mem_set,
};
static int bootcount_mem_probe(struct udevice *dev)
{
struct bootcount_mem_priv *priv = dev_get_priv(dev);
priv->base = (phys_addr_t)dev_read_addr(dev);
if (dev_read_bool(dev, "single-word"))
priv->singleword = true;
return 0;
}
static const struct udevice_id bootcount_mem_ids[] = {
{ .compatible = "u-boot,bootcount" },
{ }
};
U_BOOT_DRIVER(bootcount_mem) = {
.name = "bootcount-mem",
.id = UCLASS_BOOTCOUNT,
.priv_auto_alloc_size = sizeof(struct bootcount_mem_priv),
.probe = bootcount_mem_probe,
.of_match = bootcount_mem_ids,
.ops = &bootcount_mem_ops,
};
#endif

View file

@ -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(&regs->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;

View file

@ -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;
};

View file

@ -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,

View file

@ -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) {

View file

@ -14,7 +14,7 @@
struct i2c_eeprom_drv_data {
u32 size; /* size in bytes */
u32 pagewidth; /* pagesize = 2^pagewidth */
u32 pagesize; /* page size in bytes */
u32 addr_offset_mask; /* bits in addr used for offset overflow */
u32 offset_len; /* size in bytes of offset */
};
@ -99,13 +99,11 @@ static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
u32 pagesize;
u32 size;
if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
priv->pagesize = pagesize;
} else {
else
/* 6 bit -> page size of up to 2^63 (should be sufficient) */
priv->pagewidth = data->pagewidth;
priv->pagesize = (1 << priv->pagewidth);
}
priv->pagesize = data->pagesize;
if (dev_read_u32(dev, "size", &size) == 0)
priv->size = size;
@ -158,98 +156,98 @@ static int i2c_eeprom_std_probe(struct udevice *dev)
static const struct i2c_eeprom_drv_data eeprom_data = {
.size = 0,
.pagewidth = 0,
.pagesize = 1,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
.size = 256,
.pagewidth = 3,
.pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c01a_data = {
.size = 128,
.pagewidth = 3,
.pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c02_data = {
.size = 256,
.pagewidth = 3,
.pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c04_data = {
.size = 512,
.pagewidth = 4,
.pagesize = 16,
.addr_offset_mask = 0x1,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c08_data = {
.size = 1024,
.pagewidth = 4,
.pagesize = 16,
.addr_offset_mask = 0x3,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c08a_data = {
.size = 1024,
.pagewidth = 4,
.pagesize = 16,
.addr_offset_mask = 0x3,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c16a_data = {
.size = 2048,
.pagewidth = 4,
.pagesize = 16,
.addr_offset_mask = 0x7,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24mac402_data = {
.size = 256,
.pagewidth = 4,
.pagesize = 16,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c32_data = {
.size = 4096,
.pagewidth = 5,
.pagesize = 32,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c64_data = {
.size = 8192,
.pagewidth = 5,
.pagesize = 32,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c128_data = {
.size = 16384,
.pagewidth = 6,
.pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c256_data = {
.size = 32768,
.pagewidth = 6,
.pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c512_data = {
.size = 65536,
.pagewidth = 6,
.pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};

View file

@ -330,6 +330,24 @@ uint i2c_get_chip_addr_offset_mask(struct udevice *dev);
*/
int i2c_deblock(struct udevice *bus);
/**
* i2c_deblock_gpio_loop() - recover a bus from an unknown state by toggling SDA/SCL
*
* This is the inner logic used for toggling I2C SDA/SCL lines as GPIOs
* for deblocking the I2C bus.
*
* @sda_pin: SDA GPIO
* @scl_pin: SCL GPIO
* @scl_count: Number of SCL clock cycles generated to deblock SDA
* @start_count:Number of I2C start conditions sent after deblocking SDA
* @delay: Delay between SCL clock line changes
* @return 0 if OK, -ve on error
*/
struct gpio_desc;
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);
/**
* struct dm_i2c_ops - driver operations for I2C uclass
*

View file

@ -16,8 +16,6 @@ struct i2c_eeprom_ops {
struct i2c_eeprom {
/* The EEPROM's page size in byte */
unsigned long pagesize;
/* The EEPROM's page width in bits (pagesize = 2^pagewidth) */
unsigned pagewidth;
/* The EEPROM's capacity in bytes */
unsigned long size;
};