Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andrew Lunn and committed by
Wolfram Sang
83e53a8f e5c6e7f2

+213
+10
drivers/i2c/busses/Kconfig
··· 874 874 This support is also available as a module. If so, the module 875 875 will be called i2c-parport-light. 876 876 877 + config 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 + 877 887 config I2C_TAOS_EVM 878 888 tristate "TAOS evaluation module" 879 889 depends on TTY
+1
drivers/i2c/busses/Makefile
··· 84 84 obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o 85 85 obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o 86 86 obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o 87 + obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o 87 88 obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o 88 89 obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o 89 90 obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o
+202
drivers/i2c/busses/i2c-robotfuzz-osif.c
··· 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 + 32 + struct osif_priv { 33 + struct usb_device *usb_dev; 34 + struct usb_interface *interface; 35 + struct i2c_adapter adapter; 36 + unsigned char status; 37 + }; 38 + 39 + static 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 + 49 + static 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 + 60 + static 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 + 115 + static u32 osif_func(struct i2c_adapter *adapter) 116 + { 117 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 118 + } 119 + 120 + static 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 + 128 + static struct usb_device_id osif_table[] = { 129 + { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) }, 130 + { } 131 + }; 132 + MODULE_DEVICE_TABLE(usb, osif_table); 133 + 134 + static 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 + 181 + static 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 + 190 + static 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 + 197 + module_usb_driver(osif_driver); 198 + 199 + MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 200 + MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>"); 201 + MODULE_DESCRIPTION("RobotFuzz OSIF driver"); 202 + MODULE_LICENSE("GPL v2");