aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWenyou Yang <wenyou.yang@atmel.com>2016-09-01 05:29:58 -0400
committerSebastian Reichel <sre@kernel.org>2016-09-01 07:55:52 -0400
commit369eba0986d503302784f55f1020129bf802ae72 (patch)
tree9da101098e5129296d70e5fdc051b928c46e246b
parent30953650801a8c83fc96acdc032e0a0dbb018b07 (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.c79
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
22static const char *act8945a_charger_model = "ACT8945A"; 23static const char *act8945a_charger_model = "ACT8945A";
23static const char *act8945a_charger_manufacturer = "Active-semi"; 24static 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
88static int act8945a_get_charger_state(struct regmap *regmap, int *val) 90static 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
213static 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
211static enum power_supply_property act8945a_charger_props[] = { 268static 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