Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[cascardo/linux.git] / drivers / power / act8945a_charger.c
1 /*
2  * Power supply driver for the Active-semi ACT8945A PMIC
3  *
4  * Copyright (C) 2015 Atmel Corporation
5  *
6  * Author: Wenyou Yang <wenyou.yang@atmel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  */
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/of_gpio.h>
16 #include <linux/platform_device.h>
17 #include <linux/power_supply.h>
18 #include <linux/regmap.h>
19
20 static const char *act8945a_charger_model = "ACT8945A";
21 static const char *act8945a_charger_manufacturer = "Active-semi";
22
23 /**
24  * ACT8945A Charger Register Map
25  */
26
27 /* 0x70: Reserved */
28 #define ACT8945A_APCH_CFG               0x71
29 #define ACT8945A_APCH_STATUS            0x78
30 #define ACT8945A_APCH_CTRL              0x79
31 #define ACT8945A_APCH_STATE             0x7A
32
33 /* ACT8945A_APCH_CFG */
34 #define APCH_CFG_OVPSET                 (0x3 << 0)
35 #define APCH_CFG_OVPSET_6V6             (0x0 << 0)
36 #define APCH_CFG_OVPSET_7V              (0x1 << 0)
37 #define APCH_CFG_OVPSET_7V5             (0x2 << 0)
38 #define APCH_CFG_OVPSET_8V              (0x3 << 0)
39 #define APCH_CFG_PRETIMO                (0x3 << 2)
40 #define APCH_CFG_PRETIMO_40_MIN         (0x0 << 2)
41 #define APCH_CFG_PRETIMO_60_MIN         (0x1 << 2)
42 #define APCH_CFG_PRETIMO_80_MIN         (0x2 << 2)
43 #define APCH_CFG_PRETIMO_DISABLED       (0x3 << 2)
44 #define APCH_CFG_TOTTIMO                (0x3 << 4)
45 #define APCH_CFG_TOTTIMO_3_HOUR         (0x0 << 4)
46 #define APCH_CFG_TOTTIMO_4_HOUR         (0x1 << 4)
47 #define APCH_CFG_TOTTIMO_5_HOUR         (0x2 << 4)
48 #define APCH_CFG_TOTTIMO_DISABLED       (0x3 << 4)
49 #define APCH_CFG_SUSCHG                 (0x1 << 7)
50
51 #define APCH_STATUS_CHGDAT              BIT(0)
52 #define APCH_STATUS_INDAT               BIT(1)
53 #define APCH_STATUS_TEMPDAT             BIT(2)
54 #define APCH_STATUS_TIMRDAT             BIT(3)
55 #define APCH_STATUS_CHGSTAT             BIT(4)
56 #define APCH_STATUS_INSTAT              BIT(5)
57 #define APCH_STATUS_TEMPSTAT            BIT(6)
58 #define APCH_STATUS_TIMRSTAT            BIT(7)
59
60 #define APCH_CTRL_CHGEOCOUT             BIT(0)
61 #define APCH_CTRL_INDIS                 BIT(1)
62 #define APCH_CTRL_TEMPOUT               BIT(2)
63 #define APCH_CTRL_TIMRPRE               BIT(3)
64 #define APCH_CTRL_CHGEOCIN              BIT(4)
65 #define APCH_CTRL_INCON                 BIT(5)
66 #define APCH_CTRL_TEMPIN                BIT(6)
67 #define APCH_CTRL_TIMRTOT               BIT(7)
68
69 #define APCH_STATE_ACINSTAT             (0x1 << 1)
70 #define APCH_STATE_CSTATE               (0x3 << 4)
71 #define APCH_STATE_CSTATE_SHIFT         4
72 #define APCH_STATE_CSTATE_DISABLED      0x00
73 #define APCH_STATE_CSTATE_EOC           0x01
74 #define APCH_STATE_CSTATE_FAST          0x02
75 #define APCH_STATE_CSTATE_PRE           0x03
76
77 struct act8945a_charger {
78         struct regmap *regmap;
79         bool battery_temperature;
80 };
81
82 static int act8945a_get_charger_state(struct regmap *regmap, int *val)
83 {
84         int ret;
85         unsigned int status, state;
86
87         ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
88         if (ret < 0)
89                 return ret;
90
91         ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
92         if (ret < 0)
93                 return ret;
94
95         state &= APCH_STATE_CSTATE;
96         state >>= APCH_STATE_CSTATE_SHIFT;
97
98         if (state == APCH_STATE_CSTATE_EOC) {
99                 if (status & APCH_STATUS_CHGDAT)
100                         *val = POWER_SUPPLY_STATUS_FULL;
101                 else
102                         *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
103         } else if ((state == APCH_STATE_CSTATE_FAST) ||
104                    (state == APCH_STATE_CSTATE_PRE)) {
105                 *val = POWER_SUPPLY_STATUS_CHARGING;
106         } else {
107                 *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
108         }
109
110         return 0;
111 }
112
113 static int act8945a_get_charge_type(struct regmap *regmap, int *val)
114 {
115         int ret;
116         unsigned int state;
117
118         ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
119         if (ret < 0)
120                 return ret;
121
122         state &= APCH_STATE_CSTATE;
123         state >>= APCH_STATE_CSTATE_SHIFT;
124
125         switch (state) {
126         case APCH_STATE_CSTATE_PRE:
127                 *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
128                 break;
129         case APCH_STATE_CSTATE_FAST:
130                 *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
131                 break;
132         case APCH_STATE_CSTATE_EOC:
133         case APCH_STATE_CSTATE_DISABLED:
134         default:
135                 *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
136         }
137
138         return 0;
139 }
140
141 static int act8945a_get_battery_health(struct act8945a_charger *charger,
142                                        struct regmap *regmap, int *val)
143 {
144         int ret;
145         unsigned int status;
146
147         ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
148         if (ret < 0)
149                 return ret;
150
151         if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT))
152                 *val = POWER_SUPPLY_HEALTH_OVERHEAT;
153         else if (!(status & APCH_STATUS_INDAT))
154                 *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
155         else if (status & APCH_STATUS_TIMRDAT)
156                 *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
157         else
158                 *val = POWER_SUPPLY_HEALTH_GOOD;
159
160         return 0;
161 }
162
163 static enum power_supply_property act8945a_charger_props[] = {
164         POWER_SUPPLY_PROP_STATUS,
165         POWER_SUPPLY_PROP_CHARGE_TYPE,
166         POWER_SUPPLY_PROP_TECHNOLOGY,
167         POWER_SUPPLY_PROP_HEALTH,
168         POWER_SUPPLY_PROP_MODEL_NAME,
169         POWER_SUPPLY_PROP_MANUFACTURER
170 };
171
172 static int act8945a_charger_get_property(struct power_supply *psy,
173                                          enum power_supply_property prop,
174                                          union power_supply_propval *val)
175 {
176         struct act8945a_charger *charger = power_supply_get_drvdata(psy);
177         struct regmap *regmap = charger->regmap;
178         int ret = 0;
179
180         switch (prop) {
181         case POWER_SUPPLY_PROP_STATUS:
182                 ret = act8945a_get_charger_state(regmap, &val->intval);
183                 break;
184         case POWER_SUPPLY_PROP_CHARGE_TYPE:
185                 ret = act8945a_get_charge_type(regmap, &val->intval);
186                 break;
187         case POWER_SUPPLY_PROP_TECHNOLOGY:
188                 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
189                 break;
190         case POWER_SUPPLY_PROP_HEALTH:
191                 ret = act8945a_get_battery_health(charger,
192                                                   regmap, &val->intval);
193                 break;
194         case POWER_SUPPLY_PROP_MODEL_NAME:
195                 val->strval = act8945a_charger_model;
196                 break;
197         case POWER_SUPPLY_PROP_MANUFACTURER:
198                 val->strval = act8945a_charger_manufacturer;
199                 break;
200         default:
201                 return -EINVAL;
202         }
203
204         return ret;
205 }
206
207 static const struct power_supply_desc act8945a_charger_desc = {
208         .name           = "act8945a-charger",
209         .type           = POWER_SUPPLY_TYPE_BATTERY,
210         .get_property   = act8945a_charger_get_property,
211         .properties     = act8945a_charger_props,
212         .num_properties = ARRAY_SIZE(act8945a_charger_props),
213 };
214
215 #define DEFAULT_TOTAL_TIME_OUT          3
216 #define DEFAULT_PRE_TIME_OUT            40
217 #define DEFAULT_INPUT_OVP_THRESHOLD     6600
218
219 static int act8945a_charger_config(struct device *dev,
220                                    struct act8945a_charger *charger)
221 {
222         struct device_node *np = dev->of_node;
223         enum of_gpio_flags flags;
224         struct regmap *regmap = charger->regmap;
225
226         u32 total_time_out;
227         u32 pre_time_out;
228         u32 input_voltage_threshold;
229         int chglev_pin;
230
231         unsigned int value = 0;
232
233         if (!np) {
234                 dev_err(dev, "no charger of node\n");
235                 return -EINVAL;
236         }
237
238         charger->battery_temperature = of_property_read_bool(np,
239                                 "active-semi,check-battery-temperature");
240
241         chglev_pin = of_get_named_gpio_flags(np,
242                                 "active-semi,chglev-gpios", 0, &flags);
243
244         if (gpio_is_valid(chglev_pin)) {
245                 gpio_set_value(chglev_pin,
246                                ((flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1));
247         }
248
249         if (of_property_read_u32(np,
250                                  "active-semi,input-voltage-threshold-microvolt",
251                                  &input_voltage_threshold))
252                 input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
253
254         if (of_property_read_u32(np,
255                                  "active-semi,precondition-timeout",
256                                  &pre_time_out))
257                 pre_time_out = DEFAULT_PRE_TIME_OUT;
258
259         if (of_property_read_u32(np, "active-semi,total-timeout",
260                                  &total_time_out))
261                 total_time_out = DEFAULT_TOTAL_TIME_OUT;
262
263         switch (input_voltage_threshold) {
264         case 8000:
265                 value |= APCH_CFG_OVPSET_8V;
266                 break;
267         case 7500:
268                 value |= APCH_CFG_OVPSET_7V5;
269                 break;
270         case 7000:
271                 value |= APCH_CFG_OVPSET_7V;
272                 break;
273         case 6600:
274         default:
275                 value |= APCH_CFG_OVPSET_6V6;
276                 break;
277         }
278
279         switch (pre_time_out) {
280         case 60:
281                 value |= APCH_CFG_PRETIMO_60_MIN;
282                 break;
283         case 80:
284                 value |= APCH_CFG_PRETIMO_80_MIN;
285                 break;
286         case 0:
287                 value |= APCH_CFG_PRETIMO_DISABLED;
288                 break;
289         case 40:
290         default:
291                 value |= APCH_CFG_PRETIMO_40_MIN;
292                 break;
293         }
294
295         switch (total_time_out) {
296         case 4:
297                 value |= APCH_CFG_TOTTIMO_4_HOUR;
298                 break;
299         case 5:
300                 value |= APCH_CFG_TOTTIMO_5_HOUR;
301                 break;
302         case 0:
303                 value |= APCH_CFG_TOTTIMO_DISABLED;
304                 break;
305         case 3:
306         default:
307                 value |= APCH_CFG_TOTTIMO_3_HOUR;
308                 break;
309         }
310
311         return regmap_write(regmap, ACT8945A_APCH_CFG, value);
312 }
313
314 static int act8945a_charger_probe(struct platform_device *pdev)
315 {
316         struct act8945a_charger *charger;
317         struct power_supply *psy;
318         struct power_supply_config psy_cfg = {};
319         int ret;
320
321         charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
322         if (!charger)
323                 return -ENOMEM;
324
325         charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
326         if (!charger->regmap) {
327                 dev_err(&pdev->dev, "Parent did not provide regmap\n");
328                 return -EINVAL;
329         }
330
331         ret = act8945a_charger_config(pdev->dev.parent, charger);
332         if (ret)
333                 return ret;
334
335         psy_cfg.of_node = pdev->dev.parent->of_node;
336         psy_cfg.drv_data = charger;
337
338         psy = devm_power_supply_register(&pdev->dev,
339                                          &act8945a_charger_desc,
340                                          &psy_cfg);
341         if (IS_ERR(psy)) {
342                 dev_err(&pdev->dev, "failed to register power supply\n");
343                 return PTR_ERR(psy);
344         }
345
346         return 0;
347 }
348
349 static struct platform_driver act8945a_charger_driver = {
350         .driver = {
351                 .name = "act8945a-charger",
352         },
353         .probe  = act8945a_charger_probe,
354 };
355 module_platform_driver(act8945a_charger_driver);
356
357 MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
358 MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
359 MODULE_LICENSE("GPL");