Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Implement GPIO driver for simple memory-mapped banks

The driver supports very simple GPIO controllers, that is, when a
controller provides just a 'data' register. Such controllers may be
found in various BCSRs (Board's FPGAs used to control board's
switches, LEDs, chip-selects, Ethernet/USB PHY power, etc).

So far we support only 1-byte GPIO banks. Support for other widths may
be implemented when/if needed.

p.s.
To avoid "made up" compatible entries (like compatible = "simple-gpio"),
boards must call simple_gpiochip_init() to pass the compatible string.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

authored by

Anton Vorontsov and committed by
Kumar Gala
3d64de9c 94409d6e

+179
+11
arch/powerpc/platforms/Kconfig
··· 312 312 Say Y here if you're going to use hardware that connects to the 313 313 MPC831x/834x/837x/8572/8610 GPIOs. 314 314 315 + config SIMPLE_GPIO 316 + bool "Support for simple, memory-mapped GPIO controllers" 317 + depends on PPC 318 + select GENERIC_GPIO 319 + select ARCH_REQUIRE_GPIOLIB 320 + help 321 + Say Y here to support simple, memory-mapped GPIO controllers. 322 + These are usually BCSRs used to control board's switches, LEDs, 323 + chip-selects, Ethernet/USB PHY's power and various other small 324 + on-board peripherals. 325 + 315 326 endmenu
+1
arch/powerpc/sysdev/Makefile
··· 17 17 obj-$(CONFIG_FSL_LBC) += fsl_lbc.o 18 18 obj-$(CONFIG_FSL_GTM) += fsl_gtm.o 19 19 obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o 20 + obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o 20 21 obj-$(CONFIG_RAPIDIO) += fsl_rio.o 21 22 obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 22 23 obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
+155
arch/powerpc/sysdev/simple_gpio.c
··· 1 + /* 2 + * Simple Memory-Mapped 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/init.h> 15 + #include <linux/kernel.h> 16 + #include <linux/module.h> 17 + #include <linux/spinlock.h> 18 + #include <linux/types.h> 19 + #include <linux/ioport.h> 20 + #include <linux/io.h> 21 + #include <linux/of.h> 22 + #include <linux/of_gpio.h> 23 + #include <linux/gpio.h> 24 + #include <asm/prom.h> 25 + #include "simple_gpio.h" 26 + 27 + struct u8_gpio_chip { 28 + struct of_mm_gpio_chip mm_gc; 29 + spinlock_t lock; 30 + 31 + /* shadowed data register to clear/set bits safely */ 32 + u8 data; 33 + }; 34 + 35 + static struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc) 36 + { 37 + return container_of(mm_gc, struct u8_gpio_chip, mm_gc); 38 + } 39 + 40 + static u8 u8_pin2mask(unsigned int pin) 41 + { 42 + return 1 << (8 - 1 - pin); 43 + } 44 + 45 + static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) 46 + { 47 + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 48 + 49 + return in_8(mm_gc->regs) & u8_pin2mask(gpio); 50 + } 51 + 52 + static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 53 + { 54 + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 55 + struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); 56 + unsigned long flags; 57 + 58 + spin_lock_irqsave(&u8_gc->lock, flags); 59 + 60 + if (val) 61 + u8_gc->data |= u8_pin2mask(gpio); 62 + else 63 + u8_gc->data &= ~u8_pin2mask(gpio); 64 + 65 + out_8(mm_gc->regs, u8_gc->data); 66 + 67 + spin_unlock_irqrestore(&u8_gc->lock, flags); 68 + } 69 + 70 + static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 71 + { 72 + return 0; 73 + } 74 + 75 + static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 76 + { 77 + u8_gpio_set(gc, gpio, val); 78 + return 0; 79 + } 80 + 81 + static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) 82 + { 83 + struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); 84 + 85 + u8_gc->data = in_8(mm_gc->regs); 86 + } 87 + 88 + static int __init u8_simple_gpiochip_add(struct device_node *np) 89 + { 90 + int ret; 91 + struct u8_gpio_chip *u8_gc; 92 + struct of_mm_gpio_chip *mm_gc; 93 + struct of_gpio_chip *of_gc; 94 + struct gpio_chip *gc; 95 + 96 + u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL); 97 + if (!u8_gc) 98 + return -ENOMEM; 99 + 100 + spin_lock_init(&u8_gc->lock); 101 + 102 + mm_gc = &u8_gc->mm_gc; 103 + of_gc = &mm_gc->of_gc; 104 + gc = &of_gc->gc; 105 + 106 + mm_gc->save_regs = u8_gpio_save_regs; 107 + of_gc->gpio_cells = 2; 108 + gc->ngpio = 8; 109 + gc->direction_input = u8_gpio_dir_in; 110 + gc->direction_output = u8_gpio_dir_out; 111 + gc->get = u8_gpio_get; 112 + gc->set = u8_gpio_set; 113 + 114 + ret = of_mm_gpiochip_add(np, mm_gc); 115 + if (ret) 116 + goto err; 117 + return 0; 118 + err: 119 + kfree(u8_gc); 120 + return ret; 121 + } 122 + 123 + void __init simple_gpiochip_init(const char *compatible) 124 + { 125 + struct device_node *np; 126 + 127 + for_each_compatible_node(np, NULL, compatible) { 128 + int ret; 129 + struct resource r; 130 + 131 + ret = of_address_to_resource(np, 0, &r); 132 + if (ret) 133 + goto err; 134 + 135 + switch (resource_size(&r)) { 136 + case 1: 137 + ret = u8_simple_gpiochip_add(np); 138 + if (ret) 139 + goto err; 140 + break; 141 + default: 142 + /* 143 + * Whenever you need support for GPIO bank width > 1, 144 + * please just turn u8_ code into huge macros, and 145 + * construct needed uX_ code with it. 146 + */ 147 + ret = -ENOSYS; 148 + goto err; 149 + } 150 + continue; 151 + err: 152 + pr_err("%s: registration failed, status %d\n", 153 + np->full_name, ret); 154 + } 155 + }
+12
arch/powerpc/sysdev/simple_gpio.h
··· 1 + #ifndef __SYSDEV_SIMPLE_GPIO_H 2 + #define __SYSDEV_SIMPLE_GPIO_H 3 + 4 + #include <linux/errno.h> 5 + 6 + #ifdef CONFIG_SIMPLE_GPIO 7 + extern void simple_gpiochip_init(const char *compatible); 8 + #else 9 + static inline void simple_gpiochip_init(const char *compatible) {} 10 + #endif /* CONFIG_SIMPLE_GPIO */ 11 + 12 + #endif /* __SYSDEV_SIMPLE_GPIO_H */