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