1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> |
4 | * Driver for chargers which report their online status through a GPIO pin |
5 | */ |
6 | |
7 | #include <linux/device.h> |
8 | #include <linux/init.h> |
9 | #include <linux/interrupt.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/power_supply.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/of.h> |
16 | #include <linux/gpio/consumer.h> |
17 | |
18 | #include <linux/power/gpio-charger.h> |
19 | |
20 | struct gpio_mapping { |
21 | u32 limit_ua; |
22 | u32 gpiodata; |
23 | } __packed; |
24 | |
25 | struct gpio_charger { |
26 | struct device *dev; |
27 | unsigned int irq; |
28 | unsigned int charge_status_irq; |
29 | bool wakeup_enabled; |
30 | |
31 | struct power_supply *charger; |
32 | struct power_supply_desc charger_desc; |
33 | struct gpio_desc *gpiod; |
34 | struct gpio_desc *charge_status; |
35 | |
36 | struct gpio_descs *current_limit_gpios; |
37 | struct gpio_mapping *current_limit_map; |
38 | u32 current_limit_map_size; |
39 | u32 charge_current_limit; |
40 | }; |
41 | |
42 | static irqreturn_t gpio_charger_irq(int irq, void *devid) |
43 | { |
44 | struct power_supply *charger = devid; |
45 | |
46 | power_supply_changed(psy: charger); |
47 | |
48 | return IRQ_HANDLED; |
49 | } |
50 | |
51 | static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy) |
52 | { |
53 | return power_supply_get_drvdata(psy); |
54 | } |
55 | |
56 | static int set_charge_current_limit(struct gpio_charger *gpio_charger, int val) |
57 | { |
58 | struct gpio_mapping mapping; |
59 | int ndescs = gpio_charger->current_limit_gpios->ndescs; |
60 | struct gpio_desc **gpios = gpio_charger->current_limit_gpios->desc; |
61 | int i; |
62 | |
63 | if (!gpio_charger->current_limit_map_size) |
64 | return -EINVAL; |
65 | |
66 | for (i = 0; i < gpio_charger->current_limit_map_size; i++) { |
67 | if (gpio_charger->current_limit_map[i].limit_ua <= val) |
68 | break; |
69 | } |
70 | mapping = gpio_charger->current_limit_map[i]; |
71 | |
72 | for (i = 0; i < ndescs; i++) { |
73 | bool val = (mapping.gpiodata >> i) & 1; |
74 | gpiod_set_value_cansleep(desc: gpios[ndescs-i-1], value: val); |
75 | } |
76 | |
77 | gpio_charger->charge_current_limit = mapping.limit_ua; |
78 | |
79 | dev_dbg(gpio_charger->dev, "set charge current limit to %d (requested: %d)\n" , |
80 | gpio_charger->charge_current_limit, val); |
81 | |
82 | return 0; |
83 | } |
84 | |
85 | static int gpio_charger_get_property(struct power_supply *psy, |
86 | enum power_supply_property psp, union power_supply_propval *val) |
87 | { |
88 | struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); |
89 | |
90 | switch (psp) { |
91 | case POWER_SUPPLY_PROP_ONLINE: |
92 | val->intval = gpiod_get_value_cansleep(desc: gpio_charger->gpiod); |
93 | break; |
94 | case POWER_SUPPLY_PROP_STATUS: |
95 | if (gpiod_get_value_cansleep(desc: gpio_charger->charge_status)) |
96 | val->intval = POWER_SUPPLY_STATUS_CHARGING; |
97 | else |
98 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; |
99 | break; |
100 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: |
101 | val->intval = gpio_charger->charge_current_limit; |
102 | break; |
103 | default: |
104 | return -EINVAL; |
105 | } |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | static int gpio_charger_set_property(struct power_supply *psy, |
111 | enum power_supply_property psp, const union power_supply_propval *val) |
112 | { |
113 | struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy); |
114 | |
115 | switch (psp) { |
116 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: |
117 | return set_charge_current_limit(gpio_charger, val: val->intval); |
118 | default: |
119 | return -EINVAL; |
120 | } |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static int gpio_charger_property_is_writeable(struct power_supply *psy, |
126 | enum power_supply_property psp) |
127 | { |
128 | switch (psp) { |
129 | case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: |
130 | return 1; |
131 | default: |
132 | break; |
133 | } |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static enum power_supply_type gpio_charger_get_type(struct device *dev) |
139 | { |
140 | const char *chargetype; |
141 | |
142 | if (!device_property_read_string(dev, propname: "charger-type" , val: &chargetype)) { |
143 | if (!strcmp("unknown" , chargetype)) |
144 | return POWER_SUPPLY_TYPE_UNKNOWN; |
145 | if (!strcmp("battery" , chargetype)) |
146 | return POWER_SUPPLY_TYPE_BATTERY; |
147 | if (!strcmp("ups" , chargetype)) |
148 | return POWER_SUPPLY_TYPE_UPS; |
149 | if (!strcmp("mains" , chargetype)) |
150 | return POWER_SUPPLY_TYPE_MAINS; |
151 | if (!strcmp("usb-sdp" , chargetype)) |
152 | return POWER_SUPPLY_TYPE_USB; |
153 | if (!strcmp("usb-dcp" , chargetype)) |
154 | return POWER_SUPPLY_TYPE_USB; |
155 | if (!strcmp("usb-cdp" , chargetype)) |
156 | return POWER_SUPPLY_TYPE_USB; |
157 | if (!strcmp("usb-aca" , chargetype)) |
158 | return POWER_SUPPLY_TYPE_USB; |
159 | } |
160 | dev_warn(dev, "unknown charger type %s\n" , chargetype); |
161 | |
162 | return POWER_SUPPLY_TYPE_UNKNOWN; |
163 | } |
164 | |
165 | static int gpio_charger_get_irq(struct device *dev, void *dev_id, |
166 | struct gpio_desc *gpio) |
167 | { |
168 | int ret, irq = gpiod_to_irq(desc: gpio); |
169 | |
170 | if (irq > 0) { |
171 | ret = devm_request_any_context_irq(dev, irq, handler: gpio_charger_irq, |
172 | IRQF_TRIGGER_RISING | |
173 | IRQF_TRIGGER_FALLING, |
174 | devname: dev_name(dev), |
175 | dev_id); |
176 | if (ret < 0) { |
177 | dev_warn(dev, "Failed to request irq: %d\n" , ret); |
178 | irq = 0; |
179 | } |
180 | } |
181 | |
182 | return irq; |
183 | } |
184 | |
185 | static int init_charge_current_limit(struct device *dev, |
186 | struct gpio_charger *gpio_charger) |
187 | { |
188 | int i, len; |
189 | u32 cur_limit = U32_MAX; |
190 | |
191 | gpio_charger->current_limit_gpios = devm_gpiod_get_array_optional(dev, |
192 | con_id: "charge-current-limit" , flags: GPIOD_OUT_LOW); |
193 | if (IS_ERR(ptr: gpio_charger->current_limit_gpios)) { |
194 | dev_err(dev, "error getting current-limit GPIOs\n" ); |
195 | return PTR_ERR(ptr: gpio_charger->current_limit_gpios); |
196 | } |
197 | |
198 | if (!gpio_charger->current_limit_gpios) |
199 | return 0; |
200 | |
201 | len = device_property_read_u32_array(dev, propname: "charge-current-limit-mapping" , |
202 | NULL, nval: 0); |
203 | if (len < 0) |
204 | return len; |
205 | |
206 | if (len == 0 || len % 2) { |
207 | dev_err(dev, "invalid charge-current-limit-mapping length\n" ); |
208 | return -EINVAL; |
209 | } |
210 | |
211 | gpio_charger->current_limit_map = devm_kmalloc_array(dev, |
212 | n: len / 2, size: sizeof(*gpio_charger->current_limit_map), GFP_KERNEL); |
213 | if (!gpio_charger->current_limit_map) |
214 | return -ENOMEM; |
215 | |
216 | gpio_charger->current_limit_map_size = len / 2; |
217 | |
218 | len = device_property_read_u32_array(dev, propname: "charge-current-limit-mapping" , |
219 | val: (u32*) gpio_charger->current_limit_map, nval: len); |
220 | if (len < 0) |
221 | return len; |
222 | |
223 | for (i=0; i < gpio_charger->current_limit_map_size; i++) { |
224 | if (gpio_charger->current_limit_map[i].limit_ua > cur_limit) { |
225 | dev_err(dev, "charge-current-limit-mapping not sorted by current in descending order\n" ); |
226 | return -EINVAL; |
227 | } |
228 | |
229 | cur_limit = gpio_charger->current_limit_map[i].limit_ua; |
230 | } |
231 | |
232 | /* default to smallest current limitation for safety reasons */ |
233 | len = gpio_charger->current_limit_map_size - 1; |
234 | set_charge_current_limit(gpio_charger, |
235 | val: gpio_charger->current_limit_map[len].limit_ua); |
236 | |
237 | return 0; |
238 | } |
239 | |
240 | /* |
241 | * The entries will be overwritten by driver's probe routine depending |
242 | * on the available features. This list ensures, that the array is big |
243 | * enough for all optional features. |
244 | */ |
245 | static enum power_supply_property gpio_charger_properties[] = { |
246 | POWER_SUPPLY_PROP_ONLINE, |
247 | POWER_SUPPLY_PROP_STATUS, |
248 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, |
249 | }; |
250 | |
251 | static int gpio_charger_probe(struct platform_device *pdev) |
252 | { |
253 | struct device *dev = &pdev->dev; |
254 | const struct gpio_charger_platform_data *pdata = dev->platform_data; |
255 | struct power_supply_config psy_cfg = {}; |
256 | struct gpio_charger *gpio_charger; |
257 | struct power_supply_desc *charger_desc; |
258 | struct gpio_desc *charge_status; |
259 | int charge_status_irq; |
260 | int ret; |
261 | int num_props = 0; |
262 | |
263 | if (!pdata && !dev->of_node) { |
264 | dev_err(dev, "No platform data\n" ); |
265 | return -ENOENT; |
266 | } |
267 | |
268 | gpio_charger = devm_kzalloc(dev, size: sizeof(*gpio_charger), GFP_KERNEL); |
269 | if (!gpio_charger) |
270 | return -ENOMEM; |
271 | gpio_charger->dev = dev; |
272 | |
273 | /* |
274 | * This will fetch a GPIO descriptor from device tree, ACPI or |
275 | * boardfile descriptor tables. It's good to try this first. |
276 | */ |
277 | gpio_charger->gpiod = devm_gpiod_get_optional(dev, NULL, flags: GPIOD_IN); |
278 | if (IS_ERR(ptr: gpio_charger->gpiod)) { |
279 | /* Just try again if this happens */ |
280 | return dev_err_probe(dev, err: PTR_ERR(ptr: gpio_charger->gpiod), |
281 | fmt: "error getting GPIO descriptor\n" ); |
282 | } |
283 | |
284 | if (gpio_charger->gpiod) { |
285 | gpio_charger_properties[num_props] = POWER_SUPPLY_PROP_ONLINE; |
286 | num_props++; |
287 | } |
288 | |
289 | charge_status = devm_gpiod_get_optional(dev, con_id: "charge-status" , flags: GPIOD_IN); |
290 | if (IS_ERR(ptr: charge_status)) |
291 | return PTR_ERR(ptr: charge_status); |
292 | if (charge_status) { |
293 | gpio_charger->charge_status = charge_status; |
294 | gpio_charger_properties[num_props] = POWER_SUPPLY_PROP_STATUS; |
295 | num_props++; |
296 | } |
297 | |
298 | ret = init_charge_current_limit(dev, gpio_charger); |
299 | if (ret < 0) |
300 | return ret; |
301 | if (gpio_charger->current_limit_map) { |
302 | gpio_charger_properties[num_props] = |
303 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; |
304 | num_props++; |
305 | } |
306 | |
307 | charger_desc = &gpio_charger->charger_desc; |
308 | charger_desc->properties = gpio_charger_properties; |
309 | charger_desc->num_properties = num_props; |
310 | charger_desc->get_property = gpio_charger_get_property; |
311 | charger_desc->set_property = gpio_charger_set_property; |
312 | charger_desc->property_is_writeable = |
313 | gpio_charger_property_is_writeable; |
314 | |
315 | psy_cfg.of_node = dev->of_node; |
316 | psy_cfg.drv_data = gpio_charger; |
317 | |
318 | if (pdata) { |
319 | charger_desc->name = pdata->name; |
320 | charger_desc->type = pdata->type; |
321 | psy_cfg.supplied_to = pdata->supplied_to; |
322 | psy_cfg.num_supplicants = pdata->num_supplicants; |
323 | } else { |
324 | charger_desc->name = dev->of_node->name; |
325 | charger_desc->type = gpio_charger_get_type(dev); |
326 | } |
327 | |
328 | if (!charger_desc->name) |
329 | charger_desc->name = pdev->name; |
330 | |
331 | gpio_charger->charger = devm_power_supply_register(parent: dev, desc: charger_desc, |
332 | cfg: &psy_cfg); |
333 | if (IS_ERR(ptr: gpio_charger->charger)) { |
334 | ret = PTR_ERR(ptr: gpio_charger->charger); |
335 | dev_err(dev, "Failed to register power supply: %d\n" , ret); |
336 | return ret; |
337 | } |
338 | |
339 | gpio_charger->irq = gpio_charger_get_irq(dev, dev_id: gpio_charger->charger, |
340 | gpio: gpio_charger->gpiod); |
341 | |
342 | charge_status_irq = gpio_charger_get_irq(dev, dev_id: gpio_charger->charger, |
343 | gpio: gpio_charger->charge_status); |
344 | gpio_charger->charge_status_irq = charge_status_irq; |
345 | |
346 | platform_set_drvdata(pdev, data: gpio_charger); |
347 | |
348 | device_init_wakeup(dev, enable: 1); |
349 | |
350 | return 0; |
351 | } |
352 | |
353 | #ifdef CONFIG_PM_SLEEP |
354 | static int gpio_charger_suspend(struct device *dev) |
355 | { |
356 | struct gpio_charger *gpio_charger = dev_get_drvdata(dev); |
357 | |
358 | if (device_may_wakeup(dev)) |
359 | gpio_charger->wakeup_enabled = |
360 | !enable_irq_wake(irq: gpio_charger->irq); |
361 | |
362 | return 0; |
363 | } |
364 | |
365 | static int gpio_charger_resume(struct device *dev) |
366 | { |
367 | struct gpio_charger *gpio_charger = dev_get_drvdata(dev); |
368 | |
369 | if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled) |
370 | disable_irq_wake(irq: gpio_charger->irq); |
371 | power_supply_changed(psy: gpio_charger->charger); |
372 | |
373 | return 0; |
374 | } |
375 | #endif |
376 | |
377 | static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, |
378 | gpio_charger_suspend, gpio_charger_resume); |
379 | |
380 | static const struct of_device_id gpio_charger_match[] = { |
381 | { .compatible = "gpio-charger" }, |
382 | { } |
383 | }; |
384 | MODULE_DEVICE_TABLE(of, gpio_charger_match); |
385 | |
386 | static struct platform_driver gpio_charger_driver = { |
387 | .probe = gpio_charger_probe, |
388 | .driver = { |
389 | .name = "gpio-charger" , |
390 | .pm = &gpio_charger_pm_ops, |
391 | .of_match_table = gpio_charger_match, |
392 | }, |
393 | }; |
394 | |
395 | module_platform_driver(gpio_charger_driver); |
396 | |
397 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>" ); |
398 | MODULE_DESCRIPTION("Driver for chargers only communicating via GPIO(s)" ); |
399 | MODULE_LICENSE("GPL" ); |
400 | MODULE_ALIAS("platform:gpio-charger" ); |
401 | |