linux/drivers/hid/hid-cp2112.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * hid-cp2112.c - Silicon Labs HID USB to SMBus master bridge
 * Copyright (c) 2013,2014 Uplogix, Inc.
 * David Barksdale <[email protected]>
 */

/*
 * The Silicon Labs CP2112 chip is a USB HID device which provides an
 * SMBus controller for talking to slave devices and 8 GPIO pins. The
 * host communicates with the CP2112 via raw HID reports.
 *
 * Data Sheet:
 *   https://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf
 * Programming Interface Specification:
 *   https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
 */

#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/string_choices.h>
#include <linux/usb/ch9.h>
#include "hid-ids.h"

#define CP2112_REPORT_MAX_LENGTH
#define CP2112_GPIO_CONFIG_LENGTH
#define CP2112_GPIO_GET_LENGTH
#define CP2112_GPIO_SET_LENGTH
#define CP2112_GPIO_MAX_GPIO
#define CP2112_GPIO_ALL_GPIO_MASK

enum {};

enum {};

enum {};

struct cp2112_smbus_config_report {} __packed;

struct cp2112_usb_config_report {} __packed;

struct cp2112_read_req_report {} __packed;

struct cp2112_write_read_req_report {} __packed;

struct cp2112_write_req_report {} __packed;

struct cp2112_force_read_report {} __packed;

struct cp2112_xfer_status_report {} __packed;

struct cp2112_string_report {} __packed;

/* Number of times to request transfer status before giving up waiting for a
   transfer to complete. This may need to be changed if SMBUS clock, retries,
   or read/write/scl_low timeout settings are changed. */
static const int XFER_STATUS_RETRIES =;

/* Time in ms to wait for a CP2112_DATA_READ_RESPONSE or
   CP2112_TRANSFER_STATUS_RESPONSE. */
static const int RESPONSE_TIMEOUT =;

static const struct hid_device_id cp2112_devices[] =;
MODULE_DEVICE_TABLE(hid, cp2112_devices);

struct cp2112_device {};

static int gpio_push_pull =;
module_param(gpio_push_pull, int, 0644);
MODULE_PARM_DESC();

static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{}

static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{}

static int cp2112_gpio_get_all(struct gpio_chip *chip)
{}

static int cp2112_gpio_get(struct gpio_chip *chip, unsigned int offset)
{}

static int cp2112_gpio_direction_output(struct gpio_chip *chip,
					unsigned offset, int value)
{}

static int cp2112_hid_get(struct hid_device *hdev, unsigned char report_number,
			  u8 *data, size_t count, unsigned char report_type)
{}

static int cp2112_hid_output(struct hid_device *hdev, u8 *data, size_t count,
			     unsigned char report_type)
{}

static int cp2112_wait(struct cp2112_device *dev, atomic_t *avail)
{}

static int cp2112_xfer_status(struct cp2112_device *dev)
{}

static int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size)
{}

static int cp2112_read_req(void *buf, u8 slave_address, u16 length)
{}

static int cp2112_write_read_req(void *buf, u8 slave_address, u16 length,
				 u8 command, u8 *data, u8 data_length)
{}

static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
			    u8 data_length)
{}

static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
				u8 data_length)
{}

static int cp2112_i2c_write_read_req(void *buf, u8 slave_address,
				     u8 *addr, int addr_length,
				     int read_length)
{}

static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
			   int num)
{}

static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
		       unsigned short flags, char read_write, u8 command,
		       int size, union i2c_smbus_data *data)
{}

static u32 cp2112_functionality(struct i2c_adapter *adap)
{}

static const struct i2c_algorithm smbus_algorithm =;

static int cp2112_get_usb_config(struct hid_device *hdev,
				 struct cp2112_usb_config_report *cfg)
{}

static int cp2112_set_usb_config(struct hid_device *hdev,
				 struct cp2112_usb_config_report *cfg)
{}

static void chmod_sysfs_attrs(struct hid_device *hdev);

#define CP2112_CONFIG_ATTR

CP2112_CONFIG_ATTR(vendor_id, ({
	u16 vid;

	if (sscanf(buf, "%hi", &vid) != 1)
		return -EINVAL;

	cfg.vid = cpu_to_le16(vid);
	cfg.mask = 0x01;
}), "0x%04x\n", le16_to_cpu(cfg.vid));

CP2112_CONFIG_ATTR(product_id, ({
	u16 pid;

	if (sscanf(buf, "%hi", &pid) != 1)
		return -EINVAL;

	cfg.pid = cpu_to_le16(pid);
	cfg.mask = 0x02;
}), "0x%04x\n", le16_to_cpu(cfg.pid));

CP2112_CONFIG_ATTR(max_power, ({
	int mA;

	if (sscanf(buf, "%i", &mA) != 1)
		return -EINVAL;

	cfg.max_power = (mA + 1) / 2;
	cfg.mask = 0x04;
}), "%u mA\n", cfg.max_power * 2);

CP2112_CONFIG_ATTR(power_mode, ({
	if (sscanf(buf, "%hhi", &cfg.power_mode) != 1)
		return -EINVAL;

	cfg.mask = 0x08;
}), "%u\n", cfg.power_mode);

CP2112_CONFIG_ATTR(release_version, ({
	if (sscanf(buf, "%hhi.%hhi", &cfg.release_major, &cfg.release_minor)
	    != 2)
		return -EINVAL;

	cfg.mask = 0x10;
}), "%u.%u\n", cfg.release_major, cfg.release_minor);

#undef CP2112_CONFIG_ATTR

static ssize_t pstr_store(struct device *kdev, struct device_attribute *kattr,
			  const char *buf, size_t count, int number)
{}

static ssize_t pstr_show(struct device *kdev, struct device_attribute *kattr,
			 char *buf, int number)
{}

#define CP2112_PSTR_ATTR

CP2112_PSTR_ATTR(manufacturer,	CP2112_MANUFACTURER_STRING);
CP2112_PSTR_ATTR(product,	CP2112_PRODUCT_STRING);
CP2112_PSTR_ATTR(serial,	CP2112_SERIAL_STRING);

#undef CP2112_PSTR_ATTR

static const struct attribute_group cp2112_attr_group =;

/* Chmoding our sysfs attributes is simply a way to expose which fields in the
 * PROM have already been programmed. We do not depend on this preventing
 * writing to these attributes since the CP2112 will simply ignore writes to
 * already-programmed fields. This is why there is no sense in fixing this
 * racy behaviour.
 */
static void chmod_sysfs_attrs(struct hid_device *hdev)
{}

static void cp2112_gpio_irq_ack(struct irq_data *d)
{}

static void cp2112_gpio_irq_mask(struct irq_data *d)
{}

static void cp2112_gpio_irq_unmask(struct irq_data *d)
{}

static void cp2112_gpio_poll_callback(struct work_struct *work)
{}


static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)
{}

static void cp2112_gpio_irq_shutdown(struct irq_data *d)
{}

static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
{}

static const struct irq_chip cp2112_gpio_irqchip =;

static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
{}

static void cp2112_remove(struct hid_device *hdev)
{}

static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,
			    u8 *data, int size)
{}

static struct hid_driver cp2112_driver =;

module_hid_driver();
MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();