From 6be109b31ccdb9c98e7be12687171f6602527a5d Mon Sep 17 00:00:00 2001 From: Arun Ramamurthy Date: Wed, 22 Apr 2015 16:04:11 -0700 Subject: phy: core: Add devm_of_phy_get_by_index to phy-core Some generic drivers, such as ehci, may use multiple phys and for such drivers referencing phy(s) by name(s) does not make sense. Instead of inventing new naming schemes and using custom code to iterate through them, such drivers are better of using nameless phy bindings and using this newly introduced API to iterate through them. Signed-off-by: Arun Ramamurthy Reviewed-by: Ray Jui Reviewed-by: Scott Branden [kishon@ti.com: fix compilation errors] Signed-off-by: Kishon Vijay Abraham I --- Documentation/phy.txt | 7 ++++++- drivers/phy/phy-core.c | 32 ++++++++++++++++++++++++++++++++ include/linux/phy/phy.h | 9 +++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Documentation/phy.txt b/Documentation/phy.txt index 371361c69a4b..b388c5af9e72 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -76,6 +76,8 @@ struct phy *phy_get(struct device *dev, const char *string); struct phy *phy_optional_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_optional_get(struct device *dev, const char *string); +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index); phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can be used to get the PHY. In the case of dt boot, the string arguments @@ -86,7 +88,10 @@ successful PHY get. On driver detach, release function is invoked on the the devres data and devres data is freed. phy_optional_get and devm_phy_optional_get should be used when the phy is optional. These two functions will never return -ENODEV, but instead returns NULL when -the phy cannot be found. +the phy cannot be found.Some generic drivers, such as ehci, may use multiple +phys and for such drivers referencing phy(s) by name(s) does not make sense. In +this case, devm_of_phy_get_by_index can be used to get a phy reference based on +the index. It should be noted that NULL is a valid phy reference. All phy consumer calls on the NULL phy become NOPs. That is the release calls, diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 3791838f4bd4..964a84d5a580 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -622,6 +622,38 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, } EXPORT_SYMBOL_GPL(devm_of_phy_get); +/** + * devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index. + * @dev: device that requests this phy + * @np: node containing the phy + * @index: index of the phy + * + * Gets the phy using _of_phy_get(), and associates a device with it using + * devres. On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + */ +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index) +{ + struct phy **ptr, *phy; + + ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + phy = _of_phy_get(np, index); + if (!IS_ERR(phy)) { + *ptr = phy; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return phy; +} +EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index); + /** * phy_create() - create a new phy * @dev: device that is creating the new phy diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index a0197fa1b116..8cf05e341cff 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -133,6 +133,8 @@ struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_optional_get(struct device *dev, const char *string); struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, const char *con_id); +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index); void phy_put(struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_get(struct device_node *np, const char *con_id); @@ -261,6 +263,13 @@ static inline struct phy *devm_of_phy_get(struct device *dev, return ERR_PTR(-ENOSYS); } +static inline struct phy *devm_of_phy_get_by_index(struct device *dev, + struct device_node *np, + int index) +{ + return ERR_PTR(-ENOSYS); +} + static inline void phy_put(struct phy *phy) { } -- cgit v1.2.3 From 216e299269c1ec16a241eaba3620b9c6e65385eb Mon Sep 17 00:00:00 2001 From: Arun Ramamurthy Date: Wed, 22 Apr 2015 16:04:12 -0700 Subject: usb: ehci-platform: Use devm_of_phy_get_by_index Getting phys by index instead of phy names so that we do not have to create a naming scheme when multiple phys are present Signed-off-by: Arun Ramamurthy Reviewed-by: Ray Jui Reviewed-by: Scott Branden Acked-by: Alan Stern Signed-off-by: Kishon Vijay Abraham I --- drivers/usb/host/ehci-platform.c | 69 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index d8a75a51d6d4..145bf19ec283 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -88,15 +88,13 @@ static int ehci_platform_power_on(struct platform_device *dev) } for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - if (priv->phys[phy_num]) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } + ret = phy_init(priv->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(priv->phys[phy_num]); + if (ret) { + phy_exit(priv->phys[phy_num]); + goto err_exit_phy; } } @@ -104,10 +102,8 @@ static int ehci_platform_power_on(struct platform_device *dev) err_exit_phy: while (--phy_num >= 0) { - if (priv->phys[phy_num]) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); } err_disable_clks: while (--clk >= 0) @@ -123,10 +119,8 @@ static void ehci_platform_power_off(struct platform_device *dev) int clk, phy_num; for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - if (priv->phys[phy_num]) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); } for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) @@ -154,7 +148,6 @@ static int ehci_platform_probe(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv; struct ehci_hcd *ehci; - const char *phy_name; int err, irq, phy_num, clk = 0; if (usb_disabled()) @@ -204,36 +197,22 @@ static int ehci_platform_probe(struct platform_device *dev) priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, "phys", "#phy-cells"); - priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1; - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; + if (priv->num_phys > 0) { + priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + } else + priv->num_phys = 0; 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) { - if (priv->num_phys > 1) { - dev_err(&dev->dev, "phy-names not provided"); - goto err_put_hcd; - } else - phy_name = "usb"; - } - - priv->phys[phy_num] = devm_phy_get(&dev->dev, - phy_name); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - if ((priv->num_phys > 1) || - (err == -EPROBE_DEFER)) - goto err_put_hcd; - priv->phys[phy_num] = NULL; - } + priv->phys[phy_num] = devm_of_phy_get_by_index( + &dev->dev, dev->dev.of_node, phy_num); + if (IS_ERR(priv->phys[phy_num])) { + err = PTR_ERR(priv->phys[phy_num]); + goto err_put_hcd; + } } for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { -- cgit v1.2.3 From a666f7d097486bb74f9b02d6d049c1e5a765fa61 Mon Sep 17 00:00:00 2001 From: Arun Ramamurthy Date: Wed, 22 Apr 2015 16:04:13 -0700 Subject: usb: ohci-platform: Use devm_of_phy_get_by_index Getting phys by index instead of phy names so that we do not have to create a naming scheme when multiple phys are present Signed-off-by: Arun Ramamurthy Reviewed-by: Ray Jui Reviewed-by: Scott Branden Acked-by: Alan Stern Signed-off-by: Kishon Vijay Abraham I --- drivers/usb/host/ohci-platform.c | 69 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 185ceee52d47..c2669f185f65 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -57,15 +57,13 @@ static int ohci_platform_power_on(struct platform_device *dev) } for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - if (priv->phys[phy_num]) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } + ret = phy_init(priv->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(priv->phys[phy_num]); + if (ret) { + phy_exit(priv->phys[phy_num]); + goto err_exit_phy; } } @@ -73,10 +71,8 @@ static int ohci_platform_power_on(struct platform_device *dev) err_exit_phy: while (--phy_num >= 0) { - if (priv->phys[phy_num]) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); } err_disable_clks: while (--clk >= 0) @@ -92,10 +88,8 @@ static void ohci_platform_power_off(struct platform_device *dev) int clk, phy_num; for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - if (priv->phys[phy_num]) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->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--) @@ -123,7 +117,6 @@ 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; - const char *phy_name; int err, irq, phy_num, clk = 0; if (usb_disabled()) @@ -174,36 +167,22 @@ static int ohci_platform_probe(struct platform_device *dev) priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, "phys", "#phy-cells"); - priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1; - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; + if (priv->num_phys > 0) { + priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + } else + priv->num_phys = 0; 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) { - if (priv->num_phys > 1) { - dev_err(&dev->dev, "phy-names not provided"); - goto err_put_hcd; - } else - phy_name = "usb"; - } - - priv->phys[phy_num] = devm_phy_get(&dev->dev, - phy_name); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - if ((priv->num_phys > 1) || - (err == -EPROBE_DEFER)) - goto err_put_hcd; - priv->phys[phy_num] = NULL; - } + priv->phys[phy_num] = devm_of_phy_get_by_index( + &dev->dev, dev->dev.of_node, phy_num); + if (IS_ERR(priv->phys[phy_num])) { + err = PTR_ERR(priv->phys[phy_num]); + goto err_put_hcd; + } } for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { -- cgit v1.2.3 From 87006dd600e36e05a2bd978c112a0aa883713c00 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Apr 2015 16:14:37 -0700 Subject: phy: phy-core: allow specifying supply at port level Multi-port phys may have per port power supplies. Let's change phy core to look for supply at the port level when multiple ports are specified. To keep compatibility with the existing device tree board descriptions for single-port phys we will continue looking up the power supply at the parent node level Signed-off-by: Dmitry Torokhov Signed-off-by: Arun Ramamurthy Reviewed-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-core.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 964a84d5a580..5f729bb0788f 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -683,16 +683,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node, goto free_phy; } - /* phy-supply */ - phy->pwr = regulator_get_optional(dev, "phy"); - if (IS_ERR(phy->pwr)) { - if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto free_ida; - } - phy->pwr = NULL; - } - device_initialize(&phy->dev); mutex_init(&phy->mutex); @@ -706,6 +696,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node, if (ret) goto put_dev; + /* phy-supply */ + phy->pwr = regulator_get_optional(&phy->dev, "phy"); + if (IS_ERR(phy->pwr)) { + ret = PTR_ERR(phy->pwr); + if (ret == -EPROBE_DEFER) + goto put_dev; + + phy->pwr = NULL; + } + ret = device_add(&phy->dev); if (ret) goto put_dev; @@ -721,9 +721,6 @@ put_dev: put_device(&phy->dev); /* calls phy_release() which frees resources */ return ERR_PTR(ret); -free_ida: - ida_simple_remove(&phy_ida, phy->id); - free_phy: kfree(phy); return ERR_PTR(ret); -- cgit v1.2.3 From 99db11c6e8a89b236b283df0ec592aecdd00d8ef Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 8 May 2015 11:30:48 -0500 Subject: phy: miphy28lp: fix sparse warnings Add missing __iomem annotation to the base address so Sparse doesn't complain. Signed-off-by: Felipe Balbi Acked-by: Maxime Coquelin Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-miphy28lp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index c4cc11dcb2a2..58d5339ff448 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -367,7 +367,7 @@ static struct miphy28lp_pll_gen pcie_pll_gen[] = { static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy) { - void *base = miphy_phy->base; + void __iomem *base = miphy_phy->base; u8 val; /* Putting Macro in reset */ @@ -391,7 +391,7 @@ static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy) static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy, struct pll_ratio *pll_ratio) { - void *base = miphy_phy->base; + void __iomem *base = miphy_phy->base; u8 val; /* Applying PLL Settings */ -- cgit v1.2.3 From 5bea496820cdcb0f6711741ba663ccfe78ac4dbf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 8 May 2015 11:30:49 -0500 Subject: phy: miphy365x: fix sparse warnings Add missing 'static' modifier so sparse won't complain anymore. Signed-off-by: Felipe Balbi Acked-by: Maxime Coquelin Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-miphy365x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 019c2d75344e..ba6993da91fe 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -441,8 +441,8 @@ static int miphy365x_init(struct phy *phy) return ret; } -int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, - int index) +static int miphy365x_get_addr(struct device *dev, + struct miphy365x_phy *miphy_phy, int index) { struct device_node *phynode = miphy_phy->phy->dev.of_node; const char *name; -- cgit v1.2.3 From 33f434d283a27116fb358ae5bc3b42967c12f85a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Apr 2015 12:23:38 +0800 Subject: phy: core: Check requested PHY status in _of_phy_get() This is a common checking in various drivers, so move the checking to _of_phy_get(). Signed-off-by: Axel Lin Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-core.c | 12 ++++++++++-- drivers/phy/phy-miphy28lp.c | 5 ----- drivers/phy/phy-miphy365x.c | 5 ----- drivers/phy/phy-rcar-gen2.c | 5 ----- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 5f729bb0788f..7d535dbb63ee 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -367,13 +367,21 @@ static struct phy *_of_phy_get(struct device_node *np, int index) phy_provider = of_phy_provider_lookup(args.np); if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) { phy = ERR_PTR(-EPROBE_DEFER); - goto err0; + goto out_unlock; + } + + if (!of_device_is_available(args.np)) { + dev_warn(phy_provider->dev, "Requested PHY is disabled\n"); + phy = ERR_PTR(-ENODEV); + goto out_put_module; } phy = phy_provider->of_xlate(phy_provider->dev, &args); + +out_put_module: module_put(phy_provider->owner); -err0: +out_unlock: mutex_unlock(&phy_provider_mutex); of_node_put(args.np); diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 58d5339ff448..5e257ef7ac05 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1107,11 +1107,6 @@ static struct phy *miphy28lp_xlate(struct device *dev, struct device_node *phynode = args->np; int ret, index = 0; - if (!of_device_is_available(phynode)) { - dev_warn(dev, "Requested PHY is disabled\n"); - return ERR_PTR(-ENODEV); - } - if (args->args_count != 1) { dev_err(dev, "Invalid number of cells in 'phy' property\n"); return ERR_PTR(-EINVAL); diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index ba6993da91fe..0ff354d6e183 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -476,11 +476,6 @@ static struct phy *miphy365x_xlate(struct device *dev, struct device_node *phynode = args->np; int ret, index; - if (!of_device_is_available(phynode)) { - dev_warn(dev, "Requested PHY is disabled\n"); - return ERR_PTR(-ENODEV); - } - if (args->args_count != 1) { dev_err(dev, "Invalid number of cells in 'phy' property\n"); return ERR_PTR(-EINVAL); diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index 778276aba3aa..f47bfd8a5368 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -206,11 +206,6 @@ static struct phy *rcar_gen2_phy_xlate(struct device *dev, struct device_node *np = args->np; int i; - if (!of_device_is_available(np)) { - dev_warn(dev, "Requested PHY is disabled\n"); - return ERR_PTR(-ENODEV); - } - drv = dev_get_drvdata(dev); if (!drv) return ERR_PTR(-EINVAL); -- cgit v1.2.3 From 9d699bf4dbe29d8f26769ea81dec4a8c91edcd5a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 May 2015 18:33:47 +0900 Subject: phy: rcar-gen2: Add support for R-Car E2 This patch adds a compatible string to support for R-Car E2. Signed-off-by: Yoshihiro Shimoda Acked-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt | 1 + drivers/phy/phy-rcar-gen2.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt index 00fc52a034b7..d564ba4f1cf6 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt @@ -6,6 +6,7 @@ This file provides information on what the device node for the R-Car generation Required properties: - compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. + "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. - reg: offset and length of the register block. - #address-cells: number of address cells for the USB channel subnodes, must be <1>. diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index f47bfd8a5368..0050301dce7a 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -195,6 +195,7 @@ static struct phy_ops rcar_gen2_phy_ops = { static const struct of_device_id rcar_gen2_phy_match_table[] = { { .compatible = "renesas,usb-phy-r8a7790" }, { .compatible = "renesas,usb-phy-r8a7791" }, + { .compatible = "renesas,usb-phy-r8a7794" }, { } }; MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); -- cgit v1.2.3 From 5972edbd8386020347656a37dc014ae838a0adff Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 12 May 2015 16:28:20 -0700 Subject: Documentation: devicetree: add Broadcom SATA PHY binding For 28nm STB chips, based on BCM7445. Signed-off-by: Brian Norris Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/brcm,brcmstb-sata-phy.txt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt new file mode 100644 index 000000000000..7f81ef90146a --- /dev/null +++ b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt @@ -0,0 +1,40 @@ +* Broadcom SATA3 PHY for STB + +Required properties: +- compatible: should be one or more of + "brcm,bcm7445-sata-phy" + "brcm,phy-sata3" +- address-cells: should be 1 +- size-cells: should be 0 +- reg: register range for the PHY PCB interface +- reg-names: should be "phy" + +Sub-nodes: + Each port's PHY should be represented as a sub-node. + +Sub-nodes required properties: +- reg: the PHY number +- phy-cells: generic PHY binding; must be 0 +Optional: +- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port + + +Example: + + sata-phy@f0458100 { + compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3"; + reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + + sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; -- cgit v1.2.3 From 0d486806ffd0de672f151763b38c19c0a357bf56 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 20 May 2015 17:18:40 -0700 Subject: phy: add Broadcom SATA3 PHY driver for Broadcom STB SoCs Supports up to two ports which can each be powered on/off and configured independently. Signed-off-by: Brian Norris Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 9 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-brcmstb-sata.c | 216 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 drivers/phy/phy-brcmstb-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a53bd5b52df9..36788b6f0220 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -309,4 +309,13 @@ config PHY_QCOM_UFS help Support for UFS PHY on QCOM chipsets. +config PHY_BRCMSTB_SATA + tristate "Broadcom STB SATA PHY driver" + depends on ARCH_BRCMSTB + depends on OF + select GENERIC_PHY + help + Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs. + Likely useful only with CONFIG_SATA_BRCMSTB enabled. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f12625178780..c61f3fdd191e 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -40,3 +40,4 @@ obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o +obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c new file mode 100644 index 000000000000..b7e303d28caf --- /dev/null +++ b/drivers/phy/phy-brcmstb-sata.c @@ -0,0 +1,216 @@ +/* + * Broadcom SATA3 AHCI Controller PHY Driver + * + * Copyright © 2009-2015 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SATA_MDIO_BANK_OFFSET 0x23c +#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) +#define SATA_MDIO_REG_SPACE_SIZE 0x1000 +#define SATA_MDIO_REG_LENGTH 0x1f00 + +#define MAX_PORTS 2 + +/* Register offset between PHYs in PCB space */ +#define SATA_MDIO_REG_SPACE_SIZE 0x1000 + +struct brcm_sata_port { + int portnum; + struct phy *phy; + struct brcm_sata_phy *phy_priv; + bool ssc_en; +}; + +struct brcm_sata_phy { + struct device *dev; + void __iomem *phy_base; + + struct brcm_sata_port phys[MAX_PORTS]; +}; + +enum sata_mdio_phy_regs_28nm { + PLL_REG_BANK_0 = 0x50, + PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, + + TXPMD_REG_BANK = 0x1a0, + TXPMD_CONTROL1 = 0x81, + TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), + TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1), + TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82, + TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83, + TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff, + TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84, + TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, +}; + +static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) +{ + struct brcm_sata_phy *priv = port->phy_priv; + + return priv->phy_base + (port->portnum * SATA_MDIO_REG_SPACE_SIZE); +} + +static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, + u32 msk, u32 value) +{ + u32 tmp; + + writel(bank, addr + SATA_MDIO_BANK_OFFSET); + tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); + tmp = (tmp & msk) | value; + writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); +} + +/* These defaults were characterized by H/W group */ +#define FMIN_VAL_DEFAULT 0x3df +#define FMAX_VAL_DEFAULT 0x3df +#define FMAX_VAL_SSC 0x83 + +static void brcm_sata_cfg_ssc_28nm(struct brcm_sata_port *port) +{ + void __iomem *base = brcm_sata_phy_base(port); + struct brcm_sata_phy *priv = port->phy_priv; + u32 tmp; + + /* override the TX spread spectrum setting */ + tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); + + /* set fixed min freq */ + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, + ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, + FMIN_VAL_DEFAULT); + + /* set fixed max freq depending on SSC config */ + if (port->ssc_en) { + dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); + tmp = FMAX_VAL_SSC; + } else { + tmp = FMAX_VAL_DEFAULT; + } + + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, + ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); +} + +static int brcm_sata_phy_init(struct phy *phy) +{ + struct brcm_sata_port *port = phy_get_drvdata(phy); + + brcm_sata_cfg_ssc_28nm(port); + + return 0; +} + +static struct phy_ops phy_ops_28nm = { + .init = brcm_sata_phy_init, + .owner = THIS_MODULE, +}; + +static const struct of_device_id brcm_sata_phy_of_match[] = { + { .compatible = "brcm,bcm7445-sata-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); + +static int brcm_sata_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node, *child; + struct brcm_sata_phy *priv; + struct resource *res; + struct phy_provider *provider; + int count = 0; + + if (of_get_child_count(dn) == 0) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(dev, priv); + priv->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + priv->phy_base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->phy_base)) + return PTR_ERR(priv->phy_base); + + for_each_available_child_of_node(dn, child) { + unsigned int id; + struct brcm_sata_port *port; + + if (of_property_read_u32(child, "reg", &id)) { + dev_err(dev, "missing reg property in node %s\n", + child->name); + return -EINVAL; + } + + if (id >= MAX_PORTS) { + dev_err(dev, "invalid reg: %u\n", id); + return -EINVAL; + } + if (priv->phys[id].phy) { + dev_err(dev, "already registered port %u\n", id); + return -EINVAL; + } + + port = &priv->phys[id]; + port->portnum = id; + port->phy_priv = priv; + port->phy = devm_phy_create(dev, child, &phy_ops_28nm); + port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); + if (IS_ERR(port->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(port->phy); + } + + phy_set_drvdata(port->phy, port); + count++; + } + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "could not register PHY provider\n"); + return PTR_ERR(provider); + } + + dev_info(dev, "registered %d port(s)\n", count); + + return 0; +} + +static struct platform_driver brcm_sata_phy_driver = { + .probe = brcm_sata_phy_probe, + .driver = { + .of_match_table = brcm_sata_phy_of_match, + .name = "brcmstb-sata-phy", + } +}; +module_platform_driver(brcm_sata_phy_driver); + +MODULE_DESCRIPTION("Broadcom STB SATA PHY driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marc Carino"); +MODULE_AUTHOR("Brian Norris"); +MODULE_ALIAS("platform:phy-brcmstb-sata"); -- cgit v1.2.3 From 56301df6bcaaed31e77b8c500ca1b437f46a3158 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Apr 2015 18:03:04 +1000 Subject: phy: twl4030-usb: make runtime pm more reliable. A construct like: if (pm_runtime_suspended(twl->dev)) pm_runtime_get_sync(twl->dev); is against the spirit of the runtime_pm interface as it makes the internal refcounting useless. In this case it is also racy, particularly as 'put_autosuspend' is used to drop a reference. When that happens a timer is started and the device is runtime-suspended after the timeout. If the above code runs in this window, the device will not be found to be suspended so no pm_runtime reference is taken. When the timer expires the device will be suspended, which is against the intention of the code. So be more direct is taking and dropping references. If twl->linkstat is VBUS_VALID or ID_GROUND, then hold a pm_runtime reference, otherwise don't. Define "cable_present()" to test for this condition. Tested-by: Tony Lindgren Signed-off-by: NeilBrown Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-twl4030-usb.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index bc42d6a8939f..3078f80bf520 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -144,6 +144,16 @@ #define PMBR1 0x0D #define GPIO_USB_4PIN_ULPI_2430C (3 << 0) +/* + * If VBUS is valid or ID is ground, then we know a + * cable is present and we need to be runtime-enabled + */ +static inline bool cable_present(enum omap_musb_vbus_id_status stat) +{ + return stat == OMAP_MUSB_VBUS_VALID || + stat == OMAP_MUSB_ID_GROUND; +} + struct twl4030_usb { struct usb_phy phy; struct device *dev; @@ -536,8 +546,10 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) mutex_lock(&twl->lock); if (status >= 0 && status != twl->linkstat) { + status_changed = + cable_present(twl->linkstat) != + cable_present(status); twl->linkstat = status; - status_changed = true; } mutex_unlock(&twl->lock); @@ -553,15 +565,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) * USB_LINK_VBUS state. musb_hdrc won't care until it * starts to handle softconnect right. */ - if ((status == OMAP_MUSB_VBUS_VALID) || - (status == OMAP_MUSB_ID_GROUND)) { - if (pm_runtime_suspended(twl->dev)) - pm_runtime_get_sync(twl->dev); + if (cable_present(status)) { + pm_runtime_get_sync(twl->dev); } else { - if (pm_runtime_active(twl->dev)) { - pm_runtime_mark_last_busy(twl->dev); - pm_runtime_put_autosuspend(twl->dev); - } + pm_runtime_mark_last_busy(twl->dev); + pm_runtime_put_autosuspend(twl->dev); } omap_musb_mailbox(status); } @@ -767,6 +775,9 @@ static int twl4030_usb_remove(struct platform_device *pdev) /* disable complete OTG block */ twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); + + if (cable_present(twl->linkstat)) + pm_runtime_put_noidle(twl->dev); pm_runtime_mark_last_busy(twl->dev); pm_runtime_put(twl->dev); -- cgit v1.2.3 From 186ecebeb60d5271c519450d71026901d9741714 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Apr 2015 18:03:04 +1000 Subject: phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback. When the runtime_suspend callback is running, 'runtime_status' is always RPM_SUSPENDING, so pm_runtime_suspended() will always fail. Similarly while the runtime_resume callback is running 'runtime_status' is RPM_RESUMING, so pm_runtime_active() will always fail. So remove these two pointless tests. Signed-off-by: NeilBrown Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-twl4030-usb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 3078f80bf520..590c2b1c1a94 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -396,8 +396,6 @@ static int twl4030_usb_runtime_suspend(struct device *dev) struct twl4030_usb *twl = dev_get_drvdata(dev); dev_dbg(twl->dev, "%s\n", __func__); - if (pm_runtime_suspended(dev)) - return 0; __twl4030_phy_power(twl, 0); regulator_disable(twl->usb1v5); @@ -413,8 +411,6 @@ static int twl4030_usb_runtime_resume(struct device *dev) int res; dev_dbg(twl->dev, "%s\n", __func__); - if (pm_runtime_active(dev)) - return 0; res = regulator_enable(twl->usb3v1); if (res) -- cgit v1.2.3 From 4724e27114c4a7eceeee07db227a17fcab6f165c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Apr 2015 18:03:04 +1000 Subject: phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function. The USB phy should initialize with power-off, and will be powered on by the USB system when a cable connection is detected. Having this pm_runtime_get_sync() during probe causes the phy to *always* be powered on. Removing it returns to sensible power management. Fixes: 96be39ab34b77c6f6f5cd6ae03aac6c6449ee5c4 Signed-off-by: NeilBrown Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-twl4030-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 590c2b1c1a94..3a707dd14238 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -715,7 +715,6 @@ static int twl4030_usb_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); /* Our job is to use irqs and status from the power module * to keep the transceiver disabled when nothing's connected. -- cgit v1.2.3 From 692fbb89fa0b8028f402e33eb912474e11b5f435 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 16 Apr 2015 18:03:04 +1000 Subject: phy: twl4030-usb: add ABI documentation This driver device one local attribute: vbus. Describe that in Documentation/ABI/testing/sysfs-platform/twl4030-usb. Signed-off-by: NeilBrown Signed-off-by: Kishon Vijay Abraham I --- Documentation/ABI/testing/sysfs-platform-twl4030-usb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-twl4030-usb diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb b/Documentation/ABI/testing/sysfs-platform-twl4030-usb new file mode 100644 index 000000000000..512c51be64ae --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb @@ -0,0 +1,8 @@ +What: /sys/bus/platform/devices/*twl4030-usb/vbus +Description: + Read-only status reporting if VBUS (approx 5V) + is being supplied by the USB bus. + + Possible values: "on", "off". + + Changes are notified via select/poll. -- cgit v1.2.3