* [U-Boot] [PATCH v4 0/2] I2C: Zynq
@ 2013-10-15 17:59 Michael Burr
2013-10-15 17:59 ` [U-Boot] [PATCH v4 1/2] I2C: Zynq: Support for 0-length register address Michael Burr
0 siblings, 1 reply; 3+ messages in thread
From: Michael Burr @ 2013-10-15 17:59 UTC (permalink / raw)
To: u-boot
This series of two patches contains improvements for the I2C driver on the
Xilinx Zynq architecture. In general, the goals are:
> Support for both I2C bus masters ("I2C0" and "I2C1") in the Zynq PS.
> Full support for bus multiplexers.
> Support for all register-address sizes (0, 1, 2).
The changes to file 'zynq_i2c.c' in this patch series are
meant to be applied in order: in other words, first apply the
changes from the PATCH 1/2 version; then apply the changes in the
PATCH 2/2 version.
v3: fixed mistake parsing PATCH 1/2
v4: _really_ fixed this time!
Michael Burr (2):
I2C: Zynq: Support for 0-length register address
I2C:Zynq: Adapt this driver to the new model
README | 9 +++
drivers/i2c/Makefile | 2 +-
drivers/i2c/zynq_i2c.c | 147
+++++++++++++++++++++++++++++-------------------
include/configs/zynq.h | 10 ++--
4 files changed, 102 insertions(+), 66 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 3+ messages in thread
* [U-Boot] [PATCH v4 1/2] I2C: Zynq: Support for 0-length register address
2013-10-15 17:59 [U-Boot] [PATCH v4 0/2] I2C: Zynq Michael Burr
@ 2013-10-15 17:59 ` Michael Burr
2013-10-15 17:59 ` [U-Boot] [PATCH v4 2/2] I2C: Zynq: Adapt this driver to the new model Michael Burr
0 siblings, 1 reply; 3+ messages in thread
From: Michael Burr @ 2013-10-15 17:59 UTC (permalink / raw)
To: u-boot
> Fixed bug with alen == 0 in 'i2c_write', 'i2c_read'
Further minor corrections:
> Write 'address' register before 'data' register.
> Write 'transfer_size' register before 'address' register.
Signed-off-by: Michael Burr <michael.burr@logicpd.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Michal Simek <monstr@monstr.eu>
---
Tested:
Xilinx ZC702 eval board.
Write and read registers with addresses of length 0 and 1.
Change history:
v2: put this in a series instead of by itself
v3: fixed formatting problem in patch message
v4: _really_ fixed this time!
---
drivers/i2c/zynq_i2c.c | 43 +++++++++++++++++++++++--------------------
1 file changed, 23 insertions(+), 20 deletions(-)
diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c
index ce2d23f..9cbd3e4 100644
--- a/drivers/i2c/zynq_i2c.c
+++ b/drivers/i2c/zynq_i2c.c
@@ -187,20 +187,22 @@ 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);
@@ -244,17 +246,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) {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [U-Boot] [PATCH v4 2/2] I2C: Zynq: Adapt this driver to the new model
2013-10-15 17:59 ` [U-Boot] [PATCH v4 1/2] I2C: Zynq: Support for 0-length register address Michael Burr
@ 2013-10-15 17:59 ` Michael Burr
0 siblings, 0 replies; 3+ messages in thread
From: Michael Burr @ 2013-10-15 17:59 UTC (permalink / raw)
To: u-boot
Driver 'zynq_i2c.c' together with CONFIGs, README,
and Makefile.
Signed-off-by: Michael Burr <michael.burr@logicpd.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Michal Simek <monstr@monstr.eu>
---
Note: the changes to file 'zynq_i2c.c' in this patch series are
meant to be applied in order: in other words, first apply the
changes from the 1/2 version; then apply the changes in the 2/2
version.
Tested on Xilinx ZC702 eval board:
Select various I2C chips using TI PCA9548 bus multiplexer.
Write and read registers with addresses of length 0 and 1.
---
README | 9 ++++
drivers/i2c/Makefile | 2 +-
drivers/i2c/zynq_i2c.c | 108
++++++++++++++++++++++++++++++------------------
include/configs/zynq.h | 10 ++---
4 files changed, 81 insertions(+), 48 deletions(-)
diff --git a/README b/README
index ccd47fa..fd2c8fc 100644
--- a/README
+++ b/README
@@ -1995,6 +1995,15 @@ CBFS (Coreboot Filesystem) support
- CONFIG_SYS_I2C_PPC4XX_CH0 activate hardware channel 0
- CONFIG_SYS_I2C_PPC4XX_CH1 activate hardware channel 1
+ - drivers/i2c/zynq_i2c.c
+ - Activate this driver with CONFIG_SYS_I2C_ZYNQ
+ - This driver operates only as bus-master (i.e. slave-
+ address == 0) and supports only 100 kbps speed.
+ - Both bus-controller devices in the Zynq PS (I2C0 and I2C1)
+ are supported. (However, note that Zynq PL configuration
+ may be needed in order to route some bus lines to external
+ pins.)
+
additional defines:
CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 37ccbd1..55ce32d 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -32,7 +32,7 @@ COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
COBJS-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
COBJS-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
COBJS-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
-COBJS-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o
+COBJS-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c
index 9cbd3e4..7972a59 100644
--- a/drivers/i2c/zynq_i2c.c
+++ b/drivers/i2c/zynq_i2c.c
@@ -7,6 +7,8 @@
*
* Copyright (c) 2012-2013 Xilinx, Michal Simek
*
+ * Copyright (c) 2013 Logic PD, Michael Burr
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -64,18 +66,28 @@ 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
-#endif
-
-static struct zynq_i2c_registers *zynq_i2c =
- (struct zynq_i2c_registers *)ZYNQ_I2C_BASE;
+static struct zynq_i2c_registers *i2c_select(struct i2c_adapter *adap)
+{
+ return adap->hwadapnr ?
+ /* Zynq PS I2C1 */
+ (struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR1 :
+ /* Zynq PS I2C0 */
+ (struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR0;
+}
/* I2C init called by cmd_i2c when doing 'i2c reset'. */
-void i2c_init(int requested_speed, int slaveadd)
+static void zynq_i2c_init(struct i2c_adapter *adap, int speed, int
slaveaddr)
{
+ struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
+
+ if (speed != 100000)
+ debug("Warning: requested speed not supported.\n");
+ if (slaveaddr)
+ debug("Warning: slave mode not supported.\n");
+
+ /* The following _assumes_ clock rate cpu_1x = 111 MHz */
+ /* This could use improvement! Also see 'i2c_set_bus_speed' below */
+
/* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) |
(2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control);
@@ -86,7 +98,7 @@ void i2c_init(int requested_speed, int slaveadd)
}
#ifdef DEBUG
-static void zynq_i2c_debug_status(void)
+static void zynq_i2c_debug_status(struct zynq_i2c_registers *zynq_i2c)
{
int int_status;
int status;
@@ -128,7 +140,7 @@ static void zynq_i2c_debug_status(void)
#endif
/* Wait for an interrupt */
-static u32 zynq_i2c_wait(u32 mask)
+static u32 zynq_i2c_wait(struct zynq_i2c_registers *zynq_i2c, u32 mask)
{
int timeout, int_status;
@@ -139,7 +151,7 @@ static u32 zynq_i2c_wait(u32 mask)
break;
}
#ifdef DEBUG
- zynq_i2c_debug_status();
+ zynq_i2c_debug_status(zynq_i2c);
#endif
/* Clear interrupt status flags */
writel(int_status & mask, &zynq_i2c->interrupt_status);
@@ -151,17 +163,19 @@ static u32 zynq_i2c_wait(u32 mask)
* I2C probe called by cmd_i2c when doing 'i2c probe'.
* Begin read, nak data byte, end.
*/
-int i2c_probe(u8 dev)
+static int zynq_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
{
+ struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
+
/* Attempt to read a byte */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_RW);
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
writel(0xFF, &zynq_i2c->interrupt_status);
- writel(dev, &zynq_i2c->address);
+ writel(chip, &zynq_i2c->address);
writel(1, &zynq_i2c->transfer_size);
- return (zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP |
+ return (zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP |
ZYNQ_I2C_INTERRUPT_NACK) &
ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT;
}
@@ -170,14 +184,18 @@ int i2c_probe(u8 dev)
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*/
-int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
+static int zynq_i2c_read(struct i2c_adapter *adap, uint8_t chip, uint addr,
+ int alen, uint8_t *buffer, int len)
{
+ struct zynq_i2c_registers *zynq_i2c;
u32 status;
u32 i = 0;
- u8 *cur_data = data;
+ u8 *cur_data = buffer;
+
+ zynq_i2c = i2c_select(adap);
/* Check the hardware can handle the requested bytes */
- if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX))
+ if ((len < 0) || (len > ZYNQ_I2C_TRANSFERT_SIZE_MAX))
return -EINVAL;
/* Write the register address */
@@ -191,12 +209,12 @@ int i2c_read(u8 dev, uint addr, int alen, u8
*data, int length)
writel(0xFF, &zynq_i2c->interrupt_status);
if (alen) {
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
- writel(dev, &zynq_i2c->address);
+ writel(chip, &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)) {
+ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
@@ -207,12 +225,12 @@ int i2c_read(u8 dev, uint addr, int alen, u8
*data, int length)
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(len, &zynq_i2c->transfer_size);
+ writel(chip, &zynq_i2c->address);
/* Wait for data */
do {
- status = zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP |
+ status = zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP |
ZYNQ_I2C_INTERRUPT_DATA);
if (!status) {
/* Release the bus */
@@ -220,15 +238,15 @@ int i2c_read(u8 dev, uint addr, int alen, u8
*data, int length)
return -ETIMEDOUT;
}
debug("Read %d bytes\n",
- length - readl(&zynq_i2c->transfer_size));
- for (; i < length - readl(&zynq_i2c->transfer_size); i++)
+ len - readl(&zynq_i2c->transfer_size));
+ for (; i < len - readl(&zynq_i2c->transfer_size); i++)
*(cur_data++) = readl(&zynq_i2c->data);
} while (readl(&zynq_i2c->transfer_size) != 0);
/* All done... release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
#ifdef DEBUG
- zynq_i2c_debug_status();
+ zynq_i2c_debug_status(zynq_i2c);
#endif
return 0;
}
@@ -237,31 +255,35 @@ int i2c_read(u8 dev, uint addr, int alen, u8
*data, int length)
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
-int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
+static int zynq_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint
addr,
+ int alen, uint8_t *buffer, int len)
{
- u8 *cur_data = data;
+ struct zynq_i2c_registers *zynq_i2c;
+ u8 *cur_data = buffer;
+
+ zynq_i2c = i2c_select(adap);
/* Write the register address */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_HOLD);
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
writel(0xFF, &zynq_i2c->interrupt_status);
- writel(dev, &zynq_i2c->address);
+ writel(chip, &zynq_i2c->address);
if (alen) {
while (alen--)
writel(addr >> (8*alen), &zynq_i2c->data);
/* Start the tranfer */
- if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
+ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
debug("Device acked address\n");
}
- while (length--) {
+ while (len--) {
writel(*(cur_data++), &zynq_i2c->data);
if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) {
- if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
+ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control,
ZYNQ_I2C_CONTROL_HOLD);
@@ -273,21 +295,25 @@ int i2c_write(u8 dev, uint addr, int alen, u8
*data, int length)
/* All done... release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
/* Wait for the address and data to be sent */
- if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP))
+ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP))
return -ETIMEDOUT;
return 0;
}
-int i2c_set_bus_num(unsigned int bus)
+static uint zynq_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
- /* Only support bus 0 */
- if (bus > 0)
+ /* struct zynq_i2c_registers *zynq_i2c = i2c_select(adap); */
+
+ /* Bus-speed selection is not implemented */
+ if (speed != 100000)
return -1;
- return 0;
-}
-unsigned int i2c_get_bus_num(void)
-{
- /* Only support bus 0 */
return 0;
}
+
+U_BOOT_I2C_ADAP_COMPLETE(ZYNQ_I2C0, zynq_i2c_init, zynq_i2c_probe,
+ zynq_i2c_read, zynq_i2c_write,
+ zynq_i2c_set_bus_speed, 100000, 0, 0)
+U_BOOT_I2C_ADAP_COMPLETE(ZYNQ_I2C1, zynq_i2c_init, zynq_i2c_probe,
+ zynq_i2c_read, zynq_i2c_write,
+ zynq_i2c_set_bus_speed, 100000, 0, 1)
diff --git a/include/configs/zynq.h b/include/configs/zynq.h
index b9f381f..1ae915f 100644
--- a/include/configs/zynq.h
+++ b/include/configs/zynq.h
@@ -56,15 +56,13 @@
# define CONFIG_DOS_PARTITION
#endif
-#define CONFIG_ZYNQ_I2C0
-
/* I2C */
-#if defined(CONFIG_ZYNQ_I2C0) || defined(CONFIG_ZYNQ_I2C1)
+#define CONFIG_SYS_I2C_ZYNQ
+#ifdef CONFIG_SYS_I2C_ZYNQ
+# define CONFIG_SYS_I2C
# define CONFIG_CMD_I2C
-# define CONFIG_ZYNQ_I2C
-# define CONFIG_HARD_I2C
# define CONFIG_SYS_I2C_SPEED 100000
-# define CONFIG_SYS_I2C_SLAVE 1
+# define CONFIG_SYS_I2C_SLAVE 0
#endif
#if defined(CONFIG_ZYNQ_DCC)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-10-15 17:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-15 17:59 [U-Boot] [PATCH v4 0/2] I2C: Zynq Michael Burr
2013-10-15 17:59 ` [U-Boot] [PATCH v4 1/2] I2C: Zynq: Support for 0-length register address Michael Burr
2013-10-15 17:59 ` [U-Boot] [PATCH v4 2/2] I2C: Zynq: Adapt this driver to the new model Michael Burr
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.