1 // SPDX-License-Identifier: GPL-2.0
3 * GPIO driver for TI TPS65219 PMICs
5 * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
8 #include <linux/bits.h>
9 #include <linux/gpio/driver.h>
10 #include <linux/mfd/tps65219.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
15 #define TPS65219_GPIO0_DIR_MASK BIT(3)
16 #define TPS65219_GPIO0_OFFSET 2
17 #define TPS65219_GPIO0_IDX 0
18 #define TPS65219_GPIO_DIR_IN 1
19 #define TPS65219_GPIO_DIR_OUT 0
21 struct tps65219_gpio {
22 struct gpio_chip gpio_chip;
26 static int tps65219_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
28 struct tps65219_gpio *gpio = gpiochip_get_data(gc);
31 if (offset != TPS65219_GPIO0_IDX)
32 return GPIO_LINE_DIRECTION_OUT;
34 ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, &val);
38 return !!(val & TPS65219_GPIO0_DIR_MASK);
41 static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
43 struct tps65219_gpio *gpio = gpiochip_get_data(gc);
44 struct device *dev = gpio->tps->dev;
47 if (offset != TPS65219_GPIO0_IDX) {
48 dev_err(dev, "GPIO%d is output only, cannot get\n", offset);
52 ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_CTRL, &val);
56 ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK));
57 dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);
60 * Depending on NVM config, return an error if direction is output, otherwise the GPIO0
64 if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
70 static void tps65219_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
72 struct tps65219_gpio *gpio = gpiochip_get_data(gc);
73 struct device *dev = gpio->tps->dev;
76 bit = (offset == TPS65219_GPIO0_IDX) ? TPS65219_GPIO0_OFFSET : offset - 1;
81 if (regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG, mask, v))
82 dev_err(dev, "GPIO%d, set to value %d failed.\n", offset, value);
85 static int tps65219_gpio_change_direction(struct gpio_chip *gc, unsigned int offset,
86 unsigned int direction)
88 struct tps65219_gpio *gpio = gpiochip_get_data(gc);
89 struct device *dev = gpio->tps->dev;
92 * Documentation is stating that GPIO0 direction must not be changed in Linux:
93 * Table 8-34. MFP_1_CONFIG(3): MULTI_DEVICE_ENABLE, should only be changed in INITIALIZE
94 * state (prior to ON Request).
95 * Set statically by NVM, changing direction in application can cause a hang.
96 * Below can be used for test purpose only.
99 if (IS_ENABLED(CONFIG_DEBUG_GPIO)) {
100 int ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG,
101 TPS65219_GPIO0_DIR_MASK, direction);
104 "GPIO DEBUG enabled: Fail to change direction to %u for GPIO%d.\n",
111 "GPIO%d direction set by NVM, change to %u failed, not allowed by specification\n",
117 static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
119 struct tps65219_gpio *gpio = gpiochip_get_data(gc);
120 struct device *dev = gpio->tps->dev;
122 if (offset != TPS65219_GPIO0_IDX) {
123 dev_err(dev, "GPIO%d is output only, cannot change to input\n", offset);
127 if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_IN)
130 return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_IN);
133 static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
135 tps65219_gpio_set(gc, offset, value);
136 if (offset != TPS65219_GPIO0_IDX)
139 if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
142 return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_OUT);
145 static const struct gpio_chip tps65219_template_chip = {
146 .label = "tps65219-gpio",
147 .owner = THIS_MODULE,
148 .get_direction = tps65219_gpio_get_direction,
149 .direction_input = tps65219_gpio_direction_input,
150 .direction_output = tps65219_gpio_direction_output,
151 .get = tps65219_gpio_get,
152 .set = tps65219_gpio_set,
158 static int tps65219_gpio_probe(struct platform_device *pdev)
160 struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
161 struct tps65219_gpio *gpio;
163 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
168 gpio->gpio_chip = tps65219_template_chip;
169 gpio->gpio_chip.parent = tps->dev;
171 return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, gpio);
174 static struct platform_driver tps65219_gpio_driver = {
176 .name = "tps65219-gpio",
178 .probe = tps65219_gpio_probe,
180 module_platform_driver(tps65219_gpio_driver);
182 MODULE_ALIAS("platform:tps65219-gpio");
183 MODULE_AUTHOR("Jonathan Cormier <jcormier@criticallink.com>");
184 MODULE_DESCRIPTION("TPS65219 GPIO driver");
185 MODULE_LICENSE("GPL");