summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorJaewon Kim <jaewon02.kim@samsung.com>2015-04-10 22:24:46 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:42:51 +0900
commit86488cb49e66950ebb515cd2988d69c56bab705b (patch)
treea294b107247b0c28b1a971baf85d2414773dbfbc /drivers/power
parent8dfd364aa3c763968c36241ef50c06b8fcfb41b4 (diff)
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 <jaewon02.kim@samsung.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/max77843_charger.c70
1 files changed, 69 insertions, 1 deletions
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 <linux/extcon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
@@ -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))