diff options
| author | Sang-Heon Jeon <ekffu200098@gmail.com> | 2026-08-24 01:18:14 +0900 |
|---|---|---|
| committer | Julia Lawall <Julia.Lawall@inria.fr> | 2026-08-23 22:12:11 +0200 |
| commit | 2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c (patch) | |
| tree | dcc4da1d99f17541c5590ac63c77da4bf372a4ab /drivers/gpio/gpio-pca9570.c | |
| download | linux-stable-2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c.tar.gz linux-stable-2bd30b8dc75b823dd7bbef9d7bc68e1fd7ecee5c.zip | |
coccinelle: alloc_cast: drop removed allocatorsgrafted
- pci_alloc_consistent() and pci_zalloc_consistent() were removed by
commit 7968778914e5
("PCI: Remove the deprecated "pci-dma-compat.h" API")
- kmem_alloc() was removed by commit f078d4ea8276
("xfs: convert kmem_alloc() to kmalloc()")
- kmem_zalloc() was removed by commit 10634530f7ba
("xfs: convert kmem_zalloc() to kzalloc()")
- kmem_zone_alloc() and kmem_zone_zalloc() were removed by commit
bae633a4a283 ("xfs: remove xfs_zone_{alloc,zalloc} helpers")
So drop them from the rules.
No functional change.
Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
Diffstat (limited to 'drivers/gpio/gpio-pca9570.c')
| -rw-r--r-- | drivers/gpio/gpio-pca9570.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c new file mode 100644 index 000000000..db027c104 --- /dev/null +++ b/drivers/gpio/gpio-pca9570.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for PCA9570 I2C GPO expander + * + * Copyright (C) 2020 Sungbo Eo <mans0n@gorani.run> + * + * Based on gpio-tpic2810.c + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis <afd@ti.com> + */ + +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/device/devres.h> +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/types.h> + +#define SLG7XL45106_GPO_REG 0xDB + +/** + * struct pca9570_chip_data - GPIO platformdata + * @ngpio: no of gpios + * @command: Command to be sent + */ +struct pca9570_chip_data { + u16 ngpio; + u32 command; +}; + +/** + * struct pca9570 - GPIO driver data + * @chip: GPIO controller chip + * @chip_data: GPIO controller platform data + * @lock: Protects write sequences + * @out: Buffer for device register + */ +struct pca9570 { + struct gpio_chip chip; + const struct pca9570_chip_data *chip_data; + struct mutex lock; + u8 out; +}; + +static int pca9570_read(struct pca9570 *gpio, u8 *value) +{ + struct i2c_client *client = to_i2c_client(gpio->chip.parent); + int ret; + + if (gpio->chip_data->command != 0) + ret = i2c_smbus_read_byte_data(client, gpio->chip_data->command); + else + ret = i2c_smbus_read_byte(client); + + if (ret < 0) + return ret; + + *value = ret; + return 0; +} + +static int pca9570_write(struct pca9570 *gpio, u8 value) +{ + struct i2c_client *client = to_i2c_client(gpio->chip.parent); + + if (gpio->chip_data->command != 0) + return i2c_smbus_write_byte_data(client, gpio->chip_data->command, value); + + return i2c_smbus_write_byte(client, value); +} + +static int pca9570_get_direction(struct gpio_chip *chip, + unsigned offset) +{ + /* This device always output */ + return GPIO_LINE_DIRECTION_OUT; +} + +static int pca9570_get(struct gpio_chip *chip, unsigned offset) +{ + struct pca9570 *gpio = gpiochip_get_data(chip); + u8 buffer; + int ret; + + ret = pca9570_read(gpio, &buffer); + if (ret) + return ret; + + return !!(buffer & BIT(offset)); +} + +static int pca9570_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct pca9570 *gpio = gpiochip_get_data(chip); + u8 buffer; + int ret; + + guard(mutex)(&gpio->lock); + + buffer = gpio->out; + if (value) + buffer |= BIT(offset); + else + buffer &= ~BIT(offset); + + ret = pca9570_write(gpio, buffer); + if (ret) + return ret; + + gpio->out = buffer; + + return 0; +} + +static int pca9570_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct pca9570 *gpio; + int ret; + + gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->chip.label = client->name; + gpio->chip.parent = &client->dev; + gpio->chip.owner = THIS_MODULE; + gpio->chip.get_direction = pca9570_get_direction; + gpio->chip.get = pca9570_get; + gpio->chip.set = pca9570_set; + gpio->chip.base = -1; + gpio->chip_data = i2c_get_match_data(client); + gpio->chip.ngpio = gpio->chip_data->ngpio; + gpio->chip.can_sleep = true; + + ret = devm_mutex_init(dev, &gpio->lock); + if (ret) + return ret; + + /* Read the current output level */ + pca9570_read(gpio, &gpio->out); + + i2c_set_clientdata(client, gpio); + + return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio); +} + +static const struct pca9570_chip_data pca9570_gpio = { + .ngpio = 4, +}; + +static const struct pca9570_chip_data pca9571_gpio = { + .ngpio = 8, +}; + +static const struct pca9570_chip_data slg7xl45106_gpio = { + .ngpio = 8, + .command = SLG7XL45106_GPO_REG, +}; + +static const struct i2c_device_id pca9570_id_table[] = { + { .name = "pca9570", .driver_data = (kernel_ulong_t)&pca9570_gpio }, + { .name = "pca9571", .driver_data = (kernel_ulong_t)&pca9571_gpio }, + { .name = "slg7xl45106", .driver_data = (kernel_ulong_t)&slg7xl45106_gpio }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, pca9570_id_table); + +static const struct of_device_id pca9570_of_match_table[] = { + { .compatible = "dlg,slg7xl45106", .data = &slg7xl45106_gpio}, + { .compatible = "nxp,pca9570", .data = &pca9570_gpio }, + { .compatible = "nxp,pca9571", .data = &pca9571_gpio }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pca9570_of_match_table); + +static struct i2c_driver pca9570_driver = { + .driver = { + .name = "pca9570", + .of_match_table = pca9570_of_match_table, + }, + .probe = pca9570_probe, + .id_table = pca9570_id_table, +}; +module_i2c_driver(pca9570_driver); + +MODULE_AUTHOR("Sungbo Eo <mans0n@gorani.run>"); +MODULE_DESCRIPTION("GPIO expander driver for PCA9570"); +MODULE_LICENSE("GPL v2"); |
