xref: /openbmc/u-boot/drivers/gpio/atmel_pio4.c (revision a821c4af)
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>
13ee3311dbSWenyou Yang #include <dm/root.h>
142c62c56aSWenyou Yang #include <asm/arch/hardware.h>
15ee3311dbSWenyou Yang #include <asm/gpio.h>
162c62c56aSWenyou Yang #include <mach/gpio.h>
172c62c56aSWenyou Yang #include <mach/atmel_pio4.h>
182c62c56aSWenyou Yang 
19ee3311dbSWenyou Yang DECLARE_GLOBAL_DATA_PTR;
20ee3311dbSWenyou Yang 
212c62c56aSWenyou Yang static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
222c62c56aSWenyou Yang {
232c62c56aSWenyou Yang 	struct atmel_pio4_port *base = NULL;
242c62c56aSWenyou Yang 
252c62c56aSWenyou Yang 	switch (port) {
262c62c56aSWenyou Yang 	case AT91_PIO_PORTA:
272c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
282c62c56aSWenyou Yang 		break;
292c62c56aSWenyou Yang 	case AT91_PIO_PORTB:
302c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
312c62c56aSWenyou Yang 		break;
322c62c56aSWenyou Yang 	case AT91_PIO_PORTC:
332c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
342c62c56aSWenyou Yang 		break;
352c62c56aSWenyou Yang 	case AT91_PIO_PORTD:
362c62c56aSWenyou Yang 		base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
372c62c56aSWenyou Yang 		break;
382c62c56aSWenyou Yang 	default:
392c62c56aSWenyou Yang 		printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
402c62c56aSWenyou Yang 		       port);
412c62c56aSWenyou Yang 		break;
422c62c56aSWenyou Yang 	}
432c62c56aSWenyou Yang 
442c62c56aSWenyou Yang 	return base;
452c62c56aSWenyou Yang }
462c62c56aSWenyou Yang 
472c62c56aSWenyou Yang static int atmel_pio4_config_io_func(u32 port, u32 pin,
482c62c56aSWenyou Yang 				     u32 func, u32 use_pullup)
492c62c56aSWenyou Yang {
502c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
512c62c56aSWenyou Yang 	u32 reg, mask;
522c62c56aSWenyou Yang 
5346ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
542c62c56aSWenyou Yang 		return -ENODEV;
552c62c56aSWenyou Yang 
562c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
572c62c56aSWenyou Yang 	if (!port_base)
582c62c56aSWenyou Yang 		return -ENODEV;
592c62c56aSWenyou Yang 
602c62c56aSWenyou Yang 	mask = 1 << pin;
612c62c56aSWenyou Yang 	reg = func;
6246ed9381SWenyou Yang 	reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0;
632c62c56aSWenyou Yang 
642c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
652c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
662c62c56aSWenyou Yang 
672c62c56aSWenyou Yang 	return 0;
682c62c56aSWenyou Yang }
692c62c56aSWenyou Yang 
702c62c56aSWenyou Yang int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup)
712c62c56aSWenyou Yang {
722c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
7346ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_GPIO,
742c62c56aSWenyou Yang 					 use_pullup);
752c62c56aSWenyou Yang }
762c62c56aSWenyou Yang 
772c62c56aSWenyou Yang int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup)
782c62c56aSWenyou Yang {
792c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
8046ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_A,
812c62c56aSWenyou Yang 					 use_pullup);
822c62c56aSWenyou Yang }
832c62c56aSWenyou Yang 
842c62c56aSWenyou Yang int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup)
852c62c56aSWenyou Yang {
862c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
8746ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_B,
882c62c56aSWenyou Yang 					 use_pullup);
892c62c56aSWenyou Yang }
902c62c56aSWenyou Yang 
912c62c56aSWenyou Yang int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup)
922c62c56aSWenyou Yang {
932c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
9446ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_C,
952c62c56aSWenyou Yang 					 use_pullup);
962c62c56aSWenyou Yang }
972c62c56aSWenyou Yang 
982c62c56aSWenyou Yang int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup)
992c62c56aSWenyou Yang {
1002c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
10146ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_D,
1022c62c56aSWenyou Yang 					 use_pullup);
1032c62c56aSWenyou Yang }
1042c62c56aSWenyou Yang 
1052c62c56aSWenyou Yang int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup)
1062c62c56aSWenyou Yang {
1072c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
10846ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_E,
1092c62c56aSWenyou Yang 					 use_pullup);
1102c62c56aSWenyou Yang }
1112c62c56aSWenyou Yang 
1122c62c56aSWenyou Yang int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup)
1132c62c56aSWenyou Yang {
1142c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
11546ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_F,
1162c62c56aSWenyou Yang 					 use_pullup);
1172c62c56aSWenyou Yang }
1182c62c56aSWenyou Yang 
1192c62c56aSWenyou Yang int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup)
1202c62c56aSWenyou Yang {
1212c62c56aSWenyou Yang 	return atmel_pio4_config_io_func(port, pin,
12246ed9381SWenyou Yang 					 ATMEL_PIO_CFGR_FUNC_PERIPH_G,
1232c62c56aSWenyou Yang 					 use_pullup);
1242c62c56aSWenyou Yang }
1252c62c56aSWenyou Yang 
1262c62c56aSWenyou Yang int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
1272c62c56aSWenyou Yang {
1282c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1292c62c56aSWenyou Yang 	u32 reg, mask;
1302c62c56aSWenyou Yang 
13146ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
1322c62c56aSWenyou Yang 		return -ENODEV;
1332c62c56aSWenyou Yang 
1342c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1352c62c56aSWenyou Yang 	if (!port_base)
1362c62c56aSWenyou Yang 		return -ENODEV;
1372c62c56aSWenyou Yang 
1382c62c56aSWenyou Yang 	mask = 0x01 << pin;
13946ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
1402c62c56aSWenyou Yang 
1412c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1422c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1432c62c56aSWenyou Yang 
1442c62c56aSWenyou Yang 	if (value)
1452c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
1462c62c56aSWenyou Yang 	else
1472c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
1482c62c56aSWenyou Yang 
1492c62c56aSWenyou Yang 	return 0;
1502c62c56aSWenyou Yang }
1512c62c56aSWenyou Yang 
1522c62c56aSWenyou Yang int atmel_pio4_get_pio_input(u32 port, u32 pin)
1532c62c56aSWenyou Yang {
1542c62c56aSWenyou Yang 	struct atmel_pio4_port *port_base;
1552c62c56aSWenyou Yang 	u32 reg, mask;
1562c62c56aSWenyou Yang 
15746ed9381SWenyou Yang 	if (pin >= ATMEL_PIO_NPINS_PER_BANK)
1582c62c56aSWenyou Yang 		return -ENODEV;
1592c62c56aSWenyou Yang 
1602c62c56aSWenyou Yang 	port_base = atmel_pio4_port_base(port);
1612c62c56aSWenyou Yang 	if (!port_base)
1622c62c56aSWenyou Yang 		return -ENODEV;
1632c62c56aSWenyou Yang 
1642c62c56aSWenyou Yang 	mask = 0x01 << pin;
16546ed9381SWenyou Yang 	reg = ATMEL_PIO_CFGR_FUNC_GPIO;
1662c62c56aSWenyou Yang 
1672c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
1682c62c56aSWenyou Yang 	writel(reg, &port_base->cfgr);
1692c62c56aSWenyou Yang 
1702c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
1712c62c56aSWenyou Yang }
1722c62c56aSWenyou Yang 
1732c62c56aSWenyou Yang #ifdef CONFIG_DM_GPIO
174ee3311dbSWenyou Yang 
175ee3311dbSWenyou Yang struct atmel_pioctrl_data {
176ee3311dbSWenyou Yang 	u32 nbanks;
177ee3311dbSWenyou Yang };
178ee3311dbSWenyou Yang 
179ee3311dbSWenyou Yang struct atmel_pio4_platdata {
180ee3311dbSWenyou Yang 	struct atmel_pio4_port *reg_base;
181ee3311dbSWenyou Yang };
182ee3311dbSWenyou Yang 
183ee3311dbSWenyou Yang static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
184ee3311dbSWenyou Yang 						    u32 bank)
185ee3311dbSWenyou Yang {
186ee3311dbSWenyou Yang 	struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
187ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base =
188ee3311dbSWenyou Yang 			(struct atmel_pio4_port *)((u32)plat->reg_base +
189ee3311dbSWenyou Yang 			ATMEL_PIO_BANK_OFFSET * bank);
190ee3311dbSWenyou Yang 
191ee3311dbSWenyou Yang 	return port_base;
192ee3311dbSWenyou Yang }
193ee3311dbSWenyou Yang 
1942c62c56aSWenyou Yang static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
1952c62c56aSWenyou Yang {
196ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
197ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
198ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
199ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2002c62c56aSWenyou Yang 
2012c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
202ee3311dbSWenyou Yang 
203ee3311dbSWenyou Yang 	clrbits_le32(&port_base->cfgr,
204ee3311dbSWenyou Yang 		     ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK);
2052c62c56aSWenyou Yang 
2062c62c56aSWenyou Yang 	return 0;
2072c62c56aSWenyou Yang }
2082c62c56aSWenyou Yang 
2092c62c56aSWenyou Yang static int atmel_pio4_direction_output(struct udevice *dev,
2102c62c56aSWenyou Yang 				       unsigned offset, int value)
2112c62c56aSWenyou Yang {
212ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
213ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
214ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
215ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2162c62c56aSWenyou Yang 
2172c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
218ee3311dbSWenyou Yang 
219ee3311dbSWenyou Yang 	clrsetbits_le32(&port_base->cfgr,
220ee3311dbSWenyou Yang 			ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK);
2212c62c56aSWenyou Yang 
2222c62c56aSWenyou Yang 	if (value)
2232c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
2242c62c56aSWenyou Yang 	else
2252c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
2262c62c56aSWenyou Yang 
2272c62c56aSWenyou Yang 	return 0;
2282c62c56aSWenyou Yang }
2292c62c56aSWenyou Yang 
2302c62c56aSWenyou Yang static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
2312c62c56aSWenyou Yang {
232ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
233ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
234ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
235ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2362c62c56aSWenyou Yang 
2372c62c56aSWenyou Yang 	return (readl(&port_base->pdsr) & mask) ? 1 : 0;
2382c62c56aSWenyou Yang }
2392c62c56aSWenyou Yang 
2402c62c56aSWenyou Yang static int atmel_pio4_set_value(struct udevice *dev,
2412c62c56aSWenyou Yang 				unsigned offset, int value)
2422c62c56aSWenyou Yang {
243ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
244ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
245ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
246ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2472c62c56aSWenyou Yang 
2482c62c56aSWenyou Yang 	if (value)
2492c62c56aSWenyou Yang 		writel(mask, &port_base->sodr);
2502c62c56aSWenyou Yang 	else
2512c62c56aSWenyou Yang 		writel(mask, &port_base->codr);
2522c62c56aSWenyou Yang 
2532c62c56aSWenyou Yang 	return 0;
2542c62c56aSWenyou Yang }
2552c62c56aSWenyou Yang 
2562c62c56aSWenyou Yang static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
2572c62c56aSWenyou Yang {
258ee3311dbSWenyou Yang 	u32 bank = ATMEL_PIO_BANK(offset);
259ee3311dbSWenyou Yang 	u32 line = ATMEL_PIO_LINE(offset);
260ee3311dbSWenyou Yang 	struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
261ee3311dbSWenyou Yang 	u32 mask = BIT(line);
2622c62c56aSWenyou Yang 
2632c62c56aSWenyou Yang 	writel(mask, &port_base->mskr);
2642c62c56aSWenyou Yang 
2652c62c56aSWenyou Yang 	return (readl(&port_base->cfgr) &
26646ed9381SWenyou Yang 		ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT;
2672c62c56aSWenyou Yang }
2682c62c56aSWenyou Yang 
2692c62c56aSWenyou Yang static const struct dm_gpio_ops atmel_pio4_ops = {
2702c62c56aSWenyou Yang 	.direction_input	= atmel_pio4_direction_input,
2712c62c56aSWenyou Yang 	.direction_output	= atmel_pio4_direction_output,
2722c62c56aSWenyou Yang 	.get_value		= atmel_pio4_get_value,
2732c62c56aSWenyou Yang 	.set_value		= atmel_pio4_set_value,
2742c62c56aSWenyou Yang 	.get_function		= atmel_pio4_get_function,
2752c62c56aSWenyou Yang };
2762c62c56aSWenyou Yang 
277ee3311dbSWenyou Yang static int atmel_pio4_bind(struct udevice *dev)
278ee3311dbSWenyou Yang {
279e160f7d4SSimon Glass 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), false);
280ee3311dbSWenyou Yang }
281ee3311dbSWenyou Yang 
2822c62c56aSWenyou Yang static int atmel_pio4_probe(struct udevice *dev)
2832c62c56aSWenyou Yang {
284ee3311dbSWenyou Yang 	struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
2852c62c56aSWenyou Yang 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
286ee3311dbSWenyou Yang 	struct atmel_pioctrl_data *pioctrl_data;
287ee3311dbSWenyou Yang 	struct clk clk;
288ee3311dbSWenyou Yang 	fdt_addr_t addr_base;
289ee3311dbSWenyou Yang 	u32 nbanks;
290ee3311dbSWenyou Yang 	int ret;
2912c62c56aSWenyou Yang 
292ee3311dbSWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk);
293ee3311dbSWenyou Yang 	if (ret)
294ee3311dbSWenyou Yang 		return ret;
295ee3311dbSWenyou Yang 
296ee3311dbSWenyou Yang 	ret = clk_enable(&clk);
297ee3311dbSWenyou Yang 	if (ret)
298ee3311dbSWenyou Yang 		return ret;
299ee3311dbSWenyou Yang 
300ee3311dbSWenyou Yang 	clk_free(&clk);
301ee3311dbSWenyou Yang 
302*a821c4afSSimon Glass 	addr_base = devfdt_get_addr(dev);
303ee3311dbSWenyou Yang 	if (addr_base == FDT_ADDR_T_NONE)
304ee3311dbSWenyou Yang 		return -EINVAL;
305ee3311dbSWenyou Yang 
306ee3311dbSWenyou Yang 	plat->reg_base = (struct atmel_pio4_port *)addr_base;
307ee3311dbSWenyou Yang 
308ee3311dbSWenyou Yang 	pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev);
309ee3311dbSWenyou Yang 	nbanks = pioctrl_data->nbanks;
310ee3311dbSWenyou Yang 
311e160f7d4SSimon Glass 	uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev),
312e160f7d4SSimon Glass 					  NULL);
313ee3311dbSWenyou Yang 	uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK;
3142c62c56aSWenyou Yang 
3152c62c56aSWenyou Yang 	return 0;
3162c62c56aSWenyou Yang }
3172c62c56aSWenyou Yang 
318ee3311dbSWenyou Yang /*
319ee3311dbSWenyou Yang  * The number of banks can be different from a SoC to another one.
320ee3311dbSWenyou Yang  * We can have up to 16 banks.
321ee3311dbSWenyou Yang  */
322ee3311dbSWenyou Yang static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = {
323ee3311dbSWenyou Yang 	.nbanks	= 4,
324ee3311dbSWenyou Yang };
325ee3311dbSWenyou Yang 
326ee3311dbSWenyou Yang static const struct udevice_id atmel_pio4_ids[] = {
327ee3311dbSWenyou Yang 	{
328ee3311dbSWenyou Yang 		.compatible = "atmel,sama5d2-gpio",
329ee3311dbSWenyou Yang 		.data = (ulong)&atmel_sama5d2_pioctrl_data,
330ee3311dbSWenyou Yang 	},
331ee3311dbSWenyou Yang 	{}
332ee3311dbSWenyou Yang };
333ee3311dbSWenyou Yang 
3342c62c56aSWenyou Yang U_BOOT_DRIVER(gpio_atmel_pio4) = {
3352c62c56aSWenyou Yang 	.name	= "gpio_atmel_pio4",
3362c62c56aSWenyou Yang 	.id	= UCLASS_GPIO,
3372c62c56aSWenyou Yang 	.ops	= &atmel_pio4_ops,
3382c62c56aSWenyou Yang 	.probe	= atmel_pio4_probe,
339ee3311dbSWenyou Yang 	.bind	= atmel_pio4_bind,
340ee3311dbSWenyou Yang 	.of_match = atmel_pio4_ids,
341ee3311dbSWenyou Yang 	.platdata_auto_alloc_size = sizeof(struct atmel_pio4_platdata),
3422c62c56aSWenyou Yang };
343ee3311dbSWenyou Yang 
3442c62c56aSWenyou Yang #endif
345