mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
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:
commit
b180e32ea3
12 changed files with 315 additions and 109 deletions
|
@ -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:
|
||||
|
||||
|
|
21
doc/device-tree-bindings/misc/bootcounter.txt
Normal file
21
doc/device-tree-bindings/misc/bootcounter.txt
Normal 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>;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue