Commit b3d424e3 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-v4.2' of...

Merge tag 'phy-for-v4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next

Kishon writes:

phy: for 4.2 merge window

*) new Broadcom SATA3 PHY driver for Broadcom STB SoCs
*) new phy API to get PHY by index which is used in EHCI and
   OHCI controller drivers
*) support specifying supply at port level used for multi-port PHYs
*) sparse warning fixes in miphy PHYs
*) fix pm_runtime issues in twl4030 driver
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parents f5042022 692fbb89
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.
* 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>;
};
};
......@@ -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>.
......
......@@ -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,
......
......@@ -316,4 +316,13 @@ config PHY_TUSB1210
help
Support for TI TUSB1210 USB ULPI PHY.
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
......@@ -41,3 +41,4 @@ 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_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
/*
* 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 <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#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");
......@@ -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);
......@@ -622,6 +630,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
......@@ -651,16 +691,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);
......@@ -674,6 +704,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;
......@@ -689,9 +729,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
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);
......
......@@ -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 */
......@@ -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);
......
......@@ -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;
......@@ -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);
......
......@@ -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);
......@@ -206,11 +207,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);
......
......@@ -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;
......@@ -386,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);
......@@ -403,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)
......@@ -536,8 +542,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,16 +561,12 @@ 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))
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);
}
}
omap_musb_mailbox(status);
}
......@@ -711,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.
......@@ -767,6 +770,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);
......
......@@ -88,7 +88,6 @@ 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;
......@@ -98,17 +97,14 @@ static int ehci_platform_power_on(struct platform_device *dev)
goto err_exit_phy;
}
}
}
return 0;
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]);
}
}
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
......@@ -123,11 +119,9 @@ 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]);
}
}
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
if (priv->clks[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())
......@@ -208,35 +201,21 @@ 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;
if (priv->num_phys > 0) {
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
sizeof(struct phy *), GFP_KERNEL);
if (!priv->phys)
return -ENOMEM;
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->num_phys = 0;
priv->phys[phy_num] = devm_phy_get(&dev->dev,
phy_name);
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
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]);
if ((priv->num_phys > 1) ||
(err == -EPROBE_DEFER))
goto err_put_hcd;
priv->phys[phy_num] = NULL;
}
}
......
......@@ -57,7 +57,6 @@ 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;
......@@ -67,17 +66,14 @@ static int ohci_platform_power_on(struct platform_device *dev)
goto err_exit_phy;
}
}
}
return 0;
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]);
}
}
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
......@@ -92,11 +88,9 @@ 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]);
}
}
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
if (priv->clks[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,35 +167,21 @@ 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;
if (priv->num_phys > 0) {
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
sizeof(struct phy *), GFP_KERNEL);
if (!priv->phys)
return -ENOMEM;
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->num_phys = 0;
priv->phys[phy_num] = devm_phy_get(&dev->dev,
phy_name);
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
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]);
if ((priv->num_phys > 1) ||
(err == -EPROBE_DEFER))
goto err_put_hcd;
priv->phys[phy_num] = NULL;
}
}
......
......@@ -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)
{
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment