aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLars Poeschel <poeschel@lemonage.de>2012-11-19 10:36:04 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2012-11-20 06:21:13 -0500
commit174a13aa8669331605b138aaf61569dd7189e453 (patch)
tree58b52bc238649f070b41a0d3ec7c71dea98aed9b /drivers/i2c
parent9d5b72de0d1627b130fa69c5edf58b5b2df4ca50 (diff)
i2c: Add viperboard i2c master driver
This adds the mfd cell to use the i2c part of the Nano River Technologies viperboard as i2c master. Signed-off-by: Lars Poeschel <poeschel@lemonage.de> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
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-viperboard.c480
3 files changed, 491 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e9df4612b7eb..c7bff51fe524 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -818,6 +818,16 @@ config I2C_TINY_USB
818 This driver can also be built as a module. If so, the module 818 This driver can also be built as a module. If so, the module
819 will be called i2c-tiny-usb. 819 will be called i2c-tiny-usb.
820 820
821config I2C_VIPERBOARD
822 tristate "Viperboard I2C master support"
823 depends on MFD_VIPERBOARD && USB
824 help
825 Say yes here to access the I2C part of the Nano River
826 Technologies Viperboard as I2C master.
827 See viperboard API specification and Nano
828 River Tech's viperboard.h for detailed meaning
829 of the module parameters.
830
821comment "Other I2C/SMBus bus drivers" 831comment "Other I2C/SMBus bus drivers"
822 832
823config I2C_ACORN 833config I2C_ACORN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 395b516ffa08..e5cb209d276c 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
79obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o 79obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
80obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o 80obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
81obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o 81obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
82obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o
82 83
83# Other I2C/SMBus bus drivers 84# Other I2C/SMBus bus drivers
84obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o 85obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
new file mode 100644
index 000000000000..f5fa20dea906
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -0,0 +1,480 @@
1/*
2 * Nano River Technologies viperboard i2c master driver
3 *
4 * (C) 2012 by Lemonage GmbH
5 * Author: Lars Poeschel <poeschel@lemonage.de>
6 * All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/types.h>
20#include <linux/mutex.h>
21#include <linux/platform_device.h>
22
23#include <linux/usb.h>
24#include <linux/i2c.h>
25
26#include <linux/mfd/viperboard.h>
27
28struct vprbrd_i2c {
29 struct i2c_adapter i2c;
30 u8 bus_freq_param;
31};
32
33/* i2c bus frequency module parameter */
34static u8 i2c_bus_param;
35static unsigned int i2c_bus_freq = 100;
36module_param(i2c_bus_freq, int, 0);
37MODULE_PARM_DESC(i2c_bus_freq,
38 "i2c bus frequency in khz (default is 100) valid values: 10, 100, 200, 400, 1000, 3000, 6000");
39
40static int vprbrd_i2c_status(struct i2c_adapter *i2c,
41 struct vprbrd_i2c_status *status, bool prev_error)
42{
43 u16 bytes_xfer;
44 int ret;
45 struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
46
47 /* check for protocol error */
48 bytes_xfer = sizeof(struct vprbrd_i2c_status);
49
50 ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
51 VPRBRD_USB_REQUEST_I2C, VPRBRD_USB_TYPE_IN, 0x0000, 0x0000,
52 status, bytes_xfer, VPRBRD_USB_TIMEOUT_MS);
53
54 if (ret != bytes_xfer)
55 prev_error = true;
56
57 if (prev_error) {
58 dev_err(&i2c->dev, "failure in usb communication\n");
59 return -EREMOTEIO;
60 }
61
62 dev_dbg(&i2c->dev, " status = %d\n", status->status);
63 if (status->status != 0x00) {
64 dev_err(&i2c->dev, "failure: i2c protocol error\n");
65 return -EPROTO;
66 }
67 return 0;
68}
69
70static int vprbrd_i2c_receive(struct usb_device *usb_dev,
71 struct vprbrd_i2c_read_msg *rmsg, int bytes_xfer)
72{
73 int ret, bytes_actual;
74 int error = 0;
75
76 /* send the read request */
77 ret = usb_bulk_msg(usb_dev,
78 usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), rmsg,
79 sizeof(struct vprbrd_i2c_read_hdr), &bytes_actual,
80 VPRBRD_USB_TIMEOUT_MS);
81
82 if ((ret < 0)
83 || (bytes_actual != sizeof(struct vprbrd_i2c_read_hdr))) {
84 dev_err(&usb_dev->dev, "failure transmitting usb\n");
85 error = -EREMOTEIO;
86 }
87
88 /* read the actual data */
89 ret = usb_bulk_msg(usb_dev,
90 usb_rcvbulkpipe(usb_dev, VPRBRD_EP_IN), rmsg,
91 bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
92
93 if ((ret < 0) || (bytes_xfer != bytes_actual)) {
94 dev_err(&usb_dev->dev, "failure receiving usb\n");
95 error = -EREMOTEIO;
96 }
97 return error;
98}
99
100static int vprbrd_i2c_addr(struct usb_device *usb_dev,
101 struct vprbrd_i2c_addr_msg *amsg)
102{
103 int ret, bytes_actual;
104
105 ret = usb_bulk_msg(usb_dev,
106 usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), amsg,
107 sizeof(struct vprbrd_i2c_addr_msg), &bytes_actual,
108 VPRBRD_USB_TIMEOUT_MS);
109
110 if ((ret < 0) ||
111 (sizeof(struct vprbrd_i2c_addr_msg) != bytes_actual)) {
112 dev_err(&usb_dev->dev, "failure transmitting usb\n");
113 return -EREMOTEIO;
114 }
115 return 0;
116}
117
118static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
119{
120 int ret;
121 u16 remain_len, bytes_xfer, len1, len2,
122 start = 0x0000;
123 struct vprbrd_i2c_read_msg *rmsg =
124 (struct vprbrd_i2c_read_msg *)vb->buf;
125
126 remain_len = msg->len;
127 rmsg->header.cmd = VPRBRD_I2C_CMD_READ;
128 while (remain_len > 0) {
129 rmsg->header.addr = cpu_to_le16(start + 0x4000);
130 if (remain_len <= 255) {
131 len1 = remain_len;
132 len2 = 0x00;
133 rmsg->header.len0 = remain_len;
134 rmsg->header.len1 = 0x00;
135 rmsg->header.len2 = 0x00;
136 rmsg->header.len3 = 0x00;
137 rmsg->header.len4 = 0x00;
138 rmsg->header.len5 = 0x00;
139 remain_len = 0;
140 } else if (remain_len <= 510) {
141 len1 = remain_len;
142 len2 = 0x00;
143 rmsg->header.len0 = remain_len - 255;
144 rmsg->header.len1 = 0xff;
145 rmsg->header.len2 = 0x00;
146 rmsg->header.len3 = 0x00;
147 rmsg->header.len4 = 0x00;
148 rmsg->header.len5 = 0x00;
149 remain_len = 0;
150 } else if (remain_len <= 512) {
151 len1 = remain_len;
152 len2 = 0x00;
153 rmsg->header.len0 = remain_len - 510;
154 rmsg->header.len1 = 0xff;
155 rmsg->header.len2 = 0xff;
156 rmsg->header.len3 = 0x00;
157 rmsg->header.len4 = 0x00;
158 rmsg->header.len5 = 0x00;
159 remain_len = 0;
160 } else if (remain_len <= 767) {
161 len1 = 512;
162 len2 = remain_len - 512;
163 rmsg->header.len0 = 0x02;
164 rmsg->header.len1 = 0xff;
165 rmsg->header.len2 = 0xff;
166 rmsg->header.len3 = remain_len - 512;
167 rmsg->header.len4 = 0x00;
168 rmsg->header.len5 = 0x00;
169 bytes_xfer = remain_len;
170 remain_len = 0;
171 } else if (remain_len <= 1022) {
172 len1 = 512;
173 len2 = remain_len - 512;
174 rmsg->header.len0 = 0x02;
175 rmsg->header.len1 = 0xff;
176 rmsg->header.len2 = 0xff;
177 rmsg->header.len3 = remain_len - 767;
178 rmsg->header.len4 = 0xff;
179 rmsg->header.len5 = 0x00;
180 remain_len = 0;
181 } else if (remain_len <= 1024) {
182 len1 = 512;
183 len2 = remain_len - 512;
184 rmsg->header.len0 = 0x02;
185 rmsg->header.len1 = 0xff;
186 rmsg->header.len2 = 0xff;
187 rmsg->header.len3 = remain_len - 1022;
188 rmsg->header.len4 = 0xff;
189 rmsg->header.len5 = 0xff;
190 remain_len = 0;
191 } else {
192 len1 = 512;
193 len2 = 512;
194 rmsg->header.len0 = 0x02;
195 rmsg->header.len1 = 0xff;
196 rmsg->header.len2 = 0xff;
197 rmsg->header.len3 = 0x02;
198 rmsg->header.len4 = 0xff;
199 rmsg->header.len5 = 0xff;
200 remain_len -= 1024;
201 start += 1024;
202 }
203 rmsg->header.tf1 = cpu_to_le16(len1);
204 rmsg->header.tf2 = cpu_to_le16(len2);
205
206 /* first read transfer */
207 ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len1);
208 if (ret < 0)
209 return ret;
210 /* copy the received data */
211 memcpy(msg->buf + start, rmsg, len1);
212
213 /* second read transfer if neccessary */
214 if (len2 > 0) {
215 ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2);
216 if (ret < 0)
217 return ret;
218 /* copy the received data */
219 memcpy(msg->buf + start + 512, rmsg, len2);
220 }
221 }
222 return 0;
223}
224
225static int vprbrd_i2c_write(struct vprbrd *vb, struct i2c_msg *msg)
226{
227 int ret, bytes_actual;
228 u16 remain_len, bytes_xfer,
229 start = 0x0000;
230 struct vprbrd_i2c_write_msg *wmsg =
231 (struct vprbrd_i2c_write_msg *)vb->buf;
232
233 remain_len = msg->len;
234 wmsg->header.cmd = VPRBRD_I2C_CMD_WRITE;
235 wmsg->header.last = 0x00;
236 wmsg->header.chan = 0x00;
237 wmsg->header.spi = 0x0000;
238 while (remain_len > 0) {
239 wmsg->header.addr = cpu_to_le16(start + 0x4000);
240 if (remain_len > 503) {
241 wmsg->header.len1 = 0xff;
242 wmsg->header.len2 = 0xf8;
243 remain_len -= 503;
244 bytes_xfer = 503 + sizeof(struct vprbrd_i2c_write_hdr);
245 start += 503;
246 } else if (remain_len > 255) {
247 wmsg->header.len1 = 0xff;
248 wmsg->header.len2 = (remain_len - 255);
249 bytes_xfer = remain_len +
250 sizeof(struct vprbrd_i2c_write_hdr);
251 remain_len = 0;
252 } else {
253 wmsg->header.len1 = remain_len;
254 wmsg->header.len2 = 0x00;
255 bytes_xfer = remain_len +
256 sizeof(struct vprbrd_i2c_write_hdr);
257 remain_len = 0;
258 }
259 memcpy(wmsg->data, msg->buf + start,
260 bytes_xfer - sizeof(struct vprbrd_i2c_write_hdr));
261
262 ret = usb_bulk_msg(vb->usb_dev,
263 usb_sndbulkpipe(vb->usb_dev,
264 VPRBRD_EP_OUT), wmsg,
265 bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
266 if ((ret < 0) || (bytes_xfer != bytes_actual))
267 return -EREMOTEIO;
268 }
269 return 0;
270}
271
272static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
273 int num)
274{
275 struct i2c_msg *pmsg;
276 int i, ret,
277 error = 0;
278 struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
279 struct vprbrd_i2c_addr_msg *amsg =
280 (struct vprbrd_i2c_addr_msg *)vb->buf;
281 struct vprbrd_i2c_status *smsg = (struct vprbrd_i2c_status *)vb->buf;
282
283 dev_dbg(&i2c->dev, "master xfer %d messages:\n", num);
284
285 for (i = 0 ; i < num ; i++) {
286 pmsg = &msgs[i];
287
288 dev_dbg(&i2c->dev,
289 " %d: %s (flags %d) %d bytes to 0x%02x\n",
290 i, pmsg->flags & I2C_M_RD ? "read" : "write",
291 pmsg->flags, pmsg->len, pmsg->addr);
292
293 /* msgs longer than 2048 bytes are not supported by adapter */
294 if (pmsg->len > 2048)
295 return -EINVAL;
296
297 mutex_lock(&vb->lock);
298 /* directly send the message */
299 if (pmsg->flags & I2C_M_RD) {
300 /* read data */
301 amsg->cmd = VPRBRD_I2C_CMD_ADDR;
302 amsg->unknown2 = 0x00;
303 amsg->unknown3 = 0x00;
304 amsg->addr = pmsg->addr;
305 amsg->unknown1 = 0x01;
306 amsg->len = cpu_to_le16(pmsg->len);
307 /* send the addr and len, we're interested to board */
308 ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
309 if (ret < 0)
310 error = ret;
311
312 ret = vprbrd_i2c_read(vb, pmsg);
313 if (ret < 0)
314 error = ret;
315
316 ret = vprbrd_i2c_status(i2c, smsg, error);
317 if (ret < 0)
318 error = ret;
319 /* in case of protocol error, return the error */
320 if (error < 0)
321 goto error;
322 } else {
323 /* write data */
324 ret = vprbrd_i2c_write(vb, pmsg);
325
326 amsg->cmd = VPRBRD_I2C_CMD_ADDR;
327 amsg->unknown2 = 0x00;
328 amsg->unknown3 = 0x00;
329 amsg->addr = pmsg->addr;
330 amsg->unknown1 = 0x00;
331 amsg->len = cpu_to_le16(pmsg->len);
332 /* send the addr, the data goes to to board */
333 ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
334 if (ret < 0)
335 error = ret;
336
337 ret = vprbrd_i2c_status(i2c, smsg, error);
338 if (ret < 0)
339 error = ret;
340
341 if (error < 0)
342 goto error;
343 }
344 mutex_unlock(&vb->lock);
345 }
346 return 0;
347error:
348 mutex_unlock(&vb->lock);
349 return error;
350}
351
352static u32 vprbrd_i2c_func(struct i2c_adapter *i2c)
353{
354 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
355}
356
357/* This is the actual algorithm we define */
358static const struct i2c_algorithm vprbrd_algorithm = {
359 .master_xfer = vprbrd_i2c_xfer,
360 .functionality = vprbrd_i2c_func,
361};
362
363static int __devinit vprbrd_i2c_probe(struct platform_device *pdev)
364{
365 struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
366 struct vprbrd_i2c *vb_i2c;
367 int ret;
368 int pipe;
369
370 vb_i2c = kzalloc(sizeof(*vb_i2c), GFP_KERNEL);
371 if (vb_i2c == NULL)
372 return -ENOMEM;
373
374 /* setup i2c adapter description */
375 vb_i2c->i2c.owner = THIS_MODULE;
376 vb_i2c->i2c.class = I2C_CLASS_HWMON;
377 vb_i2c->i2c.algo = &vprbrd_algorithm;
378 vb_i2c->i2c.algo_data = vb;
379 /* save the param in usb capabable memory */
380 vb_i2c->bus_freq_param = i2c_bus_param;
381
382 snprintf(vb_i2c->i2c.name, sizeof(vb_i2c->i2c.name),
383 "viperboard at bus %03d device %03d",
384 vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
385
386 /* setting the bus frequency */
387 if ((i2c_bus_param <= VPRBRD_I2C_FREQ_10KHZ)
388 && (i2c_bus_param >= VPRBRD_I2C_FREQ_6MHZ)) {
389 pipe = usb_sndctrlpipe(vb->usb_dev, 0);
390 ret = usb_control_msg(vb->usb_dev, pipe,
391 VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT,
392 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1,
393 VPRBRD_USB_TIMEOUT_MS);
394 if (ret != 1) {
395 dev_err(&pdev->dev,
396 "failure setting i2c_bus_freq to %d\n", i2c_bus_freq);
397 ret = -EIO;
398 goto error;
399 }
400 } else {
401 dev_err(&pdev->dev,
402 "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq);
403 ret = -EIO;
404 goto error;
405 }
406
407 vb_i2c->i2c.dev.parent = &pdev->dev;
408
409 /* attach to i2c layer */
410 i2c_add_adapter(&vb_i2c->i2c);
411
412 platform_set_drvdata(pdev, vb_i2c);
413
414 return 0;
415
416error:
417 kfree(vb_i2c);
418 return ret;
419}
420
421static int __devexit vprbrd_i2c_remove(struct platform_device *pdev)
422{
423 struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev);
424 int ret;
425
426 ret = i2c_del_adapter(&vb_i2c->i2c);
427
428 return ret;
429}
430
431static struct platform_driver vprbrd_i2c_driver = {
432 .driver.name = "viperboard-i2c",
433 .driver.owner = THIS_MODULE,
434 .probe = vprbrd_i2c_probe,
435 .remove = __devexit_p(vprbrd_i2c_remove),
436};
437
438static int __init vprbrd_i2c_init(void)
439{
440 switch (i2c_bus_freq) {
441 case 6000:
442 i2c_bus_param = VPRBRD_I2C_FREQ_6MHZ;
443 break;
444 case 3000:
445 i2c_bus_param = VPRBRD_I2C_FREQ_3MHZ;
446 break;
447 case 1000:
448 i2c_bus_param = VPRBRD_I2C_FREQ_1MHZ;
449 break;
450 case 400:
451 i2c_bus_param = VPRBRD_I2C_FREQ_400KHZ;
452 break;
453 case 200:
454 i2c_bus_param = VPRBRD_I2C_FREQ_200KHZ;
455 break;
456 case 100:
457 i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
458 break;
459 case 10:
460 i2c_bus_param = VPRBRD_I2C_FREQ_10KHZ;
461 break;
462 default:
463 pr_warn("invalid i2c_bus_freq (%d)\n", i2c_bus_freq);
464 i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
465 }
466
467 return platform_driver_register(&vprbrd_i2c_driver);
468}
469subsys_initcall(vprbrd_i2c_init);
470
471static void __exit vprbrd_i2c_exit(void)
472{
473 platform_driver_unregister(&vprbrd_i2c_driver);
474}
475module_exit(vprbrd_i2c_exit);
476
477MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
478MODULE_DESCRIPTION("I2C master driver for Nano River Techs Viperboard");
479MODULE_LICENSE("GPL");
480MODULE_ALIAS("platform:viperboard-i2c");