mvebu phy and ata fixes for v3.14

- phy
     - add support for optional phys via NULL
 
  - ata
     - fix boot hang due to probe failure of optional phys
 
 NOTE:  Series has been Ack'd by both the phy maintainer and the ata maintainer
 for going through arm-soc
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJS9mY1AAoJEP45WPkGe8ZnbcYP/jkidupz/J/AFkZ9h94hxBin
 qxU54nQkUNSfhwqhZzVoED7DMCokCNj09t4I3b++YHg1SDXcRpPbZfuUcEDd7RD9
 ysiyFlrm6pv68KyYuR2IFOtaEP2MRU4iewgzMYHDYNCrovUoiy9TA/owdX2Pamnw
 qL9knDOCvRJvByTlv1+13giFbDu0JHpPiOOmW8S53c9jfrWuBX+VzVfF8UHTiJhg
 3d3NfQlWcIpvAA4nZbc2+4gubiv1PeWYfJ48nWw95uzsfEIPgXGNklJpHwuF4u0J
 sJpZNP5L7Y4xJCGBCjMIgAx7YDs3mnkGGDLC9n0as9HTp0X0edMD0gnJVUOszZS9
 CQZSnmMxtbY6w6WzGo1fHD6c4cZoVUc6TsJqwagblxN2oR70QlPu/jodwFieTbnE
 iZIUAMBQZMaE6xnBWfp1LDy/LW2IiaLGFGAaQydVdl8Sys4iXqyG18qKi3VAvhwM
 JrLMsYXDR400n/E9b0dMFmCpGT0z/NPug1GFH750rtDVe8p1vI2BJJfRhmetMMP0
 EYyS11i3Z6IaGCAxph6YaCPbtlASZsuJRJznmyk+4CWhgMloYJpSOtJQX9D5gM0u
 hRxABHz/sw32W/TyvhSR6Dp50Oa+vRyz69difVaannzzw8V5li8iQ7fqfdeUBUUc
 +i1mKeNKg8HNaW/I8LEk
 =TXSu
 -----END PGP SIGNATURE-----

Merge tag 'mvebu-phy_ata-fixes-3.14' of git://git.infradead.org/linux-mvebu into fixes

From Jason Cooper:
mvebu phy and ata fixes for v3.14

 - phy
    - add support for optional phys via NULL

 - ata
    - fix boot hang due to probe failure of optional phys

NOTE:  Series has been Ack'd by both the phy maintainer and the ata maintainer
for going through arm-soc

* tag 'mvebu-phy_ata-fixes-3.14' of git://git.infradead.org/linux-mvebu:
  ata: sata_mv: Fix probe failures with optional phys
  drivers: phy: Add support for optional phys
  drivers: phy: Make NULL a valid phy reference

Signed-off-by: Kevin Hilman <khilman@linaro.org>
This commit is contained in:
Kevin Hilman 2014-02-10 09:44:34 -08:00
commit 41a11e31d4
4 changed files with 98 additions and 10 deletions

View File

@ -75,14 +75,26 @@ Before the controller can make use of the PHY, it has to get a reference to
it. This framework provides the following APIs to get a reference to the PHY.
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);
phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot,
the string arguments should contain the phy name as given in the dt data and
in the case of non-dt boot, it should contain the label of the PHY.
The only difference between the two APIs is that devm_phy_get associates the
device with the PHY using devres on successful PHY get. On driver detach,
release function is invoked on the the devres data and devres data is freed.
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
should contain the phy name as given in the dt data and in the case of
non-dt boot, it should contain the label of the PHY. The two
devm_phy_get associates the device with the PHY using devres on
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.
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,
the phy_init() and phy_exit() calls, and phy_power_on() and
phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
phy is useful in devices for handling optional phy devices.
5. Releasing a reference to the PHY

View File

@ -4126,12 +4126,14 @@ static int mv_platform_probe(struct platform_device *pdev)
clk_prepare_enable(hpriv->port_clks[port]);
sprintf(port_number, "port%d", port);
hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number);
hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
port_number);
if (IS_ERR(hpriv->port_phys[port])) {
rc = PTR_ERR(hpriv->port_phys[port]);
hpriv->port_phys[port] = NULL;
if ((rc != -EPROBE_DEFER) && (rc != -ENODEV))
dev_warn(&pdev->dev, "error getting phy");
if (rc != -EPROBE_DEFER)
dev_warn(&pdev->dev, "error getting phy %d",
rc);
goto err;
} else
phy_power_on(hpriv->port_phys[port]);

View File

@ -162,6 +162,9 @@ int phy_init(struct phy *phy)
{
int ret;
if (!phy)
return 0;
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@ -187,6 +190,9 @@ int phy_exit(struct phy *phy)
{
int ret;
if (!phy)
return 0;
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@ -212,6 +218,9 @@ int phy_power_on(struct phy *phy)
{
int ret;
if (!phy)
return 0;
ret = phy_pm_runtime_get_sync(phy);
if (ret < 0 && ret != -ENOTSUPP)
return ret;
@ -240,6 +249,9 @@ int phy_power_off(struct phy *phy)
{
int ret;
if (!phy)
return 0;
mutex_lock(&phy->mutex);
if (phy->power_count == 1 && phy->ops->power_off) {
ret = phy->ops->power_off(phy);
@ -308,7 +320,7 @@ err0:
*/
void phy_put(struct phy *phy)
{
if (IS_ERR(phy))
if (!phy || IS_ERR(phy))
return;
module_put(phy->ops->owner);
@ -328,6 +340,9 @@ void devm_phy_put(struct device *dev, struct phy *phy)
{
int r;
if (!phy)
return;
r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
}
@ -410,6 +425,27 @@ struct phy *phy_get(struct device *dev, const char *string)
}
EXPORT_SYMBOL_GPL(phy_get);
/**
* phy_optional_get() - lookup and obtain a reference to an optional phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or the name of the controller
* port for non-dt case
*
* Returns the phy driver, after getting a refcount to it; or
* NULL if there is no such phy. The caller is responsible for
* calling phy_put() to release that count.
*/
struct phy *phy_optional_get(struct device *dev, const char *string)
{
struct phy *phy = phy_get(dev, string);
if (PTR_ERR(phy) == -ENODEV)
phy = NULL;
return phy;
}
EXPORT_SYMBOL_GPL(phy_optional_get);
/**
* devm_phy_get() - lookup and obtain a reference to a phy.
* @dev: device that requests this phy
@ -440,6 +476,30 @@ struct phy *devm_phy_get(struct device *dev, const char *string)
}
EXPORT_SYMBOL_GPL(devm_phy_get);
/**
* devm_phy_optional_get() - lookup and obtain a reference to an optional phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or phy device name
* for non-dt case
*
* Gets the phy using 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. This differs to devm_phy_get() in
* that if the phy does not exist, it is not considered an error and
* -ENODEV will not be returned. Instead the NULL phy is returned,
* which can be passed to all other phy consumer calls.
*/
struct phy *devm_phy_optional_get(struct device *dev, const char *string)
{
struct phy *phy = devm_phy_get(dev, string);
if (PTR_ERR(phy) == -ENODEV)
phy = NULL;
return phy;
}
EXPORT_SYMBOL_GPL(devm_phy_optional_get);
/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy

View File

@ -146,7 +146,9 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width)
phy->attrs.bus_width = bus_width;
}
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);
void phy_put(struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
struct phy *of_phy_simple_xlate(struct device *dev,
@ -232,11 +234,23 @@ static inline struct phy *phy_get(struct device *dev, const char *string)
return ERR_PTR(-ENOSYS);
}
static inline struct phy *phy_optional_get(struct device *dev,
const char *string)
{
return ERR_PTR(-ENOSYS);
}
static inline struct phy *devm_phy_get(struct device *dev, const char *string)
{
return ERR_PTR(-ENOSYS);
}
static inline struct phy *devm_phy_optional_get(struct device *dev,
const char *string)
{
return ERR_PTR(-ENOSYS);
}
static inline void phy_put(struct phy *phy)
{
}