Home | History | Annotate | Download | only in gpio
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2012 Henrik Nordstrom <henrik (at) henriknordstrom.net>
      4  *
      5  * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
      6  *
      7  * (C) Copyright 2007-2011
      8  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
      9  * Tom Cubie <tangliang (at) allwinnertech.com>
     10  */
     11 
     12 #include <common.h>
     13 #include <dm.h>
     14 #include <errno.h>
     15 #include <fdtdec.h>
     16 #include <malloc.h>
     17 #include <asm/arch/gpio.h>
     18 #include <asm/io.h>
     19 #include <asm/gpio.h>
     20 #include <dm/device-internal.h>
     21 #include <dt-bindings/gpio/gpio.h>
     22 
     23 #define SUNXI_GPIOS_PER_BANK	SUNXI_GPIO_A_NR
     24 
     25 struct sunxi_gpio_platdata {
     26 	struct sunxi_gpio *regs;
     27 	const char *bank_name;	/* Name of bank, e.g. "B" */
     28 	int gpio_count;
     29 };
     30 
     31 #ifndef CONFIG_DM_GPIO
     32 static int sunxi_gpio_output(u32 pin, u32 val)
     33 {
     34 	u32 dat;
     35 	u32 bank = GPIO_BANK(pin);
     36 	u32 num = GPIO_NUM(pin);
     37 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
     38 
     39 	dat = readl(&pio->dat);
     40 	if (val)
     41 		dat |= 0x1 << num;
     42 	else
     43 		dat &= ~(0x1 << num);
     44 
     45 	writel(dat, &pio->dat);
     46 
     47 	return 0;
     48 }
     49 
     50 static int sunxi_gpio_input(u32 pin)
     51 {
     52 	u32 dat;
     53 	u32 bank = GPIO_BANK(pin);
     54 	u32 num = GPIO_NUM(pin);
     55 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
     56 
     57 	dat = readl(&pio->dat);
     58 	dat >>= num;
     59 
     60 	return dat & 0x1;
     61 }
     62 
     63 int gpio_request(unsigned gpio, const char *label)
     64 {
     65 	return 0;
     66 }
     67 
     68 int gpio_free(unsigned gpio)
     69 {
     70 	return 0;
     71 }
     72 
     73 int gpio_direction_input(unsigned gpio)
     74 {
     75 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
     76 
     77 	return 0;
     78 }
     79 
     80 int gpio_direction_output(unsigned gpio, int value)
     81 {
     82 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
     83 
     84 	return sunxi_gpio_output(gpio, value);
     85 }
     86 
     87 int gpio_get_value(unsigned gpio)
     88 {
     89 	return sunxi_gpio_input(gpio);
     90 }
     91 
     92 int gpio_set_value(unsigned gpio, int value)
     93 {
     94 	return sunxi_gpio_output(gpio, value);
     95 }
     96 
     97 int sunxi_name_to_gpio(const char *name)
     98 {
     99 	int group = 0;
    100 	int groupsize = 9 * 32;
    101 	long pin;
    102 	char *eptr;
    103 
    104 	if (*name == 'P' || *name == 'p')
    105 		name++;
    106 	if (*name >= 'A') {
    107 		group = *name - (*name > 'a' ? 'a' : 'A');
    108 		groupsize = 32;
    109 		name++;
    110 	}
    111 
    112 	pin = simple_strtol(name, &eptr, 10);
    113 	if (!*name || *eptr)
    114 		return -1;
    115 	if (pin < 0 || pin > groupsize || group >= 9)
    116 		return -1;
    117 	return group * 32 + pin;
    118 }
    119 #endif
    120 
    121 int sunxi_name_to_gpio_bank(const char *name)
    122 {
    123 	int group = 0;
    124 
    125 	if (*name == 'P' || *name == 'p')
    126 		name++;
    127 	if (*name >= 'A') {
    128 		group = *name - (*name > 'a' ? 'a' : 'A');
    129 		return group;
    130 	}
    131 
    132 	return -1;
    133 }
    134 
    135 #ifdef CONFIG_DM_GPIO
    136 /* TODO(sjg (at) chromium.org): Remove this function and use device tree */
    137 int sunxi_name_to_gpio(const char *name)
    138 {
    139 	unsigned int gpio;
    140 	int ret;
    141 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
    142 	char lookup[8];
    143 
    144 	if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
    145 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
    146 			SUNXI_GPIO_AXP0_VBUS_DETECT);
    147 		name = lookup;
    148 	} else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
    149 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
    150 			SUNXI_GPIO_AXP0_VBUS_ENABLE);
    151 		name = lookup;
    152 	}
    153 #endif
    154 	ret = gpio_lookup_name(name, NULL, NULL, &gpio);
    155 
    156 	return ret ? ret : gpio;
    157 }
    158 
    159 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
    160 {
    161 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    162 
    163 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
    164 
    165 	return 0;
    166 }
    167 
    168 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
    169 				       int value)
    170 {
    171 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    172 	u32 num = GPIO_NUM(offset);
    173 
    174 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
    175 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
    176 
    177 	return 0;
    178 }
    179 
    180 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
    181 {
    182 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    183 	u32 num = GPIO_NUM(offset);
    184 	unsigned dat;
    185 
    186 	dat = readl(&plat->regs->dat);
    187 	dat >>= num;
    188 
    189 	return dat & 0x1;
    190 }
    191 
    192 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
    193 				int value)
    194 {
    195 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    196 	u32 num = GPIO_NUM(offset);
    197 
    198 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
    199 	return 0;
    200 }
    201 
    202 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
    203 {
    204 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    205 	int func;
    206 
    207 	func = sunxi_gpio_get_cfgbank(plat->regs, offset);
    208 	if (func == SUNXI_GPIO_OUTPUT)
    209 		return GPIOF_OUTPUT;
    210 	else if (func == SUNXI_GPIO_INPUT)
    211 		return GPIOF_INPUT;
    212 	else
    213 		return GPIOF_FUNC;
    214 }
    215 
    216 static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
    217 			    struct ofnode_phandle_args *args)
    218 {
    219 	int ret;
    220 
    221 	ret = device_get_child(dev, args->args[0], &desc->dev);
    222 	if (ret)
    223 		return ret;
    224 	desc->offset = args->args[1];
    225 	desc->flags = args->args[2] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
    226 
    227 	return 0;
    228 }
    229 
    230 static const struct dm_gpio_ops gpio_sunxi_ops = {
    231 	.direction_input	= sunxi_gpio_direction_input,
    232 	.direction_output	= sunxi_gpio_direction_output,
    233 	.get_value		= sunxi_gpio_get_value,
    234 	.set_value		= sunxi_gpio_set_value,
    235 	.get_function		= sunxi_gpio_get_function,
    236 	.xlate			= sunxi_gpio_xlate,
    237 };
    238 
    239 /**
    240  * Returns the name of a GPIO bank
    241  *
    242  * GPIO banks are named A, B, C, ...
    243  *
    244  * @bank:	Bank number (0, 1..n-1)
    245  * @return allocated string containing the name
    246  */
    247 static char *gpio_bank_name(int bank)
    248 {
    249 	char *name;
    250 
    251 	name = malloc(3);
    252 	if (name) {
    253 		name[0] = 'P';
    254 		name[1] = 'A' + bank;
    255 		name[2] = '\0';
    256 	}
    257 
    258 	return name;
    259 }
    260 
    261 static int gpio_sunxi_probe(struct udevice *dev)
    262 {
    263 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
    264 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
    265 
    266 	/* Tell the uclass how many GPIOs we have */
    267 	if (plat) {
    268 		uc_priv->gpio_count = plat->gpio_count;
    269 		uc_priv->bank_name = plat->bank_name;
    270 	}
    271 
    272 	return 0;
    273 }
    274 
    275 struct sunxi_gpio_soc_data {
    276 	int start;
    277 	int no_banks;
    278 };
    279 
    280 /**
    281  * We have a top-level GPIO device with no actual GPIOs. It has a child
    282  * device for each Sunxi bank.
    283  */
    284 static int gpio_sunxi_bind(struct udevice *parent)
    285 {
    286 	struct sunxi_gpio_soc_data *soc_data =
    287 		(struct sunxi_gpio_soc_data *)dev_get_driver_data(parent);
    288 	struct sunxi_gpio_platdata *plat = parent->platdata;
    289 	struct sunxi_gpio_reg *ctlr;
    290 	int bank, ret;
    291 
    292 	/* If this is a child device, there is nothing to do here */
    293 	if (plat)
    294 		return 0;
    295 
    296 	ctlr = (struct sunxi_gpio_reg *)devfdt_get_addr(parent);
    297 	for (bank = 0; bank < soc_data->no_banks; bank++) {
    298 		struct sunxi_gpio_platdata *plat;
    299 		struct udevice *dev;
    300 
    301 		plat = calloc(1, sizeof(*plat));
    302 		if (!plat)
    303 			return -ENOMEM;
    304 		plat->regs = &ctlr->gpio_bank[bank];
    305 		plat->bank_name = gpio_bank_name(soc_data->start + bank);
    306 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
    307 
    308 		ret = device_bind(parent, parent->driver,
    309 					plat->bank_name, plat, -1, &dev);
    310 		if (ret)
    311 			return ret;
    312 		dev_set_of_offset(dev, dev_of_offset(parent));
    313 	}
    314 
    315 	return 0;
    316 }
    317 
    318 static const struct sunxi_gpio_soc_data soc_data_a_all = {
    319 	.start = 0,
    320 	.no_banks = SUNXI_GPIO_BANKS,
    321 };
    322 
    323 static const struct sunxi_gpio_soc_data soc_data_l_1 = {
    324 	.start = 'L' - 'A',
    325 	.no_banks = 1,
    326 };
    327 
    328 static const struct sunxi_gpio_soc_data soc_data_l_2 = {
    329 	.start = 'L' - 'A',
    330 	.no_banks = 2,
    331 };
    332 
    333 static const struct sunxi_gpio_soc_data soc_data_l_3 = {
    334 	.start = 'L' - 'A',
    335 	.no_banks = 3,
    336 };
    337 
    338 #define ID(_compat_, _soc_data_) \
    339 	{ .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ }
    340 
    341 static const struct udevice_id sunxi_gpio_ids[] = {
    342 	ID("allwinner,sun4i-a10-pinctrl",	a_all),
    343 	ID("allwinner,sun5i-a10s-pinctrl",	a_all),
    344 	ID("allwinner,sun5i-a13-pinctrl",	a_all),
    345 	ID("allwinner,sun50i-h5-pinctrl",	a_all),
    346 	ID("allwinner,sun6i-a31-pinctrl",	a_all),
    347 	ID("allwinner,sun6i-a31s-pinctrl",	a_all),
    348 	ID("allwinner,sun7i-a20-pinctrl",	a_all),
    349 	ID("allwinner,sun8i-a23-pinctrl",	a_all),
    350 	ID("allwinner,sun8i-a33-pinctrl",	a_all),
    351 	ID("allwinner,sun8i-a83t-pinctrl",	a_all),
    352 	ID("allwinner,sun8i-h3-pinctrl",	a_all),
    353 	ID("allwinner,sun8i-r40-pinctrl",	a_all),
    354 	ID("allwinner,sun8i-v3s-pinctrl",	a_all),
    355 	ID("allwinner,sun9i-a80-pinctrl",	a_all),
    356 	ID("allwinner,sun50i-a64-pinctrl",	a_all),
    357 	ID("allwinner,sun6i-a31-r-pinctrl",	l_2),
    358 	ID("allwinner,sun8i-a23-r-pinctrl",	l_1),
    359 	ID("allwinner,sun8i-a83t-r-pinctrl",	l_1),
    360 	ID("allwinner,sun8i-h3-r-pinctrl",	l_1),
    361 	ID("allwinner,sun9i-a80-r-pinctrl",	l_3),
    362 	ID("allwinner,sun50i-a64-r-pinctrl",	l_1),
    363 	{ }
    364 };
    365 
    366 U_BOOT_DRIVER(gpio_sunxi) = {
    367 	.name	= "gpio_sunxi",
    368 	.id	= UCLASS_GPIO,
    369 	.ops	= &gpio_sunxi_ops,
    370 	.of_match = sunxi_gpio_ids,
    371 	.bind	= gpio_sunxi_bind,
    372 	.probe	= gpio_sunxi_probe,
    373 };
    374 #endif
    375