Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpio/gpio-bd72720.c
121797 views
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 <[email protected]>
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
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
100
static 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
110
static 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
131
static 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
164
static 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
175
static 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 */
225
static 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
238
static 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
260
return devm_gpiochip_add_data(dev, &g->chip, g);
261
}
262
263
static const struct platform_device_id bd72720_gpio_id[] = {
264
{ "bd72720-gpio" },
265
{ },
266
};
267
MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
268
269
static struct platform_driver gpo_bd72720_driver = {
270
.driver = {
271
.name = "bd72720-gpio",
272
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
273
},
274
.probe = gpo_bd72720_probe,
275
.id_table = bd72720_gpio_id,
276
};
277
module_platform_driver(gpo_bd72720_driver);
278
279
MODULE_AUTHOR("Matti Vaittinen <[email protected]>");
280
MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
281
MODULE_LICENSE("GPL");
282
283