Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Support to GPIOs on ROHM BD72720 and BD79300
4 * Copyright 2025 ROHM Semiconductors.
5 * Author: Matti Vaittinen <mazziesaccount@gmail.com>
6 */
7
8#include <linux/gpio/driver.h>
9#include <linux/init.h>
10#include <linux/irq.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/platform_device.h>
14#include <linux/mfd/rohm-bd72720.h>
15
16#define BD72720_GPIO_OPEN_DRAIN 0
17#define BD72720_GPIO_CMOS BIT(1)
18#define BD72720_INT_GPIO1_IN_SRC 4
19/*
20 * The BD72720 has several "one time programmable" (OTP) configurations which
21 * can be set at manufacturing phase. A set of these options allow using pins
22 * as GPIO. The OTP configuration can't be read at run-time, so drivers rely on
23 * device-tree to advertise the correct options.
24 *
25 * Both DVS[0,1] pins can be configured to be used for:
26 * - OTP0: regulator RUN state control
27 * - OTP1: GPI
28 * - OTP2: GPO
29 * - OTP3: Power sequencer output
30 * Data-sheet also states that these PINs can always be used for IRQ but the
31 * driver limits this by allowing them to be used for IRQs with OTP1 only.
32 *
33 * Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP
34 * options for a specific (non GPIO) purposes, but also an option to configure
35 * them to be used as a GPO.
36 *
37 * OTP settings can be separately configured for each pin.
38 *
39 * DT properties:
40 * "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values:
41 * "dvs-input", "gpi", "gpo".
42 *
43 * "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to:
44 * "gpo"
45 */
46
47enum bd72720_gpio_state {
48 BD72720_PIN_UNKNOWN,
49 BD72720_PIN_GPI,
50 BD72720_PIN_GPO,
51};
52
53enum {
54 BD72720_GPIO1,
55 BD72720_GPIO2,
56 BD72720_GPIO3,
57 BD72720_GPIO4,
58 BD72720_GPIO5,
59 BD72720_GPIO_EPDEN,
60 BD72720_NUM_GPIOS
61};
62
63struct bd72720_gpio {
64 /* chip.parent points the MFD which provides DT node and regmap */
65 struct gpio_chip chip;
66 /* dev points to the platform device for devm and prints */
67 struct device *dev;
68 struct regmap *regmap;
69 int gpio_is_input;
70};
71
72static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset)
73{
74 int ret, val, shift;
75
76 ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val);
77 if (ret)
78 return ret;
79
80 shift = BD72720_INT_GPIO1_IN_SRC + reg_offset;
81
82 return (val >> shift) & 1;
83}
84
85static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
86 unsigned int offset)
87{
88 const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
89 BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
90 BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
91 int ret, val;
92
93 ret = regmap_read(bdgpio->regmap, regs[offset], &val);
94 if (ret)
95 return ret;
96
97 return val & BD72720_GPIO_HIGH;
98}
99
100static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
101{
102 struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
103
104 if (BIT(offset) & bdgpio->gpio_is_input)
105 return bd72720gpi_get(bdgpio, offset);
106
107 return bd72720gpo_get(bdgpio, offset);
108}
109
110static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
111 int value)
112{
113 struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
114 const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
115 BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
116 BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
117
118 if (BIT(offset) & bdgpio->gpio_is_input) {
119 dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
120 return -EINVAL;
121 }
122
123 if (value)
124 return regmap_set_bits(bdgpio->regmap, regs[offset],
125 BD72720_GPIO_HIGH);
126
127 return regmap_clear_bits(bdgpio->regmap, regs[offset],
128 BD72720_GPIO_HIGH);
129}
130
131static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
132 unsigned long config)
133{
134 struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
135 const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
136 BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
137 BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
138
139 /*
140 * We can only set the output mode, which makes sense only when output
141 * OTP configuration is used.
142 */
143 if (BIT(offset) & bdgpio->gpio_is_input)
144 return -ENOTSUPP;
145
146 switch (pinconf_to_config_param(config)) {
147 case PIN_CONFIG_DRIVE_OPEN_DRAIN:
148 return regmap_update_bits(bdgpio->regmap,
149 regs[offset],
150 BD72720_GPIO_DRIVE_MASK,
151 BD72720_GPIO_OPEN_DRAIN);
152 case PIN_CONFIG_DRIVE_PUSH_PULL:
153 return regmap_update_bits(bdgpio->regmap,
154 regs[offset],
155 BD72720_GPIO_DRIVE_MASK,
156 BD72720_GPIO_CMOS);
157 default:
158 break;
159 }
160
161 return -ENOTSUPP;
162}
163
164static int bd72720gpo_direction_get(struct gpio_chip *chip,
165 unsigned int offset)
166{
167 struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
168
169 if (BIT(offset) & bdgpio->gpio_is_input)
170 return GPIO_LINE_DIRECTION_IN;
171
172 return GPIO_LINE_DIRECTION_OUT;
173}
174
175static int bd72720_valid_mask(struct gpio_chip *gc,
176 unsigned long *valid_mask,
177 unsigned int ngpios)
178{
179 static const char * const properties[] = {
180 "rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
181 "rohm,pin-exten1", "rohm,pin-fault_b"
182 };
183 struct bd72720_gpio *g = gpiochip_get_data(gc);
184 const char *val;
185 int i, ret;
186
187 *valid_mask = BIT(BD72720_GPIO_EPDEN);
188
189 if (!gc->parent)
190 return 0;
191
192 for (i = 0; i < ARRAY_SIZE(properties); i++) {
193 ret = fwnode_property_read_string(dev_fwnode(gc->parent),
194 properties[i], &val);
195
196 if (ret) {
197 if (ret == -EINVAL)
198 continue;
199
200 dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
201 properties[i]);
202
203 return ret;
204 }
205
206 if (strcmp(val, "gpi") == 0) {
207 if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
208 dev_warn(g->dev,
209 "pin %d (%s) does not support INPUT mode",
210 i, properties[i]);
211 continue;
212 }
213
214 *valid_mask |= BIT(i);
215 g->gpio_is_input |= BIT(i);
216 } else if (strcmp(val, "gpo") == 0) {
217 *valid_mask |= BIT(i);
218 }
219 }
220
221 return 0;
222}
223
224/* Template for GPIO chip */
225static const struct gpio_chip bd72720gpo_chip = {
226 .label = "bd72720",
227 .owner = THIS_MODULE,
228 .get = bd72720gpio_get,
229 .get_direction = bd72720gpo_direction_get,
230 .set = bd72720gpo_set,
231 .set_config = bd72720_gpio_set_config,
232 .init_valid_mask = bd72720_valid_mask,
233 .can_sleep = true,
234 .ngpio = BD72720_NUM_GPIOS,
235 .base = -1,
236};
237
238static int gpo_bd72720_probe(struct platform_device *pdev)
239{
240 struct bd72720_gpio *g;
241 struct device *parent, *dev;
242
243 /*
244 * Bind devm lifetime to this platform device => use dev for devm.
245 * also the prints should originate from this device.
246 */
247 dev = &pdev->dev;
248 /* The device-tree and regmap come from MFD => use parent for that */
249 parent = dev->parent;
250
251 g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
252 if (!g)
253 return -ENOMEM;
254
255 g->chip = bd72720gpo_chip;
256 g->dev = dev;
257 g->chip.parent = parent;
258 g->regmap = dev_get_regmap(parent, NULL);
259 if (!g->regmap)
260 return -ENODEV;
261
262 return devm_gpiochip_add_data(dev, &g->chip, g);
263}
264
265static const struct platform_device_id bd72720_gpio_id[] = {
266 { "bd72720-gpio" },
267 { },
268};
269MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
270
271static struct platform_driver gpo_bd72720_driver = {
272 .driver = {
273 .name = "bd72720-gpio",
274 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
275 },
276 .probe = gpo_bd72720_probe,
277 .id_table = bd72720_gpio_id,
278};
279module_platform_driver(gpo_bd72720_driver);
280
281MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
282MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
283MODULE_LICENSE("GPL");