Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Sungbo Eo | 588 | 96.39% | 1 | 50.00% |
Lucas Stach | 22 | 3.61% | 1 | 50.00% |
Total | 610 | 2 |
// 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/gpio/driver.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> /** * struct pca9570 - GPIO driver data * @chip: GPIO controller chip * @lock: Protects write sequences * @out: Buffer for device register */ struct pca9570 { struct gpio_chip chip; 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; 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); 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 void pca9570_set(struct gpio_chip *chip, unsigned offset, int value) { struct pca9570 *gpio = gpiochip_get_data(chip); u8 buffer; int ret; mutex_lock(&gpio->lock); buffer = gpio->out; if (value) buffer |= BIT(offset); else buffer &= ~BIT(offset); ret = pca9570_write(gpio, buffer); if (ret) goto out; gpio->out = buffer; out: mutex_unlock(&gpio->lock); } static int pca9570_probe(struct i2c_client *client) { struct pca9570 *gpio; 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.ngpio = (uintptr_t)device_get_match_data(&client->dev); gpio->chip.can_sleep = true; mutex_init(&gpio->lock); /* 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 i2c_device_id pca9570_id_table[] = { { "pca9570", 4 }, { "pca9571", 8 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, pca9570_id_table); static const struct of_device_id pca9570_of_match_table[] = { { .compatible = "nxp,pca9570", .data = (void *)4 }, { .compatible = "nxp,pca9571", .data = (void *)8 }, { /* 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_new = 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");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1