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; 66 int i; 67 68 for (i = 0; i < num; i++) { 69 pmsg = &msgs[i]; 70 71 if (pmsg->flags & I2C_M_RD) { 72 ret = osif_usb_read(adapter, OSIFI2C_READ, 73 pmsg->flags, pmsg->addr, 74 pmsg->buf, pmsg->len); 75 if (ret != pmsg->len) { 76 dev_err(&adapter->dev, "failure reading data\n"); 77 return -EREMOTEIO; 78 } 79 } else { 80 ret = osif_usb_write(adapter, OSIFI2C_WRITE, 81 pmsg->flags, pmsg->addr, 82 pmsg->buf, pmsg->len); 83 if (ret != pmsg->len) { 84 dev_err(&adapter->dev, "failure writing data\n"); 85 return -EREMOTEIO; 86 } 87 } 88 89 ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0); 90 if (ret) { 91 dev_err(&adapter->dev, "failure sending STOP\n"); 92 return -EREMOTEIO; 93 } 94 95 /* read status */ 96 ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0, 97 &priv->status, 1); 98 if (ret != 1) { 99 dev_err(&adapter->dev, "failure reading status\n"); 100 return -EREMOTEIO; 101 } 102 103 if (priv->status != STATUS_ADDRESS_ACK) { 104 dev_dbg(&adapter->dev, "status = %d\n", priv->status); 105 return -EREMOTEIO; 106 } 107 } 108 109 return i; 110 } 111 112 static u32 osif_func(struct i2c_adapter *adapter) 113 { 114 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 115 } 116 117 static const struct i2c_algorithm osif_algorithm = { 118 .master_xfer = osif_xfer, 119 .functionality = osif_func, 120 }; 121 122 #define USB_OSIF_VENDOR_ID 0x1964 123 #define USB_OSIF_PRODUCT_ID 0x0001 124 125 static const struct usb_device_id osif_table[] = { 126 { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) }, 127 { } 128 }; 129 MODULE_DEVICE_TABLE(usb, osif_table); 130 131 static int osif_probe(struct usb_interface *interface, 132 const struct usb_device_id *id) 133 { 134 int ret; 135 struct osif_priv *priv; 136 u16 version; 137 138 priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL); 139 if (!priv) 140 return -ENOMEM; 141 142 priv->usb_dev = usb_get_dev(interface_to_usbdev(interface)); 143 priv->interface = interface; 144 145 usb_set_intfdata(interface, priv); 146 147 priv->adapter.owner = THIS_MODULE; 148 priv->adapter.class = I2C_CLASS_HWMON; 149 priv->adapter.algo = &osif_algorithm; 150 priv->adapter.algo_data = priv; 151 snprintf(priv->adapter.name, sizeof(priv->adapter.name), 152 "OSIF at bus %03d device %03d", 153 priv->usb_dev->bus->busnum, priv->usb_dev->devnum); 154 155 /* 156 * Set bus frequency. The frequency is: 157 * 120,000,000 / ( 16 + 2 * div * 4^prescale). 158 * Using dev = 52, prescale = 0 give 100KHz */ 159 ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0, 160 NULL, 0); 161 if (ret) { 162 dev_err(&interface->dev, "failure sending bit rate"); 163 usb_put_dev(priv->usb_dev); 164 return ret; 165 } 166 167 i2c_add_adapter(&(priv->adapter)); 168 169 version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice); 170 dev_info(&interface->dev, 171 "version %x.%02x found at bus %03d address %03d", 172 version >> 8, version & 0xff, 173 priv->usb_dev->bus->busnum, priv->usb_dev->devnum); 174 175 return 0; 176 } 177 178 static void osif_disconnect(struct usb_interface *interface) 179 { 180 struct osif_priv *priv = usb_get_intfdata(interface); 181 182 i2c_del_adapter(&(priv->adapter)); 183 usb_set_intfdata(interface, NULL); 184 usb_put_dev(priv->usb_dev); 185 } 186 187 static struct usb_driver osif_driver = { 188 .name = "RobotFuzz Open Source InterFace, OSIF", 189 .probe = osif_probe, 190 .disconnect = osif_disconnect, 191 .id_table = osif_table, 192 }; 193 194 module_usb_driver(osif_driver); 195 196 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); 197 MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>"); 198 MODULE_DESCRIPTION("RobotFuzz OSIF driver"); 199 MODULE_LICENSE("GPL v2"); 200