xref: /openbmc/u-boot/drivers/gpio/atmel_pio4.c (revision 46ed9381)
12c62c56aSWenyou Yang /*
22c62c56aSWenyou Yang  * Atmel PIO4 device driver
32c62c56aSWenyou Yang  *
42c62c56aSWenyou Yang  * Copyright (C) 2015 Atmel Corporation
52c62c56aSWenyou Yang  *		 Wenyou.Yang <wenyou.yang@atmel.com>
62c62c56aSWenyou Yang  *
72c62c56aSWenyou Yang  * SPDX-License-Identifier:	GPL-2.0+
82c62c56aSWenyou Yang  */
92c62c56aSWenyou Yang #include <common.h>
102c62c56aSWenyou Yang #include <dm.h>
112c62c56aSWenyou Yang #include <asm/arch/hardware.h>
122c62c56aSWenyou Yang #include <mach/gpio.h>
132c62c56aSWenyou Yang #include <mach/atmel_pio4.h>
142c62c56aSWenyou Yang 
152c62c56aSWenyou Yang static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
162c62c56aSWenyou Yang {
172c62c56aSWenyou Yang 	struct atmel_pio4_port *base = NULL;
182c62c56aSWenyou Yang 
192c62c56aSWenyou Yang 	switch (port) {
202c62c56aSWenyou Yang 	case AT91_PIO_PORTA:
212c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
222c62c56aSWenyou Yang 		break;
232c62c56aSWenyou Yang 	case AT91_PIO_PORTB:
242c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
252c62c56aSWenyou Yang 		break;
262c62c56aSWenyou Yang 	case AT91_PIO_PORTC:
272c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
282c62c56aSWenyou Yang 		break;
292c62c56aSWenyou Yang 	case AT91_PIO_PORTD:
302c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
312c62c56aSWenyou Yang 		break;
322c62c56aSWenyou Yang 	default:
332c62c56aSWenyou Yang 		printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
342c62c56aSWenyou Yang 		       port);
352c62c56aSWenyou Yang 		break;
362c62c56aSWenyou Yang 	}
372c62c56aSWenyou Yang 
382c62c56aSWenyou Yang 	return base;
392c62c56aSWenyou Yang }
402c62c56aSWenyou Yang 
412c62c56aSWenyou Yang static int atmel_pio4_config_io_func(u32 port, u32 pin,
422c62c56aSWenyou Yang 				     u32 func, u32 use_pullup)
432c62c56aSWenyou Yang {
442c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
452c62c56aSWenyou Yang 	u32 reg, mask;
462c62c56aSWenyou Yang 
47*46ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
482c62c56aSWenyou Yang 		return -ENODEV;
492c62c56aSWenyou Yang 
502c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
512c62c56aSWenyou Yang 	if (!port_base)
522c62c56aSWenyou Yang 		return -ENODEV;
532c62c56aSWenyou Yang 
542c62c56aSWenyou Yang 	mask = 1 << pin;
552c62c56aSWenyou Yang 	reg = func;
56*46ed9381SWenyou Yang 	reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0;
572c62c56aSWenyou Yang 
582c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
592c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
602c62c56aSWenyou Yang 
612c62c56aSWenyou Yang 	return 0;
622c62c56aSWenyou Yang }
632c62c56aSWenyou Yang 
642c62c56aSWenyou Yang int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup)
652c62c56aSWenyou Yang {
662c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
67*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_GPIO,
682c62c56aSWenyou Yang 					 use_pullup);
692c62c56aSWenyou Yang }
702c62c56aSWenyou Yang 
712c62c56aSWenyou Yang int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup)
722c62c56aSWenyou Yang {
732c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
74*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_A,
752c62c56aSWenyou Yang 					 use_pullup);
762c62c56aSWenyou Yang }
772c62c56aSWenyou Yang 
782c62c56aSWenyou Yang int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup)
792c62c56aSWenyou Yang {
802c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
81*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_B,
822c62c56aSWenyou Yang 					 use_pullup);
832c62c56aSWenyou Yang }
842c62c56aSWenyou Yang 
852c62c56aSWenyou Yang int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup)
862c62c56aSWenyou Yang {
872c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
88*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_C,
892c62c56aSWenyou Yang 					 use_pullup);
902c62c56aSWenyou Yang }
912c62c56aSWenyou Yang 
922c62c56aSWenyou Yang int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup)
932c62c56aSWenyou Yang {
942c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
95*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_D,
962c62c56aSWenyou Yang 					 use_pullup);
972c62c56aSWenyou Yang }
982c62c56aSWenyou Yang 
992c62c56aSWenyou Yang int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup)
1002c62c56aSWenyou Yang {
1012c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
102*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_E,
1032c62c56aSWenyou Yang 					 use_pullup);
1042c62c56aSWenyou Yang }
1052c62c56aSWenyou Yang 
1062c62c56aSWenyou Yang int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup)
1072c62c56aSWenyou Yang {
1082c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
109*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_F,
1102c62c56aSWenyou Yang 					 use_pullup);
1112c62c56aSWenyou Yang }
1122c62c56aSWenyou Yang 
1132c62c56aSWenyou Yang int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup)
1142c62c56aSWenyou Yang {
1152c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
116*46ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_G,
1172c62c56aSWenyou Yang 					 use_pullup);
1182c62c56aSWenyou Yang }
1192c62c56aSWenyou Yang 
1202c62c56aSWenyou Yang int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
1212c62c56aSWenyou Yang {
1222c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1232c62c56aSWenyou Yang 	u32 reg, mask;
1242c62c56aSWenyou Yang 
125*46ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
1262c62c56aSWenyou Yang 		return -ENODEV;
1272c62c56aSWenyou Yang 
1282c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1292c62c56aSWenyou Yang 	if (!port_base)
1302c62c56aSWenyou Yang 		return -ENODEV;
1312c62c56aSWenyou Yang 
1322c62c56aSWenyou Yang 	mask = 0x01 << pin;
133*46ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
1342c62c56aSWenyou Yang 
1352c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1362c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1372c62c56aSWenyou Yang 
1382c62c56aSWenyou Yang 	if (value)
1392c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
1402c62c56aSWenyou Yang 	else
1412c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
1422c62c56aSWenyou Yang 
1432c62c56aSWenyou Yang 	return 0;
1442c62c56aSWenyou Yang }
1452c62c56aSWenyou Yang 
1462c62c56aSWenyou Yang int atmel_pio4_get_pio_input(u32 port, u32 pin)
1472c62c56aSWenyou Yang {
1482c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1492c62c56aSWenyou Yang 	u32 reg, mask;
1502c62c56aSWenyou Yang 
151*46ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
1522c62c56aSWenyou Yang 		return -ENODEV;
1532c62c56aSWenyou Yang 
1542c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1552c62c56aSWenyou Yang 	if (!port_base)
1562c62c56aSWenyou Yang 		return -ENODEV;
1572c62c56aSWenyou Yang 
1582c62c56aSWenyou Yang 	mask = 0x01 << pin;
159*46ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO;
1602c62c56aSWenyou Yang 
1612c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1622c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1632c62c56aSWenyou Yang 
1642c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
1652c62c56aSWenyou Yang }
1662c62c56aSWenyou Yang 
1672c62c56aSWenyou Yang #ifdef CONFIG_DM_GPIO
1682c62c56aSWenyou Yang static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
1692c62c56aSWenyou Yang {
1702c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
1712c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
1722c62c56aSWenyou Yang 	u32 mask = 0x01 << offset;
173*46ed9381SWenyou Yang 	u32 reg = ATMEL_PIO_CFGR_FUNC_GPIO;
1742c62c56aSWenyou Yang 
1752c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1762c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1772c62c56aSWenyou Yang 
1782c62c56aSWenyou Yang 	return 0;
1792c62c56aSWenyou Yang }
1802c62c56aSWenyou Yang 
1812c62c56aSWenyou Yang static int atmel_pio4_direction_output(struct udevice *dev,
1822c62c56aSWenyou Yang 				       unsigned offset, int value)
1832c62c56aSWenyou Yang {
1842c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
1852c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
1862c62c56aSWenyou Yang 	u32 mask = 0x01 << offset;
187*46ed9381SWenyou Yang 	u32 reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
1882c62c56aSWenyou Yang 
1892c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1902c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1912c62c56aSWenyou Yang 
1922c62c56aSWenyou Yang 	if (value)
1932c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
1942c62c56aSWenyou Yang 	else
1952c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
1962c62c56aSWenyou Yang 
1972c62c56aSWenyou Yang 	return 0;
1982c62c56aSWenyou Yang }
1992c62c56aSWenyou Yang 
2002c62c56aSWenyou Yang static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
2012c62c56aSWenyou Yang {
2022c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
2032c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
2042c62c56aSWenyou Yang 	u32 mask = 0x01 << offset;
2052c62c56aSWenyou Yang 
2062c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
2072c62c56aSWenyou Yang }
2082c62c56aSWenyou Yang 
2092c62c56aSWenyou Yang static int atmel_pio4_set_value(struct udevice *dev,
2102c62c56aSWenyou Yang 				unsigned offset, int value)
2112c62c56aSWenyou Yang {
2122c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
2132c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
2142c62c56aSWenyou Yang 	u32 mask = 0x01 << offset;
2152c62c56aSWenyou Yang 
2162c62c56aSWenyou Yang 	if (value)
2172c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
2182c62c56aSWenyou Yang 	else
2192c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
2202c62c56aSWenyou Yang 
2212c62c56aSWenyou Yang 	return 0;
2222c62c56aSWenyou Yang }
2232c62c56aSWenyou Yang 
2242c62c56aSWenyou Yang static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
2252c62c56aSWenyou Yang {
2262c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
2272c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
2282c62c56aSWenyou Yang 	u32 mask = 0x01 << offset;
2292c62c56aSWenyou Yang 
2302c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
2312c62c56aSWenyou Yang 
2322c62c56aSWenyou Yang 	return (readl(&port_base->cfgr) &
233*46ed9381SWenyou Yang 		ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT;
2342c62c56aSWenyou Yang }
2352c62c56aSWenyou Yang 
2362c62c56aSWenyou Yang static const struct dm_gpio_ops atmel_pio4_ops = {
2372c62c56aSWenyou Yang 	.direction_input	= atmel_pio4_direction_input,
2382c62c56aSWenyou Yang 	.direction_output	= atmel_pio4_direction_output,
2392c62c56aSWenyou Yang 	.get_value		= atmel_pio4_get_value,
2402c62c56aSWenyou Yang 	.set_value		= atmel_pio4_set_value,
2412c62c56aSWenyou Yang 	.get_function		= atmel_pio4_get_function,
2422c62c56aSWenyou Yang };
2432c62c56aSWenyou Yang 
2442c62c56aSWenyou Yang static int atmel_pio4_probe(struct udevice *dev)
2452c62c56aSWenyou Yang {
2462c62c56aSWenyou Yang 	struct at91_port_platdata *plat = dev_get_platdata(dev);
2472c62c56aSWenyou Yang 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
2482c62c56aSWenyou Yang 
2492c62c56aSWenyou Yang 	uc_priv->bank_name = plat->bank_name;
250*46ed9381SWenyou Yang 	uc_priv->gpio_count = ATMEL_PIO_NPINS_PER_BANK;
2512c62c56aSWenyou Yang 
2522c62c56aSWenyou Yang 	return 0;
2532c62c56aSWenyou Yang }
2542c62c56aSWenyou Yang 
2552c62c56aSWenyou Yang U_BOOT_DRIVER(gpio_atmel_pio4) = {
2562c62c56aSWenyou Yang 	.name	= "gpio_atmel_pio4",
2572c62c56aSWenyou Yang 	.id	= UCLASS_GPIO,
2582c62c56aSWenyou Yang 	.ops	= &atmel_pio4_ops,
2592c62c56aSWenyou Yang 	.probe	= atmel_pio4_probe,
2602c62c56aSWenyou Yang };
2612c62c56aSWenyou Yang #endif
262