blob: a964e25ea620611f8302d5f4b7b78053087cdf02 [file] [log] [blame]
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +02001/*
Liu Gang42178e22016-02-03 19:27:34 +08002 * GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +02003 *
4 * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
Liu Gang42178e22016-02-03 19:27:34 +08005 * Copyright (C) 2016 Freescale Semiconductor Inc.
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +02006 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
Ran Wang76c47d12021-03-22 11:38:46 +080012#include <linux/acpi.h>
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020013#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/spinlock.h>
16#include <linux/io.h>
17#include <linux/of.h>
18#include <linux/of_gpio.h>
Liu Gang42178e22016-02-03 19:27:34 +080019#include <linux/of_address.h>
Rob Herring5af50732013-09-17 14:28:33 -050020#include <linux/of_irq.h>
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +010021#include <linux/of_platform.h>
Ran Wang76c47d12021-03-22 11:38:46 +080022#include <linux/property.h>
23#include <linux/mod_devicetable.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Peter Korsgaard345e5c82010-01-07 17:57:46 +010025#include <linux/irq.h>
Liu Gang42178e22016-02-03 19:27:34 +080026#include <linux/gpio/driver.h>
Linus Walleijb3222f72017-10-20 16:08:12 +020027#include <linux/bitops.h>
Song Hui698b8ee2019-10-11 08:56:43 +080028#include <linux/interrupt.h>
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020029
30#define MPC8XXX_GPIO_PINS 32
31
32#define GPIO_DIR 0x00
33#define GPIO_ODR 0x04
34#define GPIO_DAT 0x08
35#define GPIO_IER 0x0c
36#define GPIO_IMR 0x10
37#define GPIO_ICR 0x14
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +020038#define GPIO_ICR2 0x18
Song Huibd4bd332019-07-18 17:49:02 +080039#define GPIO_IBE 0x18
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020040
41struct mpc8xxx_gpio_chip {
Liu Gang42178e22016-02-03 19:27:34 +080042 struct gpio_chip gc;
43 void __iomem *regs;
Alexander Stein50593612015-07-21 15:54:30 +020044 raw_spinlock_t lock;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020045
Liu Gang42178e22016-02-03 19:27:34 +080046 int (*direction_output)(struct gpio_chip *chip,
47 unsigned offset, int value);
48
Grant Likelybae1d8f2012-02-14 14:06:50 -070049 struct irq_domain *irq;
Yang Li9f51ce02022-01-19 09:04:32 +080050 int irqn;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020051};
52
Linus Walleijb3222f72017-10-20 16:08:12 +020053/*
54 * This hardware has a big endian bit assignment such that GPIO line 0 is
55 * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
56 * This inline helper give the right bitmask for a certain line.
57 */
58static inline u32 mpc_pin2mask(unsigned int offset)
59{
60 return BIT(31 - offset);
61}
62
Felix Radenskyc1a676d2009-08-12 08:57:39 +030063/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
64 * defined as output cannot be determined by reading GPDAT register,
65 * so we use shadow data register instead. The status of input pins
66 * is determined by reading GPDAT register.
67 */
68static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
69{
70 u32 val;
Linus Walleij709d71a2015-12-07 10:34:28 +010071 struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
Liu Gang1aeef302013-11-22 16:12:40 +080072 u32 out_mask, out_shadow;
Felix Radenskyc1a676d2009-08-12 08:57:39 +030073
Axel Lincd0d3f52016-02-22 15:24:01 +080074 out_mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR);
75 val = gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) & ~out_mask;
Liu Gang42178e22016-02-03 19:27:34 +080076 out_shadow = gc->bgpio_data & out_mask;
Felix Radenskyc1a676d2009-08-12 08:57:39 +030077
Linus Walleijb3222f72017-10-20 16:08:12 +020078 return !!((val | out_shadow) & mpc_pin2mask(gpio));
Felix Radenskyc1a676d2009-08-12 08:57:39 +030079}
80
Liu Gang42178e22016-02-03 19:27:34 +080081static int mpc5121_gpio_dir_out(struct gpio_chip *gc,
82 unsigned int gpio, int val)
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +020083{
Linus Walleij709d71a2015-12-07 10:34:28 +010084 struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
Wolfram Sang28538df2011-12-13 10:12:48 +010085 /* GPIO 28..31 are input only on MPC5121 */
86 if (gpio >= 28)
87 return -EINVAL;
88
Liu Gang42178e22016-02-03 19:27:34 +080089 return mpc8xxx_gc->direction_output(gc, gpio, val);
Wolfram Sang28538df2011-12-13 10:12:48 +010090}
91
Liu Gang42178e22016-02-03 19:27:34 +080092static int mpc5125_gpio_dir_out(struct gpio_chip *gc,
93 unsigned int gpio, int val)
Uwe Kleine-König0ba69e02015-07-16 21:08:23 +020094{
Liu Gang42178e22016-02-03 19:27:34 +080095 struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
Uwe Kleine-König0ba69e02015-07-16 21:08:23 +020096 /* GPIO 0..3 are input only on MPC5125 */
97 if (gpio <= 3)
98 return -EINVAL;
99
Liu Gang42178e22016-02-03 19:27:34 +0800100 return mpc8xxx_gc->direction_output(gc, gpio, val);
Uwe Kleine-König0ba69e02015-07-16 21:08:23 +0200101}
102
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100103static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
104{
Linus Walleij709d71a2015-12-07 10:34:28 +0100105 struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100106
107 if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
108 return irq_create_mapping(mpc8xxx_gc->irq, offset);
109 else
110 return -ENXIO;
111}
112
Song Hui698b8ee2019-10-11 08:56:43 +0800113static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100114{
Song Hui698b8ee2019-10-11 08:56:43 +0800115 struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
Axel Lincd0d3f52016-02-22 15:24:01 +0800116 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Song Hui698b8ee2019-10-11 08:56:43 +0800117 unsigned long mask;
118 int i;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100119
Axel Lincd0d3f52016-02-22 15:24:01 +0800120 mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
121 & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
Song Hui698b8ee2019-10-11 08:56:43 +0800122 for_each_set_bit(i, &mask, 32)
Marc Zyngierdbd1c542021-05-04 17:42:18 +0100123 generic_handle_domain_irq(mpc8xxx_gc->irq, 31 - i);
Song Hui698b8ee2019-10-11 08:56:43 +0800124
125 return IRQ_HANDLED;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100126}
127
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000128static void mpc8xxx_irq_unmask(struct irq_data *d)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100129{
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000130 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
Liu Gang42178e22016-02-03 19:27:34 +0800131 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100132 unsigned long flags;
133
Alexander Stein50593612015-07-21 15:54:30 +0200134 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100135
Axel Lincd0d3f52016-02-22 15:24:01 +0800136 gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
137 gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
Linus Walleijb3222f72017-10-20 16:08:12 +0200138 | mpc_pin2mask(irqd_to_hwirq(d)));
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100139
Alexander Stein50593612015-07-21 15:54:30 +0200140 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100141}
142
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000143static void mpc8xxx_irq_mask(struct irq_data *d)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100144{
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000145 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
Liu Gang42178e22016-02-03 19:27:34 +0800146 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100147 unsigned long flags;
148
Alexander Stein50593612015-07-21 15:54:30 +0200149 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100150
Axel Lincd0d3f52016-02-22 15:24:01 +0800151 gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
152 gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
Linus Walleijb3222f72017-10-20 16:08:12 +0200153 & ~mpc_pin2mask(irqd_to_hwirq(d)));
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100154
Alexander Stein50593612015-07-21 15:54:30 +0200155 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100156}
157
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000158static void mpc8xxx_irq_ack(struct irq_data *d)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100159{
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000160 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
Liu Gang42178e22016-02-03 19:27:34 +0800161 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100162
Axel Lincd0d3f52016-02-22 15:24:01 +0800163 gc->write_reg(mpc8xxx_gc->regs + GPIO_IER,
Linus Walleijb3222f72017-10-20 16:08:12 +0200164 mpc_pin2mask(irqd_to_hwirq(d)));
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100165}
166
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000167static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100168{
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000169 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
Liu Gang42178e22016-02-03 19:27:34 +0800170 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100171 unsigned long flags;
172
173 switch (flow_type) {
174 case IRQ_TYPE_EDGE_FALLING:
Alexander Stein50593612015-07-21 15:54:30 +0200175 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Axel Lincd0d3f52016-02-22 15:24:01 +0800176 gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
177 gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
Linus Walleijb3222f72017-10-20 16:08:12 +0200178 | mpc_pin2mask(irqd_to_hwirq(d)));
Alexander Stein50593612015-07-21 15:54:30 +0200179 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100180 break;
181
182 case IRQ_TYPE_EDGE_BOTH:
Alexander Stein50593612015-07-21 15:54:30 +0200183 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Axel Lincd0d3f52016-02-22 15:24:01 +0800184 gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
185 gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
Linus Walleijb3222f72017-10-20 16:08:12 +0200186 & ~mpc_pin2mask(irqd_to_hwirq(d)));
Alexander Stein50593612015-07-21 15:54:30 +0200187 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100188 break;
189
190 default:
191 return -EINVAL;
192 }
193
194 return 0;
195}
196
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000197static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200198{
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000199 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
Axel Lincd0d3f52016-02-22 15:24:01 +0800200 struct gpio_chip *gc = &mpc8xxx_gc->gc;
Grant Likely476eb492011-05-04 15:02:15 +1000201 unsigned long gpio = irqd_to_hwirq(d);
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200202 void __iomem *reg;
203 unsigned int shift;
204 unsigned long flags;
205
206 if (gpio < 16) {
Liu Gang42178e22016-02-03 19:27:34 +0800207 reg = mpc8xxx_gc->regs + GPIO_ICR;
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200208 shift = (15 - gpio) * 2;
209 } else {
Liu Gang42178e22016-02-03 19:27:34 +0800210 reg = mpc8xxx_gc->regs + GPIO_ICR2;
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200211 shift = (15 - (gpio % 16)) * 2;
212 }
213
214 switch (flow_type) {
215 case IRQ_TYPE_EDGE_FALLING:
216 case IRQ_TYPE_LEVEL_LOW:
Alexander Stein50593612015-07-21 15:54:30 +0200217 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Axel Lincd0d3f52016-02-22 15:24:01 +0800218 gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift))
Liu Gang42178e22016-02-03 19:27:34 +0800219 | (2 << shift));
Alexander Stein50593612015-07-21 15:54:30 +0200220 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200221 break;
222
223 case IRQ_TYPE_EDGE_RISING:
224 case IRQ_TYPE_LEVEL_HIGH:
Alexander Stein50593612015-07-21 15:54:30 +0200225 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Axel Lincd0d3f52016-02-22 15:24:01 +0800226 gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift))
Liu Gang42178e22016-02-03 19:27:34 +0800227 | (1 << shift));
Alexander Stein50593612015-07-21 15:54:30 +0200228 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200229 break;
230
231 case IRQ_TYPE_EDGE_BOTH:
Alexander Stein50593612015-07-21 15:54:30 +0200232 raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
Axel Lincd0d3f52016-02-22 15:24:01 +0800233 gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift)));
Alexander Stein50593612015-07-21 15:54:30 +0200234 raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200235 break;
236
237 default:
238 return -EINVAL;
239 }
240
241 return 0;
242}
243
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100244static struct irq_chip mpc8xxx_irq_chip = {
245 .name = "mpc8xxx-gpio",
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000246 .irq_unmask = mpc8xxx_irq_unmask,
247 .irq_mask = mpc8xxx_irq_mask,
248 .irq_ack = mpc8xxx_irq_ack,
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200249 /* this might get overwritten in mpc8xxx_probe() */
Lennert Buytenhek94347cb2011-03-08 22:26:58 +0000250 .irq_set_type = mpc8xxx_irq_set_type,
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100251};
252
Linus Walleij5ba17ae2013-10-11 19:37:30 +0200253static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
254 irq_hw_number_t hwirq)
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100255{
Linus Walleij5ba17ae2013-10-11 19:37:30 +0200256 irq_set_chip_data(irq, h->host_data);
Liu Gangd71cf152016-10-21 15:31:28 +0800257 irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100258
259 return 0;
260}
261
Krzysztof Kozlowski0b354dc2015-04-27 21:54:07 +0900262static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100263 .map = mpc8xxx_gpio_irq_map,
Grant Likelyff8c3ab2012-01-24 17:09:13 -0700264 .xlate = irq_domain_xlate_twocell,
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100265};
266
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200267struct mpc8xxx_gpio_devtype {
268 int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int);
269 int (*gpio_get)(struct gpio_chip *, unsigned int);
270 int (*irq_set_type)(struct irq_data *, unsigned int);
271};
272
273static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = {
274 .gpio_dir_out = mpc5121_gpio_dir_out,
275 .irq_set_type = mpc512x_irq_set_type,
276};
277
Uwe Kleine-König0ba69e02015-07-16 21:08:23 +0200278static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
279 .gpio_dir_out = mpc5125_gpio_dir_out,
280 .irq_set_type = mpc512x_irq_set_type,
281};
282
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200283static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = {
284 .gpio_get = mpc8572_gpio_get,
285};
286
287static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = {
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200288 .irq_set_type = mpc8xxx_irq_set_type,
289};
290
Uwe Kleine-König4183afe2015-07-16 21:08:21 +0200291static const struct of_device_id mpc8xxx_gpio_ids[] = {
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200292 { .compatible = "fsl,mpc8349-gpio", },
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200293 { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, },
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200294 { .compatible = "fsl,mpc8610-gpio", },
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200295 { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, },
Uwe Kleine-König0ba69e02015-07-16 21:08:23 +0200296 { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, },
Kumar Gala15a51482011-10-22 16:20:42 -0500297 { .compatible = "fsl,pq3-gpio", },
Michael Walle3795d7c2020-09-30 09:42:11 +0200298 { .compatible = "fsl,ls1028a-gpio", },
299 { .compatible = "fsl,ls1088a-gpio", },
Anatolij Gustschind1dcfbb2011-01-08 16:51:16 +0100300 { .compatible = "fsl,qoriq-gpio", },
Anatolij Gustschine39d5ef2010-08-09 07:58:48 +0200301 {}
302};
303
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100304static int mpc8xxx_probe(struct platform_device *pdev)
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200305{
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100306 struct device_node *np = pdev->dev.of_node;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200307 struct mpc8xxx_gpio_chip *mpc8xxx_gc;
Liu Gang42178e22016-02-03 19:27:34 +0800308 struct gpio_chip *gc;
Ran Wang76c47d12021-03-22 11:38:46 +0800309 const struct mpc8xxx_gpio_devtype *devtype = NULL;
310 struct fwnode_handle *fwnode;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200311 int ret;
312
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100313 mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL);
314 if (!mpc8xxx_gc)
315 return -ENOMEM;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200316
Ricardo Ribalda Delgado257e1072015-01-18 12:39:33 +0100317 platform_set_drvdata(pdev, mpc8xxx_gc);
318
Alexander Stein50593612015-07-21 15:54:30 +0200319 raw_spin_lock_init(&mpc8xxx_gc->lock);
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200320
Ran Wang76c47d12021-03-22 11:38:46 +0800321 mpc8xxx_gc->regs = devm_platform_ioremap_resource(pdev, 0);
322 if (IS_ERR(mpc8xxx_gc->regs))
323 return PTR_ERR(mpc8xxx_gc->regs);
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200324
Liu Gang42178e22016-02-03 19:27:34 +0800325 gc = &mpc8xxx_gc->gc;
Johnson CH Chen (陳昭勳)322f6a32019-11-26 06:51:11 +0000326 gc->parent = &pdev->dev;
Liu Gang42178e22016-02-03 19:27:34 +0800327
Ran Wang76c47d12021-03-22 11:38:46 +0800328 if (device_property_read_bool(&pdev->dev, "little-endian")) {
Liu Gang42178e22016-02-03 19:27:34 +0800329 ret = bgpio_init(gc, &pdev->dev, 4,
330 mpc8xxx_gc->regs + GPIO_DAT,
331 NULL, NULL,
332 mpc8xxx_gc->regs + GPIO_DIR, NULL,
333 BGPIOF_BIG_ENDIAN);
334 if (ret)
Christophe JAILLET7d658892021-08-20 17:38:03 +0200335 return ret;
Liu Gang42178e22016-02-03 19:27:34 +0800336 dev_dbg(&pdev->dev, "GPIO registers are LITTLE endian\n");
337 } else {
338 ret = bgpio_init(gc, &pdev->dev, 4,
339 mpc8xxx_gc->regs + GPIO_DAT,
340 NULL, NULL,
341 mpc8xxx_gc->regs + GPIO_DIR, NULL,
342 BGPIOF_BIG_ENDIAN
343 | BGPIOF_BIG_ENDIAN_BYTE_ORDER);
344 if (ret)
Christophe JAILLET7d658892021-08-20 17:38:03 +0200345 return ret;
Liu Gang42178e22016-02-03 19:27:34 +0800346 dev_dbg(&pdev->dev, "GPIO registers are BIG endian\n");
347 }
348
Axel Linfa4007c2016-02-22 15:22:52 +0800349 mpc8xxx_gc->direction_output = gc->direction_output;
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200350
Ran Wang76c47d12021-03-22 11:38:46 +0800351 devtype = device_get_match_data(&pdev->dev);
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200352 if (!devtype)
353 devtype = &mpc8xxx_gpio_devtype_default;
354
355 /*
356 * It's assumed that only a single type of gpio controller is available
357 * on the current machine, so overwriting global data is fine.
358 */
Vladimir Oltean4e505732019-11-15 14:55:51 +0200359 if (devtype->irq_set_type)
360 mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
Uwe Kleine-König82e39b02015-07-16 21:08:22 +0200361
Axel Linadf32ea2016-02-22 15:24:54 +0800362 if (devtype->gpio_dir_out)
363 gc->direction_output = devtype->gpio_dir_out;
364 if (devtype->gpio_get)
365 gc->get = devtype->gpio_get;
366
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100367 gc->to_irq = mpc8xxx_gpio_to_irq;
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200368
Michael Walle3795d7c2020-09-30 09:42:11 +0200369 /*
370 * The GPIO Input Buffer Enable register(GPIO_IBE) is used to control
371 * the input enable of each individual GPIO port. When an individual
372 * GPIO port’s direction is set to input (GPIO_GPDIR[DRn=0]), the
373 * associated input enable must be set (GPIOxGPIE[IEn]=1) to propagate
374 * the port value to the GPIO Data Register.
375 */
Ran Wang76c47d12021-03-22 11:38:46 +0800376 fwnode = dev_fwnode(&pdev->dev);
Michael Walle3795d7c2020-09-30 09:42:11 +0200377 if (of_device_is_compatible(np, "fsl,qoriq-gpio") ||
378 of_device_is_compatible(np, "fsl,ls1028a-gpio") ||
Ran Wang76c47d12021-03-22 11:38:46 +0800379 of_device_is_compatible(np, "fsl,ls1088a-gpio") ||
380 is_acpi_node(fwnode))
Russell King787b64a2019-11-19 13:10:38 +0000381 gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
382
Christophe JAILLET889a1b32021-08-20 17:38:13 +0200383 ret = devm_gpiochip_add_data(&pdev->dev, gc, mpc8xxx_gc);
Liu Gang42178e22016-02-03 19:27:34 +0800384 if (ret) {
Ran Wang76c47d12021-03-22 11:38:46 +0800385 dev_err(&pdev->dev,
386 "GPIO chip registration failed with status %d\n", ret);
Christophe JAILLET7d658892021-08-20 17:38:03 +0200387 return ret;
Liu Gang42178e22016-02-03 19:27:34 +0800388 }
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200389
Ran Wang76c47d12021-03-22 11:38:46 +0800390 mpc8xxx_gc->irqn = platform_get_irq(pdev, 0);
Miaoqian Lin0b395362022-01-14 06:48:20 +0000391 if (mpc8xxx_gc->irqn < 0)
392 return mpc8xxx_gc->irqn;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100393
Ran Wang76c47d12021-03-22 11:38:46 +0800394 mpc8xxx_gc->irq = irq_domain_create_linear(fwnode,
395 MPC8XXX_GPIO_PINS,
396 &mpc8xxx_gpio_irq_ops,
397 mpc8xxx_gc);
398
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100399 if (!mpc8xxx_gc->irq)
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100400 return 0;
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100401
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100402 /* ack and mask all irqs */
Axel Lincd0d3f52016-02-22 15:24:01 +0800403 gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
404 gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
Peter Korsgaard345e5c82010-01-07 17:57:46 +0100405
Song Hui698b8ee2019-10-11 08:56:43 +0800406 ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
407 mpc8xxx_gpio_irq_cascade,
Rasmus Villemoesec7099f2021-07-02 15:37:12 +0200408 IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
Song Hui698b8ee2019-10-11 08:56:43 +0800409 mpc8xxx_gc);
410 if (ret) {
Ran Wang76c47d12021-03-22 11:38:46 +0800411 dev_err(&pdev->dev,
412 "failed to devm_request_irq(%d), ret = %d\n",
413 mpc8xxx_gc->irqn, ret);
Song Hui698b8ee2019-10-11 08:56:43 +0800414 goto err;
415 }
416
Ricardo Ribalda Delgado257e1072015-01-18 12:39:33 +0100417 return 0;
Liu Gang42178e22016-02-03 19:27:34 +0800418err:
Christophe JAILLET7d658892021-08-20 17:38:03 +0200419 irq_domain_remove(mpc8xxx_gc->irq);
Liu Gang42178e22016-02-03 19:27:34 +0800420 return ret;
Ricardo Ribalda Delgado257e1072015-01-18 12:39:33 +0100421}
422
423static int mpc8xxx_remove(struct platform_device *pdev)
424{
425 struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev);
426
427 if (mpc8xxx_gc->irq) {
Thomas Gleixner05379812015-06-21 21:10:46 +0200428 irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL);
Ricardo Ribalda Delgado257e1072015-01-18 12:39:33 +0100429 irq_domain_remove(mpc8xxx_gc->irq);
430 }
431
Peter Korsgaard1e16dfc2008-09-23 17:35:38 +0200432 return 0;
433}
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100434
Ran Wang76c47d12021-03-22 11:38:46 +0800435#ifdef CONFIG_ACPI
436static const struct acpi_device_id gpio_acpi_ids[] = {
437 {"NXP0031",},
438 { }
439};
440MODULE_DEVICE_TABLE(acpi, gpio_acpi_ids);
441#endif
442
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100443static struct platform_driver mpc8xxx_plat_driver = {
444 .probe = mpc8xxx_probe,
Ricardo Ribalda Delgado257e1072015-01-18 12:39:33 +0100445 .remove = mpc8xxx_remove,
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100446 .driver = {
447 .name = "gpio-mpc8xxx",
448 .of_match_table = mpc8xxx_gpio_ids,
Ran Wang76c47d12021-03-22 11:38:46 +0800449 .acpi_match_table = ACPI_PTR(gpio_acpi_ids),
Ricardo Ribalda Delgado98686d9a52015-01-18 12:39:32 +0100450 },
451};
452
453static int __init mpc8xxx_init(void)
454{
455 return platform_driver_register(&mpc8xxx_plat_driver);
456}
457
458arch_initcall(mpc8xxx_init);