aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2011-02-16 07:39:16 -0500
committerBen Dooks <ben-linux@fluff.org>2011-02-22 20:00:11 -0500
commita8da7fecb6010222fe495cc2b4330b99bca20c61 (patch)
tree728fd5746e1ce0ad78c809f1dcf6f9c95fddf5b1 /drivers/i2c
parentd8204a37baf5474d3154eb536c936369be2bd5c0 (diff)
i2c: add driver for Freescale i.MX28
Currently only supporting the PIOQUEUE-mode, because DMA-support for this platform is not yet in mainline. When it becomes available and support has been added to this driver, it will also be suitable for i.MX23 and STMP3xxx. Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Cc: Ben Dooks <ben-linux@fluff.org> Cc: Shawn Guo <shawn.guo@freescale.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-mxs.c412
3 files changed, 423 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 113505a6434e..e08e8356bdb5 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -452,6 +452,16 @@ config I2C_MV64XXX
452 This driver can also be built as a module. If so, the module 452 This driver can also be built as a module. If so, the module
453 will be called i2c-mv64xxx. 453 will be called i2c-mv64xxx.
454 454
455config I2C_MXS
456 tristate "Freescale i.MX28 I2C interface"
457 depends on SOC_IMX28
458 help
459 Say Y here if you want to use the I2C bus controller on
460 the Freescale i.MX28 processors.
461
462 This driver can also be built as a module. If so, the module
463 will be called i2c-mxs.
464
455config I2C_NOMADIK 465config I2C_NOMADIK
456 tristate "ST-Ericsson Nomadik/Ux500 I2C Controller" 466 tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
457 depends on PLAT_NOMADIK 467 depends on PLAT_NOMADIK
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 9d2d0ec7fb23..77cf7e6447fc 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
43obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o 43obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
44obj-$(CONFIG_I2C_MPC) += i2c-mpc.o 44obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
45obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o 45obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
46obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
46obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o 47obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
47obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o 48obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o
48obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o 49obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
new file mode 100644
index 000000000000..8022e2390a5a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -0,0 +1,412 @@
1/*
2 * Freescale MXS I2C bus driver
3 *
4 * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
5 *
6 * based on a (non-working) driver which was:
7 *
8 * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
9 *
10 * TODO: add dma-support if platform-support for it is available
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 */
18
19#include <linux/slab.h>
20#include <linux/device.h>
21#include <linux/module.h>
22#include <linux/i2c.h>
23#include <linux/err.h>
24#include <linux/interrupt.h>
25#include <linux/completion.h>
26#include <linux/platform_device.h>
27#include <linux/jiffies.h>
28#include <linux/io.h>
29
30#include <mach/common.h>
31
32#define DRIVER_NAME "mxs-i2c"
33
34#define MXS_I2C_CTRL0 (0x00)
35#define MXS_I2C_CTRL0_SET (0x04)
36
37#define MXS_I2C_CTRL0_SFTRST 0x80000000
38#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
39#define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000
40#define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000
41#define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000
42#define MXS_I2C_CTRL0_MASTER_MODE 0x00020000
43#define MXS_I2C_CTRL0_DIRECTION 0x00010000
44#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
45
46#define MXS_I2C_CTRL1 (0x40)
47#define MXS_I2C_CTRL1_SET (0x44)
48#define MXS_I2C_CTRL1_CLR (0x48)
49
50#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80
51#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40
52#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20
53#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x10
54#define MXS_I2C_CTRL1_EARLY_TERM_IRQ 0x08
55#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ 0x04
56#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02
57#define MXS_I2C_CTRL1_SLAVE_IRQ 0x01
58
59#define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \
60 MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \
61 MXS_I2C_CTRL1_EARLY_TERM_IRQ | \
62 MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \
63 MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
64 MXS_I2C_CTRL1_SLAVE_IRQ)
65
66#define MXS_I2C_QUEUECTRL (0x60)
67#define MXS_I2C_QUEUECTRL_SET (0x64)
68#define MXS_I2C_QUEUECTRL_CLR (0x68)
69
70#define MXS_I2C_QUEUECTRL_QUEUE_RUN 0x20
71#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE 0x04
72
73#define MXS_I2C_QUEUESTAT (0x70)
74#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000
75
76#define MXS_I2C_QUEUECMD (0x80)
77
78#define MXS_I2C_QUEUEDATA (0x90)
79
80#define MXS_I2C_DATA (0xa0)
81
82
83#define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \
84 MXS_I2C_CTRL0_PRE_SEND_START | \
85 MXS_I2C_CTRL0_MASTER_MODE | \
86 MXS_I2C_CTRL0_DIRECTION | \
87 MXS_I2C_CTRL0_XFER_COUNT(1))
88
89#define MXS_CMD_I2C_WRITE (MXS_I2C_CTRL0_PRE_SEND_START | \
90 MXS_I2C_CTRL0_MASTER_MODE | \
91 MXS_I2C_CTRL0_DIRECTION)
92
93#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
94 MXS_I2C_CTRL0_MASTER_MODE)
95
96/**
97 * struct mxs_i2c_dev - per device, private MXS-I2C data
98 *
99 * @dev: driver model device node
100 * @regs: IO registers pointer
101 * @cmd_complete: completion object for transaction wait
102 * @cmd_err: error code for last transaction
103 * @adapter: i2c subsystem adapter node
104 */
105struct mxs_i2c_dev {
106 struct device *dev;
107 void __iomem *regs;
108 struct completion cmd_complete;
109 u32 cmd_err;
110 struct i2c_adapter adapter;
111};
112
113/*
114 * TODO: check if calls to here are really needed. If not, we could get rid of
115 * mxs_reset_block and the mach-dependency. Needs an I2C analyzer, probably.
116 */
117static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
118{
119 mxs_reset_block(i2c->regs);
120 writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
121}
122
123static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
124 int flags)
125{
126 u32 data;
127
128 writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD);
129
130 data = (addr << 1) | I2C_SMBUS_READ;
131 writel(data, i2c->regs + MXS_I2C_DATA);
132
133 data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags;
134 writel(data, i2c->regs + MXS_I2C_QUEUECMD);
135}
136
137static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c,
138 u8 addr, u8 *buf, int len, int flags)
139{
140 u32 data;
141 int i, shifts_left;
142
143 data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
144 writel(data, i2c->regs + MXS_I2C_QUEUECMD);
145
146 /*
147 * We have to copy the slave address (u8) and buffer (arbitrary number
148 * of u8) into the data register (u32). To achieve that, the u8 are put
149 * into the MSBs of 'data' which is then shifted for the next u8. When
150 * apropriate, 'data' is written to MXS_I2C_DATA. So, the first u32
151 * looks like this:
152 *
153 * 3 2 1 0
154 * 10987654|32109876|54321098|76543210
155 * --------+--------+--------+--------
156 * buffer+2|buffer+1|buffer+0|slave_addr
157 */
158
159 data = ((addr << 1) | I2C_SMBUS_WRITE) << 24;
160
161 for (i = 0; i < len; i++) {
162 data >>= 8;
163 data |= buf[i] << 24;
164 if ((i & 3) == 2)
165 writel(data, i2c->regs + MXS_I2C_DATA);
166 }
167
168 /* Write out the remaining bytes if any */
169 shifts_left = 24 - (i & 3) * 8;
170 if (shifts_left)
171 writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA);
172}
173
174/*
175 * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the
176 * rd_threshold to 1). Couldn't get this to work, though.
177 */
178static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
179{
180 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
181
182 while (readl(i2c->regs + MXS_I2C_QUEUESTAT)
183 & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) {
184 if (time_after(jiffies, timeout))
185 return -ETIMEDOUT;
186 cond_resched();
187 }
188
189 return 0;
190}
191
192static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
193{
194 u32 data;
195 int i;
196
197 for (i = 0; i < len; i++) {
198 if ((i & 3) == 0) {
199 if (mxs_i2c_wait_for_data(i2c))
200 return -ETIMEDOUT;
201 data = readl(i2c->regs + MXS_I2C_QUEUEDATA);
202 }
203 buf[i] = data & 0xff;
204 data >>= 8;
205 }
206
207 return 0;
208}
209
210/*
211 * Low level master read/write transaction.
212 */
213static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
214 int stop)
215{
216 struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
217 int ret;
218 int flags;
219
220 init_completion(&i2c->cmd_complete);
221
222 dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
223 msg->addr, msg->len, msg->flags, stop);
224
225 if (msg->len == 0)
226 return -EINVAL;
227
228 flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
229
230 if (msg->flags & I2C_M_RD)
231 mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
232 else
233 mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
234 flags);
235
236 writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
237 i2c->regs + MXS_I2C_QUEUECTRL_SET);
238
239 ret = wait_for_completion_timeout(&i2c->cmd_complete,
240 msecs_to_jiffies(1000));
241 if (ret == 0)
242 goto timeout;
243
244 if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
245 ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
246 if (ret)
247 goto timeout;
248 }
249
250 if (i2c->cmd_err == -ENXIO)
251 mxs_i2c_reset(i2c);
252
253 dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err);
254
255 return i2c->cmd_err;
256
257timeout:
258 dev_dbg(i2c->dev, "Timeout!\n");
259 mxs_i2c_reset(i2c);
260 return -ETIMEDOUT;
261}
262
263static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
264 int num)
265{
266 int i;
267 int err;
268
269 for (i = 0; i < num; i++) {
270 err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1));
271 if (err)
272 return err;
273 }
274
275 return num;
276}
277
278static u32 mxs_i2c_func(struct i2c_adapter *adap)
279{
280 return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
281}
282
283static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
284{
285 struct mxs_i2c_dev *i2c = dev_id;
286 u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
287
288 if (!stat)
289 return IRQ_NONE;
290
291 if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
292 i2c->cmd_err = -ENXIO;
293 else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
294 MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
295 MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ))
296 /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
297 i2c->cmd_err = -EIO;
298 else
299 i2c->cmd_err = 0;
300
301 complete(&i2c->cmd_complete);
302
303 writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
304 return IRQ_HANDLED;
305}
306
307static const struct i2c_algorithm mxs_i2c_algo = {
308 .master_xfer = mxs_i2c_xfer,
309 .functionality = mxs_i2c_func,
310};
311
312static int __devinit mxs_i2c_probe(struct platform_device *pdev)
313{
314 struct device *dev = &pdev->dev;
315 struct mxs_i2c_dev *i2c;
316 struct i2c_adapter *adap;
317 struct resource *res;
318 resource_size_t res_size;
319 int err, irq;
320
321 i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
322 if (!i2c)
323 return -ENOMEM;
324
325 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
326 if (!res)
327 return -ENOENT;
328
329 res_size = resource_size(res);
330 if (!devm_request_mem_region(dev, res->start, res_size, res->name))
331 return -EBUSY;
332
333 i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
334 if (!i2c->regs)
335 return -EBUSY;
336
337 irq = platform_get_irq(pdev, 0);
338 if (irq < 0)
339 return irq;
340
341 err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
342 if (err)
343 return err;
344
345 i2c->dev = dev;
346 platform_set_drvdata(pdev, i2c);
347
348 /* Do reset to enforce correct startup after pinmuxing */
349 mxs_i2c_reset(i2c);
350 writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
351 i2c->regs + MXS_I2C_QUEUECTRL_SET);
352
353 adap = &i2c->adapter;
354 strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
355 adap->owner = THIS_MODULE;
356 adap->algo = &mxs_i2c_algo;
357 adap->dev.parent = dev;
358 adap->nr = pdev->id;
359 i2c_set_adapdata(adap, i2c);
360 err = i2c_add_numbered_adapter(adap);
361 if (err) {
362 dev_err(dev, "Failed to add adapter (%d)\n", err);
363 writel(MXS_I2C_CTRL0_SFTRST,
364 i2c->regs + MXS_I2C_CTRL0_SET);
365 return err;
366 }
367
368 return 0;
369}
370
371static int __devexit mxs_i2c_remove(struct platform_device *pdev)
372{
373 struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
374 int ret;
375
376 ret = i2c_del_adapter(&i2c->adapter);
377 if (ret)
378 return -EBUSY;
379
380 writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
381 i2c->regs + MXS_I2C_QUEUECTRL_CLR);
382 writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
383
384 platform_set_drvdata(pdev, NULL);
385
386 return 0;
387}
388
389static struct platform_driver mxs_i2c_driver = {
390 .driver = {
391 .name = DRIVER_NAME,
392 .owner = THIS_MODULE,
393 },
394 .remove = __devexit_p(mxs_i2c_remove),
395};
396
397static int __init mxs_i2c_init(void)
398{
399 return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
400}
401subsys_initcall(mxs_i2c_init);
402
403static void __exit mxs_i2c_exit(void)
404{
405 platform_driver_unregister(&mxs_i2c_driver);
406}
407module_exit(mxs_i2c_exit);
408
409MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
410MODULE_DESCRIPTION("MXS I2C Bus Driver");
411MODULE_LICENSE("GPL");
412MODULE_ALIAS("platform:" DRIVER_NAME);