diff mbox

[v3,1/2] ohci-platform: Add support for devicetree instantiation

Message ID 1389290226-6971-2-git-send-email-hdegoede@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Hans de Goede Jan. 9, 2014, 5:57 p.m. UTC
Add support for ohci-platform instantiation from devicetree, including
optionally getting clks and a phy from devicetree, and enabling / disabling
those on power_on / off.

This should allow using ohci-platform from devicetree in various cases.
Specifically after this commit it can be used for the ohci controller found
on Allwinner sunxi SoCs.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
 drivers/usb/host/ohci-platform.c                   | 150 ++++++++++++++++++---
 2 files changed, 152 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt

Comments

Arnd Bergmann Jan. 9, 2014, 6:07 p.m. UTC | #1
On Thursday 09 January 2014 18:57:05 Hans de Goede wrote:
> +       if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
> +               priv->phy = devm_phy_get(&dev->dev, "usb");
> +               if (IS_ERR(priv->phy)) {
> +                       err = PTR_ERR(priv->phy);
> +                       if (err == -EPROBE_DEFER)
> +                               goto err_put_hcd;
> +                       priv->phy = NULL;
> +               }
> +
> +               for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
> +                       priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
> +                       if (IS_ERR(priv->clks[clk])) {
> +                               err = PTR_ERR(priv->clks[clk]);
> +                               if (err == -EPROBE_DEFER)
> +                                       goto err_put_clks;
> +                               priv->clks[clk] = NULL;
> +                               break;
> +                       }
> +               }
> +       }

Ah, very nice! This way it will actually work to replace a number
of older drivers that require a specific clock name.

I still think we should change the phy subsystem to allow the
same, that would make it more consistent here, and avoid the
need for coming up with a number of bogus phy names for random
drivers that can only ever have one phy.

	Arnd
Hans de Goede Jan. 9, 2014, 6:18 p.m. UTC | #2
Hi,

On 01/09/2014 07:07 PM, Arnd Bergmann wrote:
> On Thursday 09 January 2014 18:57:05 Hans de Goede wrote:
>> +       if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
>> +               priv->phy = devm_phy_get(&dev->dev, "usb");
>> +               if (IS_ERR(priv->phy)) {
>> +                       err = PTR_ERR(priv->phy);
>> +                       if (err == -EPROBE_DEFER)
>> +                               goto err_put_hcd;
>> +                       priv->phy = NULL;
>> +               }
>> +
>> +               for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
>> +                       priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
>> +                       if (IS_ERR(priv->clks[clk])) {
>> +                               err = PTR_ERR(priv->clks[clk]);
>> +                               if (err == -EPROBE_DEFER)
>> +                                       goto err_put_clks;
>> +                               priv->clks[clk] = NULL;
>> +                               break;
>> +                       }
>> +               }
>> +       }
>
> Ah, very nice! This way it will actually work to replace a number
> of older drivers that require a specific clock name.

I'm glad you like it.
>
> I still think we should change the phy subsystem to allow the
> same, that would make it more consistent here, and avoid the
> need for coming up with a number of bogus phy names for random
> drivers that can only ever have one phy.

I'm not disagreeing, but that will have to be a battle for
another day. Currently the dt-bindings for phy actually
make phy-names mandatory at the bindings-description level, so
someone would first need to change the specification.

Documentation/devicetree/bindings/phy/phy-bindings.txt:

"""
PHY user node
=============

Required Properties:
phys : the phandle for the PHY device (used by the PHY subsystem)
phy-names : the names of the PHY corresponding to the PHYs present in the
             *phys* phandle
"""

Regards,

Hans
Hans de Goede Jan. 9, 2014, 7:48 p.m. UTC | #3
Hi,

On 01/09/2014 09:14 PM, Sergei Shtylyov wrote:
> Hello.
>
> On 01/09/2014 08:57 PM, Hans de Goede wrote:
>
>> Add support for ohci-platform instantiation from devicetree, including
>> optionally getting clks and a phy from devicetree, and enabling / disabling
>> those on power_on / off.
>
>> This should allow using ohci-platform from devicetree in various cases.
>> Specifically after this commit it can be used for the ohci controller found
>> on Allwinner sunxi SoCs.
>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>   .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
>>   drivers/usb/host/ohci-platform.c                   | 150 ++++++++++++++++++---
>>   2 files changed, 152 insertions(+), 20 deletions(-)
>>   create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt
>
>> diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>> new file mode 100644
>> index 0000000..9c776ed
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>> @@ -0,0 +1,22 @@
>> +Generic MMIO OHCI controller
>
>     OHCI controller always uses MMIO, and likewise EHCI. You don't need to specifically mention it.

Right, I'm only using it here because it is also used in the compatible string.

>
>> +
>> +Required properties:
>> +- compatible : "mmio-ohci"
>
>     Likewise, it's not a good name. Why not call it "platform-ohci"?

Because, as you would have known had you read the entire thread, people objected
against exactly that name because the "platform" bus thing is a Linux invention,
and other operating systems don't use the platform nomenclature for non pci
busses.

Regards,

Hans
Sergei Shtylyov Jan. 9, 2014, 8:14 p.m. UTC | #4
Hello.

On 01/09/2014 08:57 PM, Hans de Goede wrote:

> Add support for ohci-platform instantiation from devicetree, including
> optionally getting clks and a phy from devicetree, and enabling / disabling
> those on power_on / off.

> This should allow using ohci-platform from devicetree in various cases.
> Specifically after this commit it can be used for the ohci controller found
> on Allwinner sunxi SoCs.

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>   .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
>   drivers/usb/host/ohci-platform.c                   | 150 ++++++++++++++++++---
>   2 files changed, 152 insertions(+), 20 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt

> diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
> new file mode 100644
> index 0000000..9c776ed
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
> @@ -0,0 +1,22 @@
> +Generic MMIO OHCI controller

    OHCI controller always uses MMIO, and likewise EHCI. You don't need to 
specifically mention it.

> +
> +Required properties:
> +- compatible : "mmio-ohci"

    Likewise, it's not a good name. Why not call it "platform-ohci"?

> +- reg : ohci controller register range (address and length)
> +- interrupts : ohci controller interrupt
> +
> +Optional properties:
> +- clocks : a list of phandle + clock specifier pairs
> +- phys : phandle + phy specifier pair
> +- phy-names : "usb"
> +
> +Example:
> +
> +	ohci0: ohci@0x01c14400 {
> +		compatible = "mmio-ohci";
> +		reg = <0x01c14400 0x100>;
> +		interrupts = <64>;
> +		clocks = <&usb_clk 6>, <&ahb_gates 2>;
> +		phys = <&usbphy 1>;
> +		phy-names = "usb";
> +	};

WBR, Sergei
Alan Stern Jan. 9, 2014, 8:36 p.m. UTC | #5
On Thu, 9 Jan 2014, Hans de Goede wrote:

> Add support for ohci-platform instantiation from devicetree, including
> optionally getting clks and a phy from devicetree, and enabling / disabling
> those on power_on / off.
> 
> This should allow using ohci-platform from devicetree in various cases.
> Specifically after this commit it can be used for the ohci controller found
> on Allwinner sunxi SoCs.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Looking pretty good.  Still a couple of things to address...

> +static struct usb_ohci_pdata ohci_platform_defaults = {
> +	.power_on =		ohci_platform_power_on,
> +	.power_suspend =	ohci_platform_power_off,
> +	.power_off =		ohci_platform_power_off,
>  };

I wonder if these routines couldn't be shared with non-DT setups.  We
could add an array of 3 struct clk pointers to the usb_ohci_pdata
structure.  Then if any of them are set, store these routines in the
power_* pointers.  (And likewise for ehci-platform.)  Something to
consider for a future patch...

> @@ -60,12 +128,24 @@ static int ohci_platform_probe(struct platform_device *dev)
>  	struct usb_hcd *hcd;
>  	struct resource *res_mem;
>  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
> -	int irq;
> -	int err = -ENOMEM;
> +	struct ohci_platform_priv *priv;
> +	int clk, irq, err;
>  
> +	/*
> +	 * Use reasonable defaults so platforms don't have to provide these
> +	 * with DT probing on ARM.
> +	 */
>  	if (!pdata) {
> -		WARN_ON(1);
> -		return -ENODEV;
> +		pdata = dev->dev.platform_data = &ohci_platform_defaults;

This has a subtle bug.  Consider what will happen if ohci-platform is 
loaded, then unloaded and loaded again.

The existing ehci-platform driver has this same bug.  I definitely 
remember discussing at once or twice in the past, but evidently it has 
never been fixed.

> +		/*
> +		 * Right now device-tree probed devices don't get dma_mask set.
> +		 * Since shared usb code relies on it, set it here for now.
> +		 * Once we have dma capability bindings this can go away.
> +		 */
> +		err = dma_coerce_mask_and_coherent(&dev->dev,
> +						   DMA_BIT_MASK(32));
> +		if (err)
> +			return err;

The ehci-platform driver does this even when platform data is present.  
I guess you should do the same thing here (and lose the comment).

(Also, I dislike this alignment of the continuation line.  IMO it's a 
bad idea to match up with some particular element of the preceding 
line.  The style used in most of the USB stack is to indent 
continuation lines by two tab stops.)

>  	}
>  
>  	if (usb_disabled())

This test belongs at the start of the function.  It is more fundamental 
than the stuff you inserted.

> @@ -83,17 +163,39 @@ static int ohci_platform_probe(struct platform_device *dev)
>  		return -ENXIO;
>  	}
>  
> +	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
> +			dev_name(&dev->dev));
> +	if (!hcd)
> +		return -ENOMEM;
> +
> +	priv = (struct ohci_platform_priv *)hcd_to_ohci(hcd)->priv;

Please define an inline routine or a macro for this messy computation.

Alan Stern
Sergei Shtylyov Jan. 9, 2014, 9:08 p.m. UTC | #6
On 01/09/2014 10:48 PM, Hans de Goede wrote:
> Hi,
>
> On 01/09/2014 09:14 PM, Sergei Shtylyov wrote:
>> Hello.
>>
>> On 01/09/2014 08:57 PM, Hans de Goede wrote:
>>
>>> Add support for ohci-platform instantiation from devicetree, including
>>> optionally getting clks and a phy from devicetree, and enabling / disabling
>>> those on power_on / off.
>>
>>> This should allow using ohci-platform from devicetree in various cases.
>>> Specifically after this commit it can be used for the ohci controller found
>>> on Allwinner sunxi SoCs.
>>
>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>> ---
>>>   .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
>>>   drivers/usb/host/ohci-platform.c                   | 150
>>> ++++++++++++++++++---
>>>   2 files changed, 152 insertions(+), 20 deletions(-)
>>>   create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>> b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>> new file mode 100644
>>> index 0000000..9c776ed
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>> @@ -0,0 +1,22 @@
>>> +Generic MMIO OHCI controller

>>     OHCI controller always uses MMIO, and likewise EHCI. You don't need to
>> specifically mention it.

> Right, I'm only using it here because it is also used in the compatible string.

    Please drop it.

>>> +
>>> +Required properties:
>>> +- compatible : "mmio-ohci"

>>     Likewise, it's not a good name. Why not call it "platform-ohci"?

> Because, as you would have known had you read the entire thread, people objected
> against exactly that name because the "platform" bus thing is a Linux invention,
> and other operating systems don't use the platform nomenclature for non pci
> busses.

    I wonder where were all those people when "xhci-platform" compatible got 
adopted in drivers/usb/host/xhci-plat.c? :-P

    Anyway, I want to suggest "usb-[eo]hci" of which "usb-ehci" binding has 
even already documented in Documentation/devicetree/bindings/usb/usb-ehci.txt.
Both these "compatible" values are used as backups in the multiple described 
bindings of the platform-specific [EO]HCI controllers. I really don't see why 
you should invent anything new (and so poorly named).

> Regards,

> Hans

WBR, Sergei
Hans de Goede Jan. 10, 2014, 9:47 a.m. UTC | #7
Hi,

On 01/09/2014 10:08 PM, Sergei Shtylyov wrote:
> On 01/09/2014 10:48 PM, Hans de Goede wrote:
>> Hi,
>>
>> On 01/09/2014 09:14 PM, Sergei Shtylyov wrote:
>>> Hello.
>>>
>>> On 01/09/2014 08:57 PM, Hans de Goede wrote:
>>>
>>>> Add support for ohci-platform instantiation from devicetree, including
>>>> optionally getting clks and a phy from devicetree, and enabling / disabling
>>>> those on power_on / off.
>>>
>>>> This should allow using ohci-platform from devicetree in various cases.
>>>> Specifically after this commit it can be used for the ohci controller found
>>>> on Allwinner sunxi SoCs.
>>>
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>>   .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
>>>>   drivers/usb/host/ohci-platform.c                   | 150
>>>> ++++++++++++++++++---
>>>>   2 files changed, 152 insertions(+), 20 deletions(-)
>>>>   create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>
>>>> diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>> b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>> new file mode 100644
>>>> index 0000000..9c776ed
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>> @@ -0,0 +1,22 @@
>>>> +Generic MMIO OHCI controller
>
>>>     OHCI controller always uses MMIO, and likewise EHCI. You don't need to
>>> specifically mention it.
>
>> Right, I'm only using it here because it is also used in the compatible string.
>
>     Please drop it.
>
>>>> +
>>>> +Required properties:
>>>> +- compatible : "mmio-ohci"
>
>>>     Likewise, it's not a good name. Why not call it "platform-ohci"?
>
>> Because, as you would have known had you read the entire thread, people objected
>> against exactly that name because the "platform" bus thing is a Linux invention,
>> and other operating systems don't use the platform nomenclature for non pci
>> busses.
>
>     I wonder where were all those people when "xhci-platform" compatible got adopted in drivers/usb/host/xhci-plat.c? :-P
>
>     Anyway, I want to suggest "usb-[eo]hci" of which "usb-ehci" binding has even already documented in Documentation/devicetree/bindings/usb/usb-ehci.txt.
> Both these "compatible" values are used as backups in the multiple described bindings of the platform-specific [EO]HCI controllers. I really don't see why you should invent anything new (and so poorly named).

This too has already been discussed, again please read the entire thread including review of earlier versions of the patch.

We cannot usb usb-ehci, because the existing usb-ehci compatible string is not used for a generic usb controller, but
for a ppc specific one which needs model specific setup, see the driver currently implementing compatible = usb-ehci.

Regards,

Hans
Hans de Goede Jan. 10, 2014, 10:13 a.m. UTC | #8
Hi,

On 01/09/2014 09:36 PM, Alan Stern wrote:
> On Thu, 9 Jan 2014, Hans de Goede wrote:
>
>> Add support for ohci-platform instantiation from devicetree, including
>> optionally getting clks and a phy from devicetree, and enabling / disabling
>> those on power_on / off.
>>
>> This should allow using ohci-platform from devicetree in various cases.
>> Specifically after this commit it can be used for the ohci controller found
>> on Allwinner sunxi SoCs.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>
> Looking pretty good.  Still a couple of things to address...
>
>> +static struct usb_ohci_pdata ohci_platform_defaults = {
>> +	.power_on =		ohci_platform_power_on,
>> +	.power_suspend =	ohci_platform_power_off,
>> +	.power_off =		ohci_platform_power_off,
>>   };
>
> I wonder if these routines couldn't be shared with non-DT setups.  We
> could add an array of 3 struct clk pointers to the usb_ohci_pdata
> structure.  Then if any of them are set, store these routines in the
> power_* pointers.  (And likewise for ehci-platform.)  Something to
> consider for a future patch...

I don't like automatically setting the power_ platform_data members much.

But I've already been thinking about moving the clks member to platform_data,
and simply exporting ohci_platform_power_* so that other drivers can use them
and put them in the platform_data members themselves. That is indeed something
for another patch though.

>> @@ -60,12 +128,24 @@ static int ohci_platform_probe(struct platform_device *dev)
>>   	struct usb_hcd *hcd;
>>   	struct resource *res_mem;
>>   	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
>> -	int irq;
>> -	int err = -ENOMEM;
>> +	struct ohci_platform_priv *priv;
>> +	int clk, irq, err;
>>
>> +	/*
>> +	 * Use reasonable defaults so platforms don't have to provide these
>> +	 * with DT probing on ARM.
>> +	 */
>>   	if (!pdata) {
>> -		WARN_ON(1);
>> -		return -ENODEV;
>> +		pdata = dev->dev.platform_data = &ohci_platform_defaults;
>
> This has a subtle bug.  Consider what will happen if ohci-platform is
> loaded, then unloaded and loaded again.

Right, so we need to add a "dev->dev.platform_data == &ohci_platform_defaults"
check on remove an then set platform_data to NULL, good point, will fix in the
next version.

>
> The existing ehci-platform driver has this same bug.  I definitely
> remember discussing at once or twice in the past, but evidently it has
> never been fixed.

If you agree with the above fix I'll also throw it into the next revision
of the ehci patch.

>
>> +		/*
>> +		 * Right now device-tree probed devices don't get dma_mask set.
>> +		 * Since shared usb code relies on it, set it here for now.
>> +		 * Once we have dma capability bindings this can go away.
>> +		 */
>> +		err = dma_coerce_mask_and_coherent(&dev->dev,
>> +						   DMA_BIT_MASK(32));
>> +		if (err)
>> +			return err;
>
> The ehci-platform driver does this even when platform data is present.
> I guess you should do the same thing here (and lose the comment).
>
> (Also, I dislike this alignment of the continuation line.  IMO it's a
> bad idea to match up with some particular element of the preceding
> line.  The style used in most of the USB stack is to indent
> continuation lines by two tab stops.)

Ok, will fix.

>
>>   	}
>>
>>   	if (usb_disabled())
>
> This test belongs at the start of the function.  It is more fundamental
> than the stuff you inserted.
>

Ok, will fix.

>> @@ -83,17 +163,39 @@ static int ohci_platform_probe(struct platform_device *dev)
>>   		return -ENXIO;
>>   	}
>>
>> +	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
>> +			dev_name(&dev->dev));
>> +	if (!hcd)
>> +		return -ENOMEM;
>> +
>> +	priv = (struct ohci_platform_priv *)hcd_to_ohci(hcd)->priv;
>
> Please define an inline routine or a macro for this messy computation.

Ok, will fix.

Before I do a v4, one question:

Ma Haijun does not like the use of OHCI_MAX_CLKS:

 >> +#define OHCI_MAX_CLKS 3
 >
 > I still recommend using of_count_phandle_with_args(np, "clocks",
 > "#clock-cells") to determine the number of clocks or the existence of clocks
 > property (-ENOENT)

His suggestion would mean dynamically allocating the clks array and having
clks_count variable. I still think this is a bit overkill, but I can do that for
v4 if you want, so what do you prefer ?

Regards,

Hans
Alan Stern Jan. 10, 2014, 3:29 p.m. UTC | #9
On Fri, 10 Jan 2014, Hans de Goede wrote:

> >> +static struct usb_ohci_pdata ohci_platform_defaults = {
> >> +	.power_on =		ohci_platform_power_on,
> >> +	.power_suspend =	ohci_platform_power_off,
> >> +	.power_off =		ohci_platform_power_off,
> >>   };
> >
> > I wonder if these routines couldn't be shared with non-DT setups.  We
> > could add an array of 3 struct clk pointers to the usb_ohci_pdata
> > structure.  Then if any of them are set, store these routines in the
> > power_* pointers.  (And likewise for ehci-platform.)  Something to
> > consider for a future patch...
> 
> I don't like automatically setting the power_ platform_data members much.

Me either.

> But I've already been thinking about moving the clks member to platform_data,
> and simply exporting ohci_platform_power_* so that other drivers can use them
> and put them in the platform_data members themselves. That is indeed something
> for another patch though.

It would require building ohci-platform into the kernel instead of 
making it a separate module.  That shouldn't matter much for 
embedded/SoC systems, though.  It seems like a good approach.

> >>   	if (!pdata) {
> >> -		WARN_ON(1);
> >> -		return -ENODEV;
> >> +		pdata = dev->dev.platform_data = &ohci_platform_defaults;
> >
> > This has a subtle bug.  Consider what will happen if ohci-platform is
> > loaded, then unloaded and loaded again.
> 
> Right, so we need to add a "dev->dev.platform_data == &ohci_platform_defaults"
> check on remove an then set platform_data to NULL, good point, will fix in the
> next version.

Exactly.

> > The existing ehci-platform driver has this same bug.  I definitely
> > remember discussing at once or twice in the past, but evidently it has
> > never been fixed.
> 
> If you agree with the above fix I'll also throw it into the next revision
> of the ehci patch.

Thank you.

> Before I do a v4, one question:
> 
> Ma Haijun does not like the use of OHCI_MAX_CLKS:
> 
>  >> +#define OHCI_MAX_CLKS 3
>  >
>  > I still recommend using of_count_phandle_with_args(np, "clocks",
>  > "#clock-cells") to determine the number of clocks or the existence of clocks
>  > property (-ENOENT)
> 
> His suggestion would mean dynamically allocating the clks array and having
> clks_count variable. I still think this is a bit overkill, but I can do that for
> v4 if you want, so what do you prefer ?

Space isn't a big consideration, because we're not likely to see a 
system with more a few controllers.  I say keep it simple.  If someone 
comes up with a controller using more than 3 clocks, we can change to 
dynamic allocation then.

Alan Stern
Sergei Shtylyov Jan. 10, 2014, 10:02 p.m. UTC | #10
Hello.

On 01/10/2014 12:47 PM, Hans de Goede wrote:

> Hi,

    I would like to know why you dropped me from the To: list when replying. I 
have hardly noticed your reply.

>>>>> Add support for ohci-platform instantiation from devicetree, including
>>>>> optionally getting clks and a phy from devicetree, and enabling / disabling
>>>>> those on power_on / off.

>>>>> This should allow using ohci-platform from devicetree in various cases.
>>>>> Specifically after this commit it can be used for the ohci controller found
>>>>> on Allwinner sunxi SoCs.

>>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>>> ---
>>>>>   .../devicetree/bindings/usb/mmio-ohci.txt          |  22 +++
>>>>>   drivers/usb/host/ohci-platform.c                   | 150
>>>>> ++++++++++++++++++---
>>>>>   2 files changed, 152 insertions(+), 20 deletions(-)
>>>>>   create mode 100644 Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>>> b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>>> new file mode 100644
>>>>> index 0000000..9c776ed
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
>>>>> @@ -0,0 +1,22 @@
>>>>> +Generic MMIO OHCI controller

>>>>     OHCI controller always uses MMIO, and likewise EHCI. You don't need to
>>>> specifically mention it.

>>> Right, I'm only using it here because it is also used in the compatible
>>> string.

>>     Please drop it.

>>>>> +
>>>>> +Required properties:
>>>>> +- compatible : "mmio-ohci"

>>>>     Likewise, it's not a good name. Why not call it "platform-ohci"?

>>> Because, as you would have known had you read the entire thread, people
>>> objected
>>> against exactly that name because the "platform" bus thing is a Linux
>>> invention,
>>> and other operating systems don't use the platform nomenclature for non pci
>>> busses.

>>     I wonder where were all those people when "xhci-platform" compatible got
>> adopted in drivers/usb/host/xhci-plat.c? :-P

    I remember I suggested "usb-xhci" but the author didn't want to do it and 
I said that I have no strong opinion (along with Alan Stern, IIRC), so we have 
it now...

>>     Anyway, I want to suggest "usb-[eo]hci" of which "usb-ehci" binding has
>> even already documented in Documentation/devicetree/bindings/usb/usb-ehci.txt.
>> Both these "compatible" values are used as backups in the multiple described
>> bindings of the platform-specific [EO]HCI controllers. I really don't see
>> why you should invent anything new (and so poorly named).

> This too has already been discussed, again please read the entire thread
> including review of earlier versions of the patch.

    Sorry, I have been generally lacking the time to read linux-usb recently.
I only bumped into your patch randomly, despite me being interested in this 
matter for my own platform...

> We cannot usb usb-ehci, because the existing usb-ehci compatible string is not
> used for a generic usb controller, but
> for a ppc specific one  which needs model specific setup, see the driver
> currently implementing compatible = usb-ehci.

    Not true about it being entirely PPC specific: the driver actually looks 
for another "compatible" property to make it truly PPC specific (and apply 
some errata fixes for that specific PPC platform) and "usb-ehci" is used in 
many non-PPC binding examples as a backup still. Valentine Barshak's did his 
work on ehci-ppc-of.c when DT was used only on PPC and SPARC, so it was kind 
of a honest mistake on his part to name the driver so that people would think 
it's PPC specific (not only his, it seems, as the driver was based on the 
other two). This does not seem a fatal mistake, and we could limit the driver 
to match only on that IBM 440EPx platform it was designed for and tested on, 
making ehci-platform.c handle "usb-ehci". This is more work but I believe it's 
the Right Thing. The problem is that we'll have to do this atomically with 
ehci-platform.c change since 2 other PPC platforms use "usb-ehci" as a backup 
to their specific "compatible" props and don't have the platform-specific 
drivers for them, and we probably wouldn't want to break them.
I would like to help you here but the matter is not urgent for me, so cannot 
work on it right now... :-(
    Anyway, I'm strongly against such names as "mmio-[eo]hci". But I could 
live with just "[eo]hci" if you don't follow my advice and unravel the 
ehci-ppc-of.c knot...

> Regards,

> Hans

WBR, Sergei
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/usb/mmio-ohci.txt b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
new file mode 100644
index 0000000..9c776ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mmio-ohci.txt
@@ -0,0 +1,22 @@ 
+Generic MMIO OHCI controller
+
+Required properties:
+- compatible : "mmio-ohci"
+- reg : ohci controller register range (address and length)
+- interrupts : ohci controller interrupt
+
+Optional properties:
+- clocks : a list of phandle + clock specifier pairs
+- phys : phandle + phy specifier pair
+- phy-names : "usb"
+
+Example:
+
+	ohci0: ohci@0x01c14400 {
+		compatible = "mmio-ohci";
+		reg = <0x01c14400 0x100>;
+		interrupts = <64>;
+		clocks = <&usb_clk 6>, <&ahb_gates 2>;
+		phys = <&usbphy 1>;
+		phy-names = "usb";
+	};
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index f351ff5..a46d7ac 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -3,6 +3,7 @@ 
  *
  * Copyright 2007 Michael Buesch <m@bues.ch>
  * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
  *
  * Derived from the OCHI-SSB driver
  * Derived from the OHCI-PCI driver
@@ -14,11 +15,14 @@ 
  * Licensed under the GNU/GPL. See COPYING for details.
  */
 
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/hrtimer.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/err.h>
+#include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ohci_pdriver.h>
 #include <linux/usb.h>
@@ -28,6 +32,12 @@ 
 
 #define DRIVER_DESC "OHCI generic platform driver"
 
+#define OHCI_MAX_CLKS 3
+struct ohci_platform_priv {
+	struct clk *clks[OHCI_MAX_CLKS];
+	struct phy *phy;
+};
+
 static const char hcd_name[] = "ohci-platform";
 
 static int ohci_platform_reset(struct usb_hcd *hcd)
@@ -48,11 +58,69 @@  static int ohci_platform_reset(struct usb_hcd *hcd)
 	return ohci_setup(hcd);
 }
 
+static int ohci_platform_power_on(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct ohci_platform_priv *priv =
+		(struct ohci_platform_priv *)hcd_to_ohci(hcd)->priv;
+	int clk, ret;
+
+	for (clk = 0; priv->clks[clk] && clk < OHCI_MAX_CLKS; clk++) {
+		ret = clk_prepare_enable(priv->clks[clk]);
+		if (ret)
+			goto err_disable_clks;
+	}
+
+	if (priv->phy) {
+		ret = phy_init(priv->phy);
+		if (ret)
+			goto err_disable_clks;
+
+		ret = phy_power_on(priv->phy);
+		if (ret)
+			goto err_exit_phy;
+	}
+
+	return 0;
+
+err_exit_phy:
+	phy_exit(priv->phy);
+err_disable_clks:
+	while (--clk >= 0)
+		clk_disable_unprepare(priv->clks[clk]);
+
+	return ret;
+}
+
+static void ohci_platform_power_off(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct ohci_platform_priv *priv =
+		(struct ohci_platform_priv *)hcd_to_ohci(hcd)->priv;
+	int clk;
+
+	if (priv->phy) {
+		phy_power_off(priv->phy);
+		phy_exit(priv->phy);
+	}
+
+	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
+		if (priv->clks[clk])
+			clk_disable_unprepare(priv->clks[clk]);
+}
+
 static struct hc_driver __read_mostly ohci_platform_hc_driver;
 
 static const struct ohci_driver_overrides platform_overrides __initconst = {
-	.product_desc =	"Generic Platform OHCI controller",
-	.reset =	ohci_platform_reset,
+	.product_desc =		"Generic Platform OHCI controller",
+	.reset =		ohci_platform_reset,
+	.extra_priv_size =	sizeof(struct ohci_platform_priv),
+};
+
+static struct usb_ohci_pdata ohci_platform_defaults = {
+	.power_on =		ohci_platform_power_on,
+	.power_suspend =	ohci_platform_power_off,
+	.power_off =		ohci_platform_power_off,
 };
 
 static int ohci_platform_probe(struct platform_device *dev)
@@ -60,12 +128,24 @@  static int ohci_platform_probe(struct platform_device *dev)
 	struct usb_hcd *hcd;
 	struct resource *res_mem;
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
-	int irq;
-	int err = -ENOMEM;
+	struct ohci_platform_priv *priv;
+	int clk, irq, err;
 
+	/*
+	 * Use reasonable defaults so platforms don't have to provide these
+	 * with DT probing on ARM.
+	 */
 	if (!pdata) {
-		WARN_ON(1);
-		return -ENODEV;
+		pdata = dev->dev.platform_data = &ohci_platform_defaults;
+		/*
+		 * Right now device-tree probed devices don't get dma_mask set.
+		 * Since shared usb code relies on it, set it here for now.
+		 * Once we have dma capability bindings this can go away.
+		 */
+		err = dma_coerce_mask_and_coherent(&dev->dev,
+						   DMA_BIT_MASK(32));
+		if (err)
+			return err;
 	}
 
 	if (usb_disabled())
@@ -83,17 +163,39 @@  static int ohci_platform_probe(struct platform_device *dev)
 		return -ENXIO;
 	}
 
+	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
+			dev_name(&dev->dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	priv = (struct ohci_platform_priv *)hcd_to_ohci(hcd)->priv;
+
+	if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
+		priv->phy = devm_phy_get(&dev->dev, "usb");
+		if (IS_ERR(priv->phy)) {
+			err = PTR_ERR(priv->phy);
+			if (err == -EPROBE_DEFER)
+				goto err_put_hcd;
+			priv->phy = NULL;
+		}
+
+		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
+			priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
+			if (IS_ERR(priv->clks[clk])) {
+				err = PTR_ERR(priv->clks[clk]);
+				if (err == -EPROBE_DEFER)
+					goto err_put_clks;
+				priv->clks[clk] = NULL;
+				break;
+			}
+		}
+	}
+
+	platform_set_drvdata(dev, hcd);
 	if (pdata->power_on) {
 		err = pdata->power_on(dev);
 		if (err < 0)
-			return err;
-	}
-
-	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
-			dev_name(&dev->dev));
-	if (!hcd) {
-		err = -ENOMEM;
-		goto err_power;
+			goto err_put_clks;
 	}
 
 	hcd->rsrc_start = res_mem->start;
@@ -102,21 +204,22 @@  static int ohci_platform_probe(struct platform_device *dev)
 	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
 	if (IS_ERR(hcd->regs)) {
 		err = PTR_ERR(hcd->regs);
-		goto err_put_hcd;
+		goto err_power;
 	}
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err)
-		goto err_put_hcd;
-
-	platform_set_drvdata(dev, hcd);
+		goto err_power;
 
 	return err;
 
-err_put_hcd:
-	usb_put_hcd(hcd);
 err_power:
 	if (pdata->power_off)
 		pdata->power_off(dev);
+err_put_clks:
+	while (--clk >= 0)
+		clk_disable_unprepare(priv->clks[clk]);
+err_put_hcd:
+	usb_put_hcd(hcd);
 
 	return err;
 }
@@ -178,6 +281,12 @@  static int ohci_platform_resume(struct device *dev)
 #define ohci_platform_resume	NULL
 #endif /* CONFIG_PM */
 
+static const struct of_device_id ohci_platform_ids[] = {
+	{ .compatible = "mmio-ohci", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ohci_platform_ids);
+
 static const struct platform_device_id ohci_platform_table[] = {
 	{ "ohci-platform", 0 },
 	{ }
@@ -198,6 +307,7 @@  static struct platform_driver ohci_platform_driver = {
 		.owner	= THIS_MODULE,
 		.name	= "ohci-platform",
 		.pm	= &ohci_platform_pm_ops,
+		.of_match_table = ohci_platform_ids,
 	}
 };