Patchwork [RFC,5/6] usb: otg: add device tree support to otg library

login
register
mail settings
Submitter Kishon Vijay Abraham I
Date Jan. 16, 2013, 3:01 p.m.
Message ID <1358348462-27693-6-git-send-email-kishon@ti.com>
Download mbox | patch
Permalink /patch/212554/
State Not Applicable
Headers show

Comments

Kishon Vijay Abraham I - Jan. 16, 2013, 3:01 p.m.
Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a
device node phandle value. This function will return a pointer to
the phy on success, -EPROBE_DEFER if there is a device_node for the phandle,
but the phy has not been added, or a ERR_PTR() otherwise.

Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/usb/otg/otg.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/phy.h |    8 +++++
 2 files changed, 85 insertions(+)
Roger Quadros - Jan. 21, 2013, 1:21 p.m.
On 01/16/2013 05:01 PM, Kishon Vijay Abraham I wrote:
> Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a
> device node phandle value. This function will return a pointer to
> the phy on success, -EPROBE_DEFER if there is a device_node for the phandle,
> but the phy has not been added, or a ERR_PTR() otherwise.
> 
> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/usb/otg/otg.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/usb/phy.h |    8 +++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
> index dbf2043..e9799bb 100644
> --- a/drivers/usb/otg/otg.c
> +++ b/drivers/usb/otg/otg.c
> @@ -13,7 +13,9 @@
>  #include <linux/export.h>
>  #include <linux/err.h>
>  #include <linux/device.h>
> +#include <linux/module.h>
>  #include <linux/slab.h>
> +#include <linux/of.h>
>  
>  #include <linux/usb/otg.h>
>  
> @@ -34,6 +36,20 @@ static struct usb_phy *__usb_find_phy(struct device *dev, u8 index)
>  	return ERR_PTR(-ENODEV);
>  }
>  
> +static struct usb_phy *__of_usb_find_phy(struct device_node *node)
> +{
> +	struct usb_phy  *phy;
> +
> +	list_for_each_entry(phy, &phy_list, head) {
> +		if (node != phy->dev->of_node)
> +			continue;
> +
> +		return phy;
> +	}
> +
> +	return ERR_PTR(-ENODEV);
> +}
> +
>  static void devm_usb_phy_release(struct device *dev, void *res)
>  {
>  	struct usb_phy *phy = *(struct usb_phy **)res;
> @@ -109,6 +125,67 @@ err0:
>  }
>  EXPORT_SYMBOL(usb_get_phy);
>  
> + /**
> + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
> + * @dev - device that requests this phy
> + * @phandle - name of the property holding the phy phandle value
> + * @index - the index of the phy
> + *
> + * Returns the phy driver associated with the given phandle value,
> + * after getting a refcount to it, -ENODEV if there is no such phy or
> + * -EPROBE_DEFER if there is a phandle to the phy, but the device is
> + * not yet loaded. While at that, it also associates the device with
> + * the phy using devres. On driver detach, release function is invoked
> + * on the devres data, then, devres data is freed.
> + *
> + * For use by USB host and peripheral drivers.
> + */
> +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
> +	const char *phandle, u8 index)
> +{
> +	struct usb_phy	*phy = NULL, **ptr;
> +	unsigned long	flags;
> +	struct device_node *node;
> +
> +	if (!dev->of_node) {
> +		dev_dbg(dev, "device does not have a device node entry\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	node = of_parse_phandle(dev->of_node, phandle, index);
> +	if (!node) {
> +		dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
> +			dev->of_node->full_name);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
> +	if (!ptr) {
> +		dev_dbg(dev, "failed to allocate memory for devres\n");
> +		return ERR_PTR(-ENOMEM);
> +	}

I fail to understand why you need ptr at all and why do devres_alloc()
for it.

> +
> +	spin_lock_irqsave(&phy_lock, flags);
> +
> +	phy = __of_usb_find_phy(node);
> +	if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
> +		phy = ERR_PTR(-EPROBE_DEFER);
> +		devres_free(ptr);
> +		goto err0;
> +	}
> +
> +	*ptr = phy;
> +	devres_add(dev, ptr);
> +
> +	get_device(phy->dev);
> +
> +err0:
> +	spin_unlock_irqrestore(&phy_lock, flags);
> +
> +	return phy;
> +}
> +EXPORT_SYMBOL(devm_usb_get_phy_by_phandle);
> +

--
cheers,
-roger
Kishon Vijay Abraham I - Jan. 21, 2013, 1:34 p.m.
On Monday 21 January 2013 06:51 PM, Roger Quadros wrote:
> On 01/16/2013 05:01 PM, Kishon Vijay Abraham I wrote:
>> Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a
>> device node phandle value. This function will return a pointer to
>> the phy on success, -EPROBE_DEFER if there is a device_node for the phandle,
>> but the phy has not been added, or a ERR_PTR() otherwise.
>>
>> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>   drivers/usb/otg/otg.c   |   77 +++++++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/usb/phy.h |    8 +++++
>>   2 files changed, 85 insertions(+)
>>
>> diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
>> index dbf2043..e9799bb 100644
>> --- a/drivers/usb/otg/otg.c
>> +++ b/drivers/usb/otg/otg.c
>> @@ -13,7 +13,9 @@
>>   #include <linux/export.h>
>>   #include <linux/err.h>
>>   #include <linux/device.h>
>> +#include <linux/module.h>
>>   #include <linux/slab.h>
>> +#include <linux/of.h>
>>
>>   #include <linux/usb/otg.h>
>>
>> @@ -34,6 +36,20 @@ static struct usb_phy *__usb_find_phy(struct device *dev, u8 index)
>>   	return ERR_PTR(-ENODEV);
>>   }
>>
>> +static struct usb_phy *__of_usb_find_phy(struct device_node *node)
>> +{
>> +	struct usb_phy  *phy;
>> +
>> +	list_for_each_entry(phy, &phy_list, head) {
>> +		if (node != phy->dev->of_node)
>> +			continue;
>> +
>> +		return phy;
>> +	}
>> +
>> +	return ERR_PTR(-ENODEV);
>> +}
>> +
>>   static void devm_usb_phy_release(struct device *dev, void *res)
>>   {
>>   	struct usb_phy *phy = *(struct usb_phy **)res;
>> @@ -109,6 +125,67 @@ err0:
>>   }
>>   EXPORT_SYMBOL(usb_get_phy);
>>
>> + /**
>> + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
>> + * @dev - device that requests this phy
>> + * @phandle - name of the property holding the phy phandle value
>> + * @index - the index of the phy
>> + *
>> + * Returns the phy driver associated with the given phandle value,
>> + * after getting a refcount to it, -ENODEV if there is no such phy or
>> + * -EPROBE_DEFER if there is a phandle to the phy, but the device is
>> + * not yet loaded. While at that, it also associates the device with
>> + * the phy using devres. On driver detach, release function is invoked
>> + * on the devres data, then, devres data is freed.
>> + *
>> + * For use by USB host and peripheral drivers.
>> + */
>> +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
>> +	const char *phandle, u8 index)
>> +{
>> +	struct usb_phy	*phy = NULL, **ptr;
>> +	unsigned long	flags;
>> +	struct device_node *node;
>> +
>> +	if (!dev->of_node) {
>> +		dev_dbg(dev, "device does not have a device node entry\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	node = of_parse_phandle(dev->of_node, phandle, index);
>> +	if (!node) {
>> +		dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
>> +			dev->of_node->full_name);
>> +		return ERR_PTR(-ENODEV);
>> +	}
>> +
>> +	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
>> +	if (!ptr) {
>> +		dev_dbg(dev, "failed to allocate memory for devres\n");
>> +		return ERR_PTR(-ENOMEM);
>> +	}
>
> I fail to understand why you need ptr at all and why do devres_alloc()
> for it.

Thats how we create a "managed device resource". You can have a look at 
Documentation/driver-model/devres.txt and drivers/base/devres.c.

I'm not sure if that is what you are looking for :-P

Thanks
Kishon
Roger Quadros - Jan. 21, 2013, 2:23 p.m.
On 01/21/2013 03:34 PM, kishon wrote:
> On Monday 21 January 2013 06:51 PM, Roger Quadros wrote:
>> On 01/16/2013 05:01 PM, Kishon Vijay Abraham I wrote:
>>> Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a
>>> device node phandle value. This function will return a pointer to
>>> the phy on success, -EPROBE_DEFER if there is a device_node for the
>>> phandle,
>>> but the phy has not been added, or a ERR_PTR() otherwise.
>>>
>>> Cc: Marc Kleine-Budde <mkl@pengutronix.de>
>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>> ---
>>>   drivers/usb/otg/otg.c   |   77
>>> +++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/linux/usb/phy.h |    8 +++++
>>>   2 files changed, 85 insertions(+)
>>>
>>> diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
>>> index dbf2043..e9799bb 100644
>>> --- a/drivers/usb/otg/otg.c
>>> +++ b/drivers/usb/otg/otg.c
>>> @@ -13,7 +13,9 @@
>>>   #include <linux/export.h>
>>>   #include <linux/err.h>
>>>   #include <linux/device.h>
>>> +#include <linux/module.h>
>>>   #include <linux/slab.h>
>>> +#include <linux/of.h>
>>>
>>>   #include <linux/usb/otg.h>
>>>
>>> @@ -34,6 +36,20 @@ static struct usb_phy *__usb_find_phy(struct
>>> device *dev, u8 index)
>>>       return ERR_PTR(-ENODEV);
>>>   }
>>>
>>> +static struct usb_phy *__of_usb_find_phy(struct device_node *node)
>>> +{
>>> +    struct usb_phy  *phy;
>>> +
>>> +    list_for_each_entry(phy, &phy_list, head) {
>>> +        if (node != phy->dev->of_node)
>>> +            continue;
>>> +
>>> +        return phy;
>>> +    }
>>> +
>>> +    return ERR_PTR(-ENODEV);
>>> +}
>>> +
>>>   static void devm_usb_phy_release(struct device *dev, void *res)
>>>   {
>>>       struct usb_phy *phy = *(struct usb_phy **)res;
>>> @@ -109,6 +125,67 @@ err0:
>>>   }
>>>   EXPORT_SYMBOL(usb_get_phy);
>>>
>>> + /**
>>> + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
>>> + * @dev - device that requests this phy
>>> + * @phandle - name of the property holding the phy phandle value
>>> + * @index - the index of the phy
>>> + *
>>> + * Returns the phy driver associated with the given phandle value,
>>> + * after getting a refcount to it, -ENODEV if there is no such phy or
>>> + * -EPROBE_DEFER if there is a phandle to the phy, but the device is
>>> + * not yet loaded. While at that, it also associates the device with
>>> + * the phy using devres. On driver detach, release function is invoked
>>> + * on the devres data, then, devres data is freed.
>>> + *
>>> + * For use by USB host and peripheral drivers.
>>> + */
>>> +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
>>> +    const char *phandle, u8 index)
>>> +{
>>> +    struct usb_phy    *phy = NULL, **ptr;
>>> +    unsigned long    flags;
>>> +    struct device_node *node;
>>> +
>>> +    if (!dev->of_node) {
>>> +        dev_dbg(dev, "device does not have a device node entry\n");
>>> +        return ERR_PTR(-EINVAL);
>>> +    }
>>> +
>>> +    node = of_parse_phandle(dev->of_node, phandle, index);
>>> +    if (!node) {
>>> +        dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
>>> +            dev->of_node->full_name);
>>> +        return ERR_PTR(-ENODEV);
>>> +    }
>>> +
>>> +    ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
>>> +    if (!ptr) {
>>> +        dev_dbg(dev, "failed to allocate memory for devres\n");
>>> +        return ERR_PTR(-ENOMEM);
>>> +    }
>>
>> I fail to understand why you need ptr at all and why do devres_alloc()
>> for it.
> 
> Thats how we create a "managed device resource". You can have a look at
> Documentation/driver-model/devres.txt and drivers/base/devres.c.

OK, I get it now. You might want to update the text file too since you
are adding a automagically managed interface.

regards,
-roger

Patch

diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index dbf2043..e9799bb 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -13,7 +13,9 @@ 
 #include <linux/export.h>
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <linux/usb/otg.h>
 
@@ -34,6 +36,20 @@  static struct usb_phy *__usb_find_phy(struct device *dev, u8 index)
 	return ERR_PTR(-ENODEV);
 }
 
+static struct usb_phy *__of_usb_find_phy(struct device_node *node)
+{
+	struct usb_phy  *phy;
+
+	list_for_each_entry(phy, &phy_list, head) {
+		if (node != phy->dev->of_node)
+			continue;
+
+		return phy;
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
 static void devm_usb_phy_release(struct device *dev, void *res)
 {
 	struct usb_phy *phy = *(struct usb_phy **)res;
@@ -109,6 +125,67 @@  err0:
 }
 EXPORT_SYMBOL(usb_get_phy);
 
+ /**
+ * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
+ * @dev - device that requests this phy
+ * @phandle - name of the property holding the phy phandle value
+ * @index - the index of the phy
+ *
+ * Returns the phy driver associated with the given phandle value,
+ * after getting a refcount to it, -ENODEV if there is no such phy or
+ * -EPROBE_DEFER if there is a phandle to the phy, but the device is
+ * not yet loaded. While at that, it also associates the device with
+ * the phy using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ *
+ * For use by USB host and peripheral drivers.
+ */
+struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
+	const char *phandle, u8 index)
+{
+	struct usb_phy	*phy = NULL, **ptr;
+	unsigned long	flags;
+	struct device_node *node;
+
+	if (!dev->of_node) {
+		dev_dbg(dev, "device does not have a device node entry\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	node = of_parse_phandle(dev->of_node, phandle, index);
+	if (!node) {
+		dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
+			dev->of_node->full_name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr) {
+		dev_dbg(dev, "failed to allocate memory for devres\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	spin_lock_irqsave(&phy_lock, flags);
+
+	phy = __of_usb_find_phy(node);
+	if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
+		phy = ERR_PTR(-EPROBE_DEFER);
+		devres_free(ptr);
+		goto err0;
+	}
+
+	*ptr = phy;
+	devres_add(dev, ptr);
+
+	get_device(phy->dev);
+
+err0:
+	spin_unlock_irqrestore(&phy_lock, flags);
+
+	return phy;
+}
+EXPORT_SYMBOL(devm_usb_get_phy_by_phandle);
+
 /**
  * devm_usb_put_phy - release the USB PHY
  * @dev - device that wants to release this phy
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index d133c8b..5836b6d 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -163,6 +163,8 @@  usb_phy_shutdown(struct usb_phy *x)
 #ifdef CONFIG_USB_OTG_UTILS
 extern struct usb_phy *usb_get_phy(struct device *dev, u8 index);
 extern struct usb_phy *devm_usb_get_phy(struct device *dev, u8 index);
+extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
+	const char *phandle, u8 index);
 extern void usb_put_phy(struct usb_phy *);
 extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
 extern struct usb_phy_bind *usb_bind_phy(const char *dev_name, u8 index,
@@ -178,6 +180,12 @@  static inline struct usb_phy *devm_usb_get_phy(struct device *dev, u8 index)
 	return NULL;
 }
 
+static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
+	const char *phandle, u8 index)
+{
+	return NULL;
+}
+
 static inline void usb_put_phy(struct usb_phy *x)
 {
 }