1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * i2c support for Silicon Labs' CP2615 Digital Audio Bridge
5 * (c) 2021, Bence Csókás <bence98@sch.bme.hu>
8 #include <linux/errno.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/string.h>
13 #include <linux/usb.h>
15 /** CP2615 I/O Protocol implementation */
17 #define CP2615_VID 0x10c4
18 #define CP2615_PID 0xeac1
20 #define IOP_EP_IN 0x82
21 #define IOP_EP_OUT 0x02
23 #define IOP_ALTSETTING 2
25 #define MAX_IOP_SIZE 64
26 #define MAX_IOP_PAYLOAD_SIZE (MAX_IOP_SIZE - 6)
27 #define MAX_I2C_SIZE (MAX_IOP_PAYLOAD_SIZE - 4)
29 enum cp2615_iop_msg_type
{
30 iop_GetAccessoryInfo
= 0xD100,
31 iop_AccessoryInfo
= 0xA100,
32 iop_GetPortConfiguration
= 0xD203,
33 iop_PortConfiguration
= 0xA203,
34 iop_DoI2cTransfer
= 0xD400,
35 iop_I2cTransferResult
= 0xA400,
36 iop_GetSerialState
= 0xD501,
37 iop_SerialState
= 0xA501
40 struct __packed cp2615_iop_msg
{
41 __be16 preamble
, length
, msg
;
42 u8 data
[MAX_IOP_PAYLOAD_SIZE
];
45 #define PART_ID_A01 0x1400
46 #define PART_ID_A02 0x1500
48 struct __packed cp2615_iop_accessory_info
{
49 __be16 part_id
, option_id
, proto_ver
;
52 struct __packed cp2615_i2c_transfer
{
53 u8 tag
, i2caddr
, read_len
, write_len
;
54 u8 data
[MAX_I2C_SIZE
];
57 /* Possible values for struct cp2615_i2c_transfer_result.status */
58 enum cp2615_i2c_status
{
59 /* Writing to the internal EEPROM failed, because it is locked */
60 CP2615_CFG_LOCKED
= -6,
61 /* read_len or write_len out of range */
62 CP2615_INVALID_PARAM
= -4,
63 /* I2C target did not ACK in time */
67 /* I2C bus error (ie. target NAK'd the request) */
72 struct __packed cp2615_i2c_transfer_result
{
76 u8 data
[MAX_I2C_SIZE
];
79 static int cp2615_init_iop_msg(struct cp2615_iop_msg
*ret
, enum cp2615_iop_msg_type msg
,
80 const void *data
, size_t data_len
)
82 if (data_len
> MAX_IOP_PAYLOAD_SIZE
)
88 ret
->preamble
= htons(0x2A2AU
);
89 ret
->length
= htons(data_len
+ 6);
90 ret
->msg
= htons(msg
);
92 memcpy(&ret
->data
, data
, data_len
);
96 static int cp2615_init_i2c_msg(struct cp2615_iop_msg
*ret
, const struct cp2615_i2c_transfer
*data
)
98 return cp2615_init_iop_msg(ret
, iop_DoI2cTransfer
, data
, 4 + data
->write_len
);
101 /* Translates status codes to Linux errno's */
102 static int cp2615_check_status(enum cp2615_i2c_status status
)
107 case CP2615_BUS_ERROR
:
109 case CP2615_BUS_BUSY
:
113 case CP2615_INVALID_PARAM
:
115 case CP2615_CFG_LOCKED
:
118 /* Unknown error code */
125 cp2615_i2c_send(struct usb_interface
*usbif
, struct cp2615_i2c_transfer
*i2c_w
)
127 struct cp2615_iop_msg
*msg
= kzalloc(sizeof(*msg
), GFP_KERNEL
);
128 struct usb_device
*usbdev
= interface_to_usbdev(usbif
);
129 int res
= cp2615_init_i2c_msg(msg
, i2c_w
);
132 res
= usb_bulk_msg(usbdev
, usb_sndbulkpipe(usbdev
, IOP_EP_OUT
),
133 msg
, ntohs(msg
->length
), NULL
, 0);
139 cp2615_i2c_recv(struct usb_interface
*usbif
, unsigned char tag
, void *buf
)
141 struct usb_device
*usbdev
= interface_to_usbdev(usbif
);
142 struct cp2615_iop_msg
*msg
;
143 struct cp2615_i2c_transfer_result
*i2c_r
;
146 msg
= kzalloc(sizeof(*msg
), GFP_KERNEL
);
150 res
= usb_bulk_msg(usbdev
, usb_rcvbulkpipe(usbdev
, IOP_EP_IN
), msg
,
151 sizeof(struct cp2615_iop_msg
), NULL
, 0);
157 i2c_r
= (struct cp2615_i2c_transfer_result
*)&msg
->data
;
158 if (msg
->msg
!= htons(iop_I2cTransferResult
) || i2c_r
->tag
!= tag
) {
163 res
= cp2615_check_status(i2c_r
->status
);
165 memcpy(buf
, &i2c_r
->data
, i2c_r
->read_len
);
171 /* Checks if the IOP is functional by querying the part's ID */
172 static int cp2615_check_iop(struct usb_interface
*usbif
)
174 struct cp2615_iop_msg
*msg
= kzalloc(sizeof(*msg
), GFP_KERNEL
);
175 struct cp2615_iop_accessory_info
*info
= (struct cp2615_iop_accessory_info
*)&msg
->data
;
176 struct usb_device
*usbdev
= interface_to_usbdev(usbif
);
177 int res
= cp2615_init_iop_msg(msg
, iop_GetAccessoryInfo
, NULL
, 0);
182 res
= usb_bulk_msg(usbdev
, usb_sndbulkpipe(usbdev
, IOP_EP_OUT
),
183 msg
, ntohs(msg
->length
), NULL
, 0);
187 res
= usb_bulk_msg(usbdev
, usb_rcvbulkpipe(usbdev
, IOP_EP_IN
),
188 msg
, sizeof(struct cp2615_iop_msg
), NULL
, 0);
192 if (msg
->msg
!= htons(iop_AccessoryInfo
)) {
197 switch (ntohs(info
->part_id
)) {
199 dev_dbg(&usbif
->dev
, "Found A01 part. (WARNING: errata exists!)\n");
202 dev_dbg(&usbif
->dev
, "Found good A02 part.\n");
205 dev_warn(&usbif
->dev
, "Unknown part ID %04X\n", ntohs(info
->part_id
));
214 cp2615_i2c_xfer(struct i2c_adapter
*adap
, struct i2c_msg
*msgs
, int num
)
216 struct usb_interface
*usbif
= adap
->algo_data
;
219 struct cp2615_i2c_transfer i2c_w
= {0};
221 dev_dbg(&usbif
->dev
, "Doing %d I2C transactions\n", num
);
223 for (; !ret
&& i
< num
; i
++) {
227 i2c_w
.i2caddr
= i2c_8bit_addr_from_msg(msg
);
228 if (msg
->flags
& I2C_M_RD
) {
229 i2c_w
.read_len
= msg
->len
;
233 i2c_w
.write_len
= msg
->len
;
234 memcpy(&i2c_w
.data
, msg
->buf
, i2c_w
.write_len
);
236 ret
= cp2615_i2c_send(usbif
, &i2c_w
);
239 ret
= cp2615_i2c_recv(usbif
, i2c_w
.tag
, msg
->buf
);
247 cp2615_i2c_func(struct i2c_adapter
*adap
)
249 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
252 static const struct i2c_algorithm cp2615_i2c_algo
= {
253 .xfer
= cp2615_i2c_xfer
,
254 .functionality
= cp2615_i2c_func
,
258 * This chip has some limitations: one is that the USB endpoint
259 * can only receive 64 bytes/transfer, that leaves 54 bytes for
260 * the I2C transfer. On top of that, EITHER read_len OR write_len
261 * may be zero, but not both. If both are non-zero, the adapter
262 * issues a write followed by a read. And the chip does not
263 * support repeated START between the write and read phases.
265 static struct i2c_adapter_quirks cp2615_i2c_quirks
= {
266 .max_write_len
= MAX_I2C_SIZE
,
267 .max_read_len
= MAX_I2C_SIZE
,
268 .flags
= I2C_AQ_COMB_WRITE_THEN_READ
| I2C_AQ_NO_ZERO_LEN
| I2C_AQ_NO_REP_START
,
269 .max_comb_1st_msg_len
= MAX_I2C_SIZE
,
270 .max_comb_2nd_msg_len
= MAX_I2C_SIZE
274 cp2615_i2c_remove(struct usb_interface
*usbif
)
276 struct i2c_adapter
*adap
= usb_get_intfdata(usbif
);
278 usb_set_intfdata(usbif
, NULL
);
279 i2c_del_adapter(adap
);
283 cp2615_i2c_probe(struct usb_interface
*usbif
, const struct usb_device_id
*id
)
286 struct i2c_adapter
*adap
;
287 struct usb_device
*usbdev
= interface_to_usbdev(usbif
);
289 ret
= usb_set_interface(usbdev
, IOP_IFN
, IOP_ALTSETTING
);
293 ret
= cp2615_check_iop(usbif
);
297 adap
= devm_kzalloc(&usbif
->dev
, sizeof(struct i2c_adapter
), GFP_KERNEL
);
301 strscpy(adap
->name
, usbdev
->serial
, sizeof(adap
->name
));
302 adap
->owner
= THIS_MODULE
;
303 adap
->dev
.parent
= &usbif
->dev
;
304 adap
->dev
.of_node
= usbif
->dev
.of_node
;
306 adap
->algo
= &cp2615_i2c_algo
;
307 adap
->quirks
= &cp2615_i2c_quirks
;
308 adap
->algo_data
= usbif
;
310 ret
= i2c_add_adapter(adap
);
314 usb_set_intfdata(usbif
, adap
);
318 static const struct usb_device_id id_table
[] = {
319 { USB_DEVICE_INTERFACE_NUMBER(CP2615_VID
, CP2615_PID
, IOP_IFN
) },
323 MODULE_DEVICE_TABLE(usb
, id_table
);
325 static struct usb_driver cp2615_i2c_driver
= {
326 .name
= "i2c-cp2615",
327 .probe
= cp2615_i2c_probe
,
328 .disconnect
= cp2615_i2c_remove
,
329 .id_table
= id_table
,
332 module_usb_driver(cp2615_i2c_driver
);
334 MODULE_AUTHOR("Bence Csókás <bence98@sch.bme.hu>");
335 MODULE_DESCRIPTION("CP2615 I2C bus driver");
336 MODULE_LICENSE("GPL");