[PATCH 2/3] USB: add of_platform glue driver for FSL USB DR controller

Grant Likely grant.likely at secretlab.ca
Thu Jul 29 04:14:14 EST 2010


On Wed, Jul 28, 2010 at 5:58 AM, Anatolij Gustschin <agust at denx.de> wrote:
> Hi Grant,
>
> On Wed, 28 Jul 2010 02:16:08 -0600
> Grant Likely <grant.likely at secretlab.ca> wrote:
>
>> On Thu, Jul 22, 2010 at 10:25 AM, Anatolij Gustschin <agust at denx.de> wrote:
>> > The driver creates platform devices based on the information
>> > from USB nodes in the flat device tree. This is the replacement
>> > for old arch fsl_soc usb code removed by the previous patch.
>> > It uses usual of-style binding, available EHCI-HCD and UDC
>> > drivers can be bound to the created devices. The new of-style
>> > driver additionaly instantiates USB OTG platform device, as the
>> > appropriate USB OTG driver will be added soon.
>> >
>> > Signed-off-by: Anatolij Gustschin <agust at denx.de>
>> > Cc: Kumar Gala <galak at kernel.crashing.org>
>> > Cc: Grant Likely <grant.likely at secretlab.ca>
>>
>> Hi Anatolij,
>>
>> Looks pretty good, but some comments below.
>
> Thanks for review and comments! Greg already merged this series and
> therefore I'll submit an incremental cleanup patch to address
> outstanding issues. My reply is below.

Greg maintains a patchwork tree IIRC.  I believe he drops patches from
his linux-next branch if they need to be reworked.  Greg, do I have
this right?

Also, my preference would be to see some 3rd party testing before
committing to having this merged.

>
> ...
>> > --- a/drivers/usb/host/Kconfig
>> > +++ b/drivers/usb/host/Kconfig
>> > @@ -112,10 +112,15 @@ config XPS_USB_HCD_XILINX
>> >                support both high speed and full speed devices, or high speed
>> >                devices only.
>> >
>> > +config USB_FSL_MPH_DR_OF
>> > +       bool
>> > +       depends on PPC_OF
>>
>> Drop the depends.  This is selected by USB_EHCI_FSL and
>> USB_GADGET_FSL_USB2, which are already PPC only.
>
> Okay, will remove it.
>
> ...
>> > +struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = {
>> > +       {
>> > +               "host",
>> > +               { "fsl-ehci", NULL, NULL, },
>> > +               FSL_USB2_DR_HOST,
>> > +       },
>> > +       {
>> > +               "otg",
>> > +               { "fsl-ehci", "fsl-usb2-udc", "fsl-usb2-otg", },
>> > +               FSL_USB2_DR_OTG,
>> > +       },
>> > +       {
>> > +               "periferal",
>>
>> spelling.  "peripheral"
>
> Right, thanks for catching! Will fix it.
>
>>
>> > +               { "fsl-usb2-udc", NULL, NULL, },
>> > +               FSL_USB2_DR_DEVICE,
>> > +       },
>> > +};
>>
>> Program defensively.  Use the following form:
>> +       {
>> +               .dr_mode = "host",
>> +               .drivers = { "fsl-ehci", NULL, NULL, },
>> +               .op_mode = FSL_USB2_DR_HOST,
>> +       },
>
> I'll change it too as suggested.
>
> ...
>> > +struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np)
>> > +{
>> > +       const unsigned char *prop;
>> > +       int i;
>> > +
>> > +       prop = of_get_property(np, "dr_mode", NULL);
>> > +       if (prop) {
>> > +               for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
>> > +                       if (!strcmp(prop, dr_mode_data[i].dr_mode))
>> > +                               return &dr_mode_data[i];
>> > +               }
>>
>> Print a warning if you get through the loop, but don't match anything.
>>  That means that dr_mode has a bad value.
>
> I'll add a warning here.
>
> ...
>> > +struct platform_device * __devinit
>> > +fsl_usb2_device_register(struct of_device *ofdev,
>> > +                        struct fsl_usb2_platform_data *pdata,
>> > +                        const char *name, int id)
>>
>> In general, it is better to have the function name on the same line as
>> the return arguements so that grep shows the relevant info.  Move the
>> arguments to subsequent lines.
>
> It will be fixed in a clean-up patch.
>
> ...
>> > +static int __devinit fsl_usb2_mph_dr_of_probe(struct of_device *ofdev,
>> > +                                          const struct of_device_id *match)
>> > +{
>> > +       struct device_node *np = ofdev->dev.of_node;
>> > +       struct platform_device *usb_dev;
>> > +       struct fsl_usb2_platform_data data, *pdata;
>> > +       struct fsl_usb2_dev_data *dev_data;
>> > +       const unsigned char *prop;
>> > +       static unsigned int idx;
>> > +       int i;
>> > +
>> > +       if (!of_device_is_available(np))
>> > +               return -ENODEV;
>>
>> What is this for?
>
> Anton already answered this question better than I could do.
>
>> > +
>> > +       pdata = match->data;
>> > +       if (!pdata) {
>>
>> The match table doesn't have any data, so this is a no-op.
>
> The next patch [PATCH 3/3] of the series adds the data to the
> match table.
>
> ...
>> > +       if (of_device_is_compatible(np, "fsl-usb2-mph")) {
>> > +               prop = of_get_property(np, "port0", NULL);
>> > +               if (prop)
>>
>> if (of_get_property())
>>
>> > +                       pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
>> > +
>> > +               prop = of_get_property(np, "port1", NULL);
>> > +               if (prop)
>>
>> Ditto
>
> Okay, I'll clean this up.
>
> ...
>> > +static struct of_platform_driver fsl_usb2_mph_dr_driver = {
>> > +       .driver = {
>> > +               .name = "fsl-usb2-mph-dr",
>> > +               .owner = THIS_MODULE,
>> > +               .of_match_table = fsl_usb2_mph_dr_of_match,
>> > +       },
>> > +       .probe  = fsl_usb2_mph_dr_of_probe,
>> > +};
>>
>> No remove hook?
>
> Since the purpose of the driver is only creation of platform devices
> according to the selected dual role controller mode described in
> the device tree, I do not see much sense of making the driver a module
> and provide a remove hook for destruction of created devices.

It is still appropriate to have a remove function so the driver can be
unbound.  The remove function should unregister the platform devices
it created in .probe().

>
> ...
>> > +static int __init fsl_usb2_mph_dr_init(void)
>> > +{
>> > +       return of_register_platform_driver(&fsl_usb2_mph_dr_driver);
>> > +}
>> > +fs_initcall(fsl_usb2_mph_dr_init);
>>
>> Why fs_initcall?  Is module_init() not sufficient?
>
> No. Using module_init() here results in initializing the driver after
> loading FLS USB OTG and EHCI-FSL drivers and reverted probing: probe()
> in EHCI-FSL driver is called before probe() in OTG driver and doesn't
> find OTG transceiver resource which is set and exported by probe() in
> OTG driver. This breaks both USB host and device controller support
> if dual role controller is configured to operate in OTG mode.

This is still broken then, and it is just luck that it is even working
now.  The three sub-devices are registered in sequence which should
handle your ordering issues if you put the OTG driver at the start of
the list; but even that is rather hacky.  You need to make the
EHCI-FSL drivers defer initialization if it has to wait for the OTG
driver.  One option might be to use a bus notifier for this.

I won't nack this patch because of this problem because the problem
already exists in the current code, but it really does need to be
fixed.

g.


More information about the Linuxppc-dev mailing list