blob: fa3d78858a9e0f615021509f26ca0e75a31a1693 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Beniamino Galvani677b5352016-08-16 11:49:49 +02002/*
3 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
Beniamino Galvani677b5352016-08-16 11:49:49 +02004 */
5
6#include <common.h>
Simon Glass9d922452017-05-17 17:18:03 -06007#include <dm.h>
Beniamino Galvani2009a8d2017-07-10 00:30:04 +02008#include <dm/device-internal.h>
9#include <dm/lists.h>
Beniamino Galvani677b5352016-08-16 11:49:49 +020010#include <dm/pinctrl.h>
11#include <fdt_support.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/sizes.h>
Beniamino Galvani2009a8d2017-07-10 00:30:04 +020015#include <asm/gpio.h>
Beniamino Galvani677b5352016-08-16 11:49:49 +020016
17#include "pinctrl-meson.h"
18
19DECLARE_GLOBAL_DATA_PTR;
20
21static const char *meson_pinctrl_dummy_name = "_dummy";
22
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +020023int meson_pinctrl_get_groups_count(struct udevice *dev)
Beniamino Galvani677b5352016-08-16 11:49:49 +020024{
25 struct meson_pinctrl *priv = dev_get_priv(dev);
26
27 return priv->data->num_groups;
28}
29
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +020030const char *meson_pinctrl_get_group_name(struct udevice *dev,
31 unsigned int selector)
Beniamino Galvani677b5352016-08-16 11:49:49 +020032{
33 struct meson_pinctrl *priv = dev_get_priv(dev);
34
35 if (!priv->data->groups[selector].name)
36 return meson_pinctrl_dummy_name;
37
38 return priv->data->groups[selector].name;
39}
40
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +020041int meson_pinmux_get_functions_count(struct udevice *dev)
Beniamino Galvani677b5352016-08-16 11:49:49 +020042{
43 struct meson_pinctrl *priv = dev_get_priv(dev);
44
45 return priv->data->num_funcs;
46}
47
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +020048const char *meson_pinmux_get_function_name(struct udevice *dev,
49 unsigned int selector)
Beniamino Galvani677b5352016-08-16 11:49:49 +020050{
51 struct meson_pinctrl *priv = dev_get_priv(dev);
52
53 return priv->data->funcs[selector].name;
54}
55
Beniamino Galvani2009a8d2017-07-10 00:30:04 +020056static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
57 enum meson_reg_type reg_type,
58 unsigned int *reg, unsigned int *bit)
59{
Jerome Brunetc4c726c2019-01-04 15:44:34 +010060 struct meson_pinctrl *priv = dev_get_priv(dev);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +020061 struct meson_bank *bank = NULL;
62 struct meson_reg_desc *desc;
63 unsigned int pin;
64 int i;
65
66 pin = priv->data->pin_base + offset;
67
68 for (i = 0; i < priv->data->num_banks; i++) {
69 if (pin >= priv->data->banks[i].first &&
70 pin <= priv->data->banks[i].last) {
71 bank = &priv->data->banks[i];
72 break;
73 }
74 }
75
76 if (!bank)
77 return -EINVAL;
78
79 desc = &bank->regs[reg_type];
80 *reg = desc->reg * 4;
81 *bit = desc->bit + pin - bank->first;
82
83 return 0;
84}
85
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +020086int meson_gpio_get(struct udevice *dev, unsigned int offset)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +020087{
88 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
89 unsigned int reg, bit;
90 int ret;
91
Jerome Brunetc4c726c2019-01-04 15:44:34 +010092 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, &reg,
93 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +020094 if (ret)
95 return ret;
96
97 return !!(readl(priv->reg_gpio + reg) & BIT(bit));
98}
99
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200100int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200101{
102 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
103 unsigned int reg, bit;
104 int ret;
105
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100106 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
107 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200108 if (ret)
109 return ret;
110
111 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
112
113 return 0;
114}
115
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200116int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200117{
118 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
119 unsigned int reg, bit, val;
120 int ret;
121
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100122 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
123 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200124 if (ret)
125 return ret;
126
127 val = readl(priv->reg_gpio + reg);
128
129 return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
130}
131
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200132int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200133{
134 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
135 unsigned int reg, bit;
136 int ret;
137
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100138 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
139 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200140 if (ret)
141 return ret;
142
Carlo Caionefb19c7b2018-12-03 18:00:42 +0000143 setbits_le32(priv->reg_gpio + reg, BIT(bit));
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200144
145 return 0;
146}
147
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200148int meson_gpio_direction_output(struct udevice *dev,
149 unsigned int offset, int value)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200150{
151 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
152 unsigned int reg, bit;
153 int ret;
154
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100155 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
156 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200157 if (ret)
158 return ret;
159
Carlo Caionefb19c7b2018-12-03 18:00:42 +0000160 clrbits_le32(priv->reg_gpio + reg, BIT(bit));
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200161
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100162 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
163 &bit);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200164 if (ret)
165 return ret;
166
167 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
168
169 return 0;
170}
171
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100172static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin,
173 unsigned int param)
174{
175 struct meson_pinctrl *priv = dev_get_priv(dev);
176 unsigned int offset = pin - priv->data->pin_base;
177 unsigned int reg, bit;
178 int ret;
179
180 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, &reg, &bit);
181 if (ret)
182 return ret;
183
184 if (param == PIN_CONFIG_BIAS_DISABLE) {
185 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0);
186 return 0;
187 }
188
189 /* othewise, enable the bias and select level */
190 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 1);
191 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, &reg, &bit);
192 if (ret)
193 return ret;
194
195 clrsetbits_le32(priv->reg_pull + reg, BIT(bit),
196 param == PIN_CONFIG_BIAS_PULL_UP);
197
198 return 0;
199}
200
201int meson_pinconf_set(struct udevice *dev, unsigned int pin,
202 unsigned int param, unsigned int arg)
203{
204 int ret;
205
206 switch (param) {
207 case PIN_CONFIG_BIAS_DISABLE:
208 case PIN_CONFIG_BIAS_PULL_UP:
209 case PIN_CONFIG_BIAS_PULL_DOWN:
210 ret = meson_pinconf_bias_set(dev, pin, param);
211 break;
212
213 default:
214 dev_err(dev, "unsupported configuration parameter %u\n", param);
215 return -EINVAL;
216 }
217
218 return ret;
219}
220
221int meson_pinconf_group_set(struct udevice *dev,
222 unsigned int group_selector,
223 unsigned int param, unsigned int arg)
224{
225 struct meson_pinctrl *priv = dev_get_priv(dev);
226 struct meson_pmx_group *grp = &priv->data->groups[group_selector];
227 int i, ret;
228
229 for (i = 0; i < grp->num_pins; i++) {
230 ret = meson_pinconf_set(dev, grp->pins[i], param, arg);
231 if (ret)
232 return ret;
233 }
234
235 return 0;
236}
237
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200238int meson_gpio_probe(struct udevice *dev)
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200239{
240 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
241 struct gpio_dev_priv *uc_priv;
242
243 uc_priv = dev_get_uclass_priv(dev);
244 uc_priv->bank_name = priv->data->name;
245 uc_priv->gpio_count = priv->data->num_pins;
246
247 return 0;
248}
249
Beniamino Galvani677b5352016-08-16 11:49:49 +0200250static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
251{
252 int index, len = 0;
253 const fdt32_t *reg;
254
Simon Glassb02e4042016-10-02 17:59:28 -0600255 index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
Beniamino Galvani677b5352016-08-16 11:49:49 +0200256 if (index < 0)
257 return FDT_ADDR_T_NONE;
258
259 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
260 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
261 return FDT_ADDR_T_NONE;
262
263 reg += index * (na + ns);
264
265 return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
266}
267
268int meson_pinctrl_probe(struct udevice *dev)
269{
270 struct meson_pinctrl *priv = dev_get_priv(dev);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200271 struct uclass_driver *drv;
272 struct udevice *gpio_dev;
Beniamino Galvani677b5352016-08-16 11:49:49 +0200273 fdt_addr_t addr;
274 int node, gpio = -1, len;
275 int na, ns;
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200276 char *name;
Beniamino Galvani677b5352016-08-16 11:49:49 +0200277
Simon Glasse160f7d2017-01-17 16:52:55 -0700278 na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani677b5352016-08-16 11:49:49 +0200279 if (na < 1) {
280 debug("bad #address-cells\n");
281 return -EINVAL;
282 }
283
Simon Glasse160f7d2017-01-17 16:52:55 -0700284 ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani677b5352016-08-16 11:49:49 +0200285 if (ns < 1) {
286 debug("bad #size-cells\n");
287 return -EINVAL;
288 }
289
Simon Glasse160f7d2017-01-17 16:52:55 -0700290 fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
Beniamino Galvani677b5352016-08-16 11:49:49 +0200291 if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
292 gpio = node;
293 break;
294 }
295 }
296
297 if (!gpio) {
298 debug("gpio node not found\n");
299 return -EINVAL;
300 }
301
302 addr = parse_address(gpio, "mux", na, ns);
303 if (addr == FDT_ADDR_T_NONE) {
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200304 debug("mux address not found\n");
Beniamino Galvani677b5352016-08-16 11:49:49 +0200305 return -EINVAL;
306 }
Beniamino Galvani677b5352016-08-16 11:49:49 +0200307 priv->reg_mux = (void __iomem *)addr;
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200308
309 addr = parse_address(gpio, "gpio", na, ns);
310 if (addr == FDT_ADDR_T_NONE) {
311 debug("gpio address not found\n");
312 return -EINVAL;
313 }
314 priv->reg_gpio = (void __iomem *)addr;
Jerome Brunetc4c726c2019-01-04 15:44:34 +0100315
316 addr = parse_address(gpio, "pull", na, ns);
317 if (addr == FDT_ADDR_T_NONE) {
318 debug("pull address not found\n");
319 return -EINVAL;
320 }
321 priv->reg_pull = (void __iomem *)addr;
322
323 addr = parse_address(gpio, "pull-enable", na, ns);
324 /* Use pull region if pull-enable one is not present */
325 if (addr == FDT_ADDR_T_NONE)
326 priv->reg_pullen = priv->reg_pull;
327 else
328 priv->reg_pullen = (void __iomem *)addr;
329
Beniamino Galvani677b5352016-08-16 11:49:49 +0200330 priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
331
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200332 /* Lookup GPIO driver */
333 drv = lists_uclass_lookup(UCLASS_GPIO);
334 if (!drv) {
335 puts("Cannot find GPIO driver\n");
336 return -ENOENT;
337 }
338
339 name = calloc(1, 32);
340 sprintf(name, "meson-gpio");
341
342 /* Create child device UCLASS_GPIO and bind it */
Jerome Brunet7c9dcfe2018-10-05 09:35:26 +0200343 device_bind(dev, priv->data->gpio_driver, name, NULL, gpio, &gpio_dev);
Beniamino Galvani2009a8d2017-07-10 00:30:04 +0200344 dev_set_of_offset(gpio_dev, gpio);
345
Beniamino Galvani677b5352016-08-16 11:49:49 +0200346 return 0;
347}