136 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// Gateworks I2C PLD GPIO expander4//5// Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>6//7// Based on code and know-how from the OpenWrt driver:8// Copyright (C) 2009 Gateworks Corporation9// Authors: Chris Lang, Imre Kaloz10 11#include <linux/bits.h>12#include <linux/kernel.h>13#include <linux/slab.h>14#include <linux/gpio/driver.h>15#include <linux/i2c.h>16#include <linux/module.h>17 18/**19 * struct gw_pld - State container for Gateworks PLD20 * @chip: GPIO chip instance21 * @client: I2C client22 * @out: shadow register for the output bute23 */24struct gw_pld {25 struct gpio_chip chip;26 struct i2c_client *client;27 u8 out;28};29 30/*31 * The Gateworks I2C PLD chip only expose one read and one write register.32 * Writing a "one" bit (to match the reset state) lets that pin be used as an33 * input. It is an open-drain model.34 */35static int gw_pld_input8(struct gpio_chip *gc, unsigned offset)36{37 struct gw_pld *gw = gpiochip_get_data(gc);38 39 gw->out |= BIT(offset);40 return i2c_smbus_write_byte(gw->client, gw->out);41}42 43static int gw_pld_get8(struct gpio_chip *gc, unsigned offset)44{45 struct gw_pld *gw = gpiochip_get_data(gc);46 s32 val;47 48 val = i2c_smbus_read_byte(gw->client);49 50 return (val < 0) ? 0 : !!(val & BIT(offset));51}52 53static int gw_pld_output8(struct gpio_chip *gc, unsigned offset, int value)54{55 struct gw_pld *gw = gpiochip_get_data(gc);56 57 if (value)58 gw->out |= BIT(offset);59 else60 gw->out &= ~BIT(offset);61 62 return i2c_smbus_write_byte(gw->client, gw->out);63}64 65static void gw_pld_set8(struct gpio_chip *gc, unsigned offset, int value)66{67 gw_pld_output8(gc, offset, value);68}69 70static int gw_pld_probe(struct i2c_client *client)71{72 struct device *dev = &client->dev;73 struct gw_pld *gw;74 int ret;75 76 gw = devm_kzalloc(dev, sizeof(*gw), GFP_KERNEL);77 if (!gw)78 return -ENOMEM;79 80 gw->chip.base = -1;81 gw->chip.can_sleep = true;82 gw->chip.parent = dev;83 gw->chip.owner = THIS_MODULE;84 gw->chip.label = dev_name(dev);85 gw->chip.ngpio = 8;86 gw->chip.direction_input = gw_pld_input8;87 gw->chip.get = gw_pld_get8;88 gw->chip.direction_output = gw_pld_output8;89 gw->chip.set = gw_pld_set8;90 gw->client = client;91 92 /*93 * The Gateworks I2C PLD chip does not properly send the acknowledge94 * bit at all times, but we can still use the standard i2c_smbus95 * functions by simply ignoring this bit.96 */97 client->flags |= I2C_M_IGNORE_NAK;98 gw->out = 0xFF;99 100 i2c_set_clientdata(client, gw);101 102 ret = devm_gpiochip_add_data(dev, &gw->chip, gw);103 if (ret)104 return ret;105 106 dev_info(dev, "registered Gateworks PLD GPIO device\n");107 108 return 0;109}110 111static const struct i2c_device_id gw_pld_id[] = {112 { "gw-pld", },113 { }114};115MODULE_DEVICE_TABLE(i2c, gw_pld_id);116 117static const struct of_device_id gw_pld_dt_ids[] = {118 { .compatible = "gateworks,pld-gpio", },119 { },120};121MODULE_DEVICE_TABLE(of, gw_pld_dt_ids);122 123static struct i2c_driver gw_pld_driver = {124 .driver = {125 .name = "gw_pld",126 .of_match_table = gw_pld_dt_ids,127 },128 .probe = gw_pld_probe,129 .id_table = gw_pld_id,130};131module_i2c_driver(gw_pld_driver);132 133MODULE_DESCRIPTION("Gateworks I2C PLD GPIO expander");134MODULE_LICENSE("GPL");135MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");136