1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * driver for the i2c-tiny-usb adapter - 1.0 |
4 | * http://www.harbaum.org/till/i2c_tiny_usb |
5 | * |
6 | * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org) |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/types.h> |
14 | |
15 | /* include interfaces to usb layer */ |
16 | #include <linux/usb.h> |
17 | |
18 | /* include interface to i2c layer */ |
19 | #include <linux/i2c.h> |
20 | |
21 | /* commands via USB, must match command ids in the firmware */ |
22 | #define CMD_ECHO 0 |
23 | #define CMD_GET_FUNC 1 |
24 | #define CMD_SET_DELAY 2 |
25 | #define CMD_GET_STATUS 3 |
26 | |
27 | #define CMD_I2C_IO 4 |
28 | #define CMD_I2C_IO_BEGIN (1<<0) |
29 | #define CMD_I2C_IO_END (1<<1) |
30 | |
31 | /* i2c bit delay, default is 10us -> 100kHz max |
32 | (in practice, due to additional delays in the i2c bitbanging |
33 | code this results in a i2c clock of about 50kHz) */ |
34 | static unsigned short delay = 10; |
35 | module_param(delay, ushort, 0); |
36 | MODULE_PARM_DESC(delay, "bit delay in microseconds " |
37 | "(default is 10us for 100kHz max)" ); |
38 | |
39 | static int usb_read(struct i2c_adapter *adapter, int cmd, |
40 | int value, int index, void *data, int len); |
41 | |
42 | static 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 | |
51 | static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) |
52 | { |
53 | unsigned char *pstatus; |
54 | struct i2c_msg *pmsg; |
55 | int i, ret; |
56 | |
57 | dev_dbg(&adapter->dev, "master xfer %d messages:\n" , num); |
58 | |
59 | pstatus = kmalloc(size: sizeof(*pstatus), GFP_KERNEL); |
60 | if (!pstatus) |
61 | return -ENOMEM; |
62 | |
63 | for (i = 0 ; i < num ; i++) { |
64 | int cmd = CMD_I2C_IO; |
65 | |
66 | if (i == 0) |
67 | cmd |= CMD_I2C_IO_BEGIN; |
68 | |
69 | if (i == num-1) |
70 | cmd |= CMD_I2C_IO_END; |
71 | |
72 | pmsg = &msgs[i]; |
73 | |
74 | dev_dbg(&adapter->dev, |
75 | " %d: %s (flags %d) %d bytes to 0x%02x\n" , |
76 | i, pmsg->flags & I2C_M_RD ? "read" : "write" , |
77 | pmsg->flags, pmsg->len, pmsg->addr); |
78 | |
79 | /* and directly send the message */ |
80 | if (pmsg->flags & I2C_M_RD) { |
81 | /* read data */ |
82 | if (usb_read(adapter, cmd, |
83 | value: pmsg->flags, index: pmsg->addr, |
84 | data: pmsg->buf, len: pmsg->len) != pmsg->len) { |
85 | dev_err(&adapter->dev, |
86 | "failure reading data\n" ); |
87 | ret = -EIO; |
88 | goto out; |
89 | } |
90 | } else { |
91 | /* write data */ |
92 | if (usb_write(adapter, cmd, |
93 | value: pmsg->flags, index: pmsg->addr, |
94 | data: pmsg->buf, len: pmsg->len) != pmsg->len) { |
95 | dev_err(&adapter->dev, |
96 | "failure writing data\n" ); |
97 | ret = -EIO; |
98 | goto out; |
99 | } |
100 | } |
101 | |
102 | /* read status */ |
103 | if (usb_read(adapter, CMD_GET_STATUS, value: 0, index: 0, data: pstatus, len: 1) != 1) { |
104 | dev_err(&adapter->dev, "failure reading status\n" ); |
105 | ret = -EIO; |
106 | goto out; |
107 | } |
108 | |
109 | dev_dbg(&adapter->dev, " status = %d\n" , *pstatus); |
110 | if (*pstatus == STATUS_ADDRESS_NAK) { |
111 | ret = -ENXIO; |
112 | goto out; |
113 | } |
114 | } |
115 | |
116 | ret = i; |
117 | out: |
118 | kfree(objp: pstatus); |
119 | return ret; |
120 | } |
121 | |
122 | static u32 usb_func(struct i2c_adapter *adapter) |
123 | { |
124 | __le32 *pfunc; |
125 | u32 ret; |
126 | |
127 | pfunc = kmalloc(size: sizeof(*pfunc), GFP_KERNEL); |
128 | |
129 | /* get functionality from adapter */ |
130 | if (!pfunc || usb_read(adapter, CMD_GET_FUNC, value: 0, index: 0, data: pfunc, |
131 | len: sizeof(*pfunc)) != sizeof(*pfunc)) { |
132 | dev_err(&adapter->dev, "failure reading functionality\n" ); |
133 | ret = 0; |
134 | goto out; |
135 | } |
136 | |
137 | ret = le32_to_cpup(p: pfunc); |
138 | out: |
139 | kfree(objp: pfunc); |
140 | return ret; |
141 | } |
142 | |
143 | /* This is the actual algorithm we define */ |
144 | static const struct i2c_algorithm usb_algorithm = { |
145 | .master_xfer = usb_xfer, |
146 | .functionality = usb_func, |
147 | }; |
148 | |
149 | /* ----- end of i2c layer ------------------------------------------------ */ |
150 | |
151 | /* ----- begin of usb layer ---------------------------------------------- */ |
152 | |
153 | /* |
154 | * Initially the usb i2c interface uses a vid/pid pair donated by |
155 | * Future Technology Devices International Ltd., later a pair was |
156 | * bought from EZPrototypes |
157 | */ |
158 | static const struct usb_device_id i2c_tiny_usb_table[] = { |
159 | { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ |
160 | { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ |
161 | { } /* Terminating entry */ |
162 | }; |
163 | |
164 | MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table); |
165 | |
166 | /* Structure to hold all of our device specific stuff */ |
167 | struct i2c_tiny_usb { |
168 | struct usb_device *usb_dev; /* the usb device for this device */ |
169 | struct usb_interface *interface; /* the interface for this device */ |
170 | struct i2c_adapter adapter; /* i2c related things */ |
171 | }; |
172 | |
173 | static int usb_read(struct i2c_adapter *adapter, int cmd, |
174 | int value, int index, void *data, int len) |
175 | { |
176 | struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; |
177 | void *dmadata = kmalloc(size: len, GFP_KERNEL); |
178 | int ret; |
179 | |
180 | if (!dmadata) |
181 | return -ENOMEM; |
182 | |
183 | /* do control transfer */ |
184 | ret = usb_control_msg(dev: dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0), |
185 | request: cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | |
186 | USB_DIR_IN, value, index, data: dmadata, size: len, timeout: 2000); |
187 | |
188 | memcpy(data, dmadata, len); |
189 | kfree(objp: dmadata); |
190 | return ret; |
191 | } |
192 | |
193 | static int usb_write(struct i2c_adapter *adapter, int cmd, |
194 | int value, int index, void *data, int len) |
195 | { |
196 | struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; |
197 | void *dmadata = kmemdup(p: data, size: len, GFP_KERNEL); |
198 | int ret; |
199 | |
200 | if (!dmadata) |
201 | return -ENOMEM; |
202 | |
203 | /* do control transfer */ |
204 | ret = usb_control_msg(dev: dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0), |
205 | request: cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE, |
206 | value, index, data: dmadata, size: len, timeout: 2000); |
207 | |
208 | kfree(objp: dmadata); |
209 | return ret; |
210 | } |
211 | |
212 | static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev) |
213 | { |
214 | usb_put_dev(dev: dev->usb_dev); |
215 | kfree(objp: dev); |
216 | } |
217 | |
218 | static int i2c_tiny_usb_probe(struct usb_interface *interface, |
219 | const struct usb_device_id *id) |
220 | { |
221 | struct i2c_tiny_usb *dev; |
222 | int retval = -ENOMEM; |
223 | u16 version; |
224 | |
225 | if (interface->intf_assoc && |
226 | interface->intf_assoc->bFunctionClass != USB_CLASS_VENDOR_SPEC) |
227 | return -ENODEV; |
228 | |
229 | dev_dbg(&interface->dev, "probing usb device\n" ); |
230 | |
231 | /* allocate memory for our device state and initialize it */ |
232 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
233 | if (!dev) |
234 | goto error; |
235 | |
236 | dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); |
237 | dev->interface = interface; |
238 | |
239 | /* save our data pointer in this interface device */ |
240 | usb_set_intfdata(intf: interface, data: dev); |
241 | |
242 | version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice); |
243 | dev_info(&interface->dev, |
244 | "version %x.%02x found at bus %03d address %03d\n" , |
245 | version >> 8, version & 0xff, |
246 | dev->usb_dev->bus->busnum, dev->usb_dev->devnum); |
247 | |
248 | /* setup i2c adapter description */ |
249 | dev->adapter.owner = THIS_MODULE; |
250 | dev->adapter.class = I2C_CLASS_HWMON; |
251 | dev->adapter.algo = &usb_algorithm; |
252 | dev->adapter.algo_data = dev; |
253 | snprintf(buf: dev->adapter.name, size: sizeof(dev->adapter.name), |
254 | fmt: "i2c-tiny-usb at bus %03d device %03d" , |
255 | dev->usb_dev->bus->busnum, dev->usb_dev->devnum); |
256 | |
257 | if (usb_write(adapter: &dev->adapter, CMD_SET_DELAY, value: delay, index: 0, NULL, len: 0) != 0) { |
258 | dev_err(&dev->adapter.dev, |
259 | "failure setting delay to %dus\n" , delay); |
260 | retval = -EIO; |
261 | goto error; |
262 | } |
263 | |
264 | dev->adapter.dev.parent = &dev->interface->dev; |
265 | |
266 | /* and finally attach to i2c layer */ |
267 | i2c_add_adapter(adap: &dev->adapter); |
268 | |
269 | /* inform user about successful attachment to i2c layer */ |
270 | dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n" ); |
271 | |
272 | return 0; |
273 | |
274 | error: |
275 | if (dev) |
276 | i2c_tiny_usb_free(dev); |
277 | |
278 | return retval; |
279 | } |
280 | |
281 | static void i2c_tiny_usb_disconnect(struct usb_interface *interface) |
282 | { |
283 | struct i2c_tiny_usb *dev = usb_get_intfdata(intf: interface); |
284 | |
285 | i2c_del_adapter(adap: &dev->adapter); |
286 | usb_set_intfdata(intf: interface, NULL); |
287 | i2c_tiny_usb_free(dev); |
288 | |
289 | dev_dbg(&interface->dev, "disconnected\n" ); |
290 | } |
291 | |
292 | static struct usb_driver i2c_tiny_usb_driver = { |
293 | .name = "i2c-tiny-usb" , |
294 | .probe = i2c_tiny_usb_probe, |
295 | .disconnect = i2c_tiny_usb_disconnect, |
296 | .id_table = i2c_tiny_usb_table, |
297 | }; |
298 | |
299 | module_usb_driver(i2c_tiny_usb_driver); |
300 | |
301 | /* ----- end of usb layer ------------------------------------------------ */ |
302 | |
303 | MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>" ); |
304 | MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0" ); |
305 | MODULE_LICENSE("GPL" ); |
306 | |