1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for RobotFuzz OSIF
5 * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>
6 * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com>
8 * Based on the i2c-tiny-usb by
10 * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org)
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>
20 #define OSIFI2C_READ 20
21 #define OSIFI2C_WRITE 21
22 #define OSIFI2C_STOP 22
23 #define OSIFI2C_STATUS 23
24 #define OSIFI2C_SET_BIT_RATE 24
26 #define STATUS_ADDRESS_ACK 0
27 #define STATUS_ADDRESS_NAK 2
30 struct usb_device
*usb_dev
;
31 struct usb_interface
*interface
;
32 struct i2c_adapter adapter
;
36 static int osif_usb_read(struct i2c_adapter
*adapter
, int cmd
,
37 int value
, int index
, void *data
, int len
)
39 struct osif_priv
*priv
= adapter
->algo_data
;
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);
46 static int osif_usb_write(struct i2c_adapter
*adapter
, int cmd
,
47 int value
, int index
, void *data
, int len
)
50 struct osif_priv
*priv
= adapter
->algo_data
;
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);
57 static int osif_xfer(struct i2c_adapter
*adapter
, struct i2c_msg
*msgs
,
60 struct osif_priv
*priv
= adapter
->algo_data
;
65 for (i
= 0; i
< num
; i
++) {
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");
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");
86 ret
= osif_usb_write(adapter
, OSIFI2C_STOP
, 0, 0, NULL
, 0);
88 dev_err(&adapter
->dev
, "failure sending STOP\n");
93 ret
= osif_usb_read(adapter
, OSIFI2C_STATUS
, 0, 0,
96 dev_err(&adapter
->dev
, "failure reading status\n");
100 if (priv
->status
!= STATUS_ADDRESS_ACK
) {
101 dev_dbg(&adapter
->dev
, "status = %d\n", priv
->status
);
109 static u32
osif_func(struct i2c_adapter
*adapter
)
111 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
114 static const struct i2c_algorithm osif_algorithm
= {
116 .functionality
= osif_func
,
119 #define USB_OSIF_VENDOR_ID 0x1964
120 #define USB_OSIF_PRODUCT_ID 0x0001
122 static const struct usb_device_id osif_table
[] = {
123 { USB_DEVICE(USB_OSIF_VENDOR_ID
, USB_OSIF_PRODUCT_ID
) },
126 MODULE_DEVICE_TABLE(usb
, osif_table
);
128 static int osif_probe(struct usb_interface
*interface
,
129 const struct usb_device_id
*id
)
132 struct osif_priv
*priv
;
135 priv
= devm_kzalloc(&interface
->dev
, sizeof(*priv
), GFP_KERNEL
);
139 priv
->usb_dev
= usb_get_dev(interface_to_usbdev(interface
));
140 priv
->interface
= interface
;
142 usb_set_intfdata(interface
, priv
);
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
);
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,
159 dev_err(&interface
->dev
, "failure sending bit rate");
160 usb_put_dev(priv
->usb_dev
);
164 i2c_add_adapter(&(priv
->adapter
));
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
);
175 static void osif_disconnect(struct usb_interface
*interface
)
177 struct osif_priv
*priv
= usb_get_intfdata(interface
);
179 i2c_del_adapter(&(priv
->adapter
));
180 usb_set_intfdata(interface
, NULL
);
181 usb_put_dev(priv
->usb_dev
);
184 static struct usb_driver osif_driver
= {
185 .name
= "RobotFuzz Open Source InterFace, OSIF",
187 .disconnect
= osif_disconnect
,
188 .id_table
= osif_table
,
191 module_usb_driver(osif_driver
);
193 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
194 MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");
195 MODULE_DESCRIPTION("RobotFuzz OSIF driver");
196 MODULE_LICENSE("GPL v2");