[U-Boot] [PATCH 1/4] i2c: cdns: Read address from DT in ofdata_to_platdata

Extract reading IP base address in function which is designed for it. Also enable option to read more information from DT in this function.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/i2c/i2c-cdns.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 909cea24182e..66bd580aad4b 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -125,10 +125,6 @@ static int cdns_i2c_probe(struct udevice *dev) { struct i2c_cdns_bus *bus = dev_get_priv(dev);
- bus->regs = (struct cdns_i2c_regs *)dev_get_addr(dev); - if (!bus->regs) - return -ENOMEM; - /* TODO: Calculate dividers based on CPU_CLK_1X */ /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) | @@ -313,6 +309,17 @@ static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, return 0; }
+static int cdns_i2c_ofdata_to_platdata(struct udevice *dev) +{ + struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev); + + i2c_bus->regs = (struct cdns_i2c_regs *)dev_get_addr(dev); + if (!i2c_bus->regs) + return -ENOMEM; + + return 0; +} + static const struct dm_i2c_ops cdns_i2c_ops = { .xfer = cdns_i2c_xfer, .probe_chip = cdns_i2c_probe_chip, @@ -330,6 +337,7 @@ U_BOOT_DRIVER(cdns_i2c) = { .of_match = cdns_i2c_of_match, .probe = cdns_i2c_probe, .remove = cdns_i2c_remove, + .ofdata_to_platdata = cdns_i2c_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_cdns_bus), .ops = &cdns_i2c_ops, };

set_bus_speed is the right function where bus speed should be setup. This move enable option to remove probe and remove functions which are empty.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/i2c/i2c-cdns.c | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-)
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 66bd580aad4b..0bc6aaaa6f90 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -115,41 +115,6 @@ struct i2c_cdns_bus { struct cdns_i2c_regs __iomem *regs; /* register base */ };
- -/** cdns_i2c_probe() - Probe method - * @dev: udevice pointer - * - * DM callback called when device is probed - */ -static int cdns_i2c_probe(struct udevice *dev) -{ - struct i2c_cdns_bus *bus = dev_get_priv(dev); - - /* TODO: Calculate dividers based on CPU_CLK_1X */ - /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ - writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) | - (2 << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control); - - /* Enable master mode, ack, and 7-bit addressing */ - setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS | - CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA); - - debug("%s bus %d at %p\n", __func__, dev->seq, bus->regs); - - return 0; -} - -static int cdns_i2c_remove(struct udevice *dev) -{ - struct i2c_cdns_bus *bus = dev_get_priv(dev); - - debug("%s bus %d at %p\n", __func__, dev->seq, bus->regs); - - unmap_sysmem(bus->regs); - - return 0; -} - /* Wait for an interrupt */ static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask) { @@ -170,12 +135,23 @@ static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask)
static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { + struct i2c_cdns_bus *bus = dev_get_priv(dev); + if (speed != 100000) { printf("%s, failed to set clock speed to %u\n", __func__, speed); return -EINVAL; }
+ /* TODO: Calculate dividers based on CPU_CLK_1X */ + /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ + writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) | + (2 << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control); + + /* Enable master mode, ack, and 7-bit addressing */ + setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS | + CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA); + return 0; }
@@ -335,8 +311,6 @@ U_BOOT_DRIVER(cdns_i2c) = { .name = "i2c-cdns", .id = UCLASS_I2C, .of_match = cdns_i2c_of_match, - .probe = cdns_i2c_probe, - .remove = cdns_i2c_remove, .ofdata_to_platdata = cdns_i2c_ofdata_to_platdata, .priv_auto_alloc_size = sizeof(struct i2c_cdns_bus), .ops = &cdns_i2c_ops,

Hello Michal,
Am 14.04.2016 um 14:15 schrieb Michal Simek:
set_bus_speed is the right function where bus speed should be setup. This move enable option to remove probe and remove functions which are empty.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/i2c-cdns.c | 48 +++++++++++------------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-)
Reviewwed-by: Heiko Schocher hs@denx.de
bye, Heiko

400kHz is maximum freq which can be used on Xilinx ZynqMP. Support it with standard divider calculator. Input freq is hardcoded to 100MHz input freq till we have clock driver which can provide this information for exact configuration.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/i2c/i2c-cdns.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 0bc6aaaa6f90..5642cd91fe2e 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -112,6 +112,7 @@ static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
struct i2c_cdns_bus { int id; + unsigned int input_freq; struct cdns_i2c_regs __iomem *regs; /* register base */ };
@@ -133,20 +134,79 @@ static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask) return int_status & mask; }
+#define CDNS_I2C_DIVA_MAX 4 +#define CDNS_I2C_DIVB_MAX 64 + +static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk, + unsigned int *a, unsigned int *b) +{ + unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp; + unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0; + unsigned int last_error, current_error; + + /* calculate (divisor_a+1) x (divisor_b+1) */ + temp = input_clk / (22 * fscl); + + /* + * If the calculated value is negative or 0CDNS_I2C_DIVA_MAX, + * the fscl input is out of range. Return error. + */ + if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX))) + return -EINVAL; + + last_error = -1; + for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) { + div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1)); + + if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX)) + continue; + div_b--; + + actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1)); + + if (actual_fscl > fscl) + continue; + + current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) : + (fscl - actual_fscl)); + + if (last_error > current_error) { + calc_div_a = div_a; + calc_div_b = div_b; + best_fscl = actual_fscl; + last_error = current_error; + } + } + + *a = calc_div_a; + *b = calc_div_b; + *f = best_fscl; + + return 0; +} + static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { struct i2c_cdns_bus *bus = dev_get_priv(dev); + u32 div_a = 0, div_b = 0; + unsigned long speed_p = speed; + int ret = 0;
- if (speed != 100000) { - printf("%s, failed to set clock speed to %u\n", __func__, - speed); + if (speed > 400000) { + debug("%s, failed to set clock speed to %u\n", __func__, + speed); return -EINVAL; }
- /* TODO: Calculate dividers based on CPU_CLK_1X */ - /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ - writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) | - (2 << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control); + ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b); + if (ret) + return ret; + + debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n", + __func__, div_a, div_b, bus->input_freq, speed, speed_p); + + writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) | + (div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
/* Enable master mode, ack, and 7-bit addressing */ setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS | @@ -293,6 +353,8 @@ static int cdns_i2c_ofdata_to_platdata(struct udevice *dev) if (!i2c_bus->regs) return -ENOMEM;
+ i2c_bus->input_freq = 100000000; /* TODO hardcode input freq for now */ + return 0; }

Hello Michal,
Am 14.04.2016 um 14:15 schrieb Michal Simek:
400kHz is maximum freq which can be used on Xilinx ZynqMP. Support it with standard divider calculator. Input freq is hardcoded to 100MHz input freq till we have clock driver which can provide this information for exact configuration.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/i2c-cdns.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-)
just some nitpick, beside of this:
Reviewed-by: Heiko Schocher hs@denx.de
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 0bc6aaaa6f90..5642cd91fe2e 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -112,6 +112,7 @@ static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
struct i2c_cdns_bus { int id;
- unsigned int input_freq; struct cdns_i2c_regs __iomem *regs; /* register base */ };
@@ -133,20 +134,79 @@ static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask) return int_status & mask; }
+#define CDNS_I2C_DIVA_MAX 4 +#define CDNS_I2C_DIVB_MAX 64
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
unsigned int *a, unsigned int *b)
+{
- unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
- unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
- unsigned int last_error, current_error;
- /* calculate (divisor_a+1) x (divisor_b+1) */
please add a space before and after the "+"
- temp = input_clk / (22 * fscl);
- /*
* If the calculated value is negative or 0CDNS_I2C_DIVA_MAX,
* the fscl input is out of range. Return error.
*/
- if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
return -EINVAL;
- last_error = -1;
- for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
continue;
div_b--;
actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
if (actual_fscl > fscl)
continue;
current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
(fscl - actual_fscl));
if (last_error > current_error) {
calc_div_a = div_a;
calc_div_b = div_b;
best_fscl = actual_fscl;
last_error = current_error;
}
- }
- *a = calc_div_a;
- *b = calc_div_b;
- *f = best_fscl;
- return 0;
+}
- static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { struct i2c_cdns_bus *bus = dev_get_priv(dev);
- u32 div_a = 0, div_b = 0;
- unsigned long speed_p = speed;
- int ret = 0;
- if (speed != 100000) {
printf("%s, failed to set clock speed to %u\n", __func__,
speed);
- if (speed > 400000) {
debug("%s, failed to set clock speed to %u\n", __func__,
return -EINVAL; }speed);
- /* TODO: Calculate dividers based on CPU_CLK_1X */
- /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
- writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
(2 << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b);
if (ret)
return ret;
debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n",
__func__, div_a, div_b, bus->input_freq, speed, speed_p);
writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
(div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
/* Enable master mode, ack, and 7-bit addressing */ setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
@@ -293,6 +353,8 @@ static int cdns_i2c_ofdata_to_platdata(struct udevice *dev) if (!i2c_bus->regs) return -ENOMEM;
- i2c_bus->input_freq = 100000000; /* TODO hardcode input freq for now */
- return 0; }
bye, Heiko

On 18.4.2016 09:08, Heiko Schocher wrote:
Hello Michal,
Am 14.04.2016 um 14:15 schrieb Michal Simek:
400kHz is maximum freq which can be used on Xilinx ZynqMP. Support it with standard divider calculator. Input freq is hardcoded to 100MHz input freq till we have clock driver which can provide this information for exact configuration.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/i2c-cdns.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-)
just some nitpick, beside of this:
Reviewed-by: Heiko Schocher hs@denx.de
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 0bc6aaaa6f90..5642cd91fe2e 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -112,6 +112,7 @@ static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
struct i2c_cdns_bus { int id;
- unsigned int input_freq; struct cdns_i2c_regs __iomem *regs; /* register base */ };
@@ -133,20 +134,79 @@ static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask) return int_status & mask; }
+#define CDNS_I2C_DIVA_MAX 4 +#define CDNS_I2C_DIVB_MAX 64
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
unsigned int *a, unsigned int *b)
+{
- unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
- unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
- unsigned int last_error, current_error;
- /* calculate (divisor_a+1) x (divisor_b+1) */
please add a space before and after the "+"
I have fixed this.
Thanks, Michal

Add support for common TI i2c mux which is available on ZynqMP zcu102 board. DM i2c mux core code is selecting/deselecting bus before/after every command is performed that's why only one channel is active at a time. That's also the reason why deselect is just disable all available channels.
Signed-off-by: Michal Simek michal.simek@xilinx.com ---
drivers/i2c/muxes/Kconfig | 7 ++++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/pca954x.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 drivers/i2c/muxes/pca954x.c
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index f959d9de9e8b..e16b902f9611 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -24,3 +24,10 @@ config I2C_ARB_GPIO_CHALLENGE I2C multimaster arbitration scheme using GPIOs and a challenge & response mechanism where masters have to claim the bus by asserting a GPIO. + +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. diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 47c1240d7e9e..fb2d67ec9a97 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -5,3 +5,4 @@ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_I2C_MUX_PCA954X) += pca954x.o diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c new file mode 100644 index 000000000000..206581d3d908 --- /dev/null +++ b/drivers/i2c/muxes/pca954x.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 - 2016 Xilinx, Inc. + * Written by Michal Simek + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <asm/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct pca95xx_priv { + u32 addr; + u32 width; +}; + +static int pca95xx_deselect(struct udevice *mux, struct udevice *bus, + uint channel) +{ + struct pca95xx_priv *priv = dev_get_priv(mux); + uchar byte = 0; + + return dm_i2c_write(mux, priv->addr, &byte, 1); +} + +static int pca95xx_select(struct udevice *mux, struct udevice *bus, + uint channel) +{ + struct pca95xx_priv *priv = dev_get_priv(mux); + uchar byte = 1 << channel; + + return dm_i2c_write(mux, priv->addr, &byte, 1); +} + +static const struct i2c_mux_ops pca95xx_ops = { + .select = pca95xx_select, + .deselect = pca95xx_deselect, +}; + +static const struct udevice_id pca95xx_ids[] = { + { .compatible = "nxp,pca9548", .data = (ulong)8 }, + { .compatible = "nxp,pca9544", .data = (ulong)4 }, + { } +}; + +static int pca95xx_ofdata_to_platdata(struct udevice *dev) +{ + struct pca95xx_priv *priv = dev_get_priv(dev); + + priv->addr = dev_get_addr(dev); + if (!priv->addr) { + debug("MUX not found\n"); + return -ENOSYS; + } + priv->width = dev_get_driver_data(dev); + + if (!priv->width) { + debug("No I2C MUX width specified\n"); + return -ENOSYS; + } + + debug("Device %s at 0x%x with width %d\n", + dev->name, priv->addr, priv->width); + + return 0; +} + +U_BOOT_DRIVER(pca95xx) = { + .name = "pca95xx", + .id = UCLASS_I2C_MUX, + .of_match = pca95xx_ids, + .ops = &pca95xx_ops, + .ofdata_to_platdata = pca95xx_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct pca95xx_priv), +};

Hello Michal,
Am 14.04.2016 um 14:15 schrieb Michal Simek:
Add support for common TI i2c mux which is available on ZynqMP zcu102 board. DM i2c mux core code is selecting/deselecting bus before/after every command is performed that's why only one channel is active at a time. That's also the reason why deselect is just disable all available channels.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/muxes/Kconfig | 7 ++++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/pca954x.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 drivers/i2c/muxes/pca954x.c
Thanks for your work!
I added Simon to CC, as he is the DM expert ;-)
from my side, your patch looks fine, so:
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index f959d9de9e8b..e16b902f9611 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -24,3 +24,10 @@ config I2C_ARB_GPIO_CHALLENGE I2C multimaster arbitration scheme using GPIOs and a challenge & response mechanism where masters have to claim the bus by asserting a GPIO.
+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.
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 47c1240d7e9e..fb2d67ec9a97 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -5,3 +5,4 @@ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_I2C_MUX_PCA954X) += pca954x.o diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c new file mode 100644 index 000000000000..206581d3d908 --- /dev/null +++ b/drivers/i2c/muxes/pca954x.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2015 - 2016 Xilinx, Inc.
- Written by Michal Simek
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <asm/gpio.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct pca95xx_priv {
- u32 addr;
- u32 width;
+};
+static int pca95xx_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
+{
- struct pca95xx_priv *priv = dev_get_priv(mux);
- uchar byte = 0;
- return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static int pca95xx_select(struct udevice *mux, struct udevice *bus,
uint channel)
+{
- struct pca95xx_priv *priv = dev_get_priv(mux);
- uchar byte = 1 << channel;
- return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static const struct i2c_mux_ops pca95xx_ops = {
- .select = pca95xx_select,
- .deselect = pca95xx_deselect,
+};
+static const struct udevice_id pca95xx_ids[] = {
- { .compatible = "nxp,pca9548", .data = (ulong)8 },
- { .compatible = "nxp,pca9544", .data = (ulong)4 },
- { }
+};
+static int pca95xx_ofdata_to_platdata(struct udevice *dev) +{
- struct pca95xx_priv *priv = dev_get_priv(dev);
- priv->addr = dev_get_addr(dev);
- if (!priv->addr) {
debug("MUX not found\n");
return -ENOSYS;
- }
- priv->width = dev_get_driver_data(dev);
- if (!priv->width) {
debug("No I2C MUX width specified\n");
return -ENOSYS;
- }
- debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
- return 0;
+}
+U_BOOT_DRIVER(pca95xx) = {
- .name = "pca95xx",
- .id = UCLASS_I2C_MUX,
- .of_match = pca95xx_ids,
- .ops = &pca95xx_ops,
- .ofdata_to_platdata = pca95xx_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct pca95xx_priv),
+};

Hi Michal,
On 14 April 2016 at 06:15, Michal Simek michal.simek@xilinx.com wrote:
Add support for common TI i2c mux which is available on ZynqMP zcu102 board. DM i2c mux core code is selecting/deselecting bus before/after every command is performed that's why only one channel is active at a time. That's also the reason why deselect is just disable all available channels.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/muxes/Kconfig | 7 ++++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/pca954x.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 drivers/i2c/muxes/pca954x.c
nits below, but otherwise:
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index f959d9de9e8b..e16b902f9611 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -24,3 +24,10 @@ config I2C_ARB_GPIO_CHALLENGE I2C multimaster arbitration scheme using GPIOs and a challenge & response mechanism where masters have to claim the bus by asserting a GPIO.
+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.
Can you add a few lines about what this device is? What does it allow?
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 47c1240d7e9e..fb2d67ec9a97 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -5,3 +5,4 @@ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_I2C_MUX_PCA954X) += pca954x.o diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c new file mode 100644 index 000000000000..206581d3d908 --- /dev/null +++ b/drivers/i2c/muxes/pca954x.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2015 - 2016 Xilinx, Inc.
- Written by Michal Simek
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <asm/gpio.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct pca95xx_priv {
u32 addr;
ulong?
u32 width;
Comments?
+};
+static int pca95xx_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
+{
struct pca95xx_priv *priv = dev_get_priv(mux);
uchar byte = 0;
return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static int pca95xx_select(struct udevice *mux, struct udevice *bus,
uint channel)
+{
struct pca95xx_priv *priv = dev_get_priv(mux);
uchar byte = 1 << channel;
return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static const struct i2c_mux_ops pca95xx_ops = {
.select = pca95xx_select,
.deselect = pca95xx_deselect,
+};
+static const struct udevice_id pca95xx_ids[] = {
{ .compatible = "nxp,pca9548", .data = (ulong)8 },
{ .compatible = "nxp,pca9544", .data = (ulong)4 },
{ }
+};
+static int pca95xx_ofdata_to_platdata(struct udevice *dev) +{
struct pca95xx_priv *priv = dev_get_priv(dev);
priv->addr = dev_get_addr(dev);
if (!priv->addr) {
debug("MUX not found\n");
return -ENOSYS;
-EINVAL
}
priv->width = dev_get_driver_data(dev);
if (!priv->width) {
debug("No I2C MUX width specified\n");
return -ENOSYS;
-EINVAL
}
debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
return 0;
+}
+U_BOOT_DRIVER(pca95xx) = {
.name = "pca95xx",
.id = UCLASS_I2C_MUX,
.of_match = pca95xx_ids,
.ops = &pca95xx_ops,
.ofdata_to_platdata = pca95xx_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct pca95xx_priv),
+};
1.9.1
Regards, Simon

On 20.4.2016 16:41, Simon Glass wrote:
Hi Michal,
On 14 April 2016 at 06:15, Michal Simek michal.simek@xilinx.com wrote:
Add support for common TI i2c mux which is available on ZynqMP zcu102 board. DM i2c mux core code is selecting/deselecting bus before/after every command is performed that's why only one channel is active at a time. That's also the reason why deselect is just disable all available channels.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/muxes/Kconfig | 7 ++++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/pca954x.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 drivers/i2c/muxes/pca954x.c
nits below, but otherwise:
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index f959d9de9e8b..e16b902f9611 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -24,3 +24,10 @@ config I2C_ARB_GPIO_CHALLENGE I2C multimaster arbitration scheme using GPIOs and a challenge & response mechanism where masters have to claim the bus by asserting a GPIO.
+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.
Can you add a few lines about what this device is? What does it allow?
done.
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 47c1240d7e9e..fb2d67ec9a97 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -5,3 +5,4 @@ # obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o +obj-$(CONFIG_I2C_MUX_PCA954X) += pca954x.o diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c new file mode 100644 index 000000000000..206581d3d908 --- /dev/null +++ b/drivers/i2c/muxes/pca954x.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2015 - 2016 Xilinx, Inc.
- Written by Michal Simek
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <asm/gpio.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct pca95xx_priv {
u32 addr;
ulong?
it is i2c address that's why 32bit address should be enough.
u32 width;
Comments?
Added.
+};
+static int pca95xx_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
+{
struct pca95xx_priv *priv = dev_get_priv(mux);
uchar byte = 0;
return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static int pca95xx_select(struct udevice *mux, struct udevice *bus,
uint channel)
+{
struct pca95xx_priv *priv = dev_get_priv(mux);
uchar byte = 1 << channel;
return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+static const struct i2c_mux_ops pca95xx_ops = {
.select = pca95xx_select,
.deselect = pca95xx_deselect,
+};
+static const struct udevice_id pca95xx_ids[] = {
{ .compatible = "nxp,pca9548", .data = (ulong)8 },
{ .compatible = "nxp,pca9544", .data = (ulong)4 },
{ }
+};
+static int pca95xx_ofdata_to_platdata(struct udevice *dev) +{
struct pca95xx_priv *priv = dev_get_priv(dev);
priv->addr = dev_get_addr(dev);
if (!priv->addr) {
debug("MUX not found\n");
return -ENOSYS;
-EINVAL
fixed.
}
priv->width = dev_get_driver_data(dev);
if (!priv->width) {
debug("No I2C MUX width specified\n");
return -ENOSYS;
-EINVAL
fixed.
}
debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
return 0;
+}
+U_BOOT_DRIVER(pca95xx) = {
.name = "pca95xx",
.id = UCLASS_I2C_MUX,
.of_match = pca95xx_ids,
.ops = &pca95xx_ops,
.ofdata_to_platdata = pca95xx_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct pca95xx_priv),
+};
1.9.1
Regards, Simon
Thanks, Michal

Hello Michal,
Am 14.04.2016 um 14:15 schrieb Michal Simek:
Extract reading IP base address in function which is designed for it. Also enable option to read more information from DT in this function.
Signed-off-by: Michal Simek michal.simek@xilinx.com
drivers/i2c/i2c-cdns.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
Reviewed-by: Heiko Schocher hs@denx.de
bye, Heiko
participants (3)
-
Heiko Schocher
-
Michal Simek
-
Simon Glass