xref: /openbmc/u-boot/drivers/gpio/at91_gpio.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2ea8fbba7SJens Scharsig /*
339b787ecSBo Shen  * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
4ea8fbba7SJens Scharsig  *
5ea8fbba7SJens Scharsig  * Copyright (C) 2009 Jens Scharsig (js_at_ng@scharsoft.de)
6ea8fbba7SJens Scharsig  *
7ea8fbba7SJens Scharsig  *  Copyright (C) 2005 HP Labs
8ea8fbba7SJens Scharsig  */
9ea8fbba7SJens Scharsig 
10ea8fbba7SJens Scharsig #include <config.h>
11ea8fbba7SJens Scharsig #include <common.h>
12f2f3c157SWenyou Yang #include <clk.h>
13918354b1SSimon Glass #include <dm.h>
1486592f60SReinhard Meyer #include <asm/io.h>
151ace4022SAlexey Brodkin #include <linux/sizes.h>
16918354b1SSimon Glass #include <asm/gpio.h>
17ea8fbba7SJens Scharsig #include <asm/arch/hardware.h>
18ea8fbba7SJens Scharsig #include <asm/arch/at91_pio.h>
19918354b1SSimon Glass 
20918354b1SSimon Glass #define GPIO_PER_BANK	32
21ea8fbba7SJens Scharsig 
at91_pio_get_port(unsigned port)224bc9b7a5SBo Shen static struct at91_port *at91_pio_get_port(unsigned port)
234bc9b7a5SBo Shen {
244bc9b7a5SBo Shen 	switch (port) {
254bc9b7a5SBo Shen 	case AT91_PIO_PORTA:
264bc9b7a5SBo Shen 		return (struct at91_port *)ATMEL_BASE_PIOA;
274bc9b7a5SBo Shen 	case AT91_PIO_PORTB:
284bc9b7a5SBo Shen 		return (struct at91_port *)ATMEL_BASE_PIOB;
294bc9b7a5SBo Shen 	case AT91_PIO_PORTC:
304bc9b7a5SBo Shen 		return (struct at91_port *)ATMEL_BASE_PIOC;
314bc9b7a5SBo Shen #if (ATMEL_PIO_PORTS > 3)
324bc9b7a5SBo Shen 	case AT91_PIO_PORTD:
334bc9b7a5SBo Shen 		return (struct at91_port *)ATMEL_BASE_PIOD;
344bc9b7a5SBo Shen #if (ATMEL_PIO_PORTS > 4)
354bc9b7a5SBo Shen 	case AT91_PIO_PORTE:
364bc9b7a5SBo Shen 		return (struct at91_port *)ATMEL_BASE_PIOE;
374bc9b7a5SBo Shen #endif
384bc9b7a5SBo Shen #endif
394bc9b7a5SBo Shen 	default:
407d82d897SWu, Josh 		printf("Error: at91_gpio: Fail to get PIO base!\n");
414bc9b7a5SBo Shen 		return NULL;
424bc9b7a5SBo Shen 	}
434bc9b7a5SBo Shen }
444bc9b7a5SBo Shen 
at91_set_port_pullup(struct at91_port * at91_port,unsigned offset,int use_pullup)45918354b1SSimon Glass static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset,
46918354b1SSimon Glass 				 int use_pullup)
47918354b1SSimon Glass {
48918354b1SSimon Glass 	u32 mask;
49918354b1SSimon Glass 
50918354b1SSimon Glass 	mask = 1 << offset;
51918354b1SSimon Glass 	if (use_pullup)
52918354b1SSimon Glass 		writel(mask, &at91_port->puer);
53918354b1SSimon Glass 	else
54918354b1SSimon Glass 		writel(mask, &at91_port->pudr);
55918354b1SSimon Glass 	writel(mask, &at91_port->per);
56918354b1SSimon Glass }
57918354b1SSimon Glass 
at91_set_pio_pullup(unsigned port,unsigned pin,int use_pullup)58ea8fbba7SJens Scharsig int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
59ea8fbba7SJens Scharsig {
604bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
61ea8fbba7SJens Scharsig 
62918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK))
63918354b1SSimon Glass 		at91_set_port_pullup(at91_port, pin, use_pullup);
644bc9b7a5SBo Shen 
65ea8fbba7SJens Scharsig 	return 0;
66ea8fbba7SJens Scharsig }
67ea8fbba7SJens Scharsig 
68ea8fbba7SJens Scharsig /*
69ea8fbba7SJens Scharsig  * mux the pin to the "GPIO" peripheral role.
70ea8fbba7SJens Scharsig  */
at91_set_pio_periph(unsigned port,unsigned pin,int use_pullup)71ea8fbba7SJens Scharsig int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup)
72ea8fbba7SJens Scharsig {
734bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
74ea8fbba7SJens Scharsig 	u32 mask;
75ea8fbba7SJens Scharsig 
76918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
77ea8fbba7SJens Scharsig 		mask = 1 << pin;
784bc9b7a5SBo Shen 		writel(mask, &at91_port->idr);
79ea8fbba7SJens Scharsig 		at91_set_pio_pullup(port, pin, use_pullup);
804bc9b7a5SBo Shen 		writel(mask, &at91_port->per);
81ea8fbba7SJens Scharsig 	}
824bc9b7a5SBo Shen 
83ea8fbba7SJens Scharsig 	return 0;
84ea8fbba7SJens Scharsig }
85ea8fbba7SJens Scharsig 
86ea8fbba7SJens Scharsig /*
87ea8fbba7SJens Scharsig  * mux the pin to the "A" internal peripheral role.
88ea8fbba7SJens Scharsig  */
at91_set_a_periph(unsigned port,unsigned pin,int use_pullup)89ea8fbba7SJens Scharsig int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup)
90ea8fbba7SJens Scharsig {
914bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
92ea8fbba7SJens Scharsig 	u32 mask;
93ea8fbba7SJens Scharsig 
94918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
95ea8fbba7SJens Scharsig 		mask = 1 << pin;
964bc9b7a5SBo Shen 		writel(mask, &at91_port->idr);
97ea8fbba7SJens Scharsig 		at91_set_pio_pullup(port, pin, use_pullup);
982dc63f73SWenyou Yang 		writel(mask, &at91_port->mux.pio2.asr);
994bc9b7a5SBo Shen 		writel(mask, &at91_port->pdr);
100ea8fbba7SJens Scharsig 	}
1014bc9b7a5SBo Shen 
102ea8fbba7SJens Scharsig 	return 0;
103ea8fbba7SJens Scharsig }
104ea8fbba7SJens Scharsig 
105ea8fbba7SJens Scharsig /*
106ea8fbba7SJens Scharsig  * mux the pin to the "B" internal peripheral role.
107ea8fbba7SJens Scharsig  */
at91_set_b_periph(unsigned port,unsigned pin,int use_pullup)108ea8fbba7SJens Scharsig int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup)
109ea8fbba7SJens Scharsig {
1104bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
111ea8fbba7SJens Scharsig 	u32 mask;
112ea8fbba7SJens Scharsig 
113918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
114ea8fbba7SJens Scharsig 		mask = 1 << pin;
1154bc9b7a5SBo Shen 		writel(mask, &at91_port->idr);
116ea8fbba7SJens Scharsig 		at91_set_pio_pullup(port, pin, use_pullup);
1172dc63f73SWenyou Yang 		writel(mask, &at91_port->mux.pio2.bsr);
1184bc9b7a5SBo Shen 		writel(mask, &at91_port->pdr);
119ea8fbba7SJens Scharsig 	}
1204bc9b7a5SBo Shen 
121ea8fbba7SJens Scharsig 	return 0;
122ea8fbba7SJens Scharsig }
123ea8fbba7SJens Scharsig 
1242b3b1c66SBo Shen /*
1252dc63f73SWenyou Yang  * mux the pin to the "A" internal peripheral role.
1262b3b1c66SBo Shen  */
at91_pio3_set_a_periph(unsigned port,unsigned pin,int use_pullup)1272dc63f73SWenyou Yang int at91_pio3_set_a_periph(unsigned port, unsigned pin, int use_pullup)
1282b3b1c66SBo Shen {
1294bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
1302b3b1c66SBo Shen 	u32 mask;
1312b3b1c66SBo Shen 
132918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
1332b3b1c66SBo Shen 		mask = 1 << pin;
1344bc9b7a5SBo Shen 		writel(mask, &at91_port->idr);
1352b3b1c66SBo Shen 		at91_set_pio_pullup(port, pin, use_pullup);
1362dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask,
1372dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr1);
1382dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask,
1392dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr2);
1402dc63f73SWenyou Yang 
1412dc63f73SWenyou Yang 		writel(mask, &at91_port->pdr);
1422dc63f73SWenyou Yang 	}
1432dc63f73SWenyou Yang 
1442dc63f73SWenyou Yang 	return 0;
1452dc63f73SWenyou Yang }
1462dc63f73SWenyou Yang 
1472dc63f73SWenyou Yang /*
1482dc63f73SWenyou Yang  * mux the pin to the "B" internal peripheral role.
1492dc63f73SWenyou Yang  */
at91_pio3_set_b_periph(unsigned port,unsigned pin,int use_pullup)1502dc63f73SWenyou Yang int at91_pio3_set_b_periph(unsigned port, unsigned pin, int use_pullup)
1512dc63f73SWenyou Yang {
1522dc63f73SWenyou Yang 	struct at91_port *at91_port = at91_pio_get_port(port);
1532dc63f73SWenyou Yang 	u32 mask;
1542dc63f73SWenyou Yang 
1552dc63f73SWenyou Yang 	if (at91_port && (pin < GPIO_PER_BANK)) {
1562dc63f73SWenyou Yang 		mask = 1 << pin;
1572dc63f73SWenyou Yang 		writel(mask, &at91_port->idr);
1582dc63f73SWenyou Yang 		at91_set_pio_pullup(port, pin, use_pullup);
1592dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr1) | mask,
1602dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr1);
1612dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr2) & ~mask,
1622dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr2);
1632dc63f73SWenyou Yang 
1642dc63f73SWenyou Yang 		writel(mask, &at91_port->pdr);
1652dc63f73SWenyou Yang 	}
1662dc63f73SWenyou Yang 
1672dc63f73SWenyou Yang 	return 0;
1682dc63f73SWenyou Yang }
1692dc63f73SWenyou Yang /*
1702dc63f73SWenyou Yang  * mux the pin to the "C" internal peripheral role.
1712dc63f73SWenyou Yang  */
at91_pio3_set_c_periph(unsigned port,unsigned pin,int use_pullup)1722dc63f73SWenyou Yang int at91_pio3_set_c_periph(unsigned port, unsigned pin, int use_pullup)
1732dc63f73SWenyou Yang {
1742dc63f73SWenyou Yang 	struct at91_port *at91_port = at91_pio_get_port(port);
1752dc63f73SWenyou Yang 	u32 mask;
1762dc63f73SWenyou Yang 
1772dc63f73SWenyou Yang 	if (at91_port && (pin < GPIO_PER_BANK)) {
1782dc63f73SWenyou Yang 		mask = 1 << pin;
1792dc63f73SWenyou Yang 		writel(mask, &at91_port->idr);
1802dc63f73SWenyou Yang 		at91_set_pio_pullup(port, pin, use_pullup);
1812dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr1) & ~mask,
1822dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr1);
1832dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr2) | mask,
1842dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr2);
1854bc9b7a5SBo Shen 		writel(mask, &at91_port->pdr);
1862b3b1c66SBo Shen 	}
1874bc9b7a5SBo Shen 
1882b3b1c66SBo Shen 	return 0;
1892b3b1c66SBo Shen }
1902b3b1c66SBo Shen 
1912b3b1c66SBo Shen /*
1922b3b1c66SBo Shen  * mux the pin to the "D" internal peripheral role.
1932b3b1c66SBo Shen  */
at91_pio3_set_d_periph(unsigned port,unsigned pin,int use_pullup)1942dc63f73SWenyou Yang int at91_pio3_set_d_periph(unsigned port, unsigned pin, int use_pullup)
1952b3b1c66SBo Shen {
1964bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
1972b3b1c66SBo Shen 	u32 mask;
1982b3b1c66SBo Shen 
199918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
2002b3b1c66SBo Shen 		mask = 1 << pin;
2014bc9b7a5SBo Shen 		writel(mask, &at91_port->idr);
2022b3b1c66SBo Shen 		at91_set_pio_pullup(port, pin, use_pullup);
2032dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr1) | mask,
2042dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr1);
2052dc63f73SWenyou Yang 		writel(readl(&at91_port->mux.pio3.abcdsr2) | mask,
2062dc63f73SWenyou Yang 		       &at91_port->mux.pio3.abcdsr2);
2074bc9b7a5SBo Shen 		writel(mask, &at91_port->pdr);
2082b3b1c66SBo Shen 	}
2094bc9b7a5SBo Shen 
2102b3b1c66SBo Shen 	return 0;
2112b3b1c66SBo Shen }
2122b3b1c66SBo Shen 
213918354b1SSimon Glass #ifdef CONFIG_DM_GPIO
at91_get_port_output(struct at91_port * at91_port,int offset)214918354b1SSimon Glass static bool at91_get_port_output(struct at91_port *at91_port, int offset)
215918354b1SSimon Glass {
216918354b1SSimon Glass 	u32 mask, val;
217918354b1SSimon Glass 
218918354b1SSimon Glass 	mask = 1 << offset;
219918354b1SSimon Glass 	val = readl(&at91_port->osr);
220918354b1SSimon Glass 	return val & mask;
221918354b1SSimon Glass }
222918354b1SSimon Glass #endif
223918354b1SSimon Glass 
at91_set_port_input(struct at91_port * at91_port,int offset,int use_pullup)224918354b1SSimon Glass static void at91_set_port_input(struct at91_port *at91_port, int offset,
225918354b1SSimon Glass 				int use_pullup)
226918354b1SSimon Glass {
227918354b1SSimon Glass 	u32 mask;
228918354b1SSimon Glass 
229918354b1SSimon Glass 	mask = 1 << offset;
230918354b1SSimon Glass 	writel(mask, &at91_port->idr);
231918354b1SSimon Glass 	at91_set_port_pullup(at91_port, offset, use_pullup);
232918354b1SSimon Glass 	writel(mask, &at91_port->odr);
233918354b1SSimon Glass 	writel(mask, &at91_port->per);
234918354b1SSimon Glass }
235918354b1SSimon Glass 
236ea8fbba7SJens Scharsig /*
237ea8fbba7SJens Scharsig  * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
238ea8fbba7SJens Scharsig  * configure it for an input.
239ea8fbba7SJens Scharsig  */
at91_set_pio_input(unsigned port,u32 pin,int use_pullup)240ea8fbba7SJens Scharsig int at91_set_pio_input(unsigned port, u32 pin, int use_pullup)
241ea8fbba7SJens Scharsig {
2424bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
243ea8fbba7SJens Scharsig 
244918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK))
245918354b1SSimon Glass 		at91_set_port_input(at91_port, pin, use_pullup);
2464bc9b7a5SBo Shen 
247ea8fbba7SJens Scharsig 	return 0;
248ea8fbba7SJens Scharsig }
249ea8fbba7SJens Scharsig 
at91_set_port_output(struct at91_port * at91_port,int offset,int value)250918354b1SSimon Glass static void at91_set_port_output(struct at91_port *at91_port, int offset,
251918354b1SSimon Glass 				 int value)
252ea8fbba7SJens Scharsig {
253ea8fbba7SJens Scharsig 	u32 mask;
254ea8fbba7SJens Scharsig 
255918354b1SSimon Glass 	mask = 1 << offset;
2564bc9b7a5SBo Shen 	writel(mask, &at91_port->idr);
2574bc9b7a5SBo Shen 	writel(mask, &at91_port->pudr);
258ea8fbba7SJens Scharsig 	if (value)
2594bc9b7a5SBo Shen 		writel(mask, &at91_port->sodr);
260ea8fbba7SJens Scharsig 	else
2614bc9b7a5SBo Shen 		writel(mask, &at91_port->codr);
2624bc9b7a5SBo Shen 	writel(mask, &at91_port->oer);
2634bc9b7a5SBo Shen 	writel(mask, &at91_port->per);
264ea8fbba7SJens Scharsig }
2654bc9b7a5SBo Shen 
266918354b1SSimon Glass /*
267918354b1SSimon Glass  * mux the pin to the gpio controller (instead of "A" or "B" peripheral),
268918354b1SSimon Glass  * and configure it for an output.
269918354b1SSimon Glass  */
at91_set_pio_output(unsigned port,u32 pin,int value)270918354b1SSimon Glass int at91_set_pio_output(unsigned port, u32 pin, int value)
271918354b1SSimon Glass {
272918354b1SSimon Glass 	struct at91_port *at91_port = at91_pio_get_port(port);
273918354b1SSimon Glass 
274918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK))
275918354b1SSimon Glass 		at91_set_port_output(at91_port, pin, value);
276918354b1SSimon Glass 
277ea8fbba7SJens Scharsig 	return 0;
278ea8fbba7SJens Scharsig }
279ea8fbba7SJens Scharsig 
280ea8fbba7SJens Scharsig /*
281ea8fbba7SJens Scharsig  * enable/disable the glitch filter. mostly used with IRQ handling.
282ea8fbba7SJens Scharsig  */
at91_set_pio_deglitch(unsigned port,unsigned pin,int is_on)283ea8fbba7SJens Scharsig int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
284ea8fbba7SJens Scharsig {
2854bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
286ea8fbba7SJens Scharsig 	u32 mask;
287ea8fbba7SJens Scharsig 
288918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
289ea8fbba7SJens Scharsig 		mask = 1 << pin;
2902dc63f73SWenyou Yang 		if (is_on)
2912dc63f73SWenyou Yang 			writel(mask, &at91_port->ifer);
2922dc63f73SWenyou Yang 		else
2932dc63f73SWenyou Yang 			writel(mask, &at91_port->ifdr);
2942dc63f73SWenyou Yang 	}
2952dc63f73SWenyou Yang 
2962dc63f73SWenyou Yang 	return 0;
2972dc63f73SWenyou Yang }
2982dc63f73SWenyou Yang 
2992dc63f73SWenyou Yang /*
3002dc63f73SWenyou Yang  * enable/disable the glitch filter. mostly used with IRQ handling.
3012dc63f73SWenyou Yang  */
at91_pio3_set_pio_deglitch(unsigned port,unsigned pin,int is_on)3022dc63f73SWenyou Yang int at91_pio3_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
3032dc63f73SWenyou Yang {
3042dc63f73SWenyou Yang 	struct at91_port *at91_port = at91_pio_get_port(port);
3052dc63f73SWenyou Yang 	u32 mask;
3062dc63f73SWenyou Yang 
3072dc63f73SWenyou Yang 	if (at91_port && (pin < GPIO_PER_BANK)) {
3082dc63f73SWenyou Yang 		mask = 1 << pin;
3092b3b1c66SBo Shen 		if (is_on) {
3102dc63f73SWenyou Yang 			writel(mask, &at91_port->mux.pio3.ifscdr);
3114bc9b7a5SBo Shen 			writel(mask, &at91_port->ifer);
3122b3b1c66SBo Shen 		} else {
3134bc9b7a5SBo Shen 			writel(mask, &at91_port->ifdr);
314ea8fbba7SJens Scharsig 		}
3152b3b1c66SBo Shen 	}
3164bc9b7a5SBo Shen 
317ea8fbba7SJens Scharsig 	return 0;
318ea8fbba7SJens Scharsig }
319ea8fbba7SJens Scharsig 
3202b3b1c66SBo Shen /*
3212b3b1c66SBo Shen  * enable/disable the debounce filter.
3222b3b1c66SBo Shen  */
at91_pio3_set_pio_debounce(unsigned port,unsigned pin,int is_on,int div)3232dc63f73SWenyou Yang int at91_pio3_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div)
3242b3b1c66SBo Shen {
3254bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
3262b3b1c66SBo Shen 	u32 mask;
3272b3b1c66SBo Shen 
328918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
3292b3b1c66SBo Shen 		mask = 1 << pin;
3302b3b1c66SBo Shen 		if (is_on) {
3312dc63f73SWenyou Yang 			writel(mask, &at91_port->mux.pio3.ifscer);
3322dc63f73SWenyou Yang 			writel(div & PIO_SCDR_DIV, &at91_port->mux.pio3.scdr);
3334bc9b7a5SBo Shen 			writel(mask, &at91_port->ifer);
3342b3b1c66SBo Shen 		} else {
3354bc9b7a5SBo Shen 			writel(mask, &at91_port->ifdr);
3362b3b1c66SBo Shen 		}
3372b3b1c66SBo Shen 	}
3384bc9b7a5SBo Shen 
3392b3b1c66SBo Shen 	return 0;
3402b3b1c66SBo Shen }
3412b3b1c66SBo Shen 
3422b3b1c66SBo Shen /*
3432b3b1c66SBo Shen  * enable/disable the pull-down.
3442b3b1c66SBo Shen  * If pull-up already enabled while calling the function, we disable it.
3452b3b1c66SBo Shen  */
at91_pio3_set_pio_pulldown(unsigned port,unsigned pin,int is_on)3462dc63f73SWenyou Yang int at91_pio3_set_pio_pulldown(unsigned port, unsigned pin, int is_on)
3472b3b1c66SBo Shen {
3484bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
3492b3b1c66SBo Shen 	u32 mask;
3502b3b1c66SBo Shen 
351918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
3522b3b1c66SBo Shen 		mask = 1 << pin;
353152ac5faSMarek Vasut 		if (is_on) {
354152ac5faSMarek Vasut 			at91_set_pio_pullup(port, pin, 0);
3552dc63f73SWenyou Yang 			writel(mask, &at91_port->mux.pio3.ppder);
356152ac5faSMarek Vasut 		} else
3572dc63f73SWenyou Yang 			writel(mask, &at91_port->mux.pio3.ppddr);
3582b3b1c66SBo Shen 	}
3594bc9b7a5SBo Shen 
3602b3b1c66SBo Shen 	return 0;
3612b3b1c66SBo Shen }
3622b3b1c66SBo Shen 
at91_pio3_set_pio_pullup(unsigned port,unsigned pin,int use_pullup)3632dc63f73SWenyou Yang int at91_pio3_set_pio_pullup(unsigned port, unsigned pin, int use_pullup)
3642dc63f73SWenyou Yang {
3652dc63f73SWenyou Yang 	struct at91_port *at91_port = at91_pio_get_port(port);
3662dc63f73SWenyou Yang 
3672dc63f73SWenyou Yang 	if (use_pullup)
3682dc63f73SWenyou Yang 		at91_pio3_set_pio_pulldown(port, pin, 0);
3692dc63f73SWenyou Yang 
3702dc63f73SWenyou Yang 	if (at91_port && (pin < GPIO_PER_BANK))
3712dc63f73SWenyou Yang 		at91_set_port_pullup(at91_port, pin, use_pullup);
3722dc63f73SWenyou Yang 
3732dc63f73SWenyou Yang 	return 0;
3742dc63f73SWenyou Yang }
3752dc63f73SWenyou Yang 
3762b3b1c66SBo Shen /*
3772b3b1c66SBo Shen  * disable Schmitt trigger
3782b3b1c66SBo Shen  */
at91_pio3_set_pio_disable_schmitt_trig(unsigned port,unsigned pin)3792dc63f73SWenyou Yang int at91_pio3_set_pio_disable_schmitt_trig(unsigned port, unsigned pin)
3802b3b1c66SBo Shen {
3814bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
3822b3b1c66SBo Shen 	u32 mask;
3832b3b1c66SBo Shen 
384918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
3852b3b1c66SBo Shen 		mask = 1 << pin;
3864bc9b7a5SBo Shen 		writel(readl(&at91_port->schmitt) | mask,
3874bc9b7a5SBo Shen 		       &at91_port->schmitt);
3882b3b1c66SBo Shen 	}
3894bc9b7a5SBo Shen 
3902b3b1c66SBo Shen 	return 0;
3912b3b1c66SBo Shen }
3922b3b1c66SBo Shen 
393ea8fbba7SJens Scharsig /*
394ea8fbba7SJens Scharsig  * enable/disable the multi-driver. This is only valid for output and
395ea8fbba7SJens Scharsig  * allows the output pin to run as an open collector output.
396ea8fbba7SJens Scharsig  */
at91_set_pio_multi_drive(unsigned port,unsigned pin,int is_on)397ea8fbba7SJens Scharsig int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on)
398ea8fbba7SJens Scharsig {
3994bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
400ea8fbba7SJens Scharsig 	u32 mask;
401ea8fbba7SJens Scharsig 
402918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK)) {
403ea8fbba7SJens Scharsig 		mask = 1 << pin;
404ea8fbba7SJens Scharsig 		if (is_on)
4054bc9b7a5SBo Shen 			writel(mask, &at91_port->mder);
406ea8fbba7SJens Scharsig 		else
4074bc9b7a5SBo Shen 			writel(mask, &at91_port->mddr);
408ea8fbba7SJens Scharsig 	}
4094bc9b7a5SBo Shen 
410ea8fbba7SJens Scharsig 	return 0;
411ea8fbba7SJens Scharsig }
412ea8fbba7SJens Scharsig 
at91_set_port_value(struct at91_port * at91_port,int offset,int value)413918354b1SSimon Glass static void at91_set_port_value(struct at91_port *at91_port, int offset,
414918354b1SSimon Glass 				int value)
415ea8fbba7SJens Scharsig {
416ea8fbba7SJens Scharsig 	u32 mask;
417ea8fbba7SJens Scharsig 
418918354b1SSimon Glass 	mask = 1 << offset;
419ea8fbba7SJens Scharsig 	if (value)
4204bc9b7a5SBo Shen 		writel(mask, &at91_port->sodr);
421ea8fbba7SJens Scharsig 	else
4224bc9b7a5SBo Shen 		writel(mask, &at91_port->codr);
423ea8fbba7SJens Scharsig }
4244bc9b7a5SBo Shen 
425918354b1SSimon Glass /*
426918354b1SSimon Glass  * assuming the pin is muxed as a gpio output, set its value.
427918354b1SSimon Glass  */
at91_set_pio_value(unsigned port,unsigned pin,int value)428918354b1SSimon Glass int at91_set_pio_value(unsigned port, unsigned pin, int value)
429918354b1SSimon Glass {
430918354b1SSimon Glass 	struct at91_port *at91_port = at91_pio_get_port(port);
431918354b1SSimon Glass 
432918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK))
433918354b1SSimon Glass 		at91_set_port_value(at91_port, pin, value);
434918354b1SSimon Glass 
435ea8fbba7SJens Scharsig 	return 0;
436ea8fbba7SJens Scharsig }
437ea8fbba7SJens Scharsig 
at91_get_port_value(struct at91_port * at91_port,int offset)438918354b1SSimon Glass static int at91_get_port_value(struct at91_port *at91_port, int offset)
439918354b1SSimon Glass {
440918354b1SSimon Glass 	u32 pdsr = 0, mask;
441918354b1SSimon Glass 
442918354b1SSimon Glass 	mask = 1 << offset;
443918354b1SSimon Glass 	pdsr = readl(&at91_port->pdsr) & mask;
444918354b1SSimon Glass 
445918354b1SSimon Glass 	return pdsr != 0;
446918354b1SSimon Glass }
447ea8fbba7SJens Scharsig /*
448ea8fbba7SJens Scharsig  * read the pin's value (works even if it's not muxed as a gpio).
449ea8fbba7SJens Scharsig  */
at91_get_pio_value(unsigned port,unsigned pin)450ea8fbba7SJens Scharsig int at91_get_pio_value(unsigned port, unsigned pin)
451ea8fbba7SJens Scharsig {
4524bc9b7a5SBo Shen 	struct at91_port *at91_port = at91_pio_get_port(port);
453ea8fbba7SJens Scharsig 
454918354b1SSimon Glass 	if (at91_port && (pin < GPIO_PER_BANK))
455918354b1SSimon Glass 		return at91_get_port_value(at91_port, pin);
456918354b1SSimon Glass 
457918354b1SSimon Glass 	return 0;
458ea8fbba7SJens Scharsig }
4594bc9b7a5SBo Shen 
460918354b1SSimon Glass #ifndef CONFIG_DM_GPIO
4616edaea87SBo Shen /* Common GPIO API */
4626edaea87SBo Shen 
gpio_request(unsigned gpio,const char * label)4636edaea87SBo Shen int gpio_request(unsigned gpio, const char *label)
4646edaea87SBo Shen {
4656edaea87SBo Shen 	return 0;
4666edaea87SBo Shen }
4676edaea87SBo Shen 
gpio_free(unsigned gpio)4686edaea87SBo Shen int gpio_free(unsigned gpio)
4696edaea87SBo Shen {
4706edaea87SBo Shen 	return 0;
4716edaea87SBo Shen }
4726edaea87SBo Shen 
gpio_direction_input(unsigned gpio)4736edaea87SBo Shen int gpio_direction_input(unsigned gpio)
4746edaea87SBo Shen {
4756edaea87SBo Shen 	at91_set_pio_input(at91_gpio_to_port(gpio),
4766edaea87SBo Shen 			   at91_gpio_to_pin(gpio), 0);
4776edaea87SBo Shen 	return 0;
4786edaea87SBo Shen }
4796edaea87SBo Shen 
gpio_direction_output(unsigned gpio,int value)4806edaea87SBo Shen int gpio_direction_output(unsigned gpio, int value)
4816edaea87SBo Shen {
4826edaea87SBo Shen 	at91_set_pio_output(at91_gpio_to_port(gpio),
4836edaea87SBo Shen 			    at91_gpio_to_pin(gpio), value);
4846edaea87SBo Shen 	return 0;
4856edaea87SBo Shen }
4866edaea87SBo Shen 
gpio_get_value(unsigned gpio)4876edaea87SBo Shen int gpio_get_value(unsigned gpio)
4886edaea87SBo Shen {
4896edaea87SBo Shen 	return at91_get_pio_value(at91_gpio_to_port(gpio),
4906edaea87SBo Shen 				  at91_gpio_to_pin(gpio));
4916edaea87SBo Shen }
4926edaea87SBo Shen 
gpio_set_value(unsigned gpio,int value)4936edaea87SBo Shen int gpio_set_value(unsigned gpio, int value)
4946edaea87SBo Shen {
4956edaea87SBo Shen 	at91_set_pio_value(at91_gpio_to_port(gpio),
4966edaea87SBo Shen 			   at91_gpio_to_pin(gpio), value);
4976edaea87SBo Shen 
4986edaea87SBo Shen 	return 0;
4996edaea87SBo Shen }
500918354b1SSimon Glass #endif
501918354b1SSimon Glass 
502918354b1SSimon Glass #ifdef CONFIG_DM_GPIO
503918354b1SSimon Glass 
504918354b1SSimon Glass struct at91_port_priv {
505918354b1SSimon Glass 	struct at91_port *regs;
506918354b1SSimon Glass };
507918354b1SSimon Glass 
508918354b1SSimon Glass /* set GPIO pin 'gpio' as an input */
at91_gpio_direction_input(struct udevice * dev,unsigned offset)509918354b1SSimon Glass static int at91_gpio_direction_input(struct udevice *dev, unsigned offset)
510918354b1SSimon Glass {
511d895821fSAxel Lin 	struct at91_port_priv *port = dev_get_priv(dev);
512918354b1SSimon Glass 
513918354b1SSimon Glass 	at91_set_port_input(port->regs, offset, 0);
514918354b1SSimon Glass 
515918354b1SSimon Glass 	return 0;
516918354b1SSimon Glass }
517918354b1SSimon Glass 
518918354b1SSimon Glass /* set GPIO pin 'gpio' as an output, with polarity 'value' */
at91_gpio_direction_output(struct udevice * dev,unsigned offset,int value)519918354b1SSimon Glass static int at91_gpio_direction_output(struct udevice *dev, unsigned offset,
520918354b1SSimon Glass 				       int value)
521918354b1SSimon Glass {
522d895821fSAxel Lin 	struct at91_port_priv *port = dev_get_priv(dev);
523918354b1SSimon Glass 
524918354b1SSimon Glass 	at91_set_port_output(port->regs, offset, value);
525918354b1SSimon Glass 
526918354b1SSimon Glass 	return 0;
527918354b1SSimon Glass }
528918354b1SSimon Glass 
529918354b1SSimon Glass /* read GPIO IN value of pin 'gpio' */
at91_gpio_get_value(struct udevice * dev,unsigned offset)530918354b1SSimon Glass static int at91_gpio_get_value(struct udevice *dev, unsigned offset)
531918354b1SSimon Glass {
532d895821fSAxel Lin 	struct at91_port_priv *port = dev_get_priv(dev);
533918354b1SSimon Glass 
534918354b1SSimon Glass 	return at91_get_port_value(port->regs, offset);
535918354b1SSimon Glass }
536918354b1SSimon Glass 
537918354b1SSimon Glass /* write GPIO OUT value to pin 'gpio' */
at91_gpio_set_value(struct udevice * dev,unsigned offset,int value)538918354b1SSimon Glass static int at91_gpio_set_value(struct udevice *dev, unsigned offset,
539918354b1SSimon Glass 			       int value)
540918354b1SSimon Glass {
541d895821fSAxel Lin 	struct at91_port_priv *port = dev_get_priv(dev);
542918354b1SSimon Glass 
543918354b1SSimon Glass 	at91_set_port_value(port->regs, offset, value);
544918354b1SSimon Glass 
545918354b1SSimon Glass 	return 0;
546918354b1SSimon Glass }
547918354b1SSimon Glass 
at91_gpio_get_function(struct udevice * dev,unsigned offset)548918354b1SSimon Glass static int at91_gpio_get_function(struct udevice *dev, unsigned offset)
549918354b1SSimon Glass {
550d895821fSAxel Lin 	struct at91_port_priv *port = dev_get_priv(dev);
551918354b1SSimon Glass 
552918354b1SSimon Glass 	/* GPIOF_FUNC is not implemented yet */
553918354b1SSimon Glass 	if (at91_get_port_output(port->regs, offset))
554918354b1SSimon Glass 		return GPIOF_OUTPUT;
555918354b1SSimon Glass 	else
556918354b1SSimon Glass 		return GPIOF_INPUT;
557918354b1SSimon Glass }
558918354b1SSimon Glass 
559918354b1SSimon Glass static const struct dm_gpio_ops gpio_at91_ops = {
560918354b1SSimon Glass 	.direction_input	= at91_gpio_direction_input,
561918354b1SSimon Glass 	.direction_output	= at91_gpio_direction_output,
562918354b1SSimon Glass 	.get_value		= at91_gpio_get_value,
563918354b1SSimon Glass 	.set_value		= at91_gpio_set_value,
564918354b1SSimon Glass 	.get_function		= at91_gpio_get_function,
565918354b1SSimon Glass };
566918354b1SSimon Glass 
at91_gpio_probe(struct udevice * dev)567918354b1SSimon Glass static int at91_gpio_probe(struct udevice *dev)
568918354b1SSimon Glass {
569918354b1SSimon Glass 	struct at91_port_priv *port = dev_get_priv(dev);
570918354b1SSimon Glass 	struct at91_port_platdata *plat = dev_get_platdata(dev);
571e564f054SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
572f2f3c157SWenyou Yang 	struct clk clk;
573f2f3c157SWenyou Yang 	int ret;
574f2f3c157SWenyou Yang 
575f2f3c157SWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk);
576f2f3c157SWenyou Yang 	if (ret)
577f2f3c157SWenyou Yang 		return ret;
578f2f3c157SWenyou Yang 
579f2f3c157SWenyou Yang 	ret = clk_enable(&clk);
580f2f3c157SWenyou Yang 	if (ret)
581f2f3c157SWenyou Yang 		return ret;
582f2f3c157SWenyou Yang 
583f2f3c157SWenyou Yang 	clk_free(&clk);
584918354b1SSimon Glass 
585918354b1SSimon Glass 	uc_priv->bank_name = plat->bank_name;
586918354b1SSimon Glass 	uc_priv->gpio_count = GPIO_PER_BANK;
587cf468880SWenyou Yang 
588cf468880SWenyou Yang #if CONFIG_IS_ENABLED(OF_CONTROL)
589a821c4afSSimon Glass 	plat->base_addr = (uint32_t)devfdt_get_addr_ptr(dev);
590cf468880SWenyou Yang #endif
591918354b1SSimon Glass 	port->regs = (struct at91_port *)plat->base_addr;
592918354b1SSimon Glass 
593918354b1SSimon Glass 	return 0;
594918354b1SSimon Glass }
595918354b1SSimon Glass 
596cf468880SWenyou Yang #if CONFIG_IS_ENABLED(OF_CONTROL)
597cf468880SWenyou Yang static const struct udevice_id at91_gpio_ids[] = {
598cf468880SWenyou Yang 	{ .compatible = "atmel,at91rm9200-gpio" },
599cf468880SWenyou Yang 	{ }
600cf468880SWenyou Yang };
601cf468880SWenyou Yang #endif
602cf468880SWenyou Yang 
603918354b1SSimon Glass U_BOOT_DRIVER(gpio_at91) = {
604918354b1SSimon Glass 	.name	= "gpio_at91",
605918354b1SSimon Glass 	.id	= UCLASS_GPIO,
606cf468880SWenyou Yang #if CONFIG_IS_ENABLED(OF_CONTROL)
607cf468880SWenyou Yang 	.of_match = at91_gpio_ids,
608cf468880SWenyou Yang 	.platdata_auto_alloc_size = sizeof(struct at91_port_platdata),
609cf468880SWenyou Yang #endif
610918354b1SSimon Glass 	.ops	= &gpio_at91_ops,
611918354b1SSimon Glass 	.probe	= at91_gpio_probe,
612918354b1SSimon Glass 	.priv_auto_alloc_size = sizeof(struct at91_port_priv),
613918354b1SSimon Glass };
614918354b1SSimon Glass #endif
615