gpio-ts4900.c (4987B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Digital I/O driver for Technologic Systems I2C FPGA Core 4 * 5 * Copyright (C) 2015, 2018 Technologic Systems 6 * Copyright (C) 2016 Savoir-Faire Linux 7 */ 8 9#include <linux/gpio/driver.h> 10#include <linux/i2c.h> 11#include <linux/of_device.h> 12#include <linux/module.h> 13#include <linux/regmap.h> 14 15#define DEFAULT_PIN_NUMBER 32 16/* 17 * Register bits used by the GPIO device 18 * Some boards, such as TS-7970 do not have a separate input bit 19 */ 20#define TS4900_GPIO_OE 0x01 21#define TS4900_GPIO_OUT 0x02 22#define TS4900_GPIO_IN 0x04 23#define TS7970_GPIO_IN 0x02 24 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 issue 52 * 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 the 66 * GPIO's DAT bit to what is requested and then set the OE bit. This 67 * 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 else 74 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 else 83 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 else 107 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 const struct i2c_device_id *id) 141{ 142 struct ts4900_gpio_priv *priv; 143 u32 ngpio; 144 int ret; 145 146 if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio)) 147 ngpio = DEFAULT_PIN_NUMBER; 148 149 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 150 if (!priv) 151 return -ENOMEM; 152 153 priv->gpio_chip = template_chip; 154 priv->gpio_chip.label = "ts4900-gpio"; 155 priv->gpio_chip.ngpio = ngpio; 156 priv->gpio_chip.parent = &client->dev; 157 priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev); 158 159 priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config); 160 if (IS_ERR(priv->regmap)) { 161 ret = PTR_ERR(priv->regmap); 162 dev_err(&client->dev, "Failed to allocate register map: %d\n", 163 ret); 164 return ret; 165 } 166 167 ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv); 168 if (ret < 0) { 169 dev_err(&client->dev, "Unable to register gpiochip\n"); 170 return ret; 171 } 172 173 i2c_set_clientdata(client, priv); 174 175 return 0; 176} 177 178static const struct i2c_device_id ts4900_gpio_id_table[] = { 179 { "ts4900-gpio", }, 180 { /* sentinel */ } 181}; 182MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table); 183 184static struct i2c_driver ts4900_gpio_driver = { 185 .driver = { 186 .name = "ts4900-gpio", 187 .of_match_table = ts4900_gpio_of_match_table, 188 }, 189 .probe = ts4900_gpio_probe, 190 .id_table = ts4900_gpio_id_table, 191}; 192module_i2c_driver(ts4900_gpio_driver); 193 194MODULE_AUTHOR("Technologic Systems"); 195MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core"); 196MODULE_LICENSE("GPL");