summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-ich.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-05 12:01:30 +0900
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-05 12:01:30 +0900
commit578f1ef91aa92beb571bfb9af8f4d18f405f3b9e (patch)
tree8ff59e772d09180b7e7f952a8c90a1bcf25e1d19 /drivers/gpio/gpio-ich.c
parentecefbd94b834fa32559d854646d777c56749ef1c (diff)
parent74d8378159de16a0a1d1975d4778120d263d6000 (diff)
downloadtalos-obmc-linux-578f1ef91aa92beb571bfb9af8f4d18f405f3b9e.tar.gz
talos-obmc-linux-578f1ef91aa92beb571bfb9af8f4d18f405f3b9e.zip
Merge tag 'mfd-3.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
Pull MFD changes from Samuel Ortiz: "MFD bits for the 3.7 merge window. As usual we have a few new drivers: - TI LP8788 - TI OMAP USB TLL - Maxim MAX8907 - SMSC ECE1099 - Dialog Semiconductor DA9055 - A simpler syscon driver that allow us to get rid of the anatop one. Drivers are also gradually getting Device Tree and IRQ domain support. The following drivers got DT support: - palmas, 88pm860x, tc3589x and twl4030-audio And those ones now use the IRQ domain APIs: - 88pm860x, tc3589x, db8500_prcmu Also some other interesting changes: - Intel's ICH LPC now supports Lynx Point - TI's twl4030-audio added a GPO child - tps6527 enabled its backlight subdevice - The twl6030 pwm driver moved to the new PWM subsystem And finally a bunch of cleanup and casual fixes for mc13xxx, 88pm860x, palmas, ab8500, wm8994, wm5110, max8907 and the tps65xxx family." Fix up various annoying conflicts: the DT and IRQ domain support came in twice and was already in 3.6. And then it was apparently rebased. Guys, DON'T REBASE! * tag 'mfd-3.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (89 commits) ARM: dts: Enable 88pm860x pmic mfd: 88pm860x: Move gpadc init into touch mfd: 88pm860x: Device tree support mfd: 88pm860x: Use irqdomain mfd: smsc: Add support for smsc gpio io/keypad driver backlight: tps65217_bl: Add missing platform_set_drvdata in tps65217_bl_probe mfd: DA9055 core driver mfd: tps65910: Add alarm interrupt of TPS65910 RTC to mfd device list mfd: wm5110: Add register patches for revision B mfd: wm5110: Disable control interface error report for WM5110 rev B mfd: max8907: Remove regulator-compatible from DT docs backlight: Add TPS65217 WLED driver mfd: Add backlight as subdevice to the tps65217 mfd: Provide the PRCMU with its own IRQ domain mfd: Fix max8907 sparse warning mfd: Add lp8788 mfd driver mfd: dbx500: Provide a more accurate smp_twd clock mfd: rc5t583: Fix warning messages regulator: palmas: Add DT support mfd: palmas: Change regulator defns to better suite DT ...
Diffstat (limited to 'drivers/gpio/gpio-ich.c')
-rw-r--r--drivers/gpio/gpio-ich.c79
1 files changed, 69 insertions, 10 deletions
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index b7c06517403d..d4d617966696 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -49,6 +49,10 @@ static const u8 ichx_regs[3][3] = {
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
};
+static const u8 ichx_reglen[3] = {
+ 0x30, 0x10, 0x10,
+};
+
#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
@@ -75,6 +79,7 @@ static struct {
struct resource *pm_base; /* Power Mangagment IO base */
struct ichx_desc *desc; /* Pointer to chipset-specific description */
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
+ u8 use_gpio; /* Which GPIO groups are usable */
} ichx_priv;
static int modparam_gpiobase = -1; /* dynamic */
@@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr)
return data & (1 << bit) ? 1 : 0;
}
+static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
+{
+ return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO;
+}
+
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
+ if (!ichx_gpio_check_available(gpio, nr))
+ return -ENXIO;
+
/*
* Try setting pin as an input and verify it worked since many pins
* are output-only.
@@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
+ if (!ichx_gpio_check_available(gpio, nr))
+ return -ENXIO;
+
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
@@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
{
+ if (!ichx_gpio_check_available(chip, nr))
+ return -ENXIO;
+
return ichx_read_bit(GPIO_LVL, nr);
}
@@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
unsigned long flags;
u32 data;
+ if (!ichx_gpio_check_available(chip, nr))
+ return -ENXIO;
+
/*
* GPI 0 - 15 need to be read from the power management registers on
* a ICH6/3100 bridge.
@@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = {
.ngpio = 76,
};
+static int __devinit ichx_gpio_request_regions(struct resource *res_base,
+ const char *name, u8 use_gpio)
+{
+ int i;
+
+ if (!res_base || !res_base->start || !res_base->end)
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ if (!(use_gpio & (1 << i)))
+ continue;
+ if (!request_region(res_base->start + ichx_regs[0][i],
+ ichx_reglen[i], name))
+ goto request_err;
+ }
+ return 0;
+
+request_err:
+ /* Clean up: release already requested regions, if any */
+ for (i--; i >= 0; i--) {
+ if (!(use_gpio & (1 << i)))
+ continue;
+ release_region(res_base->start + ichx_regs[0][i],
+ ichx_reglen[i]);
+ }
+ return -EBUSY;
+}
+
+static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ if (!(use_gpio & (1 << i)))
+ continue;
+ release_region(res_base->start + ichx_regs[0][i],
+ ichx_reglen[i]);
+ }
+}
+
static int __devinit ichx_gpio_probe(struct platform_device *pdev)
{
struct resource *res_base, *res_pm;
@@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev)
}
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
- if (!res_base || !res_base->start || !res_base->end)
- return -ENODEV;
-
- if (!request_region(res_base->start, resource_size(res_base),
- pdev->name))
- return -EBUSY;
+ ichx_priv.use_gpio = ich_info->use_gpio;
+ err = ichx_gpio_request_regions(res_base, pdev->name,
+ ichx_priv.use_gpio);
+ if (err)
+ return err;
ichx_priv.gpio_base = res_base;
@@ -374,8 +435,7 @@ init:
return 0;
add_err:
- release_region(ichx_priv.gpio_base->start,
- resource_size(ichx_priv.gpio_base));
+ ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
@@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev)
return err;
}
- release_region(ichx_priv.gpio_base->start,
- resource_size(ichx_priv.gpio_base));
+ ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
OpenPOWER on IntegriCloud