1e932d817866770d456815c9a84b7ed94f0589d80David Barksdale/* 2e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * hid-cp2112.c - Silicon Labs HID USB to SMBus master bridge 3e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * Copyright (c) 2013,2014 Uplogix, Inc. 4e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * David Barksdale <dbarksdale@uplogix.com> 5e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * 6e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * This program is free software; you can redistribute it and/or modify it 7e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * under the terms and conditions of the GNU General Public License, 8e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * version 2, as published by the Free Software Foundation. 9e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * 10e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * This program is distributed in the hope it will be useful, but WITHOUT 11e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * more details. 14e932d817866770d456815c9a84b7ed94f0589d80David Barksdale */ 15e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 16e932d817866770d456815c9a84b7ed94f0589d80David Barksdale/* 17e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * The Silicon Labs CP2112 chip is a USB HID device which provides an 18e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * SMBus controller for talking to slave devices and 8 GPIO pins. The 19e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * host communicates with the CP2112 via raw HID reports. 20e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * 21e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * Data Sheet: 22e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf 23e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * Programming Interface Specification: 24e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf 25e932d817866770d456815c9a84b7ed94f0589d80David Barksdale */ 26e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 27e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/gpio.h> 28e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/hid.h> 29e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/i2c.h> 30e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/module.h> 31e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/nls.h> 32e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include <linux/usb/ch9.h> 33e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#include "hid-ids.h" 34e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 35e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleenum { 36e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_GPIO_CONFIG = 0x02, 37e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_GPIO_GET = 0x03, 38e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_GPIO_SET = 0x04, 39e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_GET_VERSION_INFO = 0x05, 40e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_SMBUS_CONFIG = 0x06, 41e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_DATA_READ_REQUEST = 0x10, 42e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_DATA_WRITE_READ_REQUEST = 0x11, 43e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_DATA_READ_FORCE_SEND = 0x12, 44e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_DATA_READ_RESPONSE = 0x13, 45e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_DATA_WRITE_REQUEST = 0x14, 46e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_TRANSFER_STATUS_REQUEST = 0x15, 47e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_TRANSFER_STATUS_RESPONSE = 0x16, 48e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_CANCEL_TRANSFER = 0x17, 49e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_LOCK_BYTE = 0x20, 50e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_USB_CONFIG = 0x21, 51e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_MANUFACTURER_STRING = 0x22, 52e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_PRODUCT_STRING = 0x23, 53e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_SERIAL_STRING = 0x24, 54e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 55e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 56e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleenum { 57e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS0_IDLE = 0x00, 58e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS0_BUSY = 0x01, 59e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS0_COMPLETE = 0x02, 60e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS0_ERROR = 0x03, 61e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 62e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 63e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleenum { 64e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_TIMEOUT_NACK = 0x00, 65e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_TIMEOUT_BUS = 0x01, 66e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_ARBITRATION_LOST = 0x02, 67e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_READ_INCOMPLETE = 0x03, 68e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_WRITE_INCOMPLETE = 0x04, 69e932d817866770d456815c9a84b7ed94f0589d80David Barksdale STATUS1_SUCCESS = 0x05, 70e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 71e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 72e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_smbus_config_report { 73e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_SMBUS_CONFIG */ 74e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be32 clock_speed; /* Hz */ 75e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 device_address; /* Stored in the upper 7 bits */ 76e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 auto_send_read; /* 1 = enabled, 0 = disabled */ 77e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 write_timeout; /* ms, 0 = no timeout */ 78e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 read_timeout; /* ms, 0 = no timeout */ 79e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 scl_low_timeout; /* 1 = enabled, 0 = disabled */ 80e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 retry_time; /* # of retries, 0 = no limit */ 81e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 82e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 83e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_usb_config_report { 84e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_USB_CONFIG */ 85e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __le16 vid; /* Vendor ID */ 86e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __le16 pid; /* Product ID */ 87e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 max_power; /* Power requested in 2mA units */ 88e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 power_mode; /* 0x00 = bus powered 89e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 0x01 = self powered & regulator off 90e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 0x02 = self powered & regulator on */ 91e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 release_major; 92e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 release_minor; 93e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 mask; /* What fields to program */ 94e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 95e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 96e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_read_req_report { 97e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_DATA_READ_REQUEST */ 98e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 slave_address; 99e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 length; 100e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 101e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 102e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_write_read_req_report { 103e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_DATA_WRITE_READ_REQUEST */ 104e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 slave_address; 105e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 length; 106e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 target_address_length; 107e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 target_address[16]; 108e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 109e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 110e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_write_req_report { 111e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_DATA_WRITE_REQUEST */ 112e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 slave_address; 113e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 length; 114e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 data[61]; 115e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 116e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 117e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_force_read_report { 118e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_DATA_READ_FORCE_SEND */ 119e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 length; 120e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 121e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 122e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_xfer_status_report { 123e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_TRANSFER_STATUS_RESPONSE */ 124e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 status0; /* STATUS0_* */ 125e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 status1; /* STATUS1_* */ 126e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 retries; 127e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 length; 128e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 129e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 130e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_string_report { 131e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 dummy; /* force .string to be aligned */ 132e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 report; /* CP2112_*_STRING */ 133e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 length; /* length in bytes of everyting after .report */ 134e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 type; /* USB_DT_STRING */ 135e932d817866770d456815c9a84b7ed94f0589d80David Barksdale wchar_t string[30]; /* UTF16_LITTLE_ENDIAN string */ 136e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} __packed; 137e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 138e932d817866770d456815c9a84b7ed94f0589d80David Barksdale/* Number of times to request transfer status before giving up waiting for a 139e932d817866770d456815c9a84b7ed94f0589d80David Barksdale transfer to complete. This may need to be changed if SMBUS clock, retries, 140e932d817866770d456815c9a84b7ed94f0589d80David Barksdale or read/write/scl_low timeout settings are changed. */ 141e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic const int XFER_STATUS_RETRIES = 10; 142e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 143e932d817866770d456815c9a84b7ed94f0589d80David Barksdale/* Time in ms to wait for a CP2112_DATA_READ_RESPONSE or 144e932d817866770d456815c9a84b7ed94f0589d80David Barksdale CP2112_TRANSFER_STATUS_RESPONSE. */ 145e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic const int RESPONSE_TIMEOUT = 50; 146e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 147e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic const struct hid_device_id cp2112_devices[] = { 148e932d817866770d456815c9a84b7ed94f0589d80David Barksdale { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) }, 149e932d817866770d456815c9a84b7ed94f0589d80David Barksdale { } 150e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 151e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleMODULE_DEVICE_TABLE(hid, cp2112_devices); 152e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 153e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_device { 154e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct i2c_adapter adap; 155e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev; 156e932d817866770d456815c9a84b7ed94f0589d80David Barksdale wait_queue_head_t wait; 157e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 read_data[61]; 158e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 read_length; 159e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int xfer_status; 160e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_t read_avail; 161e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_t xfer_avail; 162e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct gpio_chip gc; 163e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 164e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 165e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int gpio_push_pull = 0xFF; 166e932d817866770d456815c9a84b7ed94f0589d80David Barksdalemodule_param(gpio_push_pull, int, S_IRUGO | S_IWUSR); 167e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleMODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask"); 168e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 169e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 170e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 171e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = container_of(chip, struct cp2112_device, 172e932d817866770d456815c9a84b7ed94f0589d80David Barksdale gc); 173e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 174e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[5]; 175e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 176e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 177490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, 178490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina sizeof(buf), HID_FEATURE_REPORT, 179490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina HID_REQ_GET_REPORT); 180e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(buf)) { 181e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error requesting GPIO config: %d\n", ret); 182e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 183e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 184e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 185e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] &= ~(1 << offset); 186e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[2] = gpio_push_pull; 187e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 188293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf), 189293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 190e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 191e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error setting GPIO config: %d\n", ret); 192e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 193e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 194e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 195e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 196e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 197e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 198e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 199e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 200e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = container_of(chip, struct cp2112_device, 201e932d817866770d456815c9a84b7ed94f0589d80David Barksdale gc); 202e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 203e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[3]; 204e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 205e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 206e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[0] = CP2112_GPIO_SET; 207e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] = value ? 0xff : 0; 208e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[2] = 1 << offset; 209e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 210293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, sizeof(buf), 211293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 212e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 213e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error setting GPIO values: %d\n", ret); 214e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 215e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 216e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) 217e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 218e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = container_of(chip, struct cp2112_device, 219e932d817866770d456815c9a84b7ed94f0589d80David Barksdale gc); 220e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 221e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[2]; 222e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 223e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 224490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, sizeof(buf), 225490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 226e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(buf)) { 227e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error requesting GPIO values: %d\n", ret); 228e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 229e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 230e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 231e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return (buf[1] >> offset) & 1; 232e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 233e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 234e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_gpio_direction_output(struct gpio_chip *chip, 235e932d817866770d456815c9a84b7ed94f0589d80David Barksdale unsigned offset, int value) 236e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 237e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = container_of(chip, struct cp2112_device, 238e932d817866770d456815c9a84b7ed94f0589d80David Barksdale gc); 239e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 240e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[5]; 241e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 242e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 243490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, 244490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina sizeof(buf), HID_FEATURE_REPORT, 245490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina HID_REQ_GET_REPORT); 246e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(buf)) { 247e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error requesting GPIO config: %d\n", ret); 248e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 249e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 250e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 251e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] |= 1 << offset; 252e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[2] = gpio_push_pull; 253e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 254293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, sizeof(buf), 255293e483defe499f3c33dfd6e022bf5d0b01ff27fBenjamin Tissoires HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 256e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 257e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error setting GPIO config: %d\n", ret); 258e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 259e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 260e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 261beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo /* 262beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo * Set gpio value when output direction is already set, 263beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo * as specified in AN495, Rev. 0.2, cpt. 4.4 264beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo */ 265beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo cp2112_gpio_set(chip, offset, value); 266beb9d007a846e661cfaa7719cab6b004b3380418Antonio Borneo 267e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 268e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 269e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 270e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number, 271e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 *data, size_t count, unsigned char report_type) 272e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 273e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 *buf; 274e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 275e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 276e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf = kmalloc(count, GFP_KERNEL); 277e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (!buf) 278e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -ENOMEM; 279e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 280490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina ret = hid_hw_raw_request(hdev, report_number, buf, count, 281490051ad164ac53a96ca41f6edc270640bfc499dJiri Kosina report_type, HID_REQ_GET_REPORT); 282e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(data, buf, count); 283e932d817866770d456815c9a84b7ed94f0589d80David Barksdale kfree(buf); 284e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 285e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 286e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 287e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_hid_output(struct hid_device *hdev, u8 *data, size_t count, 288e932d817866770d456815c9a84b7ed94f0589d80David Barksdale unsigned char report_type) 289e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 290e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 *buf; 291e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 292e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 293e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf = kmemdup(data, count, GFP_KERNEL); 294e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (!buf) 295e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -ENOMEM; 296e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 297866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires if (report_type == HID_OUTPUT_REPORT) 298866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires ret = hid_hw_output_report(hdev, buf, count); 299866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires else 300866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires ret = hid_hw_raw_request(hdev, buf[0], buf, count, report_type, 301866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires HID_REQ_SET_REPORT); 302866e4797b4e8100f5abcf2bfd3f7843dc40306cdBenjamin Tissoires 303e932d817866770d456815c9a84b7ed94f0589d80David Barksdale kfree(buf); 304e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 305e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 306e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 307e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_wait(struct cp2112_device *dev, atomic_t *avail) 308e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 309e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret = 0; 310e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 311e932d817866770d456815c9a84b7ed94f0589d80David Barksdale /* We have sent either a CP2112_TRANSFER_STATUS_REQUEST or a 312e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * CP2112_DATA_READ_FORCE_SEND and we are waiting for the response to 313e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * come in cp2112_raw_event or timeout. There will only be one of these 314e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * in flight at any one time. The timeout is extremely large and is a 315e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * last resort if the CP2112 has died. If we do timeout we don't expect 316e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * to receive the response which would cause data races, it's not like 317e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * we can do anything about it anyway. 318e932d817866770d456815c9a84b7ed94f0589d80David Barksdale */ 319e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = wait_event_interruptible_timeout(dev->wait, 320e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_read(avail), msecs_to_jiffies(RESPONSE_TIMEOUT)); 321e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (-ERESTARTSYS == ret) 322e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 323e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (!ret) 324e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -ETIMEDOUT; 325e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 326e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_set(avail, 0); 327e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 328e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 329e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 330e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_xfer_status(struct cp2112_device *dev) 331e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 332e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 333e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[2]; 334e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 335e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 336e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[0] = CP2112_TRANSFER_STATUS_REQUEST; 337e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] = 0x01; 338e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_set(&dev->xfer_avail, 0); 339e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 340e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT); 341e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 342e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Error requesting status: %d\n", ret); 343e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 344e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 345e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 346e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_wait(dev, &dev->xfer_avail); 347e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) 348e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 349e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 350e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return dev->xfer_status; 351e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 352e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 353e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size) 354e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 355e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 356e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_force_read_report report; 357e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 358e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 359e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.report = CP2112_DATA_READ_FORCE_SEND; 360e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.length = cpu_to_be16(size); 361e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 362e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_set(&dev->read_avail, 0); 363e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 364e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, &report.report, sizeof(report), 365e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_OUTPUT_REPORT); 366e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 367e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Error requesting data: %d\n", ret); 368e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 369e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 370e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 371e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_wait(dev, &dev->read_avail); 372e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) 373e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 374e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 3755a673fce04fa953c6915f8ed4bb8491c7d099d14Jiri Kosina hid_dbg(hdev, "read %d of %zd bytes requested\n", 376e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->read_length, size); 377e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 378e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (size > dev->read_length) 379e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size = dev->read_length; 380e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 381e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(data, dev->read_data, size); 382e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return dev->read_length; 383e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 384e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 385e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_read_req(void *buf, u8 slave_address, u16 length) 386e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 387e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_read_req_report *report = buf; 388e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 389e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (length < 1 || length > 512) 390e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 391e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 392e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->report = CP2112_DATA_READ_REQUEST; 393e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->slave_address = slave_address << 1; 394e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->length = cpu_to_be16(length); 395e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return sizeof(*report); 396e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 397e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 398e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_write_read_req(void *buf, u8 slave_address, u16 length, 399e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 command, u8 *data, u8 data_length) 400e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 401e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_write_read_req_report *report = buf; 402e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 403e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (length < 1 || length > 512 404e932d817866770d456815c9a84b7ed94f0589d80David Barksdale || data_length > sizeof(report->target_address) - 1) 405e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 406e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 407e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->report = CP2112_DATA_WRITE_READ_REQUEST; 408e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->slave_address = slave_address << 1; 409e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->length = cpu_to_be16(length); 410e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->target_address_length = data_length + 1; 411e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->target_address[0] = command; 412e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(&report->target_address[1], data, data_length); 413e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return data_length + 6; 414e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 415e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 416e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data, 417e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 data_length) 418e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 419e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_write_req_report *report = buf; 420e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 421e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (data_length > sizeof(report->data) - 1) 422e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 423e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 424e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->report = CP2112_DATA_WRITE_REQUEST; 425e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->slave_address = slave_address << 1; 426e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->length = data_length + 1; 427e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report->data[0] = command; 428e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(&report->data[1], data, data_length); 429e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return data_length + 4; 430e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 431e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 432b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneostatic int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data, 433b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo u8 data_length) 434b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo{ 435b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo struct cp2112_write_req_report *report = buf; 436b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 437b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (data_length > sizeof(report->data)) 438b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return -EINVAL; 439b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 440b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo report->report = CP2112_DATA_WRITE_REQUEST; 441b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo report->slave_address = slave_address << 1; 442b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo report->length = data_length; 443b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo memcpy(report->data, data, data_length); 444b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return data_length + 3; 445b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo} 446b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 447b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneostatic int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 448b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo int num) 449b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo{ 450b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data; 451b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo struct hid_device *hdev = dev->hdev; 452b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo u8 buf[64]; 453b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ssize_t count; 454b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo unsigned int retries; 455b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo int ret; 456b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 457b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_dbg(hdev, "I2C %d messages\n", num); 458b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 459b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (num != 1) { 460b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_err(hdev, 461b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo "Multi-message I2C transactions not supported\n"); 462b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return -EOPNOTSUPP; 463b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 464b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 465b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (msgs->flags & I2C_M_RD) 466b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo count = cp2112_read_req(buf, msgs->addr, msgs->len); 467b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo else 468b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf, 469b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo msgs->len); 470b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 471b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (count < 0) 472b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return count; 473b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 474b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = hid_hw_power(hdev, PM_HINT_FULLON); 475b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret < 0) { 476b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_err(hdev, "power management error: %d\n", ret); 477b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return ret; 478b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 479b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 480b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT); 481b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret < 0) { 482b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_warn(hdev, "Error starting transaction: %d\n", ret); 483b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto power_normal; 484b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 485b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 486b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) { 487b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = cp2112_xfer_status(dev); 488b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (-EBUSY == ret) 489b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo continue; 490b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret < 0) 491b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto power_normal; 492b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo break; 493b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 494b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 495b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (XFER_STATUS_RETRIES <= retries) { 496b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_warn(hdev, "Transfer timed out, cancelling.\n"); 497b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo buf[0] = CP2112_CANCEL_TRANSFER; 498b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo buf[1] = 0x01; 499b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 500b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT); 501b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret < 0) 502b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_warn(hdev, "Error cancelling transaction: %d\n", 503b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret); 504b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 505b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = -ETIMEDOUT; 506b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto power_normal; 507b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 508b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 509b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (!(msgs->flags & I2C_M_RD)) 510b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto finish; 511b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 512b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = cp2112_read(dev, msgs->buf, msgs->len); 513b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret < 0) 514b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto power_normal; 515b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo if (ret != msgs->len) { 516b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len); 517b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = -EIO; 518b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo goto power_normal; 519b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo } 520b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 521b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneofinish: 522b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo /* return the number of transferred messages */ 523b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo ret = 1; 524b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 525b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneopower_normal: 526b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_hw_power(hdev, PM_HINT_NORMAL); 527b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo hid_dbg(hdev, "I2C transfer finished: %d\n", ret); 528b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return ret; 529b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo} 530b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo 531e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_xfer(struct i2c_adapter *adap, u16 addr, 532e932d817866770d456815c9a84b7ed94f0589d80David Barksdale unsigned short flags, char read_write, u8 command, 533e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int size, union i2c_smbus_data *data) 534e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 535e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data; 536e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = dev->hdev; 537e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[64]; 538e932d817866770d456815c9a84b7ed94f0589d80David Barksdale __be16 word; 5390438ee7080ac83a6a831c52bc4e8c29dc2306e95Jiri Kosina ssize_t count; 540e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size_t read_length = 0; 541e932d817866770d456815c9a84b7ed94f0589d80David Barksdale unsigned int retries; 542e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 543e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 544e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n", 545e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_write == I2C_SMBUS_WRITE ? "write" : "read", 546e932d817866770d456815c9a84b7ed94f0589d80David Barksdale addr, flags, command, size); 547e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 548e932d817866770d456815c9a84b7ed94f0589d80David Barksdale switch (size) { 549e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BYTE: 550e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_length = 1; 551e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 552e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_READ == read_write) 553e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_read_req(buf, addr, read_length); 554e932d817866770d456815c9a84b7ed94f0589d80David Barksdale else 555e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_req(buf, addr, data->byte, NULL, 556e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 0); 557e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 558e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BYTE_DATA: 559e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_length = 1; 560e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 561e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_READ == read_write) 562e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_read_req(buf, addr, read_length, 563e932d817866770d456815c9a84b7ed94f0589d80David Barksdale command, NULL, 0); 564e932d817866770d456815c9a84b7ed94f0589d80David Barksdale else 565e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_req(buf, addr, command, 566e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &data->byte, 1); 567e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 568e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_WORD_DATA: 569e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_length = 2; 570e932d817866770d456815c9a84b7ed94f0589d80David Barksdale word = cpu_to_be16(data->word); 571e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 572e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_READ == read_write) 573e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_read_req(buf, addr, read_length, 574e932d817866770d456815c9a84b7ed94f0589d80David Barksdale command, NULL, 0); 575e932d817866770d456815c9a84b7ed94f0589d80David Barksdale else 576e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_req(buf, addr, command, 577e932d817866770d456815c9a84b7ed94f0589d80David Barksdale (u8 *)&word, 2); 578e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 579e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_PROC_CALL: 580e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size = I2C_SMBUS_WORD_DATA; 581e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_write = I2C_SMBUS_READ; 582e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_length = 2; 583e932d817866770d456815c9a84b7ed94f0589d80David Barksdale word = cpu_to_be16(data->word); 584e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 585e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_read_req(buf, addr, read_length, command, 586e932d817866770d456815c9a84b7ed94f0589d80David Barksdale (u8 *)&word, 2); 587e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 588e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_I2C_BLOCK_DATA: 589e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size = I2C_SMBUS_BLOCK_DATA; 590e932d817866770d456815c9a84b7ed94f0589d80David Barksdale /* fallthrough */ 591e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BLOCK_DATA: 592e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_READ == read_write) { 593e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_read_req(buf, addr, 594e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_SMBUS_BLOCK_MAX, 595e932d817866770d456815c9a84b7ed94f0589d80David Barksdale command, NULL, 0); 596e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } else { 597e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_req(buf, addr, command, 598e932d817866770d456815c9a84b7ed94f0589d80David Barksdale data->block, 599e932d817866770d456815c9a84b7ed94f0589d80David Barksdale data->block[0] + 1); 600e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 601e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 602e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BLOCK_PROC_CALL: 603e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size = I2C_SMBUS_BLOCK_DATA; 604e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_write = I2C_SMBUS_READ; 605e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 606e932d817866770d456815c9a84b7ed94f0589d80David Barksdale count = cp2112_write_read_req(buf, addr, I2C_SMBUS_BLOCK_MAX, 607e932d817866770d456815c9a84b7ed94f0589d80David Barksdale command, data->block, 608e932d817866770d456815c9a84b7ed94f0589d80David Barksdale data->block[0] + 1); 609e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 610e932d817866770d456815c9a84b7ed94f0589d80David Barksdale default: 611e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Unsupported transaction %d\n", size); 612e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EOPNOTSUPP; 613e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 614e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 615e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (count < 0) 616e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return count; 617e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 618e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = hid_hw_power(hdev, PM_HINT_FULLON); 619e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 620e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "power management error: %d\n", ret); 621e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 622e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 623e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 624e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT); 625e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 626e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Error starting transaction: %d\n", ret); 627e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 628e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 629e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 630e932d817866770d456815c9a84b7ed94f0589d80David Barksdale for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) { 631e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_xfer_status(dev); 632e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (-EBUSY == ret) 633e932d817866770d456815c9a84b7ed94f0589d80David Barksdale continue; 634e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 635e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 636e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 637e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 638e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 639e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (XFER_STATUS_RETRIES <= retries) { 640e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Transfer timed out, cancelling.\n"); 641e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[0] = CP2112_CANCEL_TRANSFER; 642e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] = 0x01; 643e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 644e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT); 645e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 646e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_warn(hdev, "Error cancelling transaction: %d\n", 647e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret); 648e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 649e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -ETIMEDOUT; 650e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 651e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 652e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 653e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_WRITE == read_write) { 654e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = 0; 655e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 656e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 657e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 658e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (I2C_SMBUS_BLOCK_DATA == size) 659e932d817866770d456815c9a84b7ed94f0589d80David Barksdale read_length = ret; 660e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 661e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_read(dev, buf, read_length); 662e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 663e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 664e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != read_length) { 6655a673fce04fa953c6915f8ed4bb8491c7d099d14Jiri Kosina hid_warn(hdev, "short read: %d < %zd\n", ret, read_length); 666e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -EIO; 667e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 668e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 669e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 670e932d817866770d456815c9a84b7ed94f0589d80David Barksdale switch (size) { 671e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BYTE: 672e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BYTE_DATA: 673e932d817866770d456815c9a84b7ed94f0589d80David Barksdale data->byte = buf[0]; 674e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 675e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_WORD_DATA: 676e932d817866770d456815c9a84b7ed94f0589d80David Barksdale data->word = be16_to_cpup((__be16 *)buf); 677e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 678e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case I2C_SMBUS_BLOCK_DATA: 679e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (read_length > I2C_SMBUS_BLOCK_MAX) { 680e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -EPROTO; 681e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto power_normal; 682e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 683e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 684e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(data->block, buf, read_length); 685e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 686e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 687e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 688e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = 0; 689e932d817866770d456815c9a84b7ed94f0589d80David Barksdalepower_normal: 690e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_power(hdev, PM_HINT_NORMAL); 691e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_dbg(hdev, "transfer finished: %d\n", ret); 692e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 693e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 694e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 695e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic u32 cp2112_functionality(struct i2c_adapter *adap) 696e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 697b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo return I2C_FUNC_I2C | 698b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo I2C_FUNC_SMBUS_BYTE | 699e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_BYTE_DATA | 700e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_WORD_DATA | 701e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_BLOCK_DATA | 702e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_I2C_BLOCK | 703e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_PROC_CALL | 704e932d817866770d456815c9a84b7ed94f0589d80David Barksdale I2C_FUNC_SMBUS_BLOCK_PROC_CALL; 705e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 706e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 707e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic const struct i2c_algorithm smbus_algorithm = { 708b9029345ed6483fcadadc4834b44a5656dd56d70Antonio Borneo .master_xfer = cp2112_i2c_xfer, 709e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .smbus_xfer = cp2112_xfer, 710e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .functionality = cp2112_functionality, 711e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 712e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 713e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_get_usb_config(struct hid_device *hdev, 714e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_usb_config_report *cfg) 715e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 716e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 717e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 718e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_get(hdev, CP2112_USB_CONFIG, (u8 *)cfg, sizeof(*cfg), 719e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 720e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(*cfg)) { 721e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error reading usb config: %d\n", ret); 722e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 723e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 724e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EIO; 725e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 726e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 727e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 728e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 729e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 730e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_set_usb_config(struct hid_device *hdev, 731e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_usb_config_report *cfg) 732e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 733e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 734e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 735e932d817866770d456815c9a84b7ed94f0589d80David Barksdale BUG_ON(cfg->report != CP2112_USB_CONFIG); 736e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 737e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, (u8 *)cfg, sizeof(*cfg), 738e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 739e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(*cfg)) { 740e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error writing usb config: %d\n", ret); 741e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 742e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 743e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EIO; 744e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 745e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 746e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 747e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 748e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 749e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic void chmod_sysfs_attrs(struct hid_device *hdev); 750e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 751e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#define CP2112_CONFIG_ATTR(name, store, format, ...) \ 752e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic ssize_t name##_store(struct device *kdev, \ 753e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct device_attribute *attr, const char *buf, \ 754e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size_t count) \ 755e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ \ 756e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \ 757e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_usb_config_report cfg; \ 758e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret = cp2112_get_usb_config(hdev, &cfg); \ 759e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) \ 760e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; \ 761e932d817866770d456815c9a84b7ed94f0589d80David Barksdale store; \ 762e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_set_usb_config(hdev, &cfg); \ 763e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) \ 764e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; \ 765e932d817866770d456815c9a84b7ed94f0589d80David Barksdale chmod_sysfs_attrs(hdev); \ 766e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return count; \ 767e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} \ 768e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic ssize_t name##_show(struct device *kdev, \ 769e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct device_attribute *attr, char *buf) \ 770e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ \ 771e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \ 772e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_usb_config_report cfg; \ 773e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret = cp2112_get_usb_config(hdev, &cfg); \ 774e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) \ 775e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; \ 776e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return scnprintf(buf, PAGE_SIZE, format, ##__VA_ARGS__); \ 777e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} \ 778c3c041ba4c61535d7f5a36230c8dfdff2a9a70bbJiri Kosinastatic DEVICE_ATTR_RW(name); 779e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 780e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_CONFIG_ATTR(vendor_id, ({ 781e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u16 vid; 782e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 783e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (sscanf(buf, "%hi", &vid) != 1) 784e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 785e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 786e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.vid = cpu_to_le16(vid); 787e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.mask = 0x01; 788e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}), "0x%04x\n", le16_to_cpu(cfg.vid)); 789e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 790e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_CONFIG_ATTR(product_id, ({ 791e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u16 pid; 792e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 793e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (sscanf(buf, "%hi", &pid) != 1) 794e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 795e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 796e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.pid = cpu_to_le16(pid); 797e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.mask = 0x02; 798e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}), "0x%04x\n", le16_to_cpu(cfg.pid)); 799e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 800e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_CONFIG_ATTR(max_power, ({ 801e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int mA; 802e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 803e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (sscanf(buf, "%i", &mA) != 1) 804e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 805e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 806e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.max_power = (mA + 1) / 2; 807e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.mask = 0x04; 808e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}), "%u mA\n", cfg.max_power * 2); 809e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 810e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_CONFIG_ATTR(power_mode, ({ 811e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (sscanf(buf, "%hhi", &cfg.power_mode) != 1) 812e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 813e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 814e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.mask = 0x08; 815e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}), "%u\n", cfg.power_mode); 816e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 817e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_CONFIG_ATTR(release_version, ({ 818e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (sscanf(buf, "%hhi.%hhi", &cfg.release_major, &cfg.release_minor) 819e932d817866770d456815c9a84b7ed94f0589d80David Barksdale != 2) 820e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EINVAL; 821e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 822e932d817866770d456815c9a84b7ed94f0589d80David Barksdale cfg.mask = 0x10; 823e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}), "%u.%u\n", cfg.release_major, cfg.release_minor); 824e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 825e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#undef CP2112_CONFIG_ATTR 826e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 827e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestruct cp2112_pstring_attribute { 828e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct device_attribute attr; 829e932d817866770d456815c9a84b7ed94f0589d80David Barksdale unsigned char report; 830e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 831e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 832e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic ssize_t pstr_store(struct device *kdev, 833e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct device_attribute *kattr, const char *buf, 834e932d817866770d456815c9a84b7ed94f0589d80David Barksdale size_t count) 835e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 836e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = container_of(kdev, struct hid_device, dev); 837e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_pstring_attribute *attr = 838e932d817866770d456815c9a84b7ed94f0589d80David Barksdale container_of(kattr, struct cp2112_pstring_attribute, attr); 839e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_string_report report; 840e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 841e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 842e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memset(&report, 0, sizeof(report)); 843e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 844e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN, 845e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.string, ARRAY_SIZE(report.string)); 846e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.report = attr->report; 847e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.length = ret * sizeof(report.string[0]) + 2; 848e932d817866770d456815c9a84b7ed94f0589d80David Barksdale report.type = USB_DT_STRING; 849e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 850e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, &report.report, report.length + 1, 851e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 852e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != report.length + 1) { 853e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error writing %s string: %d\n", kattr->attr.name, 854e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret); 855e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 856e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 857e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EIO; 858e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 859e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 860e932d817866770d456815c9a84b7ed94f0589d80David Barksdale chmod_sysfs_attrs(hdev); 861e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return count; 862e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 863e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 864e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic ssize_t pstr_show(struct device *kdev, 865e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct device_attribute *kattr, char *buf) 866e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 867e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct hid_device *hdev = container_of(kdev, struct hid_device, dev); 868e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_pstring_attribute *attr = 869e932d817866770d456815c9a84b7ed94f0589d80David Barksdale container_of(kattr, struct cp2112_pstring_attribute, attr); 870e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_string_report report; 871e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 length; 872e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 873e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 874e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_get(hdev, attr->report, &report.report, 875e932d817866770d456815c9a84b7ed94f0589d80David Barksdale sizeof(report) - 1, HID_FEATURE_REPORT); 876e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 3) { 877e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name, 878e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret); 879e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 880e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 881e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EIO; 882e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 883e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 884e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (report.length < 2) { 885e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "invalid %s string length: %d\n", 886e932d817866770d456815c9a84b7ed94f0589d80David Barksdale kattr->attr.name, report.length); 887e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return -EIO; 888e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 889e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 890e932d817866770d456815c9a84b7ed94f0589d80David Barksdale length = report.length > ret - 1 ? ret - 1 : report.length; 891e932d817866770d456815c9a84b7ed94f0589d80David Barksdale length = (length - 2) / sizeof(report.string[0]); 892e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = utf16s_to_utf8s(report.string, length, UTF16_LITTLE_ENDIAN, buf, 893e932d817866770d456815c9a84b7ed94f0589d80David Barksdale PAGE_SIZE - 1); 894e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[ret++] = '\n'; 895e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 896e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 897e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 898e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#define CP2112_PSTR_ATTR(name, _report) \ 899c3c041ba4c61535d7f5a36230c8dfdff2a9a70bbJiri Kosinastatic struct cp2112_pstring_attribute dev_attr_##name = { \ 900e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \ 901e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .report = _report, \ 902e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 903e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 904e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING); 905e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_PSTR_ATTR(product, CP2112_PRODUCT_STRING); 906e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleCP2112_PSTR_ATTR(serial, CP2112_SERIAL_STRING); 907e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 908e932d817866770d456815c9a84b7ed94f0589d80David Barksdale#undef CP2112_PSTR_ATTR 909e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 910e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic const struct attribute_group cp2112_attr_group = { 911e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .attrs = (struct attribute *[]){ 912e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_vendor_id.attr, 913e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_product_id.attr, 914e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_max_power.attr, 915e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_power_mode.attr, 916e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_release_version.attr, 917e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_manufacturer.attr.attr, 918e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_product.attr.attr, 919e932d817866770d456815c9a84b7ed94f0589d80David Barksdale &dev_attr_serial.attr.attr, 920e932d817866770d456815c9a84b7ed94f0589d80David Barksdale NULL 921e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 922e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 923e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 924e932d817866770d456815c9a84b7ed94f0589d80David Barksdale/* Chmoding our sysfs attributes is simply a way to expose which fields in the 925e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * PROM have already been programmed. We do not depend on this preventing 926e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * writing to these attributes since the CP2112 will simply ignore writes to 927e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * already-programmed fields. This is why there is no sense in fixing this 928e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * racy behaviour. 929e932d817866770d456815c9a84b7ed94f0589d80David Barksdale */ 930e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic void chmod_sysfs_attrs(struct hid_device *hdev) 931e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 932e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct attribute **attr; 933e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[2]; 934e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 935e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 936e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_get(hdev, CP2112_LOCK_BYTE, buf, sizeof(buf), 937e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 938e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(buf)) { 939e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error reading lock byte: %d\n", ret); 940e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return; 941e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 942e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 943e932d817866770d456815c9a84b7ed94f0589d80David Barksdale for (attr = cp2112_attr_group.attrs; *attr; ++attr) { 944e932d817866770d456815c9a84b7ed94f0589d80David Barksdale umode_t mode = (buf[1] & 1) ? S_IWUSR | S_IRUGO : S_IRUGO; 945e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode); 946e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) 947e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error chmoding sysfs file %s\n", 948e932d817866770d456815c9a84b7ed94f0589d80David Barksdale (*attr)->name); 949e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1] >>= 1; 950e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 951e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 952e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 953e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) 954e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 955e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev; 956e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 buf[3]; 957e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_smbus_config_report config; 958e932d817866770d456815c9a84b7ed94f0589d80David Barksdale int ret; 959e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 960e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = hid_parse(hdev); 961e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) { 962e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "parse failed\n"); 963e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 964e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 965e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 966e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 967e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) { 968e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "hw start failed\n"); 969e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 970e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 971e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 972e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = hid_hw_open(hdev); 973e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) { 974e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "hw open failed\n"); 975e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_hid_stop; 976e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 977e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 978e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = hid_hw_power(hdev, PM_HINT_FULLON); 979e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 980e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "power management error: %d\n", ret); 981e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_hid_close; 982e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 983e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 984e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_get(hdev, CP2112_GET_VERSION_INFO, buf, sizeof(buf), 985e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 986e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(buf)) { 987e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error requesting version\n"); 988e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret >= 0) 989e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -EIO; 990e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_power_normal; 991e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 992e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 993e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_info(hdev, "Part Number: 0x%02X Device Version: 0x%02X\n", 994e932d817866770d456815c9a84b7ed94f0589d80David Barksdale buf[1], buf[2]); 995e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 996e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_get(hdev, CP2112_SMBUS_CONFIG, (u8 *)&config, 997e932d817866770d456815c9a84b7ed94f0589d80David Barksdale sizeof(config), HID_FEATURE_REPORT); 998e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(config)) { 999e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error requesting SMBus config\n"); 1000e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret >= 0) 1001e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -EIO; 1002e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_power_normal; 1003e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1004e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1005e932d817866770d456815c9a84b7ed94f0589d80David Barksdale config.retry_time = cpu_to_be16(1); 1006e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1007e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = cp2112_hid_output(hdev, (u8 *)&config, sizeof(config), 1008e932d817866770d456815c9a84b7ed94f0589d80David Barksdale HID_FEATURE_REPORT); 1009e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret != sizeof(config)) { 1010e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error setting SMBus config\n"); 1011e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret >= 0) 1012e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -EIO; 1013e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_power_normal; 1014e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1015e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1016e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1017e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (!dev) { 1018e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = -ENOMEM; 1019e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_power_normal; 1020e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1021e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1022e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_set_drvdata(hdev, (void *)dev); 1023e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->hdev = hdev; 1024e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->adap.owner = THIS_MODULE; 1025e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->adap.class = I2C_CLASS_HWMON; 1026e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->adap.algo = &smbus_algorithm; 1027e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->adap.algo_data = dev; 1028e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->adap.dev.parent = &hdev->dev; 1029e932d817866770d456815c9a84b7ed94f0589d80David Barksdale snprintf(dev->adap.name, sizeof(dev->adap.name), 1030e932d817866770d456815c9a84b7ed94f0589d80David Barksdale "CP2112 SMBus Bridge on hiddev%d", hdev->minor); 1031e932d817866770d456815c9a84b7ed94f0589d80David Barksdale init_waitqueue_head(&dev->wait); 1032e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1033e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_device_io_start(hdev); 1034e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = i2c_add_adapter(&dev->adap); 1035e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_device_io_stop(hdev); 1036e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1037e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret) { 1038e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error registering i2c adapter\n"); 1039e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_free_dev; 1040e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1041e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1042e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_dbg(hdev, "adapter registered\n"); 1043e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1044e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.label = "cp2112_gpio"; 1045e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.direction_input = cp2112_gpio_direction_input; 1046e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.direction_output = cp2112_gpio_direction_output; 1047e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.set = cp2112_gpio_set; 1048e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.get = cp2112_gpio_get; 1049e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.base = -1; 1050e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.ngpio = 8; 1051e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.can_sleep = 1; 1052e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->gc.dev = &hdev->dev; 1053e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1054e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = gpiochip_add(&dev->gc); 1055e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 1056e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error registering gpio chip\n"); 1057e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_free_i2c; 1058e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1059e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1060e932d817866770d456815c9a84b7ed94f0589d80David Barksdale ret = sysfs_create_group(&hdev->dev.kobj, &cp2112_attr_group); 1061e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (ret < 0) { 1062e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "error creating sysfs attrs\n"); 1063e932d817866770d456815c9a84b7ed94f0589d80David Barksdale goto err_gpiochip_remove; 1064e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1065e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1066e932d817866770d456815c9a84b7ed94f0589d80David Barksdale chmod_sysfs_attrs(hdev); 1067e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_power(hdev, PM_HINT_NORMAL); 1068e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1069e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 1070e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1071e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_gpiochip_remove: 107288d5e520aa9701eb3e4f46165e02097cc03d363aabdoulaye berthe gpiochip_remove(&dev->gc); 1073e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_free_i2c: 1074e932d817866770d456815c9a84b7ed94f0589d80David Barksdale i2c_del_adapter(&dev->adap); 1075e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_free_dev: 1076e932d817866770d456815c9a84b7ed94f0589d80David Barksdale kfree(dev); 1077e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_power_normal: 1078e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_power(hdev, PM_HINT_NORMAL); 1079e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_hid_close: 1080e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_close(hdev); 1081e932d817866770d456815c9a84b7ed94f0589d80David Barksdaleerr_hid_stop: 1082e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_stop(hdev); 1083e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return ret; 1084e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 1085e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1086e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic void cp2112_remove(struct hid_device *hdev) 1087e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 1088e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = hid_get_drvdata(hdev); 1089e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1090e932d817866770d456815c9a84b7ed94f0589d80David Barksdale sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group); 109188d5e520aa9701eb3e4f46165e02097cc03d363aabdoulaye berthe gpiochip_remove(&dev->gc); 1092e932d817866770d456815c9a84b7ed94f0589d80David Barksdale i2c_del_adapter(&dev->adap); 1093e932d817866770d456815c9a84b7ed94f0589d80David Barksdale /* i2c_del_adapter has finished removing all i2c devices from our 1094e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * adapter. Well behaved devices should no longer call our cp2112_xfer 1095e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * and should have waited for any pending calls to finish. It has also 1096e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * waited for device_unregister(&adap->dev) to complete. Therefore we 1097e932d817866770d456815c9a84b7ed94f0589d80David Barksdale * can safely free our struct cp2112_device. 1098e932d817866770d456815c9a84b7ed94f0589d80David Barksdale */ 1099e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_close(hdev); 1100e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_hw_stop(hdev); 1101e932d817866770d456815c9a84b7ed94f0589d80David Barksdale kfree(dev); 1102e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 1103e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1104e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report, 1105e932d817866770d456815c9a84b7ed94f0589d80David Barksdale u8 *data, int size) 1106e932d817866770d456815c9a84b7ed94f0589d80David Barksdale{ 1107e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_device *dev = hid_get_drvdata(hdev); 1108e932d817866770d456815c9a84b7ed94f0589d80David Barksdale struct cp2112_xfer_status_report *xfer = (void *)data; 1109e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1110e932d817866770d456815c9a84b7ed94f0589d80David Barksdale switch (data[0]) { 1111e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case CP2112_TRANSFER_STATUS_RESPONSE: 1112e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_dbg(hdev, "xfer status: %02x %02x %04x %04x\n", 1113e932d817866770d456815c9a84b7ed94f0589d80David Barksdale xfer->status0, xfer->status1, 1114e932d817866770d456815c9a84b7ed94f0589d80David Barksdale be16_to_cpu(xfer->retries), be16_to_cpu(xfer->length)); 1115e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1116e932d817866770d456815c9a84b7ed94f0589d80David Barksdale switch (xfer->status0) { 1117e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS0_IDLE: 1118e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = -EAGAIN; 1119e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1120e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS0_BUSY: 1121e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = -EBUSY; 1122e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1123e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS0_COMPLETE: 1124e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = be16_to_cpu(xfer->length); 1125e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1126e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS0_ERROR: 1127e932d817866770d456815c9a84b7ed94f0589d80David Barksdale switch (xfer->status1) { 1128e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS1_TIMEOUT_NACK: 1129e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case STATUS1_TIMEOUT_BUS: 1130e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = -ETIMEDOUT; 1131e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1132e932d817866770d456815c9a84b7ed94f0589d80David Barksdale default: 1133e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = -EIO; 1134e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1135e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1136e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1137e932d817866770d456815c9a84b7ed94f0589d80David Barksdale default: 1138e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->xfer_status = -EINVAL; 1139e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1140e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1141e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1142e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_set(&dev->xfer_avail, 1); 1143e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1144e932d817866770d456815c9a84b7ed94f0589d80David Barksdale case CP2112_DATA_READ_RESPONSE: 1145e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_dbg(hdev, "read response: %02x %02x\n", data[1], data[2]); 1146e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1147e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->read_length = data[2]; 1148e932d817866770d456815c9a84b7ed94f0589d80David Barksdale if (dev->read_length > sizeof(dev->read_data)) 1149e932d817866770d456815c9a84b7ed94f0589d80David Barksdale dev->read_length = sizeof(dev->read_data); 1150e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1151e932d817866770d456815c9a84b7ed94f0589d80David Barksdale memcpy(dev->read_data, &data[3], dev->read_length); 1152e932d817866770d456815c9a84b7ed94f0589d80David Barksdale atomic_set(&dev->read_avail, 1); 1153e932d817866770d456815c9a84b7ed94f0589d80David Barksdale break; 1154e932d817866770d456815c9a84b7ed94f0589d80David Barksdale default: 1155e932d817866770d456815c9a84b7ed94f0589d80David Barksdale hid_err(hdev, "unknown report\n"); 1156e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1157e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 0; 1158e932d817866770d456815c9a84b7ed94f0589d80David Barksdale } 1159e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1160e932d817866770d456815c9a84b7ed94f0589d80David Barksdale wake_up_interruptible(&dev->wait); 1161e932d817866770d456815c9a84b7ed94f0589d80David Barksdale return 1; 1162e932d817866770d456815c9a84b7ed94f0589d80David Barksdale} 1163e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1164e932d817866770d456815c9a84b7ed94f0589d80David Barksdalestatic struct hid_driver cp2112_driver = { 1165e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .name = "cp2112", 1166e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .id_table = cp2112_devices, 1167e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .probe = cp2112_probe, 1168e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .remove = cp2112_remove, 1169e932d817866770d456815c9a84b7ed94f0589d80David Barksdale .raw_event = cp2112_raw_event, 1170e932d817866770d456815c9a84b7ed94f0589d80David Barksdale}; 1171e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1172e932d817866770d456815c9a84b7ed94f0589d80David Barksdalemodule_hid_driver(cp2112_driver); 1173e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleMODULE_DESCRIPTION("Silicon Labs HID USB to SMBus master bridge"); 1174e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleMODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>"); 1175e932d817866770d456815c9a84b7ed94f0589d80David BarksdaleMODULE_LICENSE("GPL"); 1176e932d817866770d456815c9a84b7ed94f0589d80David Barksdale 1177