diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 12:01:30 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 12:01:30 +0900 |
commit | 578f1ef91aa92beb571bfb9af8f4d18f405f3b9e (patch) | |
tree | 8ff59e772d09180b7e7f952a8c90a1bcf25e1d19 /drivers/gpio/gpio-ich.c | |
parent | ecefbd94b834fa32559d854646d777c56749ef1c (diff) | |
parent | 74d8378159de16a0a1d1975d4778120d263d6000 (diff) | |
download | talos-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.c | 79 |
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)); |