diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2010-10-21 11:55:01 -0400 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2010-11-18 08:56:17 -0500 |
commit | 5070437cd99511f69ae561f2ab417142a47a85ec (patch) | |
tree | 379dd2ab427ff33c09bee57f9d89726071b64137 /drivers/power | |
parent | 8ec98fe0b4ffdedce4c1caa9fb3d550f52ad1c6b (diff) |
power_supply: Add gpio charger driver
This patch adds a simple driver for chargers indicating their online
status through a GPIO pin.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/Kconfig | 10 | ||||
-rw-r--r-- | drivers/power/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/gpio-charger.c | 185 |
3 files changed, 196 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 60d83d983a36..32165295cb1b 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -185,4 +185,14 @@ config CHARGER_TWL4030 | |||
185 | help | 185 | help |
186 | Say Y here to enable support for TWL4030 Battery Charge Interface. | 186 | Say Y here to enable support for TWL4030 Battery Charge Interface. |
187 | 187 | ||
188 | config CHARGER_GPIO | ||
189 | tristate "GPIO charger" | ||
190 | depends on GPIOLIB | ||
191 | help | ||
192 | Say Y to include support for chargers which report their online status | ||
193 | through a GPIO pin. | ||
194 | |||
195 | This driver can be build as a module. If so, the module will be | ||
196 | called gpio-charger. | ||
197 | |||
188 | endif # POWER_SUPPLY | 198 | endif # POWER_SUPPLY |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index c75772eb157c..545459f9f356 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -32,3 +32,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o | |||
32 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o | 32 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o |
33 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o | 33 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o |
34 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o | 34 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o |
35 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o | ||
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c new file mode 100644 index 000000000000..fccbe99b619c --- /dev/null +++ b/drivers/power/gpio-charger.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
3 | * Driver for chargers which report their online status through a GPIO pin | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * You should have received a copy of the GNU General Public License along | ||
11 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/power_supply.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <linux/power/gpio-charger.h> | ||
27 | |||
28 | struct gpio_charger { | ||
29 | const struct gpio_charger_platform_data *pdata; | ||
30 | unsigned int irq; | ||
31 | |||
32 | struct power_supply charger; | ||
33 | }; | ||
34 | |||
35 | static irqreturn_t gpio_charger_irq(int irq, void *devid) | ||
36 | { | ||
37 | struct power_supply *charger = devid; | ||
38 | |||
39 | power_supply_changed(charger); | ||
40 | |||
41 | return IRQ_HANDLED; | ||
42 | } | ||
43 | |||
44 | static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) | ||
45 | { | ||
46 | return container_of(psy, struct gpio_charger, charger); | ||
47 | } | ||
48 | |||
49 | static int gpio_charger_get_property(struct power_supply *psy, | ||
50 | enum power_supply_property psp, union power_supply_propval *val) | ||
51 | { | ||
52 | struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); | ||
53 | const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; | ||
54 | |||
55 | switch (psp) { | ||
56 | case POWER_SUPPLY_PROP_ONLINE: | ||
57 | val->intval = gpio_get_value(pdata->gpio); | ||
58 | val->intval ^= pdata->gpio_active_low; | ||
59 | break; | ||
60 | default: | ||
61 | return -EINVAL; | ||
62 | } | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static enum power_supply_property gpio_charger_properties[] = { | ||
68 | POWER_SUPPLY_PROP_ONLINE, | ||
69 | }; | ||
70 | |||
71 | static int __devinit gpio_charger_probe(struct platform_device *pdev) | ||
72 | { | ||
73 | const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; | ||
74 | struct gpio_charger *gpio_charger; | ||
75 | struct power_supply *charger; | ||
76 | int ret; | ||
77 | int irq; | ||
78 | |||
79 | if (!pdata) { | ||
80 | dev_err(&pdev->dev, "No platform data\n"); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | if (!gpio_is_valid(pdata->gpio)) { | ||
85 | dev_err(&pdev->dev, "Invalid gpio pin\n"); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); | ||
90 | |||
91 | charger = &gpio_charger->charger; | ||
92 | |||
93 | charger->name = pdata->name; | ||
94 | charger->type = pdata->type; | ||
95 | charger->properties = gpio_charger_properties; | ||
96 | charger->num_properties = ARRAY_SIZE(gpio_charger_properties); | ||
97 | charger->get_property = gpio_charger_get_property; | ||
98 | charger->supplied_to = pdata->supplied_to; | ||
99 | charger->num_supplicants = pdata->num_supplicants; | ||
100 | |||
101 | ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); | ||
102 | if (ret) { | ||
103 | dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); | ||
104 | goto err_free; | ||
105 | } | ||
106 | ret = gpio_direction_input(pdata->gpio); | ||
107 | if (ret) { | ||
108 | dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); | ||
109 | goto err_gpio_free; | ||
110 | } | ||
111 | |||
112 | irq = gpio_to_irq(pdata->gpio); | ||
113 | if (irq > 0) { | ||
114 | ret = request_irq(irq, gpio_charger_irq, | ||
115 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
116 | dev_name(&pdev->dev), charger); | ||
117 | if (ret) | ||
118 | dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret); | ||
119 | else | ||
120 | gpio_charger->irq = irq; | ||
121 | } | ||
122 | |||
123 | gpio_charger->pdata = pdata; | ||
124 | |||
125 | ret = power_supply_register(&pdev->dev, charger); | ||
126 | if (ret < 0) { | ||
127 | dev_err(&pdev->dev, "Failed to register power supply: %d\n", ret); | ||
128 | goto err_irq_free; | ||
129 | } | ||
130 | |||
131 | platform_set_drvdata(pdev, gpio_charger); | ||
132 | |||
133 | return 0; | ||
134 | |||
135 | err_irq_free: | ||
136 | if (gpio_charger->irq) | ||
137 | free_irq(gpio_charger->irq, charger); | ||
138 | err_gpio_free: | ||
139 | gpio_free(pdata->gpio); | ||
140 | err_free: | ||
141 | kfree(gpio_charger); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static int __devexit gpio_charger_remove(struct platform_device *pdev) | ||
146 | { | ||
147 | struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | ||
148 | |||
149 | power_supply_unregister(&gpio_charger->charger); | ||
150 | |||
151 | if (gpio_charger->irq) | ||
152 | free_irq(gpio_charger->irq, &gpio_charger->charger); | ||
153 | gpio_free(gpio_charger->pdata->gpio); | ||
154 | |||
155 | platform_set_drvdata(pdev, NULL); | ||
156 | kfree(gpio_charger); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static struct platform_driver gpio_charger_driver = { | ||
162 | .probe = gpio_charger_probe, | ||
163 | .remove = __devexit_p(gpio_charger_remove), | ||
164 | .driver = { | ||
165 | .name = "gpio-charger", | ||
166 | .owner = THIS_MODULE, | ||
167 | }, | ||
168 | }; | ||
169 | |||
170 | static int __init gpio_charger_init(void) | ||
171 | { | ||
172 | return platform_driver_register(&gpio_charger_driver); | ||
173 | } | ||
174 | module_init(gpio_charger_init); | ||
175 | |||
176 | static void __exit gpio_charger_exit(void) | ||
177 | { | ||
178 | platform_driver_unregister(&gpio_charger_driver); | ||
179 | } | ||
180 | module_exit(gpio_charger_exit); | ||
181 | |||
182 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
183 | MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO"); | ||
184 | MODULE_LICENSE("GPL"); | ||
185 | MODULE_ALIAS("platform:gpio-charger"); | ||