xref: /openbmc/linux/drivers/hid/hid-ft260.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
16a82582dSMichael Zaidman // SPDX-License-Identifier: GPL-2.0-only
26a82582dSMichael Zaidman /*
36a82582dSMichael Zaidman  * hid-ft260.c - FTDI FT260 USB HID to I2C host bridge
46a82582dSMichael Zaidman  *
56a82582dSMichael Zaidman  * Copyright (c) 2021, Michael Zaidman <michaelz@xsightlabs.com>
66a82582dSMichael Zaidman  *
76a82582dSMichael Zaidman  * Data Sheet:
86a82582dSMichael Zaidman  *   https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT260.pdf
96a82582dSMichael Zaidman  */
106a82582dSMichael Zaidman 
116a82582dSMichael Zaidman #include "hid-ids.h"
126a82582dSMichael Zaidman #include <linux/hidraw.h>
136a82582dSMichael Zaidman #include <linux/i2c.h>
146a82582dSMichael Zaidman #include <linux/module.h>
156a82582dSMichael Zaidman #include <linux/usb.h>
166a82582dSMichael Zaidman 
176a82582dSMichael Zaidman #ifdef DEBUG
186a82582dSMichael Zaidman static int ft260_debug = 1;
196a82582dSMichael Zaidman #else
206a82582dSMichael Zaidman static int ft260_debug;
216a82582dSMichael Zaidman #endif
226a82582dSMichael Zaidman module_param_named(debug, ft260_debug, int, 0600);
236a82582dSMichael Zaidman MODULE_PARM_DESC(debug, "Toggle FT260 debugging messages");
246a82582dSMichael Zaidman 
256a82582dSMichael Zaidman #define ft260_dbg(format, arg...)					  \
266a82582dSMichael Zaidman 	do {								  \
276a82582dSMichael Zaidman 		if (ft260_debug)					  \
286a82582dSMichael Zaidman 			pr_info("%s: " format, __func__, ##arg);	  \
296a82582dSMichael Zaidman 	} while (0)
306a82582dSMichael Zaidman 
316a82582dSMichael Zaidman #define FT260_REPORT_MAX_LENGTH (64)
326a82582dSMichael Zaidman #define FT260_I2C_DATA_REPORT_ID(len) (FT260_I2C_REPORT_MIN + (len - 1) / 4)
3354410c14SMichael Zaidman 
344b3da685SMichael Zaidman #define FT260_WAKEUP_NEEDED_AFTER_MS (4800) /* 5s minus 200ms margin */
354b3da685SMichael Zaidman 
366a82582dSMichael Zaidman /*
3754410c14SMichael Zaidman  * The ft260 input report format defines 62 bytes for the data payload, but
3854410c14SMichael Zaidman  * when requested 62 bytes, the controller returns 60 and 2 in separate input
3954410c14SMichael Zaidman  * reports. To achieve better performance with the multi-report read data
4054410c14SMichael Zaidman  * transfers, we set the maximum read payload length to a multiple of 60.
4154410c14SMichael Zaidman  * With a 100 kHz I2C clock, one 240 bytes read takes about 1/27 second,
4254410c14SMichael Zaidman  * which is excessive; On the other hand, some higher layer drivers like at24
4354410c14SMichael Zaidman  * or optoe limit the i2c reads to 128 bytes. To not block other drivers out
4454410c14SMichael Zaidman  * of I2C for potentially troublesome amounts of time, we select the maximum
4554410c14SMichael Zaidman  * read payload length to be 180 bytes.
466a82582dSMichael Zaidman */
4754410c14SMichael Zaidman #define FT260_RD_DATA_MAX (180)
486a82582dSMichael Zaidman #define FT260_WR_DATA_MAX (60)
496a82582dSMichael Zaidman 
506a82582dSMichael Zaidman /*
516a82582dSMichael Zaidman  * Device interface configuration.
526a82582dSMichael Zaidman  * The FT260 has 2 interfaces that are controlled by DCNF0 and DCNF1 pins.
536a82582dSMichael Zaidman  * First implementes USB HID to I2C bridge function and
546a82582dSMichael Zaidman  * second - USB HID to UART bridge function.
556a82582dSMichael Zaidman  */
566a82582dSMichael Zaidman enum {
576a82582dSMichael Zaidman 	FT260_MODE_ALL			= 0x00,
586a82582dSMichael Zaidman 	FT260_MODE_I2C			= 0x01,
596a82582dSMichael Zaidman 	FT260_MODE_UART			= 0x02,
606a82582dSMichael Zaidman 	FT260_MODE_BOTH			= 0x03,
616a82582dSMichael Zaidman };
626a82582dSMichael Zaidman 
636a82582dSMichael Zaidman /* Control pipe */
646a82582dSMichael Zaidman enum {
656a82582dSMichael Zaidman 	FT260_GET_RQST_TYPE		= 0xA1,
666a82582dSMichael Zaidman 	FT260_GET_REPORT		= 0x01,
676a82582dSMichael Zaidman 	FT260_SET_RQST_TYPE		= 0x21,
686a82582dSMichael Zaidman 	FT260_SET_REPORT		= 0x09,
696a82582dSMichael Zaidman 	FT260_FEATURE			= 0x03,
706a82582dSMichael Zaidman };
716a82582dSMichael Zaidman 
726a82582dSMichael Zaidman /* Report IDs / Feature In */
736a82582dSMichael Zaidman enum {
746a82582dSMichael Zaidman 	FT260_CHIP_VERSION		= 0xA0,
756a82582dSMichael Zaidman 	FT260_SYSTEM_SETTINGS		= 0xA1,
766a82582dSMichael Zaidman 	FT260_I2C_STATUS		= 0xC0,
776a82582dSMichael Zaidman 	FT260_I2C_READ_REQ		= 0xC2,
786a82582dSMichael Zaidman 	FT260_I2C_REPORT_MIN		= 0xD0,
796a82582dSMichael Zaidman 	FT260_I2C_REPORT_MAX		= 0xDE,
806a82582dSMichael Zaidman 	FT260_GPIO			= 0xB0,
816a82582dSMichael Zaidman 	FT260_UART_INTERRUPT_STATUS	= 0xB1,
826a82582dSMichael Zaidman 	FT260_UART_STATUS		= 0xE0,
836a82582dSMichael Zaidman 	FT260_UART_RI_DCD_STATUS	= 0xE1,
846a82582dSMichael Zaidman 	FT260_UART_REPORT		= 0xF0,
856a82582dSMichael Zaidman };
866a82582dSMichael Zaidman 
876a82582dSMichael Zaidman /* Feature Out */
886a82582dSMichael Zaidman enum {
896a82582dSMichael Zaidman 	FT260_SET_CLOCK			= 0x01,
906a82582dSMichael Zaidman 	FT260_SET_I2C_MODE		= 0x02,
916a82582dSMichael Zaidman 	FT260_SET_UART_MODE		= 0x03,
926a82582dSMichael Zaidman 	FT260_ENABLE_INTERRUPT		= 0x05,
936a82582dSMichael Zaidman 	FT260_SELECT_GPIO2_FUNC		= 0x06,
946a82582dSMichael Zaidman 	FT260_ENABLE_UART_DCD_RI	= 0x07,
956a82582dSMichael Zaidman 	FT260_SELECT_GPIOA_FUNC		= 0x08,
966a82582dSMichael Zaidman 	FT260_SELECT_GPIOG_FUNC		= 0x09,
976a82582dSMichael Zaidman 	FT260_SET_INTERRUPT_TRIGGER	= 0x0A,
986a82582dSMichael Zaidman 	FT260_SET_SUSPEND_OUT_POLAR	= 0x0B,
996a82582dSMichael Zaidman 	FT260_ENABLE_UART_RI_WAKEUP	= 0x0C,
1006a82582dSMichael Zaidman 	FT260_SET_UART_RI_WAKEUP_CFG	= 0x0D,
1016a82582dSMichael Zaidman 	FT260_SET_I2C_RESET		= 0x20,
1026a82582dSMichael Zaidman 	FT260_SET_I2C_CLOCK_SPEED	= 0x22,
1036a82582dSMichael Zaidman 	FT260_SET_UART_RESET		= 0x40,
1046a82582dSMichael Zaidman 	FT260_SET_UART_CONFIG		= 0x41,
1056a82582dSMichael Zaidman 	FT260_SET_UART_BAUD_RATE	= 0x42,
1066a82582dSMichael Zaidman 	FT260_SET_UART_DATA_BIT		= 0x43,
1076a82582dSMichael Zaidman 	FT260_SET_UART_PARITY		= 0x44,
1086a82582dSMichael Zaidman 	FT260_SET_UART_STOP_BIT		= 0x45,
1096a82582dSMichael Zaidman 	FT260_SET_UART_BREAKING		= 0x46,
1106a82582dSMichael Zaidman 	FT260_SET_UART_XON_XOFF		= 0x49,
1116a82582dSMichael Zaidman };
1126a82582dSMichael Zaidman 
1136a82582dSMichael Zaidman /* Response codes in I2C status report */
1146a82582dSMichael Zaidman enum {
1156a82582dSMichael Zaidman 	FT260_I2C_STATUS_SUCCESS	= 0x00,
1166a82582dSMichael Zaidman 	FT260_I2C_STATUS_CTRL_BUSY	= 0x01,
1176a82582dSMichael Zaidman 	FT260_I2C_STATUS_ERROR		= 0x02,
1186a82582dSMichael Zaidman 	FT260_I2C_STATUS_ADDR_NO_ACK	= 0x04,
1196a82582dSMichael Zaidman 	FT260_I2C_STATUS_DATA_NO_ACK	= 0x08,
1206a82582dSMichael Zaidman 	FT260_I2C_STATUS_ARBITR_LOST	= 0x10,
1216a82582dSMichael Zaidman 	FT260_I2C_STATUS_CTRL_IDLE	= 0x20,
1226a82582dSMichael Zaidman 	FT260_I2C_STATUS_BUS_BUSY	= 0x40,
1236a82582dSMichael Zaidman };
1246a82582dSMichael Zaidman 
1256a82582dSMichael Zaidman /* I2C Conditions flags */
1266a82582dSMichael Zaidman enum {
1276a82582dSMichael Zaidman 	FT260_FLAG_NONE			= 0x00,
1286a82582dSMichael Zaidman 	FT260_FLAG_START		= 0x02,
1296a82582dSMichael Zaidman 	FT260_FLAG_START_REPEATED	= 0x03,
1306a82582dSMichael Zaidman 	FT260_FLAG_STOP			= 0x04,
1316a82582dSMichael Zaidman 	FT260_FLAG_START_STOP		= 0x06,
1326a82582dSMichael Zaidman 	FT260_FLAG_START_STOP_REPEATED	= 0x07,
1336a82582dSMichael Zaidman };
1346a82582dSMichael Zaidman 
1356a82582dSMichael Zaidman #define FT260_SET_REQUEST_VALUE(report_id) ((FT260_FEATURE << 8) | report_id)
1366a82582dSMichael Zaidman 
1376a82582dSMichael Zaidman /* Feature In reports */
1386a82582dSMichael Zaidman 
1396a82582dSMichael Zaidman struct ft260_get_chip_version_report {
1406a82582dSMichael Zaidman 	u8 report;		/* FT260_CHIP_VERSION */
1416a82582dSMichael Zaidman 	u8 chip_code[4];	/* FTDI chip identification code */
1426a82582dSMichael Zaidman 	u8 reserved[8];
1436a82582dSMichael Zaidman } __packed;
1446a82582dSMichael Zaidman 
1456a82582dSMichael Zaidman struct ft260_get_system_status_report {
1466a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
1476a82582dSMichael Zaidman 	u8 chip_mode;		/* DCNF0 and DCNF1 status, bits 0-1 */
1486a82582dSMichael Zaidman 	u8 clock_ctl;		/* 0 - 12MHz, 1 - 24MHz, 2 - 48MHz */
1496a82582dSMichael Zaidman 	u8 suspend_status;	/* 0 - not suspended, 1 - suspended */
1506a82582dSMichael Zaidman 	u8 pwren_status;	/* 0 - FT260 is not ready, 1 - ready */
1516a82582dSMichael Zaidman 	u8 i2c_enable;		/* 0 - disabled, 1 - enabled */
1526a82582dSMichael Zaidman 	u8 uart_mode;		/* 0 - OFF; 1 - RTS_CTS, 2 - DTR_DSR, */
1536a82582dSMichael Zaidman 				/* 3 - XON_XOFF, 4 - No flow control */
1546a82582dSMichael Zaidman 	u8 hid_over_i2c_en;	/* 0 - disabled, 1 - enabled */
1556a82582dSMichael Zaidman 	u8 gpio2_function;	/* 0 - GPIO,  1 - SUSPOUT, */
1566a82582dSMichael Zaidman 				/* 2 - PWREN, 4 - TX_LED */
1576a82582dSMichael Zaidman 	u8 gpioA_function;	/* 0 - GPIO, 3 - TX_ACTIVE, 4 - TX_LED */
1586a82582dSMichael Zaidman 	u8 gpioG_function;	/* 0 - GPIO, 2 - PWREN, */
1596a82582dSMichael Zaidman 				/* 5 - RX_LED, 6 - BCD_DET */
1606a82582dSMichael Zaidman 	u8 suspend_out_pol;	/* 0 - active-high, 1 - active-low */
1616a82582dSMichael Zaidman 	u8 enable_wakeup_int;	/* 0 - disabled, 1 - enabled */
1626a82582dSMichael Zaidman 	u8 intr_cond;		/* Interrupt trigger conditions */
1636a82582dSMichael Zaidman 	u8 power_saving_en;	/* 0 - disabled, 1 - enabled */
1646a82582dSMichael Zaidman 	u8 reserved[10];
1656a82582dSMichael Zaidman } __packed;
1666a82582dSMichael Zaidman 
1676a82582dSMichael Zaidman struct ft260_get_i2c_status_report {
1686a82582dSMichael Zaidman 	u8 report;		/* FT260_I2C_STATUS */
1696a82582dSMichael Zaidman 	u8 bus_status;		/* I2C bus status */
1706a82582dSMichael Zaidman 	__le16 clock;		/* I2C bus clock in range 60-3400 KHz */
1716a82582dSMichael Zaidman 	u8 reserved;
1726a82582dSMichael Zaidman } __packed;
1736a82582dSMichael Zaidman 
1746a82582dSMichael Zaidman /* Feature Out reports */
1756a82582dSMichael Zaidman 
1766a82582dSMichael Zaidman struct ft260_set_system_clock_report {
1776a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
1786a82582dSMichael Zaidman 	u8 request;		/* FT260_SET_CLOCK */
1796a82582dSMichael Zaidman 	u8 clock_ctl;		/* 0 - 12MHz, 1 - 24MHz, 2 - 48MHz */
1806a82582dSMichael Zaidman } __packed;
1816a82582dSMichael Zaidman 
1826a82582dSMichael Zaidman struct ft260_set_i2c_mode_report {
1836a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
1846a82582dSMichael Zaidman 	u8 request;		/* FT260_SET_I2C_MODE */
1856a82582dSMichael Zaidman 	u8 i2c_enable;		/* 0 - disabled, 1 - enabled */
1866a82582dSMichael Zaidman } __packed;
1876a82582dSMichael Zaidman 
1886a82582dSMichael Zaidman struct ft260_set_uart_mode_report {
1896a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
1906a82582dSMichael Zaidman 	u8 request;		/* FT260_SET_UART_MODE */
1916a82582dSMichael Zaidman 	u8 uart_mode;		/* 0 - OFF; 1 - RTS_CTS, 2 - DTR_DSR, */
1926a82582dSMichael Zaidman 				/* 3 - XON_XOFF, 4 - No flow control */
1936a82582dSMichael Zaidman } __packed;
1946a82582dSMichael Zaidman 
1956a82582dSMichael Zaidman struct ft260_set_i2c_reset_report {
1966a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
1976a82582dSMichael Zaidman 	u8 request;		/* FT260_SET_I2C_RESET */
1986a82582dSMichael Zaidman } __packed;
1996a82582dSMichael Zaidman 
2006a82582dSMichael Zaidman struct ft260_set_i2c_speed_report {
2016a82582dSMichael Zaidman 	u8 report;		/* FT260_SYSTEM_SETTINGS */
2026a82582dSMichael Zaidman 	u8 request;		/* FT260_SET_I2C_CLOCK_SPEED */
2036a82582dSMichael Zaidman 	__le16 clock;		/* I2C bus clock in range 60-3400 KHz */
2046a82582dSMichael Zaidman } __packed;
2056a82582dSMichael Zaidman 
2066a82582dSMichael Zaidman /* Data transfer reports */
2076a82582dSMichael Zaidman 
2086a82582dSMichael Zaidman struct ft260_i2c_write_request_report {
2096a82582dSMichael Zaidman 	u8 report;		/* FT260_I2C_REPORT */
2106a82582dSMichael Zaidman 	u8 address;		/* 7-bit I2C address */
2116a82582dSMichael Zaidman 	u8 flag;		/* I2C transaction condition */
2126a82582dSMichael Zaidman 	u8 length;		/* data payload length */
213b45ef5dbSMichael Zaidman 	u8 data[FT260_WR_DATA_MAX]; /* data payload */
2146a82582dSMichael Zaidman } __packed;
2156a82582dSMichael Zaidman 
2166a82582dSMichael Zaidman struct ft260_i2c_read_request_report {
2176a82582dSMichael Zaidman 	u8 report;		/* FT260_I2C_READ_REQ */
2186a82582dSMichael Zaidman 	u8 address;		/* 7-bit I2C address */
2196a82582dSMichael Zaidman 	u8 flag;		/* I2C transaction condition */
2206a82582dSMichael Zaidman 	__le16 length;		/* data payload length */
2216a82582dSMichael Zaidman } __packed;
2226a82582dSMichael Zaidman 
2236a82582dSMichael Zaidman struct ft260_i2c_input_report {
2246a82582dSMichael Zaidman 	u8 report;		/* FT260_I2C_REPORT */
2256a82582dSMichael Zaidman 	u8 length;		/* data payload length */
2266a82582dSMichael Zaidman 	u8 data[2];		/* data payload */
2276a82582dSMichael Zaidman } __packed;
2286a82582dSMichael Zaidman 
2296a82582dSMichael Zaidman static const struct hid_device_id ft260_devices[] = {
2306a82582dSMichael Zaidman 	{ HID_USB_DEVICE(USB_VENDOR_ID_FUTURE_TECHNOLOGY,
2316a82582dSMichael Zaidman 			 USB_DEVICE_ID_FT260) },
2326a82582dSMichael Zaidman 	{ /* END OF LIST */ }
2336a82582dSMichael Zaidman };
2346a82582dSMichael Zaidman MODULE_DEVICE_TABLE(hid, ft260_devices);
2356a82582dSMichael Zaidman 
2366a82582dSMichael Zaidman struct ft260_device {
2376a82582dSMichael Zaidman 	struct i2c_adapter adap;
2386a82582dSMichael Zaidman 	struct hid_device *hdev;
2396a82582dSMichael Zaidman 	struct completion wait;
2406a82582dSMichael Zaidman 	struct mutex lock;
2416a82582dSMichael Zaidman 	u8 write_buf[FT260_REPORT_MAX_LENGTH];
2424b3da685SMichael Zaidman 	unsigned long need_wakeup_at;
2436a82582dSMichael Zaidman 	u8 *read_buf;
2446a82582dSMichael Zaidman 	u16 read_idx;
2456a82582dSMichael Zaidman 	u16 read_len;
2466a82582dSMichael Zaidman 	u16 clock;
2476a82582dSMichael Zaidman };
2486a82582dSMichael Zaidman 
ft260_hid_feature_report_get(struct hid_device * hdev,unsigned char report_id,u8 * data,size_t len)2496a82582dSMichael Zaidman static int ft260_hid_feature_report_get(struct hid_device *hdev,
2506a82582dSMichael Zaidman 					unsigned char report_id, u8 *data,
2516a82582dSMichael Zaidman 					size_t len)
2526a82582dSMichael Zaidman {
2536a82582dSMichael Zaidman 	u8 *buf;
2546a82582dSMichael Zaidman 	int ret;
2556a82582dSMichael Zaidman 
2566a82582dSMichael Zaidman 	buf = kmalloc(len, GFP_KERNEL);
2576a82582dSMichael Zaidman 	if (!buf)
2586a82582dSMichael Zaidman 		return -ENOMEM;
2596a82582dSMichael Zaidman 
2606a82582dSMichael Zaidman 	ret = hid_hw_raw_request(hdev, report_id, buf, len, HID_FEATURE_REPORT,
2616a82582dSMichael Zaidman 				 HID_REQ_GET_REPORT);
26282f09a63SMichael Zaidman 	if (likely(ret == len))
2636a82582dSMichael Zaidman 		memcpy(data, buf, len);
26482f09a63SMichael Zaidman 	else if (ret >= 0)
26582f09a63SMichael Zaidman 		ret = -EIO;
2666a82582dSMichael Zaidman 	kfree(buf);
2676a82582dSMichael Zaidman 	return ret;
2686a82582dSMichael Zaidman }
2696a82582dSMichael Zaidman 
ft260_hid_feature_report_set(struct hid_device * hdev,u8 * data,size_t len)2706a82582dSMichael Zaidman static int ft260_hid_feature_report_set(struct hid_device *hdev, u8 *data,
2716a82582dSMichael Zaidman 					size_t len)
2726a82582dSMichael Zaidman {
2736a82582dSMichael Zaidman 	u8 *buf;
2746a82582dSMichael Zaidman 	int ret;
2756a82582dSMichael Zaidman 
2766a82582dSMichael Zaidman 	buf = kmemdup(data, len, GFP_KERNEL);
2776a82582dSMichael Zaidman 	if (!buf)
2786a82582dSMichael Zaidman 		return -ENOMEM;
2796a82582dSMichael Zaidman 
2806a82582dSMichael Zaidman 	buf[0] = FT260_SYSTEM_SETTINGS;
2816a82582dSMichael Zaidman 
2826a82582dSMichael Zaidman 	ret = hid_hw_raw_request(hdev, buf[0], buf, len, HID_FEATURE_REPORT,
2836a82582dSMichael Zaidman 				 HID_REQ_SET_REPORT);
2846a82582dSMichael Zaidman 
2856a82582dSMichael Zaidman 	kfree(buf);
2866a82582dSMichael Zaidman 	return ret;
2876a82582dSMichael Zaidman }
2886a82582dSMichael Zaidman 
ft260_i2c_reset(struct hid_device * hdev)2896a82582dSMichael Zaidman static int ft260_i2c_reset(struct hid_device *hdev)
2906a82582dSMichael Zaidman {
2916a82582dSMichael Zaidman 	struct ft260_set_i2c_reset_report report;
2926a82582dSMichael Zaidman 	int ret;
2936a82582dSMichael Zaidman 
2946a82582dSMichael Zaidman 	report.request = FT260_SET_I2C_RESET;
2956a82582dSMichael Zaidman 
2966a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_set(hdev, (u8 *)&report, sizeof(report));
2976a82582dSMichael Zaidman 	if (ret < 0) {
2986a82582dSMichael Zaidman 		hid_err(hdev, "failed to reset I2C controller: %d\n", ret);
2996a82582dSMichael Zaidman 		return ret;
3006a82582dSMichael Zaidman 	}
3016a82582dSMichael Zaidman 
3026a82582dSMichael Zaidman 	ft260_dbg("done\n");
3036a82582dSMichael Zaidman 	return ret;
3046a82582dSMichael Zaidman }
3056a82582dSMichael Zaidman 
ft260_xfer_status(struct ft260_device * dev,u8 bus_busy)3065afac727SMichael Zaidman static int ft260_xfer_status(struct ft260_device *dev, u8 bus_busy)
3076a82582dSMichael Zaidman {
3086a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
3096a82582dSMichael Zaidman 	struct ft260_get_i2c_status_report report;
3106a82582dSMichael Zaidman 	int ret;
3116a82582dSMichael Zaidman 
3124b3da685SMichael Zaidman 	if (time_is_before_jiffies(dev->need_wakeup_at)) {
3134b3da685SMichael Zaidman 		ret = ft260_hid_feature_report_get(hdev, FT260_I2C_STATUS,
3144b3da685SMichael Zaidman 						(u8 *)&report, sizeof(report));
3154b3da685SMichael Zaidman 		if (unlikely(ret < 0)) {
3164b3da685SMichael Zaidman 			hid_err(hdev, "failed to retrieve status: %d, no wakeup\n",
3174b3da685SMichael Zaidman 				ret);
3184b3da685SMichael Zaidman 		} else {
3194b3da685SMichael Zaidman 			dev->need_wakeup_at = jiffies +
3204b3da685SMichael Zaidman 				msecs_to_jiffies(FT260_WAKEUP_NEEDED_AFTER_MS);
3214b3da685SMichael Zaidman 			ft260_dbg("bus_status %#02x, wakeup\n",
3224b3da685SMichael Zaidman 				  report.bus_status);
3234b3da685SMichael Zaidman 		}
3244b3da685SMichael Zaidman 	}
3254b3da685SMichael Zaidman 
3266a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_get(hdev, FT260_I2C_STATUS,
3276a82582dSMichael Zaidman 					   (u8 *)&report, sizeof(report));
32882f09a63SMichael Zaidman 	if (unlikely(ret < 0)) {
3296a82582dSMichael Zaidman 		hid_err(hdev, "failed to retrieve status: %d\n", ret);
3306a82582dSMichael Zaidman 		return ret;
3316a82582dSMichael Zaidman 	}
3326a82582dSMichael Zaidman 
3336a82582dSMichael Zaidman 	dev->clock = le16_to_cpu(report.clock);
3346a82582dSMichael Zaidman 	ft260_dbg("bus_status %#02x, clock %u\n", report.bus_status,
3356a82582dSMichael Zaidman 		  dev->clock);
3366a82582dSMichael Zaidman 
3375afac727SMichael Zaidman 	if (report.bus_status & (FT260_I2C_STATUS_CTRL_BUSY | bus_busy))
3386a82582dSMichael Zaidman 		return -EAGAIN;
3396a82582dSMichael Zaidman 
340f45d50edSMichael Zaidman 	/*
341f45d50edSMichael Zaidman 	 * The error condition (bit 1) is a status bit reflecting any
342f45d50edSMichael Zaidman 	 * error conditions. When any of the bits 2, 3, or 4 are raised
343f45d50edSMichael Zaidman 	 * to 1, bit 1 is also set to 1.
344f45d50edSMichael Zaidman 	 */
345f45d50edSMichael Zaidman 	if (report.bus_status & FT260_I2C_STATUS_ERROR) {
346f45d50edSMichael Zaidman 		hid_err(hdev, "i2c bus error: %#02x\n", report.bus_status);
3476a82582dSMichael Zaidman 		return -EIO;
348f45d50edSMichael Zaidman 	}
3496a82582dSMichael Zaidman 
350f45d50edSMichael Zaidman 	return 0;
3516a82582dSMichael Zaidman }
3526a82582dSMichael Zaidman 
ft260_hid_output_report(struct hid_device * hdev,u8 * data,size_t len)3536a82582dSMichael Zaidman static int ft260_hid_output_report(struct hid_device *hdev, u8 *data,
3546a82582dSMichael Zaidman 				   size_t len)
3556a82582dSMichael Zaidman {
3566a82582dSMichael Zaidman 	u8 *buf;
3576a82582dSMichael Zaidman 	int ret;
3586a82582dSMichael Zaidman 
3596a82582dSMichael Zaidman 	buf = kmemdup(data, len, GFP_KERNEL);
3606a82582dSMichael Zaidman 	if (!buf)
3616a82582dSMichael Zaidman 		return -ENOMEM;
3626a82582dSMichael Zaidman 
3636a82582dSMichael Zaidman 	ret = hid_hw_output_report(hdev, buf, len);
3646a82582dSMichael Zaidman 
3656a82582dSMichael Zaidman 	kfree(buf);
3666a82582dSMichael Zaidman 	return ret;
3676a82582dSMichael Zaidman }
3686a82582dSMichael Zaidman 
ft260_hid_output_report_check_status(struct ft260_device * dev,u8 * data,int len)3696a82582dSMichael Zaidman static int ft260_hid_output_report_check_status(struct ft260_device *dev,
3706a82582dSMichael Zaidman 						u8 *data, int len)
3716a82582dSMichael Zaidman {
3725afac727SMichael Zaidman 	u8 bus_busy;
3736fca5e3fSMichael Zaidman 	int ret, usec, try = 100;
3746a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
3755afac727SMichael Zaidman 	struct ft260_i2c_write_request_report *rep =
3765afac727SMichael Zaidman 		(struct ft260_i2c_write_request_report *)data;
3776a82582dSMichael Zaidman 
3786a82582dSMichael Zaidman 	ret = ft260_hid_output_report(hdev, data, len);
3796a82582dSMichael Zaidman 	if (ret < 0) {
3806a82582dSMichael Zaidman 		hid_err(hdev, "%s: failed to start transfer, ret %d\n",
3816a82582dSMichael Zaidman 			__func__, ret);
3826a82582dSMichael Zaidman 		ft260_i2c_reset(hdev);
3836a82582dSMichael Zaidman 		return ret;
3846a82582dSMichael Zaidman 	}
3856a82582dSMichael Zaidman 
3866fca5e3fSMichael Zaidman 	/* transfer time = 1 / clock(KHz) * 9 bits * bytes */
3876fca5e3fSMichael Zaidman 	usec = len * 9000 / dev->clock;
3886fca5e3fSMichael Zaidman 	if (usec > 2000) {
3896fca5e3fSMichael Zaidman 		usec -= 1500;
3906a82582dSMichael Zaidman 		usleep_range(usec, usec + 100);
3916a82582dSMichael Zaidman 		ft260_dbg("wait %d usec, len %d\n", usec, len);
3926fca5e3fSMichael Zaidman 	}
3936fca5e3fSMichael Zaidman 
3945afac727SMichael Zaidman 	/*
3955afac727SMichael Zaidman 	 * Do not check the busy bit for combined transactions
3965afac727SMichael Zaidman 	 * since the controller keeps the bus busy between writing
3975afac727SMichael Zaidman 	 * and reading IOs to ensure an atomic operation.
3985afac727SMichael Zaidman 	 */
3995afac727SMichael Zaidman 	if (rep->flag == FT260_FLAG_START)
4005afac727SMichael Zaidman 		bus_busy = 0;
4015afac727SMichael Zaidman 	else
4025afac727SMichael Zaidman 		bus_busy = FT260_I2C_STATUS_BUS_BUSY;
4035afac727SMichael Zaidman 
4046a82582dSMichael Zaidman 	do {
4055afac727SMichael Zaidman 		ret = ft260_xfer_status(dev, bus_busy);
4066a82582dSMichael Zaidman 		if (ret != -EAGAIN)
4076a82582dSMichael Zaidman 			break;
4086a82582dSMichael Zaidman 	} while (--try);
4096a82582dSMichael Zaidman 
410f45d50edSMichael Zaidman 	if (ret == 0)
4116a82582dSMichael Zaidman 		return 0;
4126a82582dSMichael Zaidman 
4136a82582dSMichael Zaidman 	ft260_i2c_reset(hdev);
4146a82582dSMichael Zaidman 	return -EIO;
4156a82582dSMichael Zaidman }
4166a82582dSMichael Zaidman 
ft260_i2c_write(struct ft260_device * dev,u8 addr,u8 * data,int len,u8 flag)4176a82582dSMichael Zaidman static int ft260_i2c_write(struct ft260_device *dev, u8 addr, u8 *data,
4181edfae51SMichael Zaidman 			   int len, u8 flag)
4196a82582dSMichael Zaidman {
4201edfae51SMichael Zaidman 	int ret, wr_len, idx = 0;
4216a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
4226a82582dSMichael Zaidman 	struct ft260_i2c_write_request_report *rep =
4236a82582dSMichael Zaidman 		(struct ft260_i2c_write_request_report *)dev->write_buf;
4246a82582dSMichael Zaidman 
425c2500bdfSMichael Zaidman 	if (len < 1)
426c2500bdfSMichael Zaidman 		return -EINVAL;
427c2500bdfSMichael Zaidman 
4281edfae51SMichael Zaidman 	rep->flag = FT260_FLAG_START;
4291edfae51SMichael Zaidman 
4306a82582dSMichael Zaidman 	do {
4311edfae51SMichael Zaidman 		if (len <= FT260_WR_DATA_MAX) {
4321edfae51SMichael Zaidman 			wr_len = len;
4331edfae51SMichael Zaidman 			if (flag == FT260_FLAG_START_STOP)
4341edfae51SMichael Zaidman 				rep->flag |= FT260_FLAG_STOP;
4351edfae51SMichael Zaidman 		} else {
4361edfae51SMichael Zaidman 			wr_len = FT260_WR_DATA_MAX;
4371edfae51SMichael Zaidman 		}
4386a82582dSMichael Zaidman 
4391edfae51SMichael Zaidman 		rep->report = FT260_I2C_DATA_REPORT_ID(wr_len);
4406a82582dSMichael Zaidman 		rep->address = addr;
4411edfae51SMichael Zaidman 		rep->length = wr_len;
4426a82582dSMichael Zaidman 
4431edfae51SMichael Zaidman 		memcpy(rep->data, &data[idx], wr_len);
4446a82582dSMichael Zaidman 
4451edfae51SMichael Zaidman 		ft260_dbg("rep %#02x addr %#02x off %d len %d wlen %d flag %#x d[0] %#02x\n",
4461edfae51SMichael Zaidman 			  rep->report, addr, idx, len, wr_len,
4471edfae51SMichael Zaidman 			  rep->flag, data[0]);
4486a82582dSMichael Zaidman 
4496a82582dSMichael Zaidman 		ret = ft260_hid_output_report_check_status(dev, (u8 *)rep,
4501edfae51SMichael Zaidman 							   wr_len + 4);
4516a82582dSMichael Zaidman 		if (ret < 0) {
4521edfae51SMichael Zaidman 			hid_err(hdev, "%s: failed with %d\n", __func__, ret);
4536a82582dSMichael Zaidman 			return ret;
4546a82582dSMichael Zaidman 		}
4556a82582dSMichael Zaidman 
4561edfae51SMichael Zaidman 		len -= wr_len;
4571edfae51SMichael Zaidman 		idx += wr_len;
4581edfae51SMichael Zaidman 		rep->flag = 0;
4596a82582dSMichael Zaidman 
4601edfae51SMichael Zaidman 	} while (len > 0);
4616a82582dSMichael Zaidman 
4626a82582dSMichael Zaidman 	return 0;
4636a82582dSMichael Zaidman }
4646a82582dSMichael Zaidman 
ft260_smbus_write(struct ft260_device * dev,u8 addr,u8 cmd,u8 * data,u8 data_len,u8 flag)4656a82582dSMichael Zaidman static int ft260_smbus_write(struct ft260_device *dev, u8 addr, u8 cmd,
4666a82582dSMichael Zaidman 			     u8 *data, u8 data_len, u8 flag)
4676a82582dSMichael Zaidman {
4686a82582dSMichael Zaidman 	int ret = 0;
4696a82582dSMichael Zaidman 	int len = 4;
4706a82582dSMichael Zaidman 
4716a82582dSMichael Zaidman 	struct ft260_i2c_write_request_report *rep =
4726a82582dSMichael Zaidman 		(struct ft260_i2c_write_request_report *)dev->write_buf;
4736a82582dSMichael Zaidman 
474b45ef5dbSMichael Zaidman 	if (data_len >= sizeof(rep->data))
475b45ef5dbSMichael Zaidman 		return -EINVAL;
476b45ef5dbSMichael Zaidman 
4776a82582dSMichael Zaidman 	rep->address = addr;
4786a82582dSMichael Zaidman 	rep->data[0] = cmd;
4796a82582dSMichael Zaidman 	rep->length = data_len + 1;
4806a82582dSMichael Zaidman 	rep->flag = flag;
4816a82582dSMichael Zaidman 	len += rep->length;
4826a82582dSMichael Zaidman 
4836a82582dSMichael Zaidman 	rep->report = FT260_I2C_DATA_REPORT_ID(len);
4846a82582dSMichael Zaidman 
4856a82582dSMichael Zaidman 	if (data_len > 0)
4866a82582dSMichael Zaidman 		memcpy(&rep->data[1], data, data_len);
4876a82582dSMichael Zaidman 
4886a82582dSMichael Zaidman 	ft260_dbg("rep %#02x addr %#02x cmd %#02x datlen %d replen %d\n",
4896a82582dSMichael Zaidman 		  rep->report, addr, cmd, rep->length, len);
4906a82582dSMichael Zaidman 
4916a82582dSMichael Zaidman 	ret = ft260_hid_output_report_check_status(dev, (u8 *)rep, len);
4926a82582dSMichael Zaidman 
4936a82582dSMichael Zaidman 	return ret;
4946a82582dSMichael Zaidman }
4956a82582dSMichael Zaidman 
ft260_i2c_read(struct ft260_device * dev,u8 addr,u8 * data,u16 len,u8 flag)4966a82582dSMichael Zaidman static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data,
4976a82582dSMichael Zaidman 			  u16 len, u8 flag)
4986a82582dSMichael Zaidman {
4990acb869fSMichael Zaidman 	u16 rd_len;
500728b117eSMichael Zaidman 	u16 rd_data_max = 60;
501b7121e3cSMichael Zaidman 	int timeout, ret = 0;
5026a82582dSMichael Zaidman 	struct ft260_i2c_read_request_report rep;
5036a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
5045afac727SMichael Zaidman 	u8 bus_busy = 0;
5056a82582dSMichael Zaidman 
5060acb869fSMichael Zaidman 	if ((flag & FT260_FLAG_START_REPEATED) == FT260_FLAG_START_REPEATED)
5070acb869fSMichael Zaidman 		flag = FT260_FLAG_START_REPEATED;
5080acb869fSMichael Zaidman 	else
5090acb869fSMichael Zaidman 		flag = FT260_FLAG_START;
5100acb869fSMichael Zaidman 	do {
511728b117eSMichael Zaidman 		if (len <= rd_data_max) {
5120acb869fSMichael Zaidman 			rd_len = len;
5130acb869fSMichael Zaidman 			flag |= FT260_FLAG_STOP;
5140acb869fSMichael Zaidman 		} else {
515728b117eSMichael Zaidman 			rd_len = rd_data_max;
5166a82582dSMichael Zaidman 		}
517728b117eSMichael Zaidman 		rd_data_max = FT260_RD_DATA_MAX;
5186a82582dSMichael Zaidman 
5196a82582dSMichael Zaidman 		rep.report = FT260_I2C_READ_REQ;
5200acb869fSMichael Zaidman 		rep.length = cpu_to_le16(rd_len);
5216a82582dSMichael Zaidman 		rep.address = addr;
5226a82582dSMichael Zaidman 		rep.flag = flag;
5236a82582dSMichael Zaidman 
5240acb869fSMichael Zaidman 		ft260_dbg("rep %#02x addr %#02x len %d rlen %d flag %#x\n",
5250acb869fSMichael Zaidman 			  rep.report, rep.address, len, rd_len, flag);
5266a82582dSMichael Zaidman 
5276a82582dSMichael Zaidman 		reinit_completion(&dev->wait);
5286a82582dSMichael Zaidman 
529b7121e3cSMichael Zaidman 		dev->read_idx = 0;
530b7121e3cSMichael Zaidman 		dev->read_buf = data;
531b7121e3cSMichael Zaidman 		dev->read_len = rd_len;
532b7121e3cSMichael Zaidman 
5336a82582dSMichael Zaidman 		ret = ft260_hid_output_report(hdev, (u8 *)&rep, sizeof(rep));
5346a82582dSMichael Zaidman 		if (ret < 0) {
5350acb869fSMichael Zaidman 			hid_err(hdev, "%s: failed with %d\n", __func__, ret);
536b7121e3cSMichael Zaidman 			goto ft260_i2c_read_exit;
5376a82582dSMichael Zaidman 		}
5386a82582dSMichael Zaidman 
5396a82582dSMichael Zaidman 		timeout = msecs_to_jiffies(5000);
5406a82582dSMichael Zaidman 		if (!wait_for_completion_timeout(&dev->wait, timeout)) {
541b7121e3cSMichael Zaidman 			ret = -ETIMEDOUT;
5426a82582dSMichael Zaidman 			ft260_i2c_reset(hdev);
543b7121e3cSMichael Zaidman 			goto ft260_i2c_read_exit;
5446a82582dSMichael Zaidman 		}
5456a82582dSMichael Zaidman 
546b7121e3cSMichael Zaidman 		dev->read_buf = NULL;
547b7121e3cSMichael Zaidman 
5485afac727SMichael Zaidman 		if (flag & FT260_FLAG_STOP)
5495afac727SMichael Zaidman 			bus_busy = FT260_I2C_STATUS_BUS_BUSY;
5505afac727SMichael Zaidman 
5515afac727SMichael Zaidman 		ret = ft260_xfer_status(dev, bus_busy);
5520acb869fSMichael Zaidman 		if (ret < 0) {
553b7121e3cSMichael Zaidman 			ret = -EIO;
5546a82582dSMichael Zaidman 			ft260_i2c_reset(hdev);
555b7121e3cSMichael Zaidman 			goto ft260_i2c_read_exit;
5566a82582dSMichael Zaidman 		}
5576a82582dSMichael Zaidman 
5580acb869fSMichael Zaidman 		len -= rd_len;
5590acb869fSMichael Zaidman 		data += rd_len;
5600acb869fSMichael Zaidman 		flag = 0;
5610acb869fSMichael Zaidman 
5620acb869fSMichael Zaidman 	} while (len > 0);
5630acb869fSMichael Zaidman 
564b7121e3cSMichael Zaidman ft260_i2c_read_exit:
565b7121e3cSMichael Zaidman 	dev->read_buf = NULL;
566b7121e3cSMichael Zaidman 	return ret;
5670acb869fSMichael Zaidman }
5680acb869fSMichael Zaidman 
5696a82582dSMichael Zaidman /*
5706a82582dSMichael Zaidman  * A random read operation is implemented as a dummy write operation, followed
5716a82582dSMichael Zaidman  * by a current address read operation. The dummy write operation is used to
5726a82582dSMichael Zaidman  * load the target byte address into the current byte address counter, from
5736a82582dSMichael Zaidman  * which the subsequent current address read operation then reads.
5746a82582dSMichael Zaidman  */
ft260_i2c_write_read(struct ft260_device * dev,struct i2c_msg * msgs)5756a82582dSMichael Zaidman static int ft260_i2c_write_read(struct ft260_device *dev, struct i2c_msg *msgs)
5766a82582dSMichael Zaidman {
5770acb869fSMichael Zaidman 	int ret;
5780acb869fSMichael Zaidman 	int wr_len = msgs[0].len;
5790acb869fSMichael Zaidman 	int rd_len = msgs[1].len;
5800acb869fSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
5816a82582dSMichael Zaidman 	u8 addr = msgs[0].addr;
5826a82582dSMichael Zaidman 	u16 read_off = 0;
5836a82582dSMichael Zaidman 
5840acb869fSMichael Zaidman 	if (wr_len > 2) {
5850acb869fSMichael Zaidman 		hid_err(hdev, "%s: invalid wr_len: %d\n", __func__, wr_len);
5866a82582dSMichael Zaidman 		return -EOPNOTSUPP;
5876a82582dSMichael Zaidman 	}
5886a82582dSMichael Zaidman 
5890acb869fSMichael Zaidman 	if (ft260_debug) {
5900acb869fSMichael Zaidman 		if (wr_len == 2)
591*fb5d783bSMichael Zaidman 			read_off = be16_to_cpu(*(__be16 *)msgs[0].buf);
5926a82582dSMichael Zaidman 		else
5930acb869fSMichael Zaidman 			read_off = *msgs[0].buf;
5946a82582dSMichael Zaidman 
5950acb869fSMichael Zaidman 		pr_info("%s: off %#x rlen %d wlen %d\n", __func__,
5960acb869fSMichael Zaidman 			read_off, rd_len, wr_len);
5970acb869fSMichael Zaidman 	}
5986a82582dSMichael Zaidman 
5990acb869fSMichael Zaidman 	ret = ft260_i2c_write(dev, addr, msgs[0].buf, wr_len,
6006a82582dSMichael Zaidman 			      FT260_FLAG_START);
6016a82582dSMichael Zaidman 	if (ret < 0)
6026a82582dSMichael Zaidman 		return ret;
6036a82582dSMichael Zaidman 
6040acb869fSMichael Zaidman 	ret = ft260_i2c_read(dev, addr, msgs[1].buf, rd_len,
6050acb869fSMichael Zaidman 			     FT260_FLAG_START_STOP_REPEATED);
6066a82582dSMichael Zaidman 	if (ret < 0)
6076a82582dSMichael Zaidman 		return ret;
6086a82582dSMichael Zaidman 
6096a82582dSMichael Zaidman 	return 0;
6106a82582dSMichael Zaidman }
6116a82582dSMichael Zaidman 
ft260_i2c_xfer(struct i2c_adapter * adapter,struct i2c_msg * msgs,int num)6126a82582dSMichael Zaidman static int ft260_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
6136a82582dSMichael Zaidman 			  int num)
6146a82582dSMichael Zaidman {
6156a82582dSMichael Zaidman 	int ret;
6166a82582dSMichael Zaidman 	struct ft260_device *dev = i2c_get_adapdata(adapter);
6176a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
6186a82582dSMichael Zaidman 
6196a82582dSMichael Zaidman 	mutex_lock(&dev->lock);
6206a82582dSMichael Zaidman 
6216a82582dSMichael Zaidman 	ret = hid_hw_power(hdev, PM_HINT_FULLON);
6226a82582dSMichael Zaidman 	if (ret < 0) {
6236a82582dSMichael Zaidman 		hid_err(hdev, "failed to enter FULLON power mode: %d\n", ret);
6246a82582dSMichael Zaidman 		mutex_unlock(&dev->lock);
6256a82582dSMichael Zaidman 		return ret;
6266a82582dSMichael Zaidman 	}
6276a82582dSMichael Zaidman 
6286a82582dSMichael Zaidman 	if (num == 1) {
6296a82582dSMichael Zaidman 		if (msgs->flags & I2C_M_RD)
6306a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, msgs->addr, msgs->buf,
6316a82582dSMichael Zaidman 					     msgs->len, FT260_FLAG_START_STOP);
6326a82582dSMichael Zaidman 		else
6336a82582dSMichael Zaidman 			ret = ft260_i2c_write(dev, msgs->addr, msgs->buf,
6346a82582dSMichael Zaidman 					      msgs->len, FT260_FLAG_START_STOP);
6356a82582dSMichael Zaidman 		if (ret < 0)
6366a82582dSMichael Zaidman 			goto i2c_exit;
6376a82582dSMichael Zaidman 
6386a82582dSMichael Zaidman 	} else {
6396a82582dSMichael Zaidman 		/* Combined write then read message */
6406a82582dSMichael Zaidman 		ret = ft260_i2c_write_read(dev, msgs);
6416a82582dSMichael Zaidman 		if (ret < 0)
6426a82582dSMichael Zaidman 			goto i2c_exit;
6436a82582dSMichael Zaidman 	}
6446a82582dSMichael Zaidman 
6456a82582dSMichael Zaidman 	ret = num;
6466a82582dSMichael Zaidman i2c_exit:
6476a82582dSMichael Zaidman 	hid_hw_power(hdev, PM_HINT_NORMAL);
6486a82582dSMichael Zaidman 	mutex_unlock(&dev->lock);
6496a82582dSMichael Zaidman 	return ret;
6506a82582dSMichael Zaidman }
6516a82582dSMichael Zaidman 
ft260_smbus_xfer(struct i2c_adapter * adapter,u16 addr,u16 flags,char read_write,u8 cmd,int size,union i2c_smbus_data * data)6526a82582dSMichael Zaidman static int ft260_smbus_xfer(struct i2c_adapter *adapter, u16 addr, u16 flags,
6536a82582dSMichael Zaidman 			    char read_write, u8 cmd, int size,
6546a82582dSMichael Zaidman 			    union i2c_smbus_data *data)
6556a82582dSMichael Zaidman {
6566a82582dSMichael Zaidman 	int ret;
6576a82582dSMichael Zaidman 	struct ft260_device *dev = i2c_get_adapdata(adapter);
6586a82582dSMichael Zaidman 	struct hid_device *hdev = dev->hdev;
6596a82582dSMichael Zaidman 
6606a82582dSMichael Zaidman 	ft260_dbg("smbus size %d\n", size);
6616a82582dSMichael Zaidman 
6626a82582dSMichael Zaidman 	mutex_lock(&dev->lock);
6636a82582dSMichael Zaidman 
6646a82582dSMichael Zaidman 	ret = hid_hw_power(hdev, PM_HINT_FULLON);
6656a82582dSMichael Zaidman 	if (ret < 0) {
6666a82582dSMichael Zaidman 		hid_err(hdev, "power management error: %d\n", ret);
6676a82582dSMichael Zaidman 		mutex_unlock(&dev->lock);
6686a82582dSMichael Zaidman 		return ret;
6696a82582dSMichael Zaidman 	}
6706a82582dSMichael Zaidman 
6716a82582dSMichael Zaidman 	switch (size) {
6726a82582dSMichael Zaidman 	case I2C_SMBUS_BYTE:
6736a82582dSMichael Zaidman 		if (read_write == I2C_SMBUS_READ)
6746a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, addr, &data->byte, 1,
6756a82582dSMichael Zaidman 					     FT260_FLAG_START_STOP);
6766a82582dSMichael Zaidman 		else
6776a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
6786a82582dSMichael Zaidman 						FT260_FLAG_START_STOP);
6796a82582dSMichael Zaidman 		break;
6806a82582dSMichael Zaidman 	case I2C_SMBUS_BYTE_DATA:
6816a82582dSMichael Zaidman 		if (read_write == I2C_SMBUS_READ) {
6826a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
6836a82582dSMichael Zaidman 						FT260_FLAG_START);
6846a82582dSMichael Zaidman 			if (ret)
6856a82582dSMichael Zaidman 				goto smbus_exit;
6866a82582dSMichael Zaidman 
6876a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, addr, &data->byte, 1,
6886a82582dSMichael Zaidman 					     FT260_FLAG_START_STOP_REPEATED);
6896a82582dSMichael Zaidman 		} else {
6906a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, &data->byte, 1,
6916a82582dSMichael Zaidman 						FT260_FLAG_START_STOP);
6926a82582dSMichael Zaidman 		}
6936a82582dSMichael Zaidman 		break;
6946a82582dSMichael Zaidman 	case I2C_SMBUS_WORD_DATA:
6956a82582dSMichael Zaidman 		if (read_write == I2C_SMBUS_READ) {
6966a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
6976a82582dSMichael Zaidman 						FT260_FLAG_START);
6986a82582dSMichael Zaidman 			if (ret)
6996a82582dSMichael Zaidman 				goto smbus_exit;
7006a82582dSMichael Zaidman 
7016a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, addr, (u8 *)&data->word, 2,
7026a82582dSMichael Zaidman 					     FT260_FLAG_START_STOP_REPEATED);
7036a82582dSMichael Zaidman 		} else {
7046a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd,
7056a82582dSMichael Zaidman 						(u8 *)&data->word, 2,
7066a82582dSMichael Zaidman 						FT260_FLAG_START_STOP);
7076a82582dSMichael Zaidman 		}
7086a82582dSMichael Zaidman 		break;
7096a82582dSMichael Zaidman 	case I2C_SMBUS_BLOCK_DATA:
7106a82582dSMichael Zaidman 		if (read_write == I2C_SMBUS_READ) {
7116a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
7126a82582dSMichael Zaidman 						FT260_FLAG_START);
7136a82582dSMichael Zaidman 			if (ret)
7146a82582dSMichael Zaidman 				goto smbus_exit;
7156a82582dSMichael Zaidman 
7166a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, addr, data->block,
7176a82582dSMichael Zaidman 					     data->block[0] + 1,
7186a82582dSMichael Zaidman 					     FT260_FLAG_START_STOP_REPEATED);
7196a82582dSMichael Zaidman 		} else {
7206a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, data->block,
7216a82582dSMichael Zaidman 						data->block[0] + 1,
7226a82582dSMichael Zaidman 						FT260_FLAG_START_STOP);
7236a82582dSMichael Zaidman 		}
7246a82582dSMichael Zaidman 		break;
7256a82582dSMichael Zaidman 	case I2C_SMBUS_I2C_BLOCK_DATA:
7266a82582dSMichael Zaidman 		if (read_write == I2C_SMBUS_READ) {
7276a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, NULL, 0,
7286a82582dSMichael Zaidman 						FT260_FLAG_START);
7296a82582dSMichael Zaidman 			if (ret)
7306a82582dSMichael Zaidman 				goto smbus_exit;
7316a82582dSMichael Zaidman 
7326a82582dSMichael Zaidman 			ret = ft260_i2c_read(dev, addr, data->block + 1,
7336a82582dSMichael Zaidman 					     data->block[0],
7346a82582dSMichael Zaidman 					     FT260_FLAG_START_STOP_REPEATED);
7356a82582dSMichael Zaidman 		} else {
7366a82582dSMichael Zaidman 			ret = ft260_smbus_write(dev, addr, cmd, data->block + 1,
7376a82582dSMichael Zaidman 						data->block[0],
7386a82582dSMichael Zaidman 						FT260_FLAG_START_STOP);
7396a82582dSMichael Zaidman 		}
7406a82582dSMichael Zaidman 		break;
7416a82582dSMichael Zaidman 	default:
7426a82582dSMichael Zaidman 		hid_err(hdev, "unsupported smbus transaction size %d\n", size);
7436a82582dSMichael Zaidman 		ret = -EOPNOTSUPP;
7446a82582dSMichael Zaidman 	}
7456a82582dSMichael Zaidman 
7466a82582dSMichael Zaidman smbus_exit:
7476a82582dSMichael Zaidman 	hid_hw_power(hdev, PM_HINT_NORMAL);
7486a82582dSMichael Zaidman 	mutex_unlock(&dev->lock);
7496a82582dSMichael Zaidman 	return ret;
7506a82582dSMichael Zaidman }
7516a82582dSMichael Zaidman 
ft260_functionality(struct i2c_adapter * adap)7526a82582dSMichael Zaidman static u32 ft260_functionality(struct i2c_adapter *adap)
7536a82582dSMichael Zaidman {
7543b56ff48SMichael Zaidman 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE |
7556a82582dSMichael Zaidman 	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
7566a82582dSMichael Zaidman 	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
7576a82582dSMichael Zaidman }
7586a82582dSMichael Zaidman 
7596a82582dSMichael Zaidman static const struct i2c_adapter_quirks ft260_i2c_quirks = {
7606a82582dSMichael Zaidman 	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
7616a82582dSMichael Zaidman 	.max_comb_1st_msg_len = 2,
7626a82582dSMichael Zaidman };
7636a82582dSMichael Zaidman 
7646a82582dSMichael Zaidman static const struct i2c_algorithm ft260_i2c_algo = {
7656a82582dSMichael Zaidman 	.master_xfer = ft260_i2c_xfer,
7666a82582dSMichael Zaidman 	.smbus_xfer = ft260_smbus_xfer,
7676a82582dSMichael Zaidman 	.functionality = ft260_functionality,
7686a82582dSMichael Zaidman };
7696a82582dSMichael Zaidman 
ft260_get_system_config(struct hid_device * hdev,struct ft260_get_system_status_report * cfg)7706a82582dSMichael Zaidman static int ft260_get_system_config(struct hid_device *hdev,
7716a82582dSMichael Zaidman 				   struct ft260_get_system_status_report *cfg)
7726a82582dSMichael Zaidman {
7736a82582dSMichael Zaidman 	int ret;
7746a82582dSMichael Zaidman 	int len = sizeof(struct ft260_get_system_status_report);
7756a82582dSMichael Zaidman 
7766a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_get(hdev, FT260_SYSTEM_SETTINGS,
7776a82582dSMichael Zaidman 					   (u8 *)cfg, len);
77882f09a63SMichael Zaidman 	if (ret < 0) {
7796a82582dSMichael Zaidman 		hid_err(hdev, "failed to retrieve system status\n");
78082f09a63SMichael Zaidman 		return ret;
7816a82582dSMichael Zaidman 	}
7826a82582dSMichael Zaidman 	return 0;
7836a82582dSMichael Zaidman }
7846a82582dSMichael Zaidman 
ft260_is_interface_enabled(struct hid_device * hdev)7856a82582dSMichael Zaidman static int ft260_is_interface_enabled(struct hid_device *hdev)
7866a82582dSMichael Zaidman {
7876a82582dSMichael Zaidman 	struct ft260_get_system_status_report cfg;
7886a82582dSMichael Zaidman 	struct usb_interface *usbif = to_usb_interface(hdev->dev.parent);
7896a82582dSMichael Zaidman 	int interface = usbif->cur_altsetting->desc.bInterfaceNumber;
7906a82582dSMichael Zaidman 	int ret;
7916a82582dSMichael Zaidman 
7926a82582dSMichael Zaidman 	ret = ft260_get_system_config(hdev, &cfg);
793db8d3a21SMichael Zaidman 	if (ret < 0)
7946a82582dSMichael Zaidman 		return ret;
7956a82582dSMichael Zaidman 
7966a82582dSMichael Zaidman 	ft260_dbg("interface:  0x%02x\n", interface);
7976a82582dSMichael Zaidman 	ft260_dbg("chip mode:  0x%02x\n", cfg.chip_mode);
7986a82582dSMichael Zaidman 	ft260_dbg("clock_ctl:  0x%02x\n", cfg.clock_ctl);
7996a82582dSMichael Zaidman 	ft260_dbg("i2c_enable: 0x%02x\n", cfg.i2c_enable);
8006a82582dSMichael Zaidman 	ft260_dbg("uart_mode:  0x%02x\n", cfg.uart_mode);
8016a82582dSMichael Zaidman 
8026a82582dSMichael Zaidman 	switch (cfg.chip_mode) {
8036a82582dSMichael Zaidman 	case FT260_MODE_ALL:
8046a82582dSMichael Zaidman 	case FT260_MODE_BOTH:
805db8d3a21SMichael Zaidman 		if (interface == 1)
8066a82582dSMichael Zaidman 			hid_info(hdev, "uart interface is not supported\n");
807db8d3a21SMichael Zaidman 		else
8086a82582dSMichael Zaidman 			ret = 1;
8096a82582dSMichael Zaidman 		break;
8106a82582dSMichael Zaidman 	case FT260_MODE_UART:
811db8d3a21SMichael Zaidman 		hid_info(hdev, "uart interface is not supported\n");
8126a82582dSMichael Zaidman 		break;
8136a82582dSMichael Zaidman 	case FT260_MODE_I2C:
814db8d3a21SMichael Zaidman 		ret = 1;
8156a82582dSMichael Zaidman 		break;
8166a82582dSMichael Zaidman 	}
8176a82582dSMichael Zaidman 	return ret;
8186a82582dSMichael Zaidman }
8196a82582dSMichael Zaidman 
ft260_byte_show(struct hid_device * hdev,int id,u8 * cfg,int len,u8 * field,u8 * buf)8206a82582dSMichael Zaidman static int ft260_byte_show(struct hid_device *hdev, int id, u8 *cfg, int len,
8216a82582dSMichael Zaidman 			   u8 *field, u8 *buf)
8226a82582dSMichael Zaidman {
8236a82582dSMichael Zaidman 	int ret;
8246a82582dSMichael Zaidman 
8256a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_get(hdev, id, cfg, len);
82682f09a63SMichael Zaidman 	if (ret < 0)
82782f09a63SMichael Zaidman 		return ret;
8286a82582dSMichael Zaidman 
8299f59efcdSMichael Zaidman 	return scnprintf(buf, PAGE_SIZE, "%d\n", *field);
8306a82582dSMichael Zaidman }
8316a82582dSMichael Zaidman 
ft260_word_show(struct hid_device * hdev,int id,u8 * cfg,int len,__le16 * field,u8 * buf)8326a82582dSMichael Zaidman static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len,
833*fb5d783bSMichael Zaidman 			   __le16 *field, u8 *buf)
8346a82582dSMichael Zaidman {
8356a82582dSMichael Zaidman 	int ret;
8366a82582dSMichael Zaidman 
8376a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_get(hdev, id, cfg, len);
83882f09a63SMichael Zaidman 	if (ret < 0)
83982f09a63SMichael Zaidman 		return ret;
8406a82582dSMichael Zaidman 
8419f59efcdSMichael Zaidman 	return scnprintf(buf, PAGE_SIZE, "%d\n", le16_to_cpu(*field));
8426a82582dSMichael Zaidman }
8436a82582dSMichael Zaidman 
8446a82582dSMichael Zaidman #define FT260_ATTR_SHOW(name, reptype, id, type, func)			       \
8456a82582dSMichael Zaidman 	static ssize_t name##_show(struct device *kdev,			       \
8466a82582dSMichael Zaidman 				   struct device_attribute *attr, char *buf)   \
8476a82582dSMichael Zaidman 	{								       \
8486a82582dSMichael Zaidman 		struct reptype rep;					       \
8496a82582dSMichael Zaidman 		struct hid_device *hdev = to_hid_device(kdev);		       \
8506a82582dSMichael Zaidman 		type *field = &rep.name;				       \
8516a82582dSMichael Zaidman 		int len = sizeof(rep);					       \
8526a82582dSMichael Zaidman 									       \
8536a82582dSMichael Zaidman 		return func(hdev, id, (u8 *)&rep, len, field, buf);	       \
8546a82582dSMichael Zaidman 	}
8556a82582dSMichael Zaidman 
8566a82582dSMichael Zaidman #define FT260_SSTAT_ATTR_SHOW(name)					       \
8576a82582dSMichael Zaidman 		FT260_ATTR_SHOW(name, ft260_get_system_status_report,	       \
8586a82582dSMichael Zaidman 				FT260_SYSTEM_SETTINGS, u8, ft260_byte_show)
8596a82582dSMichael Zaidman 
8606a82582dSMichael Zaidman #define FT260_I2CST_ATTR_SHOW(name)					       \
8616a82582dSMichael Zaidman 		FT260_ATTR_SHOW(name, ft260_get_i2c_status_report,	       \
862*fb5d783bSMichael Zaidman 				FT260_I2C_STATUS, __le16, ft260_word_show)
8636a82582dSMichael Zaidman 
864*fb5d783bSMichael Zaidman #define FT260_ATTR_STORE(name, reptype, id, req, type, ctype, func)	       \
8656a82582dSMichael Zaidman 	static ssize_t name##_store(struct device *kdev,		       \
8666a82582dSMichael Zaidman 				    struct device_attribute *attr,	       \
8676a82582dSMichael Zaidman 				    const char *buf, size_t count)	       \
8686a82582dSMichael Zaidman 	{								       \
8696a82582dSMichael Zaidman 		struct reptype rep;					       \
8706a82582dSMichael Zaidman 		struct hid_device *hdev = to_hid_device(kdev);		       \
8716a82582dSMichael Zaidman 		type name;						       \
8726a82582dSMichael Zaidman 		int ret;						       \
8736a82582dSMichael Zaidman 									       \
874*fb5d783bSMichael Zaidman 		if (!func(buf, 10, (ctype *)&name)) {			       \
8756a82582dSMichael Zaidman 			rep.name = name;				       \
8766a82582dSMichael Zaidman 			rep.report = id;				       \
8776a82582dSMichael Zaidman 			rep.request = req;				       \
8786a82582dSMichael Zaidman 			ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep,   \
8796a82582dSMichael Zaidman 							   sizeof(rep));       \
8806a82582dSMichael Zaidman 			if (!ret)					       \
8816a82582dSMichael Zaidman 				ret = count;				       \
8826a82582dSMichael Zaidman 		} else {						       \
8836a82582dSMichael Zaidman 			ret = -EINVAL;					       \
8846a82582dSMichael Zaidman 		}							       \
8856a82582dSMichael Zaidman 		return ret;						       \
8866a82582dSMichael Zaidman 	}
8876a82582dSMichael Zaidman 
8886a82582dSMichael Zaidman #define FT260_BYTE_ATTR_STORE(name, reptype, req)			       \
8896a82582dSMichael Zaidman 		FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req,    \
890*fb5d783bSMichael Zaidman 				 u8, u8, kstrtou8)
8916a82582dSMichael Zaidman 
8926a82582dSMichael Zaidman #define FT260_WORD_ATTR_STORE(name, reptype, req)			       \
8936a82582dSMichael Zaidman 		FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req,    \
894*fb5d783bSMichael Zaidman 				 __le16, u16, kstrtou16)
8956a82582dSMichael Zaidman 
8966a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(chip_mode);
8976a82582dSMichael Zaidman static DEVICE_ATTR_RO(chip_mode);
8986a82582dSMichael Zaidman 
8996a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(pwren_status);
9006a82582dSMichael Zaidman static DEVICE_ATTR_RO(pwren_status);
9016a82582dSMichael Zaidman 
9026a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(suspend_status);
9036a82582dSMichael Zaidman static DEVICE_ATTR_RO(suspend_status);
9046a82582dSMichael Zaidman 
9056a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(hid_over_i2c_en);
9066a82582dSMichael Zaidman static DEVICE_ATTR_RO(hid_over_i2c_en);
9076a82582dSMichael Zaidman 
9086a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(power_saving_en);
9096a82582dSMichael Zaidman static DEVICE_ATTR_RO(power_saving_en);
9106a82582dSMichael Zaidman 
9116a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(i2c_enable);
9126a82582dSMichael Zaidman FT260_BYTE_ATTR_STORE(i2c_enable, ft260_set_i2c_mode_report,
9136a82582dSMichael Zaidman 		      FT260_SET_I2C_MODE);
9146a82582dSMichael Zaidman static DEVICE_ATTR_RW(i2c_enable);
9156a82582dSMichael Zaidman 
9166a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(uart_mode);
9176a82582dSMichael Zaidman FT260_BYTE_ATTR_STORE(uart_mode, ft260_set_uart_mode_report,
9186a82582dSMichael Zaidman 		      FT260_SET_UART_MODE);
9196a82582dSMichael Zaidman static DEVICE_ATTR_RW(uart_mode);
9206a82582dSMichael Zaidman 
9216a82582dSMichael Zaidman FT260_SSTAT_ATTR_SHOW(clock_ctl);
9226a82582dSMichael Zaidman FT260_BYTE_ATTR_STORE(clock_ctl, ft260_set_system_clock_report,
9236a82582dSMichael Zaidman 		      FT260_SET_CLOCK);
9246a82582dSMichael Zaidman static DEVICE_ATTR_RW(clock_ctl);
9256a82582dSMichael Zaidman 
9266a82582dSMichael Zaidman FT260_I2CST_ATTR_SHOW(clock);
9276a82582dSMichael Zaidman FT260_WORD_ATTR_STORE(clock, ft260_set_i2c_speed_report,
9286a82582dSMichael Zaidman 		      FT260_SET_I2C_CLOCK_SPEED);
9296a82582dSMichael Zaidman static DEVICE_ATTR_RW(clock);
9306a82582dSMichael Zaidman 
i2c_reset_store(struct device * kdev,struct device_attribute * attr,const char * buf,size_t count)9316a82582dSMichael Zaidman static ssize_t i2c_reset_store(struct device *kdev,
9326a82582dSMichael Zaidman 			       struct device_attribute *attr, const char *buf,
9336a82582dSMichael Zaidman 			       size_t count)
9346a82582dSMichael Zaidman {
9356a82582dSMichael Zaidman 	struct hid_device *hdev = to_hid_device(kdev);
9366a82582dSMichael Zaidman 	int ret = ft260_i2c_reset(hdev);
9376a82582dSMichael Zaidman 
9386a82582dSMichael Zaidman 	if (ret)
9396a82582dSMichael Zaidman 		return ret;
9406a82582dSMichael Zaidman 	return count;
9416a82582dSMichael Zaidman }
9426a82582dSMichael Zaidman static DEVICE_ATTR_WO(i2c_reset);
9436a82582dSMichael Zaidman 
9446a82582dSMichael Zaidman static const struct attribute_group ft260_attr_group = {
9456a82582dSMichael Zaidman 	.attrs = (struct attribute *[]) {
9466a82582dSMichael Zaidman 		  &dev_attr_chip_mode.attr,
9476a82582dSMichael Zaidman 		  &dev_attr_pwren_status.attr,
9486a82582dSMichael Zaidman 		  &dev_attr_suspend_status.attr,
9496a82582dSMichael Zaidman 		  &dev_attr_hid_over_i2c_en.attr,
9506a82582dSMichael Zaidman 		  &dev_attr_power_saving_en.attr,
9516a82582dSMichael Zaidman 		  &dev_attr_i2c_enable.attr,
9526a82582dSMichael Zaidman 		  &dev_attr_uart_mode.attr,
9536a82582dSMichael Zaidman 		  &dev_attr_clock_ctl.attr,
9546a82582dSMichael Zaidman 		  &dev_attr_i2c_reset.attr,
9556a82582dSMichael Zaidman 		  &dev_attr_clock.attr,
9566a82582dSMichael Zaidman 		  NULL
9576a82582dSMichael Zaidman 	}
9586a82582dSMichael Zaidman };
9596a82582dSMichael Zaidman 
ft260_probe(struct hid_device * hdev,const struct hid_device_id * id)9606a82582dSMichael Zaidman static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
9616a82582dSMichael Zaidman {
9626a82582dSMichael Zaidman 	struct ft260_device *dev;
9636a82582dSMichael Zaidman 	struct ft260_get_chip_version_report version;
9646a82582dSMichael Zaidman 	int ret;
9656a82582dSMichael Zaidman 
96693020953SGreg Kroah-Hartman 	if (!hid_is_usb(hdev))
96793020953SGreg Kroah-Hartman 		return -EINVAL;
96893020953SGreg Kroah-Hartman 
9696a82582dSMichael Zaidman 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
9706a82582dSMichael Zaidman 	if (!dev)
9716a82582dSMichael Zaidman 		return -ENOMEM;
9726a82582dSMichael Zaidman 
9736a82582dSMichael Zaidman 	ret = hid_parse(hdev);
9746a82582dSMichael Zaidman 	if (ret) {
9756a82582dSMichael Zaidman 		hid_err(hdev, "failed to parse HID\n");
9766a82582dSMichael Zaidman 		return ret;
9776a82582dSMichael Zaidman 	}
9786a82582dSMichael Zaidman 
97976e76e79SMichael Zaidman 	ret = hid_hw_start(hdev, 0);
9806a82582dSMichael Zaidman 	if (ret) {
9816a82582dSMichael Zaidman 		hid_err(hdev, "failed to start HID HW\n");
9826a82582dSMichael Zaidman 		return ret;
9836a82582dSMichael Zaidman 	}
9846a82582dSMichael Zaidman 
9856a82582dSMichael Zaidman 	ret = hid_hw_open(hdev);
9866a82582dSMichael Zaidman 	if (ret) {
9876a82582dSMichael Zaidman 		hid_err(hdev, "failed to open HID HW\n");
9886a82582dSMichael Zaidman 		goto err_hid_stop;
9896a82582dSMichael Zaidman 	}
9906a82582dSMichael Zaidman 
9916a82582dSMichael Zaidman 	ret = ft260_hid_feature_report_get(hdev, FT260_CHIP_VERSION,
9926a82582dSMichael Zaidman 					   (u8 *)&version, sizeof(version));
99382f09a63SMichael Zaidman 	if (ret < 0) {
9946a82582dSMichael Zaidman 		hid_err(hdev, "failed to retrieve chip version\n");
9956a82582dSMichael Zaidman 		goto err_hid_close;
9966a82582dSMichael Zaidman 	}
9976a82582dSMichael Zaidman 
9986a82582dSMichael Zaidman 	hid_info(hdev, "chip code: %02x%02x %02x%02x\n",
9996a82582dSMichael Zaidman 		 version.chip_code[0], version.chip_code[1],
10006a82582dSMichael Zaidman 		 version.chip_code[2], version.chip_code[3]);
10016a82582dSMichael Zaidman 
10026a82582dSMichael Zaidman 	ret = ft260_is_interface_enabled(hdev);
10036a82582dSMichael Zaidman 	if (ret <= 0)
10046a82582dSMichael Zaidman 		goto err_hid_close;
10056a82582dSMichael Zaidman 
100676e76e79SMichael Zaidman 	hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n",
100776e76e79SMichael Zaidman 		hdev->version >> 8, hdev->version & 0xff, hdev->name,
100876e76e79SMichael Zaidman 		hdev->phys);
100976e76e79SMichael Zaidman 
10106a82582dSMichael Zaidman 	hid_set_drvdata(hdev, dev);
10116a82582dSMichael Zaidman 	dev->hdev = hdev;
10126a82582dSMichael Zaidman 	dev->adap.owner = THIS_MODULE;
10136a82582dSMichael Zaidman 	dev->adap.class = I2C_CLASS_HWMON;
10146a82582dSMichael Zaidman 	dev->adap.algo = &ft260_i2c_algo;
10156a82582dSMichael Zaidman 	dev->adap.quirks = &ft260_i2c_quirks;
10166a82582dSMichael Zaidman 	dev->adap.dev.parent = &hdev->dev;
10176a82582dSMichael Zaidman 	snprintf(dev->adap.name, sizeof(dev->adap.name),
101876e76e79SMichael Zaidman 		 "FT260 usb-i2c bridge");
10196a82582dSMichael Zaidman 
10206a82582dSMichael Zaidman 	mutex_init(&dev->lock);
10216a82582dSMichael Zaidman 	init_completion(&dev->wait);
10226a82582dSMichael Zaidman 
10235afac727SMichael Zaidman 	ret = ft260_xfer_status(dev, FT260_I2C_STATUS_BUS_BUSY);
1024a94f61e6SMichael Zaidman 	if (ret)
1025a94f61e6SMichael Zaidman 		ft260_i2c_reset(hdev);
1026a94f61e6SMichael Zaidman 
1027a94f61e6SMichael Zaidman 	i2c_set_adapdata(&dev->adap, dev);
10286a82582dSMichael Zaidman 	ret = i2c_add_adapter(&dev->adap);
10296a82582dSMichael Zaidman 	if (ret) {
10306a82582dSMichael Zaidman 		hid_err(hdev, "failed to add i2c adapter\n");
10316a82582dSMichael Zaidman 		goto err_hid_close;
10326a82582dSMichael Zaidman 	}
10336a82582dSMichael Zaidman 
10346a82582dSMichael Zaidman 	ret = sysfs_create_group(&hdev->dev.kobj, &ft260_attr_group);
10356a82582dSMichael Zaidman 	if (ret < 0) {
10366a82582dSMichael Zaidman 		hid_err(hdev, "failed to create sysfs attrs\n");
10376a82582dSMichael Zaidman 		goto err_i2c_free;
10386a82582dSMichael Zaidman 	}
10396a82582dSMichael Zaidman 
10406a82582dSMichael Zaidman 	return 0;
10416a82582dSMichael Zaidman 
10426a82582dSMichael Zaidman err_i2c_free:
10436a82582dSMichael Zaidman 	i2c_del_adapter(&dev->adap);
10446a82582dSMichael Zaidman err_hid_close:
10456a82582dSMichael Zaidman 	hid_hw_close(hdev);
10466a82582dSMichael Zaidman err_hid_stop:
10476a82582dSMichael Zaidman 	hid_hw_stop(hdev);
10486a82582dSMichael Zaidman 	return ret;
10496a82582dSMichael Zaidman }
10506a82582dSMichael Zaidman 
ft260_remove(struct hid_device * hdev)10516a82582dSMichael Zaidman static void ft260_remove(struct hid_device *hdev)
10526a82582dSMichael Zaidman {
10536a82582dSMichael Zaidman 	struct ft260_device *dev = hid_get_drvdata(hdev);
10546a82582dSMichael Zaidman 
1055db8d3a21SMichael Zaidman 	if (!dev)
10566a82582dSMichael Zaidman 		return;
10576a82582dSMichael Zaidman 
10586a82582dSMichael Zaidman 	sysfs_remove_group(&hdev->dev.kobj, &ft260_attr_group);
10596a82582dSMichael Zaidman 	i2c_del_adapter(&dev->adap);
10606a82582dSMichael Zaidman 
10616a82582dSMichael Zaidman 	hid_hw_close(hdev);
10626a82582dSMichael Zaidman 	hid_hw_stop(hdev);
10636a82582dSMichael Zaidman }
10646a82582dSMichael Zaidman 
ft260_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)10656a82582dSMichael Zaidman static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report,
10666a82582dSMichael Zaidman 			   u8 *data, int size)
10676a82582dSMichael Zaidman {
10686a82582dSMichael Zaidman 	struct ft260_device *dev = hid_get_drvdata(hdev);
10696a82582dSMichael Zaidman 	struct ft260_i2c_input_report *xfer = (void *)data;
10706a82582dSMichael Zaidman 
10716a82582dSMichael Zaidman 	if (xfer->report >= FT260_I2C_REPORT_MIN &&
10726a82582dSMichael Zaidman 	    xfer->report <= FT260_I2C_REPORT_MAX) {
10736a82582dSMichael Zaidman 		ft260_dbg("i2c resp: rep %#02x len %d\n", xfer->report,
10746a82582dSMichael Zaidman 			  xfer->length);
10756a82582dSMichael Zaidman 
1076b7121e3cSMichael Zaidman 		if ((dev->read_buf == NULL) ||
1077b7121e3cSMichael Zaidman 		    (xfer->length > dev->read_len - dev->read_idx)) {
1078b7121e3cSMichael Zaidman 			hid_err(hdev, "unexpected report %#02x, length %d\n",
1079b7121e3cSMichael Zaidman 				xfer->report, xfer->length);
1080b7121e3cSMichael Zaidman 			return -1;
1081b7121e3cSMichael Zaidman 		}
1082b7121e3cSMichael Zaidman 
10836a82582dSMichael Zaidman 		memcpy(&dev->read_buf[dev->read_idx], &xfer->data,
10846a82582dSMichael Zaidman 		       xfer->length);
10856a82582dSMichael Zaidman 		dev->read_idx += xfer->length;
10866a82582dSMichael Zaidman 
10876a82582dSMichael Zaidman 		if (dev->read_idx == dev->read_len)
10886a82582dSMichael Zaidman 			complete(&dev->wait);
10896a82582dSMichael Zaidman 
10906a82582dSMichael Zaidman 	} else {
1091b7121e3cSMichael Zaidman 		hid_err(hdev, "unhandled report %#02x\n", xfer->report);
10926a82582dSMichael Zaidman 	}
1093b7121e3cSMichael Zaidman 	return 0;
10946a82582dSMichael Zaidman }
10956a82582dSMichael Zaidman 
10966a82582dSMichael Zaidman static struct hid_driver ft260_driver = {
10976a82582dSMichael Zaidman 	.name		= "ft260",
10986a82582dSMichael Zaidman 	.id_table	= ft260_devices,
10996a82582dSMichael Zaidman 	.probe		= ft260_probe,
11006a82582dSMichael Zaidman 	.remove		= ft260_remove,
11016a82582dSMichael Zaidman 	.raw_event	= ft260_raw_event,
11026a82582dSMichael Zaidman };
11036a82582dSMichael Zaidman 
11046a82582dSMichael Zaidman module_hid_driver(ft260_driver);
11056a82582dSMichael Zaidman MODULE_DESCRIPTION("FTDI FT260 USB HID to I2C host bridge");
11066a82582dSMichael Zaidman MODULE_AUTHOR("Michael Zaidman <michael.zaidman@gmail.com>");
11076a82582dSMichael Zaidman MODULE_LICENSE("GPL v2");
1108