linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] usb: phy: introduce usb_phy device type with its own uevent handler
@ 2021-05-31 12:22 Grzegorz Jaszczyk
  2021-06-01  3:50 ` Peter Chen
  0 siblings, 1 reply; 2+ messages in thread
From: Grzegorz Jaszczyk @ 2021-05-31 12:22 UTC (permalink / raw)
  To: balbi, gregkh; +Cc: linux-usb, linux-kernel, grzegorz.jaszczyk

The USB charger type and status was already propagated to userspace
through kobject_uevent_env during charger notify work. Nevertheless the
uevent could be lost e.g. because it could be fired at an early kernel
boot stage, way before udev daemon or any other user-space app was able
to catch it. Registering uevent hook for introduced usb_phy_dev_type
will allow to query sysfs 'uevent' file to restore that information at
any time.

Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
---
 drivers/usb/phy/phy.c | 55 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index b47285f023cf..83ed5089475a 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -42,6 +42,12 @@ static const char *const usb_chger_type[] = {
 	[ACA_TYPE]			= "USB_CHARGER_ACA_TYPE",
 };
 
+static const char *const usb_chger_state[] = {
+	[USB_CHARGER_DEFAULT]	= "USB_CHARGER_DEFAULT",
+	[USB_CHARGER_PRESENT]	= "USB_CHARGER_PRESENT",
+	[USB_CHARGER_ABSENT]	= "USB_CHARGER_ABSENT",
+};
+
 static struct usb_phy *__usb_find_phy(struct list_head *list,
 	enum usb_phy_type type)
 {
@@ -74,6 +80,18 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
 	return ERR_PTR(-EPROBE_DEFER);
 }
 
+static struct usb_phy *__device_to_usb_phy(struct device *dev)
+{
+	struct usb_phy *usb_phy;
+
+	list_for_each_entry(usb_phy, &phy_list, head) {
+		if (usb_phy->dev == dev)
+			break;
+	}
+
+	return usb_phy;
+}
+
 static void usb_phy_set_default_current(struct usb_phy *usb_phy)
 {
 	usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN;
@@ -105,9 +123,6 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy)
 static void usb_phy_notify_charger_work(struct work_struct *work)
 {
 	struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work);
-	char uchger_state[50] = { 0 };
-	char uchger_type[50] = { 0 };
-	char *envp[] = { uchger_state, uchger_type, NULL };
 	unsigned int min, max;
 
 	switch (usb_phy->chg_state) {
@@ -115,15 +130,11 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
 		usb_phy_get_charger_current(usb_phy, &min, &max);
 
 		atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy);
-		snprintf(uchger_state, ARRAY_SIZE(uchger_state),
-			 "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT");
 		break;
 	case USB_CHARGER_ABSENT:
 		usb_phy_set_default_current(usb_phy);
 
 		atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy);
-		snprintf(uchger_state, ARRAY_SIZE(uchger_state),
-			 "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT");
 		break;
 	default:
 		dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n",
@@ -131,9 +142,30 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
 		return;
 	}
 
+	kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE);
+}
+
+static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct usb_phy *usb_phy;
+	char uchger_state[50] = { 0 };
+	char uchger_type[50] = { 0 };
+
+	usb_phy = __device_to_usb_phy(dev);
+
+	snprintf(uchger_state, ARRAY_SIZE(uchger_state),
+		 "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]);
+
 	snprintf(uchger_type, ARRAY_SIZE(uchger_type),
 		 "USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]);
-	kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp);
+
+	if (add_uevent_var(env, uchger_state))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, uchger_type))
+		return -ENOMEM;
+
+	return 0;
 }
 
 static void __usb_phy_get_charger_type(struct usb_phy *usb_phy)
@@ -661,6 +693,11 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
 }
 EXPORT_SYMBOL_GPL(usb_add_phy);
 
+static struct device_type usb_phy_dev_type = {
+	.name = "usb_phy",
+	.uevent = usb_phy_uevent,
+};
+
 /**
  * usb_add_phy_dev - declare the USB PHY
  * @x: the USB phy to be used; or NULL
@@ -684,6 +721,8 @@ int usb_add_phy_dev(struct usb_phy *x)
 	if (ret)
 		return ret;
 
+	x->dev->type = &usb_phy_dev_type;
+
 	ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
 
 	spin_lock_irqsave(&phy_lock, flags);
-- 
2.29.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] usb: phy: introduce usb_phy device type with its own uevent handler
  2021-05-31 12:22 [PATCH] usb: phy: introduce usb_phy device type with its own uevent handler Grzegorz Jaszczyk
@ 2021-06-01  3:50 ` Peter Chen
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Chen @ 2021-06-01  3:50 UTC (permalink / raw)
  To: Grzegorz Jaszczyk; +Cc: balbi, gregkh, linux-usb, linux-kernel

On 21-05-31 14:22:22, Grzegorz Jaszczyk wrote:
> The USB charger type and status was already propagated to userspace
> through kobject_uevent_env during charger notify work. Nevertheless the
> uevent could be lost e.g. because it could be fired at an early kernel
> boot stage, way before udev daemon or any other user-space app was able
> to catch it. Registering uevent hook for introduced usb_phy_dev_type
> will allow to query sysfs 'uevent' file to restore that information at
> any time.
> 
> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>

Reviewed-by: Peter Chen <peter.chen@kernel.org>

Peter
> ---
>  drivers/usb/phy/phy.c | 55 ++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
> index b47285f023cf..83ed5089475a 100644
> --- a/drivers/usb/phy/phy.c
> +++ b/drivers/usb/phy/phy.c
> @@ -42,6 +42,12 @@ static const char *const usb_chger_type[] = {
>  	[ACA_TYPE]			= "USB_CHARGER_ACA_TYPE",
>  };
>  
> +static const char *const usb_chger_state[] = {
> +	[USB_CHARGER_DEFAULT]	= "USB_CHARGER_DEFAULT",
> +	[USB_CHARGER_PRESENT]	= "USB_CHARGER_PRESENT",
> +	[USB_CHARGER_ABSENT]	= "USB_CHARGER_ABSENT",
> +};
> +
>  static struct usb_phy *__usb_find_phy(struct list_head *list,
>  	enum usb_phy_type type)
>  {
> @@ -74,6 +80,18 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
>  	return ERR_PTR(-EPROBE_DEFER);
>  }
>  
> +static struct usb_phy *__device_to_usb_phy(struct device *dev)
> +{
> +	struct usb_phy *usb_phy;
> +
> +	list_for_each_entry(usb_phy, &phy_list, head) {
> +		if (usb_phy->dev == dev)
> +			break;
> +	}
> +
> +	return usb_phy;
> +}
> +
>  static void usb_phy_set_default_current(struct usb_phy *usb_phy)
>  {
>  	usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN;
> @@ -105,9 +123,6 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy)
>  static void usb_phy_notify_charger_work(struct work_struct *work)
>  {
>  	struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work);
> -	char uchger_state[50] = { 0 };
> -	char uchger_type[50] = { 0 };
> -	char *envp[] = { uchger_state, uchger_type, NULL };
>  	unsigned int min, max;
>  
>  	switch (usb_phy->chg_state) {
> @@ -115,15 +130,11 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
>  		usb_phy_get_charger_current(usb_phy, &min, &max);
>  
>  		atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy);
> -		snprintf(uchger_state, ARRAY_SIZE(uchger_state),
> -			 "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT");
>  		break;
>  	case USB_CHARGER_ABSENT:
>  		usb_phy_set_default_current(usb_phy);
>  
>  		atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy);
> -		snprintf(uchger_state, ARRAY_SIZE(uchger_state),
> -			 "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT");
>  		break;
>  	default:
>  		dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n",
> @@ -131,9 +142,30 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
>  		return;
>  	}
>  
> +	kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE);
> +}
> +
> +static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env)
> +{
> +	struct usb_phy *usb_phy;
> +	char uchger_state[50] = { 0 };
> +	char uchger_type[50] = { 0 };
> +
> +	usb_phy = __device_to_usb_phy(dev);
> +
> +	snprintf(uchger_state, ARRAY_SIZE(uchger_state),
> +		 "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]);
> +
>  	snprintf(uchger_type, ARRAY_SIZE(uchger_type),
>  		 "USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]);
> -	kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp);
> +
> +	if (add_uevent_var(env, uchger_state))
> +		return -ENOMEM;
> +
> +	if (add_uevent_var(env, uchger_type))
> +		return -ENOMEM;
> +
> +	return 0;
>  }
>  
>  static void __usb_phy_get_charger_type(struct usb_phy *usb_phy)
> @@ -661,6 +693,11 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
>  }
>  EXPORT_SYMBOL_GPL(usb_add_phy);
>  
> +static struct device_type usb_phy_dev_type = {
> +	.name = "usb_phy",
> +	.uevent = usb_phy_uevent,
> +};
> +
>  /**
>   * usb_add_phy_dev - declare the USB PHY
>   * @x: the USB phy to be used; or NULL
> @@ -684,6 +721,8 @@ int usb_add_phy_dev(struct usb_phy *x)
>  	if (ret)
>  		return ret;
>  
> +	x->dev->type = &usb_phy_dev_type;
> +
>  	ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
>  
>  	spin_lock_irqsave(&phy_lock, flags);
> -- 
> 2.29.0
> 

-- 

Thanks,
Peter Chen


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-06-01  3:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-31 12:22 [PATCH] usb: phy: introduce usb_phy device type with its own uevent handler Grzegorz Jaszczyk
2021-06-01  3:50 ` Peter Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).