.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * hid-cp2112.c - Silicon Labs HID USB to SMBus master bridge |
---|
3 | 4 | * Copyright (c) 2013,2014 Uplogix, Inc. |
---|
4 | 5 | * David Barksdale <dbarksdale@uplogix.com> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms and conditions of the GNU General Public License, |
---|
8 | | - * version 2, as published by the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | 6 | */ |
---|
15 | 7 | |
---|
16 | 8 | /* |
---|
.. | .. |
---|
19 | 11 | * host communicates with the CP2112 via raw HID reports. |
---|
20 | 12 | * |
---|
21 | 13 | * Data Sheet: |
---|
22 | | - * http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf |
---|
| 14 | + * https://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf |
---|
23 | 15 | * Programming Interface Specification: |
---|
24 | 16 | * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf |
---|
25 | 17 | */ |
---|
26 | 18 | |
---|
27 | | -#include <linux/gpio.h> |
---|
| 19 | +#include <linux/gpio/consumer.h> |
---|
| 20 | +#include <linux/gpio/machine.h> |
---|
28 | 21 | #include <linux/gpio/driver.h> |
---|
29 | 22 | #include <linux/hid.h> |
---|
30 | 23 | #include <linux/hidraw.h> |
---|
.. | .. |
---|
168 | 161 | atomic_t read_avail; |
---|
169 | 162 | atomic_t xfer_avail; |
---|
170 | 163 | struct gpio_chip gc; |
---|
| 164 | + struct irq_chip irq; |
---|
171 | 165 | u8 *in_out_buffer; |
---|
172 | 166 | struct mutex lock; |
---|
173 | 167 | |
---|
.. | .. |
---|
794 | 788 | data->word = le16_to_cpup((__le16 *)buf); |
---|
795 | 789 | break; |
---|
796 | 790 | case I2C_SMBUS_I2C_BLOCK_DATA: |
---|
| 791 | + if (read_length > I2C_SMBUS_BLOCK_MAX) { |
---|
| 792 | + ret = -EINVAL; |
---|
| 793 | + goto power_normal; |
---|
| 794 | + } |
---|
| 795 | + |
---|
797 | 796 | memcpy(data->block + 1, buf, read_length); |
---|
798 | 797 | break; |
---|
799 | 798 | case I2C_SMBUS_BLOCK_DATA: |
---|
.. | .. |
---|
1182 | 1181 | return 0; |
---|
1183 | 1182 | } |
---|
1184 | 1183 | |
---|
1185 | | -static struct irq_chip cp2112_gpio_irqchip = { |
---|
1186 | | - .name = "cp2112-gpio", |
---|
1187 | | - .irq_startup = cp2112_gpio_irq_startup, |
---|
1188 | | - .irq_shutdown = cp2112_gpio_irq_shutdown, |
---|
1189 | | - .irq_ack = cp2112_gpio_irq_ack, |
---|
1190 | | - .irq_mask = cp2112_gpio_irq_mask, |
---|
1191 | | - .irq_unmask = cp2112_gpio_irq_unmask, |
---|
1192 | | - .irq_set_type = cp2112_gpio_irq_type, |
---|
1193 | | -}; |
---|
1194 | | - |
---|
1195 | 1184 | static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev, |
---|
1196 | 1185 | int pin) |
---|
1197 | 1186 | { |
---|
.. | .. |
---|
1201 | 1190 | return -EINVAL; |
---|
1202 | 1191 | |
---|
1203 | 1192 | dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin, |
---|
1204 | | - "HID/I2C:Event"); |
---|
| 1193 | + "HID/I2C:Event", |
---|
| 1194 | + GPIO_ACTIVE_HIGH, |
---|
| 1195 | + GPIOD_IN); |
---|
1205 | 1196 | if (IS_ERR(dev->desc[pin])) { |
---|
1206 | 1197 | dev_err(dev->gc.parent, "Failed to request GPIO\n"); |
---|
1207 | 1198 | return PTR_ERR(dev->desc[pin]); |
---|
.. | .. |
---|
1240 | 1231 | struct cp2112_device *dev; |
---|
1241 | 1232 | u8 buf[3]; |
---|
1242 | 1233 | struct cp2112_smbus_config_report config; |
---|
| 1234 | + struct gpio_irq_chip *girq; |
---|
1243 | 1235 | int ret; |
---|
1244 | 1236 | |
---|
1245 | 1237 | dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL); |
---|
.. | .. |
---|
1343 | 1335 | dev->gc.can_sleep = 1; |
---|
1344 | 1336 | dev->gc.parent = &hdev->dev; |
---|
1345 | 1337 | |
---|
| 1338 | + dev->irq.name = "cp2112-gpio"; |
---|
| 1339 | + dev->irq.irq_startup = cp2112_gpio_irq_startup; |
---|
| 1340 | + dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown; |
---|
| 1341 | + dev->irq.irq_ack = cp2112_gpio_irq_ack; |
---|
| 1342 | + dev->irq.irq_mask = cp2112_gpio_irq_mask; |
---|
| 1343 | + dev->irq.irq_unmask = cp2112_gpio_irq_unmask; |
---|
| 1344 | + dev->irq.irq_set_type = cp2112_gpio_irq_type; |
---|
| 1345 | + dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND; |
---|
| 1346 | + |
---|
| 1347 | + girq = &dev->gc.irq; |
---|
| 1348 | + girq->chip = &dev->irq; |
---|
| 1349 | + /* The event comes from the outside so no parent handler */ |
---|
| 1350 | + girq->parent_handler = NULL; |
---|
| 1351 | + girq->num_parents = 0; |
---|
| 1352 | + girq->parents = NULL; |
---|
| 1353 | + girq->default_type = IRQ_TYPE_NONE; |
---|
| 1354 | + girq->handler = handle_simple_irq; |
---|
| 1355 | + girq->threaded = true; |
---|
| 1356 | + |
---|
1346 | 1357 | ret = gpiochip_add_data(&dev->gc, dev); |
---|
1347 | 1358 | if (ret < 0) { |
---|
1348 | 1359 | hid_err(hdev, "error registering gpio chip\n"); |
---|
.. | .. |
---|
1358 | 1369 | chmod_sysfs_attrs(hdev); |
---|
1359 | 1370 | hid_hw_power(hdev, PM_HINT_NORMAL); |
---|
1360 | 1371 | |
---|
1361 | | - ret = gpiochip_irqchip_add(&dev->gc, &cp2112_gpio_irqchip, 0, |
---|
1362 | | - handle_simple_irq, IRQ_TYPE_NONE); |
---|
1363 | | - if (ret) { |
---|
1364 | | - dev_err(dev->gc.parent, "failed to add IRQ chip\n"); |
---|
1365 | | - goto err_sysfs_remove; |
---|
1366 | | - } |
---|
1367 | | - |
---|
1368 | 1372 | return ret; |
---|
1369 | 1373 | |
---|
1370 | | -err_sysfs_remove: |
---|
1371 | | - sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group); |
---|
1372 | 1374 | err_gpiochip_remove: |
---|
1373 | 1375 | gpiochip_remove(&dev->gc); |
---|
1374 | 1376 | err_free_i2c: |
---|