summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatti Vaittinen <matti.vaittinen@fi.rohmeurope.com>2019-06-03 03:26:45 -0400
committerLee Jones <lee.jones@linaro.org>2019-06-27 05:57:24 -0400
commit18bc64b3aebfa693f34463d2bcad9c82e21af9f6 (patch)
treed420b69d6d846fd32821e3e0cdc5148732724eac
parent478bb8f32e26c2497c1c594f547ecbfec9c55b98 (diff)
gpio: Initial support for ROHM bd70528 GPIO block
ROHM BD70528 PMIC has 4 GPIO pins. Allow them to be controlled by GPIO framework. IRQs are handled by regmap-irq and GPIO driver is not aware of the irq usage. Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--drivers/gpio/Kconfig11
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-bd70528.c232
3 files changed, 244 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8023d03ec362..87dbbd03910d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -977,6 +977,17 @@ config GPIO_ARIZONA
977 help 977 help
978 Support for GPIOs on Wolfson Arizona class devices. 978 Support for GPIOs on Wolfson Arizona class devices.
979 979
980config GPIO_BD70528
981 tristate "ROHM BD70528 GPIO support"
982 depends on MFD_ROHM_BD70528
983 help
984 Support for GPIOs on ROHM BD70528 PMIC. There are four GPIOs
985 available on the ROHM PMIC in total. The GPIOs can also
986 generate interrupts.
987
988 This driver can also be built as a module. If so, the module
989 will be called gpio-bd70528.
990
980config GPIO_BD9571MWV 991config GPIO_BD9571MWV
981 tristate "ROHM BD9571 GPIO support" 992 tristate "ROHM BD9571 GPIO support"
982 depends on MFD_BD9571MWV 993 depends on MFD_BD9571MWV
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 6700eee860b7..10efc4f743fe 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
35obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o 35obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
36obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o 36obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
37obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o 37obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
38obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
38obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o 39obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
39obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o 40obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
40obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o 41obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c
new file mode 100644
index 000000000000..fd85605d2dab
--- /dev/null
+++ b/drivers/gpio/gpio-bd70528.c
@@ -0,0 +1,232 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2018 ROHM Semiconductors
3// gpio-bd70528.c ROHM BD70528MWV gpio driver
4
5#include <linux/gpio/driver.h>
6#include <linux/mfd/rohm-bd70528.h>
7#include <linux/module.h>
8#include <linux/platform_device.h>
9#include <linux/regmap.h>
10
11#define GPIO_IN_REG(offset) (BD70528_REG_GPIO1_IN + (offset) * 2)
12#define GPIO_OUT_REG(offset) (BD70528_REG_GPIO1_OUT + (offset) * 2)
13
14struct bd70528_gpio {
15 struct rohm_regmap_dev chip;
16 struct gpio_chip gpio;
17};
18
19static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
20 unsigned int offset, unsigned int debounce)
21{
22 u8 val;
23
24 switch (debounce) {
25 case 0:
26 val = BD70528_DEBOUNCE_DISABLE;
27 break;
28 case 1 ... 15:
29 val = BD70528_DEBOUNCE_15MS;
30 break;
31 case 16 ... 30:
32 val = BD70528_DEBOUNCE_30MS;
33 break;
34 case 31 ... 50:
35 val = BD70528_DEBOUNCE_50MS;
36 break;
37 default:
38 dev_err(bdgpio->chip.dev,
39 "Invalid debouce value %u\n", debounce);
40 return -EINVAL;
41 }
42 return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
43 BD70528_DEBOUNCE_MASK, val);
44}
45
46static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset)
47{
48 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
49 int val, ret;
50
51 /* Do we need to do something to IRQs here? */
52 ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
53 if (ret) {
54 dev_err(bdgpio->chip.dev, "Could not read gpio direction\n");
55 return ret;
56 }
57
58 return !(val & BD70528_GPIO_OUT_EN_MASK);
59}
60
61static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
62 unsigned long config)
63{
64 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
65
66 switch (pinconf_to_config_param(config)) {
67 case PIN_CONFIG_DRIVE_OPEN_DRAIN:
68 return regmap_update_bits(bdgpio->chip.regmap,
69 GPIO_OUT_REG(offset),
70 BD70528_GPIO_DRIVE_MASK,
71 BD70528_GPIO_OPEN_DRAIN);
72 break;
73 case PIN_CONFIG_DRIVE_PUSH_PULL:
74 return regmap_update_bits(bdgpio->chip.regmap,
75 GPIO_OUT_REG(offset),
76 BD70528_GPIO_DRIVE_MASK,
77 BD70528_GPIO_PUSH_PULL);
78 break;
79 case PIN_CONFIG_INPUT_DEBOUNCE:
80 return bd70528_set_debounce(bdgpio, offset,
81 pinconf_to_config_argument(config));
82 break;
83 default:
84 break;
85 }
86 return -ENOTSUPP;
87}
88
89static int bd70528_direction_input(struct gpio_chip *chip, unsigned int offset)
90{
91 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
92
93 /* Do we need to do something to IRQs here? */
94 return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
95 BD70528_GPIO_OUT_EN_MASK,
96 BD70528_GPIO_OUT_DISABLE);
97}
98
99static void bd70528_gpio_set(struct gpio_chip *chip, unsigned int offset,
100 int value)
101{
102 int ret;
103 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
104 u8 val = (value) ? BD70528_GPIO_OUT_HI : BD70528_GPIO_OUT_LO;
105
106 ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
107 BD70528_GPIO_OUT_MASK, val);
108 if (ret)
109 dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value);
110}
111
112static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset,
113 int value)
114{
115 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
116
117 bd70528_gpio_set(chip, offset, value);
118 return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
119 BD70528_GPIO_OUT_EN_MASK,
120 BD70528_GPIO_OUT_ENABLE);
121}
122
123#define GPIO_IN_STATE_MASK(offset) (BD70528_GPIO_IN_STATE_BASE << (offset))
124
125static int bd70528_gpio_get_o(struct bd70528_gpio *bdgpio, unsigned int offset)
126{
127 int ret;
128 unsigned int val;
129
130 ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val);
131 if (!ret)
132 ret = !!(val & BD70528_GPIO_OUT_MASK);
133 else
134 dev_err(bdgpio->chip.dev, "GPIO (out) state read failed\n");
135
136 return ret;
137}
138
139static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
140{
141 unsigned int val;
142 int ret;
143
144 ret = regmap_read(bdgpio->chip.regmap, BD70528_REG_GPIO_STATE, &val);
145
146 if (!ret)
147 ret = !(val & GPIO_IN_STATE_MASK(offset));
148 else
149 dev_err(bdgpio->chip.dev, "GPIO (in) state read failed\n");
150
151 return ret;
152}
153
154static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
155{
156 int ret = -EINVAL;
157 struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
158
159 /*
160 * There is a race condition where someone might be changing the
161 * GPIO direction after we get it but before we read the value. But
162 * application design where GPIO direction may be changed just when
163 * we read GPIO value would be pointless as reader could not know
164 * whether the returned high/low state is caused by input or output.
165 * Or then there must be other ways to mitigate the issue. Thus
166 * locking would make no sense.
167 */
168 ret = bd70528_get_direction(chip, offset);
169 if (ret == 0)
170 ret = bd70528_gpio_get_o(bdgpio, offset);
171 else if (ret == 1)
172 ret = bd70528_gpio_get_i(bdgpio, offset);
173 else
174 dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n");
175
176 return ret;
177}
178
179static int bd70528_probe(struct platform_device *pdev)
180{
181 struct bd70528_gpio *bdgpio;
182 struct rohm_regmap_dev *bd70528;
183 int ret;
184
185 bd70528 = dev_get_drvdata(pdev->dev.parent);
186 if (!bd70528) {
187 dev_err(&pdev->dev, "No MFD driver data\n");
188 return -EINVAL;
189 }
190
191 bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio),
192 GFP_KERNEL);
193 if (!bdgpio)
194 return -ENOMEM;
195 bdgpio->chip.dev = &pdev->dev;
196 bdgpio->gpio.parent = pdev->dev.parent;
197 bdgpio->gpio.label = "bd70528-gpio";
198 bdgpio->gpio.owner = THIS_MODULE;
199 bdgpio->gpio.get_direction = bd70528_get_direction;
200 bdgpio->gpio.direction_input = bd70528_direction_input;
201 bdgpio->gpio.direction_output = bd70528_direction_output;
202 bdgpio->gpio.set_config = bd70528_gpio_set_config;
203 bdgpio->gpio.can_sleep = true;
204 bdgpio->gpio.get = bd70528_gpio_get;
205 bdgpio->gpio.set = bd70528_gpio_set;
206 bdgpio->gpio.ngpio = 4;
207 bdgpio->gpio.base = -1;
208#ifdef CONFIG_OF_GPIO
209 bdgpio->gpio.of_node = pdev->dev.parent->of_node;
210#endif
211 bdgpio->chip.regmap = bd70528->regmap;
212
213 ret = devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio,
214 bdgpio);
215 if (ret)
216 dev_err(&pdev->dev, "gpio_init: Failed to add bd70528-gpio\n");
217
218 return ret;
219}
220
221static struct platform_driver bd70528_gpio = {
222 .driver = {
223 .name = "bd70528-gpio"
224 },
225 .probe = bd70528_probe,
226};
227
228module_platform_driver(bd70528_gpio);
229
230MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
231MODULE_DESCRIPTION("BD70528 voltage regulator driver");
232MODULE_LICENSE("GPL");