diff options
author | Wenyou Yang <wenyou.yang@atmel.com> | 2016-09-01 05:29:58 -0400 |
---|---|---|
committer | Sebastian Reichel <sre@kernel.org> | 2016-09-01 07:55:52 -0400 |
commit | 369eba0986d503302784f55f1020129bf802ae72 (patch) | |
tree | 9da101098e5129296d70e5fdc051b928c46e246b | |
parent | 30953650801a8c83fc96acdc032e0a0dbb018b07 (diff) |
power: supply: act8945a_charger: Add capacity level property
Add the power supply capacity level property, it corresponds to
POWER_SUPPLY_CAPACITY_LEVEL_*.
It also utilizes the precision voltage detector function module
to catch the low battery voltage.
Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
-rw-r--r-- | drivers/power/supply/act8945a_charger.c | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 48775f8233f3..2f875997d97a 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/power_supply.h> | 19 | #include <linux/power_supply.h> |
20 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
21 | #include <linux/gpio/consumer.h> | ||
21 | 22 | ||
22 | static const char *act8945a_charger_model = "ACT8945A"; | 23 | static const char *act8945a_charger_model = "ACT8945A"; |
23 | static const char *act8945a_charger_manufacturer = "Active-semi"; | 24 | static const char *act8945a_charger_manufacturer = "Active-semi"; |
@@ -83,6 +84,7 @@ struct act8945a_charger { | |||
83 | struct work_struct work; | 84 | struct work_struct work; |
84 | 85 | ||
85 | bool init_done; | 86 | bool init_done; |
87 | struct gpio_desc *lbo_gpio; | ||
86 | }; | 88 | }; |
87 | 89 | ||
88 | static int act8945a_get_charger_state(struct regmap *regmap, int *val) | 90 | static int act8945a_get_charger_state(struct regmap *regmap, int *val) |
@@ -208,11 +210,67 @@ static int act8945a_get_battery_health(struct regmap *regmap, int *val) | |||
208 | return 0; | 210 | return 0; |
209 | } | 211 | } |
210 | 212 | ||
213 | static int act8945a_get_capacity_level(struct act8945a_charger *charger, | ||
214 | struct regmap *regmap, int *val) | ||
215 | { | ||
216 | int ret; | ||
217 | unsigned int status, state, config; | ||
218 | int lbo_level = gpiod_get_value(charger->lbo_gpio); | ||
219 | |||
220 | ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); | ||
221 | if (ret < 0) | ||
222 | return ret; | ||
223 | |||
224 | ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config); | ||
225 | if (ret < 0) | ||
226 | return ret; | ||
227 | |||
228 | ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); | ||
229 | if (ret < 0) | ||
230 | return ret; | ||
231 | |||
232 | state &= APCH_STATE_CSTATE; | ||
233 | state >>= APCH_STATE_CSTATE_SHIFT; | ||
234 | |||
235 | switch (state) { | ||
236 | case APCH_STATE_CSTATE_PRE: | ||
237 | *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
238 | break; | ||
239 | case APCH_STATE_CSTATE_FAST: | ||
240 | if (lbo_level) | ||
241 | *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; | ||
242 | else | ||
243 | *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW; | ||
244 | break; | ||
245 | case APCH_STATE_CSTATE_EOC: | ||
246 | if (status & APCH_STATUS_CHGDAT) | ||
247 | *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL; | ||
248 | else | ||
249 | *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
250 | break; | ||
251 | case APCH_STATE_CSTATE_DISABLED: | ||
252 | default: | ||
253 | if (config & APCH_CFG_SUSCHG) { | ||
254 | *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; | ||
255 | } else { | ||
256 | *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | ||
257 | if (!(status & APCH_STATUS_INDAT)) { | ||
258 | if (!lbo_level) | ||
259 | *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; | ||
260 | } | ||
261 | } | ||
262 | break; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
211 | static enum power_supply_property act8945a_charger_props[] = { | 268 | static enum power_supply_property act8945a_charger_props[] = { |
212 | POWER_SUPPLY_PROP_STATUS, | 269 | POWER_SUPPLY_PROP_STATUS, |
213 | POWER_SUPPLY_PROP_CHARGE_TYPE, | 270 | POWER_SUPPLY_PROP_CHARGE_TYPE, |
214 | POWER_SUPPLY_PROP_TECHNOLOGY, | 271 | POWER_SUPPLY_PROP_TECHNOLOGY, |
215 | POWER_SUPPLY_PROP_HEALTH, | 272 | POWER_SUPPLY_PROP_HEALTH, |
273 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | ||
216 | POWER_SUPPLY_PROP_MODEL_NAME, | 274 | POWER_SUPPLY_PROP_MODEL_NAME, |
217 | POWER_SUPPLY_PROP_MANUFACTURER | 275 | POWER_SUPPLY_PROP_MANUFACTURER |
218 | }; | 276 | }; |
@@ -238,6 +296,10 @@ static int act8945a_charger_get_property(struct power_supply *psy, | |||
238 | case POWER_SUPPLY_PROP_HEALTH: | 296 | case POWER_SUPPLY_PROP_HEALTH: |
239 | ret = act8945a_get_battery_health(regmap, &val->intval); | 297 | ret = act8945a_get_battery_health(regmap, &val->intval); |
240 | break; | 298 | break; |
299 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | ||
300 | ret = act8945a_get_capacity_level(charger, | ||
301 | regmap, &val->intval); | ||
302 | break; | ||
241 | case POWER_SUPPLY_PROP_MODEL_NAME: | 303 | case POWER_SUPPLY_PROP_MODEL_NAME: |
242 | val->strval = act8945a_charger_model; | 304 | val->strval = act8945a_charger_model; |
243 | break; | 305 | break; |
@@ -335,7 +397,7 @@ static int act8945a_charger_config(struct device *dev, | |||
335 | u32 pre_time_out; | 397 | u32 pre_time_out; |
336 | u32 input_voltage_threshold; | 398 | u32 input_voltage_threshold; |
337 | int chglev_pin; | 399 | int chglev_pin; |
338 | int ret; | 400 | int err, ret; |
339 | 401 | ||
340 | unsigned int tmp; | 402 | unsigned int tmp; |
341 | unsigned int value = 0; | 403 | unsigned int value = 0; |
@@ -354,6 +416,21 @@ static int act8945a_charger_config(struct device *dev, | |||
354 | dev_info(dev, "have been suspended\n"); | 416 | dev_info(dev, "have been suspended\n"); |
355 | } | 417 | } |
356 | 418 | ||
419 | charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo", | ||
420 | GPIOD_IN); | ||
421 | if (IS_ERR(charger->lbo_gpio)) { | ||
422 | err = PTR_ERR(charger->lbo_gpio); | ||
423 | dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err); | ||
424 | return err; | ||
425 | } | ||
426 | |||
427 | ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio), | ||
428 | act8945a_status_changed, | ||
429 | (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), | ||
430 | "act8945a_lbo_detect", charger); | ||
431 | if (ret) | ||
432 | dev_info(dev, "failed to request gpio \"lbo\" IRQ\n"); | ||
433 | |||
357 | chglev_pin = of_get_named_gpio_flags(np, | 434 | chglev_pin = of_get_named_gpio_flags(np, |
358 | "active-semi,chglev-gpios", 0, &flags); | 435 | "active-semi,chglev-gpios", 0, &flags); |
359 | 436 | ||