xref: /openbmc/u-boot/drivers/gpio/atmel_pio4.c (revision 7c84319a)
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>
10ee3311dbSWenyou Yang #include <clk.h>
112c62c56aSWenyou Yang #include <dm.h>
12ee3311dbSWenyou Yang #include <fdtdec.h>
132c62c56aSWenyou Yang #include <asm/arch/hardware.h>
14ee3311dbSWenyou Yang #include <asm/gpio.h>
152c62c56aSWenyou Yang #include <mach/gpio.h>
162c62c56aSWenyou Yang #include <mach/atmel_pio4.h>
172c62c56aSWenyou Yang 
18ee3311dbSWenyou Yang DECLARE_GLOBAL_DATA_PTR;
19ee3311dbSWenyou Yang 
202c62c56aSWenyou Yang static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
212c62c56aSWenyou Yang {
222c62c56aSWenyou Yang 	struct atmel_pio4_port *base = NULL;
232c62c56aSWenyou Yang 
242c62c56aSWenyou Yang 	switch (port) {
252c62c56aSWenyou Yang 	case AT91_PIO_PORTA:
262c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
272c62c56aSWenyou Yang 		break;
282c62c56aSWenyou Yang 	case AT91_PIO_PORTB:
292c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
302c62c56aSWenyou Yang 		break;
312c62c56aSWenyou Yang 	case AT91_PIO_PORTC:
322c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
332c62c56aSWenyou Yang 		break;
342c62c56aSWenyou Yang 	case AT91_PIO_PORTD:
352c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
362c62c56aSWenyou Yang 		break;
372c62c56aSWenyou Yang 	default:
382c62c56aSWenyou Yang 		printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
392c62c56aSWenyou Yang 		       port);
402c62c56aSWenyou Yang 		break;
412c62c56aSWenyou Yang 	}
422c62c56aSWenyou Yang 
432c62c56aSWenyou Yang 	return base;
442c62c56aSWenyou Yang }
452c62c56aSWenyou Yang 
462c62c56aSWenyou Yang static int atmel_pio4_config_io_func(u32 port, u32 pin,
472c62c56aSWenyou Yang 				     u32 func, u32 use_pullup)
482c62c56aSWenyou Yang {
492c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
502c62c56aSWenyou Yang 	u32 reg, mask;
512c62c56aSWenyou Yang 
5246ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
53*7c84319aSSimon Glass 		return -EINVAL;
542c62c56aSWenyou Yang 
552c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
562c62c56aSWenyou Yang 	if (!port_base)
57*7c84319aSSimon Glass 		return -EINVAL;
582c62c56aSWenyou Yang 
592c62c56aSWenyou Yang 	mask = 1 << pin;
602c62c56aSWenyou Yang 	reg = func;
6146ed9381SWenyou Yang 	reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0;
622c62c56aSWenyou Yang 
632c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
642c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
652c62c56aSWenyou Yang 
662c62c56aSWenyou Yang 	return 0;
672c62c56aSWenyou Yang }
682c62c56aSWenyou Yang 
692c62c56aSWenyou Yang int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup)
702c62c56aSWenyou Yang {
712c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
7246ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_GPIO,
732c62c56aSWenyou Yang 					 use_pullup);
742c62c56aSWenyou Yang }
752c62c56aSWenyou Yang 
762c62c56aSWenyou Yang int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup)
772c62c56aSWenyou Yang {
782c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
7946ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_A,
802c62c56aSWenyou Yang 					 use_pullup);
812c62c56aSWenyou Yang }
822c62c56aSWenyou Yang 
832c62c56aSWenyou Yang int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup)
842c62c56aSWenyou Yang {
852c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
8646ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_B,
872c62c56aSWenyou Yang 					 use_pullup);
882c62c56aSWenyou Yang }
892c62c56aSWenyou Yang 
902c62c56aSWenyou Yang int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup)
912c62c56aSWenyou Yang {
922c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
9346ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_C,
942c62c56aSWenyou Yang 					 use_pullup);
952c62c56aSWenyou Yang }
962c62c56aSWenyou Yang 
972c62c56aSWenyou Yang int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup)
982c62c56aSWenyou Yang {
992c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
10046ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_D,
1012c62c56aSWenyou Yang 					 use_pullup);
1022c62c56aSWenyou Yang }
1032c62c56aSWenyou Yang 
1042c62c56aSWenyou Yang int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup)
1052c62c56aSWenyou Yang {
1062c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
10746ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_E,
1082c62c56aSWenyou Yang 					 use_pullup);
1092c62c56aSWenyou Yang }
1102c62c56aSWenyou Yang 
1112c62c56aSWenyou Yang int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup)
1122c62c56aSWenyou Yang {
1132c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
11446ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_F,
1152c62c56aSWenyou Yang 					 use_pullup);
1162c62c56aSWenyou Yang }
1172c62c56aSWenyou Yang 
1182c62c56aSWenyou Yang int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup)
1192c62c56aSWenyou Yang {
1202c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
12146ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_G,
1222c62c56aSWenyou Yang 					 use_pullup);
1232c62c56aSWenyou Yang }
1242c62c56aSWenyou Yang 
1252c62c56aSWenyou Yang int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
1262c62c56aSWenyou Yang {
1272c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1282c62c56aSWenyou Yang 	u32 reg, mask;
1292c62c56aSWenyou Yang 
13046ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
131*7c84319aSSimon Glass 		return -EINVAL;
1322c62c56aSWenyou Yang 
1332c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1342c62c56aSWenyou Yang 	if (!port_base)
135*7c84319aSSimon Glass 		return -EINVAL;
1362c62c56aSWenyou Yang 
1372c62c56aSWenyou Yang 	mask = 0x01 << pin;
13846ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
1392c62c56aSWenyou Yang 
1402c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1412c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1422c62c56aSWenyou Yang 
1432c62c56aSWenyou Yang 	if (value)
1442c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
1452c62c56aSWenyou Yang 	else
1462c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
1472c62c56aSWenyou Yang 
1482c62c56aSWenyou Yang 	return 0;
1492c62c56aSWenyou Yang }
1502c62c56aSWenyou Yang 
1512c62c56aSWenyou Yang int atmel_pio4_get_pio_input(u32 port, u32 pin)
1522c62c56aSWenyou Yang {
1532c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1542c62c56aSWenyou Yang 	u32 reg, mask;
1552c62c56aSWenyou Yang 
15646ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
157*7c84319aSSimon Glass 		return -EINVAL;
1582c62c56aSWenyou Yang 
1592c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1602c62c56aSWenyou Yang 	if (!port_base)
161*7c84319aSSimon Glass 		return -EINVAL;
1622c62c56aSWenyou Yang 
1632c62c56aSWenyou Yang 	mask = 0x01 << pin;
16446ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO;
1652c62c56aSWenyou Yang 
1662c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1672c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1682c62c56aSWenyou Yang 
1692c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
1702c62c56aSWenyou Yang }
1712c62c56aSWenyou Yang 
1722c62c56aSWenyou Yang #ifdef CONFIG_DM_GPIO
173ee3311dbSWenyou Yang 
174ee3311dbSWenyou Yang struct atmel_pioctrl_data {
175ee3311dbSWenyou Yang 	u32 nbanks;
176ee3311dbSWenyou Yang };
177ee3311dbSWenyou Yang 
178ee3311dbSWenyou Yang struct atmel_pio4_platdata {
179ee3311dbSWenyou Yang 	struct atmel_pio4_port *reg_base;
180ee3311dbSWenyou Yang };
181ee3311dbSWenyou Yang 
182ee3311dbSWenyou Yang static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
183ee3311dbSWenyou Yang 						    u32 bank)
184ee3311dbSWenyou Yang {
185ee3311dbSWenyou Yang 	struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
186ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base =
187ee3311dbSWenyou Yang 			(struct atmel_pio4_port *)((u32)plat->reg_base +
188ee3311dbSWenyou Yang 			ATMEL_PIO_BANK_OFFSET * bank);
189ee3311dbSWenyou Yang 
190ee3311dbSWenyou Yang 	return port_base;
191ee3311dbSWenyou Yang }
192ee3311dbSWenyou Yang 
1932c62c56aSWenyou Yang static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
1942c62c56aSWenyou Yang {
195ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
196ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
197ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
198ee3311dbSWenyou Yang 	u32 mask = BIT(line);
1992c62c56aSWenyou Yang 
2002c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
201ee3311dbSWenyou Yang 
202ee3311dbSWenyou Yang 	clrbits_le32(&port_base->cfgr,
203ee3311dbSWenyou Yang 		     ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK);
2042c62c56aSWenyou Yang 
2052c62c56aSWenyou Yang 	return 0;
2062c62c56aSWenyou Yang }
2072c62c56aSWenyou Yang 
2082c62c56aSWenyou Yang static int atmel_pio4_direction_output(struct udevice *dev,
2092c62c56aSWenyou Yang 				       unsigned offset, int value)
2102c62c56aSWenyou Yang {
211ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
212ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
213ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
214ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2152c62c56aSWenyou Yang 
2162c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
217ee3311dbSWenyou Yang 
218ee3311dbSWenyou Yang 	clrsetbits_le32(&port_base->cfgr,
219ee3311dbSWenyou Yang 			ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK);
2202c62c56aSWenyou Yang 
2212c62c56aSWenyou Yang 	if (value)
2222c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
2232c62c56aSWenyou Yang 	else
2242c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
2252c62c56aSWenyou Yang 
2262c62c56aSWenyou Yang 	return 0;
2272c62c56aSWenyou Yang }
2282c62c56aSWenyou Yang 
2292c62c56aSWenyou Yang static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
2302c62c56aSWenyou Yang {
231ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
232ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
233ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
234ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2352c62c56aSWenyou Yang 
2362c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
2372c62c56aSWenyou Yang }
2382c62c56aSWenyou Yang 
2392c62c56aSWenyou Yang static int atmel_pio4_set_value(struct udevice *dev,
2402c62c56aSWenyou Yang 				unsigned offset, int value)
2412c62c56aSWenyou Yang {
242ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
243ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
244ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
245ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2462c62c56aSWenyou Yang 
2472c62c56aSWenyou Yang 	if (value)
2482c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
2492c62c56aSWenyou Yang 	else
2502c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
2512c62c56aSWenyou Yang 
2522c62c56aSWenyou Yang 	return 0;
2532c62c56aSWenyou Yang }
2542c62c56aSWenyou Yang 
2552c62c56aSWenyou Yang static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
2562c62c56aSWenyou Yang {
257ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
258ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
259ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
260ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2612c62c56aSWenyou Yang 
2622c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
2632c62c56aSWenyou Yang 
2642c62c56aSWenyou Yang 	return (readl(&port_base->cfgr) &
26546ed9381SWenyou Yang 		ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT;
2662c62c56aSWenyou Yang }
2672c62c56aSWenyou Yang 
2682c62c56aSWenyou Yang static const struct dm_gpio_ops atmel_pio4_ops = {
2692c62c56aSWenyou Yang 	.direction_input	= atmel_pio4_direction_input,
2702c62c56aSWenyou Yang 	.direction_output	= atmel_pio4_direction_output,
2712c62c56aSWenyou Yang 	.get_value		= atmel_pio4_get_value,
2722c62c56aSWenyou Yang 	.set_value		= atmel_pio4_set_value,
2732c62c56aSWenyou Yang 	.get_function		= atmel_pio4_get_function,
2742c62c56aSWenyou Yang };
2752c62c56aSWenyou Yang 
276ee3311dbSWenyou Yang static int atmel_pio4_bind(struct udevice *dev)
277ee3311dbSWenyou Yang {
27879fc0c78SSimon Glass 	return dm_scan_fdt_dev(dev);
279ee3311dbSWenyou Yang }
280ee3311dbSWenyou Yang 
2812c62c56aSWenyou Yang static int atmel_pio4_probe(struct udevice *dev)
2822c62c56aSWenyou Yang {
283ee3311dbSWenyou Yang 	struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
2842c62c56aSWenyou Yang 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
285ee3311dbSWenyou Yang 	struct atmel_pioctrl_data *pioctrl_data;
286ee3311dbSWenyou Yang 	struct clk clk;
287ee3311dbSWenyou Yang 	fdt_addr_t addr_base;
288ee3311dbSWenyou Yang 	u32 nbanks;
289ee3311dbSWenyou Yang 	int ret;
2902c62c56aSWenyou Yang 
291ee3311dbSWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk);
292ee3311dbSWenyou Yang 	if (ret)
293ee3311dbSWenyou Yang 		return ret;
294ee3311dbSWenyou Yang 
295ee3311dbSWenyou Yang 	ret = clk_enable(&clk);
296ee3311dbSWenyou Yang 	if (ret)
297ee3311dbSWenyou Yang 		return ret;
298ee3311dbSWenyou Yang 
299ee3311dbSWenyou Yang 	clk_free(&clk);
300ee3311dbSWenyou Yang 
301a821c4afSSimon Glass 	addr_base = devfdt_get_addr(dev);
302ee3311dbSWenyou Yang 	if (addr_base == FDT_ADDR_T_NONE)
303ee3311dbSWenyou Yang 		return -EINVAL;
304ee3311dbSWenyou Yang 
305ee3311dbSWenyou Yang 	plat->reg_base = (struct atmel_pio4_port *)addr_base;
306ee3311dbSWenyou Yang 
307ee3311dbSWenyou Yang 	pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev);
308ee3311dbSWenyou Yang 	nbanks = pioctrl_data->nbanks;
309ee3311dbSWenyou Yang 
310e160f7d4SSimon Glass 	uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev),
311e160f7d4SSimon Glass 					  NULL);
312ee3311dbSWenyou Yang 	uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK;
3132c62c56aSWenyou Yang 
3142c62c56aSWenyou Yang 	return 0;
3152c62c56aSWenyou Yang }
3162c62c56aSWenyou Yang 
317ee3311dbSWenyou Yang /*
318ee3311dbSWenyou Yang  * The number of banks can be different from a SoC to another one.
319ee3311dbSWenyou Yang  * We can have up to 16 banks.
320ee3311dbSWenyou Yang  */
321ee3311dbSWenyou Yang static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = {
322ee3311dbSWenyou Yang 	.nbanks	= 4,
323ee3311dbSWenyou Yang };
324ee3311dbSWenyou Yang 
325ee3311dbSWenyou Yang static const struct udevice_id atmel_pio4_ids[] = {
326ee3311dbSWenyou Yang 	{
327ee3311dbSWenyou Yang 		.compatible = "atmel,sama5d2-gpio",
328ee3311dbSWenyou Yang 		.data = (ulong)&atmel_sama5d2_pioctrl_data,
329ee3311dbSWenyou Yang 	},
330ee3311dbSWenyou Yang 	{}
331ee3311dbSWenyou Yang };
332ee3311dbSWenyou Yang 
3332c62c56aSWenyou Yang U_BOOT_DRIVER(gpio_atmel_pio4) = {
3342c62c56aSWenyou Yang 	.name	= "gpio_atmel_pio4",
3352c62c56aSWenyou Yang 	.id	= UCLASS_GPIO,
3362c62c56aSWenyou Yang 	.ops	= &atmel_pio4_ops,
3372c62c56aSWenyou Yang 	.probe	= atmel_pio4_probe,
338ee3311dbSWenyou Yang 	.bind	= atmel_pio4_bind,
339ee3311dbSWenyou Yang 	.of_match = atmel_pio4_ids,
340ee3311dbSWenyou Yang 	.platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata),
3412c62c56aSWenyou Yang };
342ee3311dbSWenyou Yang 
3432c62c56aSWenyou Yang #endif
344