1/* 2 * AMD CS5535/CS5536 GPIO driver 3 * Copyright (C) 2006 Advanced Micro Devices, Inc. 4 * Copyright (C) 2007-2009 Andres Salomon <dilinger@collabora.co.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2 of the GNU General Public License 8 * as published by the Free Software Foundation. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/spinlock.h> 13#include <linux/module.h> 14#include <linux/pci.h> 15#include <linux/gpio.h> 16#include <linux/io.h> 17#include <linux/cs5535.h> 18 19#define DRV_NAME "cs5535-gpio" 20#define GPIO_BAR 1 21 22/* 23 * Some GPIO pins 24 * 31-29,23 : reserved (always mask out) 25 * 28 : Power Button 26 * 26 : PME# 27 * 22-16 : LPC 28 * 14,15 : SMBus 29 * 9,8 : UART1 30 * 7 : PCI INTB 31 * 3,4 : UART2/DDC 32 * 2 : IDE_IRQ0 33 * 1 : AC_BEEP 34 * 0 : PCI INTA 35 * 36 * If a mask was not specified, allow all except 37 * reserved and Power Button 38 */ 39#define GPIO_DEFAULT_MASK 0x0F7FFFFF 40 41static ulong mask = GPIO_DEFAULT_MASK; 42module_param_named(mask, mask, ulong, 0444); 43MODULE_PARM_DESC(mask, "GPIO channel mask."); 44 45static struct cs5535_gpio_chip { 46 struct gpio_chip chip; 47 resource_size_t base; 48 49 struct pci_dev *pdev; 50 spinlock_t lock; 51} cs5535_gpio_chip; 52 53/* 54 * The CS5535/CS5536 GPIOs support a number of extra features not defined 55 * by the gpio_chip API, so these are exported. For a full list of the 56 * registers, see include/linux/cs5535.h. 57 */ 58 59static void errata_outl(struct cs5535_gpio_chip *chip, u32 val, 60 unsigned int reg) 61{ 62 unsigned long addr = chip->base + 0x80 + reg; 63 64 if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) { 65 if (val & 0xffff) 66 val |= (inl(addr) & 0xffff); /* ignore the high bits */ 67 else 68 val |= (inl(addr) ^ (val >> 16)); 69 } 70 outl(val, addr); 71} 72 73static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, 74 unsigned int reg) 75{ 76 if (offset < 16) 77 /* low bank register */ 78 outl(1 << offset, chip->base + reg); 79 else 80 /* high bank register */ 81 errata_outl(chip, 1 << (offset - 16), reg); 82} 83 84void cs5535_gpio_set(unsigned offset, unsigned int reg) 85{ 86 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; 87 unsigned long flags; 88 89 spin_lock_irqsave(&chip->lock, flags); 90 __cs5535_gpio_set(chip, offset, reg); 91 spin_unlock_irqrestore(&chip->lock, flags); 92} 93EXPORT_SYMBOL_GPL(cs5535_gpio_set); 94 95static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset, 96 unsigned int reg) 97{ 98 if (offset < 16) 99 /* low bank register */ 100 outl(1 << (offset + 16), chip->base + reg); 101 else 102 /* high bank register */ 103 errata_outl(chip, 1 << offset, reg); 104} 105 106void cs5535_gpio_clear(unsigned offset, unsigned int reg) 107{ 108 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; 109 unsigned long flags; 110 111 spin_lock_irqsave(&chip->lock, flags); 112 __cs5535_gpio_clear(chip, offset, reg); 113 spin_unlock_irqrestore(&chip->lock, flags); 114} 115EXPORT_SYMBOL_GPL(cs5535_gpio_clear); 116 117int cs5535_gpio_isset(unsigned offset, unsigned int reg) 118{ 119 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; 120 unsigned long flags; 121 long val; 122 123 spin_lock_irqsave(&chip->lock, flags); 124 if (offset < 16) 125 /* low bank register */ 126 val = inl(chip->base + reg); 127 else { 128 /* high bank register */ 129 val = inl(chip->base + 0x80 + reg); 130 offset -= 16; 131 } 132 spin_unlock_irqrestore(&chip->lock, flags); 133 134 return (val & (1 << offset)) ? 1 : 0; 135} 136EXPORT_SYMBOL_GPL(cs5535_gpio_isset); 137 138/* 139 * Generic gpio_chip API support. 140 */ 141 142static int chip_gpio_request(struct gpio_chip *c, unsigned offset) 143{ 144 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; 145 unsigned long flags; 146 147 spin_lock_irqsave(&chip->lock, flags); 148 149 /* check if this pin is available */ 150 if ((mask & (1 << offset)) == 0) { 151 dev_info(&chip->pdev->dev, 152 "pin %u is not available (check mask)\n", offset); 153 spin_unlock_irqrestore(&chip->lock, flags); 154 return -EINVAL; 155 } 156 157 /* disable output aux 1 & 2 on this pin */ 158 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX1); 159 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX2); 160 161 /* disable input aux 1 on this pin */ 162 __cs5535_gpio_clear(chip, offset, GPIO_INPUT_AUX1); 163 164 spin_unlock_irqrestore(&chip->lock, flags); 165 166 return 0; 167} 168 169static int chip_gpio_get(struct gpio_chip *chip, unsigned offset) 170{ 171 return cs5535_gpio_isset(offset, GPIO_READ_BACK); 172} 173 174static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 175{ 176 if (val) 177 cs5535_gpio_set(offset, GPIO_OUTPUT_VAL); 178 else 179 cs5535_gpio_clear(offset, GPIO_OUTPUT_VAL); 180} 181 182static int chip_direction_input(struct gpio_chip *c, unsigned offset) 183{ 184 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; 185 unsigned long flags; 186 187 spin_lock_irqsave(&chip->lock, flags); 188 __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE); 189 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_ENABLE); 190 spin_unlock_irqrestore(&chip->lock, flags); 191 192 return 0; 193} 194 195static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val) 196{ 197 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; 198 unsigned long flags; 199 200 spin_lock_irqsave(&chip->lock, flags); 201 202 __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE); 203 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE); 204 if (val) 205 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL); 206 else 207 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_VAL); 208 209 spin_unlock_irqrestore(&chip->lock, flags); 210 211 return 0; 212} 213 214static const char * const cs5535_gpio_names[] = { 215 "GPIO0", "GPIO1", "GPIO2", "GPIO3", 216 "GPIO4", "GPIO5", "GPIO6", "GPIO7", 217 "GPIO8", "GPIO9", "GPIO10", "GPIO11", 218 "GPIO12", "GPIO13", "GPIO14", "GPIO15", 219 "GPIO16", "GPIO17", "GPIO18", "GPIO19", 220 "GPIO20", "GPIO21", "GPIO22", NULL, 221 "GPIO24", "GPIO25", "GPIO26", "GPIO27", 222 "GPIO28", NULL, NULL, NULL, 223}; 224 225static struct cs5535_gpio_chip cs5535_gpio_chip = { 226 .chip = { 227 .owner = THIS_MODULE, 228 .label = DRV_NAME, 229 230 .base = 0, 231 .ngpio = 32, 232 .names = cs5535_gpio_names, 233 .request = chip_gpio_request, 234 235 .get = chip_gpio_get, 236 .set = chip_gpio_set, 237 238 .direction_input = chip_direction_input, 239 .direction_output = chip_direction_output, 240 }, 241}; 242 243static int __init cs5535_gpio_probe(struct pci_dev *pdev, 244 const struct pci_device_id *pci_id) 245{ 246 int err; 247 ulong mask_orig = mask; 248 249 /* There are two ways to get the GPIO base address; one is by 250 * fetching it from MSR_LBAR_GPIO, the other is by reading the 251 * PCI BAR info. The latter method is easier (especially across 252 * different architectures), so we'll stick with that for now. If 253 * it turns out to be unreliable in the face of crappy BIOSes, we 254 * can always go back to using MSRs.. */ 255 256 err = pci_enable_device_io(pdev); 257 if (err) { 258 dev_err(&pdev->dev, "can't enable device IO\n"); 259 goto done; 260 } 261 262 err = pci_request_region(pdev, GPIO_BAR, DRV_NAME); 263 if (err) { 264 dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR); 265 goto done; 266 } 267 268 /* set up the driver-specific struct */ 269 cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR); 270 cs5535_gpio_chip.pdev = pdev; 271 spin_lock_init(&cs5535_gpio_chip.lock); 272 273 dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR, 274 (unsigned long long) cs5535_gpio_chip.base); 275 276 /* mask out reserved pins */ 277 mask &= 0x1F7FFFFF; 278 279 /* do not allow pin 28, Power Button, as there's special handling 280 * in the PMC needed. (note 12, p. 48) */ 281 mask &= ~(1 << 28); 282 283 if (mask_orig != mask) 284 dev_info(&pdev->dev, "mask changed from 0x%08lX to 0x%08lX\n", 285 mask_orig, mask); 286 287 /* finally, register with the generic GPIO API */ 288 err = gpiochip_add(&cs5535_gpio_chip.chip); 289 if (err) 290 goto release_region; 291 292 dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n"); 293 return 0; 294 295release_region: 296 pci_release_region(pdev, GPIO_BAR); 297done: 298 return err; 299} 300 301static void __exit cs5535_gpio_remove(struct pci_dev *pdev) 302{ 303 int err; 304 305 err = gpiochip_remove(&cs5535_gpio_chip.chip); 306 if (err) { 307 /* uhh? */ 308 dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); 309 } 310 pci_release_region(pdev, GPIO_BAR); 311} 312 313static struct pci_device_id cs5535_gpio_pci_tbl[] = { 314 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, 315 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, 316 { 0, }, 317}; 318MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl); 319 320/* 321 * We can't use the standard PCI driver registration stuff here, since 322 * that allows only one driver to bind to each PCI device (and we want 323 * multiple drivers to be able to bind to the device). Instead, manually 324 * scan for the PCI device, request a single region, and keep track of the 325 * devices that we're using. 326 */ 327 328static int __init cs5535_gpio_scan_pci(void) 329{ 330 struct pci_dev *pdev; 331 int err = -ENODEV; 332 int i; 333 334 for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) { 335 pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor, 336 cs5535_gpio_pci_tbl[i].device, NULL); 337 if (pdev) { 338 err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]); 339 if (err) 340 pci_dev_put(pdev); 341 342 /* we only support a single CS5535/6 southbridge */ 343 break; 344 } 345 } 346 347 return err; 348} 349 350static void __exit cs5535_gpio_free_pci(void) 351{ 352 cs5535_gpio_remove(cs5535_gpio_chip.pdev); 353 pci_dev_put(cs5535_gpio_chip.pdev); 354} 355 356static int __init cs5535_gpio_init(void) 357{ 358 return cs5535_gpio_scan_pci(); 359} 360 361static void __exit cs5535_gpio_exit(void) 362{ 363 cs5535_gpio_free_pci(); 364} 365 366module_init(cs5535_gpio_init); 367module_exit(cs5535_gpio_exit); 368 369MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); 370MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver"); 371MODULE_LICENSE("GPL"); 372