187ba5badSKris Bahnsen // SPDX-License-Identifier: GPL-2.0
29c668632SLucile Quirion /*
39c668632SLucile Quirion * Digital I/O driver for Technologic Systems I2C FPGA Core
49c668632SLucile Quirion *
503fe0035SMark Featherston * Copyright (C) 2015, 2018 Technologic Systems
69c668632SLucile Quirion * Copyright (C) 2016 Savoir-Faire Linux
79c668632SLucile Quirion */
89c668632SLucile Quirion
99c668632SLucile Quirion #include <linux/gpio/driver.h>
109c668632SLucile Quirion #include <linux/i2c.h>
11*e91d0f05SRob Herring #include <linux/of.h>
129c668632SLucile Quirion #include <linux/module.h>
139c668632SLucile Quirion #include <linux/regmap.h>
149c668632SLucile Quirion
159c668632SLucile Quirion #define DEFAULT_PIN_NUMBER 32
169c668632SLucile Quirion /*
179c668632SLucile Quirion * Register bits used by the GPIO device
189c668632SLucile Quirion * Some boards, such as TS-7970 do not have a separate input bit
199c668632SLucile Quirion */
209c668632SLucile Quirion #define TS4900_GPIO_OE 0x01
219c668632SLucile Quirion #define TS4900_GPIO_OUT 0x02
229c668632SLucile Quirion #define TS4900_GPIO_IN 0x04
239c668632SLucile Quirion #define TS7970_GPIO_IN 0x02
249c668632SLucile Quirion
259c668632SLucile Quirion struct ts4900_gpio_priv {
269c668632SLucile Quirion struct regmap *regmap;
279c668632SLucile Quirion struct gpio_chip gpio_chip;
289c668632SLucile Quirion unsigned int input_bit;
299c668632SLucile Quirion };
309c668632SLucile Quirion
ts4900_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)319c668632SLucile Quirion static int ts4900_gpio_get_direction(struct gpio_chip *chip,
329c668632SLucile Quirion unsigned int offset)
339c668632SLucile Quirion {
349c668632SLucile Quirion struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
359c668632SLucile Quirion unsigned int reg;
369c668632SLucile Quirion
379c668632SLucile Quirion regmap_read(priv->regmap, offset, ®);
389c668632SLucile Quirion
39e42615ecSMatti Vaittinen if (reg & TS4900_GPIO_OE)
40e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT;
41e42615ecSMatti Vaittinen
42e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN;
439c668632SLucile Quirion }
449c668632SLucile Quirion
ts4900_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)459c668632SLucile Quirion static int ts4900_gpio_direction_input(struct gpio_chip *chip,
469c668632SLucile Quirion unsigned int offset)
479c668632SLucile Quirion {
489c668632SLucile Quirion struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
499c668632SLucile Quirion
50576892a8SKris Bahnsen /*
51576892a8SKris Bahnsen * Only clear the OE bit here, requires a RMW. Prevents a potential issue
52576892a8SKris Bahnsen * with OE and DAT getting to the physical pin at different times.
539c668632SLucile Quirion */
5403fe0035SMark Featherston return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);
559c668632SLucile Quirion }
569c668632SLucile Quirion
ts4900_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int value)579c668632SLucile Quirion static int ts4900_gpio_direction_output(struct gpio_chip *chip,
589c668632SLucile Quirion unsigned int offset, int value)
599c668632SLucile Quirion {
609c668632SLucile Quirion struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
6103fe0035SMark Featherston unsigned int reg;
629c668632SLucile Quirion int ret;
639c668632SLucile Quirion
64576892a8SKris Bahnsen /*
65576892a8SKris Bahnsen * If changing from an input to an output, we need to first set the
66576892a8SKris Bahnsen * GPIO's DAT bit to what is requested and then set the OE bit. This
67576892a8SKris Bahnsen * prevents a glitch that can occur on the IO line.
6803fe0035SMark Featherston */
6903fe0035SMark Featherston regmap_read(priv->regmap, offset, ®);
7003fe0035SMark Featherston if (!(reg & TS4900_GPIO_OE)) {
7103fe0035SMark Featherston if (value)
7203fe0035SMark Featherston reg = TS4900_GPIO_OUT;
7303fe0035SMark Featherston else
7403fe0035SMark Featherston reg &= ~TS4900_GPIO_OUT;
7503fe0035SMark Featherston
7603fe0035SMark Featherston regmap_write(priv->regmap, offset, reg);
7703fe0035SMark Featherston }
7803fe0035SMark Featherston
799c668632SLucile Quirion if (value)
809c668632SLucile Quirion ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
819c668632SLucile Quirion TS4900_GPIO_OUT);
829c668632SLucile Quirion else
839c668632SLucile Quirion ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE);
849c668632SLucile Quirion
859c668632SLucile Quirion return ret;
869c668632SLucile Quirion }
879c668632SLucile Quirion
ts4900_gpio_get(struct gpio_chip * chip,unsigned int offset)889c668632SLucile Quirion static int ts4900_gpio_get(struct gpio_chip *chip, unsigned int offset)
899c668632SLucile Quirion {
909c668632SLucile Quirion struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
919c668632SLucile Quirion unsigned int reg;
929c668632SLucile Quirion
939c668632SLucile Quirion regmap_read(priv->regmap, offset, ®);
949c668632SLucile Quirion
959c668632SLucile Quirion return !!(reg & priv->input_bit);
969c668632SLucile Quirion }
979c668632SLucile Quirion
ts4900_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)989c668632SLucile Quirion static void ts4900_gpio_set(struct gpio_chip *chip, unsigned int offset,
999c668632SLucile Quirion int value)
1009c668632SLucile Quirion {
1019c668632SLucile Quirion struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
1029c668632SLucile Quirion
1039c668632SLucile Quirion if (value)
1049c668632SLucile Quirion regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT,
1059c668632SLucile Quirion TS4900_GPIO_OUT);
1069c668632SLucile Quirion else
1079c668632SLucile Quirion regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, 0);
1089c668632SLucile Quirion }
1099c668632SLucile Quirion
1109c668632SLucile Quirion static const struct regmap_config ts4900_regmap_config = {
1119c668632SLucile Quirion .reg_bits = 16,
1129c668632SLucile Quirion .val_bits = 8,
1139c668632SLucile Quirion };
1149c668632SLucile Quirion
115e35b5ab0SJulia Lawall static const struct gpio_chip template_chip = {
1169c668632SLucile Quirion .label = "ts4900-gpio",
1179c668632SLucile Quirion .owner = THIS_MODULE,
1189c668632SLucile Quirion .get_direction = ts4900_gpio_get_direction,
1199c668632SLucile Quirion .direction_input = ts4900_gpio_direction_input,
1209c668632SLucile Quirion .direction_output = ts4900_gpio_direction_output,
1219c668632SLucile Quirion .get = ts4900_gpio_get,
1229c668632SLucile Quirion .set = ts4900_gpio_set,
1239c668632SLucile Quirion .base = -1,
1249c668632SLucile Quirion .can_sleep = true,
1259c668632SLucile Quirion };
1269c668632SLucile Quirion
1279c668632SLucile Quirion static const struct of_device_id ts4900_gpio_of_match_table[] = {
1289c668632SLucile Quirion {
1299c668632SLucile Quirion .compatible = "technologic,ts4900-gpio",
1309c668632SLucile Quirion .data = (void *)TS4900_GPIO_IN,
1319c668632SLucile Quirion }, {
1329c668632SLucile Quirion .compatible = "technologic,ts7970-gpio",
1339c668632SLucile Quirion .data = (void *)TS7970_GPIO_IN,
1349c668632SLucile Quirion },
1359c668632SLucile Quirion { /* sentinel */ },
1369c668632SLucile Quirion };
1379c668632SLucile Quirion MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
1389c668632SLucile Quirion
ts4900_gpio_probe(struct i2c_client * client)139bf08ce13SStephen Kitt static int ts4900_gpio_probe(struct i2c_client *client)
1409c668632SLucile Quirion {
1419c668632SLucile Quirion struct ts4900_gpio_priv *priv;
1429c668632SLucile Quirion u32 ngpio;
1439c668632SLucile Quirion int ret;
1449c668632SLucile Quirion
1459c668632SLucile Quirion if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))
1469c668632SLucile Quirion ngpio = DEFAULT_PIN_NUMBER;
1479c668632SLucile Quirion
1489c668632SLucile Quirion priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
1499c668632SLucile Quirion if (!priv)
1509c668632SLucile Quirion return -ENOMEM;
1519c668632SLucile Quirion
1529c668632SLucile Quirion priv->gpio_chip = template_chip;
1539c668632SLucile Quirion priv->gpio_chip.label = "ts4900-gpio";
1549c668632SLucile Quirion priv->gpio_chip.ngpio = ngpio;
1559c668632SLucile Quirion priv->gpio_chip.parent = &client->dev;
15681317c5aSThierry Reding priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev);
1579c668632SLucile Quirion
1589c668632SLucile Quirion priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);
1599c668632SLucile Quirion if (IS_ERR(priv->regmap)) {
1609c668632SLucile Quirion ret = PTR_ERR(priv->regmap);
1619c668632SLucile Quirion dev_err(&client->dev, "Failed to allocate register map: %d\n",
1629c668632SLucile Quirion ret);
1639c668632SLucile Quirion return ret;
1649c668632SLucile Quirion }
1659c668632SLucile Quirion
1669c668632SLucile Quirion ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv);
1679c668632SLucile Quirion if (ret < 0) {
1689c668632SLucile Quirion dev_err(&client->dev, "Unable to register gpiochip\n");
1699c668632SLucile Quirion return ret;
1709c668632SLucile Quirion }
1719c668632SLucile Quirion
1729c668632SLucile Quirion i2c_set_clientdata(client, priv);
1739c668632SLucile Quirion
1749c668632SLucile Quirion return 0;
1759c668632SLucile Quirion }
1769c668632SLucile Quirion
1779c668632SLucile Quirion static const struct i2c_device_id ts4900_gpio_id_table[] = {
1789c668632SLucile Quirion { "ts4900-gpio", },
1799c668632SLucile Quirion { /* sentinel */ }
1809c668632SLucile Quirion };
1819c668632SLucile Quirion MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
1829c668632SLucile Quirion
1839c668632SLucile Quirion static struct i2c_driver ts4900_gpio_driver = {
1849c668632SLucile Quirion .driver = {
1859c668632SLucile Quirion .name = "ts4900-gpio",
1869c668632SLucile Quirion .of_match_table = ts4900_gpio_of_match_table,
1879c668632SLucile Quirion },
188b41cabb7SUwe Kleine-König .probe = ts4900_gpio_probe,
1899c668632SLucile Quirion .id_table = ts4900_gpio_id_table,
1909c668632SLucile Quirion };
1919c668632SLucile Quirion module_i2c_driver(ts4900_gpio_driver);
1929c668632SLucile Quirion
1939c668632SLucile Quirion MODULE_AUTHOR("Technologic Systems");
1949c668632SLucile Quirion MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core");
1959c668632SLucile Quirion MODULE_LICENSE("GPL");
196