[V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller

Mark Rutland mark.rutland at arm.com
Wed Feb 6 09:42:16 EST 2013


Hi,

I have a few comments on the devicetree binding and the way it's parsed.

I note many are similar to those I commented on for the mv_udc and ehci-mv
devicetree code.

On Wed, Feb 06, 2013 at 07:23:36AM +0000, Chao Xie wrote:
> The PHY is seperated from usb controller.
> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
> but PHY initialization may be different.
> the usb controller can support udc/otg/ehci, and for each of
> the mode, it need PHY to initialized before use the controller.
> Direclty writing the phy driver will make the usb controller
> driver to be simple and portable.
> The PHY driver will be used by marvell udc/otg/ehci.
> 
> Signed-off-by: Chao Xie <chao.xie at marvell.com>
> ---
>  drivers/usb/phy/Kconfig              |    7 +
>  drivers/usb/phy/Makefile             |    1 +
>  drivers/usb/phy/mv_usb2_phy.c        |  454 ++++++++++++++++++++++++++++++++++
>  include/linux/platform_data/mv_usb.h |    9 +-
>  include/linux/usb/mv_usb2.h          |   43 ++++
>  5 files changed, 511 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>  create mode 100644 include/linux/usb/mv_usb2.h


[...]

> +static struct of_device_id usb_phy_dt_ids[] = {
> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void *)PXA168_USB},
> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void *)PXA910_USB},
> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void *)MMP2_USB},
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);

The binding (including these compatible string) needs to be documented.

> +
> +static int usb_phy_parse_dt(struct platform_device *pdev,
> +                               struct mv_usb2_phy *mv_phy)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       const struct of_device_id *of_id =
> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
> +       unsigned int clks_num;
> +       int i, ret;
> +       const char *clk_name;
> +
> +       if (!np)
> +               return 1;

An actual error code please.

-ENODEV? -EINVAL?

> +
> +       clks_num = of_property_count_strings(np, "clocks");
> +       if (clks_num < 0) {
> +               dev_err(&pdev->dev, "failed to get clock number\n");
> +               return clks_num;
> +       }

The common clock bindings use "clocks" as a list of phandle and clock-specifier
pairs. It seems bad to reuse that name in a different sense for this binding.

I'd recommend you use the common clock binding. There doesn't seem to be an
of_clk_count, but it should be a relatively simple addition, and it'd make this
code clearer and more consistent with other drivers.

See Documentation/devicetree/bindings/clock/clock-bindings.txt

> +
> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
> +       if (mv_phy->clks == NULL) {
> +               dev_err(&pdev->dev,
> +                       "failed to allocate mempory for clocks");

s/mempory/memory/

> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < clks_num; i++) {
> +               ret = of_property_read_string_index(np, "clocks", i,
> +                       &clk_name);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "failed to read clocks\n");
> +                       return ret;
> +               }
> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
> +               if (IS_ERR(mv_phy->clks[i])) {
> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
> +                               clk_name);
> +                       return PTR_ERR(mv_phy->clks[i]);
> +               }
> +       }
> +
> +       mv_phy->clks_num = clks_num;
> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
> +
> +       return 0;
> +}

There's probably a need for something like devm_of_clk_get to make it easier to
write of-backed drivers.

> +
> +static int usb_phy_probe(struct platform_device *pdev)
> +{
> +       struct mv_usb2_phy *mv_phy;
> +       struct resource *r;
> +       int ret, i;
> +
> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
> +       if (mv_phy == NULL) {
> +               dev_err(&pdev->dev, "failed to allocate memory\n");
> +               return -ENOMEM;
> +       }
> +       mutex_init(&mv_phy->phy_lock);
> +
> +       ret = usb_phy_parse_dt(pdev, mv_phy);
> +       /* no CONFIG_OF */
> +       if (ret > 0) {

Reorganise this so you test for pdev->dev.of_node, and based of that you either
call usb_phy_parse_dt or do this stuff in the block below. That way you don't need
the positive return code from usb_phy_parse_dt.

> +               struct mv_usb_phy_platform_data *pdata
> +                               = pdev->dev.platform_data;
> +               const struct platform_device_id *id
> +                               = platform_get_device_id(pdev);
> +
> +               if (pdata == NULL || id == NULL) {
> +                       dev_err(&pdev->dev,
> +                               "missing platform_data or id_entry\n");
> +                       return -ENODEV;
> +               }
> +               mv_phy->type = (unsigned int)(id->driver_data);
> +               mv_phy->clks_num = pdata->clknum;
> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
> +                       sizeof(struct clk *) * mv_phy->clks_num, GFP_KERNEL);
> +               if (mv_phy->clks == NULL) {
> +                       dev_err(&pdev->dev,
> +                               "failed to allocate mempory for clocks");

s/mempory/memory/

> +                       return -ENOMEM;
> +               }
> +               for (i = 0; i < mv_phy->clks_num; i++)
> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
> +                                                       pdata->clkname[i]);
> +                       if (IS_ERR(mv_phy->clks[i])) {
> +                               dev_err(&pdev->dev, "failed to get clock %s\n",
> +                                       pdata->clkname[i]);
> +                               return PTR_ERR(mv_phy->clks[i]);
> +                       }
> +       } else if (ret < 0) {
> +               dev_err(&pdev->dev, "error parse dt\n");

s/parse/parsing/

> +               return ret;
> +       }
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (r == NULL) {
> +               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
> +               return -ENODEV;
> +       }
> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
> +       if (mv_phy->base == NULL) {
> +               dev_err(&pdev->dev, "error map register base\n");

s/map/mapping/

> +               return -EBUSY;
> +       }
> +       platform_set_drvdata(pdev, mv_phy);
> +       mv_phy->pdev = pdev;
> +       mv_phy->init = usb_phy_init;
> +       mv_phy->shutdown = usb_phy_shutdown;
> +
> +       platform_set_drvdata(pdev, mv_phy);
> +
> +       the_phy = mv_phy;
> +
> +       dev_info(&pdev->dev, "mv usb2 phy initialized\n");
> +
> +       return 0;
> +}
> +
> +static int usb_phy_remove(struct platform_device *pdev)
> +{
> +       the_phy = NULL;
> +
> +       return 0;
> +}

Is mv_usb2_phy large? Why does it need to be dynamically allocated / freed at
all given it's treated as a singleton?

[...]

Thanks,
Mark.





More information about the linux-arm-kernel mailing list