gpio: add Intel SCH GPIO controller driver

Signed-off-by: Denis Turischev <denis@compulab.co.il>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by Denis Turischev and committed by Samuel Ortiz be9b06b2 fd46a006

+299
+16
drivers/gpio/Kconfig
··· 94 help 95 Say yes here to support the NEC VR4100 series General-purpose I/O Uint 96 97 comment "I2C GPIO expanders:" 98 99 config GPIO_MAX7300
··· 94 help 95 Say yes here to support the NEC VR4100 series General-purpose I/O Uint 96 97 + config GPIO_SCH 98 + tristate "Intel SCH GPIO" 99 + depends on GPIOLIB 100 + select LPC_SCH 101 + help 102 + Say yes here to support GPIO interface on Intel Poulsbo SCH. 103 + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are 104 + powered by the core power rail and are turned off during sleep 105 + modes (S3 and higher). The remaining four GPIOs are powered by 106 + the Intel SCH suspend power supply. These GPIOs remain 107 + active during S3. The suspend powered GPIOs can be used to wake the 108 + system from the Suspend-to-RAM state. 109 + 110 + This driver can also be built as a module. If so, the module 111 + will be called sch-gpio. 112 + 113 comment "I2C GPIO expanders:" 114 115 config GPIO_MAX7300
+1
drivers/gpio/Makefile
··· 27 obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o 28 obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o 29 obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o
··· 27 obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o 28 obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o 29 obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o 30 + obj-$(CONFIG_GPIO_SCH) += sch_gpio.o
+282
drivers/gpio/sch_gpio.c
···
··· 1 + /* 2 + * sch_gpio.c - GPIO interface for Intel Poulsbo SCH 3 + * 4 + * Copyright (c) 2010 CompuLab Ltd 5 + * Author: Denis Turischev <denis@compulab.co.il> 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 2 as published 9 + * by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; see the file COPYING. If not, write to 18 + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + 21 + #include <linux/init.h> 22 + #include <linux/kernel.h> 23 + #include <linux/module.h> 24 + #include <linux/io.h> 25 + #include <linux/errno.h> 26 + #include <linux/acpi.h> 27 + #include <linux/platform_device.h> 28 + 29 + #include <linux/gpio.h> 30 + 31 + static DEFINE_SPINLOCK(gpio_lock); 32 + 33 + #define CGEN (0x00) 34 + #define CGIO (0x04) 35 + #define CGLV (0x08) 36 + 37 + #define RGEN (0x20) 38 + #define RGIO (0x24) 39 + #define RGLV (0x28) 40 + 41 + static unsigned short gpio_ba; 42 + 43 + static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num) 44 + { 45 + u8 curr_dirs; 46 + unsigned short offset, bit; 47 + 48 + spin_lock(&gpio_lock); 49 + 50 + offset = CGIO + gpio_num / 8; 51 + bit = gpio_num % 8; 52 + 53 + curr_dirs = inb(gpio_ba + offset); 54 + 55 + if (!(curr_dirs & (1 << bit))) 56 + outb(curr_dirs | (1 << bit), gpio_ba + offset); 57 + 58 + spin_unlock(&gpio_lock); 59 + return 0; 60 + } 61 + 62 + static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num) 63 + { 64 + int res; 65 + unsigned short offset, bit; 66 + 67 + offset = CGLV + gpio_num / 8; 68 + bit = gpio_num % 8; 69 + 70 + res = !!(inb(gpio_ba + offset) & (1 << bit)); 71 + return res; 72 + } 73 + 74 + static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val) 75 + { 76 + u8 curr_vals; 77 + unsigned short offset, bit; 78 + 79 + spin_lock(&gpio_lock); 80 + 81 + offset = CGLV + gpio_num / 8; 82 + bit = gpio_num % 8; 83 + 84 + curr_vals = inb(gpio_ba + offset); 85 + 86 + if (val) 87 + outb(curr_vals | (1 << bit), gpio_ba + offset); 88 + else 89 + outb((curr_vals & ~(1 << bit)), gpio_ba + offset); 90 + spin_unlock(&gpio_lock); 91 + } 92 + 93 + static int sch_gpio_core_direction_out(struct gpio_chip *gc, 94 + unsigned gpio_num, int val) 95 + { 96 + u8 curr_dirs; 97 + unsigned short offset, bit; 98 + 99 + sch_gpio_core_set(gc, gpio_num, val); 100 + 101 + spin_lock(&gpio_lock); 102 + 103 + offset = CGIO + gpio_num / 8; 104 + bit = gpio_num % 8; 105 + 106 + curr_dirs = inb(gpio_ba + offset); 107 + if (curr_dirs & (1 << bit)) 108 + outb(curr_dirs & ~(1 << bit), gpio_ba + offset); 109 + 110 + spin_unlock(&gpio_lock); 111 + return 0; 112 + } 113 + 114 + static struct gpio_chip sch_gpio_core = { 115 + .label = "sch_gpio_core", 116 + .owner = THIS_MODULE, 117 + .direction_input = sch_gpio_core_direction_in, 118 + .get = sch_gpio_core_get, 119 + .direction_output = sch_gpio_core_direction_out, 120 + .set = sch_gpio_core_set, 121 + }; 122 + 123 + static int sch_gpio_resume_direction_in(struct gpio_chip *gc, 124 + unsigned gpio_num) 125 + { 126 + u8 curr_dirs; 127 + 128 + spin_lock(&gpio_lock); 129 + 130 + curr_dirs = inb(gpio_ba + RGIO); 131 + 132 + if (!(curr_dirs & (1 << gpio_num))) 133 + outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); 134 + 135 + spin_unlock(&gpio_lock); 136 + return 0; 137 + } 138 + 139 + static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) 140 + { 141 + return !!(inb(gpio_ba + RGLV) & (1 << gpio_num)); 142 + } 143 + 144 + static void sch_gpio_resume_set(struct gpio_chip *gc, 145 + unsigned gpio_num, int val) 146 + { 147 + u8 curr_vals; 148 + 149 + spin_lock(&gpio_lock); 150 + 151 + curr_vals = inb(gpio_ba + RGLV); 152 + 153 + if (val) 154 + outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); 155 + else 156 + outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); 157 + 158 + spin_unlock(&gpio_lock); 159 + } 160 + 161 + static int sch_gpio_resume_direction_out(struct gpio_chip *gc, 162 + unsigned gpio_num, int val) 163 + { 164 + u8 curr_dirs; 165 + 166 + sch_gpio_resume_set(gc, gpio_num, val); 167 + 168 + spin_lock(&gpio_lock); 169 + 170 + curr_dirs = inb(gpio_ba + RGIO); 171 + if (curr_dirs & (1 << gpio_num)) 172 + outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); 173 + 174 + spin_unlock(&gpio_lock); 175 + return 0; 176 + } 177 + 178 + static struct gpio_chip sch_gpio_resume = { 179 + .label = "sch_gpio_resume", 180 + .owner = THIS_MODULE, 181 + .direction_input = sch_gpio_resume_direction_in, 182 + .get = sch_gpio_resume_get, 183 + .direction_output = sch_gpio_resume_direction_out, 184 + .set = sch_gpio_resume_set, 185 + }; 186 + 187 + static int __devinit sch_gpio_probe(struct platform_device *pdev) 188 + { 189 + struct resource *res; 190 + int err; 191 + 192 + res = platform_get_resource(pdev, IORESOURCE_IO, 0); 193 + if (!res) 194 + return -EBUSY; 195 + 196 + if (!request_region(res->start, resource_size(res), pdev->name)) 197 + return -EBUSY; 198 + 199 + gpio_ba = res->start; 200 + 201 + sch_gpio_core.base = 0; 202 + sch_gpio_core.ngpio = 10; 203 + sch_gpio_core.dev = &pdev->dev; 204 + 205 + sch_gpio_resume.base = 10; 206 + sch_gpio_resume.ngpio = 4; 207 + sch_gpio_resume.dev = &pdev->dev; 208 + 209 + err = gpiochip_add(&sch_gpio_core); 210 + if (err < 0) 211 + goto err_sch_gpio_core; 212 + 213 + err = gpiochip_add(&sch_gpio_resume); 214 + if (err < 0) 215 + goto err_sch_gpio_resume; 216 + 217 + /* 218 + * GPIO[6:0] enabled by default 219 + * GPIO7 is configured by the CMC as SLPIOVR 220 + * Enable GPIO[9:8] core powered gpios explicitly 221 + */ 222 + outb(0x3, gpio_ba + CGEN + 1); 223 + /* 224 + * SUS_GPIO[2:0] enabled by default 225 + * Enable SUS_GPIO3 resume powered gpio explicitly 226 + */ 227 + outb(0x8, gpio_ba + RGEN); 228 + 229 + return 0; 230 + 231 + err_sch_gpio_resume: 232 + gpiochip_remove(&sch_gpio_core); 233 + 234 + err_sch_gpio_core: 235 + release_region(res->start, resource_size(res)); 236 + gpio_ba = 0; 237 + 238 + return err; 239 + } 240 + 241 + static int __devexit sch_gpio_remove(struct platform_device *pdev) 242 + { 243 + struct resource *res; 244 + if (gpio_ba) { 245 + gpiochip_remove(&sch_gpio_core); 246 + gpiochip_remove(&sch_gpio_resume); 247 + 248 + res = platform_get_resource(pdev, IORESOURCE_IO, 0); 249 + 250 + release_region(res->start, resource_size(res)); 251 + gpio_ba = 0; 252 + } 253 + 254 + return 0; 255 + } 256 + 257 + static struct platform_driver sch_gpio_driver = { 258 + .driver = { 259 + .name = "sch_gpio", 260 + .owner = THIS_MODULE, 261 + }, 262 + .probe = sch_gpio_probe, 263 + .remove = __devexit_p(sch_gpio_remove), 264 + }; 265 + 266 + static int __init sch_gpio_init(void) 267 + { 268 + return platform_driver_register(&sch_gpio_driver); 269 + } 270 + 271 + static void __exit sch_gpio_exit(void) 272 + { 273 + platform_driver_unregister(&sch_gpio_driver); 274 + } 275 + 276 + module_init(sch_gpio_init); 277 + module_exit(sch_gpio_exit); 278 + 279 + MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>"); 280 + MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH"); 281 + MODULE_LICENSE("GPL"); 282 + MODULE_ALIAS("platform:sch_gpio");