mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-29 15:43:44 +08:00
Merge git://git.denx.de/u-boot-i2c
This commit is contained in:
commit
1a7cdb88f5
@ -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 */
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user