aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorTill Harbaum <lists@harbaum.org>2007-05-01 17:26:35 -0400
committerJean Delvare <khali@hyperion.delvare>2007-05-01 17:26:35 -0400
commite8c76eed2ecdb8e9ca5339761d2c076d32b7cbca (patch)
tree1c03cab194b6a25d6a2fa159ff7798e9d17c4844 /drivers/i2c
parenteefcd75e72f382270f8f64e030550b10e3882b2b (diff)
i2c: New i2c-tiny-usb bus driver
Add a driver for the i2c-tiny-usb interface. This is a simple do-it-yourself USB to I2C interface targeted at experimental and home use. See the i2c-tiny-usb homepage for hardware details: http://www.harbaum.org/till/i2c_tiny_usb Signed-off-by: Till Harbaum <till@harbaum.org> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig11
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c277
3 files changed, 289 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e4f1a463f41a..838dc1c19d61 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -525,6 +525,17 @@ config I2C_STUB
525 525
526 If you don't know what to do here, definitely say N. 526 If you don't know what to do here, definitely say N.
527 527
528config I2C_TINY_USB
529 tristate "I2C-Tiny-USB"
530 depends on USB
531 help
532 If you say yes to this option, support will be included for the
533 i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
534 http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
535
536 This driver can also be built as a module. If so, the module
537 will be called i2c-tiny-usb.
538
528config I2C_VERSATILE 539config I2C_VERSATILE
529 tristate "ARM Versatile/Realview I2C bus support" 540 tristate "ARM Versatile/Realview I2C bus support"
530 depends on ARCH_VERSATILE || ARCH_REALVIEW 541 depends on ARCH_VERSATILE || ARCH_REALVIEW
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3a020ea8edef..14d1432f698b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
44obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o 44obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
45obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o 45obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
46obj-$(CONFIG_I2C_STUB) += i2c-stub.o 46obj-$(CONFIG_I2C_STUB) += i2c-stub.o
47obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
47obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o 48obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
48obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o 49obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
49obj-$(CONFIG_I2C_VIA) += i2c-via.o 50obj-$(CONFIG_I2C_VIA) += i2c-via.o
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 000000000000..907999049d50
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,277 @@
1/*
2 * driver for the i2c-tiny-usb adapter - 1.0
3 * http://www.harbaum.org/till/i2c_tiny_usb
4 *
5 * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2.
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/module.h>
16
17/* include interfaces to usb layer */
18#include <linux/usb.h>
19
20/* include interface to i2c layer */
21#include <linux/i2c.h>
22
23/* commands via USB, must match command ids in the firmware */
24#define CMD_ECHO 0
25#define CMD_GET_FUNC 1
26#define CMD_SET_DELAY 2
27#define CMD_GET_STATUS 3
28
29#define CMD_I2C_IO 4
30#define CMD_I2C_IO_BEGIN (1<<0)
31#define CMD_I2C_IO_END (1<<1)
32
33/* i2c bit delay, default is 10us -> 100kHz */
34static int delay = 10;
35module_param(delay, int, 0);
36MODULE_PARM_DESC(delay, "bit delay in microseconds, "
37 "e.g. 10 for 100kHz (default is 100kHz)");
38
39static int usb_read(struct i2c_adapter *adapter, int cmd,
40 int value, int index, void *data, int len);
41
42static int usb_write(struct i2c_adapter *adapter, int cmd,
43 int value, int index, void *data, int len);
44
45/* ----- begin of i2c layer ---------------------------------------------- */
46
47#define STATUS_IDLE 0
48#define STATUS_ADDRESS_ACK 1
49#define STATUS_ADDRESS_NAK 2
50
51static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
52{
53 unsigned char status;
54 struct i2c_msg *pmsg;
55 int i;
56
57 dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
58
59 for (i = 0 ; i < num ; i++) {
60 int cmd = CMD_I2C_IO;
61
62 if (i == 0)
63 cmd |= CMD_I2C_IO_BEGIN;
64
65 if (i == num-1)
66 cmd |= CMD_I2C_IO_END;
67
68 pmsg = &msgs[i];
69
70 dev_dbg(&adapter->dev,
71 " %d: %s (flags %d) %d bytes to 0x%02x\n",
72 i, pmsg->flags & I2C_M_RD ? "read" : "write",
73 pmsg->flags, pmsg->len, pmsg->addr);
74
75 /* and directly send the message */
76 if (pmsg->flags & I2C_M_RD) {
77 /* read data */
78 if (usb_read(adapter, cmd,
79 pmsg->flags, pmsg->addr,
80 pmsg->buf, pmsg->len) != pmsg->len) {
81 dev_err(&adapter->dev,
82 "failure reading data\n");
83 return -EREMOTEIO;
84 }
85 } else {
86 /* write data */
87 if (usb_write(adapter, cmd,
88 pmsg->flags, pmsg->addr,
89 pmsg->buf, pmsg->len) != pmsg->len) {
90 dev_err(&adapter->dev,
91 "failure writing data\n");
92 return -EREMOTEIO;
93 }
94 }
95
96 /* read status */
97 if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
98 dev_err(&adapter->dev, "failure reading status\n");
99 return -EREMOTEIO;
100 }
101
102 dev_dbg(&adapter->dev, " status = %d\n", status);
103 if (status == STATUS_ADDRESS_NAK)
104 return -EREMOTEIO;
105 }
106
107 return i;
108}
109
110static u32 usb_func(struct i2c_adapter *adapter)
111{
112 u32 func;
113
114 /* get functionality from adapter */
115 if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
116 sizeof(func)) {
117 dev_err(&adapter->dev, "failure reading functionality\n");
118 return 0;
119 }
120
121 return func;
122}
123
124/* This is the actual algorithm we define */
125static const struct i2c_algorithm usb_algorithm = {
126 .master_xfer = usb_xfer,
127 .functionality = usb_func,
128};
129
130/* ----- end of i2c layer ------------------------------------------------ */
131
132/* ----- begin of usb layer ---------------------------------------------- */
133
134/* The usb i2c interface uses a vid/pid pair donated by */
135/* Future Technology Devices International Ltd. */
136static struct usb_device_id i2c_tiny_usb_table [] = {
137 { USB_DEVICE(0x0403, 0xc631) },
138 { } /* Terminating entry */
139};
140
141MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
142
143/* Structure to hold all of our device specific stuff */
144struct i2c_tiny_usb {
145 struct usb_device *usb_dev; /* the usb device for this device */
146 struct usb_interface *interface; /* the interface for this device */
147 struct i2c_adapter adapter; /* i2c related things */
148};
149
150static int usb_read(struct i2c_adapter *adapter, int cmd,
151 int value, int index, void *data, int len)
152{
153 struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
154
155 /* do control transfer */
156 return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
157 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
158 USB_DIR_IN, value, index, data, len, 2000);
159}
160
161static int usb_write(struct i2c_adapter *adapter, int cmd,
162 int value, int index, void *data, int len)
163{
164 struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
165
166 /* do control transfer */
167 return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
168 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
169 value, index, data, len, 2000);
170}
171
172static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
173{
174 usb_put_dev(dev->usb_dev);
175 kfree(dev);
176}
177
178static int i2c_tiny_usb_probe(struct usb_interface *interface,
179 const struct usb_device_id *id)
180{
181 struct i2c_tiny_usb *dev;
182 int retval = -ENOMEM;
183 u16 version;
184
185 dev_dbg(&interface->dev, "probing usb device\n");
186
187 /* allocate memory for our device state and initialize it */
188 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
189 if (dev == NULL) {
190 dev_err(&interface->dev, "Out of memory\n");
191 goto error;
192 }
193
194 dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
195 dev->interface = interface;
196
197 /* save our data pointer in this interface device */
198 usb_set_intfdata(interface, dev);
199
200 version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
201 dev_info(&interface->dev,
202 "version %x.%02x found at bus %03d address %03d\n",
203 version >> 8, version & 0xff,
204 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
205
206 /* setup i2c adapter description */
207 dev->adapter.owner = THIS_MODULE;
208 dev->adapter.class = I2C_CLASS_HWMON;
209 dev->adapter.algo = &usb_algorithm;
210 dev->adapter.algo_data = dev;
211 snprintf(dev->adapter.name, I2C_NAME_SIZE,
212 "i2c-tiny-usb at bus %03d device %03d",
213 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
214
215 if (usb_write(&dev->adapter, CMD_SET_DELAY,
216 cpu_to_le16(delay), 0, NULL, 0) != 0) {
217 dev_err(&dev->adapter.dev,
218 "failure setting delay to %dus\n", delay);
219 retval = -EIO;
220 goto error;
221 }
222
223 dev->adapter.dev.parent = &dev->interface->dev;
224
225 /* and finally attach to i2c layer */
226 i2c_add_adapter(&dev->adapter);
227
228 /* inform user about successful attachment to i2c layer */
229 dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
230
231 return 0;
232
233 error:
234 if (dev)
235 i2c_tiny_usb_free(dev);
236
237 return retval;
238}
239
240static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
241{
242 struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
243
244 i2c_del_adapter(&dev->adapter);
245 usb_set_intfdata(interface, NULL);
246 i2c_tiny_usb_free(dev);
247
248 dev_dbg(&interface->dev, "disconnected\n");
249}
250
251static struct usb_driver i2c_tiny_usb_driver = {
252 .name = "i2c-tiny-usb",
253 .probe = i2c_tiny_usb_probe,
254 .disconnect = i2c_tiny_usb_disconnect,
255 .id_table = i2c_tiny_usb_table,
256};
257
258static int __init usb_i2c_tiny_usb_init(void)
259{
260 /* register this driver with the USB subsystem */
261 return usb_register(&i2c_tiny_usb_driver);
262}
263
264static void __exit usb_i2c_tiny_usb_exit(void)
265{
266 /* deregister this driver with the USB subsystem */
267 usb_deregister(&i2c_tiny_usb_driver);
268}
269
270module_init(usb_i2c_tiny_usb_init);
271module_exit(usb_i2c_tiny_usb_exit);
272
273/* ----- end of usb layer ------------------------------------------------ */
274
275MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
276MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
277MODULE_LICENSE("GPL");