Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Digital I/O driver for Technologic Systems I2C FPGA Core
0004  *
0005  * Copyright (C) 2015, 2018 Technologic Systems
0006  * Copyright (C) 2016 Savoir-Faire Linux
0007  */
0008 
0009 #include <linux/gpio/driver.h>
0010 #include <linux/i2c.h>
0011 #include <linux/of_device.h>
0012 #include <linux/module.h>
0013 #include <linux/regmap.h>
0014 
0015 #define DEFAULT_PIN_NUMBER  32
0016 /*
0017  * Register bits used by the GPIO device
0018  * Some boards, such as TS-7970 do not have a separate input bit
0019  */
0020 #define TS4900_GPIO_OE      0x01
0021 #define TS4900_GPIO_OUT     0x02
0022 #define TS4900_GPIO_IN      0x04
0023 #define TS7970_GPIO_IN      0x02
0024 
0025 struct ts4900_gpio_priv {
0026     struct regmap *regmap;
0027     struct gpio_chip gpio_chip;
0028     unsigned int input_bit;
0029 };
0030 
0031 static int ts4900_gpio_get_direction(struct gpio_chip *chip,
0032                      unsigned int offset)
0033 {
0034     struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
0035     unsigned int reg;
0036 
0037     regmap_read(priv->regmap, offset, &reg);
0038 
0039     if (reg & TS4900_GPIO_OE)
0040         return GPIO_LINE_DIRECTION_OUT;
0041 
0042     return GPIO_LINE_DIRECTION_IN;
0043 }
0044 
0045 static int ts4900_gpio_direction_input(struct gpio_chip *chip,
0046                        unsigned int offset)
0047 {
0048     struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
0049 
0050     /*
0051      * Only clear the OE bit here, requires a RMW. Prevents a potential issue
0052      * with OE and DAT getting to the physical pin at different times.
0053      */
0054     return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);
0055 }
0056 
0057 static int ts4900_gpio_direction_output(struct gpio_chip *chip,
0058                     unsigned int offset, int value)
0059 {
0060     struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
0061     unsigned int reg;
0062     int ret;
0063 
0064     /*
0065      * If changing from an input to an output, we need to first set the
0066      * GPIO's DAT bit to what is requested and then set the OE bit. This
0067      * prevents a glitch that can occur on the IO line.
0068      */
0069     regmap_read(priv->regmap, offset, &reg);
0070     if (!(reg & TS4900_GPIO_OE)) {
0071         if (value)
0072             reg = TS4900_GPIO_OUT;
0073         else
0074             reg &= ~TS4900_GPIO_OUT;
0075 
0076         regmap_write(priv->regmap, offset, reg);
0077     }
0078 
0079     if (value)
0080         ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
0081                              TS4900_GPIO_OUT);
0082     else
0083         ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE);
0084 
0085     return ret;
0086 }
0087 
0088 static int ts4900_gpio_get(struct gpio_chip *chip, unsigned int offset)
0089 {
0090     struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
0091     unsigned int reg;
0092 
0093     regmap_read(priv->regmap, offset, &reg);
0094 
0095     return !!(reg & priv->input_bit);
0096 }
0097 
0098 static void ts4900_gpio_set(struct gpio_chip *chip, unsigned int offset,
0099                 int value)
0100 {
0101     struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
0102 
0103     if (value)
0104         regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT,
0105                    TS4900_GPIO_OUT);
0106     else
0107         regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, 0);
0108 }
0109 
0110 static const struct regmap_config ts4900_regmap_config = {
0111     .reg_bits = 16,
0112     .val_bits = 8,
0113 };
0114 
0115 static const struct gpio_chip template_chip = {
0116     .label          = "ts4900-gpio",
0117     .owner          = THIS_MODULE,
0118     .get_direction      = ts4900_gpio_get_direction,
0119     .direction_input    = ts4900_gpio_direction_input,
0120     .direction_output   = ts4900_gpio_direction_output,
0121     .get            = ts4900_gpio_get,
0122     .set            = ts4900_gpio_set,
0123     .base           = -1,
0124     .can_sleep      = true,
0125 };
0126 
0127 static const struct of_device_id ts4900_gpio_of_match_table[] = {
0128     {
0129         .compatible = "technologic,ts4900-gpio",
0130         .data = (void *)TS4900_GPIO_IN,
0131     }, {
0132         .compatible = "technologic,ts7970-gpio",
0133         .data = (void *)TS7970_GPIO_IN,
0134     },
0135     { /* sentinel */ },
0136 };
0137 MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
0138 
0139 static int ts4900_gpio_probe(struct i2c_client *client,
0140             const struct i2c_device_id *id)
0141 {
0142     struct ts4900_gpio_priv *priv;
0143     u32 ngpio;
0144     int ret;
0145 
0146     if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))
0147         ngpio = DEFAULT_PIN_NUMBER;
0148 
0149     priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
0150     if (!priv)
0151         return -ENOMEM;
0152 
0153     priv->gpio_chip = template_chip;
0154     priv->gpio_chip.label = "ts4900-gpio";
0155     priv->gpio_chip.ngpio = ngpio;
0156     priv->gpio_chip.parent = &client->dev;
0157     priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev);
0158 
0159     priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);
0160     if (IS_ERR(priv->regmap)) {
0161         ret = PTR_ERR(priv->regmap);
0162         dev_err(&client->dev, "Failed to allocate register map: %d\n",
0163             ret);
0164         return ret;
0165     }
0166 
0167     ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv);
0168     if (ret < 0) {
0169         dev_err(&client->dev, "Unable to register gpiochip\n");
0170         return ret;
0171     }
0172 
0173     i2c_set_clientdata(client, priv);
0174 
0175     return 0;
0176 }
0177 
0178 static const struct i2c_device_id ts4900_gpio_id_table[] = {
0179     { "ts4900-gpio", },
0180     { /* sentinel */ }
0181 };
0182 MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
0183 
0184 static struct i2c_driver ts4900_gpio_driver = {
0185     .driver = {
0186         .name = "ts4900-gpio",
0187         .of_match_table = ts4900_gpio_of_match_table,
0188     },
0189     .probe = ts4900_gpio_probe,
0190     .id_table = ts4900_gpio_id_table,
0191 };
0192 module_i2c_driver(ts4900_gpio_driver);
0193 
0194 MODULE_AUTHOR("Technologic Systems");
0195 MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core");
0196 MODULE_LICENSE("GPL");