196 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Digital I/O driver for Technologic Systems I2C FPGA Core4 *5 * Copyright (C) 2015, 2018 Technologic Systems6 * Copyright (C) 2016 Savoir-Faire Linux7 */8 9#include <linux/gpio/driver.h>10#include <linux/i2c.h>11#include <linux/of.h>12#include <linux/module.h>13#include <linux/regmap.h>14 15#define DEFAULT_PIN_NUMBER 3216/*17 * Register bits used by the GPIO device18 * Some boards, such as TS-7970 do not have a separate input bit19 */20#define TS4900_GPIO_OE 0x0121#define TS4900_GPIO_OUT 0x0222#define TS4900_GPIO_IN 0x0423#define TS7970_GPIO_IN 0x0224 25struct ts4900_gpio_priv {26 struct regmap *regmap;27 struct gpio_chip gpio_chip;28 unsigned int input_bit;29};30 31static int ts4900_gpio_get_direction(struct gpio_chip *chip,32 unsigned int offset)33{34 struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);35 unsigned int reg;36 37 regmap_read(priv->regmap, offset, ®);38 39 if (reg & TS4900_GPIO_OE)40 return GPIO_LINE_DIRECTION_OUT;41 42 return GPIO_LINE_DIRECTION_IN;43}44 45static int ts4900_gpio_direction_input(struct gpio_chip *chip,46 unsigned int offset)47{48 struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);49 50 /*51 * Only clear the OE bit here, requires a RMW. Prevents a potential issue52 * with OE and DAT getting to the physical pin at different times.53 */54 return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);55}56 57static int ts4900_gpio_direction_output(struct gpio_chip *chip,58 unsigned int offset, int value)59{60 struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);61 unsigned int reg;62 int ret;63 64 /*65 * If changing from an input to an output, we need to first set the66 * GPIO's DAT bit to what is requested and then set the OE bit. This67 * prevents a glitch that can occur on the IO line.68 */69 regmap_read(priv->regmap, offset, ®);70 if (!(reg & TS4900_GPIO_OE)) {71 if (value)72 reg = TS4900_GPIO_OUT;73 else74 reg &= ~TS4900_GPIO_OUT;75 76 regmap_write(priv->regmap, offset, reg);77 }78 79 if (value)80 ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |81 TS4900_GPIO_OUT);82 else83 ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE);84 85 return ret;86}87 88static int ts4900_gpio_get(struct gpio_chip *chip, unsigned int offset)89{90 struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);91 unsigned int reg;92 93 regmap_read(priv->regmap, offset, ®);94 95 return !!(reg & priv->input_bit);96}97 98static void ts4900_gpio_set(struct gpio_chip *chip, unsigned int offset,99 int value)100{101 struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);102 103 if (value)104 regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT,105 TS4900_GPIO_OUT);106 else107 regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, 0);108}109 110static const struct regmap_config ts4900_regmap_config = {111 .reg_bits = 16,112 .val_bits = 8,113};114 115static const struct gpio_chip template_chip = {116 .label = "ts4900-gpio",117 .owner = THIS_MODULE,118 .get_direction = ts4900_gpio_get_direction,119 .direction_input = ts4900_gpio_direction_input,120 .direction_output = ts4900_gpio_direction_output,121 .get = ts4900_gpio_get,122 .set = ts4900_gpio_set,123 .base = -1,124 .can_sleep = true,125};126 127static const struct of_device_id ts4900_gpio_of_match_table[] = {128 {129 .compatible = "technologic,ts4900-gpio",130 .data = (void *)TS4900_GPIO_IN,131 }, {132 .compatible = "technologic,ts7970-gpio",133 .data = (void *)TS7970_GPIO_IN,134 },135 { /* sentinel */ },136};137MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);138 139static int ts4900_gpio_probe(struct i2c_client *client)140{141 struct ts4900_gpio_priv *priv;142 u32 ngpio;143 int ret;144 145 if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))146 ngpio = DEFAULT_PIN_NUMBER;147 148 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);149 if (!priv)150 return -ENOMEM;151 152 priv->gpio_chip = template_chip;153 priv->gpio_chip.label = "ts4900-gpio";154 priv->gpio_chip.ngpio = ngpio;155 priv->gpio_chip.parent = &client->dev;156 priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev);157 158 priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);159 if (IS_ERR(priv->regmap)) {160 ret = PTR_ERR(priv->regmap);161 dev_err(&client->dev, "Failed to allocate register map: %d\n",162 ret);163 return ret;164 }165 166 ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv);167 if (ret < 0) {168 dev_err(&client->dev, "Unable to register gpiochip\n");169 return ret;170 }171 172 i2c_set_clientdata(client, priv);173 174 return 0;175}176 177static const struct i2c_device_id ts4900_gpio_id_table[] = {178 { "ts4900-gpio", },179 { /* sentinel */ }180};181MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);182 183static struct i2c_driver ts4900_gpio_driver = {184 .driver = {185 .name = "ts4900-gpio",186 .of_match_table = ts4900_gpio_of_match_table,187 },188 .probe = ts4900_gpio_probe,189 .id_table = ts4900_gpio_id_table,190};191module_i2c_driver(ts4900_gpio_driver);192 193MODULE_AUTHOR("Technologic Systems");194MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core");195MODULE_LICENSE("GPL");196