blob: e7d0994f29e740cf90c6d42d2154b926ab1a8f74 [file] [log] [blame]
Stefan Boschbe278c12020-07-10 19:07:30 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Pinctrl driver for Nexell SoCs
4 * (C) Copyright 2016 Nexell
5 * Bongyu, KOO <freestyle@nexell.co.kr>
6 *
7 * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net>
8 */
9
Stefan Boschbe278c12020-07-10 19:07:30 +020010#include <dm.h>
11#include <errno.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Stefan Boschbe278c12020-07-10 19:07:30 +020013#include <asm/io.h>
14#include <dm/pinctrl.h>
15#include <dm/root.h>
16#include "pinctrl-nexell.h"
17#include "pinctrl-s5pxx18.h"
18
19DECLARE_GLOBAL_DATA_PTR;
20
21static void nx_gpio_set_bit(u32 *value, u32 bit, int enable)
22{
23 register u32 newvalue;
24
25 newvalue = *value;
26 newvalue &= ~(1ul << bit);
27 newvalue |= (u32)enable << bit;
28 writel(newvalue, value);
29}
30
31static void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value)
32{
33 register u32 newvalue = *value;
34
35 newvalue = (u32)(newvalue & ~(3ul << (bit * 2)));
36 newvalue = (u32)(newvalue | (bit_value << (bit * 2)));
37
38 writel(newvalue, value);
39}
40
41static int nx_gpio_open_module(void *base)
42{
43 writel(0xFFFFFFFF, base + GPIOX_SLEW_DISABLE_DEFAULT);
44 writel(0xFFFFFFFF, base + GPIOX_DRV1_DISABLE_DEFAULT);
45 writel(0xFFFFFFFF, base + GPIOX_DRV0_DISABLE_DEFAULT);
46 writel(0xFFFFFFFF, base + GPIOX_PULLSEL_DISABLE_DEFAULT);
47 writel(0xFFFFFFFF, base + GPIOX_PULLENB_DISABLE_DEFAULT);
48 return true;
49}
50
51static void nx_gpio_set_pad_function(void *base, u32 pin, u32 padfunc)
52{
53 u32 reg = (pin / 16) ? GPIOX_ALTFN1 : GPIOX_ALTFN0;
54
55 nx_gpio_set_bit2(base + reg, pin % 16, padfunc);
56}
57
58static void nx_gpio_set_drive_strength(void *base, u32 pin, u32 drv)
59{
60 nx_gpio_set_bit(base + GPIOX_DRV1, pin, (int)(((u32)drv >> 0) & 0x1));
61 nx_gpio_set_bit(base + GPIOX_DRV0, pin, (int)(((u32)drv >> 1) & 0x1));
62}
63
64static void nx_gpio_set_pull_mode(void *base, u32 pin, u32 mode)
65{
66 if (mode == nx_gpio_pull_off) {
67 nx_gpio_set_bit(base + GPIOX_PULLENB, pin, false);
68 nx_gpio_set_bit(base + GPIOX_PULLSEL, pin, false);
69 } else {
70 nx_gpio_set_bit(base + GPIOX_PULLSEL,
71 pin, (mode & 1 ? true : false));
72 nx_gpio_set_bit(base + GPIOX_PULLENB, pin, true);
73 }
74}
75
76static void nx_alive_set_pullup(void *base, u32 pin, bool enable)
77{
78 u32 PULLUP_MASK;
79
80 PULLUP_MASK = (1UL << pin);
81 if (enable)
82 writel(PULLUP_MASK, base + ALIVE_PADPULLUPSET);
83 else
84 writel(PULLUP_MASK, base + ALIVE_PADPULLUPRST);
85}
86
87static int s5pxx18_pinctrl_gpio_init(struct udevice *dev)
88{
89 struct nexell_pinctrl_priv *priv = dev_get_priv(dev);
90 const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl;
91 unsigned long reg = priv->base;
92 int i;
93
94 for (i = 0; i < ctrl->nr_banks - 1; i++) /* except alive bank */
95 nx_gpio_open_module((void *)(reg + ctrl->pin_banks[i].offset));
96
97 return 0;
98}
99
100static int s5pxx18_pinctrl_alive_init(struct udevice *dev)
101{
102 struct nexell_pinctrl_priv *priv = dev_get_priv(dev);
103 const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl;
104 unsigned long reg = priv->base;
105
106 reg += ctrl->pin_banks[ctrl->nr_banks - 1].offset;
107
108 writel(1, reg + ALIVE_PWRGATE);
109 return 0;
110}
111
112int s5pxx18_pinctrl_init(struct udevice *dev)
113{
114 s5pxx18_pinctrl_gpio_init(dev);
115 s5pxx18_pinctrl_alive_init(dev);
116
117 return 0;
118}
119
120static int is_pin_alive(const char *name)
121{
122 return !strncmp(name, "alive", 5);
123}
124
125/**
126 * s5pxx18_pinctrl_set_state: configure a pin state.
127 * dev: the pinctrl device to be configured.
128 * config: the state to be configured.
129 */
130static int s5pxx18_pinctrl_set_state(struct udevice *dev,
131 struct udevice *config)
132{
133 unsigned int count, idx, pin;
134 unsigned int pinfunc, pinpud, pindrv;
135 unsigned long reg;
136 const char *name;
137 int ret;
138
139 /*
140 * refer to the following document for the pinctrl bindings
141 * doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt
142 */
143 count = dev_read_string_count(config, "pins");
144
145 if (count <= 0)
146 return -EINVAL;
147
148 pinfunc = dev_read_s32_default(config, "pin-function", -1);
149 pinpud = dev_read_s32_default(config, "pin-pull", -1);
150 pindrv = dev_read_s32_default(config, "pin-strength", -1);
151
152 for (idx = 0; idx < count; idx++) {
153 ret = dev_read_string_index(config, "pins", idx, &name);
154 if (ret)
155 return ret;
156 if (!name)
157 continue;
158 reg = pin_to_bank_base(dev, name, &pin);
159
160 if (is_pin_alive(name)) {
161 /* pin pull up/down */
162 if (pinpud != -1)
163 nx_alive_set_pullup((void *)reg, pin,
164 pinpud & 1);
165 continue;
166 }
167
168 /* pin function */
169 if (pinfunc != -1)
170 nx_gpio_set_pad_function((void *)reg, pin, pinfunc);
171
172 /* pin pull up/down/off */
173 if (pinpud != -1)
174 nx_gpio_set_pull_mode((void *)reg, pin, pinpud);
175
176 /* pin drive strength */
177 if (pindrv != -1)
178 nx_gpio_set_drive_strength((void *)reg, pin, pindrv);
179 }
180
181 return 0;
182}
183
184static struct pinctrl_ops s5pxx18_pinctrl_ops = {
185 .set_state = s5pxx18_pinctrl_set_state,
186};
187
188/* pin banks of s5pxx18 pin-controller */
189static const struct nexell_pin_bank_data s5pxx18_pin_banks[] = {
190 NEXELL_PIN_BANK(32, 0xA000, "gpioa"),
191 NEXELL_PIN_BANK(32, 0xB000, "gpiob"),
192 NEXELL_PIN_BANK(32, 0xC000, "gpioc"),
193 NEXELL_PIN_BANK(32, 0xD000, "gpiod"),
194 NEXELL_PIN_BANK(32, 0xE000, "gpioe"),
195 NEXELL_PIN_BANK(6, 0x0800, "alive"),
196};
197
198const struct nexell_pin_ctrl s5pxx18_pin_ctrl[] = {
199 {
200 /* pin-controller data */
201 .pin_banks = s5pxx18_pin_banks,
202 .nr_banks = ARRAY_SIZE(s5pxx18_pin_banks),
203 },
204};
205
206static const struct udevice_id s5pxx18_pinctrl_ids[] = {
207 { .compatible = "nexell,s5pxx18-pinctrl",
208 .data = (ulong)s5pxx18_pin_ctrl },
209 { }
210};
211
212U_BOOT_DRIVER(pinctrl_s5pxx18) = {
213 .name = "pinctrl_s5pxx18",
214 .id = UCLASS_PINCTRL,
215 .of_match = s5pxx18_pinctrl_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700216 .priv_auto = sizeof(struct nexell_pinctrl_priv),
Stefan Boschbe278c12020-07-10 19:07:30 +0200217 .ops = &s5pxx18_pinctrl_ops,
218 .probe = nexell_pinctrl_probe,
219 .flags = DM_FLAG_PRE_RELOC
220};