blob: e434a38f1fec573fc6b5c82d1eca03257f318a57 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Wenyou Yangac72e172016-07-20 17:16:27 +08002/*
3 * Atmel PIO4 pinctrl driver
4 *
5 * Copyright (C) 2016 Atmel Corporation
6 * Wenyou.Yang <wenyou.yang@atmel.com>
Wenyou Yangac72e172016-07-20 17:16:27 +08007 */
8
9#include <common.h>
Simon Glass9d922452017-05-17 17:18:03 -060010#include <dm.h>
Simon Glass401d1c42020-10-30 21:38:53 -060011#include <asm/global_data.h>
Sergiu Moga2ed96a82022-09-01 17:22:41 +030012#include <dm/device-internal.h>
13#include <dm/lists.h>
Wenyou Yangac72e172016-07-20 17:16:27 +080014#include <dm/pinctrl.h>
Simon Glasscd93d622020-05-10 11:40:13 -060015#include <linux/bitops.h>
Wenyou Yangac72e172016-07-20 17:16:27 +080016#include <linux/io.h>
17#include <linux/err.h>
18#include <mach/atmel_pio4.h>
19
20DECLARE_GLOBAL_DATA_PTR;
21
22/*
23 * Warning:
24 * In order to not introduce confusion between Atmel PIO groups and pinctrl
25 * framework groups, Atmel PIO groups will be called banks.
26 */
27
Simon Glass8a8d24b2020-12-03 16:55:23 -070028struct atmel_pio4_plat {
Wenyou Yangac72e172016-07-20 17:16:27 +080029 struct atmel_pio4_port *reg_base;
Claudiu Beznea8bad34a2021-01-27 15:00:30 +020030 unsigned int slew_rate_support;
Wenyou Yangac72e172016-07-20 17:16:27 +080031};
32
Sergiu Moga2ed96a82022-09-01 17:22:41 +030033/*
34 * Table keeping track of the pinctrl driver's slew rate support and the
35 * corresponding index into the struct udevice_id of the gpio_atmel_pio4 GPIO
36 * driver. This has been done in order to align the DT of U-Boot with the DT of
37 * Linux. In Linux, a phandle from a '-gpio' DT property is linked to the
38 * pinctrl driver, unlike U-Boot which redirects this phandle to a corresponding
39 * UCLASS_GPIO driver. Thus, in order to link the two, a hook to the bind method
40 * of the pinctrl driver in U-Boot has been added. This bind method will attach
41 * the GPIO driver to the pinctrl DT node using this table.
42 * @slew_rate_support pinctrl driver's slew rate support
43 * @gdidx index into the GPIO driver's struct udevide_id
44 * (needed in order to properly bind with driver_data)
45 */
46
47struct atmel_pinctrl_data {
48 unsigned int slew_rate_support;
49 int gdidx;
50};
51
Wenyou Yangac72e172016-07-20 17:16:27 +080052static const struct pinconf_param conf_params[] = {
53 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
54 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
55 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
56 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
57 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
58 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
59 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
Eugen Hristev417eca02021-01-05 10:54:01 +020060 { "atmel,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
Claudiu Beznea8bad34a2021-01-27 15:00:30 +020061 { "slew-rate", PIN_CONFIG_SLEW_RATE, 0},
Wenyou Yangac72e172016-07-20 17:16:27 +080062};
63
Claudiu Beznea8bad34a2021-01-27 15:00:30 +020064static u32 atmel_pinctrl_get_pinconf(struct udevice *config,
65 struct atmel_pio4_plat *plat)
Wenyou Yangac72e172016-07-20 17:16:27 +080066{
67 const struct pinconf_param *params;
68 u32 param, arg, conf = 0;
69 u32 i;
Eugen Hristev417eca02021-01-05 10:54:01 +020070 u32 val;
Wenyou Yangac72e172016-07-20 17:16:27 +080071
72 for (i = 0; i < ARRAY_SIZE(conf_params); i++) {
73 params = &conf_params[i];
Eugen Hristev864a4142021-01-05 10:51:53 +020074 if (!dev_read_prop(config, params->property, NULL))
Wenyou Yangac72e172016-07-20 17:16:27 +080075 continue;
76
77 param = params->param;
78 arg = params->default_value;
79
Claudiu Beznea8bad34a2021-01-27 15:00:30 +020080 /* Keep slew rate enabled by default. */
81 if (plat->slew_rate_support)
82 conf |= ATMEL_PIO_SR;
83
Wenyou Yangac72e172016-07-20 17:16:27 +080084 switch (param) {
85 case PIN_CONFIG_BIAS_DISABLE:
86 conf &= (~ATMEL_PIO_PUEN_MASK);
87 conf &= (~ATMEL_PIO_PDEN_MASK);
88 break;
89 case PIN_CONFIG_BIAS_PULL_UP:
90 conf |= ATMEL_PIO_PUEN_MASK;
91 break;
92 case PIN_CONFIG_BIAS_PULL_DOWN:
93 conf |= ATMEL_PIO_PDEN_MASK;
94 break;
95 case PIN_CONFIG_DRIVE_OPEN_DRAIN:
96 if (arg == 0)
97 conf &= (~ATMEL_PIO_OPD_MASK);
98 else
99 conf |= ATMEL_PIO_OPD_MASK;
100 break;
101 case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
102 if (arg == 0)
103 conf |= ATMEL_PIO_SCHMITT_MASK;
104 else
105 conf &= (~ATMEL_PIO_SCHMITT_MASK);
106 break;
107 case PIN_CONFIG_INPUT_DEBOUNCE:
108 if (arg == 0) {
109 conf &= (~ATMEL_PIO_IFEN_MASK);
110 conf &= (~ATMEL_PIO_IFSCEN_MASK);
111 } else {
112 conf |= ATMEL_PIO_IFEN_MASK;
113 conf |= ATMEL_PIO_IFSCEN_MASK;
114 }
115 break;
Eugen Hristev417eca02021-01-05 10:54:01 +0200116 case PIN_CONFIG_DRIVE_STRENGTH:
117 dev_read_u32(config, params->property, &val);
118 conf &= (~ATMEL_PIO_DRVSTR_MASK);
119 conf |= (val << ATMEL_PIO_DRVSTR_OFFSET)
120 & ATMEL_PIO_DRVSTR_MASK;
121 break;
Claudiu Beznea8bad34a2021-01-27 15:00:30 +0200122 case PIN_CONFIG_SLEW_RATE:
123 if (!plat->slew_rate_support)
124 break;
125
126 dev_read_u32(config, params->property, &val);
127 /* And disable it if requested. */
128 if (val == 0)
129 conf &= ~ATMEL_PIO_SR;
130 break;
Wenyou Yangac72e172016-07-20 17:16:27 +0800131 default:
132 printf("%s: Unsupported configuration parameter: %u\n",
133 __func__, param);
134 break;
135 }
136 }
137
138 return conf;
139}
140
141static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
142 u32 bank)
143{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700144 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yangac72e172016-07-20 17:16:27 +0800145 struct atmel_pio4_port *bank_base =
146 (struct atmel_pio4_port *)((u32)plat->reg_base +
147 ATMEL_PIO_BANK_OFFSET * bank);
148
149 return bank_base;
150}
151
152#define MAX_PINMUX_ENTRIES 40
153
154static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
155{
Claudiu Beznea8bad34a2021-01-27 15:00:30 +0200156 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yangac72e172016-07-20 17:16:27 +0800157 struct atmel_pio4_port *bank_base;
158 const void *blob = gd->fdt_blob;
Simon Glasse160f7d2017-01-17 16:52:55 -0700159 int node = dev_of_offset(config);
Wenyou Yangac72e172016-07-20 17:16:27 +0800160 u32 offset, func, bank, line;
161 u32 cells[MAX_PINMUX_ENTRIES];
162 u32 i, conf;
163 int count;
164
Claudiu Beznea8bad34a2021-01-27 15:00:30 +0200165 conf = atmel_pinctrl_get_pinconf(config, plat);
Wenyou Yangac72e172016-07-20 17:16:27 +0800166
167 count = fdtdec_get_int_array_count(blob, node, "pinmux",
168 cells, ARRAY_SIZE(cells));
169 if (count < 0) {
170 printf("%s: bad pinmux array %d\n", __func__, count);
171 return -EINVAL;
172 }
173
174 if (count > MAX_PINMUX_ENTRIES) {
175 printf("%s: unsupported pinmux array count %d\n",
176 __func__, count);
177 return -EINVAL;
178 }
179
180 for (i = 0 ; i < count; i++) {
181 offset = ATMEL_GET_PIN_NO(cells[i]);
182 func = ATMEL_GET_PIN_FUNC(cells[i]);
183
184 bank = ATMEL_PIO_BANK(offset);
185 line = ATMEL_PIO_LINE(offset);
186
187 bank_base = atmel_pio4_bank_base(dev, bank);
188
189 writel(BIT(line), &bank_base->mskr);
190 conf &= (~ATMEL_PIO_CFGR_FUNC_MASK);
191 conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK);
192 writel(conf, &bank_base->cfgr);
193 }
194
195 return 0;
196}
197
198const struct pinctrl_ops atmel_pinctrl_ops = {
199 .set_state = atmel_pinctrl_set_state,
200};
201
202static int atmel_pinctrl_probe(struct udevice *dev)
203{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700204 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300205 struct atmel_pinctrl_data *priv = (struct atmel_pinctrl_data *)dev_get_driver_data(dev);
Wenyou Yangac72e172016-07-20 17:16:27 +0800206 fdt_addr_t addr_base;
207
Masahiro Yamada25484932020-07-17 14:36:48 +0900208 addr_base = dev_read_addr(dev);
Wenyou Yangac72e172016-07-20 17:16:27 +0800209 if (addr_base == FDT_ADDR_T_NONE)
210 return -EINVAL;
211
212 plat->reg_base = (struct atmel_pio4_port *)addr_base;
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300213 plat->slew_rate_support = priv->slew_rate_support;
Wenyou Yangac72e172016-07-20 17:16:27 +0800214
215 return 0;
216}
217
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300218static int atmel_pinctrl_bind(struct udevice *dev)
219{
220 struct udevice *g;
221 struct driver *drv;
222 ofnode node = dev_ofnode(dev);
223 struct atmel_pinctrl_data *priv = (struct atmel_pinctrl_data *)dev_get_driver_data(dev);
224
225 if (!CONFIG_IS_ENABLED(ATMEL_PIO4))
226 return 0;
227
228 /* Obtain a handle to the GPIO driver */
229 drv = lists_driver_lookup_name("gpio_atmel_pio4");
230 if (!drv)
231 return -ENOENT;
232
233 /*
234 * Bind the GPIO driver to the pinctrl DT node, together
235 * with its corresponding driver_data.
236 */
237 return device_bind_with_driver_data(dev, drv, drv->name,
238 drv->of_match[priv->gdidx].data,
239 node, &g);
240}
241
242static const struct atmel_pinctrl_data atmel_sama5d2_pinctrl_data = {
243 .gdidx = 0,
244};
245
246static const struct atmel_pinctrl_data microchip_sama7g5_pinctrl_data = {
247 .slew_rate_support = 1,
248 .gdidx = 1,
249};
250
Wenyou Yangac72e172016-07-20 17:16:27 +0800251static const struct udevice_id atmel_pinctrl_match[] = {
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300252 { .compatible = "atmel,sama5d2-pinctrl",
253 .data = (ulong)&atmel_sama5d2_pinctrl_data, },
Claudiu Beznea8bad34a2021-01-27 15:00:30 +0200254 { .compatible = "microchip,sama7g5-pinctrl",
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300255 .data = (ulong)&microchip_sama7g5_pinctrl_data, },
Wenyou Yangac72e172016-07-20 17:16:27 +0800256 {}
257};
258
259U_BOOT_DRIVER(atmel_pinctrl) = {
260 .name = "pinctrl_atmel_pio4",
261 .id = UCLASS_PINCTRL,
262 .of_match = atmel_pinctrl_match,
Sergiu Moga2ed96a82022-09-01 17:22:41 +0300263 .bind = atmel_pinctrl_bind,
Wenyou Yangac72e172016-07-20 17:16:27 +0800264 .probe = atmel_pinctrl_probe,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700265 .plat_auto = sizeof(struct atmel_pio4_plat),
Wenyou Yangac72e172016-07-20 17:16:27 +0800266 .ops = &atmel_pinctrl_ops,
267};