aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Simek2013-04-22 08:21:33 -0500
committerMichal Simek2013-04-30 04:39:28 -0500
commit8934f7846501070a5b01c1fab5db27559e9d70d1 (patch)
tree56012200ad94320370944669f7ab2427902366f3
parent293eb33fcb95e2b2bae71edf97b0ca3bdd6ba98d (diff)
downloadu-boot-8934f7846501070a5b01c1fab5db27559e9d70d1.tar.gz
u-boot-8934f7846501070a5b01c1fab5db27559e9d70d1.tar.xz
u-boot-8934f7846501070a5b01c1fab5db27559e9d70d1.zip
i2c: zynq: Add support for Xilinx Zynq
Support Xilinx Zynq i2c controller. Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> Acked-by: Heiko Schocher <hs@denx.de> Reviewed-by: Tom Rini <trini@ti.com>
-rw-r--r--arch/arm/include/asm/arch-zynq/hardware.h2
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/zynq_i2c.c306
-rw-r--r--include/configs/zynq.h11
4 files changed, 320 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-zynq/hardware.h b/arch/arm/include/asm/arch-zynq/hardware.h
index 8eb4e1a7a9..6af892a789 100644
--- a/arch/arm/include/asm/arch-zynq/hardware.h
+++ b/arch/arm/include/asm/arch-zynq/hardware.h
@@ -31,6 +31,8 @@
31#define ZYNQ_GEM_BASEADDR1 0xE000C000 31#define ZYNQ_GEM_BASEADDR1 0xE000C000
32#define ZYNQ_SDHCI_BASEADDR0 0xE0100000 32#define ZYNQ_SDHCI_BASEADDR0 0xE0100000
33#define ZYNQ_SDHCI_BASEADDR1 0xE0101000 33#define ZYNQ_SDHCI_BASEADDR1 0xE0101000
34#define ZYNQ_I2C_BASEADDR0 0xE0004000
35#define ZYNQ_I2C_BASEADDR1 0xE0005000
34 36
35/* Reflect slcr offsets */ 37/* Reflect slcr offsets */
36struct slcr_regs { 38struct slcr_regs {
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3672..72e85a349a 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
46COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o 46COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o
47COBJS-$(CONFIG_SH_I2C) += sh_i2c.o 47COBJS-$(CONFIG_SH_I2C) += sh_i2c.o
48COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o 48COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o
49COBJS-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o
49 50
50COBJS := $(COBJS-y) 51COBJS := $(COBJS-y)
51SRCS := $(COBJS:.o=.c) 52SRCS := $(COBJS:.o=.c)
diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c
new file mode 100644
index 0000000000..ec49660cf7
--- /dev/null
+++ b/drivers/i2c/zynq_i2c.c
@@ -0,0 +1,306 @@
1/*
2 * Driver for the Zynq-7000 PS I2C controller
3 * IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2)
4 *
5 * Author: Joe Hershberger <joe.hershberger@ni.com>
6 * Copyright (c) 2012 Joe Hershberger.
7 *
8 * Copyright (c) 2012-2013 Xilinx, Michal Simek
9 *
10 * See file CREDITS for list of people who contributed to this
11 * project.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 * MA 02110-1301 USA
27 */
28
29#include <common.h>
30#include <asm/io.h>
31#include <i2c.h>
32#include <asm/errno.h>
33#include <asm/arch/hardware.h>
34
35/* i2c register set */
36struct zynq_i2c_registers {
37 u32 control;
38 u32 status;
39 u32 address;
40 u32 data;
41 u32 interrupt_status;
42 u32 transfer_size;
43 u32 slave_mon_pause;
44 u32 time_out;
45 u32 interrupt_mask;
46 u32 interrupt_enable;
47 u32 interrupt_disable;
48};
49
50/* Control register fields */
51#define ZYNQ_I2C_CONTROL_RW 0x00000001
52#define ZYNQ_I2C_CONTROL_MS 0x00000002
53#define ZYNQ_I2C_CONTROL_NEA 0x00000004
54#define ZYNQ_I2C_CONTROL_ACKEN 0x00000008
55#define ZYNQ_I2C_CONTROL_HOLD 0x00000010
56#define ZYNQ_I2C_CONTROL_SLVMON 0x00000020
57#define ZYNQ_I2C_CONTROL_CLR_FIFO 0x00000040
58#define ZYNQ_I2C_CONTROL_DIV_B_SHIFT 8
59#define ZYNQ_I2C_CONTROL_DIV_B_MASK 0x00003F00
60#define ZYNQ_I2C_CONTROL_DIV_A_SHIFT 14
61#define ZYNQ_I2C_CONTROL_DIV_A_MASK 0x0000C000
62
63/* Status register values */
64#define ZYNQ_I2C_STATUS_RXDV 0x00000020
65#define ZYNQ_I2C_STATUS_TXDV 0x00000040
66#define ZYNQ_I2C_STATUS_RXOVF 0x00000080
67#define ZYNQ_I2C_STATUS_BA 0x00000100
68
69/* Interrupt register fields */
70#define ZYNQ_I2C_INTERRUPT_COMP 0x00000001
71#define ZYNQ_I2C_INTERRUPT_DATA 0x00000002
72#define ZYNQ_I2C_INTERRUPT_NACK 0x00000004
73#define ZYNQ_I2C_INTERRUPT_TO 0x00000008
74#define ZYNQ_I2C_INTERRUPT_SLVRDY 0x00000010
75#define ZYNQ_I2C_INTERRUPT_RXOVF 0x00000020
76#define ZYNQ_I2C_INTERRUPT_TXOVF 0x00000040
77#define ZYNQ_I2C_INTERRUPT_RXUNF 0x00000080
78#define ZYNQ_I2C_INTERRUPT_ARBLOST 0x00000200
79
80#define ZYNQ_I2C_FIFO_DEPTH 16
81#define ZYNQ_I2C_TRANSFERT_SIZE_MAX 255 /* Controller transfer limit */
82
83#if defined(CONFIG_ZYNQ_I2C0)
84# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR0
85#else
86# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR1
87#endif
88
89static struct zynq_i2c_registers *zynq_i2c =
90 (struct zynq_i2c_registers *)ZYNQ_I2C_BASE;
91
92/* I2C init called by cmd_i2c when doing 'i2c reset'. */
93void i2c_init(int requested_speed, int slaveadd)
94{
95 /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
96 writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) |
97 (2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control);
98
99 /* Enable master mode, ack, and 7-bit addressing */
100 setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_MS |
101 ZYNQ_I2C_CONTROL_ACKEN | ZYNQ_I2C_CONTROL_NEA);
102}
103
104#ifdef DEBUG
105static void zynq_i2c_debug_status(void)
106{
107 int int_status;
108 int status;
109 int_status = readl(&zynq_i2c->interrupt_status);
110
111 status = readl(&zynq_i2c->status);
112 if (int_status || status) {
113 debug("Status: ");
114 if (int_status & ZYNQ_I2C_INTERRUPT_COMP)
115 debug("COMP ");
116 if (int_status & ZYNQ_I2C_INTERRUPT_DATA)
117 debug("DATA ");
118 if (int_status & ZYNQ_I2C_INTERRUPT_NACK)
119 debug("NACK ");
120 if (int_status & ZYNQ_I2C_INTERRUPT_TO)
121 debug("TO ");
122 if (int_status & ZYNQ_I2C_INTERRUPT_SLVRDY)
123 debug("SLVRDY ");
124 if (int_status & ZYNQ_I2C_INTERRUPT_RXOVF)
125 debug("RXOVF ");
126 if (int_status & ZYNQ_I2C_INTERRUPT_TXOVF)
127 debug("TXOVF ");
128 if (int_status & ZYNQ_I2C_INTERRUPT_RXUNF)
129 debug("RXUNF ");
130 if (int_status & ZYNQ_I2C_INTERRUPT_ARBLOST)
131 debug("ARBLOST ");
132 if (status & ZYNQ_I2C_STATUS_RXDV)
133 debug("RXDV ");
134 if (status & ZYNQ_I2C_STATUS_TXDV)
135 debug("TXDV ");
136 if (status & ZYNQ_I2C_STATUS_RXOVF)
137 debug("RXOVF ");
138 if (status & ZYNQ_I2C_STATUS_BA)
139 debug("BA ");
140 debug("TS%d ", readl(&zynq_i2c->transfer_size));
141 debug("\n");
142 }
143}
144#endif
145
146/* Wait for an interrupt */
147static u32 zynq_i2c_wait(u32 mask)
148{
149 int timeout, int_status;
150
151 for (timeout = 0; timeout < 100; timeout++) {
152 udelay(100);
153 int_status = readl(&zynq_i2c->interrupt_status);
154 if (int_status & mask)
155 break;
156 }
157#ifdef DEBUG
158 zynq_i2c_debug_status();
159#endif
160 /* Clear interrupt status flags */
161 writel(int_status & mask, &zynq_i2c->interrupt_status);
162
163 return int_status & mask;
164}
165
166/*
167 * I2C probe called by cmd_i2c when doing 'i2c probe'.
168 * Begin read, nak data byte, end.
169 */
170int i2c_probe(u8 dev)
171{
172 /* Attempt to read a byte */
173 setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
174 ZYNQ_I2C_CONTROL_RW);
175 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
176 writel(0xFF, &zynq_i2c->interrupt_status);
177 writel(dev, &zynq_i2c->address);
178 writel(1, &zynq_i2c->transfer_size);
179
180 return (zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP |
181 ZYNQ_I2C_INTERRUPT_NACK) &
182 ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT;
183}
184
185/*
186 * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
187 * Begin write, send address byte(s), begin read, receive data bytes, end.
188 */
189int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
190{
191 u32 status;
192 u32 i = 0;
193 u8 *cur_data = data;
194
195 /* Check the hardware can handle the requested bytes */
196 if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX))
197 return -EINVAL;
198
199 /* Write the register address */
200 setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
201 ZYNQ_I2C_CONTROL_HOLD);
202 /*
203 * Temporarily disable restart (by clearing hold)
204 * It doesn't seem to work.
205 */
206 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW |
207 ZYNQ_I2C_CONTROL_HOLD);
208 writel(0xFF, &zynq_i2c->interrupt_status);
209 while (alen--)
210 writel(addr >> (8*alen), &zynq_i2c->data);
211 writel(dev, &zynq_i2c->address);
212
213 /* Wait for the address to be sent */
214 if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
215 /* Release the bus */
216 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
217 return -ETIMEDOUT;
218 }
219 debug("Device acked address\n");
220
221 setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
222 ZYNQ_I2C_CONTROL_RW);
223 /* Start reading data */
224 writel(dev, &zynq_i2c->address);
225 writel(length, &zynq_i2c->transfer_size);
226
227 /* Wait for data */
228 do {
229 status = zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP |
230 ZYNQ_I2C_INTERRUPT_DATA);
231 if (!status) {
232 /* Release the bus */
233 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
234 return -ETIMEDOUT;
235 }
236 debug("Read %d bytes\n",
237 length - readl(&zynq_i2c->transfer_size));
238 for (; i < length - readl(&zynq_i2c->transfer_size); i++)
239 *(cur_data++) = readl(&zynq_i2c->data);
240 } while (readl(&zynq_i2c->transfer_size) != 0);
241 /* All done... release the bus */
242 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
243
244#ifdef DEBUG
245 zynq_i2c_debug_status();
246#endif
247 return 0;
248}
249
250/*
251 * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
252 * Begin write, send address byte(s), send data bytes, end.
253 */
254int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
255{
256 u8 *cur_data = data;
257
258 /* Write the register address */
259 setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
260 ZYNQ_I2C_CONTROL_HOLD);
261 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
262 writel(0xFF, &zynq_i2c->interrupt_status);
263 while (alen--)
264 writel(addr >> (8*alen), &zynq_i2c->data);
265 /* Start the tranfer */
266 writel(dev, &zynq_i2c->address);
267 if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
268 /* Release the bus */
269 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
270 return -ETIMEDOUT;
271 }
272
273 debug("Device acked address\n");
274 while (length--) {
275 writel(*(cur_data++), &zynq_i2c->data);
276 if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) {
277 if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) {
278 /* Release the bus */
279 clrbits_le32(&zynq_i2c->control,
280 ZYNQ_I2C_CONTROL_HOLD);
281 return -ETIMEDOUT;
282 }
283 }
284 }
285
286 /* All done... release the bus */
287 clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
288 /* Wait for the address and data to be sent */
289 if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP))
290 return -ETIMEDOUT;
291 return 0;
292}
293
294int i2c_set_bus_num(unsigned int bus)
295{
296 /* Only support bus 0 */
297 if (bus > 0)
298 return -1;
299 return 0;
300}
301
302unsigned int i2c_get_bus_num(void)
303{
304 /* Only support bus 0 */
305 return 0;
306}
diff --git a/include/configs/zynq.h b/include/configs/zynq.h
index 2ed88a72c4..f1f182edfb 100644
--- a/include/configs/zynq.h
+++ b/include/configs/zynq.h
@@ -72,6 +72,17 @@
72# define CONFIG_DOS_PARTITION 72# define CONFIG_DOS_PARTITION
73#endif 73#endif
74 74
75#define CONFIG_ZYNQ_I2C0
76
77/* I2C */
78#if defined(CONFIG_ZYNQ_I2C0) || defined(CONFIG_ZYNQ_I2C1)
79# define CONFIG_CMD_I2C
80# define CONFIG_ZYNQ_I2C
81# define CONFIG_HARD_I2C
82# define CONFIG_SYS_I2C_SPEED 100000
83# define CONFIG_SYS_I2C_SLAVE 1
84#endif
85
75#if defined(CONFIG_ZYNQ_DCC) 86#if defined(CONFIG_ZYNQ_DCC)
76# define CONFIG_ARM_DCC 87# define CONFIG_ARM_DCC
77# define CONFIG_CPU_V6 /* Required by CONFIG_ARM_DCC */ 88# define CONFIG_CPU_V6 /* Required by CONFIG_ARM_DCC */