2 * GPIOs on MPC8349/8572/8610 and compatible
4 * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/spinlock.h>
16 #include <linux/of_gpio.h>
17 #include <linux/gpio.h>
18 #include <linux/slab.h>
19 #include <linux/irq.h>
21 #define MPC8XXX_GPIO_PINS 32
30 struct mpc8xxx_gpio_chip
{
31 struct of_mm_gpio_chip mm_gc
;
35 * shadowed data register to be able to clear/set output pins in
36 * open drain mode safely
42 static inline u32
mpc8xxx_gpio2mask(unsigned int gpio
)
44 return 1u << (MPC8XXX_GPIO_PINS
- 1 - gpio
);
47 static inline struct mpc8xxx_gpio_chip
*
48 to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip
*mm
)
50 return container_of(mm
, struct mpc8xxx_gpio_chip
, mm_gc
);
53 static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip
*mm
)
55 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
57 mpc8xxx_gc
->data
= in_be32(mm
->regs
+ GPIO_DAT
);
60 /* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
61 * defined as output cannot be determined by reading GPDAT register,
62 * so we use shadow data register instead. The status of input pins
63 * is determined by reading GPDAT register.
65 static int mpc8572_gpio_get(struct gpio_chip
*gc
, unsigned int gpio
)
68 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
69 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
71 val
= in_be32(mm
->regs
+ GPIO_DAT
) & ~in_be32(mm
->regs
+ GPIO_DIR
);
73 return (val
| mpc8xxx_gc
->data
) & mpc8xxx_gpio2mask(gpio
);
76 static int mpc8xxx_gpio_get(struct gpio_chip
*gc
, unsigned int gpio
)
78 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
80 return in_be32(mm
->regs
+ GPIO_DAT
) & mpc8xxx_gpio2mask(gpio
);
83 static void mpc8xxx_gpio_set(struct gpio_chip
*gc
, unsigned int gpio
, int val
)
85 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
86 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
89 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
92 mpc8xxx_gc
->data
|= mpc8xxx_gpio2mask(gpio
);
94 mpc8xxx_gc
->data
&= ~mpc8xxx_gpio2mask(gpio
);
96 out_be32(mm
->regs
+ GPIO_DAT
, mpc8xxx_gc
->data
);
98 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
101 static int mpc8xxx_gpio_dir_in(struct gpio_chip
*gc
, unsigned int gpio
)
103 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
104 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
107 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
109 clrbits32(mm
->regs
+ GPIO_DIR
, mpc8xxx_gpio2mask(gpio
));
111 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
116 static int mpc8xxx_gpio_dir_out(struct gpio_chip
*gc
, unsigned int gpio
, int val
)
118 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
119 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
122 mpc8xxx_gpio_set(gc
, gpio
, val
);
124 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
126 setbits32(mm
->regs
+ GPIO_DIR
, mpc8xxx_gpio2mask(gpio
));
128 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
133 static int mpc8xxx_gpio_to_irq(struct gpio_chip
*gc
, unsigned offset
)
135 struct of_mm_gpio_chip
*mm
= to_of_mm_gpio_chip(gc
);
136 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= to_mpc8xxx_gpio_chip(mm
);
138 if (mpc8xxx_gc
->irq
&& offset
< MPC8XXX_GPIO_PINS
)
139 return irq_create_mapping(mpc8xxx_gc
->irq
, offset
);
144 static void mpc8xxx_gpio_irq_cascade(unsigned int irq
, struct irq_desc
*desc
)
146 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= get_irq_desc_data(desc
);
147 struct of_mm_gpio_chip
*mm
= &mpc8xxx_gc
->mm_gc
;
150 mask
= in_be32(mm
->regs
+ GPIO_IER
) & in_be32(mm
->regs
+ GPIO_IMR
);
152 generic_handle_irq(irq_linear_revmap(mpc8xxx_gc
->irq
,
156 static void mpc8xxx_irq_unmask(unsigned int virq
)
158 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= get_irq_chip_data(virq
);
159 struct of_mm_gpio_chip
*mm
= &mpc8xxx_gc
->mm_gc
;
162 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
164 setbits32(mm
->regs
+ GPIO_IMR
, mpc8xxx_gpio2mask(virq_to_hw(virq
)));
166 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
169 static void mpc8xxx_irq_mask(unsigned int virq
)
171 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= get_irq_chip_data(virq
);
172 struct of_mm_gpio_chip
*mm
= &mpc8xxx_gc
->mm_gc
;
175 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
177 clrbits32(mm
->regs
+ GPIO_IMR
, mpc8xxx_gpio2mask(virq_to_hw(virq
)));
179 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
182 static void mpc8xxx_irq_ack(unsigned int virq
)
184 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= get_irq_chip_data(virq
);
185 struct of_mm_gpio_chip
*mm
= &mpc8xxx_gc
->mm_gc
;
187 out_be32(mm
->regs
+ GPIO_IER
, mpc8xxx_gpio2mask(virq_to_hw(virq
)));
190 static int mpc8xxx_irq_set_type(unsigned int virq
, unsigned int flow_type
)
192 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
= get_irq_chip_data(virq
);
193 struct of_mm_gpio_chip
*mm
= &mpc8xxx_gc
->mm_gc
;
197 case IRQ_TYPE_EDGE_FALLING
:
198 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
199 setbits32(mm
->regs
+ GPIO_ICR
,
200 mpc8xxx_gpio2mask(virq_to_hw(virq
)));
201 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
204 case IRQ_TYPE_EDGE_BOTH
:
205 spin_lock_irqsave(&mpc8xxx_gc
->lock
, flags
);
206 clrbits32(mm
->regs
+ GPIO_ICR
,
207 mpc8xxx_gpio2mask(virq_to_hw(virq
)));
208 spin_unlock_irqrestore(&mpc8xxx_gc
->lock
, flags
);
218 static struct irq_chip mpc8xxx_irq_chip
= {
219 .name
= "mpc8xxx-gpio",
220 .unmask
= mpc8xxx_irq_unmask
,
221 .mask
= mpc8xxx_irq_mask
,
222 .ack
= mpc8xxx_irq_ack
,
223 .set_type
= mpc8xxx_irq_set_type
,
226 static int mpc8xxx_gpio_irq_map(struct irq_host
*h
, unsigned int virq
,
229 set_irq_chip_data(virq
, h
->host_data
);
230 set_irq_chip_and_handler(virq
, &mpc8xxx_irq_chip
, handle_level_irq
);
231 set_irq_type(virq
, IRQ_TYPE_NONE
);
236 static int mpc8xxx_gpio_irq_xlate(struct irq_host
*h
, struct device_node
*ct
,
237 const u32
*intspec
, unsigned int intsize
,
238 irq_hw_number_t
*out_hwirq
,
239 unsigned int *out_flags
)
242 /* interrupt sense values coming from the device tree equal either
243 * EDGE_FALLING or EDGE_BOTH
245 *out_hwirq
= intspec
[0];
246 *out_flags
= intspec
[1];
251 static struct irq_host_ops mpc8xxx_gpio_irq_ops
= {
252 .map
= mpc8xxx_gpio_irq_map
,
253 .xlate
= mpc8xxx_gpio_irq_xlate
,
256 static void __init
mpc8xxx_add_controller(struct device_node
*np
)
258 struct mpc8xxx_gpio_chip
*mpc8xxx_gc
;
259 struct of_mm_gpio_chip
*mm_gc
;
260 struct of_gpio_chip
*of_gc
;
261 struct gpio_chip
*gc
;
265 mpc8xxx_gc
= kzalloc(sizeof(*mpc8xxx_gc
), GFP_KERNEL
);
271 spin_lock_init(&mpc8xxx_gc
->lock
);
273 mm_gc
= &mpc8xxx_gc
->mm_gc
;
274 of_gc
= &mm_gc
->of_gc
;
277 mm_gc
->save_regs
= mpc8xxx_gpio_save_regs
;
278 of_gc
->gpio_cells
= 2;
279 gc
->ngpio
= MPC8XXX_GPIO_PINS
;
280 gc
->direction_input
= mpc8xxx_gpio_dir_in
;
281 gc
->direction_output
= mpc8xxx_gpio_dir_out
;
282 if (of_device_is_compatible(np
, "fsl,mpc8572-gpio"))
283 gc
->get
= mpc8572_gpio_get
;
285 gc
->get
= mpc8xxx_gpio_get
;
286 gc
->set
= mpc8xxx_gpio_set
;
287 gc
->to_irq
= mpc8xxx_gpio_to_irq
;
289 ret
= of_mm_gpiochip_add(np
, mm_gc
);
293 hwirq
= irq_of_parse_and_map(np
, 0);
298 irq_alloc_host(np
, IRQ_HOST_MAP_LINEAR
, MPC8XXX_GPIO_PINS
,
299 &mpc8xxx_gpio_irq_ops
, MPC8XXX_GPIO_PINS
);
300 if (!mpc8xxx_gc
->irq
)
303 mpc8xxx_gc
->irq
->host_data
= mpc8xxx_gc
;
305 /* ack and mask all irqs */
306 out_be32(mm_gc
->regs
+ GPIO_IER
, 0xffffffff);
307 out_be32(mm_gc
->regs
+ GPIO_IMR
, 0);
309 set_irq_data(hwirq
, mpc8xxx_gc
);
310 set_irq_chained_handler(hwirq
, mpc8xxx_gpio_irq_cascade
);
316 pr_err("%s: registration failed with status %d\n",
323 static int __init
mpc8xxx_add_gpiochips(void)
325 struct device_node
*np
;
327 for_each_compatible_node(np
, NULL
, "fsl,mpc8349-gpio")
328 mpc8xxx_add_controller(np
);
330 for_each_compatible_node(np
, NULL
, "fsl,mpc8572-gpio")
331 mpc8xxx_add_controller(np
);
333 for_each_compatible_node(np
, NULL
, "fsl,mpc8610-gpio")
334 mpc8xxx_add_controller(np
);
338 arch_initcall(mpc8xxx_add_gpiochips
);