diff options
| author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2008-12-03 14:27:38 -0500 |
|---|---|---|
| committer | Kumar Gala <galak@kernel.crashing.org> | 2008-12-30 12:13:43 -0500 |
| commit | 1b9e89046c31fd39d08742915b6bd72f6c239608 (patch) | |
| tree | 0fbb35ccfd0c0645db7b304277d48aa95b2375b5 /arch | |
| parent | 78c7705037ed9f107660178e17aa73f8bc4127e8 (diff) | |
powerpc/qe: Implement QE Pin Multiplexing API
With this API we're able to set a QE pin to the GPIO mode or a dedicated
peripheral function.
The API relies on the fact that QE gpio controllers are registered. If
they aren't, the API won't work (gracefully though).
There is one caveat though: if anybody occupied the node->data before us,
or overwrote it, then bad things will happen. Luckily this is all in the
platform code that we fully control, so this should never happen.
I could implement more checks (for example we could create a list of
successfully registered QE controllers, and compare the node->data in the
qe_pin_request()), but this is unneeded if nobody is going to do silly
things behind our back.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/powerpc/include/asm/qe.h | 21 | ||||
| -rw-r--r-- | arch/powerpc/sysdev/qe_lib/gpio.c | 195 |
2 files changed, 216 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index edee15d269ea..32274407b93a 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #ifdef __KERNEL__ | 17 | #ifdef __KERNEL__ |
| 18 | 18 | ||
| 19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/err.h> | ||
| 20 | #include <asm/cpm.h> | 22 | #include <asm/cpm.h> |
| 21 | #include <asm/immap_qe.h> | 23 | #include <asm/immap_qe.h> |
| 22 | 24 | ||
| @@ -112,6 +114,25 @@ extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, | |||
| 112 | int assignment, int has_irq); | 114 | int assignment, int has_irq); |
| 113 | extern int par_io_data_set(u8 port, u8 pin, u8 val); | 115 | extern int par_io_data_set(u8 port, u8 pin, u8 val); |
| 114 | 116 | ||
| 117 | /* | ||
| 118 | * Pin multiplexing functions. | ||
| 119 | */ | ||
| 120 | struct qe_pin; | ||
| 121 | #ifdef CONFIG_QE_GPIO | ||
| 122 | extern struct qe_pin *qe_pin_request(struct device_node *np, int index); | ||
| 123 | extern void qe_pin_free(struct qe_pin *qe_pin); | ||
| 124 | extern void qe_pin_set_gpio(struct qe_pin *qe_pin); | ||
| 125 | extern void qe_pin_set_dedicated(struct qe_pin *pin); | ||
| 126 | #else | ||
| 127 | static inline struct qe_pin *qe_pin_request(struct device_node *np, int index) | ||
| 128 | { | ||
| 129 | return ERR_PTR(-ENOSYS); | ||
| 130 | } | ||
| 131 | static inline void qe_pin_free(struct qe_pin *qe_pin) {} | ||
| 132 | static inline void qe_pin_set_gpio(struct qe_pin *qe_pin) {} | ||
| 133 | static inline void qe_pin_set_dedicated(struct qe_pin *pin) {} | ||
| 134 | #endif /* CONFIG_QE_GPIO */ | ||
| 135 | |||
| 115 | /* QE internal API */ | 136 | /* QE internal API */ |
| 116 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); | 137 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); |
| 117 | enum qe_clock qe_clock_source(const char *source); | 138 | enum qe_clock qe_clock_source(const char *source); |
diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 8e5a0bc36d0b..3485288dce31 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| 17 | #include <linux/err.h> | ||
| 17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
| 18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| 19 | #include <linux/of_gpio.h> | 20 | #include <linux/of_gpio.h> |
| @@ -24,8 +25,14 @@ struct qe_gpio_chip { | |||
| 24 | struct of_mm_gpio_chip mm_gc; | 25 | struct of_mm_gpio_chip mm_gc; |
| 25 | spinlock_t lock; | 26 | spinlock_t lock; |
| 26 | 27 | ||
| 28 | unsigned long pin_flags[QE_PIO_PINS]; | ||
| 29 | #define QE_PIN_REQUESTED 0 | ||
| 30 | |||
| 27 | /* shadowed data register to clear/set bits safely */ | 31 | /* shadowed data register to clear/set bits safely */ |
| 28 | u32 cpdata; | 32 | u32 cpdata; |
| 33 | |||
| 34 | /* saved_regs used to restore dedicated functions */ | ||
| 35 | struct qe_pio_regs saved_regs; | ||
| 29 | }; | 36 | }; |
| 30 | 37 | ||
| 31 | static inline struct qe_gpio_chip * | 38 | static inline struct qe_gpio_chip * |
| @@ -40,6 +47,12 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) | |||
| 40 | struct qe_pio_regs __iomem *regs = mm_gc->regs; | 47 | struct qe_pio_regs __iomem *regs = mm_gc->regs; |
| 41 | 48 | ||
| 42 | qe_gc->cpdata = in_be32(®s->cpdata); | 49 | qe_gc->cpdata = in_be32(®s->cpdata); |
| 50 | qe_gc->saved_regs.cpdata = qe_gc->cpdata; | ||
| 51 | qe_gc->saved_regs.cpdir1 = in_be32(®s->cpdir1); | ||
| 52 | qe_gc->saved_regs.cpdir2 = in_be32(®s->cpdir2); | ||
| 53 | qe_gc->saved_regs.cppar1 = in_be32(®s->cppar1); | ||
| 54 | qe_gc->saved_regs.cppar2 = in_be32(®s->cppar2); | ||
| 55 | qe_gc->saved_regs.cpodr = in_be32(®s->cpodr); | ||
| 43 | } | 56 | } |
| 44 | 57 | ||
| 45 | static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) | 58 | static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) |
| @@ -103,6 +116,188 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |||
| 103 | return 0; | 116 | return 0; |
| 104 | } | 117 | } |
| 105 | 118 | ||
| 119 | struct qe_pin { | ||
| 120 | /* | ||
| 121 | * The qe_gpio_chip name is unfortunate, we should change that to | ||
| 122 | * something like qe_pio_controller. Someday. | ||
| 123 | */ | ||
| 124 | struct qe_gpio_chip *controller; | ||
| 125 | int num; | ||
| 126 | }; | ||
| 127 | |||
| 128 | /** | ||
| 129 | * qe_pin_request - Request a QE pin | ||
| 130 | * @np: device node to get a pin from | ||
| 131 | * @index: index of a pin in the device tree | ||
| 132 | * Context: non-atomic | ||
| 133 | * | ||
| 134 | * This function return qe_pin so that you could use it with the rest of | ||
| 135 | * the QE Pin Multiplexing API. | ||
| 136 | */ | ||
| 137 | struct qe_pin *qe_pin_request(struct device_node *np, int index) | ||
| 138 | { | ||
| 139 | struct qe_pin *qe_pin; | ||
| 140 | struct device_node *gc; | ||
| 141 | struct of_gpio_chip *of_gc = NULL; | ||
| 142 | struct of_mm_gpio_chip *mm_gc; | ||
| 143 | struct qe_gpio_chip *qe_gc; | ||
| 144 | int err; | ||
| 145 | int size; | ||
| 146 | const void *gpio_spec; | ||
| 147 | const u32 *gpio_cells; | ||
| 148 | unsigned long flags; | ||
| 149 | |||
| 150 | qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL); | ||
| 151 | if (!qe_pin) { | ||
| 152 | pr_debug("%s: can't allocate memory\n", __func__); | ||
| 153 | return ERR_PTR(-ENOMEM); | ||
| 154 | } | ||
| 155 | |||
| 156 | err = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, | ||
| 157 | &gc, &gpio_spec); | ||
| 158 | if (err) { | ||
| 159 | pr_debug("%s: can't parse gpios property\n", __func__); | ||
| 160 | goto err0; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (!of_device_is_compatible(gc, "fsl,mpc8323-qe-pario-bank")) { | ||
| 164 | pr_debug("%s: tried to get a non-qe pin\n", __func__); | ||
| 165 | err = -EINVAL; | ||
| 166 | goto err1; | ||
| 167 | } | ||
| 168 | |||
| 169 | of_gc = gc->data; | ||
| 170 | if (!of_gc) { | ||
| 171 | pr_debug("%s: gpio controller %s isn't registered\n", | ||
| 172 | np->full_name, gc->full_name); | ||
| 173 | err = -ENODEV; | ||
| 174 | goto err1; | ||
| 175 | } | ||
| 176 | |||
| 177 | gpio_cells = of_get_property(gc, "#gpio-cells", &size); | ||
| 178 | if (!gpio_cells || size != sizeof(*gpio_cells) || | ||
| 179 | *gpio_cells != of_gc->gpio_cells) { | ||
| 180 | pr_debug("%s: wrong #gpio-cells for %s\n", | ||
| 181 | np->full_name, gc->full_name); | ||
| 182 | err = -EINVAL; | ||
| 183 | goto err1; | ||
| 184 | } | ||
| 185 | |||
| 186 | err = of_gc->xlate(of_gc, np, gpio_spec, NULL); | ||
| 187 | if (err < 0) | ||
| 188 | goto err1; | ||
| 189 | |||
| 190 | mm_gc = to_of_mm_gpio_chip(&of_gc->gc); | ||
| 191 | qe_gc = to_qe_gpio_chip(mm_gc); | ||
| 192 | |||
| 193 | spin_lock_irqsave(&qe_gc->lock, flags); | ||
| 194 | |||
| 195 | if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) { | ||
| 196 | qe_pin->controller = qe_gc; | ||
| 197 | qe_pin->num = err; | ||
| 198 | err = 0; | ||
| 199 | } else { | ||
| 200 | err = -EBUSY; | ||
| 201 | } | ||
| 202 | |||
| 203 | spin_unlock_irqrestore(&qe_gc->lock, flags); | ||
| 204 | |||
| 205 | if (!err) | ||
| 206 | return qe_pin; | ||
| 207 | err1: | ||
| 208 | of_node_put(gc); | ||
| 209 | err0: | ||
| 210 | kfree(qe_pin); | ||
| 211 | pr_debug("%s failed with status %d\n", __func__, err); | ||
| 212 | return ERR_PTR(err); | ||
| 213 | } | ||
| 214 | EXPORT_SYMBOL(qe_pin_request); | ||
| 215 | |||
| 216 | /** | ||
| 217 | * qe_pin_free - Free a pin | ||
| 218 | * @qe_pin: pointer to the qe_pin structure | ||
| 219 | * Context: any | ||
| 220 | * | ||
| 221 | * This function frees the qe_pin structure and makes a pin available | ||
| 222 | * for further qe_pin_request() calls. | ||
| 223 | */ | ||
| 224 | void qe_pin_free(struct qe_pin *qe_pin) | ||
| 225 | { | ||
| 226 | struct qe_gpio_chip *qe_gc = qe_pin->controller; | ||
| 227 | unsigned long flags; | ||
| 228 | const int pin = qe_pin->num; | ||
| 229 | |||
| 230 | spin_lock_irqsave(&qe_gc->lock, flags); | ||
| 231 | test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]); | ||
| 232 | spin_unlock_irqrestore(&qe_gc->lock, flags); | ||
| 233 | |||
| 234 | kfree(qe_pin); | ||
| 235 | } | ||
| 236 | EXPORT_SYMBOL(qe_pin_free); | ||
| 237 | |||
| 238 | /** | ||
| 239 | * qe_pin_set_dedicated - Revert a pin to a dedicated peripheral function mode | ||
| 240 | * @qe_pin: pointer to the qe_pin structure | ||
| 241 | * Context: any | ||
| 242 | * | ||
| 243 | * This function resets a pin to a dedicated peripheral function that | ||
| 244 | * has been set up by the firmware. | ||
| 245 | */ | ||
| 246 | void qe_pin_set_dedicated(struct qe_pin *qe_pin) | ||
| 247 | { | ||
| 248 | struct qe_gpio_chip *qe_gc = qe_pin->controller; | ||
| 249 | struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; | ||
| 250 | struct qe_pio_regs *sregs = &qe_gc->saved_regs; | ||
| 251 | int pin = qe_pin->num; | ||
| 252 | u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1)); | ||
| 253 | u32 mask2 = 0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2); | ||
| 254 | bool second_reg = pin > (QE_PIO_PINS / 2) - 1; | ||
| 255 | unsigned long flags; | ||
| 256 | |||
| 257 | spin_lock_irqsave(&qe_gc->lock, flags); | ||
| 258 | |||
| 259 | if (second_reg) { | ||
| 260 | clrsetbits_be32(®s->cpdir2, mask2, sregs->cpdir2 & mask2); | ||
| 261 | clrsetbits_be32(®s->cppar2, mask2, sregs->cppar2 & mask2); | ||
| 262 | } else { | ||
| 263 | clrsetbits_be32(®s->cpdir1, mask2, sregs->cpdir1 & mask2); | ||
| 264 | clrsetbits_be32(®s->cppar1, mask2, sregs->cppar1 & mask2); | ||
| 265 | } | ||
| 266 | |||
| 267 | if (sregs->cpdata & mask1) | ||
| 268 | qe_gc->cpdata |= mask1; | ||
| 269 | else | ||
| 270 | qe_gc->cpdata &= ~mask1; | ||
| 271 | |||
| 272 | out_be32(®s->cpdata, qe_gc->cpdata); | ||
| 273 | clrsetbits_be32(®s->cpodr, mask1, sregs->cpodr & mask1); | ||
| 274 | |||
| 275 | spin_unlock_irqrestore(&qe_gc->lock, flags); | ||
| 276 | } | ||
| 277 | EXPORT_SYMBOL(qe_pin_set_dedicated); | ||
| 278 | |||
| 279 | /** | ||
| 280 | * qe_pin_set_gpio - Set a pin to the GPIO mode | ||
| 281 | * @qe_pin: pointer to the qe_pin structure | ||
| 282 | * Context: any | ||
| 283 | * | ||
| 284 | * This function sets a pin to the GPIO mode. | ||
| 285 | */ | ||
| 286 | void qe_pin_set_gpio(struct qe_pin *qe_pin) | ||
| 287 | { | ||
| 288 | struct qe_gpio_chip *qe_gc = qe_pin->controller; | ||
| 289 | struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | spin_lock_irqsave(&qe_gc->lock, flags); | ||
| 293 | |||
| 294 | /* Let's make it input by default, GPIO API is able to change that. */ | ||
| 295 | __par_io_config_pin(regs, qe_pin->num, QE_PIO_DIR_IN, 0, 0, 0); | ||
| 296 | |||
| 297 | spin_unlock_irqrestore(&qe_gc->lock, flags); | ||
| 298 | } | ||
| 299 | EXPORT_SYMBOL(qe_pin_set_gpio); | ||
| 300 | |||
| 106 | static int __init qe_add_gpiochips(void) | 301 | static int __init qe_add_gpiochips(void) |
| 107 | { | 302 | { |
| 108 | struct device_node *np; | 303 | struct device_node *np; |
