aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorWenyou Yang <wenyou.yang@atmel.com>2016-08-25 03:19:53 -0400
committerSebastian Reichel <sre@kernel.org>2016-08-31 10:46:57 -0400
commita09209acd6a808794bdd7866af3678d1fd1d90e7 (patch)
tree1644d3d2ba406ec0f1e61b63125f166ace810826 /drivers/power
parent1f0ba4067af4bda55b7304e74fc20a245912b728 (diff)
power: supply: act8945a_charger: Add status change update support
Add the charger status change interrupt support, it will report the power supply changed event. This interrupt is generated by one of the conditions as below: - the state machine jumps out of or into the EOC state - the CHGIN input voltage goes out of or into the valid range. - the battery temperature goes out of or into the valid range. - the PRECHARGE time-out occurs. - the total charge time-out occurs. Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> Signed-off-by: Sebastian Reichel <sre@kernel.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/act8945a_charger.c95
1 files changed, 88 insertions, 7 deletions
diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c
index a6bbaff5483e..e129255c1e0d 100644
--- a/drivers/power/supply/act8945a_charger.c
+++ b/drivers/power/supply/act8945a_charger.c
@@ -10,9 +10,11 @@
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 * 11 *
12 */ 12 */
13#include <linux/interrupt.h>
13#include <linux/module.h> 14#include <linux/module.h>
14#include <linux/of.h> 15#include <linux/of.h>
15#include <linux/of_gpio.h> 16#include <linux/of_gpio.h>
17#include <linux/of_irq.h>
16#include <linux/platform_device.h> 18#include <linux/platform_device.h>
17#include <linux/power_supply.h> 19#include <linux/power_supply.h>
18#include <linux/regmap.h> 20#include <linux/regmap.h>
@@ -75,7 +77,11 @@ static const char *act8945a_charger_manufacturer = "Active-semi";
75#define APCH_STATE_CSTATE_PRE 0x03 77#define APCH_STATE_CSTATE_PRE 0x03
76 78
77struct act8945a_charger { 79struct act8945a_charger {
80 struct power_supply *psy;
78 struct regmap *regmap; 81 struct regmap *regmap;
82 struct work_struct work;
83
84 bool init_done;
79}; 85};
80 86
81static int act8945a_get_charger_state(struct regmap *regmap, int *val) 87static int act8945a_get_charger_state(struct regmap *regmap, int *val)
@@ -252,6 +258,47 @@ static const struct power_supply_desc act8945a_charger_desc = {
252 .num_properties = ARRAY_SIZE(act8945a_charger_props), 258 .num_properties = ARRAY_SIZE(act8945a_charger_props),
253}; 259};
254 260
261static int act8945a_enable_interrupt(struct act8945a_charger *charger)
262{
263 struct regmap *regmap = charger->regmap;
264 unsigned char ctrl;
265 int ret;
266
267 ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN |
268 APCH_CTRL_INDIS | APCH_CTRL_INCON |
269 APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN |
270 APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT;
271 ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl);
272 if (ret)
273 return ret;
274
275 ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT |
276 APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT;
277 ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl);
278 if (ret)
279 return ret;
280
281 return 0;
282}
283
284static void act8945a_work(struct work_struct *work)
285{
286 struct act8945a_charger *charger =
287 container_of(work, struct act8945a_charger, work);
288
289 power_supply_changed(charger->psy);
290}
291
292static irqreturn_t act8945a_status_changed(int irq, void *dev_id)
293{
294 struct act8945a_charger *charger = dev_id;
295
296 if (charger->init_done)
297 schedule_work(&charger->work);
298
299 return IRQ_HANDLED;
300}
301
255#define DEFAULT_TOTAL_TIME_OUT 3 302#define DEFAULT_TOTAL_TIME_OUT 3
256#define DEFAULT_PRE_TIME_OUT 40 303#define DEFAULT_PRE_TIME_OUT 40
257#define DEFAULT_INPUT_OVP_THRESHOLD 6600 304#define DEFAULT_INPUT_OVP_THRESHOLD 6600
@@ -362,9 +409,8 @@ static int act8945a_charger_config(struct device *dev,
362static int act8945a_charger_probe(struct platform_device *pdev) 409static int act8945a_charger_probe(struct platform_device *pdev)
363{ 410{
364 struct act8945a_charger *charger; 411 struct act8945a_charger *charger;
365 struct power_supply *psy;
366 struct power_supply_config psy_cfg = {}; 412 struct power_supply_config psy_cfg = {};
367 int ret; 413 int irq, ret;
368 414
369 charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 415 charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
370 if (!charger) 416 if (!charger)
@@ -380,17 +426,51 @@ static int act8945a_charger_probe(struct platform_device *pdev)
380 if (ret) 426 if (ret)
381 return ret; 427 return ret;
382 428
429 irq = of_irq_get(pdev->dev.of_node, 0);
430 if (irq == -EPROBE_DEFER) {
431 dev_err(&pdev->dev, "failed to find IRQ number\n");
432 return -EPROBE_DEFER;
433 }
434
435 ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
436 IRQF_TRIGGER_FALLING, "act8945a_interrupt",
437 charger);
438 if (ret) {
439 dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
440 return ret;
441 }
442
383 psy_cfg.of_node = pdev->dev.of_node; 443 psy_cfg.of_node = pdev->dev.of_node;
384 psy_cfg.drv_data = charger; 444 psy_cfg.drv_data = charger;
385 445
386 psy = devm_power_supply_register(&pdev->dev, 446 charger->psy = devm_power_supply_register(&pdev->dev,
387 &act8945a_charger_desc, 447 &act8945a_charger_desc,
388 &psy_cfg); 448 &psy_cfg);
389 if (IS_ERR(psy)) { 449 if (IS_ERR(charger->psy)) {
390 dev_err(&pdev->dev, "failed to register power supply\n"); 450 dev_err(&pdev->dev, "failed to register power supply\n");
391 return PTR_ERR(psy); 451 return PTR_ERR(charger->psy);
392 } 452 }
393 453
454 platform_set_drvdata(pdev, charger);
455
456 INIT_WORK(&charger->work, act8945a_work);
457
458 ret = act8945a_enable_interrupt(charger);
459 if (ret)
460 return -EIO;
461
462 charger->init_done = true;
463
464 return 0;
465}
466
467static int act8945a_charger_remove(struct platform_device *pdev)
468{
469 struct act8945a_charger *charger = platform_get_drvdata(pdev);
470
471 charger->init_done = false;
472 cancel_work_sync(&charger->work);
473
394 return 0; 474 return 0;
395} 475}
396 476
@@ -399,6 +479,7 @@ static struct platform_driver act8945a_charger_driver = {
399 .name = "act8945a-charger", 479 .name = "act8945a-charger",
400 }, 480 },
401 .probe = act8945a_charger_probe, 481 .probe = act8945a_charger_probe,
482 .remove = act8945a_charger_remove,
402}; 483};
403module_platform_driver(act8945a_charger_driver); 484module_platform_driver(act8945a_charger_driver);
404 485