1c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely/* 2c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely * Moorestown platform Langwell chip GPIO driver 3c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely * 48bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * Copyright (c) 2008 - 2009, Intel Corporation. 58bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * 68bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * This program is free software; you can redistribute it and/or modify 78bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * it under the terms of the GNU General Public License version 2 as 88bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * published by the Free Software Foundation. 98bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * 108bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * This program is distributed in the hope that it will be useful, 118bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * but WITHOUT ANY WARRANTY; without even the implied warranty of 128bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * GNU General Public License for more details. 148bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * 158bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * You should have received a copy of the GNU General Public License 168bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * along with this program; if not, write to the Free Software 178bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 188bf026177000c5bb566cafe2528a96f8380f38bdAlek Du */ 198bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 208bf026177000c5bb566cafe2528a96f8380f38bdAlek Du/* Supports: 218bf026177000c5bb566cafe2528a96f8380f38bdAlek Du * Moorestown platform Langwell chip. 228081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * Medfield platform Penwell chip. 2372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox * Whitney point. 248bf026177000c5bb566cafe2528a96f8380f38bdAlek Du */ 258bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 268bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/module.h> 278bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/pci.h> 2872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox#include <linux/platform_device.h> 298bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/kernel.h> 308bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/delay.h> 318bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/stddef.h> 328bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/interrupt.h> 338bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/init.h> 348bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/irq.h> 358bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/io.h> 368bf026177000c5bb566cafe2528a96f8380f38bdAlek Du#include <linux/gpio.h> 375a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 387812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#include <linux/pm_runtime.h> 398bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 408081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du/* 418081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * Langwell chip has 64 pins and thus there are 2 32bit registers to control 428081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit 438081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * registers to control them, so we only define the order here instead of a 448081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * structure, to get a bit offset for a pin (use GPDR as an example): 458081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * 468081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * nreg = ngpio / 32; 478081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * reg = offset / 32; 488081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * bit = offset % 32; 498081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; 508081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * 518081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du * so the bit of reg_addr is to control pin offset's GPDR feature 528081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du*/ 538081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du 548081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Duenum GPIO_REG { 558081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GPLR = 0, /* pin level read-only */ 568081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GPDR, /* pin direction */ 578081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GPSR, /* pin set */ 588081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GPCR, /* pin clear */ 598081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GRER, /* rising edge detect */ 608081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GFER, /* falling edge detect */ 618081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du GEDR, /* edge detect result */ 628c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter GAFR, /* alt function */ 638bf026177000c5bb566cafe2528a96f8380f38bdAlek Du}; 648bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 658bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustruct lnw_gpio { 668bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct gpio_chip chip; 678081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void *reg_base; 688bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spinlock_t lock; 698bf026177000c5bb566cafe2528a96f8380f38bdAlek Du unsigned irq_base; 707812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi struct pci_dev *pdev; 718bf026177000c5bb566cafe2528a96f8380f38bdAlek Du}; 728bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 738081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Dustatic void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, 748081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du enum GPIO_REG reg_type) 758bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 768bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); 778081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du unsigned nreg = chip->ngpio / 32; 788bf026177000c5bb566cafe2528a96f8380f38bdAlek Du u8 reg = offset / 32; 798081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *ptr; 808081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du 818081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4); 828081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du return ptr; 838081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du} 848081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du 858c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunterstatic void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, 868c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter enum GPIO_REG reg_type) 878c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter{ 888c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); 898c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter unsigned nreg = chip->ngpio / 32; 908c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter u8 reg = offset / 16; 918c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter void __iomem *ptr; 928c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter 938c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4); 948c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter return ptr; 958c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter} 968c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter 978c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunterstatic int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) 988c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter{ 998c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); 1008c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter u32 value = readl(gafr); 1018c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter int shift = (offset % 16) << 1, af = (value >> shift) & 3; 1028c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter 1038c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter if (af) { 1048c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter value &= ~(3 << shift); 1058c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter writel(value, gafr); 1068c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter } 1078c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter return 0; 1088c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter} 1098c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter 1108081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Dustatic int lnw_gpio_get(struct gpio_chip *chip, unsigned offset) 1118081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du{ 1128081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *gplr = gpio_reg(chip, offset, GPLR); 1138bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1148bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return readl(gplr) & BIT(offset % 32); 1158bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 1168bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1178bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1188bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 1198bf026177000c5bb566cafe2528a96f8380f38bdAlek Du void __iomem *gpsr, *gpcr; 1208bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1218bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (value) { 1228081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du gpsr = gpio_reg(chip, offset, GPSR); 1238bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(BIT(offset % 32), gpsr); 1248bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } else { 1258081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du gpcr = gpio_reg(chip, offset, GPCR); 1268bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(BIT(offset % 32), gpcr); 1278bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 1288bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 1298bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1308bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 1318bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 1328bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); 1338081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *gpdr = gpio_reg(chip, offset, GPDR); 1348bf026177000c5bb566cafe2528a96f8380f38bdAlek Du u32 value; 1358bf026177000c5bb566cafe2528a96f8380f38bdAlek Du unsigned long flags; 1368bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1377812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 1387812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_get(&lnw->pdev->dev); 1397812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1408bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_lock_irqsave(&lnw->lock, flags); 1418bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(gpdr); 1428bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value &= ~BIT(offset % 32); 1438bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(value, gpdr); 1448bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_unlock_irqrestore(&lnw->lock, flags); 1457812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1467812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 1477812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_put(&lnw->pdev->dev); 1487812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1498bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return 0; 1508bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 1518bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1528bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic int lnw_gpio_direction_output(struct gpio_chip *chip, 1538bf026177000c5bb566cafe2528a96f8380f38bdAlek Du unsigned offset, int value) 1548bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 1558bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); 1568081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *gpdr = gpio_reg(chip, offset, GPDR); 1578bf026177000c5bb566cafe2528a96f8380f38bdAlek Du unsigned long flags; 1588bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1598bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw_gpio_set(chip, offset, value); 1607812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1617812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 1627812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_get(&lnw->pdev->dev); 1637812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1648bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_lock_irqsave(&lnw->lock, flags); 1658bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(gpdr); 1666eab04a87677a37cf15b52e2b4b4fd57917102adJustin P. Mattock value |= BIT(offset % 32); 1678bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(value, gpdr); 1688bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_unlock_irqrestore(&lnw->lock, flags); 1697812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1707812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 1717812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_put(&lnw->pdev->dev); 1727812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1738bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return 0; 1748bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 1758bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1768bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 1778bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 1788bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); 1798bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return lnw->irq_base + offset; 1808bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 1818bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1825ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhekstatic int lnw_irq_type(struct irq_data *d, unsigned type) 1838bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 1845ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhek struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); 1855ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhek u32 gpio = d->irq - lnw->irq_base; 1868bf026177000c5bb566cafe2528a96f8380f38bdAlek Du unsigned long flags; 1878bf026177000c5bb566cafe2528a96f8380f38bdAlek Du u32 value; 1888081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); 1898081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER); 1908bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 1914efec6272e8e61fc77132b4d2bae56d61b289956Roel Kluin if (gpio >= lnw->chip.ngpio) 1928bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return -EINVAL; 1937812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1947812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 1957812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_get(&lnw->pdev->dev); 1967812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 1978bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_lock_irqsave(&lnw->lock, flags); 1988bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (type & IRQ_TYPE_EDGE_RISING) 1998bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(grer) | BIT(gpio % 32); 2008bf026177000c5bb566cafe2528a96f8380f38bdAlek Du else 2018bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(grer) & (~BIT(gpio % 32)); 2028bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(value, grer); 2038bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2048bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (type & IRQ_TYPE_EDGE_FALLING) 2058bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(gfer) | BIT(gpio % 32); 2068bf026177000c5bb566cafe2528a96f8380f38bdAlek Du else 2078bf026177000c5bb566cafe2528a96f8380f38bdAlek Du value = readl(gfer) & (~BIT(gpio % 32)); 2088bf026177000c5bb566cafe2528a96f8380f38bdAlek Du writel(value, gfer); 2098bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_unlock_irqrestore(&lnw->lock, flags); 2108bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2117812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (lnw->pdev) 2127812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_put(&lnw->pdev->dev); 2137812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2148bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return 0; 215fd0574cb54bf1dd068e4603f0d67d237aa1d718dAndrew Morton} 2168bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2175ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhekstatic void lnw_irq_unmask(struct irq_data *d) 2188bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 219fd0574cb54bf1dd068e4603f0d67d237aa1d718dAndrew Morton} 2208bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2215ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhekstatic void lnw_irq_mask(struct irq_data *d) 2228bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 223fd0574cb54bf1dd068e4603f0d67d237aa1d718dAndrew Morton} 2248bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2258bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic struct irq_chip lnw_irqchip = { 2268bf026177000c5bb566cafe2528a96f8380f38bdAlek Du .name = "LNW-GPIO", 2275ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhek .irq_mask = lnw_irq_mask, 2285ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhek .irq_unmask = lnw_irq_unmask, 2295ffd72c674a8332b37cfd62c364bc5492e8ea4c5Lennert Buytenhek .irq_set_type = lnw_irq_type, 2308bf026177000c5bb566cafe2528a96f8380f38bdAlek Du}; 2318bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2328081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Dustatic DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ 2338081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, 2348081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, 2358081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, 2368bf026177000c5bb566cafe2528a96f8380f38bdAlek Du { 0, } 2378bf026177000c5bb566cafe2528a96f8380f38bdAlek Du}; 2388bf026177000c5bb566cafe2528a96f8380f38bdAlek DuMODULE_DEVICE_TABLE(pci, lnw_gpio_ids); 2398bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2408bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic void lnw_irq_handler(unsigned irq, struct irq_desc *desc) 2418bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 24220e2aa916f6b56e6b1d9e34f4c6e8183d27cb81fThomas Gleixner struct irq_data *data = irq_desc_get_irq_data(desc); 24320e2aa916f6b56e6b1d9e34f4c6e8183d27cb81fThomas Gleixner struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); 24420e2aa916f6b56e6b1d9e34f4c6e8183d27cb81fThomas Gleixner struct irq_chip *chip = irq_data_get_irq_chip(data); 24584bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner u32 base, gpio, mask; 246732063b92bb727b27e61580ce278dddefe31c6adThomas Gleixner unsigned long pending; 2478bf026177000c5bb566cafe2528a96f8380f38bdAlek Du void __iomem *gedr; 2488bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2498bf026177000c5bb566cafe2528a96f8380f38bdAlek Du /* check GPIO controller to check which pin triggered the interrupt */ 2508081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du for (base = 0; base < lnw->chip.ngpio; base += 32) { 2518081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du gedr = gpio_reg(&lnw->chip, base, GEDR); 25284bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner pending = readl(gedr); 253732063b92bb727b27e61580ce278dddefe31c6adThomas Gleixner while (pending) { 2542345b20fd9160d99f7cdf34e7b028ea351bf9c25Mathias Nyman gpio = __ffs(pending); 25584bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner mask = BIT(gpio); 25684bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner pending &= ~mask; 25784bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner /* Clear before handling so we can't lose an edge */ 25884bead6c38b0374e6e7db06b3097f0e700b8f148Thomas Gleixner writel(mask, gedr); 259732063b92bb727b27e61580ce278dddefe31c6adThomas Gleixner generic_handle_irq(lnw->irq_base + base + gpio); 260732063b92bb727b27e61580ce278dddefe31c6adThomas Gleixner } 2618bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 2620766d20fdb9178b908f0268c16b464c11822c5c2Feng Tang 26320e2aa916f6b56e6b1d9e34f4c6e8183d27cb81fThomas Gleixner chip->irq_eoi(data); 2648bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 2658bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 2667812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#ifdef CONFIG_PM 2677812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardistatic int lnw_gpio_runtime_resume(struct device *dev) 2687812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi{ 2697812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi return 0; 2707812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi} 2717812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2727812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardistatic int lnw_gpio_runtime_suspend(struct device *dev) 2737812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi{ 2747812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi return 0; 2757812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi} 2767812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2777812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardistatic int lnw_gpio_runtime_idle(struct device *dev) 2787812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi{ 2797812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi int err = pm_schedule_suspend(dev, 500); 2807812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2817812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi if (!err) 2827812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi return 0; 2837812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2847812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi return -EBUSY; 2857812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi} 2867812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2877812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#else 2887812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#define lnw_gpio_runtime_suspend NULL 2897812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#define lnw_gpio_runtime_resume NULL 2907812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#define lnw_gpio_runtime_idle NULL 2917812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi#endif 2927812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2937812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardistatic const struct dev_pm_ops lnw_gpio_pm_ops = { 2947812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi .runtime_suspend = lnw_gpio_runtime_suspend, 2957812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi .runtime_resume = lnw_gpio_runtime_resume, 2967812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi .runtime_idle = lnw_gpio_runtime_idle, 2977812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi}; 2987812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 2998bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic int __devinit lnw_gpio_probe(struct pci_dev *pdev, 3008bf026177000c5bb566cafe2528a96f8380f38bdAlek Du const struct pci_device_id *id) 3018bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 3028bf026177000c5bb566cafe2528a96f8380f38bdAlek Du void *base; 3038bf026177000c5bb566cafe2528a96f8380f38bdAlek Du int i; 3048bf026177000c5bb566cafe2528a96f8380f38bdAlek Du resource_size_t start, len; 3058bf026177000c5bb566cafe2528a96f8380f38bdAlek Du struct lnw_gpio *lnw; 3068bf026177000c5bb566cafe2528a96f8380f38bdAlek Du u32 irq_base; 3078bf026177000c5bb566cafe2528a96f8380f38bdAlek Du u32 gpio_base; 3088bf026177000c5bb566cafe2528a96f8380f38bdAlek Du int retval = 0; 3098bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 3108bf026177000c5bb566cafe2528a96f8380f38bdAlek Du retval = pci_enable_device(pdev); 3118bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (retval) 3128bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto done; 3138bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 3148bf026177000c5bb566cafe2528a96f8380f38bdAlek Du retval = pci_request_regions(pdev, "langwell_gpio"); 3158bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (retval) { 3168bf026177000c5bb566cafe2528a96f8380f38bdAlek Du dev_err(&pdev->dev, "error requesting resources\n"); 3178bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto err2; 3188bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 3198bf026177000c5bb566cafe2528a96f8380f38bdAlek Du /* get the irq_base from bar1 */ 3208bf026177000c5bb566cafe2528a96f8380f38bdAlek Du start = pci_resource_start(pdev, 1); 3218bf026177000c5bb566cafe2528a96f8380f38bdAlek Du len = pci_resource_len(pdev, 1); 3228bf026177000c5bb566cafe2528a96f8380f38bdAlek Du base = ioremap_nocache(start, len); 3238bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (!base) { 3248bf026177000c5bb566cafe2528a96f8380f38bdAlek Du dev_err(&pdev->dev, "error mapping bar1\n"); 3258bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto err3; 3268bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 3278bf026177000c5bb566cafe2528a96f8380f38bdAlek Du irq_base = *(u32 *)base; 3288bf026177000c5bb566cafe2528a96f8380f38bdAlek Du gpio_base = *((u32 *)base + 1); 3298bf026177000c5bb566cafe2528a96f8380f38bdAlek Du /* release the IO mapping, since we already get the info from bar1 */ 3308bf026177000c5bb566cafe2528a96f8380f38bdAlek Du iounmap(base); 3318bf026177000c5bb566cafe2528a96f8380f38bdAlek Du /* get the register base from bar0 */ 3328bf026177000c5bb566cafe2528a96f8380f38bdAlek Du start = pci_resource_start(pdev, 0); 3338bf026177000c5bb566cafe2528a96f8380f38bdAlek Du len = pci_resource_len(pdev, 0); 3348bf026177000c5bb566cafe2528a96f8380f38bdAlek Du base = ioremap_nocache(start, len); 3358bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (!base) { 3368bf026177000c5bb566cafe2528a96f8380f38bdAlek Du dev_err(&pdev->dev, "error mapping bar0\n"); 3378bf026177000c5bb566cafe2528a96f8380f38bdAlek Du retval = -EFAULT; 3388bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto err3; 3398bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 3408bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 3418bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); 3428bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (!lnw) { 3438bf026177000c5bb566cafe2528a96f8380f38bdAlek Du dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); 3448bf026177000c5bb566cafe2528a96f8380f38bdAlek Du retval = -ENOMEM; 3458bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto err4; 3468bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 3478bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->reg_base = base; 3488bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->irq_base = irq_base; 3498bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.label = dev_name(&pdev->dev); 3508c0f7b10f1028d0bc78486affe2ccf39cdf45282Adrian Hunter lnw->chip.request = lnw_gpio_request; 3518bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.direction_input = lnw_gpio_direction_input; 3528bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.direction_output = lnw_gpio_direction_output; 3538bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.get = lnw_gpio_get; 3548bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.set = lnw_gpio_set; 3558bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.to_irq = lnw_gpio_to_irq; 3568bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.base = gpio_base; 3578081c84c9ce71ef73e591e19f1f7a516cb111e1cAlek Du lnw->chip.ngpio = id->driver_data; 3588bf026177000c5bb566cafe2528a96f8380f38bdAlek Du lnw->chip.can_sleep = 0; 3597812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi lnw->pdev = pdev; 3608bf026177000c5bb566cafe2528a96f8380f38bdAlek Du pci_set_drvdata(pdev, lnw); 3618bf026177000c5bb566cafe2528a96f8380f38bdAlek Du retval = gpiochip_add(&lnw->chip); 3628bf026177000c5bb566cafe2528a96f8380f38bdAlek Du if (retval) { 3638bf026177000c5bb566cafe2528a96f8380f38bdAlek Du dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); 3648bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto err5; 3658bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 366674db90690a5988bdaa3bb2a54619c0de50d31e9Thomas Gleixner irq_set_handler_data(pdev->irq, lnw); 367674db90690a5988bdaa3bb2a54619c0de50d31e9Thomas Gleixner irq_set_chained_handler(pdev->irq, lnw_irq_handler); 3688bf026177000c5bb566cafe2528a96f8380f38bdAlek Du for (i = 0; i < lnw->chip.ngpio; i++) { 369674db90690a5988bdaa3bb2a54619c0de50d31e9Thomas Gleixner irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, 370674db90690a5988bdaa3bb2a54619c0de50d31e9Thomas Gleixner handle_simple_irq, "demux"); 371674db90690a5988bdaa3bb2a54619c0de50d31e9Thomas Gleixner irq_set_chip_data(i + lnw->irq_base, lnw); 3728bf026177000c5bb566cafe2528a96f8380f38bdAlek Du } 3738bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 3748bf026177000c5bb566cafe2528a96f8380f38bdAlek Du spin_lock_init(&lnw->lock); 3757812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 3767812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_put_noidle(&pdev->dev); 3777812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi pm_runtime_allow(&pdev->dev); 3787812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi 3798bf026177000c5bb566cafe2528a96f8380f38bdAlek Du goto done; 3808bf026177000c5bb566cafe2528a96f8380f38bdAlek Duerr5: 3818bf026177000c5bb566cafe2528a96f8380f38bdAlek Du kfree(lnw); 3828bf026177000c5bb566cafe2528a96f8380f38bdAlek Duerr4: 3838bf026177000c5bb566cafe2528a96f8380f38bdAlek Du iounmap(base); 3848bf026177000c5bb566cafe2528a96f8380f38bdAlek Duerr3: 3858bf026177000c5bb566cafe2528a96f8380f38bdAlek Du pci_release_regions(pdev); 3868bf026177000c5bb566cafe2528a96f8380f38bdAlek Duerr2: 3878bf026177000c5bb566cafe2528a96f8380f38bdAlek Du pci_disable_device(pdev); 3888bf026177000c5bb566cafe2528a96f8380f38bdAlek Dudone: 3898bf026177000c5bb566cafe2528a96f8380f38bdAlek Du return retval; 3908bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 3918bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 3928bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic struct pci_driver lnw_gpio_driver = { 3938bf026177000c5bb566cafe2528a96f8380f38bdAlek Du .name = "langwell_gpio", 3948bf026177000c5bb566cafe2528a96f8380f38bdAlek Du .id_table = lnw_gpio_ids, 3958bf026177000c5bb566cafe2528a96f8380f38bdAlek Du .probe = lnw_gpio_probe, 3967812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi .driver = { 3977812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi .pm = &lnw_gpio_pm_ops, 3987812803a3119f7cf375bd04bc019ce2395a7c2fcKristen Carlson Accardi }, 3998bf026177000c5bb566cafe2528a96f8380f38bdAlek Du}; 4008bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 40172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 40272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Coxstatic int __devinit wp_gpio_probe(struct platform_device *pdev) 40372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox{ 40472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox struct lnw_gpio *lnw; 40572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox struct gpio_chip *gc; 40672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox struct resource *rc; 40772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox int retval = 0; 40872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 40972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); 41072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (!rc) 41172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return -EINVAL; 41272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 41372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); 41472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (!lnw) { 41572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox dev_err(&pdev->dev, 41672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox "can't allocate whitneypoint_gpio chip data\n"); 41772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return -ENOMEM; 41872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox } 41972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc)); 42072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (lnw->reg_base == NULL) { 42172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox retval = -EINVAL; 42272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox goto err_kmalloc; 42372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox } 42472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox spin_lock_init(&lnw->lock); 42572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc = &lnw->chip; 42672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->label = dev_name(&pdev->dev); 42772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->owner = THIS_MODULE; 42872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->direction_input = lnw_gpio_direction_input; 42972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->direction_output = lnw_gpio_direction_output; 43072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->get = lnw_gpio_get; 43172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->set = lnw_gpio_set; 43272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->to_irq = NULL; 43372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->base = 0; 43472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->ngpio = 64; 43572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox gc->can_sleep = 0; 43672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox retval = gpiochip_add(gc); 43772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (retval) { 43872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n", 43972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox retval); 44072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox goto err_ioremap; 44172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox } 44272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox platform_set_drvdata(pdev, lnw); 44372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return 0; 44472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Coxerr_ioremap: 44572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox iounmap(lnw->reg_base); 44672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Coxerr_kmalloc: 44772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox kfree(lnw); 44872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return retval; 44972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox} 45072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 45172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Coxstatic int __devexit wp_gpio_remove(struct platform_device *pdev) 45272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox{ 45372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox struct lnw_gpio *lnw = platform_get_drvdata(pdev); 45472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox int err; 45572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox err = gpiochip_remove(&lnw->chip); 45672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (err) 45772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox dev_err(&pdev->dev, "failed to remove gpio_chip.\n"); 45872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox iounmap(lnw->reg_base); 45972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox kfree(lnw); 46072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox platform_set_drvdata(pdev, NULL); 46172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return 0; 46272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox} 46372b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 46472b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Coxstatic struct platform_driver wp_gpio_driver = { 46572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox .probe = wp_gpio_probe, 46672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox .remove = __devexit_p(wp_gpio_remove), 46772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox .driver = { 46872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox .name = "wp_gpio", 46972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox .owner = THIS_MODULE, 47072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox }, 47172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox}; 47272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox 4738bf026177000c5bb566cafe2528a96f8380f38bdAlek Dustatic int __init lnw_gpio_init(void) 4748bf026177000c5bb566cafe2528a96f8380f38bdAlek Du{ 47572b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox int ret; 47672b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox ret = pci_register_driver(&lnw_gpio_driver); 47772b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (ret < 0) 47872b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return ret; 47972b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox ret = platform_driver_register(&wp_gpio_driver); 48072b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox if (ret < 0) 48172b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox pci_unregister_driver(&lnw_gpio_driver); 48272b4379e9502e7bf64256af83a55f90bd13d1ce6Alan Cox return ret; 4838bf026177000c5bb566cafe2528a96f8380f38bdAlek Du} 4848bf026177000c5bb566cafe2528a96f8380f38bdAlek Du 4858bf026177000c5bb566cafe2528a96f8380f38bdAlek Dudevice_initcall(lnw_gpio_init); 486