diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2013-01-03 05:46:59 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-02-13 18:22:45 -0500 |
commit | 3d50a278527154974f4240584da691db7424956d (patch) | |
tree | e3be6471fc3b85226106ea983fb5ea72c308c81e /drivers/gpio/gpio-palmas.c | |
parent | 60c185f059c88ad4b9b170b1f9322e3adcccca07 (diff) |
gpio: palmas: Add support for Palmas GPIO
Add gpio driver for TI Palmas series PMIC. This has 8 gpio which can
work as input/output.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/gpio/gpio-palmas.c')
-rw-r--r-- | drivers/gpio/gpio-palmas.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c new file mode 100644 index 000000000000..e3a4e56f5a42 --- /dev/null +++ b/drivers/gpio/gpio-palmas.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * TI Palma series PMIC's GPIO driver. | ||
3 | * | ||
4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Laxman Dewangan <ldewangan@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mfd/palmas.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | |||
29 | struct palmas_gpio { | ||
30 | struct gpio_chip gpio_chip; | ||
31 | struct palmas *palmas; | ||
32 | }; | ||
33 | |||
34 | static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) | ||
35 | { | ||
36 | return container_of(chip, struct palmas_gpio, gpio_chip); | ||
37 | } | ||
38 | |||
39 | static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
40 | { | ||
41 | struct palmas_gpio *pg = to_palmas_gpio(gc); | ||
42 | struct palmas *palmas = pg->palmas; | ||
43 | unsigned int val; | ||
44 | int ret; | ||
45 | |||
46 | ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val); | ||
47 | if (ret < 0) { | ||
48 | dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret); | ||
49 | return ret; | ||
50 | } | ||
51 | return !!(val & BIT(offset)); | ||
52 | } | ||
53 | |||
54 | static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, | ||
55 | int value) | ||
56 | { | ||
57 | struct palmas_gpio *pg = to_palmas_gpio(gc); | ||
58 | struct palmas *palmas = pg->palmas; | ||
59 | int ret; | ||
60 | |||
61 | if (value) | ||
62 | ret = palmas_write(palmas, PALMAS_GPIO_BASE, | ||
63 | PALMAS_GPIO_SET_DATA_OUT, BIT(offset)); | ||
64 | else | ||
65 | ret = palmas_write(palmas, PALMAS_GPIO_BASE, | ||
66 | PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset)); | ||
67 | if (ret < 0) | ||
68 | dev_err(gc->dev, "%s write failed, err = %d\n", | ||
69 | (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT", | ||
70 | ret); | ||
71 | } | ||
72 | |||
73 | static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, | ||
74 | int value) | ||
75 | { | ||
76 | struct palmas_gpio *pg = to_palmas_gpio(gc); | ||
77 | struct palmas *palmas = pg->palmas; | ||
78 | int ret; | ||
79 | |||
80 | /* Set the initial value */ | ||
81 | palmas_gpio_set(gc, offset, value); | ||
82 | |||
83 | ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, | ||
84 | PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset)); | ||
85 | if (ret < 0) | ||
86 | dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) | ||
91 | { | ||
92 | struct palmas_gpio *pg = to_palmas_gpio(gc); | ||
93 | struct palmas *palmas = pg->palmas; | ||
94 | int ret; | ||
95 | |||
96 | ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, | ||
97 | PALMAS_GPIO_DATA_DIR, BIT(offset), 0); | ||
98 | if (ret < 0) | ||
99 | dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
104 | { | ||
105 | struct palmas_gpio *pg = to_palmas_gpio(gc); | ||
106 | struct palmas *palmas = pg->palmas; | ||
107 | |||
108 | return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); | ||
109 | } | ||
110 | |||
111 | static int palmas_gpio_probe(struct platform_device *pdev) | ||
112 | { | ||
113 | struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); | ||
114 | struct palmas_platform_data *palmas_pdata; | ||
115 | struct palmas_gpio *palmas_gpio; | ||
116 | int ret; | ||
117 | |||
118 | palmas_gpio = devm_kzalloc(&pdev->dev, | ||
119 | sizeof(*palmas_gpio), GFP_KERNEL); | ||
120 | if (!palmas_gpio) { | ||
121 | dev_err(&pdev->dev, "Could not allocate palmas_gpio\n"); | ||
122 | return -ENOMEM; | ||
123 | } | ||
124 | |||
125 | palmas_gpio->palmas = palmas; | ||
126 | palmas_gpio->gpio_chip.owner = THIS_MODULE; | ||
127 | palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); | ||
128 | palmas_gpio->gpio_chip.ngpio = 8; | ||
129 | palmas_gpio->gpio_chip.can_sleep = 1; | ||
130 | palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; | ||
131 | palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; | ||
132 | palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; | ||
133 | palmas_gpio->gpio_chip.set = palmas_gpio_set; | ||
134 | palmas_gpio->gpio_chip.get = palmas_gpio_get; | ||
135 | palmas_gpio->gpio_chip.dev = &pdev->dev; | ||
136 | #ifdef CONFIG_OF_GPIO | ||
137 | palmas_gpio->gpio_chip.of_node = palmas->dev->of_node; | ||
138 | #endif | ||
139 | palmas_pdata = dev_get_platdata(palmas->dev); | ||
140 | if (palmas_pdata && palmas_pdata->gpio_base) | ||
141 | palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base; | ||
142 | else | ||
143 | palmas_gpio->gpio_chip.base = -1; | ||
144 | |||
145 | ret = gpiochip_add(&palmas_gpio->gpio_chip); | ||
146 | if (ret < 0) { | ||
147 | dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | platform_set_drvdata(pdev, palmas_gpio); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static int palmas_gpio_remove(struct platform_device *pdev) | ||
156 | { | ||
157 | struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev); | ||
158 | |||
159 | return gpiochip_remove(&palmas_gpio->gpio_chip); | ||
160 | } | ||
161 | |||
162 | static struct platform_driver palmas_gpio_driver = { | ||
163 | .driver.name = "palmas-gpio", | ||
164 | .driver.owner = THIS_MODULE, | ||
165 | .probe = palmas_gpio_probe, | ||
166 | .remove = palmas_gpio_remove, | ||
167 | }; | ||
168 | |||
169 | static int __init palmas_gpio_init(void) | ||
170 | { | ||
171 | return platform_driver_register(&palmas_gpio_driver); | ||
172 | } | ||
173 | subsys_initcall(palmas_gpio_init); | ||
174 | |||
175 | static void __exit palmas_gpio_exit(void) | ||
176 | { | ||
177 | platform_driver_unregister(&palmas_gpio_driver); | ||
178 | } | ||
179 | module_exit(palmas_gpio_exit); | ||
180 | |||
181 | MODULE_ALIAS("platform:palmas-gpio"); | ||
182 | MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); | ||
183 | MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs"); | ||
184 | MODULE_LICENSE("GPL v2"); | ||