Home | History | Annotate | Line # | Download | only in samsung
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