Zynq PS has two I2C bus masters (called 'I2C0' and 'I2C1'):
> Implement 'i2c_set_bus_num' routine to select from these.
Support I2C devices which do not use internal addresses:
> Handle case of 'alen == 0' in 'i2c_read', 'i2c_write'.
This supports PCA9548 bus multiplexer on Xilinx ZC702 board.
Tested cases of 'alen == 0' and 'alen == 1' on this board.
Further minor corrections:
> Write 'address' register before 'data' register.
> Write 'transfer_size' register before 'address' register.

Signed-off-by: Michael Burr <michael.b...@logicpd.com>
Cc: Albert Aribaud <albert.u.b...@aribaud.net>
Cc: Heiko Schocher <h...@denx.de>
Cc: Michal Simek <mon...@monstr.eu>
---
 drivers/i2c/zynq_i2c.c |   87 ++++++++++++++++++++++++++++++------------------
 1 file changed, 55 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c
index ce2d23f..1c9ae30 100644
--- a/drivers/i2c/zynq_i2c.c
+++ b/drivers/i2c/zynq_i2c.c
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2012-2013 Xilinx, Michal Simek
  *
- * SPDX-License-Identifier:    GPL-2.0+
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
@@ -64,18 +64,19 @@ struct zynq_i2c_registers {
 #define ZYNQ_I2C_FIFO_DEPTH            16
 #define ZYNQ_I2C_TRANSFERT_SIZE_MAX    255 /* Controller transfer limit */
 
-#if defined(CONFIG_ZYNQ_I2C0)
-# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR0
-#else
-# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR1
+#ifdef CONFIG_I2C_MULTI_BUS
+static unsigned int current_bus;
 #endif
-
-static struct zynq_i2c_registers *zynq_i2c =
-       (struct zynq_i2c_registers *)ZYNQ_I2C_BASE;
+static struct zynq_i2c_registers *zynq_i2c;
 
 /* I2C init called by cmd_i2c when doing 'i2c reset'. */
 void i2c_init(int requested_speed, int slaveadd)
 {
+#ifdef CONFIG_I2C_MULTI_BUS
+       current_bus = 0;
+#endif
+       zynq_i2c = (struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR0;
+
        /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
        writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) |
                (2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control);
@@ -187,26 +188,29 @@ int i2c_read(u8 dev, uint addr, int alen, u8 *data, int 
length)
         * Temporarily disable restart (by clearing hold)
         * It doesn't seem to work.
         */
-       clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW |
-               ZYNQ_I2C_CONTROL_HOLD);
+       clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
+
        writel(0xFF, &zynq_i2c->interrupt_status);
-       while (alen--)
-               writel(addr >> (8*alen), &zynq_i2c->data);
-       writel(dev, &zynq_i2c->address);
+       if (alen) {
+               clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
+               writel(dev, &zynq_i2c->address);
+               while (alen--)
+                       writel(addr >> (8*alen), &zynq_i2c->data);
 
-       /* Wait for the address to be sent */
-       if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
-               /* Release the bus */
-               clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
-               return -ETIMEDOUT;
+               /* Wait for the address to be sent */
+               if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
+                       /* Release the bus */
+                       clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
+                       return -ETIMEDOUT;
+               }
+               debug("Device acked address\n");
        }
-       debug("Device acked address\n");
 
        setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
                ZYNQ_I2C_CONTROL_RW);
        /* Start reading data */
-       writel(dev, &zynq_i2c->address);
        writel(length, &zynq_i2c->transfer_size);
+       writel(dev, &zynq_i2c->address);
 
        /* Wait for data */
        do {
@@ -244,17 +248,18 @@ int i2c_write(u8 dev, uint addr, int alen, u8 *data, int 
length)
                ZYNQ_I2C_CONTROL_HOLD);
        clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
        writel(0xFF, &zynq_i2c->interrupt_status);
-       while (alen--)
-               writel(addr >> (8*alen), &zynq_i2c->data);
-       /* Start the tranfer */
        writel(dev, &zynq_i2c->address);
-       if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
-               /* Release the bus */
-               clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
-               return -ETIMEDOUT;
+       if (alen) {
+               while (alen--)
+                       writel(addr >> (8*alen), &zynq_i2c->data);
+               /* Start the tranfer */
+               if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
+                       /* Release the bus */
+                       clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
+                       return -ETIMEDOUT;
+               }
+               debug("Device acked address\n");
        }
-
-       debug("Device acked address\n");
        while (length--) {
                writel(*(cur_data++), &zynq_i2c->data);
                if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) {
@@ -277,14 +282,32 @@ int i2c_write(u8 dev, uint addr, int alen, u8 *data, int 
length)
 
 int i2c_set_bus_num(unsigned int bus)
 {
-       /* Only support bus 0 */
-       if (bus > 0)
+       if (bus >= CONFIG_SYS_MAX_I2C_BUS)
                return -1;
+
+       switch (bus) {
+       case 0:
+               zynq_i2c = (struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR0;
+               break;
+#ifdef CONFIG_I2C_MULTI_BUS
+       case 1:
+               zynq_i2c = (struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR1;
+               break;
+#endif
+       default:
+               return -1;
+       }
+#ifdef CONFIG_I2C_MULTI_BUS
+       current_bus = bus;
+#endif
        return 0;
 }
 
 unsigned int i2c_get_bus_num(void)
 {
-       /* Only support bus 0 */
+#ifdef CONFIG_I2C_MULTI_BUS
+       return current_bus;
+#else
        return 0;
+#endif
 }
-- 
1.7.9.5

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to