diff options
author | Tom Rini <trini@konsulko.com> | 2019-04-12 15:43:04 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-04-12 15:43:04 -0400 |
commit | 683754f0aae6a17f82370d5c902af54c316b8f35 (patch) | |
tree | edc336b2cdc7ec49945e7de064224bc009c1b4c8 | |
parent | 066cc7c6cf8bb4fcf2a372e7c19c12fdec0868e7 (diff) | |
parent | 84c80c63d53bc8a7779b1e7e7084ee3b2d20e768 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-i2c
-rw-r--r-- | arch/arm/dts/imx53-kp-u-boot.dtsi | 10 | ||||
-rw-r--r-- | doc/device-tree-bindings/i2c/i2c.txt | 5 | ||||
-rw-r--r-- | drivers/i2c/i2c-uclass.c | 24 | ||||
-rw-r--r-- | drivers/i2c/muxes/Kconfig | 11 | ||||
-rw-r--r-- | drivers/i2c/muxes/pca954x.c | 10 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 19 | ||||
-rw-r--r-- | drivers/misc/i2c_eeprom.c | 26 | ||||
-rw-r--r-- | include/i2c.h | 2 |
8 files changed, 96 insertions, 11 deletions
diff --git a/arch/arm/dts/imx53-kp-u-boot.dtsi b/arch/arm/dts/imx53-kp-u-boot.dtsi new file mode 100644 index 0000000000..acab9b3657 --- /dev/null +++ b/arch/arm/dts/imx53-kp-u-boot.dtsi @@ -0,0 +1,10 @@ +/* + * Copyright 2019 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ or X11 + */ + +&pmic { + u-boot,i2c-transaction-bytes = <3>; +}; diff --git a/doc/device-tree-bindings/i2c/i2c.txt b/doc/device-tree-bindings/i2c/i2c.txt index de818d4713..9698e4899b 100644 --- a/doc/device-tree-bindings/i2c/i2c.txt +++ b/doc/device-tree-bindings/i2c/i2c.txt @@ -12,6 +12,10 @@ 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. +- u-boot,i2c-transaction-bytes - the length of single I2C transaction on + the bus. Some devices require more than single byte transmission + (e.g. mc34708 mfd). This information is necessary to correctly + initialize (put into idle state) I2C bus after soft reset. - gpios = <sda ...>, <scl ...>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&i2c_xfer>; @@ -28,6 +32,7 @@ i2c4: i2c@12ca0000 { compatible = "google,cros-ec"; i2c-max-frequency = <100000>; u-boot,i2c-offset-len = <0>; + u-boot,i2c-transaction-bytes = <3>; ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>; }; }; diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 49e23a0a4b..e47abf1833 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -593,6 +593,29 @@ int i2c_chip_ofdata_to_platdata(struct udevice *dev, struct dm_i2c_chip *chip) } #endif +static int i2c_pre_probe(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) + struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev); + unsigned int max = 0; + ofnode node; + int ret; + + i2c->max_transaction_bytes = 0; + dev_for_each_subnode(node, dev) { + ret = ofnode_read_u32(node, + "u-boot,i2c-transaction-bytes", + &max); + if (!ret && max > i2c->max_transaction_bytes) + i2c->max_transaction_bytes = max; + } + + debug("%s: I2C bus: %s max transaction bytes: %d\n", __func__, + dev->name, i2c->max_transaction_bytes); +#endif + return 0; +} + static int i2c_post_probe(struct udevice *dev) { #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) @@ -674,6 +697,7 @@ UCLASS_DRIVER(i2c) = { .post_bind = i2c_post_bind, .init = i2c_uclass_init, .priv_auto_alloc_size = sizeof(struct i2c_priv), + .pre_probe = i2c_pre_probe, .post_probe = i2c_post_probe, .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus), .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip), diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index b0da67ce2c..68f15261be 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -29,11 +29,12 @@ config I2C_MUX_PCA954x tristate "TI PCA954x I2C Mux/switches" depends on I2C_MUX help - If you say yes here you get support for the TI PCA954x - I2C mux/switch devices. It is x width I2C multiplexer which enables to - partitioning I2C bus and connect multiple devices with the same address - to the same I2C controller where driver handles proper routing to - target i2c device. PCA9544 and PCA9548 are supported. + If you say yes here you get support for the TI PCA954x I2C mux/switch + devices. It is x width I2C multiplexer which enables to partitioning + I2C bus and connect multiple devices with the same address to the same + I2C controller where driver handles proper routing to target i2c + device. Supported chips are PCA9543, PCA9544, PCA9547, PCA9548 and + PCA9646. config I2C_MUX_GPIO tristate "GPIO-based I2C multiplexer" diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index bd4e9abe5f..a630ce991d 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -15,6 +15,7 @@ DECLARE_GLOBAL_DATA_PTR; enum pca_type { + PCA9543, PCA9544, PCA9547, PCA9548, @@ -22,7 +23,7 @@ enum pca_type { }; struct chip_desc { - u8 enable; + u8 enable; /* Enable mask in ctl register (used for muxes only) */ enum muxtype { pca954x_ismux = 0, pca954x_isswi, @@ -37,6 +38,10 @@ struct pca954x_priv { }; static const struct chip_desc chips[] = { + [PCA9543] = { + .muxtype = pca954x_isswi, + .width = 2, + }, [PCA9544] = { .enable = 0x4, .muxtype = pca954x_ismux, @@ -48,12 +53,10 @@ static const struct chip_desc chips[] = { .width = 8, }, [PCA9548] = { - .enable = 0x8, .muxtype = pca954x_isswi, .width = 8, }, [PCA9646] = { - .enable = 0x0, .muxtype = pca954x_isswi, .width = 4, }, @@ -89,6 +92,7 @@ static const struct i2c_mux_ops pca954x_ops = { }; static const struct udevice_id pca954x_ids[] = { + { .compatible = "nxp,pca9543", .data = PCA9543 }, { .compatible = "nxp,pca9544", .data = PCA9544 }, { .compatible = "nxp,pca9547", .data = PCA9547 }, { .compatible = "nxp,pca9548", .data = PCA9548 }, diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 9999d9fe5e..5420afbc8e 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -354,9 +354,10 @@ int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus) int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus) { struct udevice *bus = i2c_bus->bus; + struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus); struct gpio_desc *scl_gpio = &i2c_bus->scl_gpio; struct gpio_desc *sda_gpio = &i2c_bus->sda_gpio; - int sda, scl; + int sda, scl, idle_sclks; int i, ret = 0; ulong elapsed, start_time; @@ -380,8 +381,22 @@ int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus) if ((sda & scl) == 1) goto exit; /* Bus is idle already */ + /* + * In most cases it is just enough to generate 8 + 1 SCLK + * clocks to recover I2C slave device from 'stuck' state + * (when for example SW reset was performed, in the middle of + * I2C transmission). + * + * However, there are devices which send data in packets of + * N bytes (N > 1). In such case we do need N * 8 + 1 SCLK + * clocks. + */ + idle_sclks = 8 + 1; + + if (i2c->max_transaction_bytes > 0) + idle_sclks = i2c->max_transaction_bytes * 8 + 1; /* Send high and low on the SCL line */ - for (i = 0; i < 9; i++) { + for (i = 0; i < idle_sclks; i++) { dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_OUT); dm_gpio_set_value(scl_gpio, 0); udelay(50); diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index 29ad87c1d7..f25d054007 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -5,6 +5,7 @@ #include <common.h> #include <linux/err.h> +#include <linux/kernel.h> #include <dm.h> #include <i2c.h> #include <i2c_eeprom.h> @@ -38,7 +39,24 @@ static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf, static int i2c_eeprom_std_write(struct udevice *dev, int offset, const uint8_t *buf, int size) { - return -ENODEV; + struct i2c_eeprom *priv = dev_get_priv(dev); + int ret; + + while (size > 0) { + int write_size = min_t(int, size, priv->pagesize); + + ret = dm_i2c_write(dev, offset, buf, write_size); + if (ret) + return ret; + + offset += write_size; + buf += write_size; + size -= write_size; + + udelay(10000); + } + + return 0; } static const struct i2c_eeprom_ops i2c_eeprom_std_ops = { @@ -50,6 +68,12 @@ static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) { struct i2c_eeprom *priv = dev_get_priv(dev); u64 data = dev_get_driver_data(dev); + u32 pagesize; + + if (dev_read_u32(dev, "pagesize", &pagesize) == 0) { + priv->pagesize = pagesize; + return 0; + } /* 6 bit -> page size of up to 2^63 (should be sufficient) */ priv->pagewidth = data & 0x3F; diff --git a/include/i2c.h b/include/i2c.h index ccffc19552..a5c760c711 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -68,9 +68,11 @@ struct dm_i2c_chip { * I2C bus udevice. * * @speed_hz: Bus speed in hertz (typically 100000) + * @max_transaction_bytes: Maximal size of single I2C transfer */ struct dm_i2c_bus { int speed_hz; + int max_transaction_bytes; }; /* |