diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-04 23:01:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-04 23:01:30 -0400 |
commit | 578f1ef91aa92beb571bfb9af8f4d18f405f3b9e (patch) | |
tree | 8ff59e772d09180b7e7f952a8c90a1bcf25e1d19 /drivers/gpio | |
parent | ecefbd94b834fa32559d854646d777c56749ef1c (diff) | |
parent | 74d8378159de16a0a1d1975d4778120d263d6000 (diff) |
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')
-rw-r--r-- | drivers/gpio/Kconfig | 7 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-ich.c | 79 | ||||
-rw-r--r-- | drivers/gpio/gpio-twl6040.c | 137 |
4 files changed, 214 insertions, 10 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8382dc832929..aa73ef3233b8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -409,6 +409,13 @@ config GPIO_TWL4030 | |||
409 | Say yes here to access the GPIO signals of various multi-function | 409 | Say yes here to access the GPIO signals of various multi-function |
410 | power management chips from Texas Instruments. | 410 | power management chips from Texas Instruments. |
411 | 411 | ||
412 | config GPIO_TWL6040 | ||
413 | tristate "TWL6040 GPO" | ||
414 | depends on TWL6040_CORE | ||
415 | help | ||
416 | Say yes here to access the GPO signals of twl6040 | ||
417 | audio chip from Texas Instruments. | ||
418 | |||
412 | config GPIO_WM831X | 419 | config GPIO_WM831X |
413 | tristate "WM831x GPIOs" | 420 | tristate "WM831x GPIOs" |
414 | depends on MFD_WM831X | 421 | depends on MFD_WM831X |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0ffaa8423e87..b2c109d1303d 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o | |||
68 | obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o | 68 | obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o |
69 | obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o | 69 | obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o |
70 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o | 70 | obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o |
71 | obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o | ||
71 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o | 72 | obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o |
72 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o | 73 | obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o |
73 | obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o | 74 | obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o |
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] = { | |||
49 | {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ | 49 | {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static const u8 ichx_reglen[3] = { | ||
53 | 0x30, 0x10, 0x10, | ||
54 | }; | ||
55 | |||
52 | #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) | 56 | #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) |
53 | #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) | 57 | #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) |
54 | 58 | ||
@@ -75,6 +79,7 @@ static struct { | |||
75 | struct resource *pm_base; /* Power Mangagment IO base */ | 79 | struct resource *pm_base; /* Power Mangagment IO base */ |
76 | struct ichx_desc *desc; /* Pointer to chipset-specific description */ | 80 | struct ichx_desc *desc; /* Pointer to chipset-specific description */ |
77 | u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ | 81 | u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ |
82 | u8 use_gpio; /* Which GPIO groups are usable */ | ||
78 | } ichx_priv; | 83 | } ichx_priv; |
79 | 84 | ||
80 | static int modparam_gpiobase = -1; /* dynamic */ | 85 | static int modparam_gpiobase = -1; /* dynamic */ |
@@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr) | |||
123 | return data & (1 << bit) ? 1 : 0; | 128 | return data & (1 << bit) ? 1 : 0; |
124 | } | 129 | } |
125 | 130 | ||
131 | static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) | ||
132 | { | ||
133 | return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO; | ||
134 | } | ||
135 | |||
126 | static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) | 136 | static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) |
127 | { | 137 | { |
138 | if (!ichx_gpio_check_available(gpio, nr)) | ||
139 | return -ENXIO; | ||
140 | |||
128 | /* | 141 | /* |
129 | * Try setting pin as an input and verify it worked since many pins | 142 | * Try setting pin as an input and verify it worked since many pins |
130 | * are output-only. | 143 | * are output-only. |
@@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) | |||
138 | static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, | 151 | static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, |
139 | int val) | 152 | int val) |
140 | { | 153 | { |
154 | if (!ichx_gpio_check_available(gpio, nr)) | ||
155 | return -ENXIO; | ||
156 | |||
141 | /* Set GPIO output value. */ | 157 | /* Set GPIO output value. */ |
142 | ichx_write_bit(GPIO_LVL, nr, val, 0); | 158 | ichx_write_bit(GPIO_LVL, nr, val, 0); |
143 | 159 | ||
@@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, | |||
153 | 169 | ||
154 | static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) | 170 | static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) |
155 | { | 171 | { |
172 | if (!ichx_gpio_check_available(chip, nr)) | ||
173 | return -ENXIO; | ||
174 | |||
156 | return ichx_read_bit(GPIO_LVL, nr); | 175 | return ichx_read_bit(GPIO_LVL, nr); |
157 | } | 176 | } |
158 | 177 | ||
@@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) | |||
161 | unsigned long flags; | 180 | unsigned long flags; |
162 | u32 data; | 181 | u32 data; |
163 | 182 | ||
183 | if (!ichx_gpio_check_available(chip, nr)) | ||
184 | return -ENXIO; | ||
185 | |||
164 | /* | 186 | /* |
165 | * GPI 0 - 15 need to be read from the power management registers on | 187 | * GPI 0 - 15 need to be read from the power management registers on |
166 | * a ICH6/3100 bridge. | 188 | * a ICH6/3100 bridge. |
@@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = { | |||
291 | .ngpio = 76, | 313 | .ngpio = 76, |
292 | }; | 314 | }; |
293 | 315 | ||
316 | static int __devinit ichx_gpio_request_regions(struct resource *res_base, | ||
317 | const char *name, u8 use_gpio) | ||
318 | { | ||
319 | int i; | ||
320 | |||
321 | if (!res_base || !res_base->start || !res_base->end) | ||
322 | return -ENODEV; | ||
323 | |||
324 | for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { | ||
325 | if (!(use_gpio & (1 << i))) | ||
326 | continue; | ||
327 | if (!request_region(res_base->start + ichx_regs[0][i], | ||
328 | ichx_reglen[i], name)) | ||
329 | goto request_err; | ||
330 | } | ||
331 | return 0; | ||
332 | |||
333 | request_err: | ||
334 | /* Clean up: release already requested regions, if any */ | ||
335 | for (i--; i >= 0; i--) { | ||
336 | if (!(use_gpio & (1 << i))) | ||
337 | continue; | ||
338 | release_region(res_base->start + ichx_regs[0][i], | ||
339 | ichx_reglen[i]); | ||
340 | } | ||
341 | return -EBUSY; | ||
342 | } | ||
343 | |||
344 | static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) | ||
345 | { | ||
346 | int i; | ||
347 | |||
348 | for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { | ||
349 | if (!(use_gpio & (1 << i))) | ||
350 | continue; | ||
351 | release_region(res_base->start + ichx_regs[0][i], | ||
352 | ichx_reglen[i]); | ||
353 | } | ||
354 | } | ||
355 | |||
294 | static int __devinit ichx_gpio_probe(struct platform_device *pdev) | 356 | static int __devinit ichx_gpio_probe(struct platform_device *pdev) |
295 | { | 357 | { |
296 | struct resource *res_base, *res_pm; | 358 | struct resource *res_base, *res_pm; |
@@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev) | |||
329 | } | 391 | } |
330 | 392 | ||
331 | res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); | 393 | res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); |
332 | if (!res_base || !res_base->start || !res_base->end) | 394 | ichx_priv.use_gpio = ich_info->use_gpio; |
333 | return -ENODEV; | 395 | err = ichx_gpio_request_regions(res_base, pdev->name, |
334 | 396 | ichx_priv.use_gpio); | |
335 | if (!request_region(res_base->start, resource_size(res_base), | 397 | if (err) |
336 | pdev->name)) | 398 | return err; |
337 | return -EBUSY; | ||
338 | 399 | ||
339 | ichx_priv.gpio_base = res_base; | 400 | ichx_priv.gpio_base = res_base; |
340 | 401 | ||
@@ -374,8 +435,7 @@ init: | |||
374 | return 0; | 435 | return 0; |
375 | 436 | ||
376 | add_err: | 437 | add_err: |
377 | release_region(ichx_priv.gpio_base->start, | 438 | ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); |
378 | resource_size(ichx_priv.gpio_base)); | ||
379 | if (ichx_priv.pm_base) | 439 | if (ichx_priv.pm_base) |
380 | release_region(ichx_priv.pm_base->start, | 440 | release_region(ichx_priv.pm_base->start, |
381 | resource_size(ichx_priv.pm_base)); | 441 | resource_size(ichx_priv.pm_base)); |
@@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev) | |||
393 | return err; | 453 | return err; |
394 | } | 454 | } |
395 | 455 | ||
396 | release_region(ichx_priv.gpio_base->start, | 456 | ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); |
397 | resource_size(ichx_priv.gpio_base)); | ||
398 | if (ichx_priv.pm_base) | 457 | if (ichx_priv.pm_base) |
399 | release_region(ichx_priv.pm_base->start, | 458 | release_region(ichx_priv.pm_base->start, |
400 | resource_size(ichx_priv.pm_base)); | 459 | resource_size(ichx_priv.pm_base)); |
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c new file mode 100644 index 000000000000..dd58e8b25043 --- /dev/null +++ b/drivers/gpio/gpio-twl6040.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Access to GPOs on TWL6040 chip | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Authors: | ||
7 | * Sergio Aguirre <saaguirre@ti.com> | ||
8 | * Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/kthread.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/of.h> | ||
32 | |||
33 | #include <linux/mfd/twl6040.h> | ||
34 | |||
35 | static struct gpio_chip twl6040gpo_chip; | ||
36 | |||
37 | static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) | ||
38 | { | ||
39 | struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); | ||
40 | int ret = 0; | ||
41 | |||
42 | ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); | ||
43 | if (ret < 0) | ||
44 | return ret; | ||
45 | |||
46 | return (ret >> offset) & 1; | ||
47 | } | ||
48 | |||
49 | static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, | ||
50 | int value) | ||
51 | { | ||
52 | /* This only drives GPOs, and can't change direction */ | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value) | ||
57 | { | ||
58 | struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); | ||
59 | int ret; | ||
60 | u8 gpoctl; | ||
61 | |||
62 | ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); | ||
63 | if (ret < 0) | ||
64 | return; | ||
65 | |||
66 | if (value) | ||
67 | gpoctl = ret | (1 << offset); | ||
68 | else | ||
69 | gpoctl = ret & ~(1 << offset); | ||
70 | |||
71 | twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl); | ||
72 | } | ||
73 | |||
74 | static struct gpio_chip twl6040gpo_chip = { | ||
75 | .label = "twl6040", | ||
76 | .owner = THIS_MODULE, | ||
77 | .get = twl6040gpo_get, | ||
78 | .direction_output = twl6040gpo_direction_out, | ||
79 | .set = twl6040gpo_set, | ||
80 | .can_sleep = 1, | ||
81 | }; | ||
82 | |||
83 | /*----------------------------------------------------------------------*/ | ||
84 | |||
85 | static int __devinit gpo_twl6040_probe(struct platform_device *pdev) | ||
86 | { | ||
87 | struct twl6040_gpo_data *pdata = pdev->dev.platform_data; | ||
88 | struct device *twl6040_core_dev = pdev->dev.parent; | ||
89 | struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); | ||
90 | int ret; | ||
91 | |||
92 | if (pdata) | ||
93 | twl6040gpo_chip.base = pdata->gpio_base; | ||
94 | else | ||
95 | twl6040gpo_chip.base = -1; | ||
96 | |||
97 | if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) | ||
98 | twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */ | ||
99 | else | ||
100 | twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */ | ||
101 | |||
102 | twl6040gpo_chip.dev = &pdev->dev; | ||
103 | #ifdef CONFIG_OF_GPIO | ||
104 | twl6040gpo_chip.of_node = twl6040_core_dev->of_node; | ||
105 | #endif | ||
106 | |||
107 | ret = gpiochip_add(&twl6040gpo_chip); | ||
108 | if (ret < 0) { | ||
109 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); | ||
110 | twl6040gpo_chip.ngpio = 0; | ||
111 | } | ||
112 | |||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static int __devexit gpo_twl6040_remove(struct platform_device *pdev) | ||
117 | { | ||
118 | return gpiochip_remove(&twl6040gpo_chip); | ||
119 | } | ||
120 | |||
121 | /* Note: this hardware lives inside an I2C-based multi-function device. */ | ||
122 | MODULE_ALIAS("platform:twl6040-gpo"); | ||
123 | |||
124 | static struct platform_driver gpo_twl6040_driver = { | ||
125 | .driver = { | ||
126 | .name = "twl6040-gpo", | ||
127 | .owner = THIS_MODULE, | ||
128 | }, | ||
129 | .probe = gpo_twl6040_probe, | ||
130 | .remove = gpo_twl6040_remove, | ||
131 | }; | ||
132 | |||
133 | module_platform_driver(gpo_twl6040_driver); | ||
134 | |||
135 | MODULE_AUTHOR("Texas Instruments, Inc."); | ||
136 | MODULE_DESCRIPTION("GPO interface for TWL6040"); | ||
137 | MODULE_LICENSE("GPL"); | ||