Re: [PATCHv2 1/2] usb: ohci-platform: add support for multiple phys per controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thank you for the comments Alan

On 15-01-06 07:45 AM, Alan Stern wrote:
On Thu, 11 Dec 2014 arun.ramamurthy@xxxxxxxxxxxx wrote:

From: Arun Ramamurthy <arunrama@xxxxxxxxxxxx>

Added support for cases where one controller is connected
to multiple phys

Will this continue to work on systems that use only one PHY?  What
about systems that don't use DT?

Yes, It should work on systems that use only one phy but I see now that I have not accounted for the non DT case. I will rework the patch to include that and address your other comments.

diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 4369299..eef82f1 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -38,7 +38,8 @@
  struct ohci_platform_priv {
  	struct clk *clks[OHCI_MAX_CLKS];
  	struct reset_control *rst;
-	struct phy *phy;
+	struct phy *phys;

Is this supposed to be an array of phy _structures_ or an array of
_pointers_ to phy structures?  The code says an array of structures,
which seems very suspicious.  Why copy phy structures into your own
private array?

+	int num_phys;
  };

  static const char hcd_name[] = "ohci-platform";
@@ -61,7 +62,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
  {
  	struct usb_hcd *hcd = platform_get_drvdata(dev);
  	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk, ret;
+	int clk, ret, phy_num;

  	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
  		ret = clk_prepare_enable(priv->clks[clk]);
@@ -69,20 +70,28 @@ static int ohci_platform_power_on(struct platform_device *dev)
  			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)
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		ret = phy_init(&priv->phys[phy_num]);
+		if (ret) {
+			if (phy_num == 0)
+				goto err_disable_clks;
+			else
+				goto err_exit_phy;

You don't need this "if" statement.  Just goto err_exit_phy always; it
will do the right thing.

+		}
+		ret = phy_power_on(&priv->phys[phy_num]);
+		if (ret) {
+			phy_exit(&priv->phys[phy_num]);
  			goto err_exit_phy;
+		}
  	}

  	return 0;

  err_exit_phy:
-	phy_exit(priv->phy);
+	while (--phy_num >= 0) {
+		phy_power_off(&priv->phys[phy_num]);
+		phy_exit(&priv->phys[phy_num]);
+	};
  err_disable_clks:
  	while (--clk >= 0)
  		clk_disable_unprepare(priv->clks[clk]);
@@ -94,11 +103,11 @@ static void ohci_platform_power_off(struct platform_device *dev)
  {
  	struct usb_hcd *hcd = platform_get_drvdata(dev);
  	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk;
+	int clk, phy_num;

-	if (priv->phy) {
-		phy_power_off(priv->phy);
-		phy_exit(priv->phy);
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		phy_power_off(&priv->phys[phy_num]);
+		phy_exit(&priv->phys[phy_num]);
  	}

  	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -127,7 +136,9 @@ static int ohci_platform_probe(struct platform_device *dev)
  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
  	struct ohci_platform_priv *priv;
  	struct ohci_hcd *ohci;
-	int err, irq, clk = 0;
+	struct phy *temp_phy;
+	const char *phy_name;
+	int err, irq, phy_num, clk = 0;

  	if (usb_disabled())
  		return -ENODEV;
@@ -175,12 +186,29 @@ static int ohci_platform_probe(struct platform_device *dev)
  		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
  			ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;

-		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;
+		priv->num_phys = of_count_phandle_with_args
+		  (dev->dev.of_node, "phys", "#phy-cells");

It's things like this that make me question whether this patch will
work correctly.  What about systems that don't use OF but do use
devm_phy_get()?

Also, the line break is at a strange place (just before the open paren
of a function call), and the indentation of the continuation line is
unusual.

+		if (priv->num_phys > 0) {
+			priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+						sizeof(struct phy), GFP_KERNEL);

Here again the indentation is unusual.  In this file, continuation
lines are indented by 2 tab stops beyond the statement's opening line.
Not 3.

What happens if the memory allocation fails?

+			for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+				err = of_property_read_string_index(
+						dev->dev.of_node,
+						"phy-names", phy_num,
+						&phy_name);
+				if (err < 0) {
+					dev_err(&dev->dev, "Phy-names not provided");
+					goto err_put_hcd;
+				}
+
+				temp_phy = devm_of_phy_get(&dev->dev,
+						dev->dev.of_node, phy_name);
+				if (IS_ERR(temp_phy)) {
+					err = PTR_ERR(temp_phy);
+					goto err_put_hcd;
+				} else
+					priv->phys[phy_num] = *temp_phy;
+			}
  		}

  		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {

Similar comments apply to the 2/2 patch.

Alan Stern


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux