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