blob: dbc75cd463ad21b8552438ac220455be3b4447e4 [file] [log] [blame]
Jay Chokshi89489c32011-11-16 16:55:26 -08001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/power_supply.h>
20#include <linux/slab.h>
21#include <linux/gpio.h>
22#include <linux/power/ltc4088-charger.h>
23
24#define MAX_CURRENT_UA(n) (n)
25#define MAX_CURRENT_MA(n) (n * MAX_CURRENT_UA(1000))
26
27/**
28 * ltc4088_max_current - A typical current values supported by the charger
29 * @LTC4088_MAX_CURRENT_100mA: 100mA current
30 * @LTC4088_MAX_CURRENT_500mA: 500mA current
31 * @LTC4088_MAX_CURRENT_1A: 1A current
32 */
33enum ltc4088_max_current {
34 LTC4088_MAX_CURRENT_100mA = 100,
35 LTC4088_MAX_CURRENT_500mA = 500,
36 LTC4088_MAX_CURRENT_1A = 1000,
37};
38
39/**
40 * struct ltc4088_chg_chip - Device information
41 * @dev: Device pointer to access the parent
42 * @lock: Enable mutual exclusion
43 * @usb_psy: USB device information
44 * @gpio_mode_select_d0: GPIO #pin for D0 charger line
45 * @gpio_mode_select_d1: GPIO #pin for D1 charger line
46 * @gpio_mode_select_d2: GPIO #pin for D2 charger line
47 * @max_current: Maximum current that is supplied at this time
48 */
49struct ltc4088_chg_chip {
50 struct device *dev;
51 struct mutex lock;
52 struct power_supply usb_psy;
53 unsigned int gpio_mode_select_d0;
54 unsigned int gpio_mode_select_d1;
55 unsigned int gpio_mode_select_d2;
56 unsigned int max_current;
57};
58
59static enum power_supply_property pm_power_props[] = {
60 POWER_SUPPLY_PROP_CURRENT_MAX,
61 POWER_SUPPLY_PROP_ONLINE,
62};
63
64static char *pm_power_supplied_to[] = {
65 "battery",
66};
67
68static int ltc4088_set_charging(struct ltc4088_chg_chip *chip, bool enable)
69{
70 mutex_lock(&chip->lock);
71
72 if (enable) {
73 gpio_set_value_cansleep(chip->gpio_mode_select_d2, 0);
74 } else {
75 /* When disabling charger, set the max current to 0 also */
76 chip->max_current = 0;
77 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
78 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
79 gpio_set_value_cansleep(chip->gpio_mode_select_d2, 1);
80 }
81
82 mutex_unlock(&chip->lock);
83
84 return 0;
85}
86
87static void ltc4088_set_max_current(struct ltc4088_chg_chip *chip, int value)
88{
89 mutex_lock(&chip->lock);
90
91 /* If current is less than 100mA, we can not support that granularity */
92 if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_100mA)) {
93 chip->max_current = 0;
94 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
95 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
96 } else if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_500mA)) {
97 chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_100mA);
98 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 0);
99 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 0);
100 } else if (value < MAX_CURRENT_MA(LTC4088_MAX_CURRENT_1A)) {
101 chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_500mA);
102 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 0);
103 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
104 } else {
105 chip->max_current = MAX_CURRENT_MA(LTC4088_MAX_CURRENT_1A);
106 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
107 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 0);
108 }
109
110 mutex_unlock(&chip->lock);
111}
112
113static void ltc4088_set_charging_off(struct ltc4088_chg_chip *chip)
114{
115 gpio_set_value_cansleep(chip->gpio_mode_select_d0, 1);
116 gpio_set_value_cansleep(chip->gpio_mode_select_d1, 1);
117}
118
119static int ltc4088_set_initial_state(struct ltc4088_chg_chip *chip)
120{
121 int rc;
122
123 rc = gpio_request(chip->gpio_mode_select_d0, "ltc4088_D0");
124 if (rc) {
125 pr_err("gpio request failed for GPIO %d\n",
126 chip->gpio_mode_select_d0);
127 return rc;
128 }
129
130 rc = gpio_request(chip->gpio_mode_select_d1, "ltc4088_D1");
131 if (rc) {
132 pr_err("gpio request failed for GPIO %d\n",
133 chip->gpio_mode_select_d1);
134 goto gpio_err_d0;
135 }
136
137 rc = gpio_request(chip->gpio_mode_select_d2, "ltc4088_D2");
138 if (rc) {
139 pr_err("gpio request failed for GPIO %d\n",
140 chip->gpio_mode_select_d2);
141 goto gpio_err_d1;
142 }
143
144 rc = gpio_direction_output(chip->gpio_mode_select_d0, 0);
145 if (rc) {
146 pr_err("failed to set direction for GPIO %d\n",
147 chip->gpio_mode_select_d0);
148 goto gpio_err_d2;
149 }
150
151 rc = gpio_direction_output(chip->gpio_mode_select_d1, 0);
152 if (rc) {
153 pr_err("failed to set direction for GPIO %d\n",
154 chip->gpio_mode_select_d1);
155 goto gpio_err_d2;
156 }
157
158 rc = gpio_direction_output(chip->gpio_mode_select_d2, 1);
159 if (rc) {
160 pr_err("failed to set direction for GPIO %d\n",
161 chip->gpio_mode_select_d2);
162 goto gpio_err_d2;
163 }
164
165 return 0;
166
167gpio_err_d2:
168 gpio_free(chip->gpio_mode_select_d2);
169gpio_err_d1:
170 gpio_free(chip->gpio_mode_select_d1);
171gpio_err_d0:
172 gpio_free(chip->gpio_mode_select_d0);
173 return rc;
174}
175
176static int pm_power_get_property(struct power_supply *psy,
177 enum power_supply_property psp,
178 union power_supply_propval *val)
179{
180 struct ltc4088_chg_chip *chip;
181
182 if (psy->type == POWER_SUPPLY_TYPE_USB) {
183 chip = container_of(psy, struct ltc4088_chg_chip,
184 usb_psy);
185 switch (psp) {
186 case POWER_SUPPLY_PROP_ONLINE:
187 if (chip->max_current)
188 val->intval = 1;
189 else
190 val->intval = 0;
191 break;
192 case POWER_SUPPLY_PROP_CURRENT_MAX:
193 val->intval = chip->max_current;
194 break;
195 default:
196 return -EINVAL;
197 }
198 }
199 return 0;
200}
201
202static int pm_power_set_property(struct power_supply *psy,
203 enum power_supply_property psp,
204 const union power_supply_propval *val)
205{
206 struct ltc4088_chg_chip *chip;
207
208 if (psy->type == POWER_SUPPLY_TYPE_USB) {
209 chip = container_of(psy, struct ltc4088_chg_chip,
210 usb_psy);
211 switch (psp) {
212 case POWER_SUPPLY_PROP_ONLINE:
213 ltc4088_set_charging(chip, val->intval);
214 break;
215 case POWER_SUPPLY_PROP_CURRENT_MAX:
216 ltc4088_set_max_current(chip, val->intval);
217 break;
218 default:
219 return -EINVAL;
220 }
221 }
222 return 0;
223}
224
225static int __devinit ltc4088_charger_probe(struct platform_device *pdev)
226{
227 int rc;
228 struct ltc4088_chg_chip *chip;
229 const struct ltc4088_charger_platform_data *pdata
230 = pdev->dev.platform_data;
231
232 if (!pdata) {
233 pr_err("missing platform data\n");
234 return -EINVAL;
235 }
236
237 chip = kzalloc(sizeof(struct ltc4088_chg_chip),
238 GFP_KERNEL);
239 if (!chip) {
240 pr_err("Cannot allocate pm_chg_chip\n");
241 return -ENOMEM;
242 }
243
244 chip->dev = &pdev->dev;
245
246 if (pdata->gpio_mode_select_d0 < 0 ||
247 pdata->gpio_mode_select_d1 < 0 ||
248 pdata->gpio_mode_select_d2 < 0) {
249 pr_err("Invalid platform data supplied\n");
250 rc = -EINVAL;
251 goto free_chip;
252 }
253
254 mutex_init(&chip->lock);
255
256 chip->gpio_mode_select_d0 = pdata->gpio_mode_select_d0;
257 chip->gpio_mode_select_d1 = pdata->gpio_mode_select_d1;
258 chip->gpio_mode_select_d2 = pdata->gpio_mode_select_d2;
259
260 chip->usb_psy.name = "usb",
261 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
262 chip->usb_psy.supplied_to = pm_power_supplied_to,
263 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
264 chip->usb_psy.properties = pm_power_props,
265 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
266 chip->usb_psy.get_property = pm_power_get_property,
267 chip->usb_psy.set_property = pm_power_set_property,
268
269 rc = power_supply_register(chip->dev, &chip->usb_psy);
270 if (rc < 0) {
271 pr_err("power_supply_register usb failed rc = %d\n", rc);
272 goto free_chip;
273 }
274
275 platform_set_drvdata(pdev, chip);
276
277 rc = ltc4088_set_initial_state(chip);
278 if (rc < 0) {
279 pr_err("setting initial state failed rc = %d\n", rc);
280 goto unregister_usb;
281 }
282
283 return 0;
284
285unregister_usb:
286 platform_set_drvdata(pdev, NULL);
287 power_supply_unregister(&chip->usb_psy);
288free_chip:
289 kfree(chip);
290
291 return rc;
292}
293
294static int __devexit ltc4088_charger_remove(struct platform_device *pdev)
295{
296 struct ltc4088_chg_chip *chip = platform_get_drvdata(pdev);
297
298 ltc4088_set_charging_off(chip);
299
300 gpio_free(chip->gpio_mode_select_d2);
301 gpio_free(chip->gpio_mode_select_d1);
302 gpio_free(chip->gpio_mode_select_d0);
303
304 power_supply_unregister(&chip->usb_psy);
305
306 platform_set_drvdata(pdev, NULL);
307 mutex_destroy(&chip->lock);
308 kfree(chip);
309
310 return 0;
311}
312
313static struct platform_driver ltc4088_charger_driver = {
314 .probe = ltc4088_charger_probe,
315 .remove = __devexit_p(ltc4088_charger_remove),
316 .driver = {
317 .name = LTC4088_CHARGER_DEV_NAME,
318 .owner = THIS_MODULE,
319 },
320};
321
322static int __init ltc4088_charger_init(void)
323{
324 return platform_driver_register(&ltc4088_charger_driver);
325}
326
327static void __exit ltc4088_charger_exit(void)
328{
329 platform_driver_unregister(&ltc4088_charger_driver);
330}
331
332subsys_initcall(ltc4088_charger_init);
333module_exit(ltc4088_charger_exit);
334
335MODULE_LICENSE("GPL v2");
336MODULE_DESCRIPTION("LTC4088 charger/battery driver");
337MODULE_VERSION("1.0");
338MODULE_ALIAS("platform:" LTC4088_CHARGER_DEV_NAME);