Merge tag 'reset-for-v5.3' of git://git.pengutronix.de/git/pza/linux into arm/drivers
[sfrench/cifs-2.6.git] / drivers / power / supply / tps65090-charger.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Battery charger driver for TI's tps65090
4  *
5  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
6
7  */
8 #include <linux/delay.h>
9 #include <linux/err.h>
10 #include <linux/freezer.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel.h>
14 #include <linux/kthread.h>
15 #include <linux/module.h>
16 #include <linux/of_device.h>
17 #include <linux/platform_device.h>
18 #include <linux/power_supply.h>
19 #include <linux/slab.h>
20
21 #include <linux/mfd/tps65090.h>
22
23 #define TPS65090_CHARGER_ENABLE BIT(0)
24 #define TPS65090_VACG           BIT(1)
25 #define TPS65090_NOITERM        BIT(5)
26
27 #define POLL_INTERVAL           (HZ * 2)        /* Used when no irq */
28
29 struct tps65090_charger {
30         struct  device  *dev;
31         int     ac_online;
32         int     prev_ac_online;
33         int     irq;
34         struct task_struct      *poll_task;
35         bool                    passive_mode;
36         struct power_supply     *ac;
37         struct tps65090_platform_data *pdata;
38 };
39
40 static enum power_supply_property tps65090_ac_props[] = {
41         POWER_SUPPLY_PROP_ONLINE,
42 };
43
44 static int tps65090_low_chrg_current(struct tps65090_charger *charger)
45 {
46         int ret;
47
48         if (charger->passive_mode)
49                 return 0;
50
51         ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5,
52                         TPS65090_NOITERM);
53         if (ret < 0) {
54                 dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
55                         __func__, TPS65090_REG_CG_CTRL5);
56                 return ret;
57         }
58         return 0;
59 }
60
61 static int tps65090_enable_charging(struct tps65090_charger *charger)
62 {
63         int ret;
64         uint8_t ctrl0 = 0;
65
66         if (charger->passive_mode)
67                 return 0;
68
69         ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0,
70                             &ctrl0);
71         if (ret < 0) {
72                 dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
73                                 __func__, TPS65090_REG_CG_CTRL0);
74                 return ret;
75         }
76
77         ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL0,
78                                 (ctrl0 | TPS65090_CHARGER_ENABLE));
79         if (ret < 0) {
80                 dev_err(charger->dev, "%s(): error writing in register 0x%x\n",
81                                 __func__, TPS65090_REG_CG_CTRL0);
82                 return ret;
83         }
84         return 0;
85 }
86
87 static int tps65090_config_charger(struct tps65090_charger *charger)
88 {
89         uint8_t intrmask = 0;
90         int ret;
91
92         if (charger->passive_mode)
93                 return 0;
94
95         if (charger->pdata->enable_low_current_chrg) {
96                 ret = tps65090_low_chrg_current(charger);
97                 if (ret < 0) {
98                         dev_err(charger->dev,
99                                 "error configuring low charge current\n");
100                         return ret;
101                 }
102         }
103
104         /* Enable the VACG interrupt for AC power detect */
105         ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_MASK,
106                             &intrmask);
107         if (ret < 0) {
108                 dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
109                         __func__, TPS65090_REG_INTR_MASK);
110                 return ret;
111         }
112
113         ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_MASK,
114                              (intrmask | TPS65090_VACG));
115         if (ret < 0) {
116                 dev_err(charger->dev, "%s(): error writing in register 0x%x\n",
117                         __func__, TPS65090_REG_CG_CTRL0);
118                 return ret;
119         }
120
121         return 0;
122 }
123
124 static int tps65090_ac_get_property(struct power_supply *psy,
125                         enum power_supply_property psp,
126                         union power_supply_propval *val)
127 {
128         struct tps65090_charger *charger = power_supply_get_drvdata(psy);
129
130         if (psp == POWER_SUPPLY_PROP_ONLINE) {
131                 val->intval = charger->ac_online;
132                 charger->prev_ac_online = charger->ac_online;
133                 return 0;
134         }
135         return -EINVAL;
136 }
137
138 static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
139 {
140         struct tps65090_charger *charger = dev_id;
141         int ret;
142         uint8_t status1 = 0;
143         uint8_t intrsts = 0;
144
145         ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_STATUS1,
146                             &status1);
147         if (ret < 0) {
148                 dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n",
149                                 __func__, TPS65090_REG_CG_STATUS1);
150                 return IRQ_HANDLED;
151         }
152         msleep(75);
153         ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_STS,
154                             &intrsts);
155         if (ret < 0) {
156                 dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n",
157                                 __func__, TPS65090_REG_INTR_STS);
158                 return IRQ_HANDLED;
159         }
160
161         if (intrsts & TPS65090_VACG) {
162                 ret = tps65090_enable_charging(charger);
163                 if (ret < 0)
164                         return IRQ_HANDLED;
165                 charger->ac_online = 1;
166         } else {
167                 charger->ac_online = 0;
168         }
169
170         /* Clear interrupts. */
171         if (!charger->passive_mode) {
172                 ret = tps65090_write(charger->dev->parent,
173                                      TPS65090_REG_INTR_STS, 0x00);
174                 if (ret < 0) {
175                         dev_err(charger->dev,
176                                 "%s(): Error in writing reg 0x%x\n",
177                                 __func__, TPS65090_REG_INTR_STS);
178                 }
179         }
180
181         if (charger->prev_ac_online != charger->ac_online)
182                 power_supply_changed(charger->ac);
183
184         return IRQ_HANDLED;
185 }
186
187 static struct tps65090_platform_data *
188                 tps65090_parse_dt_charger_data(struct platform_device *pdev)
189 {
190         struct tps65090_platform_data *pdata;
191         struct device_node *np = pdev->dev.of_node;
192         unsigned int prop;
193
194         pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
195         if (!pdata) {
196                 dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
197                 return NULL;
198         }
199
200         prop = of_property_read_bool(np, "ti,enable-low-current-chrg");
201         pdata->enable_low_current_chrg = prop;
202
203         pdata->irq_base = -1;
204
205         return pdata;
206
207 }
208
209 static int tps65090_charger_poll_task(void *data)
210 {
211         set_freezable();
212
213         while (!kthread_should_stop()) {
214                 schedule_timeout_interruptible(POLL_INTERVAL);
215                 try_to_freeze();
216                 tps65090_charger_isr(-1, data);
217         }
218         return 0;
219 }
220
221 static const struct power_supply_desc tps65090_charger_desc = {
222         .name                   = "tps65090-ac",
223         .type                   = POWER_SUPPLY_TYPE_MAINS,
224         .get_property           = tps65090_ac_get_property,
225         .properties             = tps65090_ac_props,
226         .num_properties         = ARRAY_SIZE(tps65090_ac_props),
227 };
228
229 static int tps65090_charger_probe(struct platform_device *pdev)
230 {
231         struct tps65090_charger *cdata;
232         struct tps65090_platform_data *pdata;
233         struct power_supply_config psy_cfg = {};
234         uint8_t status1 = 0;
235         int ret;
236         int irq;
237
238         pdata = dev_get_platdata(pdev->dev.parent);
239
240         if (IS_ENABLED(CONFIG_OF) && !pdata && pdev->dev.of_node)
241                 pdata = tps65090_parse_dt_charger_data(pdev);
242
243         if (!pdata) {
244                 dev_err(&pdev->dev, "%s():no platform data available\n",
245                                 __func__);
246                 return -ENODEV;
247         }
248
249         cdata = devm_kzalloc(&pdev->dev, sizeof(*cdata), GFP_KERNEL);
250         if (!cdata) {
251                 dev_err(&pdev->dev, "failed to allocate memory status\n");
252                 return -ENOMEM;
253         }
254
255         platform_set_drvdata(pdev, cdata);
256
257         cdata->dev                      = &pdev->dev;
258         cdata->pdata                    = pdata;
259
260         psy_cfg.supplied_to             = pdata->supplied_to;
261         psy_cfg.num_supplicants         = pdata->num_supplicants;
262         psy_cfg.of_node                 = pdev->dev.of_node;
263         psy_cfg.drv_data                = cdata;
264
265         cdata->ac = power_supply_register(&pdev->dev, &tps65090_charger_desc,
266                         &psy_cfg);
267         if (IS_ERR(cdata->ac)) {
268                 dev_err(&pdev->dev, "failed: power supply register\n");
269                 return PTR_ERR(cdata->ac);
270         }
271
272         irq = platform_get_irq(pdev, 0);
273         if (irq < 0)
274                 irq = -ENXIO;
275         cdata->irq = irq;
276
277         ret = tps65090_config_charger(cdata);
278         if (ret < 0) {
279                 dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
280                 goto fail_unregister_supply;
281         }
282
283         /* Check for charger presence */
284         ret = tps65090_read(cdata->dev->parent, TPS65090_REG_CG_STATUS1,
285                         &status1);
286         if (ret < 0) {
287                 dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__,
288                         TPS65090_REG_CG_STATUS1);
289                 goto fail_unregister_supply;
290         }
291
292         if (status1 != 0) {
293                 ret = tps65090_enable_charging(cdata);
294                 if (ret < 0) {
295                         dev_err(cdata->dev, "error enabling charger\n");
296                         goto fail_unregister_supply;
297                 }
298                 cdata->ac_online = 1;
299                 power_supply_changed(cdata->ac);
300         }
301
302         if (irq != -ENXIO) {
303                 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
304                         tps65090_charger_isr, 0, "tps65090-charger", cdata);
305                 if (ret) {
306                         dev_err(cdata->dev,
307                                 "Unable to register irq %d err %d\n", irq,
308                                 ret);
309                         goto fail_unregister_supply;
310                 }
311         } else {
312                 cdata->poll_task = kthread_run(tps65090_charger_poll_task,
313                                               cdata, "ktps65090charger");
314                 cdata->passive_mode = true;
315                 if (IS_ERR(cdata->poll_task)) {
316                         ret = PTR_ERR(cdata->poll_task);
317                         dev_err(cdata->dev,
318                                 "Unable to run kthread err %d\n", ret);
319                         goto fail_unregister_supply;
320                 }
321         }
322
323         return 0;
324
325 fail_unregister_supply:
326         power_supply_unregister(cdata->ac);
327
328         return ret;
329 }
330
331 static int tps65090_charger_remove(struct platform_device *pdev)
332 {
333         struct tps65090_charger *cdata = platform_get_drvdata(pdev);
334
335         if (cdata->irq == -ENXIO)
336                 kthread_stop(cdata->poll_task);
337         power_supply_unregister(cdata->ac);
338
339         return 0;
340 }
341
342 static const struct of_device_id of_tps65090_charger_match[] = {
343         { .compatible = "ti,tps65090-charger", },
344         { /* end */ }
345 };
346 MODULE_DEVICE_TABLE(of, of_tps65090_charger_match);
347
348 static struct platform_driver tps65090_charger_driver = {
349         .driver = {
350                 .name   = "tps65090-charger",
351                 .of_match_table = of_tps65090_charger_match,
352         },
353         .probe  = tps65090_charger_probe,
354         .remove = tps65090_charger_remove,
355 };
356 module_platform_driver(tps65090_charger_driver);
357
358 MODULE_LICENSE("GPL v2");
359 MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>");
360 MODULE_DESCRIPTION("tps65090 battery charger driver");