diff options
author | Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> | 2015-03-31 09:03:55 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2015-04-03 15:22:52 -0400 |
commit | ba92222ed63a12d09120df9b92f56cc990abac19 (patch) | |
tree | 9cf7f2b45533e3c18030f85550eba5f041dee0c0 /drivers/i2c | |
parent | 3b10db23c0411524357c5834731df2e24897b53b (diff) |
i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780
Adds the i2c bus controller driver for the Ingenic JZ4780 SoC.
Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-jz4780.c | 832 |
3 files changed, 842 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index db09881614b7..0b0ca7dd5d1f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -583,6 +583,15 @@ config I2C_IOP3XX | |||
583 | This driver can also be built as a module. If so, the module | 583 | This driver can also be built as a module. If so, the module |
584 | will be called i2c-iop3xx. | 584 | will be called i2c-iop3xx. |
585 | 585 | ||
586 | config I2C_JZ4780 | ||
587 | tristate "JZ4780 I2C controller interface support" | ||
588 | depends on MACH_JZ4780 || COMPILE_TEST | ||
589 | help | ||
590 | If you say yes to this option, support will be included for the | ||
591 | Ingenic JZ4780 I2C controller. | ||
592 | |||
593 | If you don't know what to do here, say N. | ||
594 | |||
586 | config I2C_KEMPLD | 595 | config I2C_KEMPLD |
587 | tristate "Kontron COM I2C Controller" | 596 | tristate "Kontron COM I2C Controller" |
588 | depends on MFD_KEMPLD | 597 | depends on MFD_KEMPLD |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 4413f09996cb..ab6a0a67aca1 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o | |||
56 | obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o | 56 | obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o |
57 | obj-$(CONFIG_I2C_IMX) += i2c-imx.o | 57 | obj-$(CONFIG_I2C_IMX) += i2c-imx.o |
58 | obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o | 58 | obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o |
59 | obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o | ||
59 | obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o | 60 | obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o |
60 | obj-$(CONFIG_I2C_MESON) += i2c-meson.o | 61 | obj-$(CONFIG_I2C_MESON) += i2c-meson.o |
61 | obj-$(CONFIG_I2C_MPC) += i2c-mpc.o | 62 | obj-$(CONFIG_I2C_MPC) += i2c-mpc.o |
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c new file mode 100644 index 000000000000..ce1d69324169 --- /dev/null +++ b/drivers/i2c/busses/i2c-jz4780.c | |||
@@ -0,0 +1,832 @@ | |||
1 | /* | ||
2 | * Ingenic JZ4780 I2C bus driver | ||
3 | * | ||
4 | * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc. | ||
5 | * Copyright (C) 2015 Imagination Technologies | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/time.h> | ||
32 | |||
33 | #define JZ4780_I2C_CTRL 0x00 | ||
34 | #define JZ4780_I2C_TAR 0x04 | ||
35 | #define JZ4780_I2C_SAR 0x08 | ||
36 | #define JZ4780_I2C_DC 0x10 | ||
37 | #define JZ4780_I2C_SHCNT 0x14 | ||
38 | #define JZ4780_I2C_SLCNT 0x18 | ||
39 | #define JZ4780_I2C_FHCNT 0x1C | ||
40 | #define JZ4780_I2C_FLCNT 0x20 | ||
41 | #define JZ4780_I2C_INTST 0x2C | ||
42 | #define JZ4780_I2C_INTM 0x30 | ||
43 | #define JZ4780_I2C_RXTL 0x38 | ||
44 | #define JZ4780_I2C_TXTL 0x3C | ||
45 | #define JZ4780_I2C_CINTR 0x40 | ||
46 | #define JZ4780_I2C_CRXUF 0x44 | ||
47 | #define JZ4780_I2C_CRXOF 0x48 | ||
48 | #define JZ4780_I2C_CTXOF 0x4C | ||
49 | #define JZ4780_I2C_CRXREQ 0x50 | ||
50 | #define JZ4780_I2C_CTXABRT 0x54 | ||
51 | #define JZ4780_I2C_CRXDONE 0x58 | ||
52 | #define JZ4780_I2C_CACT 0x5C | ||
53 | #define JZ4780_I2C_CSTP 0x60 | ||
54 | #define JZ4780_I2C_CSTT 0x64 | ||
55 | #define JZ4780_I2C_CGC 0x68 | ||
56 | #define JZ4780_I2C_ENB 0x6C | ||
57 | #define JZ4780_I2C_STA 0x70 | ||
58 | #define JZ4780_I2C_TXABRT 0x80 | ||
59 | #define JZ4780_I2C_DMACR 0x88 | ||
60 | #define JZ4780_I2C_DMATDLR 0x8C | ||
61 | #define JZ4780_I2C_DMARDLR 0x90 | ||
62 | #define JZ4780_I2C_SDASU 0x94 | ||
63 | #define JZ4780_I2C_ACKGC 0x98 | ||
64 | #define JZ4780_I2C_ENSTA 0x9C | ||
65 | #define JZ4780_I2C_SDAHD 0xD0 | ||
66 | |||
67 | #define JZ4780_I2C_CTRL_STPHLD BIT(7) | ||
68 | #define JZ4780_I2C_CTRL_SLVDIS BIT(6) | ||
69 | #define JZ4780_I2C_CTRL_REST BIT(5) | ||
70 | #define JZ4780_I2C_CTRL_MATP BIT(4) | ||
71 | #define JZ4780_I2C_CTRL_SATP BIT(3) | ||
72 | #define JZ4780_I2C_CTRL_SPDF BIT(2) | ||
73 | #define JZ4780_I2C_CTRL_SPDS BIT(1) | ||
74 | #define JZ4780_I2C_CTRL_MD BIT(0) | ||
75 | |||
76 | #define JZ4780_I2C_STA_SLVACT BIT(6) | ||
77 | #define JZ4780_I2C_STA_MSTACT BIT(5) | ||
78 | #define JZ4780_I2C_STA_RFF BIT(4) | ||
79 | #define JZ4780_I2C_STA_RFNE BIT(3) | ||
80 | #define JZ4780_I2C_STA_TFE BIT(2) | ||
81 | #define JZ4780_I2C_STA_TFNF BIT(1) | ||
82 | #define JZ4780_I2C_STA_ACT BIT(0) | ||
83 | |||
84 | static const char * const jz4780_i2c_abrt_src[] = { | ||
85 | "ABRT_7B_ADDR_NOACK", | ||
86 | "ABRT_10ADDR1_NOACK", | ||
87 | "ABRT_10ADDR2_NOACK", | ||
88 | "ABRT_XDATA_NOACK", | ||
89 | "ABRT_GCALL_NOACK", | ||
90 | "ABRT_GCALL_READ", | ||
91 | "ABRT_HS_ACKD", | ||
92 | "SBYTE_ACKDET", | ||
93 | "ABRT_HS_NORSTRT", | ||
94 | "SBYTE_NORSTRT", | ||
95 | "ABRT_10B_RD_NORSTRT", | ||
96 | "ABRT_MASTER_DIS", | ||
97 | "ARB_LOST", | ||
98 | "SLVFLUSH_TXFIFO", | ||
99 | "SLV_ARBLOST", | ||
100 | "SLVRD_INTX", | ||
101 | }; | ||
102 | |||
103 | #define JZ4780_I2C_INTST_IGC BIT(11) | ||
104 | #define JZ4780_I2C_INTST_ISTT BIT(10) | ||
105 | #define JZ4780_I2C_INTST_ISTP BIT(9) | ||
106 | #define JZ4780_I2C_INTST_IACT BIT(8) | ||
107 | #define JZ4780_I2C_INTST_RXDN BIT(7) | ||
108 | #define JZ4780_I2C_INTST_TXABT BIT(6) | ||
109 | #define JZ4780_I2C_INTST_RDREQ BIT(5) | ||
110 | #define JZ4780_I2C_INTST_TXEMP BIT(4) | ||
111 | #define JZ4780_I2C_INTST_TXOF BIT(3) | ||
112 | #define JZ4780_I2C_INTST_RXFL BIT(2) | ||
113 | #define JZ4780_I2C_INTST_RXOF BIT(1) | ||
114 | #define JZ4780_I2C_INTST_RXUF BIT(0) | ||
115 | |||
116 | #define JZ4780_I2C_INTM_MIGC BIT(11) | ||
117 | #define JZ4780_I2C_INTM_MISTT BIT(10) | ||
118 | #define JZ4780_I2C_INTM_MISTP BIT(9) | ||
119 | #define JZ4780_I2C_INTM_MIACT BIT(8) | ||
120 | #define JZ4780_I2C_INTM_MRXDN BIT(7) | ||
121 | #define JZ4780_I2C_INTM_MTXABT BIT(6) | ||
122 | #define JZ4780_I2C_INTM_MRDREQ BIT(5) | ||
123 | #define JZ4780_I2C_INTM_MTXEMP BIT(4) | ||
124 | #define JZ4780_I2C_INTM_MTXOF BIT(3) | ||
125 | #define JZ4780_I2C_INTM_MRXFL BIT(2) | ||
126 | #define JZ4780_I2C_INTM_MRXOF BIT(1) | ||
127 | #define JZ4780_I2C_INTM_MRXUF BIT(0) | ||
128 | |||
129 | #define JZ4780_I2C_DC_READ BIT(8) | ||
130 | |||
131 | #define JZ4780_I2C_SDAHD_HDENB BIT(8) | ||
132 | |||
133 | #define JZ4780_I2C_ENB_I2C BIT(0) | ||
134 | |||
135 | #define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) | ||
136 | #define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) | ||
137 | #define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) | ||
138 | #define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) | ||
139 | |||
140 | #define JZ4780_I2C_FIFO_LEN 16 | ||
141 | #define TX_LEVEL 3 | ||
142 | #define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1) | ||
143 | |||
144 | #define JZ4780_I2C_TIMEOUT 300 | ||
145 | |||
146 | #define BUFSIZE 200 | ||
147 | |||
148 | struct jz4780_i2c { | ||
149 | void __iomem *iomem; | ||
150 | int irq; | ||
151 | struct clk *clk; | ||
152 | struct i2c_adapter adap; | ||
153 | |||
154 | /* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */ | ||
155 | spinlock_t lock; | ||
156 | |||
157 | /* beginning of lock scope */ | ||
158 | unsigned char *rbuf; | ||
159 | int rd_total_len; | ||
160 | int rd_data_xfered; | ||
161 | int rd_cmd_xfered; | ||
162 | |||
163 | unsigned char *wbuf; | ||
164 | int wt_len; | ||
165 | |||
166 | int is_write; | ||
167 | int stop_hold; | ||
168 | int speed; | ||
169 | |||
170 | int data_buf[BUFSIZE]; | ||
171 | int cmd_buf[BUFSIZE]; | ||
172 | int cmd; | ||
173 | |||
174 | /* end of lock scope */ | ||
175 | struct completion trans_waitq; | ||
176 | }; | ||
177 | |||
178 | static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c, | ||
179 | unsigned long offset) | ||
180 | { | ||
181 | return readw(i2c->iomem + offset); | ||
182 | } | ||
183 | |||
184 | static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c, | ||
185 | unsigned long offset, unsigned short val) | ||
186 | { | ||
187 | writew(val, i2c->iomem + offset); | ||
188 | } | ||
189 | |||
190 | static int jz4780_i2c_disable(struct jz4780_i2c *i2c) | ||
191 | { | ||
192 | unsigned short regval; | ||
193 | unsigned long loops = 5; | ||
194 | |||
195 | jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0); | ||
196 | |||
197 | do { | ||
198 | regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); | ||
199 | if (!(regval & JZ4780_I2C_ENB_I2C)) | ||
200 | return 0; | ||
201 | |||
202 | usleep_range(5000, 15000); | ||
203 | } while (--loops); | ||
204 | |||
205 | dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval); | ||
206 | return -ETIMEDOUT; | ||
207 | } | ||
208 | |||
209 | static int jz4780_i2c_enable(struct jz4780_i2c *i2c) | ||
210 | { | ||
211 | unsigned short regval; | ||
212 | unsigned long loops = 5; | ||
213 | |||
214 | jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1); | ||
215 | |||
216 | do { | ||
217 | regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA); | ||
218 | if (regval & JZ4780_I2C_ENB_I2C) | ||
219 | return 0; | ||
220 | |||
221 | usleep_range(5000, 15000); | ||
222 | } while (--loops); | ||
223 | |||
224 | dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval); | ||
225 | return -ETIMEDOUT; | ||
226 | } | ||
227 | |||
228 | static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address) | ||
229 | { | ||
230 | unsigned short regval; | ||
231 | unsigned long loops = 5; | ||
232 | |||
233 | do { | ||
234 | regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); | ||
235 | if ((regval & JZ4780_I2C_STA_TFE) && | ||
236 | !(regval & JZ4780_I2C_STA_MSTACT)) | ||
237 | break; | ||
238 | |||
239 | usleep_range(5000, 15000); | ||
240 | } while (--loops); | ||
241 | |||
242 | if (loops) { | ||
243 | jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | dev_err(&i2c->adap.dev, | ||
248 | "set device to address 0x%02x failed, STA=0x%04x\n", | ||
249 | address, regval); | ||
250 | |||
251 | return -ENXIO; | ||
252 | } | ||
253 | |||
254 | static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c) | ||
255 | { | ||
256 | int dev_clk_khz = clk_get_rate(i2c->clk) / 1000; | ||
257 | int cnt_high = 0; /* HIGH period count of the SCL clock */ | ||
258 | int cnt_low = 0; /* LOW period count of the SCL clock */ | ||
259 | int cnt_period = 0; /* period count of the SCL clock */ | ||
260 | int setup_time = 0; | ||
261 | int hold_time = 0; | ||
262 | unsigned short tmp = 0; | ||
263 | int i2c_clk = i2c->speed; | ||
264 | |||
265 | if (jz4780_i2c_disable(i2c)) | ||
266 | dev_dbg(&i2c->adap.dev, "i2c not disabled\n"); | ||
267 | |||
268 | /* | ||
269 | * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk) | ||
270 | * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns | ||
271 | * fast mode, min LOW and HIGH period are 1300 ns and 600 ns | ||
272 | */ | ||
273 | cnt_period = dev_clk_khz / i2c_clk; | ||
274 | |||
275 | if (i2c_clk <= 100) | ||
276 | cnt_high = (cnt_period * 4000) / (4700 + 4000); | ||
277 | else | ||
278 | cnt_high = (cnt_period * 600) / (1300 + 600); | ||
279 | |||
280 | cnt_low = cnt_period - cnt_high; | ||
281 | |||
282 | /* | ||
283 | * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because | ||
284 | * normal read are 2 messages, we cannot disable i2c controller | ||
285 | * between these two messages, this means that we must always set | ||
286 | * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL | ||
287 | * | ||
288 | */ | ||
289 | if (i2c_clk <= 100) { | ||
290 | tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST | ||
291 | | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; | ||
292 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
293 | |||
294 | jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT, | ||
295 | JZ4780_I2CSHCNT_ADJUST(cnt_high)); | ||
296 | jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT, | ||
297 | JZ4780_I2CSLCNT_ADJUST(cnt_low)); | ||
298 | } else { | ||
299 | tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST | ||
300 | | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD; | ||
301 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
302 | |||
303 | jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT, | ||
304 | JZ4780_I2CFHCNT_ADJUST(cnt_high)); | ||
305 | jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT, | ||
306 | JZ4780_I2CFLCNT_ADJUST(cnt_low)); | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * a i2c device must internally provide a hold time at least 300ns | ||
311 | * tHD:DAT | ||
312 | * Standard Mode: min=300ns, max=3450ns | ||
313 | * Fast Mode: min=0ns, max=900ns | ||
314 | * tSU:DAT | ||
315 | * Standard Mode: min=250ns, max=infinite | ||
316 | * Fast Mode: min=100(250ns is recommended), max=infinite | ||
317 | * | ||
318 | * 1i2c_clk = 10^6 / dev_clk_khz | ||
319 | * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns | ||
320 | * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns | ||
321 | * | ||
322 | * The actual hold time is (SDAHD + 1) * (i2c_clk period). | ||
323 | * | ||
324 | * Length of setup time calculated using (SDASU - 1) * (ic_clk_period) | ||
325 | * | ||
326 | */ | ||
327 | if (i2c_clk <= 100) { /* standard mode */ | ||
328 | setup_time = 300; | ||
329 | hold_time = 400; | ||
330 | } else { | ||
331 | setup_time = 450; | ||
332 | hold_time = 450; | ||
333 | } | ||
334 | |||
335 | hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1; | ||
336 | setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1; | ||
337 | |||
338 | if (setup_time > 255) | ||
339 | setup_time = 255; | ||
340 | |||
341 | if (setup_time <= 0) | ||
342 | setup_time = 1; | ||
343 | |||
344 | jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time); | ||
345 | |||
346 | if (hold_time > 255) | ||
347 | hold_time = 255; | ||
348 | |||
349 | if (hold_time >= 0) { | ||
350 | /*i2c hold time enable */ | ||
351 | hold_time |= JZ4780_I2C_SDAHD_HDENB; | ||
352 | jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time); | ||
353 | } else { | ||
354 | /* disable hold time */ | ||
355 | jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0); | ||
356 | } | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c) | ||
362 | { | ||
363 | int ret; | ||
364 | unsigned long flags; | ||
365 | unsigned short tmp; | ||
366 | |||
367 | spin_lock_irqsave(&i2c->lock, flags); | ||
368 | |||
369 | /* can send stop now if need */ | ||
370 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
371 | tmp &= ~JZ4780_I2C_CTRL_STPHLD; | ||
372 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
373 | |||
374 | /* disable all interrupts first */ | ||
375 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); | ||
376 | |||
377 | /* then clear all interrupts */ | ||
378 | jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT); | ||
379 | jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR); | ||
380 | |||
381 | /* then disable the controller */ | ||
382 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
383 | tmp &= ~JZ4780_I2C_ENB_I2C; | ||
384 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
385 | udelay(10); | ||
386 | tmp |= JZ4780_I2C_ENB_I2C; | ||
387 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
388 | |||
389 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
390 | |||
391 | ret = jz4780_i2c_disable(i2c); | ||
392 | if (ret) | ||
393 | dev_err(&i2c->adap.dev, | ||
394 | "unable to disable device during cleanup!\n"); | ||
395 | |||
396 | if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM) | ||
397 | & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST))) | ||
398 | dev_err(&i2c->adap.dev, | ||
399 | "device has interrupts after a complete cleanup!\n"); | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int jz4780_i2c_prepare(struct jz4780_i2c *i2c) | ||
405 | { | ||
406 | jz4780_i2c_set_speed(i2c); | ||
407 | return jz4780_i2c_enable(i2c); | ||
408 | } | ||
409 | |||
410 | static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count) | ||
411 | { | ||
412 | int i; | ||
413 | |||
414 | for (i = 0; i < cmd_count; i++) | ||
415 | jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ); | ||
416 | } | ||
417 | |||
418 | static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c) | ||
419 | { | ||
420 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0); | ||
421 | complete(&i2c->trans_waitq); | ||
422 | } | ||
423 | |||
424 | static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id) | ||
425 | { | ||
426 | unsigned short tmp; | ||
427 | unsigned short intst; | ||
428 | unsigned short intmsk; | ||
429 | struct jz4780_i2c *i2c = dev_id; | ||
430 | unsigned long flags; | ||
431 | |||
432 | spin_lock_irqsave(&i2c->lock, flags); | ||
433 | intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); | ||
434 | intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST); | ||
435 | |||
436 | intst &= intmsk; | ||
437 | |||
438 | if (intst & JZ4780_I2C_INTST_TXABT) { | ||
439 | jz4780_i2c_trans_done(i2c); | ||
440 | goto done; | ||
441 | } | ||
442 | |||
443 | if (intst & JZ4780_I2C_INTST_RXOF) { | ||
444 | dev_dbg(&i2c->adap.dev, "received fifo overflow!\n"); | ||
445 | jz4780_i2c_trans_done(i2c); | ||
446 | goto done; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * When reading, always drain RX FIFO before we send more Read | ||
451 | * Commands to avoid fifo overrun | ||
452 | */ | ||
453 | if (i2c->is_write == 0) { | ||
454 | int rd_left; | ||
455 | |||
456 | while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA) | ||
457 | & JZ4780_I2C_STA_RFNE)) { | ||
458 | *(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC) | ||
459 | & 0xff; | ||
460 | i2c->rd_data_xfered++; | ||
461 | if (i2c->rd_data_xfered == i2c->rd_total_len) { | ||
462 | jz4780_i2c_trans_done(i2c); | ||
463 | goto done; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | rd_left = i2c->rd_total_len - i2c->rd_data_xfered; | ||
468 | |||
469 | if (rd_left <= JZ4780_I2C_FIFO_LEN) | ||
470 | jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1); | ||
471 | } | ||
472 | |||
473 | if (intst & JZ4780_I2C_INTST_TXEMP) { | ||
474 | if (i2c->is_write == 0) { | ||
475 | int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; | ||
476 | int max_send = (JZ4780_I2C_FIFO_LEN - 1) | ||
477 | - (i2c->rd_cmd_xfered | ||
478 | - i2c->rd_data_xfered); | ||
479 | int cmd_to_send = min(cmd_left, max_send); | ||
480 | |||
481 | if (i2c->rd_cmd_xfered != 0) | ||
482 | cmd_to_send = min(cmd_to_send, | ||
483 | JZ4780_I2C_FIFO_LEN | ||
484 | - TX_LEVEL - 1); | ||
485 | |||
486 | if (cmd_to_send) { | ||
487 | jz4780_i2c_send_rcmd(i2c, cmd_to_send); | ||
488 | i2c->rd_cmd_xfered += cmd_to_send; | ||
489 | } | ||
490 | |||
491 | cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered; | ||
492 | if (cmd_left == 0) { | ||
493 | intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM); | ||
494 | intmsk &= ~JZ4780_I2C_INTM_MTXEMP; | ||
495 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk); | ||
496 | |||
497 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
498 | tmp &= ~JZ4780_I2C_CTRL_STPHLD; | ||
499 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
500 | } | ||
501 | } else { | ||
502 | unsigned short data; | ||
503 | unsigned short i2c_sta; | ||
504 | |||
505 | i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); | ||
506 | |||
507 | while ((i2c_sta & JZ4780_I2C_STA_TFNF) && | ||
508 | (i2c->wt_len > 0)) { | ||
509 | i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); | ||
510 | data = *i2c->wbuf; | ||
511 | data &= ~JZ4780_I2C_DC_READ; | ||
512 | jz4780_i2c_writew(i2c, JZ4780_I2C_DC, | ||
513 | data); | ||
514 | i2c->wbuf++; | ||
515 | i2c->wt_len--; | ||
516 | } | ||
517 | |||
518 | if (i2c->wt_len == 0) { | ||
519 | if (!i2c->stop_hold) { | ||
520 | tmp = jz4780_i2c_readw(i2c, | ||
521 | JZ4780_I2C_CTRL); | ||
522 | tmp &= ~JZ4780_I2C_CTRL_STPHLD; | ||
523 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, | ||
524 | tmp); | ||
525 | } | ||
526 | |||
527 | jz4780_i2c_trans_done(i2c); | ||
528 | goto done; | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | done: | ||
534 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
535 | return IRQ_HANDLED; | ||
536 | } | ||
537 | |||
538 | static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src) | ||
539 | { | ||
540 | int i; | ||
541 | |||
542 | dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src); | ||
543 | dev_err(&i2c->adap.dev, "device addr=%x\n", | ||
544 | jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)); | ||
545 | dev_err(&i2c->adap.dev, "send cmd count:%d %d\n", | ||
546 | i2c->cmd, i2c->cmd_buf[i2c->cmd]); | ||
547 | dev_err(&i2c->adap.dev, "receive data count:%d %d\n", | ||
548 | i2c->cmd, i2c->data_buf[i2c->cmd]); | ||
549 | |||
550 | for (i = 0; i < 16; i++) { | ||
551 | if (src & BIT(i)) | ||
552 | dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n", | ||
553 | i, jz4780_i2c_abrt_src[i]); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, | ||
558 | unsigned char *buf, int len, int cnt, | ||
559 | int idx) | ||
560 | { | ||
561 | int ret = 0; | ||
562 | long timeout; | ||
563 | int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); | ||
564 | unsigned short tmp; | ||
565 | unsigned long flags; | ||
566 | |||
567 | memset(buf, 0, len); | ||
568 | |||
569 | spin_lock_irqsave(&i2c->lock, flags); | ||
570 | |||
571 | i2c->stop_hold = 0; | ||
572 | i2c->is_write = 0; | ||
573 | i2c->rbuf = buf; | ||
574 | i2c->rd_total_len = len; | ||
575 | i2c->rd_data_xfered = 0; | ||
576 | i2c->rd_cmd_xfered = 0; | ||
577 | |||
578 | if (len <= JZ4780_I2C_FIFO_LEN) | ||
579 | jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1); | ||
580 | else | ||
581 | jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL); | ||
582 | |||
583 | jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); | ||
584 | |||
585 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, | ||
586 | JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP | ||
587 | | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF); | ||
588 | |||
589 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
590 | tmp |= JZ4780_I2C_CTRL_STPHLD; | ||
591 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
592 | |||
593 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
594 | |||
595 | timeout = wait_for_completion_timeout(&i2c->trans_waitq, | ||
596 | msecs_to_jiffies(wait_time)); | ||
597 | |||
598 | if (!timeout) { | ||
599 | dev_err(&i2c->adap.dev, "irq read timeout\n"); | ||
600 | dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n", | ||
601 | i2c->cmd, i2c->cmd_buf[i2c->cmd]); | ||
602 | dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n", | ||
603 | i2c->cmd, i2c->data_buf[i2c->cmd]); | ||
604 | ret = -EIO; | ||
605 | } | ||
606 | |||
607 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); | ||
608 | if (tmp) { | ||
609 | jz4780_i2c_txabrt(i2c, tmp); | ||
610 | ret = -EIO; | ||
611 | } | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, | ||
617 | unsigned char *buf, int len, | ||
618 | int cnt, int idx) | ||
619 | { | ||
620 | int ret = 0; | ||
621 | int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); | ||
622 | long timeout; | ||
623 | unsigned short tmp; | ||
624 | unsigned long flags; | ||
625 | |||
626 | spin_lock_irqsave(&i2c->lock, flags); | ||
627 | |||
628 | if (idx < (cnt - 1)) | ||
629 | i2c->stop_hold = 1; | ||
630 | else | ||
631 | i2c->stop_hold = 0; | ||
632 | |||
633 | i2c->is_write = 1; | ||
634 | i2c->wbuf = buf; | ||
635 | i2c->wt_len = len; | ||
636 | |||
637 | jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL); | ||
638 | |||
639 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP | ||
640 | | JZ4780_I2C_INTM_MTXABT); | ||
641 | |||
642 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
643 | tmp |= JZ4780_I2C_CTRL_STPHLD; | ||
644 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
645 | |||
646 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
647 | |||
648 | timeout = wait_for_completion_timeout(&i2c->trans_waitq, | ||
649 | msecs_to_jiffies(wait_time)); | ||
650 | if (timeout && !i2c->stop_hold) { | ||
651 | unsigned short i2c_sta; | ||
652 | int write_in_process; | ||
653 | |||
654 | timeout = JZ4780_I2C_TIMEOUT * 100; | ||
655 | for (; timeout > 0; timeout--) { | ||
656 | i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); | ||
657 | |||
658 | write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) || | ||
659 | !(i2c_sta & JZ4780_I2C_STA_TFE); | ||
660 | if (!write_in_process) | ||
661 | break; | ||
662 | udelay(10); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | if (!timeout) { | ||
667 | dev_err(&i2c->adap.dev, "write wait timeout\n"); | ||
668 | ret = -EIO; | ||
669 | } | ||
670 | |||
671 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT); | ||
672 | if (tmp) { | ||
673 | jz4780_i2c_txabrt(i2c, tmp); | ||
674 | ret = -EIO; | ||
675 | } | ||
676 | |||
677 | return ret; | ||
678 | } | ||
679 | |||
680 | static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, | ||
681 | int count) | ||
682 | { | ||
683 | int i = -EIO; | ||
684 | int ret = 0; | ||
685 | struct jz4780_i2c *i2c = adap->algo_data; | ||
686 | |||
687 | ret = jz4780_i2c_prepare(i2c); | ||
688 | if (ret) { | ||
689 | dev_err(&i2c->adap.dev, "I2C prepare failed\n"); | ||
690 | goto out; | ||
691 | } | ||
692 | |||
693 | if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) { | ||
694 | ret = jz4780_i2c_set_target(i2c, msg->addr); | ||
695 | if (ret) | ||
696 | goto out; | ||
697 | } | ||
698 | for (i = 0; i < count; i++, msg++) { | ||
699 | if (msg->flags & I2C_M_RD) | ||
700 | ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len, | ||
701 | count, i); | ||
702 | else | ||
703 | ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len, | ||
704 | count, i); | ||
705 | |||
706 | if (ret) | ||
707 | goto out; | ||
708 | } | ||
709 | |||
710 | ret = i; | ||
711 | |||
712 | out: | ||
713 | jz4780_i2c_cleanup(i2c); | ||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static u32 jz4780_i2c_functionality(struct i2c_adapter *adap) | ||
718 | { | ||
719 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
720 | } | ||
721 | |||
722 | static const struct i2c_algorithm jz4780_i2c_algorithm = { | ||
723 | .master_xfer = jz4780_i2c_xfer, | ||
724 | .functionality = jz4780_i2c_functionality, | ||
725 | }; | ||
726 | |||
727 | static const struct of_device_id jz4780_i2c_of_matches[] = { | ||
728 | { .compatible = "ingenic,jz4780-i2c", }, | ||
729 | { /* sentinel */ } | ||
730 | }; | ||
731 | |||
732 | static int jz4780_i2c_probe(struct platform_device *pdev) | ||
733 | { | ||
734 | int ret = 0; | ||
735 | unsigned int clk_freq = 0; | ||
736 | unsigned short tmp; | ||
737 | struct resource *r; | ||
738 | struct jz4780_i2c *i2c; | ||
739 | |||
740 | i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL); | ||
741 | if (!i2c) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | i2c->adap.owner = THIS_MODULE; | ||
745 | i2c->adap.algo = &jz4780_i2c_algorithm; | ||
746 | i2c->adap.algo_data = i2c; | ||
747 | i2c->adap.retries = 5; | ||
748 | i2c->adap.dev.parent = &pdev->dev; | ||
749 | i2c->adap.dev.of_node = pdev->dev.of_node; | ||
750 | sprintf(i2c->adap.name, "%s", pdev->name); | ||
751 | |||
752 | init_completion(&i2c->trans_waitq); | ||
753 | spin_lock_init(&i2c->lock); | ||
754 | |||
755 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
756 | i2c->iomem = devm_ioremap_resource(&pdev->dev, r); | ||
757 | if (IS_ERR(i2c->iomem)) | ||
758 | return PTR_ERR(i2c->iomem); | ||
759 | |||
760 | platform_set_drvdata(pdev, i2c); | ||
761 | |||
762 | i2c->clk = devm_clk_get(&pdev->dev, NULL); | ||
763 | if (IS_ERR(i2c->clk)) | ||
764 | return PTR_ERR(i2c->clk); | ||
765 | |||
766 | clk_prepare_enable(i2c->clk); | ||
767 | |||
768 | if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
769 | &clk_freq)) { | ||
770 | dev_err(&pdev->dev, "clock-frequency not specified in DT"); | ||
771 | return clk_freq; | ||
772 | } | ||
773 | |||
774 | i2c->speed = clk_freq / 1000; | ||
775 | jz4780_i2c_set_speed(i2c); | ||
776 | |||
777 | dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed); | ||
778 | |||
779 | tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL); | ||
780 | tmp &= ~JZ4780_I2C_CTRL_STPHLD; | ||
781 | jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp); | ||
782 | |||
783 | jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); | ||
784 | |||
785 | i2c->cmd = 0; | ||
786 | memset(i2c->cmd_buf, 0, BUFSIZE); | ||
787 | memset(i2c->data_buf, 0, BUFSIZE); | ||
788 | |||
789 | i2c->irq = platform_get_irq(pdev, 0); | ||
790 | ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, | ||
791 | dev_name(&pdev->dev), i2c); | ||
792 | if (ret) { | ||
793 | ret = -ENODEV; | ||
794 | goto err; | ||
795 | } | ||
796 | |||
797 | ret = i2c_add_adapter(&i2c->adap); | ||
798 | if (ret < 0) { | ||
799 | dev_err(&pdev->dev, "Failed to add bus\n"); | ||
800 | goto err; | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | |||
805 | err: | ||
806 | clk_disable_unprepare(i2c->clk); | ||
807 | return ret; | ||
808 | } | ||
809 | |||
810 | static int jz4780_i2c_remove(struct platform_device *pdev) | ||
811 | { | ||
812 | struct jz4780_i2c *i2c = platform_get_drvdata(pdev); | ||
813 | |||
814 | clk_disable_unprepare(i2c->clk); | ||
815 | i2c_del_adapter(&i2c->adap); | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | static struct platform_driver jz4780_i2c_driver = { | ||
820 | .probe = jz4780_i2c_probe, | ||
821 | .remove = jz4780_i2c_remove, | ||
822 | .driver = { | ||
823 | .name = "jz4780-i2c", | ||
824 | .of_match_table = of_match_ptr(jz4780_i2c_of_matches), | ||
825 | }, | ||
826 | }; | ||
827 | |||
828 | module_platform_driver(jz4780_i2c_driver); | ||
829 | |||
830 | MODULE_LICENSE("GPL"); | ||
831 | MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>"); | ||
832 | MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs"); | ||