From 86488cb49e66950ebb515cd2988d69c56bab705b Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Fri, 10 Apr 2015 22:24:46 +0900 Subject: power: max77843_charger: update to support OTG VBUS control This patch adds OTG VBUS control function via extcon framwork. If OTG accessories attached to MUIC(Micro USB Inter), current direction should change to reverse(Battary -> USB VBUS). Signed-off-by: Jaewon Kim --- drivers/power/max77843_charger.c | 70 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c index 392eebc1ae84..3ec08f984620 100644 --- a/drivers/power/max77843_charger.c +++ b/drivers/power/max77843_charger.c @@ -9,6 +9,7 @@ * published bythe Free Software Foundation. */ +#include #include #include #include @@ -26,8 +27,12 @@ struct max77843_charger { struct i2c_client *client; struct regmap *regmap; struct power_supply psy; - + struct extcon_dev *edev; + struct work_struct work; + struct notifier_block otg_nb; + struct extcon_specific_cable_nb otg_cable_nb; struct max77843_charger_info *info; + int extcon_state; }; static int max77843_charger_get_max_current(struct max77843_charger *charger) @@ -438,6 +443,64 @@ static struct max77843_charger_info *max77843_charger_dt_init( return info; } +static void max77843_charger_otg_worker(struct work_struct *work) +{ + struct max77843_charger *charger = + container_of(work, struct max77843_charger, work); + + if (charger->extcon_state) { + /* OTG Cable attached */ + regmap_update_bits(charger->regmap, + MAX77843_CHG_REG_CHG_CNFG_00, + MAX77843_CHG_MODE_MASK, + MAX77843_CHG_OTG_MASK | MAX77843_CHG_BOOST_MASK); + } else { + /* OTG Cable detached */ + regmap_update_bits(charger->regmap, + MAX77843_CHG_REG_CHG_CNFG_00, + MAX77843_CHG_MODE_MASK, + MAX77843_CHG_ENABLE | MAX77843_CHG_BUCK_MASK); + } +} + +static int max77843_charger_otg_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct max77843_charger *charger = container_of(nb, + struct max77843_charger, otg_nb); + + charger->extcon_state = event; + schedule_work(&charger->work); + + return 0; +} + +static int max77843_extcon_register(struct max77843_charger *charger) +{ + struct device_node *np = charger->dev->of_node; + struct extcon_dev *edev; + int ret; + + if (of_property_read_bool(np, "extcon")) { + charger->otg_nb.notifier_call = max77843_charger_otg_notifier; + + edev = extcon_get_edev_by_phandle(charger->dev, 0); + if (IS_ERR(charger->edev)) { + dev_dbg(charger->dev, "Cannot get extcon device\n"); + return -EPROBE_DEFER; + } + + ret = extcon_register_interest(&charger->otg_cable_nb, + edev->name, "USB-HOST", &charger->otg_nb); + if (ret < 0) { + dev_err(charger->dev, "Cannot register OTG notifier\n"); + return ret; + } + } + + return 0; +} + static int max77843_charger_probe(struct platform_device *pdev) { struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); @@ -453,6 +516,11 @@ static int max77843_charger_probe(struct platform_device *pdev) charger->max77843 = max77843; charger->client = max77843->i2c_chg; charger->regmap = max77843->regmap_chg; + INIT_WORK(&charger->work, max77843_charger_otg_worker); + + ret = max77843_extcon_register(charger); + if (ret) + return ret; charger->info = max77843_charger_dt_init(pdev); if (IS_ERR_OR_NULL(charger->info)) -- cgit v1.2.3