exynos_gpio.c revision 1.14 1 /* $NetBSD: exynos_gpio.c,v 1.14 2015/12/19 21:42:31 marty Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Reinoud Zandijk
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "opt_exynos.h"
33 #include "opt_arm_debug.h"
34 #include "gpio.h"
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(1, "$NetBSD: exynos_gpio.c,v 1.14 2015/12/19 21:42:31 marty Exp $");
38
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/device.h>
42 #include <sys/intr.h>
43 #include <sys/systm.h>
44 #include <sys/kmem.h>
45 #include <sys/gpio.h>
46
47 #include <dev/gpio/gpiovar.h>
48
49 #include <arm/samsung/exynos_reg.h>
50 #include <arm/samsung/exynos_io.h>
51 #include <arm/samsung/exynos_intr.h>
52 #include <arm/samsung/exynos_pinctrl.h>
53
54 #include <dev/fdt/fdtvar.h>
55
56 struct exynos_gpio_pin_cfg {
57 uint32_t cfg;
58 uint32_t pud;
59 uint32_t drv;
60 uint32_t conpwd;
61 uint32_t pudpwd;
62 };
63
64 struct exynos_gpio_softc;
65
66 struct exynos_gpio_bank {
67 const char bank_name[6];
68 device_t bank_dev;
69 struct gpio_chipset_tag bank_gc;
70 struct exynos_gpio_softc *bank_softc;
71 gpio_pin_t bank_pins[8];
72
73 const bus_addr_t bank_core_offset;
74 const uint8_t bank_bits;
75
76 uint8_t bank_pin_mask;
77 uint8_t bank_pin_inuse_mask;
78 bus_space_handle_t bank_bsh;
79 struct exynos_gpio_pin_cfg bank_cfg;
80 struct exynos_gpio_bank * bank_next;
81 };
82
83 struct exynos_gpio_softc {
84 device_t sc_dev;
85 bus_space_tag_t sc_bst;
86 bus_space_handle_t sc_bsh;
87 };
88
89 struct exynos_gpio_pin {
90 struct exynos_gpio_softc *pin_sc;
91 int pin_no;
92 u_int pin_flags;
93 int pin_actlo;
94 const struct exynos_gpio_bank *pin_bank;
95 };
96
97 struct exynos_gpio_bank *exynos_gpio_banks;
98
99 static void exynos_gpio_pin_ctl(void *cookie, int pin, int flags);
100 static void *exynos_gpio_fdt_acquire(device_t, const void *,
101 size_t, int);
102 static void exynos_gpio_fdt_release(device_t, void *);
103
104 static int exynos_gpio_fdt_read(device_t, void *);
105 static void exynos_gpio_fdt_write(device_t, void *, int);
106 //static int exynos_gpio_cfprint(void *, const char *);
107
108 struct fdtbus_gpio_controller_func exynos_gpio_funcs = {
109 .acquire = exynos_gpio_fdt_acquire,
110 .release = exynos_gpio_fdt_release,
111 .read = exynos_gpio_fdt_read,
112 .write = exynos_gpio_fdt_write
113 };
114
115 #if 0
116 static int
117 exynos_gpio_cfprint(void *priv, const char *pnp)
118 {
119 struct gpiobus_attach_args *gba = priv;
120 struct exynos_gpio_bank *bank = gba->gba_gc->gp_cookie;
121 const char *bankname = bank->bank_name;
122
123 if (pnp)
124 aprint_normal("gpiobus at %s", pnp);
125
126 aprint_normal(" (%s)", bankname);
127
128 return UNCONF;
129 }
130 #endif
131
132 static void
133 exynos_gpio_update_cfg_regs(struct exynos_gpio_bank *bank,
134 const struct exynos_gpio_pin_cfg *ncfg)
135 {
136 bus_space_tag_t bst = &exynos_bs_tag;
137
138 if (bank->bank_cfg.cfg != ncfg->cfg) {
139 bus_space_write_4(bst, bank->bank_bsh,
140 EXYNOS_GPIO_CON, ncfg->cfg);
141 bank->bank_cfg.cfg = ncfg->cfg;
142 }
143 if (bank->bank_cfg.pud != ncfg->pud) {
144 bus_space_write_4(bst, bank->bank_bsh,
145 EXYNOS_GPIO_PUD, ncfg->pud);
146 bank->bank_cfg.pud = ncfg->pud;
147 }
148
149 /* the following attributes are not yet setable */
150 #if 0
151 if (bank->bank_cfg.drv != ncfg->drv) {
152 bus_space_write_4(bst, bank->bank_bsh,
153 EXYNOS_GPIO_DRV, ncfg->drv);
154 bank->bank_cfg.drv = ncfg->drv;
155 }
156 if (bank->bank_cfg.conpwd != ncfg->conpwd) {
157 bus_space_write_4(bst, bank->bank_bsh,
158 EXYNOS_GPIO_CONPWD, ncfg->conpwd);
159 bank->bank_cfg.conpwd = ncfg->conpwd;
160 }
161 if (bank->bank_cfg.pudpwd != ncfg->pudpwd) {
162 bus_space_write_4(bst, bank->bank_bsh,
163 EXYNOS_GPIO_PUDPWD, ncfg->pudpwd);
164 bank->bank_cfg.pudpwd = ncfg->pudpwd;
165 }
166 #endif
167 }
168
169
170 static void
171 exynos_gpio_pin_ctl(void *cookie, int pin, int flags)
172 {
173 struct exynos_gpio_bank * const bank = cookie;
174 struct exynos_gpio_pin_cfg ncfg = bank->bank_cfg;
175 u_int shift;
176 int pull;
177
178 /* honour pullup requests */
179 pull = EXYNOS_GPIO_PIN_FLOAT;
180 if (flags & GPIO_PIN_PULLUP)
181 pull = EXYNOS_GPIO_PIN_PULL_UP;
182 if (flags & GPIO_PIN_PULLDOWN)
183 pull = EXYNOS_GPIO_PIN_PULL_DOWN;
184 shift = (pin & 7) << 1;
185 ncfg.pud &= ~(0x3 << shift);
186 ncfg.pud |= pull << shift;
187
188 /* honour i/o */
189 if (flags & GPIO_PIN_INPUT) {
190 ncfg.cfg &= ~(0x0f << shift);
191 ncfg.cfg |= EXYNOS_GPIO_FUNC_INPUT << shift;
192 } else if (flags & GPIO_PIN_OUTPUT) {
193 ncfg.cfg &= ~(0x0f << shift);
194 ncfg.cfg |= EXYNOS_GPIO_FUNC_OUTPUT << shift;
195 }
196
197 /* update any config registers that changed */
198 exynos_gpio_update_cfg_regs(bank, &ncfg);
199 }
200
201 void
202 exynos_gpio_bank_config(struct exynos_pinctrl_softc * parent, int node)
203 {
204 // bus_space_tag_t bst = &exynos_bs_tag; /* MJF: This is wrong */
205 struct exynos_gpio_bank *bank = kmem_zalloc(sizeof(*bank), KM_SLEEP);
206 // struct exynos_gpio_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
207 // struct gpiobus_attach_args gba;
208 char result[64];
209 // int data;
210 // int error;
211
212 /*error =*/ OF_getprop(node, "name", result, sizeof(result));
213 printf(" GPIO %s\n", result);
214 if (exynos_gpio_banks)
215 bank->bank_next = exynos_gpio_banks;
216 exynos_gpio_banks = bank;
217 /* MJF: TODO: process all of the node properties */
218 #if 0
219 // pincaps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
220 // GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
221
222 // data = bus_space_read_1(sc->sc_bst, bank->bank_bsh,
223 // EXYNOS_GPIO_DAT);
224
225 sc->sc_dev = parent->sc_dev;
226 sc->sc_bst = parent->sc_bst;
227
228 memset(&gba, 0, sizeof(gba));
229 gba.gba_gc = &bank->bank_gc;
230 gba.gba_pins = bank->bank_pins;
231 // gba.gba_npins = bit; /* MJF? */
232 bank->bank_dev = config_found_ia(parent->sc_dev, "gpiobus", &gba,
233 exynos_gpio_cfprint);
234
235 bank->bank_pin_mask = __BIT(bank->bank_bits) - 1;
236 bank->bank_pin_inuse_mask = 0;
237
238
239 /* read in our initial settings */
240 bank->bank_cfg.cfg = bus_space_read_4(bst, bank->bank_bsh,
241 EXYNOS_GPIO_CON);
242 bank->bank_cfg.pud = bus_space_read_4(bst, bank->bank_bsh,
243 EXYNOS_GPIO_PUD);
244 bank->bank_cfg.drv = bus_space_read_4(bst, bank->bank_bsh,
245 EXYNOS_GPIO_DRV);
246 bank->bank_cfg.conpwd = bus_space_read_4(bst, bank->bank_bsh,
247 EXYNOS_GPIO_CONPWD);
248 bank->bank_cfg.pudpwd = bus_space_read_4(bst, bank->bank_bsh,
249 EXYNOS_GPIO_PUDPWD);
250 /* MJF: TODO: Configure from the node data, if present */
251 #endif
252 }
253
254 /*
255 * pinmame = gpLD-N
256 * L = 'a' - 'z' -+
257 * D = '0' - '8' -+ ===== bank name
258 * N = '0' - '8' ===== pin number
259 */
260
261 static const struct exynos_gpio_bank *
262 exynos_gpio_pin_lookup(const char *pinname, int *ppin)
263 {
264 char bankname[5];
265 int pin;
266 struct exynos_gpio_bank *bank;
267
268 KASSERT(strlen(pinname) == 2 || strlen(pinname) == 3);
269
270 memset(bankname, 0, sizeof(bankname));
271 bankname[0] = pinname[0]; /* 'g' */
272 bankname[1] = pinname[1]; /* 'p' */
273 bankname[2] = pinname[2]; /* L */
274 bankname[3] = pinname[3]; /* D */
275 pin = pinname[5] - '0'; /* skip the '-' */
276
277 for (bank = exynos_gpio_banks; bank; bank = bank->bank_next)
278 if (strcmp(bank->bank_name, bankname) == 0) {
279 *ppin = pin;
280 return bank;
281 }
282
283 return NULL;
284 }
285
286 static void *
287 exynos_gpio_fdt_acquire(device_t dev, const void *data, size_t len, int flags)
288 {
289 /* MJF: This is wrong. data is a u_int but I need a name */
290 // const u_int *gpio = data;
291 const char *pinname = data;
292 const struct exynos_gpio_bank *bank;
293 struct exynos_gpio_pin *gpin;
294 int pin;
295
296 bank = exynos_gpio_pin_lookup(pinname, &pin);
297 if (bank == NULL)
298 return NULL;
299
300 gpin = kmem_alloc(sizeof(*gpin), KM_SLEEP);
301 gpin->pin_sc = bank->bank_softc;
302 gpin->pin_bank = bank;
303 gpin->pin_no = pin;
304 gpin->pin_flags = flags;
305 gpin->pin_actlo = 0;
306
307 exynos_gpio_pin_ctl(&gpin->pin_bank, gpin->pin_no, gpin->pin_flags);
308
309 return gpin;
310 }
311
312 static void
313 exynos_gpio_fdt_release(device_t dev, void *priv)
314 {
315 struct exynos_gpio_pin *gpin = priv;
316
317 kmem_free(gpin, sizeof(*gpin));
318 }
319
320 static int
321 exynos_gpio_fdt_read(device_t dev, void *priv)
322 {
323 struct exynos_gpio_pin *gpin = priv;
324 int val;
325
326 val = (bus_space_read_1(gpin->pin_sc->sc_bst,
327 gpin->pin_sc->sc_bsh,
328 EXYNOS_GPIO_DAT) >> gpin->pin_no) & 1;
329
330 if (gpin->pin_actlo)
331 val = !val;
332
333 return val;
334 }
335
336 static void
337 exynos_gpio_fdt_write(device_t dev, void *priv, int val)
338 {
339 struct exynos_gpio_pin *gpin = priv;
340
341 if (gpin->pin_actlo)
342 val = !val;
343
344 val = bus_space_read_1(gpin->pin_sc->sc_bst,
345 gpin->pin_sc->sc_bsh,
346 EXYNOS_GPIO_DAT);
347 val &= ~__BIT(gpin->pin_no);
348 if (val)
349 val |= __BIT(gpin->pin_no);
350 bus_space_write_1(gpin->pin_sc->sc_bst,
351 gpin->pin_sc->sc_bsh,
352 EXYNOS_GPIO_DAT, val);
353
354 }
355