aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2014-01-10 18:23:59 -0500
committerWolfram Sang <wsa@the-dreams.de>2014-01-13 07:56:56 -0500
commit83e53a8f120f2f273cf0ad717f5372ab79ac24fe (patch)
tree6c5934ce87dec5a66f618b2631d421b386555216 /drivers/i2c
parente5c6e7f296e17011848732b5a26b8251db59595b (diff)
i2c: Add bus driver for for OSIF USB i2c device.
OSIF, Open Source InterFace, is a USB based i2c bus master. The origional design was based on i2c-tiny-usb, but more modern versions of the firmware running on the MegaAVR microcontroller use a different protocol over the USB. This code is based on Barry Carter <barry.carter@gmail.com> driver. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
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-robotfuzz-osif.c202
3 files changed, 213 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 98a3f1ffc3b7..6bcdea5856af 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -874,6 +874,16 @@ config I2C_PARPORT_LIGHT
874 This support is also available as a module. If so, the module 874 This support is also available as a module. If so, the module
875 will be called i2c-parport-light. 875 will be called i2c-parport-light.
876 876
877config I2C_ROBOTFUZZ_OSIF
878 tristate "RobotFuzz Open Source InterFace USB adapter"
879 depends on USB
880 help
881 If you say yes to this option, support will be included for the
882 RobotFuzz Open Source InterFace USB to I2C interface.
883
884 This driver can also be built as a module. If so, the module
885 will be called i2c-osif.
886
877config I2C_TAOS_EVM 887config I2C_TAOS_EVM
878 tristate "TAOS evaluation module" 888 tristate "TAOS evaluation module"
879 depends on TTY 889 depends on TTY
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index dca041b1b99d..a08931fe73e1 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
84obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o 84obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
85obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o 85obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
86obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o 86obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
87obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
87obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o 88obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
88obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o 89obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
89obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o 90obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
new file mode 100644
index 000000000000..ced9c6a308d1
--- /dev/null
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -0,0 +1,202 @@
1/*
2 * Driver for RobotFuzz OSIF
3 *
4 * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>
5 * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com>
6 *
7 * Based on the i2c-tiny-usb by
8 *
9 * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org)
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation, version 2.
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/errno.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/usb.h>
22
23#define OSIFI2C_READ 20
24#define OSIFI2C_WRITE 21
25#define OSIFI2C_STOP 22
26#define OSIFI2C_STATUS 23
27#define OSIFI2C_SET_BIT_RATE 24
28
29#define STATUS_ADDRESS_ACK 0
30#define STATUS_ADDRESS_NAK 2
31
32struct osif_priv {
33 struct usb_device *usb_dev;
34 struct usb_interface *interface;
35 struct i2c_adapter adapter;
36 unsigned char status;
37};
38
39static int osif_usb_read(struct i2c_adapter *adapter, int cmd,
40 int value, int index, void *data, int len)
41{
42 struct osif_priv *priv = adapter->algo_data;
43
44 return usb_control_msg(priv->usb_dev, usb_rcvctrlpipe(priv->usb_dev, 0),
45 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
46 USB_DIR_IN, value, index, data, len, 2000);
47}
48
49static int osif_usb_write(struct i2c_adapter *adapter, int cmd,
50 int value, int index, void *data, int len)
51{
52
53 struct osif_priv *priv = adapter->algo_data;
54
55 return usb_control_msg(priv->usb_dev, usb_sndctrlpipe(priv->usb_dev, 0),
56 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
57 value, index, data, len, 2000);
58}
59
60static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
61 int num)
62{
63 struct osif_priv *priv = adapter->algo_data;
64 struct i2c_msg *pmsg;
65 int ret = 0;
66 int i, cmd;
67
68 for (i = 0; ret >= 0 && i < num; i++) {
69 pmsg = &msgs[i];
70
71 if (pmsg->flags & I2C_M_RD) {
72 cmd = OSIFI2C_READ;
73
74 ret = osif_usb_read(adapter, cmd, pmsg->flags,
75 pmsg->addr, pmsg->buf,
76 pmsg->len);
77 if (ret != pmsg->len) {
78 dev_err(&adapter->dev, "failure reading data\n");
79 return -EREMOTEIO;
80 }
81 } else {
82 cmd = OSIFI2C_WRITE;
83
84 ret = osif_usb_write(adapter, cmd, pmsg->flags,
85 pmsg->addr, pmsg->buf, pmsg->len);
86 if (ret != pmsg->len) {
87 dev_err(&adapter->dev, "failure writing data\n");
88 return -EREMOTEIO;
89 }
90 }
91
92 ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
93 if (ret) {
94 dev_err(&adapter->dev, "failure sending STOP\n");
95 return -EREMOTEIO;
96 }
97
98 /* read status */
99 ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0,
100 &priv->status, 1);
101 if (ret != 1) {
102 dev_err(&adapter->dev, "failure reading status\n");
103 return -EREMOTEIO;
104 }
105
106 if (priv->status != STATUS_ADDRESS_ACK) {
107 dev_dbg(&adapter->dev, "status = %d\n", priv->status);
108 return -EREMOTEIO;
109 }
110 }
111
112 return i;
113}
114
115static u32 osif_func(struct i2c_adapter *adapter)
116{
117 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
118}
119
120static struct i2c_algorithm osif_algorithm = {
121 .master_xfer = osif_xfer,
122 .functionality = osif_func,
123};
124
125#define USB_OSIF_VENDOR_ID 0x1964
126#define USB_OSIF_PRODUCT_ID 0x0001
127
128static struct usb_device_id osif_table[] = {
129 { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
130 { }
131};
132MODULE_DEVICE_TABLE(usb, osif_table);
133
134static int osif_probe(struct usb_interface *interface,
135 const struct usb_device_id *id)
136{
137 int ret;
138 struct osif_priv *priv;
139 u16 version;
140
141 priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);
142 if (!priv)
143 return -ENOMEM;
144
145 priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));
146 priv->interface = interface;
147
148 usb_set_intfdata(interface, priv);
149
150 priv->adapter.owner = THIS_MODULE;
151 priv->adapter.class = I2C_CLASS_HWMON;
152 priv->adapter.algo = &osif_algorithm;
153 priv->adapter.algo_data = priv;
154 snprintf(priv->adapter.name, sizeof(priv->adapter.name),
155 "OSIF at bus %03d device %03d",
156 priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
157
158 /*
159 * Set bus frequency. The frequency is:
160 * 120,000,000 / ( 16 + 2 * div * 4^prescale).
161 * Using dev = 52, prescale = 0 give 100KHz */
162 ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
163 NULL, 0);
164 if (ret) {
165 dev_err(&interface->dev, "failure sending bit rate");
166 usb_put_dev(priv->usb_dev);
167 return ret;
168 }
169
170 i2c_add_adapter(&(priv->adapter));
171
172 version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice);
173 dev_info(&interface->dev,
174 "version %x.%02x found at bus %03d address %03d",
175 version >> 8, version & 0xff,
176 priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
177
178 return 0;
179}
180
181static void osif_disconnect(struct usb_interface *interface)
182{
183 struct osif_priv *priv = usb_get_intfdata(interface);
184
185 i2c_del_adapter(&(priv->adapter));
186 usb_set_intfdata(interface, NULL);
187 usb_put_dev(priv->usb_dev);
188}
189
190static struct usb_driver osif_driver = {
191 .name = "RobotFuzz Open Source InterFace, OSIF",
192 .probe = osif_probe,
193 .disconnect = osif_disconnect,
194 .id_table = osif_table,
195};
196
197module_usb_driver(osif_driver);
198
199MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
200MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");
201MODULE_DESCRIPTION("RobotFuzz OSIF driver");
202MODULE_LICENSE("GPL v2");