Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41a11e31 authored by Kevin Hilman's avatar Kevin Hilman
Browse files

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: default avatarKevin Hilman <khilman@linaro.org>
parents 8b7dfa7d 90aa2997
Loading
Loading
Loading
Loading
+19 −7
Original line number Original line Diff line number Diff line
@@ -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.
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_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_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
phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
in the case of non-dt boot, it should contain the label of the PHY.
be used to get the PHY. In the case of dt boot, the string arguments
The only difference between the two APIs is that devm_phy_get associates the
should contain the phy name as given in the dt data and in the case of
device with the PHY using devres on successful PHY get. On driver detach,
non-dt boot, it should contain the label of the PHY.  The two
release function is invoked on the the devres data and devres data is freed.
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
5. Releasing a reference to the PHY


+5 −3
Original line number Original line Diff line number Diff line
@@ -4126,12 +4126,14 @@ static int mv_platform_probe(struct platform_device *pdev)
			clk_prepare_enable(hpriv->port_clks[port]);
			clk_prepare_enable(hpriv->port_clks[port]);


		sprintf(port_number, "port%d", 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])) {
		if (IS_ERR(hpriv->port_phys[port])) {
			rc = PTR_ERR(hpriv->port_phys[port]);
			rc = PTR_ERR(hpriv->port_phys[port]);
			hpriv->port_phys[port] = NULL;
			hpriv->port_phys[port] = NULL;
			if ((rc != -EPROBE_DEFER) && (rc != -ENODEV))
			if (rc != -EPROBE_DEFER)
				dev_warn(&pdev->dev, "error getting phy");
				dev_warn(&pdev->dev, "error getting phy %d",
					rc);
			goto err;
			goto err;
		} else
		} else
			phy_power_on(hpriv->port_phys[port]);
			phy_power_on(hpriv->port_phys[port]);
+61 −1
Original line number Original line Diff line number Diff line
@@ -162,6 +162,9 @@ int phy_init(struct phy *phy)
{
{
	int ret;
	int ret;


	if (!phy)
		return 0;

	ret = phy_pm_runtime_get_sync(phy);
	ret = phy_pm_runtime_get_sync(phy);
	if (ret < 0 && ret != -ENOTSUPP)
	if (ret < 0 && ret != -ENOTSUPP)
		return ret;
		return ret;
@@ -187,6 +190,9 @@ int phy_exit(struct phy *phy)
{
{
	int ret;
	int ret;


	if (!phy)
		return 0;

	ret = phy_pm_runtime_get_sync(phy);
	ret = phy_pm_runtime_get_sync(phy);
	if (ret < 0 && ret != -ENOTSUPP)
	if (ret < 0 && ret != -ENOTSUPP)
		return ret;
		return ret;
@@ -212,6 +218,9 @@ int phy_power_on(struct phy *phy)
{
{
	int ret;
	int ret;


	if (!phy)
		return 0;

	ret = phy_pm_runtime_get_sync(phy);
	ret = phy_pm_runtime_get_sync(phy);
	if (ret < 0 && ret != -ENOTSUPP)
	if (ret < 0 && ret != -ENOTSUPP)
		return ret;
		return ret;
@@ -240,6 +249,9 @@ int phy_power_off(struct phy *phy)
{
{
	int ret;
	int ret;


	if (!phy)
		return 0;

	mutex_lock(&phy->mutex);
	mutex_lock(&phy->mutex);
	if (phy->power_count == 1 && phy->ops->power_off) {
	if (phy->power_count == 1 && phy->ops->power_off) {
		ret =  phy->ops->power_off(phy);
		ret =  phy->ops->power_off(phy);
@@ -308,7 +320,7 @@ err0:
 */
 */
void phy_put(struct phy *phy)
void phy_put(struct phy *phy)
{
{
	if (IS_ERR(phy))
	if (!phy || IS_ERR(phy))
		return;
		return;


	module_put(phy->ops->owner);
	module_put(phy->ops->owner);
@@ -328,6 +340,9 @@ void devm_phy_put(struct device *dev, struct phy *phy)
{
{
	int r;
	int r;


	if (!phy)
		return;

	r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
	r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
	dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
	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);
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.
 * devm_phy_get() - lookup and obtain a reference to a phy.
 * @dev: device that requests this 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);
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
 * phy_create() - create a new phy
 * @dev: device that is creating the new phy
 * @dev: device that is creating the new phy
+14 −0
Original line number Original line Diff line number Diff line
@@ -146,7 +146,9 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width)
	phy->attrs.bus_width = bus_width;
	phy->attrs.bus_width = bus_width;
}
}
struct phy *phy_get(struct device *dev, const char *string);
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_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 phy_put(struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
struct phy *of_phy_simple_xlate(struct device *dev,
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);
	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)
static inline struct phy *devm_phy_get(struct device *dev, const char *string)
{
{
	return ERR_PTR(-ENOSYS);
	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)
static inline void phy_put(struct phy *phy)
{
{
}
}