aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/sysdev/qe_lib/Kconfig9
-rw-r--r--arch/powerpc/sysdev/qe_lib/Makefile1
-rw-r--r--arch/powerpc/sysdev/qe_lib/gpio.c146
3 files changed, 156 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index 76ffbc48d4b9..4bb18f57901e 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -24,3 +24,12 @@ config QE_USB
24 bool 24 bool
25 help 25 help
26 QE USB Host Controller support 26 QE USB Host Controller support
27
28config QE_GPIO
29 bool "QE GPIO support"
30 depends on QUICC_ENGINE
31 select GENERIC_GPIO
32 select HAVE_GPIO_LIB
33 help
34 Say Y here if you're going to use hardware that connects to the
35 QE GPIOs.
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
index e9ff8884f74a..f1855c185291 100644
--- a/arch/powerpc/sysdev/qe_lib/Makefile
+++ b/arch/powerpc/sysdev/qe_lib/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_UCC) += ucc.o
7obj-$(CONFIG_UCC_SLOW) += ucc_slow.o 7obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
8obj-$(CONFIG_UCC_FAST) += ucc_fast.o 8obj-$(CONFIG_UCC_FAST) += ucc_fast.o
9obj-$(CONFIG_QE_USB) += usb.o 9obj-$(CONFIG_QE_USB) += usb.o
10obj-$(CONFIG_QE_GPIO) += gpio.o
diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c
new file mode 100644
index 000000000000..c712e245dc4c
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/gpio.c
@@ -0,0 +1,146 @@
1/*
2 * QUICC Engine GPIOs
3 *
4 * Copyright (c) MontaVista Software, Inc. 2008.
5 *
6 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/spinlock.h>
16#include <linux/io.h>
17#include <linux/of.h>
18#include <linux/of_gpio.h>
19#include <linux/gpio.h>
20#include <asm/qe.h>
21
22struct qe_gpio_chip {
23 struct of_mm_gpio_chip mm_gc;
24 spinlock_t lock;
25
26 /* shadowed data register to clear/set bits safely */
27 u32 cpdata;
28};
29
30static inline struct qe_gpio_chip *
31to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
32{
33 return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
34}
35
36static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
37{
38 struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
39 struct qe_pio_regs __iomem *regs = mm_gc->regs;
40
41 qe_gc->cpdata = in_be32(&regs->cpdata);
42}
43
44static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
45{
46 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
47 struct qe_pio_regs __iomem *regs = mm_gc->regs;
48 u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
49
50 return in_be32(&regs->cpdata) & pin_mask;
51}
52
53static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
54{
55 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
56 struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
57 struct qe_pio_regs __iomem *regs = mm_gc->regs;
58 unsigned long flags;
59 u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
60
61 spin_lock_irqsave(&qe_gc->lock, flags);
62
63 if (val)
64 qe_gc->cpdata |= pin_mask;
65 else
66 qe_gc->cpdata &= ~pin_mask;
67
68 out_be32(&regs->cpdata, qe_gc->cpdata);
69
70 spin_unlock_irqrestore(&qe_gc->lock, flags);
71}
72
73static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
74{
75 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
76 struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
77 unsigned long flags;
78
79 spin_lock_irqsave(&qe_gc->lock, flags);
80
81 __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0);
82
83 spin_unlock_irqrestore(&qe_gc->lock, flags);
84
85 return 0;
86}
87
88static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
89{
90 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
91 struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
92 unsigned long flags;
93
94 spin_lock_irqsave(&qe_gc->lock, flags);
95
96 __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);
97
98 spin_unlock_irqrestore(&qe_gc->lock, flags);
99
100 qe_gpio_set(gc, gpio, val);
101
102 return 0;
103}
104
105void __init qe_add_gpiochips(void)
106{
107 struct device_node *np;
108
109 for_each_compatible_node(np, NULL, "fsl,mpc8323-qe-pario-bank") {
110 int ret;
111 struct qe_gpio_chip *qe_gc;
112 struct of_mm_gpio_chip *mm_gc;
113 struct of_gpio_chip *of_gc;
114 struct gpio_chip *gc;
115
116 qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
117 if (!qe_gc) {
118 ret = -ENOMEM;
119 goto err;
120 }
121
122 spin_lock_init(&qe_gc->lock);
123
124 mm_gc = &qe_gc->mm_gc;
125 of_gc = &mm_gc->of_gc;
126 gc = &of_gc->gc;
127
128 mm_gc->save_regs = qe_gpio_save_regs;
129 of_gc->gpio_cells = 2;
130 gc->ngpio = QE_PIO_PINS;
131 gc->direction_input = qe_gpio_dir_in;
132 gc->direction_output = qe_gpio_dir_out;
133 gc->get = qe_gpio_get;
134 gc->set = qe_gpio_set;
135
136 ret = of_mm_gpiochip_add(np, mm_gc);
137 if (ret)
138 goto err;
139 continue;
140err:
141 pr_err("%s: registration failed with status %d\n",
142 np->full_name, ret);
143 kfree(qe_gc);
144 /* try others anyway */
145 }
146}