All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chen-Yu Tsai <wens@csie.org>
To: Maxime Ripard <maxime.ripard@bootlin.com>,
	Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Lee Jones <lee.jones@linaro.org>,
	Sebastian Reichel <sre@kernel.org>
Cc: Chen-Yu Tsai <wens@csie.org>,
	devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-sunxi@googlegroups.com,
	Quentin Schulz <quentin.schulz@bootlin.com>,
	Hans de Goede <hdegoede@redhat.com>
Subject: [RFT PATCH 4/9] power: supply: axp20x_usb_power: use polling to detect vbus status change
Date: Thu,  7 Feb 2019 14:45:30 +0800	[thread overview]
Message-ID: <20190207064535.9226-5-wens@csie.org> (raw)
In-Reply-To: <20190207064535.9226-1-wens@csie.org>

On AXP221 and later AXP PMICs that have the N_VBUSEN pin, when this pin
is high, either due to the PMIC driving it high or as an input, the VBUS
detection related interrupt mechanisms are disabled.

Previously this was worked around in the phy-sun4i-usb driver, which
needed to sense VBUS changes and report them to the musb driver in a
timely matter. However this workaround was only for the A31 and A33 type
USB PHYs. To support newer platforms we would have to enable it for
almost all the post-A31 SoCs.

However, since this is actually the result of the PMIC's behavior, the
workaround would be better if done in the PMIC driver, in this case the
VBUS power supply driver.

Add the same workqueue-based polling to the VBUS power supply driver.
The polling interval is chosen to be the debounce interval from the USB
PHY driver, as this short interval is needed in some cases, but the
power supply driver would not know when.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 drivers/power/supply/axp20x_usb_power.c | 53 +++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index e2f353906bb1..ac061bcdc056 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -24,6 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/iio/consumer.h>
+#include <linux/workqueue.h>
 
 #define DRVNAME "axp20x-usb-power-supply"
 
@@ -46,6 +47,12 @@
 
 #define AXP20X_VBUS_MON_VBUS_VALID	BIT(3)
 
+/*
+ * Note do not raise the debounce time, we must report Vusb high within
+ * 100ms otherwise we get Vbus errors in musb.
+ */
+#define DEBOUNCE_TIME			msecs_to_jiffies(50)
+
 struct axp20x_usb_power {
 	struct device_node *np;
 	struct regmap *regmap;
@@ -53,6 +60,8 @@ struct axp20x_usb_power {
 	enum axp20x_variants axp20x_id;
 	struct iio_channel *vbus_v;
 	struct iio_channel *vbus_i;
+	struct delayed_work vbus_detect;
+	unsigned int old_status;
 };
 
 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -64,6 +73,35 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
+static void axp20x_usb_power_poll_vbus(struct work_struct *work)
+{
+	struct axp20x_usb_power *power =
+		container_of(work, struct axp20x_usb_power, vbus_detect.work);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
+	if (ret)
+		goto out;
+
+	val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
+	if (val != power->old_status)
+		power_supply_changed(power->supply);
+
+	power->old_status = val;
+
+out:
+	mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+}
+
+static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
+{
+	if (power->axp20x_id >= AXP221_ID)
+		return true;
+
+	return false;
+}
+
 static int axp20x_usb_power_get_property(struct power_supply *psy,
 	enum power_supply_property psp, union power_supply_propval *val)
 {
@@ -362,6 +400,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 	if (!power)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, power);
 	power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
 								&pdev->dev);
 
@@ -420,6 +459,19 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 				 irq_names[i], ret);
 	}
 
+	INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
+	if (axp20x_usb_vbus_needs_polling(power))
+		queue_delayed_work(system_wq, &power->vbus_detect, 0);
+
+	return 0;
+}
+
+static int axp20x_usb_power_remove(struct platform_device *pdev)
+{
+	struct axp20x_usb_power *power = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&power->vbus_detect);
+
 	return 0;
 }
 
@@ -439,6 +491,7 @@ MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 
 static struct platform_driver axp20x_usb_power_driver = {
 	.probe = axp20x_usb_power_probe,
+	.remove = axp20x_usb_power_remove,
 	.driver = {
 		.name = DRVNAME,
 		.of_match_table = axp20x_usb_power_match,
-- 
2.20.1


WARNING: multiple messages have this Message-ID (diff)
From: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
To: Maxime Ripard
	<maxime.ripard-LDxbnhwyfcJBDgjK7y7TUQ@public.gmane.org>,
	Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
	Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
	Quentin Schulz
	<quentin.schulz-LDxbnhwyfcJBDgjK7y7TUQ@public.gmane.org>,
	Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Subject: [RFT PATCH 4/9] power: supply: axp20x_usb_power: use polling to detect vbus status change
Date: Thu,  7 Feb 2019 14:45:30 +0800	[thread overview]
Message-ID: <20190207064535.9226-5-wens@csie.org> (raw)
In-Reply-To: <20190207064535.9226-1-wens-jdAy2FN1RRM@public.gmane.org>

On AXP221 and later AXP PMICs that have the N_VBUSEN pin, when this pin
is high, either due to the PMIC driving it high or as an input, the VBUS
detection related interrupt mechanisms are disabled.

Previously this was worked around in the phy-sun4i-usb driver, which
needed to sense VBUS changes and report them to the musb driver in a
timely matter. However this workaround was only for the A31 and A33 type
USB PHYs. To support newer platforms we would have to enable it for
almost all the post-A31 SoCs.

However, since this is actually the result of the PMIC's behavior, the
workaround would be better if done in the PMIC driver, in this case the
VBUS power supply driver.

Add the same workqueue-based polling to the VBUS power supply driver.
The polling interval is chosen to be the debounce interval from the USB
PHY driver, as this short interval is needed in some cases, but the
power supply driver would not know when.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 drivers/power/supply/axp20x_usb_power.c | 53 +++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index e2f353906bb1..ac061bcdc056 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -24,6 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/iio/consumer.h>
+#include <linux/workqueue.h>
 
 #define DRVNAME "axp20x-usb-power-supply"
 
@@ -46,6 +47,12 @@
 
 #define AXP20X_VBUS_MON_VBUS_VALID	BIT(3)
 
+/*
+ * Note do not raise the debounce time, we must report Vusb high within
+ * 100ms otherwise we get Vbus errors in musb.
+ */
+#define DEBOUNCE_TIME			msecs_to_jiffies(50)
+
 struct axp20x_usb_power {
 	struct device_node *np;
 	struct regmap *regmap;
@@ -53,6 +60,8 @@ struct axp20x_usb_power {
 	enum axp20x_variants axp20x_id;
 	struct iio_channel *vbus_v;
 	struct iio_channel *vbus_i;
+	struct delayed_work vbus_detect;
+	unsigned int old_status;
 };
 
 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -64,6 +73,35 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
+static void axp20x_usb_power_poll_vbus(struct work_struct *work)
+{
+	struct axp20x_usb_power *power =
+		container_of(work, struct axp20x_usb_power, vbus_detect.work);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
+	if (ret)
+		goto out;
+
+	val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
+	if (val != power->old_status)
+		power_supply_changed(power->supply);
+
+	power->old_status = val;
+
+out:
+	mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+}
+
+static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
+{
+	if (power->axp20x_id >= AXP221_ID)
+		return true;
+
+	return false;
+}
+
 static int axp20x_usb_power_get_property(struct power_supply *psy,
 	enum power_supply_property psp, union power_supply_propval *val)
 {
@@ -362,6 +400,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 	if (!power)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, power);
 	power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
 								&pdev->dev);
 
@@ -420,6 +459,19 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 				 irq_names[i], ret);
 	}
 
+	INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
+	if (axp20x_usb_vbus_needs_polling(power))
+		queue_delayed_work(system_wq, &power->vbus_detect, 0);
+
+	return 0;
+}
+
+static int axp20x_usb_power_remove(struct platform_device *pdev)
+{
+	struct axp20x_usb_power *power = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&power->vbus_detect);
+
 	return 0;
 }
 
@@ -439,6 +491,7 @@ MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 
 static struct platform_driver axp20x_usb_power_driver = {
 	.probe = axp20x_usb_power_probe,
+	.remove = axp20x_usb_power_remove,
 	.driver = {
 		.name = DRVNAME,
 		.of_match_table = axp20x_usb_power_match,
-- 
2.20.1

WARNING: multiple messages have this Message-ID (diff)
From: Chen-Yu Tsai <wens@csie.org>
To: Maxime Ripard <maxime.ripard@bootlin.com>,
	Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Lee Jones <lee.jones@linaro.org>,
	Sebastian Reichel <sre@kernel.org>
Cc: devicetree@vger.kernel.org,
	Quentin Schulz <quentin.schulz@bootlin.com>,
	linux-pm@vger.kernel.org, linux-sunxi@googlegroups.com,
	linux-kernel@vger.kernel.org, Hans de Goede <hdegoede@redhat.com>,
	Chen-Yu Tsai <wens@csie.org>,
	linux-arm-kernel@lists.infradead.org
Subject: [RFT PATCH 4/9] power: supply: axp20x_usb_power: use polling to detect vbus status change
Date: Thu,  7 Feb 2019 14:45:30 +0800	[thread overview]
Message-ID: <20190207064535.9226-5-wens@csie.org> (raw)
In-Reply-To: <20190207064535.9226-1-wens@csie.org>

On AXP221 and later AXP PMICs that have the N_VBUSEN pin, when this pin
is high, either due to the PMIC driving it high or as an input, the VBUS
detection related interrupt mechanisms are disabled.

Previously this was worked around in the phy-sun4i-usb driver, which
needed to sense VBUS changes and report them to the musb driver in a
timely matter. However this workaround was only for the A31 and A33 type
USB PHYs. To support newer platforms we would have to enable it for
almost all the post-A31 SoCs.

However, since this is actually the result of the PMIC's behavior, the
workaround would be better if done in the PMIC driver, in this case the
VBUS power supply driver.

Add the same workqueue-based polling to the VBUS power supply driver.
The polling interval is chosen to be the debounce interval from the USB
PHY driver, as this short interval is needed in some cases, but the
power supply driver would not know when.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 drivers/power/supply/axp20x_usb_power.c | 53 +++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index e2f353906bb1..ac061bcdc056 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -24,6 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/iio/consumer.h>
+#include <linux/workqueue.h>
 
 #define DRVNAME "axp20x-usb-power-supply"
 
@@ -46,6 +47,12 @@
 
 #define AXP20X_VBUS_MON_VBUS_VALID	BIT(3)
 
+/*
+ * Note do not raise the debounce time, we must report Vusb high within
+ * 100ms otherwise we get Vbus errors in musb.
+ */
+#define DEBOUNCE_TIME			msecs_to_jiffies(50)
+
 struct axp20x_usb_power {
 	struct device_node *np;
 	struct regmap *regmap;
@@ -53,6 +60,8 @@ struct axp20x_usb_power {
 	enum axp20x_variants axp20x_id;
 	struct iio_channel *vbus_v;
 	struct iio_channel *vbus_i;
+	struct delayed_work vbus_detect;
+	unsigned int old_status;
 };
 
 static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
@@ -64,6 +73,35 @@ static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
+static void axp20x_usb_power_poll_vbus(struct work_struct *work)
+{
+	struct axp20x_usb_power *power =
+		container_of(work, struct axp20x_usb_power, vbus_detect.work);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &val);
+	if (ret)
+		goto out;
+
+	val &= (AXP20X_PWR_STATUS_VBUS_PRESENT | AXP20X_PWR_STATUS_VBUS_USED);
+	if (val != power->old_status)
+		power_supply_changed(power->supply);
+
+	power->old_status = val;
+
+out:
+	mod_delayed_work(system_wq, &power->vbus_detect, DEBOUNCE_TIME);
+}
+
+static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power)
+{
+	if (power->axp20x_id >= AXP221_ID)
+		return true;
+
+	return false;
+}
+
 static int axp20x_usb_power_get_property(struct power_supply *psy,
 	enum power_supply_property psp, union power_supply_propval *val)
 {
@@ -362,6 +400,7 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 	if (!power)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, power);
 	power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
 								&pdev->dev);
 
@@ -420,6 +459,19 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
 				 irq_names[i], ret);
 	}
 
+	INIT_DELAYED_WORK(&power->vbus_detect, axp20x_usb_power_poll_vbus);
+	if (axp20x_usb_vbus_needs_polling(power))
+		queue_delayed_work(system_wq, &power->vbus_detect, 0);
+
+	return 0;
+}
+
+static int axp20x_usb_power_remove(struct platform_device *pdev)
+{
+	struct axp20x_usb_power *power = platform_get_drvdata(pdev);
+
+	cancel_delayed_work_sync(&power->vbus_detect);
+
 	return 0;
 }
 
@@ -439,6 +491,7 @@ MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
 
 static struct platform_driver axp20x_usb_power_driver = {
 	.probe = axp20x_usb_power_probe,
+	.remove = axp20x_usb_power_remove,
 	.driver = {
 		.name = DRVNAME,
 		.of_match_table = axp20x_usb_power_match,
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2019-02-07  6:46 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-07  6:45 [RFT PATCH 0/9] ARM: sun8i: a83t: Enable USB OTG Chen-Yu Tsai
2019-02-07  6:45 ` Chen-Yu Tsai
2019-02-07  6:45 ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 1/9] dt-bindings: power: supply: axp20x_usb_power: add axp813 compatible Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 2/9] power: supply: axp20x_usb_power: Fix typo in VBUS current limit macros Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 3/9] power: supply: axp20x_usb_power: allow disabling input current limiting Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` Chen-Yu Tsai [this message]
2019-02-07  6:45   ` [RFT PATCH 4/9] power: supply: axp20x_usb_power: use polling to detect vbus status change Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 5/9] power: supply: axp20x_usb_power: add function to get max current Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 6/9] power: supply: axp20x_usb_power: add support for AXP813 Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 7/9] mfd: axp20x: add USB power supply mfd cell to AXP813 Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07 11:02   ` Lee Jones
2019-02-07 11:02     ` Lee Jones
2019-02-07 11:02     ` Lee Jones
2019-02-07 14:28     ` Chen-Yu Tsai
2019-02-07 14:28       ` Chen-Yu Tsai
2019-02-08 11:03       ` Lee Jones
2019-02-08 11:03         ` Lee Jones
2019-02-07 15:13   ` [linux-sunxi] " Priit Laes
2019-02-07 15:13     ` Priit Laes
2019-02-07 15:13     ` Priit Laes
2019-02-07  6:45 ` [RFT PATCH 8/9] ARM: dtsi: axp81x: add USB power supply node Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45 ` [RFT PATCH 9/9] ARM: dts: sun8i: a83t: Enable USB OTG controller on some boards Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai
2019-02-07  6:45   ` Chen-Yu Tsai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190207064535.9226-5-wens@csie.org \
    --to=wens@csie.org \
    --cc=devicetree@vger.kernel.org \
    --cc=hdegoede@redhat.com \
    --cc=lee.jones@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-sunxi@googlegroups.com \
    --cc=mark.rutland@arm.com \
    --cc=maxime.ripard@bootlin.com \
    --cc=quentin.schulz@bootlin.com \
    --cc=robh+dt@kernel.org \
    --cc=sre@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.