brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 80d4507 Raw
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