197 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Driver for RobotFuzz OSIF4 *5 * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>6 * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com>7 *8 * Based on the i2c-tiny-usb by9 *10 * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org)11 */12 13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/errno.h>16#include <linux/i2c.h>17#include <linux/slab.h>18#include <linux/usb.h>19 20#define OSIFI2C_READ 2021#define OSIFI2C_WRITE 2122#define OSIFI2C_STOP 2223#define OSIFI2C_STATUS 2324#define OSIFI2C_SET_BIT_RATE 2425 26#define STATUS_ADDRESS_ACK 027#define STATUS_ADDRESS_NAK 228 29struct osif_priv {30 struct usb_device *usb_dev;31 struct usb_interface *interface;32 struct i2c_adapter adapter;33 unsigned char status;34};35 36static int osif_usb_read(struct i2c_adapter *adapter, int cmd,37 int value, int index, void *data, int len)38{39 struct osif_priv *priv = adapter->algo_data;40 41 return usb_control_msg(priv->usb_dev, usb_rcvctrlpipe(priv->usb_dev, 0),42 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |43 USB_DIR_IN, value, index, data, len, 2000);44}45 46static int osif_usb_write(struct i2c_adapter *adapter, int cmd,47 int value, int index, void *data, int len)48{49 50 struct osif_priv *priv = adapter->algo_data;51 52 return usb_control_msg(priv->usb_dev, usb_sndctrlpipe(priv->usb_dev, 0),53 cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,54 value, index, data, len, 2000);55}56 57static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,58 int num)59{60 struct osif_priv *priv = adapter->algo_data;61 struct i2c_msg *pmsg;62 int ret;63 int i;64 65 for (i = 0; i < num; i++) {66 pmsg = &msgs[i];67 68 if (pmsg->flags & I2C_M_RD) {69 ret = osif_usb_read(adapter, OSIFI2C_READ,70 pmsg->flags, pmsg->addr,71 pmsg->buf, pmsg->len);72 if (ret != pmsg->len) {73 dev_err(&adapter->dev, "failure reading data\n");74 return -EREMOTEIO;75 }76 } else {77 ret = osif_usb_write(adapter, OSIFI2C_WRITE,78 pmsg->flags, pmsg->addr,79 pmsg->buf, pmsg->len);80 if (ret != pmsg->len) {81 dev_err(&adapter->dev, "failure writing data\n");82 return -EREMOTEIO;83 }84 }85 86 ret = osif_usb_write(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);87 if (ret) {88 dev_err(&adapter->dev, "failure sending STOP\n");89 return -EREMOTEIO;90 }91 92 /* read status */93 ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0,94 &priv->status, 1);95 if (ret != 1) {96 dev_err(&adapter->dev, "failure reading status\n");97 return -EREMOTEIO;98 }99 100 if (priv->status != STATUS_ADDRESS_ACK) {101 dev_dbg(&adapter->dev, "status = %d\n", priv->status);102 return -EREMOTEIO;103 }104 }105 106 return i;107}108 109static u32 osif_func(struct i2c_adapter *adapter)110{111 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;112}113 114static const struct i2c_algorithm osif_algorithm = {115 .xfer = osif_xfer,116 .functionality = osif_func,117};118 119#define USB_OSIF_VENDOR_ID 0x1964120#define USB_OSIF_PRODUCT_ID 0x0001121 122static const struct usb_device_id osif_table[] = {123 { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },124 { }125};126MODULE_DEVICE_TABLE(usb, osif_table);127 128static int osif_probe(struct usb_interface *interface,129 const struct usb_device_id *id)130{131 int ret;132 struct osif_priv *priv;133 u16 version;134 135 priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);136 if (!priv)137 return -ENOMEM;138 139 priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));140 priv->interface = interface;141 142 usb_set_intfdata(interface, priv);143 144 priv->adapter.owner = THIS_MODULE;145 priv->adapter.class = I2C_CLASS_HWMON;146 priv->adapter.algo = &osif_algorithm;147 priv->adapter.algo_data = priv;148 snprintf(priv->adapter.name, sizeof(priv->adapter.name),149 "OSIF at bus %03d device %03d",150 priv->usb_dev->bus->busnum, priv->usb_dev->devnum);151 152 /*153 * Set bus frequency. The frequency is:154 * 120,000,000 / ( 16 + 2 * div * 4^prescale).155 * Using dev = 52, prescale = 0 give 100KHz */156 ret = osif_usb_write(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,157 NULL, 0);158 if (ret) {159 dev_err(&interface->dev, "failure sending bit rate");160 usb_put_dev(priv->usb_dev);161 return ret;162 }163 164 i2c_add_adapter(&(priv->adapter));165 166 version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice);167 dev_info(&interface->dev,168 "version %x.%02x found at bus %03d address %03d",169 version >> 8, version & 0xff,170 priv->usb_dev->bus->busnum, priv->usb_dev->devnum);171 172 return 0;173}174 175static void osif_disconnect(struct usb_interface *interface)176{177 struct osif_priv *priv = usb_get_intfdata(interface);178 179 i2c_del_adapter(&(priv->adapter));180 usb_set_intfdata(interface, NULL);181 usb_put_dev(priv->usb_dev);182}183 184static struct usb_driver osif_driver = {185 .name = "RobotFuzz Open Source InterFace, OSIF",186 .probe = osif_probe,187 .disconnect = osif_disconnect,188 .id_table = osif_table,189};190 191module_usb_driver(osif_driver);192 193MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");194MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");195MODULE_DESCRIPTION("RobotFuzz OSIF driver");196MODULE_LICENSE("GPL v2");197