xref: /openbmc/linux/arch/powerpc/platforms/4xx/gpio.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bfa9a2ebSMichael Ellerman /*
3bfa9a2ebSMichael Ellerman  * PPC4xx gpio driver
4bfa9a2ebSMichael Ellerman  *
5bfa9a2ebSMichael Ellerman  * Copyright (c) 2008 Harris Corporation
6bfa9a2ebSMichael Ellerman  * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
7bfa9a2ebSMichael Ellerman  * Copyright (c) MontaVista Software, Inc. 2008.
8bfa9a2ebSMichael Ellerman  *
9bfa9a2ebSMichael Ellerman  * Author: Steve Falco <sfalco@harris.com>
10bfa9a2ebSMichael Ellerman  */
11bfa9a2ebSMichael Ellerman 
12bfa9a2ebSMichael Ellerman #include <linux/kernel.h>
13bfa9a2ebSMichael Ellerman #include <linux/init.h>
14bfa9a2ebSMichael Ellerman #include <linux/spinlock.h>
15bfa9a2ebSMichael Ellerman #include <linux/io.h>
16bfa9a2ebSMichael Ellerman #include <linux/of.h>
17*a99cc668SArnd Bergmann #include <linux/gpio/legacy-of-mm-gpiochip.h>
18bfa9a2ebSMichael Ellerman #include <linux/gpio/driver.h>
19bfa9a2ebSMichael Ellerman #include <linux/types.h>
20bfa9a2ebSMichael Ellerman #include <linux/slab.h>
21bfa9a2ebSMichael Ellerman 
22bfa9a2ebSMichael Ellerman #define GPIO_MASK(gpio)		(0x80000000 >> (gpio))
23bfa9a2ebSMichael Ellerman #define GPIO_MASK2(gpio)	(0xc0000000 >> ((gpio) * 2))
24bfa9a2ebSMichael Ellerman 
25bfa9a2ebSMichael Ellerman /* Physical GPIO register layout */
26bfa9a2ebSMichael Ellerman struct ppc4xx_gpio {
27bfa9a2ebSMichael Ellerman 	__be32 or;
28bfa9a2ebSMichael Ellerman 	__be32 tcr;
29bfa9a2ebSMichael Ellerman 	__be32 osrl;
30bfa9a2ebSMichael Ellerman 	__be32 osrh;
31bfa9a2ebSMichael Ellerman 	__be32 tsrl;
32bfa9a2ebSMichael Ellerman 	__be32 tsrh;
33bfa9a2ebSMichael Ellerman 	__be32 odr;
34bfa9a2ebSMichael Ellerman 	__be32 ir;
35bfa9a2ebSMichael Ellerman 	__be32 rr1;
36bfa9a2ebSMichael Ellerman 	__be32 rr2;
37bfa9a2ebSMichael Ellerman 	__be32 rr3;
38bfa9a2ebSMichael Ellerman 	__be32 reserved1;
39bfa9a2ebSMichael Ellerman 	__be32 isr1l;
40bfa9a2ebSMichael Ellerman 	__be32 isr1h;
41bfa9a2ebSMichael Ellerman 	__be32 isr2l;
42bfa9a2ebSMichael Ellerman 	__be32 isr2h;
43bfa9a2ebSMichael Ellerman 	__be32 isr3l;
44bfa9a2ebSMichael Ellerman 	__be32 isr3h;
45bfa9a2ebSMichael Ellerman };
46bfa9a2ebSMichael Ellerman 
47bfa9a2ebSMichael Ellerman struct ppc4xx_gpio_chip {
48bfa9a2ebSMichael Ellerman 	struct of_mm_gpio_chip mm_gc;
49bfa9a2ebSMichael Ellerman 	spinlock_t lock;
50bfa9a2ebSMichael Ellerman };
51bfa9a2ebSMichael Ellerman 
52bfa9a2ebSMichael Ellerman /*
53bfa9a2ebSMichael Ellerman  * GPIO LIB API implementation for GPIOs
54bfa9a2ebSMichael Ellerman  *
55bfa9a2ebSMichael Ellerman  * There are a maximum of 32 gpios in each gpio controller.
56bfa9a2ebSMichael Ellerman  */
57bfa9a2ebSMichael Ellerman 
ppc4xx_gpio_get(struct gpio_chip * gc,unsigned int gpio)58bfa9a2ebSMichael Ellerman static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
59bfa9a2ebSMichael Ellerman {
60bfa9a2ebSMichael Ellerman 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
61bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
62bfa9a2ebSMichael Ellerman 
63bfa9a2ebSMichael Ellerman 	return !!(in_be32(&regs->ir) & GPIO_MASK(gpio));
64bfa9a2ebSMichael Ellerman }
65bfa9a2ebSMichael Ellerman 
66bfa9a2ebSMichael Ellerman static inline void
__ppc4xx_gpio_set(struct gpio_chip * gc,unsigned int gpio,int val)67bfa9a2ebSMichael Ellerman __ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
68bfa9a2ebSMichael Ellerman {
69bfa9a2ebSMichael Ellerman 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
70bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
71bfa9a2ebSMichael Ellerman 
72bfa9a2ebSMichael Ellerman 	if (val)
73bfa9a2ebSMichael Ellerman 		setbits32(&regs->or, GPIO_MASK(gpio));
74bfa9a2ebSMichael Ellerman 	else
75bfa9a2ebSMichael Ellerman 		clrbits32(&regs->or, GPIO_MASK(gpio));
76bfa9a2ebSMichael Ellerman }
77bfa9a2ebSMichael Ellerman 
78bfa9a2ebSMichael Ellerman static void
ppc4xx_gpio_set(struct gpio_chip * gc,unsigned int gpio,int val)79bfa9a2ebSMichael Ellerman ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
80bfa9a2ebSMichael Ellerman {
81bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
82bfa9a2ebSMichael Ellerman 	unsigned long flags;
83bfa9a2ebSMichael Ellerman 
84bfa9a2ebSMichael Ellerman 	spin_lock_irqsave(&chip->lock, flags);
85bfa9a2ebSMichael Ellerman 
86bfa9a2ebSMichael Ellerman 	__ppc4xx_gpio_set(gc, gpio, val);
87bfa9a2ebSMichael Ellerman 
88bfa9a2ebSMichael Ellerman 	spin_unlock_irqrestore(&chip->lock, flags);
89bfa9a2ebSMichael Ellerman 
90bfa9a2ebSMichael Ellerman 	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
91bfa9a2ebSMichael Ellerman }
92bfa9a2ebSMichael Ellerman 
ppc4xx_gpio_dir_in(struct gpio_chip * gc,unsigned int gpio)93bfa9a2ebSMichael Ellerman static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
94bfa9a2ebSMichael Ellerman {
95bfa9a2ebSMichael Ellerman 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
96bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
97bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
98bfa9a2ebSMichael Ellerman 	unsigned long flags;
99bfa9a2ebSMichael Ellerman 
100bfa9a2ebSMichael Ellerman 	spin_lock_irqsave(&chip->lock, flags);
101bfa9a2ebSMichael Ellerman 
102bfa9a2ebSMichael Ellerman 	/* Disable open-drain function */
103bfa9a2ebSMichael Ellerman 	clrbits32(&regs->odr, GPIO_MASK(gpio));
104bfa9a2ebSMichael Ellerman 
105bfa9a2ebSMichael Ellerman 	/* Float the pin */
106bfa9a2ebSMichael Ellerman 	clrbits32(&regs->tcr, GPIO_MASK(gpio));
107bfa9a2ebSMichael Ellerman 
108bfa9a2ebSMichael Ellerman 	/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
109bfa9a2ebSMichael Ellerman 	if (gpio < 16) {
110bfa9a2ebSMichael Ellerman 		clrbits32(&regs->osrl, GPIO_MASK2(gpio));
111bfa9a2ebSMichael Ellerman 		clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
112bfa9a2ebSMichael Ellerman 	} else {
113bfa9a2ebSMichael Ellerman 		clrbits32(&regs->osrh, GPIO_MASK2(gpio));
114bfa9a2ebSMichael Ellerman 		clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
115bfa9a2ebSMichael Ellerman 	}
116bfa9a2ebSMichael Ellerman 
117bfa9a2ebSMichael Ellerman 	spin_unlock_irqrestore(&chip->lock, flags);
118bfa9a2ebSMichael Ellerman 
119bfa9a2ebSMichael Ellerman 	return 0;
120bfa9a2ebSMichael Ellerman }
121bfa9a2ebSMichael Ellerman 
122bfa9a2ebSMichael Ellerman static int
ppc4xx_gpio_dir_out(struct gpio_chip * gc,unsigned int gpio,int val)123bfa9a2ebSMichael Ellerman ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
124bfa9a2ebSMichael Ellerman {
125bfa9a2ebSMichael Ellerman 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
126bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
127bfa9a2ebSMichael Ellerman 	struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
128bfa9a2ebSMichael Ellerman 	unsigned long flags;
129bfa9a2ebSMichael Ellerman 
130bfa9a2ebSMichael Ellerman 	spin_lock_irqsave(&chip->lock, flags);
131bfa9a2ebSMichael Ellerman 
132bfa9a2ebSMichael Ellerman 	/* First set initial value */
133bfa9a2ebSMichael Ellerman 	__ppc4xx_gpio_set(gc, gpio, val);
134bfa9a2ebSMichael Ellerman 
135bfa9a2ebSMichael Ellerman 	/* Disable open-drain function */
136bfa9a2ebSMichael Ellerman 	clrbits32(&regs->odr, GPIO_MASK(gpio));
137bfa9a2ebSMichael Ellerman 
138bfa9a2ebSMichael Ellerman 	/* Drive the pin */
139bfa9a2ebSMichael Ellerman 	setbits32(&regs->tcr, GPIO_MASK(gpio));
140bfa9a2ebSMichael Ellerman 
141bfa9a2ebSMichael Ellerman 	/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
142bfa9a2ebSMichael Ellerman 	if (gpio < 16) {
143bfa9a2ebSMichael Ellerman 		clrbits32(&regs->osrl, GPIO_MASK2(gpio));
144bfa9a2ebSMichael Ellerman 		clrbits32(&regs->tsrl, GPIO_MASK2(gpio));
145bfa9a2ebSMichael Ellerman 	} else {
146bfa9a2ebSMichael Ellerman 		clrbits32(&regs->osrh, GPIO_MASK2(gpio));
147bfa9a2ebSMichael Ellerman 		clrbits32(&regs->tsrh, GPIO_MASK2(gpio));
148bfa9a2ebSMichael Ellerman 	}
149bfa9a2ebSMichael Ellerman 
150bfa9a2ebSMichael Ellerman 	spin_unlock_irqrestore(&chip->lock, flags);
151bfa9a2ebSMichael Ellerman 
152bfa9a2ebSMichael Ellerman 	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
153bfa9a2ebSMichael Ellerman 
154bfa9a2ebSMichael Ellerman 	return 0;
155bfa9a2ebSMichael Ellerman }
156bfa9a2ebSMichael Ellerman 
ppc4xx_add_gpiochips(void)157bfa9a2ebSMichael Ellerman static int __init ppc4xx_add_gpiochips(void)
158bfa9a2ebSMichael Ellerman {
159bfa9a2ebSMichael Ellerman 	struct device_node *np;
160bfa9a2ebSMichael Ellerman 
161bfa9a2ebSMichael Ellerman 	for_each_compatible_node(np, NULL, "ibm,ppc4xx-gpio") {
162bfa9a2ebSMichael Ellerman 		int ret;
163bfa9a2ebSMichael Ellerman 		struct ppc4xx_gpio_chip *ppc4xx_gc;
164bfa9a2ebSMichael Ellerman 		struct of_mm_gpio_chip *mm_gc;
165bfa9a2ebSMichael Ellerman 		struct gpio_chip *gc;
166bfa9a2ebSMichael Ellerman 
167bfa9a2ebSMichael Ellerman 		ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL);
168bfa9a2ebSMichael Ellerman 		if (!ppc4xx_gc) {
169bfa9a2ebSMichael Ellerman 			ret = -ENOMEM;
170bfa9a2ebSMichael Ellerman 			goto err;
171bfa9a2ebSMichael Ellerman 		}
172bfa9a2ebSMichael Ellerman 
173bfa9a2ebSMichael Ellerman 		spin_lock_init(&ppc4xx_gc->lock);
174bfa9a2ebSMichael Ellerman 
175bfa9a2ebSMichael Ellerman 		mm_gc = &ppc4xx_gc->mm_gc;
176bfa9a2ebSMichael Ellerman 		gc = &mm_gc->gc;
177bfa9a2ebSMichael Ellerman 
178bfa9a2ebSMichael Ellerman 		gc->ngpio = 32;
179bfa9a2ebSMichael Ellerman 		gc->direction_input = ppc4xx_gpio_dir_in;
180bfa9a2ebSMichael Ellerman 		gc->direction_output = ppc4xx_gpio_dir_out;
181bfa9a2ebSMichael Ellerman 		gc->get = ppc4xx_gpio_get;
182bfa9a2ebSMichael Ellerman 		gc->set = ppc4xx_gpio_set;
183bfa9a2ebSMichael Ellerman 
184bfa9a2ebSMichael Ellerman 		ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc);
185bfa9a2ebSMichael Ellerman 		if (ret)
186bfa9a2ebSMichael Ellerman 			goto err;
187bfa9a2ebSMichael Ellerman 		continue;
188bfa9a2ebSMichael Ellerman err:
189b7c670d6SRob Herring 		pr_err("%pOF: registration failed with status %d\n", np, ret);
190bfa9a2ebSMichael Ellerman 		kfree(ppc4xx_gc);
191bfa9a2ebSMichael Ellerman 		/* try others anyway */
192bfa9a2ebSMichael Ellerman 	}
193bfa9a2ebSMichael Ellerman 	return 0;
194bfa9a2ebSMichael Ellerman }
195bfa9a2ebSMichael Ellerman arch_initcall(ppc4xx_add_gpiochips);
196