Commit 11438237 authored by Benjamin Tissoires's avatar Benjamin Tissoires

Merge branch 'for-6.6/cp2112' into for-linus

Cleanup of the hid-cp2112 driver by Andy Shevchenko
parents 0c4b9411 a6a5eccc
...@@ -16,14 +16,14 @@ ...@@ -16,14 +16,14 @@
* https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
*/ */
#include <linux/gpio/consumer.h> #include <linux/bitops.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hidraw.h> #include <linux/hidraw.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/string_choices.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include "hid-ids.h" #include "hid-ids.h"
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#define CP2112_GPIO_CONFIG_LENGTH 5 #define CP2112_GPIO_CONFIG_LENGTH 5
#define CP2112_GPIO_GET_LENGTH 2 #define CP2112_GPIO_GET_LENGTH 2
#define CP2112_GPIO_SET_LENGTH 3 #define CP2112_GPIO_SET_LENGTH 3
#define CP2112_GPIO_MAX_GPIO 8
#define CP2112_GPIO_ALL_GPIO_MASK GENMASK(7, 0)
enum { enum {
CP2112_GPIO_CONFIG = 0x02, CP2112_GPIO_CONFIG = 0x02,
...@@ -163,19 +165,17 @@ struct cp2112_device { ...@@ -163,19 +165,17 @@ struct cp2112_device {
atomic_t read_avail; atomic_t read_avail;
atomic_t xfer_avail; atomic_t xfer_avail;
struct gpio_chip gc; struct gpio_chip gc;
struct irq_chip irq;
u8 *in_out_buffer; u8 *in_out_buffer;
struct mutex lock; struct mutex lock;
struct gpio_desc *desc[8];
bool gpio_poll; bool gpio_poll;
struct delayed_work gpio_poll_worker; struct delayed_work gpio_poll_worker;
unsigned long irq_mask; unsigned long irq_mask;
u8 gpio_prev_state; u8 gpio_prev_state;
}; };
static int gpio_push_pull = 0xFF; static int gpio_push_pull = CP2112_GPIO_ALL_GPIO_MASK;
module_param(gpio_push_pull, int, S_IRUGO | S_IWUSR); module_param(gpio_push_pull, int, 0644);
MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask"); MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask");
static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
...@@ -197,7 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ...@@ -197,7 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
goto exit; goto exit;
} }
buf[1] &= ~(1 << offset); buf[1] &= ~BIT(offset);
buf[2] = gpio_push_pull; buf[2] = gpio_push_pull;
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
...@@ -227,8 +227,8 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -227,8 +227,8 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
buf[0] = CP2112_GPIO_SET; buf[0] = CP2112_GPIO_SET;
buf[1] = value ? 0xff : 0; buf[1] = value ? CP2112_GPIO_ALL_GPIO_MASK : 0;
buf[2] = 1 << offset; buf[2] = BIT(offset);
ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf, ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf,
CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT, CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT,
...@@ -532,15 +532,13 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -532,15 +532,13 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
hid_dbg(hdev, "I2C %d messages\n", num); hid_dbg(hdev, "I2C %d messages\n", num);
if (num == 1) { if (num == 1) {
hid_dbg(hdev, "I2C %s %#04x len %d\n",
str_read_write(msgs->flags & I2C_M_RD), msgs->addr, msgs->len);
if (msgs->flags & I2C_M_RD) { if (msgs->flags & I2C_M_RD) {
hid_dbg(hdev, "I2C read %#04x len %d\n",
msgs->addr, msgs->len);
read_length = msgs->len; read_length = msgs->len;
read_buf = msgs->buf; read_buf = msgs->buf;
count = cp2112_read_req(buf, msgs->addr, msgs->len); count = cp2112_read_req(buf, msgs->addr, msgs->len);
} else { } else {
hid_dbg(hdev, "I2C write %#04x len %d\n",
msgs->addr, msgs->len);
count = cp2112_i2c_write_req(buf, msgs->addr, count = cp2112_i2c_write_req(buf, msgs->addr,
msgs->buf, msgs->len); msgs->buf, msgs->len);
} }
...@@ -648,7 +646,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, ...@@ -648,7 +646,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
int ret; int ret;
hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n", hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n",
read_write == I2C_SMBUS_WRITE ? "write" : "read", str_write_read(read_write == I2C_SMBUS_WRITE),
addr, flags, command, size); addr, flags, command, size);
switch (size) { switch (size) {
...@@ -895,7 +893,7 @@ static ssize_t name##_show(struct device *kdev, \ ...@@ -895,7 +893,7 @@ static ssize_t name##_show(struct device *kdev, \
int ret = cp2112_get_usb_config(hdev, &cfg); \ int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \ if (ret) \
return ret; \ return ret; \
return scnprintf(buf, PAGE_SIZE, format, ##__VA_ARGS__); \ return sysfs_emit(buf, format, ##__VA_ARGS__); \
} \ } \
static DEVICE_ATTR_RW(name); static DEVICE_ATTR_RW(name);
...@@ -946,18 +944,10 @@ CP2112_CONFIG_ATTR(release_version, ({ ...@@ -946,18 +944,10 @@ CP2112_CONFIG_ATTR(release_version, ({
#undef CP2112_CONFIG_ATTR #undef CP2112_CONFIG_ATTR
struct cp2112_pstring_attribute { static ssize_t pstr_store(struct device *kdev, struct device_attribute *kattr,
struct device_attribute attr; const char *buf, size_t count, int number)
unsigned char report;
};
static ssize_t pstr_store(struct device *kdev,
struct device_attribute *kattr, const char *buf,
size_t count)
{ {
struct hid_device *hdev = to_hid_device(kdev); struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report; struct cp2112_string_report report;
int ret; int ret;
...@@ -965,7 +955,7 @@ static ssize_t pstr_store(struct device *kdev, ...@@ -965,7 +955,7 @@ static ssize_t pstr_store(struct device *kdev,
ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN, ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN,
report.string, ARRAY_SIZE(report.string)); report.string, ARRAY_SIZE(report.string));
report.report = attr->report; report.report = number;
report.length = ret * sizeof(report.string[0]) + 2; report.length = ret * sizeof(report.string[0]) + 2;
report.type = USB_DT_STRING; report.type = USB_DT_STRING;
...@@ -983,17 +973,15 @@ static ssize_t pstr_store(struct device *kdev, ...@@ -983,17 +973,15 @@ static ssize_t pstr_store(struct device *kdev,
return count; return count;
} }
static ssize_t pstr_show(struct device *kdev, static ssize_t pstr_show(struct device *kdev, struct device_attribute *kattr,
struct device_attribute *kattr, char *buf) char *buf, int number)
{ {
struct hid_device *hdev = to_hid_device(kdev); struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report; struct cp2112_string_report report;
u8 length; u8 length;
int ret; int ret;
ret = cp2112_hid_get(hdev, attr->report, (u8 *)&report.contents, ret = cp2112_hid_get(hdev, number, (u8 *)&report.contents,
sizeof(report.contents), HID_FEATURE_REPORT); sizeof(report.contents), HID_FEATURE_REPORT);
if (ret < 3) { if (ret < 3) {
hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name, hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name,
...@@ -1018,10 +1006,16 @@ static ssize_t pstr_show(struct device *kdev, ...@@ -1018,10 +1006,16 @@ static ssize_t pstr_show(struct device *kdev,
} }
#define CP2112_PSTR_ATTR(name, _report) \ #define CP2112_PSTR_ATTR(name, _report) \
static struct cp2112_pstring_attribute dev_attr_##name = { \ static ssize_t name##_store(struct device *kdev, struct device_attribute *kattr, \
.attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \ const char *buf, size_t count) \
.report = _report, \ { \
}; return pstr_store(kdev, kattr, buf, count, _report); \
} \
static ssize_t name##_show(struct device *kdev, struct device_attribute *kattr, char *buf) \
{ \
return pstr_show(kdev, kattr, buf, _report); \
} \
static DEVICE_ATTR_RW(name);
CP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING); CP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING);
CP2112_PSTR_ATTR(product, CP2112_PRODUCT_STRING); CP2112_PSTR_ATTR(product, CP2112_PRODUCT_STRING);
...@@ -1036,9 +1030,9 @@ static const struct attribute_group cp2112_attr_group = { ...@@ -1036,9 +1030,9 @@ static const struct attribute_group cp2112_attr_group = {
&dev_attr_max_power.attr, &dev_attr_max_power.attr,
&dev_attr_power_mode.attr, &dev_attr_power_mode.attr,
&dev_attr_release_version.attr, &dev_attr_release_version.attr,
&dev_attr_manufacturer.attr.attr, &dev_attr_manufacturer.attr,
&dev_attr_product.attr.attr, &dev_attr_product.attr,
&dev_attr_serial.attr.attr, &dev_attr_serial.attr,
NULL NULL
} }
}; };
...@@ -1063,7 +1057,7 @@ static void chmod_sysfs_attrs(struct hid_device *hdev) ...@@ -1063,7 +1057,7 @@ static void chmod_sysfs_attrs(struct hid_device *hdev)
} }
for (attr = cp2112_attr_group.attrs; *attr; ++attr) { for (attr = cp2112_attr_group.attrs; *attr; ++attr) {
umode_t mode = (buf[1] & 1) ? S_IWUSR | S_IRUGO : S_IRUGO; umode_t mode = (buf[1] & 1) ? 0644 : 0444;
ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode); ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode);
if (ret < 0) if (ret < 0)
hid_err(hdev, "error chmoding sysfs file %s\n", hid_err(hdev, "error chmoding sysfs file %s\n",
...@@ -1080,16 +1074,20 @@ static void cp2112_gpio_irq_mask(struct irq_data *d) ...@@ -1080,16 +1074,20 @@ static void cp2112_gpio_irq_mask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc); struct cp2112_device *dev = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
__clear_bit(d->hwirq, &dev->irq_mask); __clear_bit(hwirq, &dev->irq_mask);
gpiochip_disable_irq(gc, hwirq);
} }
static void cp2112_gpio_irq_unmask(struct irq_data *d) static void cp2112_gpio_irq_unmask(struct irq_data *d)
{ {
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc); struct cp2112_device *dev = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
__set_bit(d->hwirq, &dev->irq_mask); gpiochip_enable_irq(gc, hwirq);
__set_bit(hwirq, &dev->irq_mask);
} }
static void cp2112_gpio_poll_callback(struct work_struct *work) static void cp2112_gpio_poll_callback(struct work_struct *work)
...@@ -1098,7 +1096,6 @@ static void cp2112_gpio_poll_callback(struct work_struct *work) ...@@ -1098,7 +1096,6 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
gpio_poll_worker.work); gpio_poll_worker.work);
struct irq_data *d; struct irq_data *d;
u8 gpio_mask; u8 gpio_mask;
u8 virqs = (u8)dev->irq_mask;
u32 irq_type; u32 irq_type;
int irq, virq, ret; int irq, virq, ret;
...@@ -1109,15 +1106,10 @@ static void cp2112_gpio_poll_callback(struct work_struct *work) ...@@ -1109,15 +1106,10 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
goto exit; goto exit;
gpio_mask = ret; gpio_mask = ret;
for_each_set_bit(virq, &dev->irq_mask, CP2112_GPIO_MAX_GPIO) {
while (virqs) { irq = irq_find_mapping(dev->gc.irq.domain, virq);
virq = ffs(virqs) - 1; if (!irq)
virqs &= ~BIT(virq); continue;
if (!dev->gc.to_irq)
break;
irq = dev->gc.to_irq(&dev->gc, virq);
d = irq_get_irq_data(irq); d = irq_get_irq_data(irq);
if (!d) if (!d)
...@@ -1175,6 +1167,7 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d) ...@@ -1175,6 +1167,7 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc); struct cp2112_device *dev = gpiochip_get_data(gc);
cp2112_gpio_irq_mask(d);
cancel_delayed_work_sync(&dev->gpio_poll_worker); cancel_delayed_work_sync(&dev->gpio_poll_worker);
} }
...@@ -1183,50 +1176,17 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type) ...@@ -1183,50 +1176,17 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
return 0; return 0;
} }
static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev, static const struct irq_chip cp2112_gpio_irqchip = {
int pin) .name = "cp2112-gpio",
{ .irq_startup = cp2112_gpio_irq_startup,
int ret; .irq_shutdown = cp2112_gpio_irq_shutdown,
.irq_ack = cp2112_gpio_irq_ack,
if (dev->desc[pin]) .irq_mask = cp2112_gpio_irq_mask,
return -EINVAL; .irq_unmask = cp2112_gpio_irq_unmask,
.irq_set_type = cp2112_gpio_irq_type,
dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin, .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
"HID/I2C:Event", GPIOCHIP_IRQ_RESOURCE_HELPERS,
GPIO_ACTIVE_HIGH, };
GPIOD_IN);
if (IS_ERR(dev->desc[pin])) {
dev_err(dev->gc.parent, "Failed to request GPIO\n");
return PTR_ERR(dev->desc[pin]);
}
ret = cp2112_gpio_direction_input(&dev->gc, pin);
if (ret < 0) {
dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
goto err_desc;
}
ret = gpiochip_lock_as_irq(&dev->gc, pin);
if (ret) {
dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
goto err_desc;
}
ret = gpiod_to_irq(dev->desc[pin]);
if (ret < 0) {
dev_err(dev->gc.parent, "Failed to translate GPIO to IRQ\n");
goto err_lock;
}
return ret;
err_lock:
gpiochip_unlock_as_irq(&dev->gc, pin);
err_desc:
gpiochip_free_own_desc(dev->desc[pin]);
dev->desc[pin] = NULL;
return ret;
}
static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
...@@ -1333,21 +1293,12 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1333,21 +1293,12 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->gc.set = cp2112_gpio_set; dev->gc.set = cp2112_gpio_set;
dev->gc.get = cp2112_gpio_get; dev->gc.get = cp2112_gpio_get;
dev->gc.base = -1; dev->gc.base = -1;
dev->gc.ngpio = 8; dev->gc.ngpio = CP2112_GPIO_MAX_GPIO;
dev->gc.can_sleep = 1; dev->gc.can_sleep = 1;
dev->gc.parent = &hdev->dev; dev->gc.parent = &hdev->dev;
dev->irq.name = "cp2112-gpio";
dev->irq.irq_startup = cp2112_gpio_irq_startup;
dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown;
dev->irq.irq_ack = cp2112_gpio_irq_ack;
dev->irq.irq_mask = cp2112_gpio_irq_mask;
dev->irq.irq_unmask = cp2112_gpio_irq_unmask;
dev->irq.irq_set_type = cp2112_gpio_irq_type;
dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND;
girq = &dev->gc.irq; girq = &dev->gc.irq;
girq->chip = &dev->irq; gpio_irq_chip_set_chip(girq, &cp2112_gpio_irqchip);
/* The event comes from the outside so no parent handler */ /* The event comes from the outside so no parent handler */
girq->parent_handler = NULL; girq->parent_handler = NULL;
girq->num_parents = 0; girq->num_parents = 0;
...@@ -1389,7 +1340,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1389,7 +1340,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
static void cp2112_remove(struct hid_device *hdev) static void cp2112_remove(struct hid_device *hdev)
{ {
struct cp2112_device *dev = hid_get_drvdata(hdev); struct cp2112_device *dev = hid_get_drvdata(hdev);
int i;
sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group); sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
i2c_del_adapter(&dev->adap); i2c_del_adapter(&dev->adap);
...@@ -1399,11 +1349,6 @@ static void cp2112_remove(struct hid_device *hdev) ...@@ -1399,11 +1349,6 @@ static void cp2112_remove(struct hid_device *hdev)
cancel_delayed_work_sync(&dev->gpio_poll_worker); cancel_delayed_work_sync(&dev->gpio_poll_worker);
} }
for (i = 0; i < ARRAY_SIZE(dev->desc); i++) {
gpiochip_unlock_as_irq(&dev->gc, i);
gpiochip_free_own_desc(dev->desc[i]);
}
gpiochip_remove(&dev->gc); gpiochip_remove(&dev->gc);
/* i2c_del_adapter has finished removing all i2c devices from our /* i2c_del_adapter has finished removing all i2c devices from our
* adapter. Well behaved devices should no longer call our cp2112_xfer * adapter. Well behaved devices should no longer call our cp2112_xfer
......
...@@ -30,6 +30,7 @@ static inline const char *str_read_write(bool v) ...@@ -30,6 +30,7 @@ static inline const char *str_read_write(bool v)
{ {
return v ? "read" : "write"; return v ? "read" : "write";
} }
#define str_write_read(v) str_read_write(!(v))
static inline const char *str_on_off(bool v) static inline const char *str_on_off(bool v)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment