| .. | .. |
|---|
| 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: |
|---|