1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright 2015 Verifone Int.
4 *
5 * Author: Nicolas Saenz Julienne <nicolassaenzj@gmail.com>
6 *
7 * This driver is based on the gpio-tps65912 implementation.
8 */
9
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/errno.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16 #include <linux/mfd/tps65218.h>
17
18 struct tps65218_gpio {
19 struct tps65218 *tps65218;
20 struct gpio_chip gpio_chip;
21 };
22
tps65218_gpio_get(struct gpio_chip * gc,unsigned offset)23 static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset)
24 {
25 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
26 struct tps65218 *tps65218 = tps65218_gpio->tps65218;
27 unsigned int val;
28 int ret;
29
30 ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val);
31 if (ret)
32 return ret;
33
34 return !!(val & (TPS65218_ENABLE2_GPIO1 << offset));
35 }
36
tps65218_gpio_set(struct gpio_chip * gc,unsigned int offset,int value)37 static int tps65218_gpio_set(struct gpio_chip *gc, unsigned int offset,
38 int value)
39 {
40 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
41 struct tps65218 *tps65218 = tps65218_gpio->tps65218;
42
43 if (value)
44 return tps65218_set_bits(tps65218, TPS65218_REG_ENABLE2,
45 TPS65218_ENABLE2_GPIO1 << offset,
46 TPS65218_ENABLE2_GPIO1 << offset,
47 TPS65218_PROTECT_L1);
48
49 return tps65218_clear_bits(tps65218, TPS65218_REG_ENABLE2,
50 TPS65218_ENABLE2_GPIO1 << offset,
51 TPS65218_PROTECT_L1);
52 }
53
tps65218_gpio_output(struct gpio_chip * gc,unsigned offset,int value)54 static int tps65218_gpio_output(struct gpio_chip *gc, unsigned offset,
55 int value)
56 {
57 /* Only drives GPOs */
58 return tps65218_gpio_set(gc, offset, value);
59 }
60
tps65218_gpio_request(struct gpio_chip * gc,unsigned offset)61 static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
62 {
63 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
64 struct tps65218 *tps65218 = tps65218_gpio->tps65218;
65 int ret;
66
67 if (gpiochip_line_is_open_source(gc, offset)) {
68 dev_err(gc->parent, "can't work as open source\n");
69 return -EINVAL;
70 }
71
72 switch (offset) {
73 case 0:
74 if (!gpiochip_line_is_open_drain(gc, offset)) {
75 dev_err(gc->parent, "GPO1 works only as open drain\n");
76 return -EINVAL;
77 }
78
79 /* Disable sequencer for GPO1 */
80 ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,
81 TPS65218_SEQ7_GPO1_SEQ_MASK,
82 TPS65218_PROTECT_L1);
83 if (ret)
84 return ret;
85
86 /* Setup GPO1 */
87 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,
88 TPS65218_CONFIG1_IO1_SEL,
89 TPS65218_PROTECT_L1);
90 if (ret)
91 return ret;
92
93 break;
94 case 1:
95 /* Setup GPO2 */
96 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,
97 TPS65218_CONFIG1_IO1_SEL,
98 TPS65218_PROTECT_L1);
99 if (ret)
100 return ret;
101
102 break;
103
104 case 2:
105 if (!gpiochip_line_is_open_drain(gc, offset)) {
106 dev_err(gc->parent, "GPO3 works only as open drain\n");
107 return -EINVAL;
108 }
109
110 /* Disable sequencer for GPO3 */
111 ret = tps65218_clear_bits(tps65218, TPS65218_REG_SEQ7,
112 TPS65218_SEQ7_GPO3_SEQ_MASK,
113 TPS65218_PROTECT_L1);
114 if (ret)
115 return ret;
116
117 /* Setup GPO3 */
118 ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG2,
119 TPS65218_CONFIG2_DC12_RST,
120 TPS65218_PROTECT_L1);
121 if (ret)
122 return ret;
123
124 break;
125 default:
126 return -EINVAL;
127 }
128
129 return 0;
130 }
131
tps65218_gpio_set_config(struct gpio_chip * gc,unsigned offset,unsigned long config)132 static int tps65218_gpio_set_config(struct gpio_chip *gc, unsigned offset,
133 unsigned long config)
134 {
135 struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
136 struct tps65218 *tps65218 = tps65218_gpio->tps65218;
137 enum pin_config_param param = pinconf_to_config_param(config);
138
139 switch (offset) {
140 case 0:
141 case 2:
142 /* GPO1 is hardwired to be open drain */
143 if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
144 return 0;
145 return -ENOTSUPP;
146 case 1:
147 /* GPO2 is push-pull by default, can be set as open drain. */
148 if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
149 return tps65218_clear_bits(tps65218,
150 TPS65218_REG_CONFIG1,
151 TPS65218_CONFIG1_GPO2_BUF,
152 TPS65218_PROTECT_L1);
153 if (param == PIN_CONFIG_DRIVE_PUSH_PULL)
154 return tps65218_set_bits(tps65218,
155 TPS65218_REG_CONFIG1,
156 TPS65218_CONFIG1_GPO2_BUF,
157 TPS65218_CONFIG1_GPO2_BUF,
158 TPS65218_PROTECT_L1);
159 return -ENOTSUPP;
160 default:
161 break;
162 }
163 return -ENOTSUPP;
164 }
165
166 static const struct gpio_chip template_chip = {
167 .label = "gpio-tps65218",
168 .owner = THIS_MODULE,
169 .request = tps65218_gpio_request,
170 .direction_output = tps65218_gpio_output,
171 .get = tps65218_gpio_get,
172 .set = tps65218_gpio_set,
173 .set_config = tps65218_gpio_set_config,
174 .can_sleep = true,
175 .ngpio = 3,
176 .base = -1,
177 };
178
tps65218_gpio_probe(struct platform_device * pdev)179 static int tps65218_gpio_probe(struct platform_device *pdev)
180 {
181 struct tps65218 *tps65218 = dev_get_drvdata(pdev->dev.parent);
182 struct tps65218_gpio *tps65218_gpio;
183
184 tps65218_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65218_gpio),
185 GFP_KERNEL);
186 if (!tps65218_gpio)
187 return -ENOMEM;
188
189 tps65218_gpio->tps65218 = tps65218;
190 tps65218_gpio->gpio_chip = template_chip;
191 tps65218_gpio->gpio_chip.parent = &pdev->dev;
192
193 return devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip,
194 tps65218_gpio);
195 }
196
197 static const struct of_device_id tps65218_dt_match[] = {
198 { .compatible = "ti,tps65218-gpio" },
199 { }
200 };
201 MODULE_DEVICE_TABLE(of, tps65218_dt_match);
202
203 static const struct platform_device_id tps65218_gpio_id_table[] = {
204 { "tps65218-gpio", },
205 { /* sentinel */ }
206 };
207 MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
208
209 static struct platform_driver tps65218_gpio_driver = {
210 .driver = {
211 .name = "tps65218-gpio",
212 .of_match_table = tps65218_dt_match,
213 },
214 .probe = tps65218_gpio_probe,
215 .id_table = tps65218_gpio_id_table,
216 };
217
218 module_platform_driver(tps65218_gpio_driver);
219
220 MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>");
221 MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs");
222 MODULE_LICENSE("GPL v2");
223