Merge git://git.denx.de/u-boot-i2c

This commit is contained in:
Tom Rini 2018-04-11 17:00:52 -04:00
commit 1a7cdb88f5
4 changed files with 154 additions and 35 deletions

View File

@ -12,6 +12,11 @@ property which allows the chip offset length to be selected.
Optional properties:
- u-boot,i2c-offset-len - length of chip offset in bytes. If omitted the
default value of 1 is used.
- gpios = <sda ...>, <scl ...>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <&i2c_xfer>;
pinctrl-1 = <&i2c_gpio>;
Pin description for I2C bus software deblocking.
Example
@ -26,3 +31,11 @@ i2c4: i2c@12ca0000 {
ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
};
};
&i2c1 {
pinctrl-names = "default", "gpio";
pinctrl-0 = <&i2c1_xfer>;
pinctrl-1 = <&i2c1_gpio>;
gpios = <&gpio1 26 GPIO_ACTIVE_LOW>, /* SDA */
<&gpio1 27 GPIO_ACTIVE_LOW>; /* SCL */
};

View File

@ -12,6 +12,7 @@
#include <i2c.h> /* Functional interface */
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
#include <clk.h>
#include <dm.h>
#include <mapmem.h>
@ -573,11 +574,9 @@ static int fsl_i2c_set_bus_speed(struct udevice *bus, uint speed)
static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
fdt_addr_t addr;
struct clk clock;
addr = dev_read_u32_default(bus, "reg", -1);
dev->base = map_sysmem(CONFIG_SYS_IMMR + addr, sizeof(struct fsl_i2c_base));
dev->base = map_sysmem(dev_read_addr(bus), sizeof(struct fsl_i2c_base));
if (!dev->base)
return -ENOMEM;
@ -587,7 +586,11 @@ static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
0x7f);
dev->speed = dev_read_u32_default(bus, "clock-frequency", 400000);
dev->i2c_clk = dev->index ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
if (!clk_get_by_index(bus, 0, &clock))
dev->i2c_clk = clk_get_rate(&clock);
else
dev->i2c_clk = dev->index ? gd->arch.i2c2_clk :
gd->arch.i2c1_clk;
return 0;
}

View File

@ -11,9 +11,19 @@
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/pinctrl.h>
#ifdef CONFIG_DM_GPIO
#include <asm/gpio.h>
#endif
#define I2C_MAX_OFFSET_LEN 4
enum {
PIN_SDA = 0,
PIN_SCL,
PIN_COUNT,
};
/* Useful debugging function */
void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
{
@ -445,20 +455,110 @@ int i2c_get_chip_offset_len(struct udevice *dev)
return chip->offset_len;
}
#ifdef CONFIG_DM_GPIO
static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit)
{
if (bit)
dm_gpio_set_dir_flags(pin, GPIOD_IS_IN);
else
dm_gpio_set_dir_flags(pin, GPIOD_IS_OUT |
GPIOD_ACTIVE_LOW |
GPIOD_IS_OUT_ACTIVE);
}
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 counter = 9;
int ret = 0;
i2c_gpio_set_pin(sda_pin, 1);
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
/* Toggle SCL until slave release SDA */
while (counter-- >= 0) {
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
i2c_gpio_set_pin(scl_pin, 0);
udelay(5);
if (i2c_gpio_get_pin(sda_pin))
break;
}
/* Then, send I2C stop */
i2c_gpio_set_pin(sda_pin, 0);
udelay(5);
i2c_gpio_set_pin(scl_pin, 1);
udelay(5);
i2c_gpio_set_pin(sda_pin, 1);
udelay(5);
if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
ret = -EREMOTEIO;
return ret;
}
static int i2c_deblock_gpio(struct udevice *bus)
{
struct gpio_desc gpios[PIN_COUNT];
int ret, ret0;
ret = gpio_request_list_by_name(bus, "gpios", gpios,
ARRAY_SIZE(gpios), GPIOD_IS_IN);
if (ret != ARRAY_SIZE(gpios)) {
debug("%s: I2C Node '%s' has no 'gpios' property %s\n",
__func__, dev_read_name(bus), bus->name);
if (ret >= 0) {
gpio_free_list(bus, gpios, ret);
ret = -ENOENT;
}
goto out;
}
ret = pinctrl_select_state(bus, "gpio");
if (ret) {
debug("%s: I2C Node '%s' has no 'gpio' pinctrl state. %s\n",
__func__, dev_read_name(bus), bus->name);
goto out_no_pinctrl;
}
ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
ret = pinctrl_select_state(bus, "default");
if (ret) {
debug("%s: I2C Node '%s' has no 'default' pinctrl state. %s\n",
__func__, dev_read_name(bus), bus->name);
}
ret = !ret ? ret0 : ret;
out_no_pinctrl:
gpio_free_list(bus, gpios, ARRAY_SIZE(gpios));
out:
return ret;
}
#else
static int i2c_deblock_gpio(struct udevice *bus)
{
return -ENOSYS;
}
#endif // CONFIG_DM_GPIO
int i2c_deblock(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
/*
* We could implement a software deblocking here if we could get
* access to the GPIOs used by I2C, and switch them to GPIO mode
* and then back to I2C. This is somewhat beyond our powers in
* driver model at present, so for now just fail.
*
* See https://patchwork.ozlabs.org/patch/399040/
*/
if (!ops->deblock)
return -ENOSYS;
return i2c_deblock_gpio(bus);
return ops->deblock(bus);
}

View File

@ -99,7 +99,8 @@ static int wait_for_int(bool read)
#endif
#ifdef CONFIG_DM_I2C
fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
FPGAMAP_SIZE_16);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
@ -110,7 +111,8 @@ static int wait_for_int(bool read)
if (ctr++ > 5000)
return 1;
#ifdef CONFIG_DM_I2C
fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
FPGAMAP_SIZE_16);
#else
I2C_GET_REG(interrupt_status, &val);
#endif
@ -128,6 +130,7 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
#endif
{
u16 val;
u16 data;
#ifdef CONFIG_DM_I2C
struct ihs_i2c_priv *priv = dev_get_priv(dev);
struct udevice *fpga;
@ -136,13 +139,14 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
#endif
/* Clear interrupt status */
data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV;
#ifdef CONFIG_DM_I2C
fpgamap_write16(fpga, priv->addr + REG_INTERRUPT_STATUS,
I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
fpgamap_read16(fpga, priv->addr + REG_INTERRUPT_STATUS, &val);
fpgamap_write(fpga, priv->addr + REG_INTERRUPT_STATUS, &data,
FPGAMAP_SIZE_16);
fpgamap_read(fpga, priv->addr + REG_INTERRUPT_STATUS, &val,
FPGAMAP_SIZE_16);
#else
I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
| I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
I2C_SET_REG(interrupt_status, data);
I2C_GET_REG(interrupt_status, &val);
#endif
@ -153,26 +157,24 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
if (len > 1)
val |= buffer[1] << 8;
#ifdef CONFIG_DM_I2C
fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, val);
fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX_EXT, &val,
FPGAMAP_SIZE_16);
#else
I2C_SET_REG(write_mailbox_ext, val);
#endif
}
data = I2CMB_NATIVE
| (read ? 0 : I2CMB_WRITE)
| (chip << 1)
| ((len > 1) ? I2CMB_2BYTE : 0)
| (is_last ? 0 : I2CMB_HOLD_BUS);
#ifdef CONFIG_DM_I2C
fpgamap_write16(fpga, priv->addr + REG_WRITE_MAILBOX,
I2CMB_NATIVE
| (read ? I2CMB_READ : I2CMB_WRITE)
| (chip << 1)
| ((len > 1) ? I2CMB_2BYTE : I2CMB_1BYTE)
| (!is_last ? I2CMB_HOLD_BUS : I2CMB_DONT_HOLD_BUS));
fpgamap_write(fpga, priv->addr + REG_WRITE_MAILBOX, &data,
FPGAMAP_SIZE_16);
#else
I2C_SET_REG(write_mailbox,
I2CMB_NATIVE
| (read ? 0 : I2CMB_WRITE)
| (chip << 1)
| ((len > 1) ? I2CMB_2BYTE : 0)
| (is_last ? 0 : I2CMB_HOLD_BUS));
I2C_SET_REG(write_mailbox, data);
#endif
#ifdef CONFIG_DM_I2C
@ -185,7 +187,8 @@ static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
/* If we want to read, get the bytes from the mailbox */
if (read) {
#ifdef CONFIG_DM_I2C
fpgamap_read16(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val);
fpgamap_read(fpga, priv->addr + REG_READ_MAILBOX_EXT, &val,
FPGAMAP_SIZE_16);
#else
I2C_GET_REG(read_mailbox_ext, &val);
#endif