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