aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAnatolij Gustschin <agust@denx.de>2010-08-09 01:58:48 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-09-10 15:31:16 -0400
commite39d5ef678045d61812c1401f04fe8edb14d6359 (patch)
tree62cc49305f5b7afb3ea80289d838a872c8e217f6 /arch
parentf6cec0ae58c17522a7bc4e2f39dae19f199ab534 (diff)
powerpc/5xxx: extend mpc8xxx_gpio driver to support mpc512x gpios
The GPIO controller of MPC512x is slightly different from 8xxx GPIO controllers. The register interface is the same except the external interrupt control register. The MPC512x GPIO controller differentiates between four interrupt event types and therefore provides two interrupt control registers, GPICR1 and GPICR2. GPIO[0:15] interrupt event types are configured in GPICR1 register, GPIO[16:31] - in GPICR2 register. This patch adds MPC512x speciffic set_type() callback and updates config file and comments. Additionally the gpio chip registration function is changed to use for_each_matching_node() preventing multiple registration if a node claimes compatibility with another gpio controller type. Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/Kconfig7
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c75
2 files changed, 71 insertions, 11 deletions
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index d1663db7810..471115a13d1 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -304,13 +304,14 @@ config OF_RTC
304source "arch/powerpc/sysdev/bestcomm/Kconfig" 304source "arch/powerpc/sysdev/bestcomm/Kconfig"
305 305
306config MPC8xxx_GPIO 306config MPC8xxx_GPIO
307 bool "MPC8xxx GPIO support" 307 bool "MPC512x/MPC8xxx GPIO support"
308 depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || FSL_SOC_BOOKE || PPC_86xx 308 depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
309 FSL_SOC_BOOKE || PPC_86xx
309 select GENERIC_GPIO 310 select GENERIC_GPIO
310 select ARCH_REQUIRE_GPIOLIB 311 select ARCH_REQUIRE_GPIOLIB
311 help 312 help
312 Say Y here if you're going to use hardware that connects to the 313 Say Y here if you're going to use hardware that connects to the
313 MPC831x/834x/837x/8572/8610 GPIOs. 314 MPC512x/831x/834x/837x/8572/8610 GPIOs.
314 315
315config SIMPLE_GPIO 316config SIMPLE_GPIO
316 bool "Support for simple, memory-mapped GPIO controllers" 317 bool "Support for simple, memory-mapped GPIO controllers"
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
index 2b69084d0f0..36499394a16 100644
--- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * GPIOs on MPC8349/8572/8610 and compatible 2 * GPIOs on MPC512x/8349/8572/8610 and compatible
3 * 3 *
4 * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> 4 * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
5 * 5 *
@@ -26,6 +26,7 @@
26#define GPIO_IER 0x0c 26#define GPIO_IER 0x0c
27#define GPIO_IMR 0x10 27#define GPIO_IMR 0x10
28#define GPIO_ICR 0x14 28#define GPIO_ICR 0x14
29#define GPIO_ICR2 0x18
29 30
30struct mpc8xxx_gpio_chip { 31struct mpc8xxx_gpio_chip {
31 struct of_mm_gpio_chip mm_gc; 32 struct of_mm_gpio_chip mm_gc;
@@ -37,6 +38,7 @@ struct mpc8xxx_gpio_chip {
37 */ 38 */
38 u32 data; 39 u32 data;
39 struct irq_host *irq; 40 struct irq_host *irq;
41 void *of_dev_id_data;
40}; 42};
41 43
42static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) 44static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
@@ -215,6 +217,51 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
215 return 0; 217 return 0;
216} 218}
217 219
220static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
221{
222 struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
223 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
224 unsigned long gpio = virq_to_hw(virq);
225 void __iomem *reg;
226 unsigned int shift;
227 unsigned long flags;
228
229 if (gpio < 16) {
230 reg = mm->regs + GPIO_ICR;
231 shift = (15 - gpio) * 2;
232 } else {
233 reg = mm->regs + GPIO_ICR2;
234 shift = (15 - (gpio % 16)) * 2;
235 }
236
237 switch (flow_type) {
238 case IRQ_TYPE_EDGE_FALLING:
239 case IRQ_TYPE_LEVEL_LOW:
240 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
241 clrsetbits_be32(reg, 3 << shift, 2 << shift);
242 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
243 break;
244
245 case IRQ_TYPE_EDGE_RISING:
246 case IRQ_TYPE_LEVEL_HIGH:
247 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
248 clrsetbits_be32(reg, 3 << shift, 1 << shift);
249 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
250 break;
251
252 case IRQ_TYPE_EDGE_BOTH:
253 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
254 clrbits32(reg, 3 << shift);
255 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
256 break;
257
258 default:
259 return -EINVAL;
260 }
261
262 return 0;
263}
264
218static struct irq_chip mpc8xxx_irq_chip = { 265static struct irq_chip mpc8xxx_irq_chip = {
219 .name = "mpc8xxx-gpio", 266 .name = "mpc8xxx-gpio",
220 .unmask = mpc8xxx_irq_unmask, 267 .unmask = mpc8xxx_irq_unmask,
@@ -226,6 +273,11 @@ static struct irq_chip mpc8xxx_irq_chip = {
226static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, 273static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
227 irq_hw_number_t hw) 274 irq_hw_number_t hw)
228{ 275{
276 struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
277
278 if (mpc8xxx_gc->of_dev_id_data)
279 mpc8xxx_irq_chip.set_type = mpc8xxx_gc->of_dev_id_data;
280
229 set_irq_chip_data(virq, h->host_data); 281 set_irq_chip_data(virq, h->host_data);
230 set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); 282 set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
231 set_irq_type(virq, IRQ_TYPE_NONE); 283 set_irq_type(virq, IRQ_TYPE_NONE);
@@ -253,11 +305,20 @@ static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
253 .xlate = mpc8xxx_gpio_irq_xlate, 305 .xlate = mpc8xxx_gpio_irq_xlate,
254}; 306};
255 307
308static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
309 { .compatible = "fsl,mpc8349-gpio", },
310 { .compatible = "fsl,mpc8572-gpio", },
311 { .compatible = "fsl,mpc8610-gpio", },
312 { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
313 {}
314};
315
256static void __init mpc8xxx_add_controller(struct device_node *np) 316static void __init mpc8xxx_add_controller(struct device_node *np)
257{ 317{
258 struct mpc8xxx_gpio_chip *mpc8xxx_gc; 318 struct mpc8xxx_gpio_chip *mpc8xxx_gc;
259 struct of_mm_gpio_chip *mm_gc; 319 struct of_mm_gpio_chip *mm_gc;
260 struct gpio_chip *gc; 320 struct gpio_chip *gc;
321 const struct of_device_id *id;
261 unsigned hwirq; 322 unsigned hwirq;
262 int ret; 323 int ret;
263 324
@@ -297,6 +358,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
297 if (!mpc8xxx_gc->irq) 358 if (!mpc8xxx_gc->irq)
298 goto skip_irq; 359 goto skip_irq;
299 360
361 id = of_match_node(mpc8xxx_gpio_ids, np);
362 if (id)
363 mpc8xxx_gc->of_dev_id_data = id->data;
364
300 mpc8xxx_gc->irq->host_data = mpc8xxx_gc; 365 mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
301 366
302 /* ack and mask all irqs */ 367 /* ack and mask all irqs */
@@ -321,13 +386,7 @@ static int __init mpc8xxx_add_gpiochips(void)
321{ 386{
322 struct device_node *np; 387 struct device_node *np;
323 388
324 for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio") 389 for_each_matching_node(np, mpc8xxx_gpio_ids)
325 mpc8xxx_add_controller(np);
326
327 for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio")
328 mpc8xxx_add_controller(np);
329
330 for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
331 mpc8xxx_add_controller(np); 390 mpc8xxx_add_controller(np);
332 391
333 return 0; 392 return 0;