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

rdc321x: GPIO routines bugfixes

This patch fixes the use of GPIO routines which are in the PCI
configuration space of the RDC321x, therefore reading/writing
to this space without spinlock protection can be problematic.

We also now request and free GPIOs and support the MGB100
board, previous code was very AR525W-centric.

Signed-off-by: Volker Weiss <volker@tintuc.de>
Signed-off-by: Florian Fainelli <florian.fainelli@telecomint.eu>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Florian Fainelli and committed by
Ingo Molnar
b2ef7497 d8d4f157

+167 -55
+153 -50
arch/x86/mach-rdc321x/gpio.c
··· 1 1 /* 2 - * Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org> 3 - * RDC321x architecture specific GPIO support 2 + * GPIO support for RDC SoC R3210/R8610 4 3 * 5 - * This program is free software; you can redistribute it and/or modify it 6 - * under the terms of the GNU General Public License as published by the 7 - * Free Software Foundation; either version 2 of the License, or (at your 8 - * option) any later version. 4 + * Copyright (C) 2007, Florian Fainelli <florian@openwrt.org> 5 + * Copyright (C) 2008, Volker Weiss <dev@tintuc.de> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License 18 + * along with this program; if not, write to the Free Software 19 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 + * 9 21 */ 10 22 11 - #include <linux/autoconf.h> 12 - #include <linux/init.h> 23 + 24 + #include <linux/spinlock.h> 13 25 #include <linux/io.h> 14 26 #include <linux/types.h> 15 27 #include <linux/module.h> 16 - #include <linux/delay.h> 17 28 29 + #include <asm/gpio.h> 18 30 #include <asm/mach-rdc321x/rdc321x_defs.h> 19 31 20 - static inline int rdc_gpio_is_valid(unsigned gpio) 32 + 33 + /* spin lock to protect our private copy of GPIO data register plus 34 + the access to PCI conf registers. */ 35 + static DEFINE_SPINLOCK(gpio_lock); 36 + 37 + /* copy of GPIO data registers */ 38 + static u32 gpio_data_reg1; 39 + static u32 gpio_data_reg2; 40 + 41 + static u32 gpio_request_data[2]; 42 + 43 + 44 + static inline void rdc321x_conf_write(unsigned addr, u32 value) 21 45 { 22 - return (gpio <= RDC_MAX_GPIO); 46 + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); 47 + outl(value, RDC3210_CFGREG_DATA); 23 48 } 24 49 25 - static unsigned int rdc_gpio_read(unsigned gpio) 50 + static inline void rdc321x_conf_or(unsigned addr, u32 value) 26 51 { 27 - unsigned int val; 28 - 29 - val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x84:0x48)); 30 - outl(val, RDC3210_CFGREG_ADDR); 31 - udelay(10); 32 - val = inl(RDC3210_CFGREG_DATA); 33 - val |= (0x1 << (gpio & 0x1F)); 34 - outl(val, RDC3210_CFGREG_DATA); 35 - udelay(10); 36 - val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x88:0x4C)); 37 - outl(val, RDC3210_CFGREG_ADDR); 38 - udelay(10); 39 - val = inl(RDC3210_CFGREG_DATA); 40 - 41 - return val; 52 + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); 53 + value |= inl(RDC3210_CFGREG_DATA); 54 + outl(value, RDC3210_CFGREG_DATA); 42 55 } 43 56 44 - static void rdc_gpio_write(unsigned int val) 57 + static inline u32 rdc321x_conf_read(unsigned addr) 45 58 { 46 - if (val) { 47 - outl(val, RDC3210_CFGREG_DATA); 48 - udelay(10); 49 - } 59 + outl((1 << 31) | (7 << 11) | addr, RDC3210_CFGREG_ADDR); 60 + 61 + return inl(RDC3210_CFGREG_DATA); 50 62 } 51 63 64 + /* configure pin as GPIO */ 65 + static void rdc321x_configure_gpio(unsigned gpio) 66 + { 67 + unsigned long flags; 68 + 69 + spin_lock_irqsave(&gpio_lock, flags); 70 + rdc321x_conf_or(gpio < 32 71 + ? RDC321X_GPIO_CTRL_REG1 : RDC321X_GPIO_CTRL_REG2, 72 + 1 << (gpio & 0x1f)); 73 + spin_unlock_irqrestore(&gpio_lock, flags); 74 + } 75 + 76 + /* initially setup the 2 copies of the gpio data registers. 77 + This function must be called by the platform setup code. */ 78 + void __init rdc321x_gpio_setup() 79 + { 80 + /* this might not be, what others (BIOS, bootloader, etc.) 81 + wrote to these registers before, but it's a good guess. Still 82 + better than just using 0xffffffff. */ 83 + 84 + gpio_data_reg1 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG1); 85 + gpio_data_reg2 = rdc321x_conf_read(RDC321X_GPIO_DATA_REG2); 86 + } 87 + 88 + /* determine, if gpio number is valid */ 89 + static inline int rdc321x_is_gpio(unsigned gpio) 90 + { 91 + return gpio <= RDC321X_MAX_GPIO; 92 + } 93 + 94 + /* request GPIO */ 95 + int rdc_gpio_request(unsigned gpio, const char *label) 96 + { 97 + unsigned long flags; 98 + 99 + if (!rdc321x_is_gpio(gpio)) 100 + return -EINVAL; 101 + 102 + spin_lock_irqsave(&gpio_lock, flags); 103 + if (gpio_request_data[(gpio & 0x20) ? 1 : 0] & (1 << (gpio & 0x1f))) 104 + goto inuse; 105 + gpio_request_data[(gpio & 0x20) ? 1 : 0] |= (1 << (gpio & 0x1f)); 106 + spin_unlock_irqrestore(&gpio_lock, flags); 107 + 108 + return 0; 109 + inuse: 110 + spin_unlock_irqrestore(&gpio_lock, flags); 111 + return -EINVAL; 112 + } 113 + EXPORT_SYMBOL(rdc_gpio_request); 114 + 115 + /* release previously-claimed GPIO */ 116 + void rdc_gpio_free(unsigned gpio) 117 + { 118 + unsigned long flags; 119 + 120 + if (!rdc321x_is_gpio(gpio)) 121 + return; 122 + 123 + spin_lock_irqsave(&gpio_lock, flags); 124 + gpio_request_data[(gpio & 0x20) ? 1 : 0] &= ~(1 << (gpio & 0x1f)); 125 + spin_unlock_irqrestore(&gpio_lock, flags); 126 + } 127 + EXPORT_SYMBOL(rdc_gpio_free); 128 + 129 + /* read GPIO pin */ 52 130 int rdc_gpio_get_value(unsigned gpio) 53 131 { 54 - if (rdc_gpio_is_valid(gpio)) 55 - return (int)rdc_gpio_read(gpio); 56 - else 57 - return -EINVAL; 132 + u32 reg; 133 + unsigned long flags; 134 + 135 + spin_lock_irqsave(&gpio_lock, flags); 136 + reg = rdc321x_conf_read(gpio < 32 137 + ? RDC321X_GPIO_DATA_REG1 : RDC321X_GPIO_DATA_REG2); 138 + spin_unlock_irqrestore(&gpio_lock, flags); 139 + 140 + return (1 << (gpio & 0x1f)) & reg ? 1 : 0; 58 141 } 59 142 EXPORT_SYMBOL(rdc_gpio_get_value); 60 143 144 + /* set GPIO pin to value */ 61 145 void rdc_gpio_set_value(unsigned gpio, int value) 62 146 { 63 - unsigned int val; 147 + unsigned long flags; 148 + u32 reg; 64 149 65 - if (!rdc_gpio_is_valid(gpio)) 66 - return; 67 - 68 - val = rdc_gpio_read(gpio); 69 - 70 - if (value) 71 - val &= ~(0x1 << (gpio & 0x1F)); 72 - else 73 - val |= (0x1 << (gpio & 0x1F)); 74 - 75 - rdc_gpio_write(val); 150 + reg = 1 << (gpio & 0x1f); 151 + if (gpio < 32) { 152 + spin_lock_irqsave(&gpio_lock, flags); 153 + if (value) 154 + gpio_data_reg1 |= reg; 155 + else 156 + gpio_data_reg1 &= ~reg; 157 + rdc321x_conf_write(RDC321X_GPIO_DATA_REG1, gpio_data_reg1); 158 + spin_unlock_irqrestore(&gpio_lock, flags); 159 + } else { 160 + spin_lock_irqsave(&gpio_lock, flags); 161 + if (value) 162 + gpio_data_reg2 |= reg; 163 + else 164 + gpio_data_reg2 &= ~reg; 165 + rdc321x_conf_write(RDC321X_GPIO_DATA_REG2, gpio_data_reg2); 166 + spin_unlock_irqrestore(&gpio_lock, flags); 167 + } 76 168 } 77 169 EXPORT_SYMBOL(rdc_gpio_set_value); 78 170 171 + /* configure GPIO pin as input */ 79 172 int rdc_gpio_direction_input(unsigned gpio) 80 173 { 174 + if (!rdc321x_is_gpio(gpio)) 175 + return -EINVAL; 176 + 177 + rdc321x_configure_gpio(gpio); 178 + 81 179 return 0; 82 180 } 83 181 EXPORT_SYMBOL(rdc_gpio_direction_input); 84 182 183 + /* configure GPIO pin as output and set value */ 85 184 int rdc_gpio_direction_output(unsigned gpio, int value) 86 185 { 186 + if (!rdc321x_is_gpio(gpio)) 187 + return -EINVAL; 188 + 189 + gpio_set_value(gpio, value); 190 + rdc321x_configure_gpio(gpio); 191 + 87 192 return 0; 88 193 } 89 194 EXPORT_SYMBOL(rdc_gpio_direction_output); 90 - 91 -
+2
arch/x86/mach-rdc321x/platform.c
··· 62 62 63 63 static int __init rdc_board_setup(void) 64 64 { 65 + rdc321x_gpio_setup(); 66 + 65 67 return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); 66 68 } 67 69
+5 -4
include/asm-x86/mach-rdc321x/gpio.h
··· 5 5 extern void rdc_gpio_set_value(unsigned gpio, int value); 6 6 extern int rdc_gpio_direction_input(unsigned gpio); 7 7 extern int rdc_gpio_direction_output(unsigned gpio, int value); 8 - 8 + extern int rdc_gpio_request(unsigned gpio, const char *label); 9 + extern void rdc_gpio_free(unsigned gpio); 10 + extern void __init rdc321x_gpio_setup(void); 9 11 10 12 /* Wrappers for the arch-neutral GPIO API */ 11 13 12 14 static inline int gpio_request(unsigned gpio, const char *label) 13 15 { 14 - /* Not yet implemented */ 15 - return 0; 16 + return rdc_gpio_request(gpio, label); 16 17 } 17 18 18 19 static inline void gpio_free(unsigned gpio) 19 20 { 20 - /* Not yet implemented */ 21 + rdc_gpio_free(gpio); 21 22 } 22 23 23 24 static inline int gpio_direction_input(unsigned gpio)
+7 -1
include/asm-x86/mach-rdc321x/rdc321x_defs.h
··· 3 3 /* General purpose configuration and data registers */ 4 4 #define RDC3210_CFGREG_ADDR 0x0CF8 5 5 #define RDC3210_CFGREG_DATA 0x0CFC 6 - #define RDC_MAX_GPIO 0x3A 6 + 7 + #define RDC321X_GPIO_CTRL_REG1 0x48 8 + #define RDC321X_GPIO_CTRL_REG2 0x84 9 + #define RDC321X_GPIO_DATA_REG1 0x4c 10 + #define RDC321X_GPIO_DATA_REG2 0x88 11 + 12 + #define RDC321X_MAX_GPIO 58