[kernel] Fix gpio_spi_old module for 2.6.35
[openwrt.git] / target / linux / xburst / patches-2.6.34 / 106-gpio-charger.patch
1 From fc2a5da7117de38ddb538fb7c9907ec1aeb386ba Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sat, 24 Apr 2010 12:29:31 +0200
4 Subject: [PATCH] Add gpio chager driver
5
6 ---
7  drivers/power/Kconfig              |    7 ++
8  drivers/power/Makefile             |    1 +
9  drivers/power/gpio-charger.c       |  184 ++++++++++++++++++++++++++++++++++++
10  include/linux/power/gpio-charger.h |   28 ++++++
11  4 files changed, 220 insertions(+), 0 deletions(-)
12  create mode 100644 drivers/power/gpio-charger.c
13  create mode 100644 include/linux/power/gpio-charger.h
14
15 diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
16 index 2f4e51f..81d13b8 100644
17 --- a/drivers/power/Kconfig
18 +++ b/drivers/power/Kconfig
19 @@ -142,4 +142,11 @@ config BATTERY_JZ4740
20           This driver can be build as a module. If so, the module will be
21           called jz4740-battery.
22  
23 +config CHARGER_GPIO
24 +       tristate "GPIO charger"
25 +       depends on GPIOLIB
26 +       help
27 +         Say Y to include support for chargers indicating their status through
28 +         a GPIO pin.
29 +
30  endif # POWER_SUPPLY
31 diff --git a/drivers/power/Makefile b/drivers/power/Makefile
32 index 3b6b971..8deb992 100644
33 --- a/drivers/power/Makefile
34 +++ b/drivers/power/Makefile
35 @@ -33,3 +33,4 @@ obj-$(CONFIG_BATTERY_DA9030)  += da9030_battery.o
36  obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
37  obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
38  obj-$(CONFIG_BATTERY_JZ4740)   += jz4740-battery.o
39 +obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
40 diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
41 new file mode 100644
42 index 0000000..7a84994
43 --- /dev/null
44 +++ b/drivers/power/gpio-charger.c
45 @@ -0,0 +1,184 @@
46 +/*
47 + *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
48 + *  Driver for chargers indicating their status through a GPIO pin
49 + *
50 + *  This program is free software; you can redistribute         it and/or modify it
51 + *  under  the terms of         the GNU General  Public License as published by the
52 + *  Free Software Foundation;  either version 2 of the License, or (at your
53 + *  option) any later version.
54 + *
55 + *  You should have received a copy of the  GNU General Public License along
56 + *  with this program; if not, write  to the Free Software Foundation, Inc.,
57 + *  675 Mass Ave, Cambridge, MA 02139, USA.
58 + *
59 + */
60 +
61 +#include <linux/device.h>
62 +#include <linux/gpio.h>
63 +#include <linux/init.h>
64 +#include <linux/interrupt.h>
65 +#include <linux/kernel.h>
66 +#include <linux/module.h>
67 +#include <linux/platform_device.h>
68 +#include <linux/power_supply.h>
69 +#include <linux/slab.h>
70 +#include <linux/types.h>
71 +
72 +#include <linux/power/gpio-charger.h>
73 +
74 +struct gpio_charger {
75 +       const struct gpio_charger_platform_data *pdata;
76 +
77 +       int irq;
78 +
79 +       struct power_supply charger;
80 +};
81 +
82 +static irqreturn_t gpio_charger_irq(int irq, void *devid)
83 +{
84 +       struct power_supply *charger = devid;
85 +       power_supply_changed(charger);
86 +
87 +       return IRQ_HANDLED;
88 +}
89 +
90 +static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
91 +{
92 +       return container_of(psy, struct gpio_charger, charger);
93 +}
94 +
95 +static int gpio_charger_get_property(struct power_supply *psy,
96 +       enum power_supply_property psp, union power_supply_propval *val)
97 +{
98 +       struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
99 +       const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
100 +
101 +       switch (psp) {
102 +       case POWER_SUPPLY_PROP_ONLINE:
103 +               val->intval = gpio_get_value(pdata->gpio);
104 +               val->intval ^= pdata->gpio_active_low;
105 +               break;
106 +       default:
107 +               return -EINVAL;
108 +       }
109 +
110 +       return 0;
111 +}
112 +
113 +static enum power_supply_property gpio_charger_properties[] = {
114 +       POWER_SUPPLY_PROP_ONLINE,
115 +};
116 +
117 +static int __devinit gpio_charger_probe(struct platform_device *pdev)
118 +{
119 +       const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
120 +       struct gpio_charger *gpio_charger;
121 +       struct power_supply *charger;
122 +       int ret;
123 +
124 +       if (!pdata) {
125 +               dev_err(&pdev->dev, "No platform data");
126 +               return -EINVAL;
127 +       }
128 +
129 +       gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
130 +
131 +       charger = &gpio_charger->charger;
132 +
133 +       charger->name = pdata->name;
134 +       charger->type = pdata->type;
135 +       charger->properties = gpio_charger_properties;
136 +       charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
137 +       charger->get_property  = gpio_charger_get_property;
138 +       charger->supplied_to = pdata->batteries;
139 +       charger->num_supplicants = pdata->num_batteries;
140 +
141 +       if (gpio_is_valid(pdata->gpio)) {
142 +               ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
143 +               if (ret) {
144 +                       dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
145 +                       goto err;
146 +               }
147 +               ret = gpio_direction_input(pdata->gpio);
148 +               if (ret) {
149 +                       dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
150 +                       goto err_gpio_free;
151 +               }
152 +
153 +               gpio_charger->irq = gpio_to_irq(pdata->gpio);
154 +               if (gpio_charger->irq >= 0) {
155 +                       ret = request_irq(gpio_charger->irq, gpio_charger_irq,
156 +                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
157 +                       dev_name(&pdev->dev), charger);
158 +                       if (ret) {
159 +                               dev_warn(&pdev->dev, "Failed to request online gpio irq: %d\n", ret);
160 +                               gpio_charger->irq = -1;
161 +                       }
162 +               }
163 +       }
164 +
165 +       ret = power_supply_register(&pdev->dev, charger);
166 +       if (ret < 0) {
167 +               dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret);
168 +               goto err_gpio_free;
169 +       }
170 +
171 +       gpio_charger->pdata = pdata;
172 +       platform_set_drvdata(pdev, gpio_charger);
173 +
174 +       return 0;
175 +
176 +err_gpio_free:
177 +       if (gpio_is_valid(pdata->gpio)) {
178 +               if (gpio_charger->irq >= 0)
179 +                       free_irq(gpio_charger->irq, charger);
180 +               gpio_free(pdata->gpio);
181 +       }
182 +err:
183 +       return ret;
184 +}
185 +
186 +static int __devexit gpio_charger_remove(struct platform_device *pdev)
187 +{
188 +       struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
189 +       const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
190 +
191 +       power_supply_unregister(&gpio_charger->charger);
192 +
193 +       if (gpio_is_valid(pdata->gpio)) {
194 +               if (gpio_charger->irq >= 0)
195 +                       free_irq(gpio_charger->irq, &gpio_charger->charger);
196 +               gpio_free(pdata->gpio);
197 +       }
198 +
199 +       platform_set_drvdata(pdev, NULL);
200 +       kfree(gpio_charger);
201 +
202 +       return 0;
203 +}
204 +
205 +static struct platform_driver  gpio_charger_driver = {
206 +       .probe = gpio_charger_probe,
207 +       .remove = __devexit_p(gpio_charger_remove),
208 +       .driver = {
209 +               .name = "gpio-charger",
210 +               .owner = THIS_MODULE,
211 +       },
212 +};
213 +
214 +static int __init gpio_charger_init(void)
215 +{
216 +       return platform_driver_register(&gpio_charger_driver);
217 +}
218 +module_init(gpio_charger_init);
219 +
220 +static void __exit gpio_charger_exit(void)
221 +{
222 +       platform_driver_unregister(&gpio_charger_driver);
223 +}
224 +module_exit(gpio_charger_exit);
225 +
226 +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
227 +MODULE_DESCRIPTION("Driver for chargers indicating their status through a gpio");
228 +MODULE_LICENSE("GPL");
229 +MODULE_ALIAS("platform:gpio-charger");
230 diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h
231 new file mode 100644
232 index 0000000..95cdfc3
233 --- /dev/null
234 +++ b/include/linux/power/gpio-charger.h
235 @@ -0,0 +1,28 @@
236 +/*
237 + *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
238 + *
239 + *  This program is free software; you can redistribute         it and/or modify it
240 + *  under  the terms of         the GNU General  Public License as published by the
241 + *  Free Software Foundation;  either version 2 of the License, or (at your
242 + *  option) any later version.
243 + *
244 + *  You should have received a copy of the  GNU General Public License along
245 + *  with this program; if not, write  to the Free Software Foundation, Inc.,
246 + *  675 Mass Ave, Cambridge, MA 02139, USA.
247 + *
248 + */
249 +
250 +#ifndef __LINUX_POWER_GPIO_CHARGER_H__
251 +#define __LINUX_POWER_GPIO_CHARGER_H__
252 +
253 +struct gpio_charger_platform_data {
254 +       const char *name;
255 +       enum power_supply_type type;
256 +       int gpio;
257 +       int gpio_active_low;
258 +
259 +       char **batteries;
260 +       size_t num_batteries;
261 +};
262 +
263 +#endif
264 -- 
265 1.5.6.5
266