xref: /linux/drivers/gpio/gpio-bd72720.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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 
47 enum bd72720_gpio_state {
48 	BD72720_PIN_UNKNOWN,
49 	BD72720_PIN_GPI,
50 	BD72720_PIN_GPO,
51 };
52 
53 enum {
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 
63 struct 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 
72 static 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 
85 static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
86 			  unsigned int offset)
87 {
88 	static const int regs[] = {
89 		BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
90 		BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
91 		BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL
92 	};
93 	int ret, val;
94 
95 	ret = regmap_read(bdgpio->regmap, regs[offset], &val);
96 	if (ret)
97 		return ret;
98 
99 	return val & BD72720_GPIO_HIGH;
100 }
101 
102 static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
103 {
104 	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
105 
106 	if (BIT(offset) & bdgpio->gpio_is_input)
107 		return bd72720gpi_get(bdgpio, offset);
108 
109 	return bd72720gpo_get(bdgpio, offset);
110 }
111 
112 static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
113 			  int value)
114 {
115 	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
116 	static const int regs[] = {
117 		BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
118 		BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
119 		BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL
120 	};
121 
122 	if (BIT(offset) & bdgpio->gpio_is_input) {
123 		dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
124 		return -EINVAL;
125 	}
126 
127 	if (value)
128 		return regmap_set_bits(bdgpio->regmap, regs[offset],
129 				      BD72720_GPIO_HIGH);
130 
131 	return regmap_clear_bits(bdgpio->regmap, regs[offset],
132 					BD72720_GPIO_HIGH);
133 }
134 
135 static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
136 				   unsigned long config)
137 {
138 	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
139 	static const int regs[] = {
140 		BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
141 		BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
142 		BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL
143 	};
144 
145 	/*
146 	 * We can only set the output mode, which makes sense only when output
147 	 * OTP configuration is used.
148 	 */
149 	if (BIT(offset) & bdgpio->gpio_is_input)
150 		return -ENOTSUPP;
151 
152 	switch (pinconf_to_config_param(config)) {
153 	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
154 		return regmap_update_bits(bdgpio->regmap,
155 					  regs[offset],
156 					  BD72720_GPIO_DRIVE_MASK,
157 					  BD72720_GPIO_OPEN_DRAIN);
158 	case PIN_CONFIG_DRIVE_PUSH_PULL:
159 		return regmap_update_bits(bdgpio->regmap,
160 					  regs[offset],
161 					  BD72720_GPIO_DRIVE_MASK,
162 					  BD72720_GPIO_CMOS);
163 	default:
164 		break;
165 	}
166 
167 	return -ENOTSUPP;
168 }
169 
170 static int bd72720gpo_direction_get(struct gpio_chip *chip,
171 				    unsigned int offset)
172 {
173 	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
174 
175 	if (BIT(offset) & bdgpio->gpio_is_input)
176 		return GPIO_LINE_DIRECTION_IN;
177 
178 	return GPIO_LINE_DIRECTION_OUT;
179 }
180 
181 static int bd72720_valid_mask(struct gpio_chip *gc,
182 			      unsigned long *valid_mask,
183 			      unsigned int ngpios)
184 {
185 	static const char * const properties[] = {
186 		"rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
187 		"rohm,pin-exten1", "rohm,pin-fault_b"
188 	};
189 	struct bd72720_gpio *g = gpiochip_get_data(gc);
190 	const char *val;
191 	int i, ret;
192 
193 	*valid_mask = BIT(BD72720_GPIO_EPDEN);
194 
195 	if (!gc->parent)
196 		return 0;
197 
198 	for (i = 0; i < ARRAY_SIZE(properties); i++) {
199 		ret = fwnode_property_read_string(dev_fwnode(gc->parent),
200 						  properties[i], &val);
201 
202 		if (ret) {
203 			if (ret == -EINVAL)
204 				continue;
205 
206 			dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
207 				properties[i]);
208 
209 			return ret;
210 		}
211 
212 		if (strcmp(val, "gpi") == 0) {
213 			if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
214 				dev_warn(g->dev,
215 					 "pin %d (%s) does not support INPUT mode",
216 					 i, properties[i]);
217 				continue;
218 			}
219 
220 			*valid_mask |= BIT(i);
221 			g->gpio_is_input |= BIT(i);
222 		} else if (strcmp(val, "gpo") == 0) {
223 			*valid_mask |= BIT(i);
224 		}
225 	}
226 
227 	return 0;
228 }
229 
230 /* Template for GPIO chip */
231 static const struct gpio_chip bd72720gpo_chip = {
232 	.label			= "bd72720",
233 	.owner			= THIS_MODULE,
234 	.get			= bd72720gpio_get,
235 	.get_direction		= bd72720gpo_direction_get,
236 	.set			= bd72720gpo_set,
237 	.set_config		= bd72720_gpio_set_config,
238 	.init_valid_mask	= bd72720_valid_mask,
239 	.can_sleep		= true,
240 	.ngpio			= BD72720_NUM_GPIOS,
241 	.base			= -1,
242 };
243 
244 static int gpo_bd72720_probe(struct platform_device *pdev)
245 {
246 	struct bd72720_gpio *g;
247 	struct device *parent, *dev;
248 
249 	/*
250 	 * Bind devm lifetime to this platform device => use dev for devm.
251 	 * also the prints should originate from this device.
252 	 */
253 	dev = &pdev->dev;
254 	/* The device-tree and regmap come from MFD => use parent for that */
255 	parent = dev->parent;
256 
257 	g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
258 	if (!g)
259 		return -ENOMEM;
260 
261 	g->chip = bd72720gpo_chip;
262 	g->dev = dev;
263 	g->chip.parent = parent;
264 	g->regmap = dev_get_regmap(parent, NULL);
265 	if (!g->regmap)
266 		return -ENODEV;
267 
268 	return devm_gpiochip_add_data(dev, &g->chip, g);
269 }
270 
271 static const struct platform_device_id bd72720_gpio_id[] = {
272 	{ .name = "bd72720-gpio" },
273 	{ }
274 };
275 MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
276 
277 static struct platform_driver gpo_bd72720_driver = {
278 	.driver = {
279 		.name = "bd72720-gpio",
280 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
281 	},
282 	.probe = gpo_bd72720_probe,
283 	.id_table = bd72720_gpio_id,
284 };
285 module_platform_driver(gpo_bd72720_driver);
286 
287 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
288 MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
289 MODULE_LICENSE("GPL");
290