diff mbox series

[v6,06/10,RESEND] power: supply: rt5033_charger: Add cable detection and USB OTG supply

Message ID 223b440ab6831f2e7302d2c49b2cfd7779d5effd.1684182964.git.jahau@rocketmail.com
State Superseded
Headers show
Series [v6,01/10,RESEND] mfd: rt5033: Drop rt5033-battery sub-device | expand

Commit Message

Jakob Hauser May 15, 2023, 8:57 p.m. UTC
Implement cable detection by extcon and handle the driver according to the
connector type.

There are basically three types of action: "set_charging", "set_otg" and
"set_disconnect".

A forth helper function to "unset_otg" was added because this is used in both
"set_charging" and "set_disconnect". In the first case it covers the rather
rare event that someone changes from OTG to charging without disconnect. In
the second case, when disconnecting, the values are set back to the ones from
initialization to return into a defined state.

Additionally, there is "set_mivr". When connecting to e.g. a laptop/PC, the
minimum input voltage regulation (MIVR) shall prevent a voltage drop if the
cable or the supply is weak. The MIVR value is set to 4600MV, same as in the
Android driver [1]. When disconnecting, MIVR is set back to DISABLED.

In the function rt5033_get_charger_state(): When in OTG mode, the chip
reports status "charging". Change this to "discharging" because there is
no charging going on in OTG mode [2].

[1] https://github.com/msm8916-mainline/linux-downstream/blob/GT-I9195I/drivers/battery/rt5033_charger.c#L499
[2] https://github.com/msm8916-mainline/linux-downstream/blob/GT-I9195I/drivers/battery/rt5033_charger.c#L686-L687

Tested-by: Raymond Hackley <raymondhackley@protonmail.com>
Signed-off-by: Jakob Hauser <jahau@rocketmail.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
---
 drivers/power/supply/rt5033_charger.c | 276 +++++++++++++++++++++++++-
 1 file changed, 274 insertions(+), 2 deletions(-)

Comments

Lee Jones Aug. 17, 2023, 9:38 a.m. UTC | #1
On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
> Implement cable detection by extcon and handle the driver according to the
> connector type.
> 
> There are basically three types of action: "set_charging", "set_otg" and
> "set_disconnect".
> 
> A forth helper function to "unset_otg" was added because this is used in both
> "set_charging" and "set_disconnect". In the first case it covers the rather
> rare event that someone changes from OTG to charging without disconnect. In
> the second case, when disconnecting, the values are set back to the ones from
> initialization to return into a defined state.
> 
> [...]

Applied, thanks!

[06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
        commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810

--
Lee Jones [李琼斯]
Lee Jones Aug. 22, 2023, 7:07 a.m. UTC | #2
On Thu, 17 Aug 2023, Lee Jones wrote:

> On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
> > Implement cable detection by extcon and handle the driver according to the
> > connector type.
> > 
> > There are basically three types of action: "set_charging", "set_otg" and
> > "set_disconnect".
> > 
> > A forth helper function to "unset_otg" was added because this is used in both
> > "set_charging" and "set_disconnect". In the first case it covers the rather
> > rare event that someone changes from OTG to charging without disconnect. In
> > the second case, when disconnecting, the values are set back to the ones from
> > initialization to return into a defined state.
> > 
> > [...]
> 
> Applied, thanks!
> 
> [06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
>         commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810

Multiple fixes now follow this patch, so I am unapplying it.

Sebastian, would you mind collecting it up please?
Sebastian Reichel Aug. 22, 2023, 9:29 p.m. UTC | #3
Hi,

On Tue, Aug 22, 2023 at 08:07:37AM +0100, Lee Jones wrote:
> On Thu, 17 Aug 2023, Lee Jones wrote:
> 
> > On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
> > > Implement cable detection by extcon and handle the driver according to the
> > > connector type.
> > > 
> > > There are basically three types of action: "set_charging", "set_otg" and
> > > "set_disconnect".
> > > 
> > > A forth helper function to "unset_otg" was added because this is used in both
> > > "set_charging" and "set_disconnect". In the first case it covers the rather
> > > rare event that someone changes from OTG to charging without disconnect. In
> > > the second case, when disconnecting, the values are set back to the ones from
> > > initialization to return into a defined state.
> > > 
> > > [...]
> > 
> > Applied, thanks!
> > 
> > [06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
> >         commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810
> 
> Multiple fixes now follow this patch, so I am unapplying it.
> 
> Sebastian, would you mind collecting it up please?

I'm leaving for a two week hiking trip (with basically no internet
access) in some hours. My planed return date is basically when Linus
is expected to tag 6.6-rc1, so I will not queue any more patches and
send my pull request early (within the next few hours).

I planned to catch up with the power-supply backlog last week during
Chaos Communication Camp, but it was too hot to do any sensible
review. Now I expect to process the power-supply backlog in the
week after the merge window.

Greetings and sorry for the inconvenience,

-- Sebastian
Jakob Hauser Sept. 3, 2023, 12:43 p.m. UTC | #4
Hi Sebastian,

On 22.08.23 23:29, Sebastian Reichel wrote:
> Hi,
> 
> On Tue, Aug 22, 2023 at 08:07:37AM +0100, Lee Jones wrote:
>> On Thu, 17 Aug 2023, Lee Jones wrote:
>>
>>> On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
>>>> Implement cable detection by extcon and handle the driver according to the
>>>> connector type.
>>>>
>>>> There are basically three types of action: "set_charging", "set_otg" and
>>>> "set_disconnect".
>>>>
>>>> A forth helper function to "unset_otg" was added because this is used in both
>>>> "set_charging" and "set_disconnect". In the first case it covers the rather
>>>> rare event that someone changes from OTG to charging without disconnect. In
>>>> the second case, when disconnecting, the values are set back to the ones from
>>>> initialization to return into a defined state.
>>>>
>>>> [...]
>>>
>>> Applied, thanks!
>>>
>>> [06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
>>>          commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810
>>
>> Multiple fixes now follow this patch, so I am unapplying it.
>>
>> Sebastian, would you mind collecting it up please?
> 
> I'm leaving for a two week hiking trip (with basically no internet
> access) in some hours. My planed return date is basically when Linus
> is expected to tag 6.6-rc1, so I will not queue any more patches and
> send my pull request early (within the next few hours).
> 
> I planned to catch up with the power-supply backlog last week during
> Chaos Communication Camp, but it was too hot to do any sensible
> review. Now I expect to process the power-supply backlog in the
> week after the merge window.

The patch 6 of the rt5033-charger series v6 gathered some issues. For 
all of them a solution was provided. Thanks to everyone involved! 
However, I don't know what's the best way to put them together.

- As the patch 6 was forgotten to apply with the others of the
   patchset, in the meantime another small patch by Rob sneaked in. The
   patch 6 needs to be rebased on Rob's patch. It affects the includes.
   Would be nice to order them alphabetically after rebase.

- After patch 6 was added on top of Rob's patch in linux-next, there
   was a build failure. This is because "linux/of.h" now explicitly
   needs to be added to the rt5033-charger driver. Stephen Rothwell
   provided a fix. I'm not sure on the order: Maybe that needs to be
   added before adding patch 6 to avoid the build failure when the
   kernel test bot checks each commit separately.
 
https://lore.kernel.org/linux-next/20230821125741.3a2474d7@canb.auug.org.au/T/#u

- Beyond that, the kernel test bot also complained about undefined
   reference related to extcon. I didn't understand why this happens
   because the driver has "linux/extcon.h" included. Randy was attentive
   and provided a fix. Here again I'm not sure about the order, I guess
   this should be added before adding patch 6 to avoid build failures if
   each commit is tested separately.
   Kernel test bot complaints:
     x86_64 clang 
https://lore.kernel.org/oe-kbuild-all/202308220324.LsI8q3ML-lkp@intel.com/T/#u
     x86_64 gcc 
https://lore.kernel.org/oe-kbuild-all/202308240723.O2rW0InU-lkp@intel.com/T/#u
     arm gcc 
https://lore.kernel.org/oe-kbuild-all/202308250617.ue4uQxWa-lkp@intel.com/T/#u
   Fix by Randy:
 
https://lore.kernel.org/linux-pm/20230828224201.26823-1-rdunlap@infradead.org/T/#u

- Yang noticed that the mutex_unlock() is not handled correctly in
   some error path and provided a fix:
 
https://lore.kernel.org/linux-pm/20230822030207.644738-1-yangyingliang@huawei.com/T/#u

- There are two clean-up patches by me. They need to be rebased to the
   patches mentioned above but there shouldn't be conflicts with them.
 
https://lore.kernel.org/linux-pm/cover.1686948074.git.jahau@rocketmail.com/T/#u

Please also note that the commit hash in the linked fixes above refers 
to linux-next, where the patch 6 had been applied. As the patch was 
dropped later on, I don't know what this means for the commit hashes in 
the fixes.

What's the best way to proceed? Can you put these patches together? Or 
do you want me something to do?

Kind regards,
Jakob
Lee Jones Sept. 4, 2023, 2:27 p.m. UTC | #5
On Sun, 03 Sep 2023, Jakob Hauser wrote:

> Hi Sebastian,
> 
> On 22.08.23 23:29, Sebastian Reichel wrote:
> > Hi,
> > 
> > On Tue, Aug 22, 2023 at 08:07:37AM +0100, Lee Jones wrote:
> > > On Thu, 17 Aug 2023, Lee Jones wrote:
> > > 
> > > > On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
> > > > > Implement cable detection by extcon and handle the driver according to the
> > > > > connector type.
> > > > > 
> > > > > There are basically three types of action: "set_charging", "set_otg" and
> > > > > "set_disconnect".
> > > > > 
> > > > > A forth helper function to "unset_otg" was added because this is used in both
> > > > > "set_charging" and "set_disconnect". In the first case it covers the rather
> > > > > rare event that someone changes from OTG to charging without disconnect. In
> > > > > the second case, when disconnecting, the values are set back to the ones from
> > > > > initialization to return into a defined state.
> > > > > 
> > > > > [...]
> > > > 
> > > > Applied, thanks!
> > > > 
> > > > [06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
> > > >          commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810
> > > 
> > > Multiple fixes now follow this patch, so I am unapplying it.
> > > 
> > > Sebastian, would you mind collecting it up please?
> > 
> > I'm leaving for a two week hiking trip (with basically no internet
> > access) in some hours. My planed return date is basically when Linus
> > is expected to tag 6.6-rc1, so I will not queue any more patches and
> > send my pull request early (within the next few hours).
> > 
> > I planned to catch up with the power-supply backlog last week during
> > Chaos Communication Camp, but it was too hot to do any sensible
> > review. Now I expect to process the power-supply backlog in the
> > week after the merge window.
> 
> The patch 6 of the rt5033-charger series v6 gathered some issues. For all of
> them a solution was provided. Thanks to everyone involved! However, I don't
> know what's the best way to put them together.
> 
> - As the patch 6 was forgotten to apply with the others of the
>   patchset, in the meantime another small patch by Rob sneaked in. The
>   patch 6 needs to be rebased on Rob's patch. It affects the includes.
>   Would be nice to order them alphabetically after rebase.
> 
> - After patch 6 was added on top of Rob's patch in linux-next, there
>   was a build failure. This is because "linux/of.h" now explicitly
>   needs to be added to the rt5033-charger driver. Stephen Rothwell
>   provided a fix. I'm not sure on the order: Maybe that needs to be
>   added before adding patch 6 to avoid the build failure when the
>   kernel test bot checks each commit separately.
> 
> https://lore.kernel.org/linux-next/20230821125741.3a2474d7@canb.auug.org.au/T/#u
> 
> - Beyond that, the kernel test bot also complained about undefined
>   reference related to extcon. I didn't understand why this happens
>   because the driver has "linux/extcon.h" included. Randy was attentive
>   and provided a fix. Here again I'm not sure about the order, I guess
>   this should be added before adding patch 6 to avoid build failures if
>   each commit is tested separately.
>   Kernel test bot complaints:
>     x86_64 clang https://lore.kernel.org/oe-kbuild-all/202308220324.LsI8q3ML-lkp@intel.com/T/#u
>     x86_64 gcc https://lore.kernel.org/oe-kbuild-all/202308240723.O2rW0InU-lkp@intel.com/T/#u
>     arm gcc https://lore.kernel.org/oe-kbuild-all/202308250617.ue4uQxWa-lkp@intel.com/T/#u
>   Fix by Randy:
> 
> https://lore.kernel.org/linux-pm/20230828224201.26823-1-rdunlap@infradead.org/T/#u
> 
> - Yang noticed that the mutex_unlock() is not handled correctly in
>   some error path and provided a fix:
> 
> https://lore.kernel.org/linux-pm/20230822030207.644738-1-yangyingliang@huawei.com/T/#u
> 
> - There are two clean-up patches by me. They need to be rebased to the
>   patches mentioned above but there shouldn't be conflicts with them.
> 
> https://lore.kernel.org/linux-pm/cover.1686948074.git.jahau@rocketmail.com/T/#u
> 
> Please also note that the commit hash in the linked fixes above refers to
> linux-next, where the patch 6 had been applied. As the patch was dropped
> later on, I don't know what this means for the commit hashes in the fixes.
> 
> What's the best way to proceed? Can you put these patches together? Or do
> you want me something to do?

You need to do this yourself.

Rebase all of the fixes on top of v6.6-rc1 (which will be released in a
little under a week).  Ensure that each patch builds as it's applied so
as not to harm bisecability.  If you have to squash them to prevent
built-breakages, then so be it, but don't forget to credit the
contributors.  Once complete, post as a set and we'll take it from
there.
Sebastian Reichel Sept. 14, 2023, 3:33 p.m. UTC | #6
Hi Jakob,

On Mon, Sep 04, 2023 at 03:27:17PM +0100, Lee Jones wrote:
> On Sun, 03 Sep 2023, Jakob Hauser wrote:
> > Hi Sebastian,
> > On 22.08.23 23:29, Sebastian Reichel wrote:
> > > On Tue, Aug 22, 2023 at 08:07:37AM +0100, Lee Jones wrote:
> > > > On Thu, 17 Aug 2023, Lee Jones wrote:
> > > > 
> > > > > On Mon, 15 May 2023 22:57:15 +0200, Jakob Hauser wrote:
> > > > > > Implement cable detection by extcon and handle the driver according to the
> > > > > > connector type.
> > > > > > 
> > > > > > There are basically three types of action: "set_charging", "set_otg" and
> > > > > > "set_disconnect".
> > > > > > 
> > > > > > A forth helper function to "unset_otg" was added because this is used in both
> > > > > > "set_charging" and "set_disconnect". In the first case it covers the rather
> > > > > > rare event that someone changes from OTG to charging without disconnect. In
> > > > > > the second case, when disconnecting, the values are set back to the ones from
> > > > > > initialization to return into a defined state.
> > > > > > 
> > > > > > [...]
> > > > > 
> > > > > Applied, thanks!
> > > > > 
> > > > > [06/10] power: supply: rt5033_charger: Add cable detection and USB OTG supply
> > > > >          commit: c1af6bcc8583b0a1083338cd26c2090d0bcb0810
> > > > 
> > > > Multiple fixes now follow this patch, so I am unapplying it.
> > > > 
> > > > Sebastian, would you mind collecting it up please?
> > > 
> > > I'm leaving for a two week hiking trip (with basically no internet
> > > access) in some hours. My planed return date is basically when Linus
> > > is expected to tag 6.6-rc1, so I will not queue any more patches and
> > > send my pull request early (within the next few hours).
> > > 
> > > I planned to catch up with the power-supply backlog last week during
> > > Chaos Communication Camp, but it was too hot to do any sensible
> > > review. Now I expect to process the power-supply backlog in the
> > > week after the merge window.
> > 
> > The patch 6 of the rt5033-charger series v6 gathered some issues. For all of
> > them a solution was provided. Thanks to everyone involved! However, I don't
> > know what's the best way to put them together.
> > 
> > - As the patch 6 was forgotten to apply with the others of the
> >   patchset, in the meantime another small patch by Rob sneaked in. The
> >   patch 6 needs to be rebased on Rob's patch. It affects the includes.
> >   Would be nice to order them alphabetically after rebase.
> > 
> > - After patch 6 was added on top of Rob's patch in linux-next, there
> >   was a build failure. This is because "linux/of.h" now explicitly
> >   needs to be added to the rt5033-charger driver. Stephen Rothwell
> >   provided a fix. I'm not sure on the order: Maybe that needs to be
> >   added before adding patch 6 to avoid the build failure when the
> >   kernel test bot checks each commit separately.
> > 
> > https://lore.kernel.org/linux-next/20230821125741.3a2474d7@canb.auug.org.au/T/#u
> > 
> > - Beyond that, the kernel test bot also complained about undefined
> >   reference related to extcon. I didn't understand why this happens
> >   because the driver has "linux/extcon.h" included. Randy was attentive
> >   and provided a fix. Here again I'm not sure about the order, I guess
> >   this should be added before adding patch 6 to avoid build failures if
> >   each commit is tested separately.
> >   Kernel test bot complaints:
> >     x86_64 clang https://lore.kernel.org/oe-kbuild-all/202308220324.LsI8q3ML-lkp@intel.com/T/#u
> >     x86_64 gcc https://lore.kernel.org/oe-kbuild-all/202308240723.O2rW0InU-lkp@intel.com/T/#u
> >     arm gcc https://lore.kernel.org/oe-kbuild-all/202308250617.ue4uQxWa-lkp@intel.com/T/#u
> >   Fix by Randy:
> > 
> > https://lore.kernel.org/linux-pm/20230828224201.26823-1-rdunlap@infradead.org/T/#u
> > 
> > - Yang noticed that the mutex_unlock() is not handled correctly in
> >   some error path and provided a fix:
> > 
> > https://lore.kernel.org/linux-pm/20230822030207.644738-1-yangyingliang@huawei.com/T/#u
> > 
> > - There are two clean-up patches by me. They need to be rebased to the
> >   patches mentioned above but there shouldn't be conflicts with them.
> > 
> > https://lore.kernel.org/linux-pm/cover.1686948074.git.jahau@rocketmail.com/T/#u
> > 
> > Please also note that the commit hash in the linked fixes above refers to
> > linux-next, where the patch 6 had been applied. As the patch was dropped
> > later on, I don't know what this means for the commit hashes in the fixes.
> > 
> > What's the best way to proceed? Can you put these patches together? Or do
> > you want me something to do?
> 
> You need to do this yourself.
> 
> Rebase all of the fixes on top of v6.6-rc1 (which will be released in a
> little under a week).  Ensure that each patch builds as it's applied so
> as not to harm bisecability.  If you have to squash them to prevent
> built-breakages, then so be it, but don't forget to credit the
> contributors.  Once complete, post as a set and we'll take it from
> there.

Fully agreed. I expect to see a new series with the missing bits.

-- Sebastian
diff mbox series

Patch

diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c
index 5218dfbf5e1b..e0303ca5a8db 100644
--- a/drivers/power/supply/rt5033_charger.c
+++ b/drivers/power/supply/rt5033_charger.c
@@ -6,7 +6,10 @@ 
  * Author: Beomho Seo <beomho.seo@samsung.com>
  */
 
+#include <linux/devm-helpers.h>
+#include <linux/extcon.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
@@ -26,6 +29,14 @@  struct rt5033_charger {
 	struct regmap			*regmap;
 	struct power_supply		*psy;
 	struct rt5033_charger_data	*chg;
+	struct extcon_dev		*edev;
+	struct notifier_block		extcon_nb;
+	struct work_struct		extcon_work;
+	struct mutex			lock;
+	bool online;
+	bool otg;
+	bool mivr_enabled;
+	u8 cv_regval;
 };
 
 static int rt5033_get_charger_state(struct rt5033_charger *charger)
@@ -56,6 +67,10 @@  static int rt5033_get_charger_state(struct rt5033_charger *charger)
 		state = POWER_SUPPLY_STATUS_UNKNOWN;
 	}
 
+	/* For OTG mode, RT5033 would still report "charging" */
+	if (charger->otg)
+		state = POWER_SUPPLY_STATUS_DISCHARGING;
+
 	return state;
 }
 
@@ -147,6 +162,9 @@  static inline int rt5033_init_const_charge(struct rt5033_charger *charger)
 		return -EINVAL;
 	}
 
+	/* Store that value for later usage */
+	charger->cv_regval = reg_data;
+
 	/* Set end of charge current */
 	if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN ||
 	    chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) {
@@ -330,6 +348,152 @@  static int rt5033_charger_reg_init(struct rt5033_charger *charger)
 	return 0;
 }
 
+static int rt5033_charger_set_otg(struct rt5033_charger *charger)
+{
+	int ret;
+
+	mutex_lock(&charger->lock);
+
+	/* Set OTG boost v_out to 5 volts */
+	ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2,
+			RT5033_CHGCTRL2_CV_MASK,
+			0x37 << RT5033_CHGCTRL2_CV_SHIFT);
+	if (ret) {
+		dev_err(charger->dev, "Failed set OTG boost v_out\n");
+		return -EINVAL;
+	}
+
+	/* Set operation mode to OTG */
+	ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1,
+			RT5033_CHGCTRL1_MODE_MASK, RT5033_BOOST_MODE);
+	if (ret) {
+		dev_err(charger->dev, "Failed to update OTG mode.\n");
+		return -EINVAL;
+	}
+
+	/* In case someone switched from charging to OTG directly */
+	if (charger->online)
+		charger->online = false;
+
+	charger->otg = true;
+
+	mutex_unlock(&charger->lock);
+
+	return 0;
+}
+
+static int rt5033_charger_unset_otg(struct rt5033_charger *charger)
+{
+	int ret;
+	u8 data;
+
+	/* Restore constant voltage for charging */
+	data = charger->cv_regval;
+	ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2,
+			RT5033_CHGCTRL2_CV_MASK,
+			data << RT5033_CHGCTRL2_CV_SHIFT);
+	if (ret) {
+		dev_err(charger->dev, "Failed to restore constant voltage\n");
+		return -EINVAL;
+	}
+
+	/* Set operation mode to charging */
+	ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1,
+			RT5033_CHGCTRL1_MODE_MASK, RT5033_CHARGER_MODE);
+	if (ret) {
+		dev_err(charger->dev, "Failed to update charger mode.\n");
+		return -EINVAL;
+	}
+
+	charger->otg = false;
+
+	return 0;
+}
+
+static int rt5033_charger_set_charging(struct rt5033_charger *charger)
+{
+	int ret;
+
+	mutex_lock(&charger->lock);
+
+	/* In case someone switched from OTG to charging directly */
+	if (charger->otg) {
+		ret = rt5033_charger_unset_otg(charger);
+		if (ret)
+			return -EINVAL;
+	}
+
+	charger->online = true;
+
+	mutex_unlock(&charger->lock);
+
+	return 0;
+}
+
+static int rt5033_charger_set_mivr(struct rt5033_charger *charger)
+{
+	int ret;
+
+	mutex_lock(&charger->lock);
+
+	/*
+	 * When connected via USB connector type SDP (Standard Downstream Port),
+	 * the minimum input voltage regulation (MIVR) should be enabled. It
+	 * prevents an input voltage drop due to insufficient current provided
+	 * by the adapter or USB input. As a downside, it may reduces the
+	 * charging current and thus slows the charging.
+	 */
+	ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4,
+			RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_4600MV);
+	if (ret) {
+		dev_err(charger->dev, "Failed to set MIVR level.\n");
+		return -EINVAL;
+	}
+
+	charger->mivr_enabled = true;
+
+	mutex_unlock(&charger->lock);
+
+	/* Beyond this, do the same steps like setting charging */
+	rt5033_charger_set_charging(charger);
+
+	return 0;
+}
+
+static int rt5033_charger_set_disconnect(struct rt5033_charger *charger)
+{
+	int ret;
+
+	mutex_lock(&charger->lock);
+
+	/* Disable MIVR if enabled */
+	if (charger->mivr_enabled) {
+		ret = regmap_update_bits(charger->regmap,
+				RT5033_REG_CHG_CTRL4,
+				RT5033_CHGCTRL4_MIVR_MASK,
+				RT5033_CHARGER_MIVR_DISABLE);
+		if (ret) {
+			dev_err(charger->dev, "Failed to disable MIVR.\n");
+			return -EINVAL;
+		}
+
+		charger->mivr_enabled = false;
+	}
+
+	if (charger->otg) {
+		ret = rt5033_charger_unset_otg(charger);
+		if (ret)
+			return -EINVAL;
+	}
+
+	if (charger->online)
+		charger->online = false;
+
+	mutex_unlock(&charger->lock);
+
+	return 0;
+}
+
 static enum power_supply_property rt5033_charger_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CHARGE_TYPE,
@@ -366,8 +530,7 @@  static int rt5033_charger_get_property(struct power_supply *psy,
 		val->strval = RT5033_MANUFACTURER;
 		break;
 	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = (rt5033_get_charger_state(charger) ==
-				POWER_SUPPLY_STATUS_CHARGING);
+		val->intval = charger->online;
 		break;
 	default:
 		return -EINVAL;
@@ -402,6 +565,86 @@  static struct rt5033_charger_data *rt5033_charger_dt_init(
 	return chg;
 }
 
+static void rt5033_charger_extcon_work(struct work_struct *work)
+{
+	struct rt5033_charger *charger =
+		container_of(work, struct rt5033_charger, extcon_work);
+	struct extcon_dev *edev = charger->edev;
+	int connector, state;
+	int ret;
+
+	for (connector = EXTCON_USB_HOST; connector <= EXTCON_CHG_USB_PD;
+	     connector++) {
+		state = extcon_get_state(edev, connector);
+		if (state == 1)
+			break;
+	}
+
+	/*
+	 * Adding a delay between extcon notification and extcon action. This
+	 * makes extcon action execution more reliable. Without the delay the
+	 * execution sometimes fails, possibly because the chip is busy or not
+	 * ready.
+	 */
+	msleep(100);
+
+	switch (connector) {
+	case EXTCON_CHG_USB_SDP:
+		ret = rt5033_charger_set_mivr(charger);
+		if (ret) {
+			dev_err(charger->dev, "failed to set USB mode\n");
+			break;
+		}
+		dev_info(charger->dev, "USB mode. connector type: %d\n",
+			 connector);
+		break;
+	case EXTCON_CHG_USB_DCP:
+	case EXTCON_CHG_USB_CDP:
+	case EXTCON_CHG_USB_ACA:
+	case EXTCON_CHG_USB_FAST:
+	case EXTCON_CHG_USB_SLOW:
+	case EXTCON_CHG_WPT:
+	case EXTCON_CHG_USB_PD:
+		ret = rt5033_charger_set_charging(charger);
+		if (ret) {
+			dev_err(charger->dev, "failed to set charging\n");
+			break;
+		}
+		dev_info(charger->dev, "charging. connector type: %d\n",
+			 connector);
+		break;
+	case EXTCON_USB_HOST:
+		ret = rt5033_charger_set_otg(charger);
+		if (ret) {
+			dev_err(charger->dev, "failed to set OTG\n");
+			break;
+		}
+		dev_info(charger->dev, "OTG enabled\n");
+		break;
+	default:
+		ret = rt5033_charger_set_disconnect(charger);
+		if (ret) {
+			dev_err(charger->dev, "failed to set disconnect\n");
+			break;
+		}
+		dev_info(charger->dev, "disconnected\n");
+		break;
+	}
+
+	power_supply_changed(charger->psy);
+}
+
+static int rt5033_charger_extcon_notifier(struct notifier_block *nb,
+					  unsigned long event, void *param)
+{
+	struct rt5033_charger *charger =
+		container_of(nb, struct rt5033_charger, extcon_nb);
+
+	schedule_work(&charger->extcon_work);
+
+	return NOTIFY_OK;
+}
+
 static const struct power_supply_desc rt5033_charger_desc = {
 	.name = "rt5033-charger",
 	.type = POWER_SUPPLY_TYPE_USB,
@@ -414,6 +657,7 @@  static int rt5033_charger_probe(struct platform_device *pdev)
 {
 	struct rt5033_charger *charger;
 	struct power_supply_config psy_cfg = {};
+	struct device_node *np_conn, *np_edev;
 	int ret;
 
 	charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
@@ -423,6 +667,7 @@  static int rt5033_charger_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, charger);
 	charger->dev = &pdev->dev;
 	charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	mutex_init(&charger->lock);
 
 	psy_cfg.of_node = pdev->dev.of_node;
 	psy_cfg.drv_data = charger;
@@ -442,6 +687,33 @@  static int rt5033_charger_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	/*
+	 * Extcon support is not vital for the charger to work. If no extcon
+	 * is available, just emit a warning and leave the probe function.
+	 */
+	np_conn = of_parse_phandle(pdev->dev.of_node, "richtek,usb-connector", 0);
+	np_edev = of_get_parent(np_conn);
+	charger->edev = extcon_find_edev_by_node(np_edev);
+	if (IS_ERR(charger->edev)) {
+		dev_warn(&pdev->dev, "no extcon device found in device-tree\n");
+		goto out;
+	}
+
+	ret = devm_work_autocancel(&pdev->dev, &charger->extcon_work,
+				   rt5033_charger_extcon_work);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize extcon work\n");
+		return ret;
+	}
+
+	charger->extcon_nb.notifier_call = rt5033_charger_extcon_notifier;
+	ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev,
+						&charger->extcon_nb);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register extcon notifier\n");
+		return ret;
+	}
+out:
 	return 0;
 }