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 const 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 const 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"); 203