diff mbox

[v6,1/9] drivers: phy: add generic PHY framework

Message ID 1367229812-30574-2-git-send-email-kishon@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kishon Vijay Abraham I April 29, 2013, 10:03 a.m. UTC
The PHY framework provides a set of APIs for the PHY drivers to
create/destroy a PHY and APIs for the PHY users to obtain a reference to the
PHY with or without using phandle. For dt-boot, the PHY drivers should
also register *PHY provider* with the framework.

PHY drivers should create the PHY by passing id and ops like init, exit,
power_on and power_off. This framework is also pm runtime enabled.

The documentation for the generic PHY framework is added in
Documentation/phy.txt and the documentation for dt binding can be found at
Documentation/devicetree/bindings/phy/phy-bindings.txt

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/phy/phy-bindings.txt       |   66 +++
 Documentation/phy.txt                              |  123 +++++
 MAINTAINERS                                        |    7 +
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    2 +
 drivers/phy/Kconfig                                |   13 +
 drivers/phy/Makefile                               |    5 +
 drivers/phy/phy-core.c                             |  539 ++++++++++++++++++++
 include/linux/phy/phy.h                            |  248 +++++++++
 9 files changed, 1005 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-bindings.txt
 create mode 100644 Documentation/phy.txt
 create mode 100644 drivers/phy/Kconfig
 create mode 100644 drivers/phy/Makefile
 create mode 100644 drivers/phy/phy-core.c
 create mode 100644 include/linux/phy/phy.h

Comments

Sylwester Nawrocki May 28, 2013, 10:37 p.m. UTC | #1
Hi Kishon,

On 04/29/2013 12:03 PM, Kishon Vijay Abraham I wrote:
> The PHY framework provides a set of APIs for the PHY drivers to
> create/destroy a PHY and APIs for the PHY users to obtain a reference to the
> PHY with or without using phandle. For dt-boot, the PHY drivers should
> also register *PHY provider* with the framework.
>
> PHY drivers should create the PHY by passing id and ops like init, exit,
> power_on and power_off. This framework is also pm runtime enabled.
>
> The documentation for the generic PHY framework is added in
> Documentation/phy.txt and the documentation for dt binding can be found at
> Documentation/devicetree/bindings/phy/phy-bindings.txt
>
> Signed-off-by: Kishon Vijay Abraham I<kishon@ti.com>

Thanks for working on this. For the record, I plan to give this a try
in the end of this week, with my simple MIPI CSI/DSI PHY driver. I might
have some more comments then. For now just couple of remarks after
reading the documentation.

> ---
>   .../devicetree/bindings/phy/phy-bindings.txt       |   66 +++
>   Documentation/phy.txt                              |  123 +++++
>   MAINTAINERS                                        |    7 +
>   drivers/Kconfig                                    |    2 +
>   drivers/Makefile                                   |    2 +
>   drivers/phy/Kconfig                                |   13 +
>   drivers/phy/Makefile                               |    5 +
>   drivers/phy/phy-core.c                             |  539 ++++++++++++++++++++
>   include/linux/phy/phy.h                            |  248 +++++++++
>   9 files changed, 1005 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/phy/phy-bindings.txt
>   create mode 100644 Documentation/phy.txt
>   create mode 100644 drivers/phy/Kconfig
>   create mode 100644 drivers/phy/Makefile
>   create mode 100644 drivers/phy/phy-core.c
>   create mode 100644 include/linux/phy/phy.h
>
> diff --git a/Documentation/devicetree/bindings/phy/phy-bindings.txt b/Documentation/devicetree/bindings/phy/phy-bindings.txt
> new file mode 100644
> index 0000000..8ae844f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-bindings.txt
> @@ -0,0 +1,66 @@
> +This document explains only the device tree data binding. For general
> +information about PHY subsystem refer to Documentation/phy.txt
> +
> +PHY device node
> +===============
> +
> +Required Properties:
> +#phy-cells:	Number of cells in a PHY specifier;  The meaning of all those
> +		cells is defined by the binding for the phy node. The PHY
> +		provider can use the values in cells to find the appropriate
> +		PHY.
> +
> +For example:
> +
> +phys: phy {
> +    compatible = "xxx";
> +    reg =<...>;
> +    .
> +    .
> +    #phy-cells =<1>;
> +    .
> +    .
> +};
> +
> +That node describes an IP block (PHY provider) that implements 2 different PHYs.
> +In order to differentiate between these 2 PHYs, an additonal specifier should be
> +given while trying to get a reference to it.
> +
> +PHY user node
> +=============
> +
> +Required Properties:
> +phys : the phandle for the PHY device (used by the PHY subsystem)
> +phy-names : the names of the PHY corresponding to the PHYs present in the
> +	    *phys* phandle
> +
> +Example 1:
> +usb1: usb_otg_ss@xxx {
> +    compatible = "xxx";
> +    reg =<xxx>;
> +    .
> +    .
> +    phys =<&usb2_phy>,<&usb3_phy>;
> +    phy-names = "usb2phy", "usb3phy";
> +    .
> +    .
> +};
> +
> +This node represents a controller that uses two PHYs, one for usb2 and one for
> +usb3.
> +
> +Example 2:
> +usb2: usb_otg_ss@xxx {
> +    compatible = "xxx";
> +    reg =<xxx>;
> +    .
> +    .
> +    phys =<&phys 1>;
> +    phy-names = "usbphy";
> +    .
> +    .
> +};
> +
> +This node represents a controller that uses one of the PHYs of the PHY provider
> +device defined previously. Note that the phy handle has an additional specifier
> +"1" to differentiate between the two PHYs.
> diff --git a/Documentation/phy.txt b/Documentation/phy.txt
> new file mode 100644
> index 0000000..408d25f
> --- /dev/null
> +++ b/Documentation/phy.txt
> @@ -0,0 +1,123 @@
> +			    PHY SUBSYSTEM
> +		  Kishon Vijay Abraham I<kishon@ti.com>
> +
> +This document explains the Generic PHY Framework along with the APIs provided,
> +and how-to-use.
> +
> +1. Introduction
> +
> +*PHY* is the abbreviation for physical layer. It is used to connect a device
> +to the physical medium e.g., the USB controller has a PHY to provide functions
> +such as serialization, de-serialization, encoding, decoding and is responsible
> +for obtaining the required data transmission rate. Note that some USB
> +controller has PHY functionality embedded into it and others use an external

"Note that some USB
controllers have PHY functionality embedded into them..." ?

> +PHY. Other peripherals that uses a PHY include Wireless LAN, Ethernet,

s/uses/use ?

> +SATA etc.
> +
> +The intention of creating this framework is to bring the phy drivers spread

s/phy/PHY ?

> +all over the Linux kernel to drivers/phy to increase code re-use and for
> +better code maintainability.
> +
> +This framework will be of use only to devices that uses external PHY (PHY

s/that uses/that use ?

> +functionality is not embedded within the controller).
> +
> +2. Registering/UnRegistering the PHY provider

s/UnRegistering/Unregistering ?

> +
> +PHY provider refers to an entity that implements one or more PHY instances.
> +For the simple case where the PHY provider implements only a single instance of
> +the PHY, the framework provides its own implementation of of_xlate in
> +of_phy_simple_xlate. If the PHY provider implements multiple instances, it
> +should provide it's own implementation of of_xlate. of_xlate is used only for

s/it's/its

> +dt boot case.
> +
> +struct phy_provider *of_phy_provider_register(struct device *dev,
> +	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
> +	struct of_phandle_args *args));
> +struct phy_provider *devm_of_phy_provider_register(struct device *dev,
> +	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
> +	struct of_phandle_args *args))
> +
> +of_phy_provider_register and devm_of_phy_provider_register can be used to
> +register the phy_provider and it takes device, owner and of_xlate as
> +arguments. For the dt boot case, all PHY providers should use one of the above
> +2 APIs to register the PHY provider.
> +
> +void devm_of_phy_provider_unregister(struct device *dev,
> +	struct phy_provider *phy_provider);
> +void of_phy_provider_unregister(struct phy_provider *phy_provider);
> +
> +devm_of_phy_provider_unregister and of_phy_provider_unregister can be used to
> +unregister the PHY.
> +
> +3. Creating the PHY
> +
> +The PHY driver should create the PHY in order for other peripheral controllers
> +to make use of it. The PHY framework provides 2 APIs to create the PHY.
> +
> +struct phy *phy_create(struct device *dev, int id, const struct phy_ops *ops,
> +	void *priv);
> +struct phy *devm_phy_create(struct device *dev, int id,
> +	const struct phy_ops *ops, void *priv);
> +
> +The PHY drivers can use one of the above 2 APIs to create the PHY by passing
> +the device pointer, id, phy ops and a driver data.
> +phy_ops is a set of function pointers for performing PHY operations such as
> +init, exit, power_on and power_off.
> +
> +4. Getting a reference to the PHY
> +
> +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 *devm_phy_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 device name of the PHY.

How about allowing null strings ? At least it seems not difficult for dt 
boot.
But there would have been some asymmetry, for non-dt an error would have to
be returned when the passed string is null.

> +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.
> +
> +5. Releasing a reference to the PHY
> +
> +When the controller no longer needs the PHY, it has to release the reference
> +to the PHY it has obtained using the APIs mentioned in the above section. The
> +PHY framework provides 2 APIS to release a reference to the PHY.

APIs ?

> +void phy_put(struct phy *phy);
> +void devm_phy_put(struct device *dev, struct phy *phy);
> +
> +Both these APIs are used to release a reference to the PHY and devm_phy_put
> +destroys the devres associated with this PHY.
> +
> +6. Destroying the PHY
> +
> +When the driver that created the PHY is unloaded, it should destroy the PHY it
> +created using one of the following 2 APIs.
> +
> +void phy_destroy(struct phy *phy);
> +void devm_phy_destroy(struct device *dev, struct phy *phy);
> +
> +Both these APIs destroys the PHY and devm_phy_destroy destroys the devres

s/APIs destroys/APIs destroy ?

> +associated with this PHY.
> +
> +7. PM Runtime
> +
> +This subsystem is pm runtime enabled. So while creating the PHY,
> +pm_runtime_enable of the phy device created by this subsystem is called and
> +while destroying the PHY, pm_runtime_disable is called. Note that the phy
> +device created by this subsystem will be a child of the device that calls
> +phy_create (PHY provider device).
> +
> +During phy_init, the clocks are enabled by calling get_sync and the clocks are

I think, if you mean pm_runtime_get_sync(), it should be said precisely 
here.

> +disable by calling put_sync during phy_exit. get_sync of the phy_device

Ditto.

s/disable/disabled

> +created by this susbsystem will invoke get_sync of PHY provider device because

s/susbsystem/subsystem

> +of parent-child relationship. For all other pm operations, there are exported
> +APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync, phy_pm_runtime_put,
> +phy_pm_runtime_put_sync, phy_pm_runtime_allow and phy_pm_runtime_forbid.
> +
> +8. DeviceTree Binding
> +
> +The documentation for PHY dt binding can be found @
> +Documentation/devicetree/bindings/phy/phy-bindings.txt

> +/**
> + * phy_release() - release the phy
> + * @dev: the dev member within phy
> + *
> + * when the last reference to the device is removed; it is called

s/when/When
s/removed;/removed ?

> + * from the embedded kobject as release method.
> + */

> +/**
> + * struct phy - represent the phy device

s/represent/represents ?

> + * @dev: phy device
> + * @id: id of the phy
> + * @ops: function pointers for performing phy operations
> + */
> +struct phy {
> +	struct device		dev;
> +	int			id;
> +	const struct phy_ops	*ops;
> +};
> +
> +/**
> + * struct phy_provider - represent the phy provider

s/represent/represents ?

> + * @dev: phy provider device
> + * @owner: the module owner having of_xlate
> + * @of_xlate: function pointer to obtain phy instance from phy pointer
> + * @list: to maintain a linked list of PHY provider

s/provider/providers ?

> + */
> +struct phy_provider {
> +	struct device		*dev;
> +	struct module		*owner;
> +	struct list_head	list;
> +	struct phy * (*of_xlate)(struct device *dev,
> +		struct of_phandle_args *args);
> +};

Regards,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I May 29, 2013, 5:38 a.m. UTC | #2
Hi,

On Wednesday 29 May 2013 04:07 AM, Sylwester Nawrocki wrote:
> Hi Kishon,
>
> On 04/29/2013 12:03 PM, Kishon Vijay Abraham I wrote:
>> The PHY framework provides a set of APIs for the PHY drivers to
>> create/destroy a PHY and APIs for the PHY users to obtain a reference
>> to the
>> PHY with or without using phandle. For dt-boot, the PHY drivers should
>> also register *PHY provider* with the framework.
>>
>> PHY drivers should create the PHY by passing id and ops like init, exit,
>> power_on and power_off. This framework is also pm runtime enabled.
>>
>> The documentation for the generic PHY framework is added in
>> Documentation/phy.txt and the documentation for dt binding can be
>> found at
>> Documentation/devicetree/bindings/phy/phy-bindings.txt
>>
>> Signed-off-by: Kishon Vijay Abraham I<kishon@ti.com>
>
> Thanks for working on this. For the record, I plan to give this a try
> in the end of this week, with my simple MIPI CSI/DSI PHY driver. I might
> have some more comments then. For now just couple of remarks after
> reading the documentation.

Thanks for reviewing. I'll wait for your comments before posting the 
next version.

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

On 05/29/2013 07:38 AM, Kishon Vijay Abraham I wrote:
> On Wednesday 29 May 2013 04:07 AM, Sylwester Nawrocki wrote:
>> > On 04/29/2013 12:03 PM, Kishon Vijay Abraham I wrote:
>>> >> The PHY framework provides a set of APIs for the PHY drivers to
>>> >> create/destroy a PHY and APIs for the PHY users to obtain a reference
>>> >> to the
>>> >> PHY with or without using phandle. For dt-boot, the PHY drivers should
>>> >> also register *PHY provider* with the framework.
>>> >>
>>> >> PHY drivers should create the PHY by passing id and ops like init, exit,
>>> >> power_on and power_off. This framework is also pm runtime enabled.
>>> >>
>>> >> The documentation for the generic PHY framework is added in
>>> >> Documentation/phy.txt and the documentation for dt binding can be
>>> >> found at
>>> >> Documentation/devicetree/bindings/phy/phy-bindings.txt
>>> >>
>>> >> Signed-off-by: Kishon Vijay Abraham I<kishon@ti.com>
>> >
>> > Thanks for working on this. For the record, I plan to give this a try
>> > in the end of this week, with my simple MIPI CSI/DSI PHY driver. I might
>> > have some more comments then. For now just couple of remarks after
>> > reading the documentation.
>
> Thanks for reviewing. I'll wait for your comments before posting the 
> next version.

So I've used this API for the Exynos SoC MIPI CSI-2 and MIPI DSI DPHYs.
I could remove all the local modifications, comparing to your v5, since 
this iteration already have what's needed, thanks! In my case the PHY 
provider was a platform device and so were the PHY consumer devices. Those 
PHYs are very simple, there is less than one register per PHY (some bits 
are shared across the MIPI CSI-2 receiver and MIPI DSI transmitter DPHYs), 
but having this generic PHY driver means, among others, there is a proper 
DT support. I could finally get rid of the the platform callback at 
arch/arm/plat-samsung/setup-mipiphy.c.

I found this code useful as is, except previous minor comments I don't 
really have more remarks now. This API looks quite good, and it seems much 
lighter comparing to the original version.

I assume, the way it is designed now, allows it to be used also with PHYs that 
hang off other buses, e.g. I2C.

It would be nice to get this in 3.11.

Hmm, actually I have some doubts, let me comment in other e-mail..


Regards,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
On 04/29/2013 12:03 PM, Kishon Vijay Abraham I wrote:
> The PHY framework provides a set of APIs for the PHY drivers to
> create/destroy a PHY and APIs for the PHY users to obtain a reference to the
> PHY with or without using phandle. For dt-boot, the PHY drivers should
> also register *PHY provider* with the framework.
> 
> PHY drivers should create the PHY by passing id and ops like init, exit,
> power_on and power_off. This framework is also pm runtime enabled.
> 
> The documentation for the generic PHY framework is added in
> Documentation/phy.txt and the documentation for dt binding can be found at
> Documentation/devicetree/bindings/phy/phy-bindings.txt
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  .../devicetree/bindings/phy/phy-bindings.txt       |   66 +++
>  Documentation/phy.txt                              |  123 +++++
>  MAINTAINERS                                        |    7 +
>  drivers/Kconfig                                    |    2 +
>  drivers/Makefile                                   |    2 +
>  drivers/phy/Kconfig                                |   13 +
>  drivers/phy/Makefile                               |    5 +
>  drivers/phy/phy-core.c                             |  539 ++++++++++++++++++++
>  include/linux/phy/phy.h                            |  248 +++++++++
>  9 files changed, 1005 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/phy-bindings.txt
>  create mode 100644 Documentation/phy.txt
>  create mode 100644 drivers/phy/Kconfig
>  create mode 100644 drivers/phy/Makefile
>  create mode 100644 drivers/phy/phy-core.c
>  create mode 100644 include/linux/phy/phy.h
 
> +static inline int phy_init(struct phy *phy)
> +{
> +	pm_runtime_get_sync(&phy->dev);

Hmm, no need to check return value here ? Also it looks a bit unexpected to 
possibly have runtime_resume callback of a PHY device called before ops->init()
call ? It seems a bit unclear what the purpose of init() callback is.

> +	if (phy->ops->init)
> +		return phy->ops->init(phy);
> +
> +	return -EINVAL;
> +}
> +
> +static inline int phy_exit(struct phy *phy)
> +{
> +	int ret = -EINVAL;
> +
> +	if (phy->ops->exit)
> +		ret = phy->ops->exit(phy);
> +
> +	pm_runtime_put_sync(&phy->dev);
> +
> +	return ret;
> +}

Do phy_init/phy_exit need to be mandatory ? What if there is really 
nothing to do in those callbacks ? Perhaps -ENOIOCTLCMD should be 
returned if a callback is not implemented, so PHY users can recognize 
such situation and proceed ?

> +static inline int phy_power_on(struct phy *phy)
> +{
> +	if (phy->ops->power_on)
> +		return phy->ops->power_on(phy);
> +
> +	return -EINVAL;
> +}
> +
> +static inline int phy_power_off(struct phy *phy)
> +{
> +	if (phy->ops->power_off)
> +		return phy->ops->power_off(phy);
> +
> +	return -EINVAL;
> +}
> +
> +static inline int phy_pm_runtime_get(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return -EINVAL;
> +
> +	return pm_runtime_get(&phy->dev);
> +}
> +
> +static inline int phy_pm_runtime_get_sync(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return -EINVAL;
> +
> +	return pm_runtime_get_sync(&phy->dev);
> +}
> +
> +static inline int phy_pm_runtime_put(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return -EINVAL;
> +
> +	return pm_runtime_put(&phy->dev);
> +}
> +
> +static inline int phy_pm_runtime_put_sync(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return -EINVAL;
> +
> +	return pm_runtime_put_sync(&phy->dev);
> +}
> +
> +static inline void phy_pm_runtime_allow(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return;
> +
> +	pm_runtime_allow(&phy->dev);
> +}
> +
> +static inline void phy_pm_runtime_forbid(struct phy *phy)
> +{
> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
> +		return;
> +
> +	pm_runtime_forbid(&phy->dev);
> +}

Do we need to have all these runtime PM wrappers ? I guess you 
intended to avoid referencing phy->dev from the PHY consumers ?


Thanks,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I June 4, 2013, 12:26 p.m. UTC | #5
Hi,

On Tuesday 04 June 2013 03:51 PM, Sylwester Nawrocki wrote:
> On 04/29/2013 12:03 PM, Kishon Vijay Abraham I wrote:
>> The PHY framework provides a set of APIs for the PHY drivers to
>> create/destroy a PHY and APIs for the PHY users to obtain a reference to the
>> PHY with or without using phandle. For dt-boot, the PHY drivers should
>> also register *PHY provider* with the framework.
>>
>> PHY drivers should create the PHY by passing id and ops like init, exit,
>> power_on and power_off. This framework is also pm runtime enabled.
>>
>> The documentation for the generic PHY framework is added in
>> Documentation/phy.txt and the documentation for dt binding can be found at
>> Documentation/devicetree/bindings/phy/phy-bindings.txt
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>   .../devicetree/bindings/phy/phy-bindings.txt       |   66 +++
>>   Documentation/phy.txt                              |  123 +++++
>>   MAINTAINERS                                        |    7 +
>>   drivers/Kconfig                                    |    2 +
>>   drivers/Makefile                                   |    2 +
>>   drivers/phy/Kconfig                                |   13 +
>>   drivers/phy/Makefile                               |    5 +
>>   drivers/phy/phy-core.c                             |  539 ++++++++++++++++++++
>>   include/linux/phy/phy.h                            |  248 +++++++++
>>   9 files changed, 1005 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/phy/phy-bindings.txt
>>   create mode 100644 Documentation/phy.txt
>>   create mode 100644 drivers/phy/Kconfig
>>   create mode 100644 drivers/phy/Makefile
>>   create mode 100644 drivers/phy/phy-core.c
>>   create mode 100644 include/linux/phy/phy.h
>
>> +static inline int phy_init(struct phy *phy)
>> +{
>> +	pm_runtime_get_sync(&phy->dev);
>
> Hmm, no need to check return value here ? Also it looks a bit unexpected to

I purposely dint check the return values in order to support platforms 
that don’t enable pm_runtime.
> possibly have runtime_resume callback of a PHY device called before ops->init()
> call ? It seems a bit unclear what the purpose of init() callback is.

Not really. Anything that is used to initialize the PHY (internal 
configuration) can go in phy_init. Usually in runtime_resume callback, 
optional functional clocks are enabled and also in some cases context 
restore is done. So it really makes sense to enable clocks/module 
(pm_runtime_get_sync) before doing a PHY configuration (phy_init).

>
>> +	if (phy->ops->init)
>> +		return phy->ops->init(phy);
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static inline int phy_exit(struct phy *phy)
>> +{
>> +	int ret = -EINVAL;
>> +
>> +	if (phy->ops->exit)
>> +		ret = phy->ops->exit(phy);
>> +
>> +	pm_runtime_put_sync(&phy->dev);
>> +
>> +	return ret;
>> +}
>
> Do phy_init/phy_exit need to be mandatory ? What if there is really

No. phy_init/phy_exit is not mandatory at all.
> nothing to do in those callbacks ? Perhaps -ENOIOCTLCMD should be
> returned if a callback is not implemented, so PHY users can recognize
> such situation and proceed ?

So currently these APIs return -EINVAL if these callbacks are not 
populated which is good enough IMHO.
>
>> +static inline int phy_power_on(struct phy *phy)
>> +{
>> +	if (phy->ops->power_on)
>> +		return phy->ops->power_on(phy);
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static inline int phy_power_off(struct phy *phy)
>> +{
>> +	if (phy->ops->power_off)
>> +		return phy->ops->power_off(phy);
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static inline int phy_pm_runtime_get(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return -EINVAL;
>> +
>> +	return pm_runtime_get(&phy->dev);
>> +}
>> +
>> +static inline int phy_pm_runtime_get_sync(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return -EINVAL;
>> +
>> +	return pm_runtime_get_sync(&phy->dev);
>> +}
>> +
>> +static inline int phy_pm_runtime_put(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return -EINVAL;
>> +
>> +	return pm_runtime_put(&phy->dev);
>> +}
>> +
>> +static inline int phy_pm_runtime_put_sync(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return -EINVAL;
>> +
>> +	return pm_runtime_put_sync(&phy->dev);
>> +}
>> +
>> +static inline void phy_pm_runtime_allow(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return;
>> +
>> +	pm_runtime_allow(&phy->dev);
>> +}
>> +
>> +static inline void phy_pm_runtime_forbid(struct phy *phy)
>> +{
>> +	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
>> +		return;
>> +
>> +	pm_runtime_forbid(&phy->dev);
>> +}
>
> Do we need to have all these runtime PM wrappers ? I guess you
> intended to avoid referencing phy->dev from the PHY consumers ?

Yeah.. I dint want pm_runtime of phy core device to be called from PHY 
consumers.

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

On 06/04/2013 02:26 PM, Kishon Vijay Abraham I wrote:
>>> +static inline int phy_init(struct phy *phy)
>>> +{
>>> +	pm_runtime_get_sync(&phy->dev);
>>
>> Hmm, no need to check return value here ? Also it looks a bit unexpected to
> 
> I purposely dint check the return values in order to support platforms 
> that don’t enable pm_runtime.

Then I guess this should be called conditionally and any errors returned
if runtime PM is enabled ? Not sure if pm_runtime_enabled() would be
helpful such situation.

>> possibly have runtime_resume callback of a PHY device called before ops->init()
>> call ? It seems a bit unclear what the purpose of init() callback is.
> 
> Not really. Anything that is used to initialize the PHY (internal 
> configuration) can go in phy_init. Usually in runtime_resume callback, 
> optional functional clocks are enabled and also in some cases context 
> restore is done. So it really makes sense to enable clocks/module 
> (pm_runtime_get_sync) before doing a PHY configuration (phy_init).

OK, that makes sense. All PHY device resources must be prepared anyway
before a PHY object is registered with the PHY core.

>>> +	if (phy->ops->init)
>>> +		return phy->ops->init(phy);
>>> +
>>> +	return -EINVAL;
>>> +}
>>> +
>>> +static inline int phy_exit(struct phy *phy)
>>> +{
>>> +	int ret = -EINVAL;
>>> +
>>> +	if (phy->ops->exit)
>>> +		ret = phy->ops->exit(phy);
>>> +
>>> +	pm_runtime_put_sync(&phy->dev);
>>> +
>>> +	return ret;
>>> +}
>>
>> Do phy_init/phy_exit need to be mandatory ? What if there is really
> 
> No. phy_init/phy_exit is not mandatory at all.
>> nothing to do in those callbacks ? Perhaps -ENOIOCTLCMD should be
>> returned if a callback is not implemented, so PHY users can recognize
>> such situation and proceed ?
> 
> So currently these APIs return -EINVAL if these callbacks are not 
> populated which is good enough IMHO.

But -EINVAL could be well returned from the callback function. Perhaps
ENOTSUPP could be used instead ?


Thanks,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kishon Vijay Abraham I June 5, 2013, 5:25 a.m. UTC | #7
Hi,

On Tuesday 04 June 2013 07:13 PM, Sylwester Nawrocki wrote:
> Hi,
>
> On 06/04/2013 02:26 PM, Kishon Vijay Abraham I wrote:
>>>> +static inline int phy_init(struct phy *phy)
>>>> +{
>>>> +	pm_runtime_get_sync(&phy->dev);
>>>
>>> Hmm, no need to check return value here ? Also it looks a bit unexpected to
>>
>> I purposely dint check the return values in order to support platforms
>> that don’t enable pm_runtime.
>
> Then I guess this should be called conditionally and any errors returned
> if runtime PM is enabled ? Not sure if pm_runtime_enabled() would be
> helpful such situation.
Indeed. I think it can be used.
>
>>> possibly have runtime_resume callback of a PHY device called before ops->init()
>>> call ? It seems a bit unclear what the purpose of init() callback is.
>>
>> Not really. Anything that is used to initialize the PHY (internal
>> configuration) can go in phy_init. Usually in runtime_resume callback,
>> optional functional clocks are enabled and also in some cases context
>> restore is done. So it really makes sense to enable clocks/module
>> (pm_runtime_get_sync) before doing a PHY configuration (phy_init).
>
> OK, that makes sense. All PHY device resources must be prepared anyway
> before a PHY object is registered with the PHY core.
>
>>>> +	if (phy->ops->init)
>>>> +		return phy->ops->init(phy);
>>>> +
>>>> +	return -EINVAL;
>>>> +}
>>>> +
>>>> +static inline int phy_exit(struct phy *phy)
>>>> +{
>>>> +	int ret = -EINVAL;
>>>> +
>>>> +	if (phy->ops->exit)
>>>> +		ret = phy->ops->exit(phy);
>>>> +
>>>> +	pm_runtime_put_sync(&phy->dev);
>>>> +
>>>> +	return ret;
>>>> +}
>>>
>>> Do phy_init/phy_exit need to be mandatory ? What if there is really
>>
>> No. phy_init/phy_exit is not mandatory at all.
>>> nothing to do in those callbacks ? Perhaps -ENOIOCTLCMD should be
>>> returned if a callback is not implemented, so PHY users can recognize
>>> such situation and proceed ?
>>
>> So currently these APIs return -EINVAL if these callbacks are not
>> populated which is good enough IMHO.
>
> But -EINVAL could be well returned from the callback function. Perhaps
> ENOTSUPP could be used instead ?

hmm.. could be..

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

Patch

diff --git a/Documentation/devicetree/bindings/phy/phy-bindings.txt b/Documentation/devicetree/bindings/phy/phy-bindings.txt
new file mode 100644
index 0000000..8ae844f
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-bindings.txt
@@ -0,0 +1,66 @@ 
+This document explains only the device tree data binding. For general
+information about PHY subsystem refer to Documentation/phy.txt
+
+PHY device node
+===============
+
+Required Properties:
+#phy-cells:	Number of cells in a PHY specifier;  The meaning of all those
+		cells is defined by the binding for the phy node. The PHY
+		provider can use the values in cells to find the appropriate
+		PHY.
+
+For example:
+
+phys: phy {
+    compatible = "xxx";
+    reg = <...>;
+    .
+    .
+    #phy-cells = <1>;
+    .
+    .
+};
+
+That node describes an IP block (PHY provider) that implements 2 different PHYs.
+In order to differentiate between these 2 PHYs, an additonal specifier should be
+given while trying to get a reference to it.
+
+PHY user node
+=============
+
+Required Properties:
+phys : the phandle for the PHY device (used by the PHY subsystem)
+phy-names : the names of the PHY corresponding to the PHYs present in the
+	    *phys* phandle
+
+Example 1:
+usb1: usb_otg_ss@xxx {
+    compatible = "xxx";
+    reg = <xxx>;
+    .
+    .
+    phys = <&usb2_phy>, <&usb3_phy>;
+    phy-names = "usb2phy", "usb3phy";
+    .
+    .
+};
+
+This node represents a controller that uses two PHYs, one for usb2 and one for
+usb3.
+
+Example 2:
+usb2: usb_otg_ss@xxx {
+    compatible = "xxx";
+    reg = <xxx>;
+    .
+    .
+    phys = <&phys 1>;
+    phy-names = "usbphy";
+    .
+    .
+};
+
+This node represents a controller that uses one of the PHYs of the PHY provider
+device defined previously. Note that the phy handle has an additional specifier
+"1" to differentiate between the two PHYs.
diff --git a/Documentation/phy.txt b/Documentation/phy.txt
new file mode 100644
index 0000000..408d25f
--- /dev/null
+++ b/Documentation/phy.txt
@@ -0,0 +1,123 @@ 
+			    PHY SUBSYSTEM
+		  Kishon Vijay Abraham I <kishon@ti.com>
+
+This document explains the Generic PHY Framework along with the APIs provided,
+and how-to-use.
+
+1. Introduction
+
+*PHY* is the abbreviation for physical layer. It is used to connect a device
+to the physical medium e.g., the USB controller has a PHY to provide functions
+such as serialization, de-serialization, encoding, decoding and is responsible
+for obtaining the required data transmission rate. Note that some USB
+controller has PHY functionality embedded into it and others use an external
+PHY. Other peripherals that uses a PHY include Wireless LAN, Ethernet,
+SATA etc.
+
+The intention of creating this framework is to bring the phy drivers spread
+all over the Linux kernel to drivers/phy to increase code re-use and for
+better code maintainability.
+
+This framework will be of use only to devices that uses external PHY (PHY
+functionality is not embedded within the controller).
+
+2. Registering/UnRegistering the PHY provider
+
+PHY provider refers to an entity that implements one or more PHY instances.
+For the simple case where the PHY provider implements only a single instance of
+the PHY, the framework provides its own implementation of of_xlate in
+of_phy_simple_xlate. If the PHY provider implements multiple instances, it
+should provide it's own implementation of of_xlate. of_xlate is used only for
+dt boot case.
+
+struct phy_provider *of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args));
+struct phy_provider *devm_of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args))
+
+of_phy_provider_register and devm_of_phy_provider_register can be used to
+register the phy_provider and it takes device, owner and of_xlate as
+arguments. For the dt boot case, all PHY providers should use one of the above
+2 APIs to register the PHY provider.
+
+void devm_of_phy_provider_unregister(struct device *dev,
+	struct phy_provider *phy_provider);
+void of_phy_provider_unregister(struct phy_provider *phy_provider);
+
+devm_of_phy_provider_unregister and of_phy_provider_unregister can be used to
+unregister the PHY.
+
+3. Creating the PHY
+
+The PHY driver should create the PHY in order for other peripheral controllers
+to make use of it. The PHY framework provides 2 APIs to create the PHY.
+
+struct phy *phy_create(struct device *dev, int id, const struct phy_ops *ops,
+	void *priv);
+struct phy *devm_phy_create(struct device *dev, int id,
+	const struct phy_ops *ops, void *priv);
+
+The PHY drivers can use one of the above 2 APIs to create the PHY by passing
+the device pointer, id, phy ops and a driver data.
+phy_ops is a set of function pointers for performing PHY operations such as
+init, exit, power_on and power_off.
+
+4. Getting a reference to the PHY
+
+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 *devm_phy_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 device name 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.
+
+5. Releasing a reference to the PHY
+
+When the controller no longer needs the PHY, it has to release the reference
+to the PHY it has obtained using the APIs mentioned in the above section. The
+PHY framework provides 2 APIS to release a reference to the PHY.
+
+void phy_put(struct phy *phy);
+void devm_phy_put(struct device *dev, struct phy *phy);
+
+Both these APIs are used to release a reference to the PHY and devm_phy_put
+destroys the devres associated with this PHY.
+
+6. Destroying the PHY
+
+When the driver that created the PHY is unloaded, it should destroy the PHY it
+created using one of the following 2 APIs.
+
+void phy_destroy(struct phy *phy);
+void devm_phy_destroy(struct device *dev, struct phy *phy);
+
+Both these APIs destroys the PHY and devm_phy_destroy destroys the devres
+associated with this PHY.
+
+7. PM Runtime
+
+This subsystem is pm runtime enabled. So while creating the PHY,
+pm_runtime_enable of the phy device created by this subsystem is called and
+while destroying the PHY, pm_runtime_disable is called. Note that the phy
+device created by this subsystem will be a child of the device that calls
+phy_create (PHY provider device).
+
+During phy_init, the clocks are enabled by calling get_sync and the clocks are
+disable by calling put_sync during phy_exit. get_sync of the phy_device
+created by this susbsystem will invoke get_sync of PHY provider device because
+of parent-child relationship. For all other pm operations, there are exported
+APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync, phy_pm_runtime_put,
+phy_pm_runtime_put_sync, phy_pm_runtime_allow and phy_pm_runtime_forbid.
+
+8. DeviceTree Binding
+
+The documentation for PHY dt binding can be found @
+Documentation/devicetree/bindings/phy/phy-bindings.txt
diff --git a/MAINTAINERS b/MAINTAINERS
index 68d376e..8584fdb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3515,6 +3515,13 @@  S:	Maintained
 F:	include/asm-generic
 F:	include/uapi/asm-generic
 
+GENERIC PHY FRAMEWORK
+M:	Kishon Vijay Abraham I <kishon@ti.com>
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+F:	drivers/phy/
+F:	include/linux/phy/
+
 GENERIC UIO DRIVER FOR PCI DEVICES
 M:	"Michael S. Tsirkin" <mst@redhat.com>
 L:	kvm@vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 9953a42..2943fb6 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -166,4 +166,6 @@  source "drivers/ipack/Kconfig"
 
 source "drivers/reset/Kconfig"
 
+source "drivers/phy/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 130abc1..ce9f0d2 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -8,6 +8,8 @@ 
 obj-y				+= irqchip/
 obj-y				+= bus/
 
+obj-y				+= phy/
+
 # GPIO must come after pinctrl as gpios may need to mux pins etc
 obj-y				+= pinctrl/
 obj-y				+= gpio/
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
new file mode 100644
index 0000000..5f85909
--- /dev/null
+++ b/drivers/phy/Kconfig
@@ -0,0 +1,13 @@ 
+#
+# PHY
+#
+
+menuconfig GENERIC_PHY
+	tristate "PHY Subsystem"
+	help
+	  Generic PHY support.
+
+	  This framework is designed to provide a generic interface for PHY
+	  devices present in the kernel. This layer will have the generic
+	  API by which phy drivers can create PHY using the phy framework and
+	  phy users can obtain reference to the PHY.
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
new file mode 100644
index 0000000..9e9560f
--- /dev/null
+++ b/drivers/phy/Makefile
@@ -0,0 +1,5 @@ 
+#
+# Makefile for the phy drivers.
+#
+
+obj-$(CONFIG_GENERIC_PHY)	+= phy-core.o
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
new file mode 100644
index 0000000..4e9e1c5
--- /dev/null
+++ b/drivers/phy/phy-core.c
@@ -0,0 +1,539 @@ 
+/*
+ * phy-core.c  --  Generic Phy framework.
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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 of the  License, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+
+static struct class *phy_class;
+static DEFINE_MUTEX(phy_provider_mutex);
+static LIST_HEAD(phy_provider_list);
+
+static void devm_phy_release(struct device *dev, void *res)
+{
+	struct phy *phy = *(struct phy **)res;
+
+	phy_put(phy);
+}
+
+static void devm_phy_provider_release(struct device *dev, void *res)
+{
+	struct phy_provider *phy_provider = *(struct phy_provider **)res;
+
+	of_phy_provider_unregister(phy_provider);
+}
+
+static void devm_phy_consume(struct device *dev, void *res)
+{
+	struct phy *phy = *(struct phy **)res;
+
+	phy_destroy(phy);
+}
+
+static int devm_phy_match(struct device *dev, void *res, void *match_data)
+{
+	return res == match_data;
+}
+
+static struct phy *phy_lookup(const char *phy_dev_name)
+{
+	struct phy *phy;
+	struct device *dev;
+	struct class_dev_iter iter;
+
+	class_dev_iter_init(&iter, phy_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		if (strcmp(dev_name(dev), phy_dev_name))
+			continue;
+
+		phy = container_of(dev, struct phy, dev);
+		class_dev_iter_exit(&iter);
+		return phy;
+	}
+
+	class_dev_iter_exit(&iter);
+	return ERR_PTR(-ENODEV);
+}
+
+static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
+{
+	struct phy_provider *phy_provider;
+
+	list_for_each_entry(phy_provider, &phy_provider_list, list) {
+		if (phy_provider->dev->of_node == node)
+			return phy_provider;
+	}
+
+	return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * of_phy_get() - lookup and obtain a reference to a phy by phandle
+ * @dev: device that requests this phy
+ * @index: the index of the phy
+ *
+ * Returns the phy associated with the given phandle value,
+ * after getting a refcount to it or -ENODEV if there is no such phy or
+ * -EPROBE_DEFER if there is a phandle to the phy, but the device is
+ * not yet loaded. This function uses of_xlate call back function provided
+ * while registering the phy_provider to find the phy instance.
+ */
+static struct phy *of_phy_get(struct device *dev, int index)
+{
+	int ret;
+	struct phy_provider *phy_provider;
+	struct phy *phy = NULL;
+	struct of_phandle_args args;
+
+	ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
+		index, &args);
+	if (ret) {
+		dev_dbg(dev, "failed to get phy in %s node\n",
+			dev->of_node->full_name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	mutex_lock(&phy_provider_mutex);
+	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;
+	}
+
+	phy = phy_provider->of_xlate(phy_provider->dev, &args);
+	module_put(phy_provider->owner);
+
+err0:
+	mutex_unlock(&phy_provider_mutex);
+	of_node_put(args.np);
+
+	return phy;
+}
+
+/**
+ * phy_put() - release the PHY
+ * @phy: the phy returned by phy_get()
+ *
+ * Releases a refcount the caller received from phy_get().
+ */
+void phy_put(struct phy *phy)
+{
+	if (IS_ERR(phy))
+		return;
+
+	module_put(phy->ops->owner);
+	put_device(&phy->dev);
+}
+EXPORT_SYMBOL_GPL(phy_put);
+
+/**
+ * devm_phy_put() - release the PHY
+ * @dev: device that wants to release this phy
+ * @phy: the phy returned by devm_phy_get()
+ *
+ * destroys the devres associated with this phy and invokes phy_put
+ * to release the phy.
+ */
+void devm_phy_put(struct device *dev, struct phy *phy)
+{
+	int r;
+
+	r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
+	dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_phy_put);
+
+/**
+ * of_phy_simple_xlate() - returns the phy instance from phy provider
+ * @dev: the PHY provider device
+ * @args: of_phandle_args (not used here)
+ *
+ * Intended to be used by phy provider for the common case where #phy-cells is
+ * 0. For other cases where #phy-cells is greater than '0', the phy provider
+ * should provide a custom of_xlate function that reads the *args* and returns
+ * the appropriate phy.
+ */
+struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args
+	*args)
+{
+	struct phy *phy;
+	struct class_dev_iter iter;
+	struct device_node *node = dev->of_node;
+
+	class_dev_iter_init(&iter, phy_class, NULL, NULL);
+	while ((dev = class_dev_iter_next(&iter))) {
+		phy = container_of(dev, struct phy, dev);
+		if (node != phy->dev.of_node)
+			continue;
+
+		class_dev_iter_exit(&iter);
+		return phy;
+	}
+
+	class_dev_iter_exit(&iter);
+	return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(of_phy_simple_xlate);
+
+/**
+ * phy_get() - lookup and obtain a reference to a 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
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy.  The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *phy_get(struct device *dev, const char *string)
+{
+	int index = 0;
+	struct phy *phy = NULL;
+
+	if (string == NULL) {
+		dev_WARN(dev, "missing string\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (dev->of_node) {
+		index = of_property_match_string(dev->of_node, "phy-names",
+			string);
+		phy = of_phy_get(dev, index);
+		if (IS_ERR(phy)) {
+			dev_WARN(dev, "unable to find phy\n");
+			return phy;
+		}
+	} else {
+		phy = phy_lookup(string);
+		if (IS_ERR(phy)) {
+			dev_WARN(dev, "unable to find phy\n");
+			return phy;
+		}
+	}
+
+	if (!try_module_get(phy->ops->owner))
+		return ERR_PTR(-EPROBE_DEFER);
+
+	get_device(&phy->dev);
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(phy_get);
+
+/**
+ * devm_phy_get() - lookup and obtain a reference to a 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.
+ */
+struct phy *devm_phy_get(struct device *dev, const char *string)
+{
+	struct phy **ptr, *phy;
+
+	ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	phy = phy_get(dev, string);
+	if (!IS_ERR(phy)) {
+		*ptr = phy;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_get);
+
+/**
+ * phy_create() - create a new phy
+ * @dev: device that is creating the new phy
+ * @id: id of the phy
+ * @ops: function pointers for performing phy operations
+ * @priv: private data from phy driver
+ *
+ * Called to create a phy using phy framework.
+ */
+struct phy *phy_create(struct device *dev, u8 id, const struct phy_ops *ops,
+	void *priv)
+{
+	int ret;
+	struct phy *phy;
+
+	if (!dev) {
+		dev_WARN(dev, "no device provided for PHY\n");
+		ret = -EINVAL;
+		goto err0;
+	}
+
+	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+	if (!phy) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	device_initialize(&phy->dev);
+
+	phy->dev.class = phy_class;
+	phy->dev.parent = dev;
+	phy->dev.of_node = dev->of_node;
+	phy->id = id;
+	phy->ops = ops;
+
+	dev_set_drvdata(&phy->dev, priv);
+
+	ret = dev_set_name(&phy->dev, "%s.%d", dev_name(dev), id);
+	if (ret)
+		goto err1;
+
+	ret = device_add(&phy->dev);
+	if (ret)
+		goto err1;
+
+	pm_runtime_enable(&phy->dev);
+
+	return phy;
+
+err1:
+	put_device(&phy->dev);
+	kfree(phy);
+
+err0:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(phy_create);
+
+/**
+ * devm_phy_create() - create a new phy
+ * @dev: device that is creating the new phy
+ * @id: id of the phy
+ * @ops: function pointers for performing phy operations
+ * @priv: private data from phy driver
+ *
+ * Creates a new PHY device adding it to the PHY class.
+ * While at that, it also associates the device with the phy using devres.
+ * On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_phy_create(struct device *dev, u8 id,
+	const struct phy_ops *ops, void *priv)
+{
+	struct phy **ptr, *phy;
+
+	ptr = devres_alloc(devm_phy_consume, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	phy = phy_create(dev, id, ops, priv);
+	if (!IS_ERR(phy)) {
+		*ptr = phy;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_create);
+
+/**
+ * phy_destroy() - destroy the phy
+ * @phy: the phy to be destroyed
+ *
+ * Called to destroy the phy.
+ */
+void phy_destroy(struct phy *phy)
+{
+	pm_runtime_disable(&phy->dev);
+	device_unregister(&phy->dev);
+}
+EXPORT_SYMBOL_GPL(phy_destroy);
+
+/**
+ * devm_phy_destroy() - destroy the PHY
+ * @dev: device that wants to release this phy
+ * @phy: the phy returned by devm_phy_get()
+ *
+ * destroys the devres associated with this phy and invokes phy_destroy
+ * to destroy the phy.
+ */
+void devm_phy_destroy(struct device *dev, struct phy *phy)
+{
+	int r;
+
+	r = devres_destroy(dev, devm_phy_consume, devm_phy_match, phy);
+	dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_phy_destroy);
+
+/**
+ * of_phy_provider_register() - create/register phy provider with the framework
+ * @dev: struct device of the phy provider
+ * @owner: the module owner containing of_xlate
+ * @of_xlate: function pointer to obtain phy instance from phy provider
+ *
+ * Creates struct phy_provider from dev and of_xlate function pointer.
+ * This is used in the case of dt boot for finding the phy instance from
+ * phy provider.
+ */
+struct phy_provider *of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args))
+{
+	struct phy_provider *phy_provider;
+
+	phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL);
+	if (!phy_provider)
+		return ERR_PTR(-ENOMEM);
+
+	phy_provider->dev = dev;
+	phy_provider->owner = owner;
+	phy_provider->of_xlate = of_xlate;
+
+	mutex_lock(&phy_provider_mutex);
+	list_add_tail(&phy_provider->list, &phy_provider_list);
+	mutex_unlock(&phy_provider_mutex);
+
+	return phy_provider;
+}
+EXPORT_SYMBOL_GPL(of_phy_provider_register);
+
+/**
+ * devm_of_phy_provider_register() - create/register phy provider with the
+ * framework
+ * @dev: struct device of the phy provider
+ * @owner: the module owner containing of_xlate
+ * @of_xlate: function pointer to obtain phy instance from phy provider
+ *
+ * Creates struct phy_provider from dev and of_xlate function pointer.
+ * This is used in the case of dt boot for finding the phy instance from
+ * phy provider. While at that, it also associates the device with the
+ * phy provider using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ */
+struct phy_provider *devm_of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args))
+{
+	struct phy_provider **ptr, *phy_provider;
+
+	ptr = devres_alloc(devm_phy_provider_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	phy_provider = of_phy_provider_register(dev, owner, of_xlate);
+	if (!IS_ERR(phy_provider)) {
+		*ptr = phy_provider;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return phy_provider;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_provider_register);
+
+/**
+ * of_phy_provider_unregister() - unregister phy provider from the framework
+ * @phy_provider: phy provider returned by of_phy_provider_register()
+ *
+ * Removes the phy_provider created using of_phy_provider_register().
+ */
+void of_phy_provider_unregister(struct phy_provider *phy_provider)
+{
+	if (IS_ERR(phy_provider))
+		return;
+
+	mutex_lock(&phy_provider_mutex);
+	list_del(&phy_provider->list);
+	kfree(phy_provider);
+	mutex_unlock(&phy_provider_mutex);
+}
+EXPORT_SYMBOL_GPL(of_phy_provider_unregister);
+
+/**
+ * devm_of_phy_provider_unregister() - remove phy provider from the framework
+ * @dev: struct device of the phy provider
+ *
+ * destroys the devres associated with this phy provider and invokes
+ * of_phy_provider_unregister to unregister the phy provider.
+ */
+void devm_of_phy_provider_unregister(struct device *dev,
+	struct phy_provider *phy_provider) {
+	int r;
+
+	r = devres_destroy(dev, devm_phy_provider_release, devm_phy_match,
+		phy_provider);
+	dev_WARN_ONCE(dev, r, "couldn't find PHY provider device resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_provider_unregister);
+
+/**
+ * phy_release() - release the phy
+ * @dev: the dev member within phy
+ *
+ * when the last reference to the device is removed; it is called
+ * from the embedded kobject as release method.
+ */
+static void phy_release(struct device *dev)
+{
+	struct phy *phy;
+
+	phy = container_of(dev, struct phy, dev);
+	dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+	kfree(phy);
+}
+
+static int __init phy_core_init(void)
+{
+	phy_class = class_create(THIS_MODULE, "phy");
+	if (IS_ERR(phy_class)) {
+		pr_err("failed to create phy class --> %ld\n",
+			PTR_ERR(phy_class));
+		return PTR_ERR(phy_class);
+	}
+
+	phy_class->dev_release = phy_release;
+
+	return 0;
+}
+module_init(phy_core_init);
+
+static void __exit phy_core_exit(void)
+{
+	class_destroy(phy_class);
+}
+module_exit(phy_core_exit);
+
+MODULE_DESCRIPTION("Generic PHY Framework");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
new file mode 100644
index 0000000..e7a570a
--- /dev/null
+++ b/include/linux/phy/phy.h
@@ -0,0 +1,248 @@ 
+/*
+ * phy.h -- generic phy header file
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_PHY_H
+#define __DRIVERS_PHY_H
+
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+
+struct phy;
+
+/**
+ * struct phy_ops - set of function pointers for performing phy operations
+ * @init: operation to be performed for initializing phy
+ * @exit: operation to be performed while exiting
+ * @power_on: powering on the phy
+ * @power_off: powering off the phy
+ * @owner: the module owner containing the ops
+ */
+struct phy_ops {
+	int	(*init)(struct phy *phy);
+	int	(*exit)(struct phy *phy);
+	int	(*power_on)(struct phy *phy);
+	int	(*power_off)(struct phy *phy);
+	struct module *owner;
+};
+
+/**
+ * struct phy - represent the phy device
+ * @dev: phy device
+ * @id: id of the phy
+ * @ops: function pointers for performing phy operations
+ */
+struct phy {
+	struct device		dev;
+	int			id;
+	const struct phy_ops	*ops;
+};
+
+/**
+ * struct phy_provider - represent the phy provider
+ * @dev: phy provider device
+ * @owner: the module owner having of_xlate
+ * @of_xlate: function pointer to obtain phy instance from phy pointer
+ * @list: to maintain a linked list of PHY provider
+ */
+struct phy_provider {
+	struct device		*dev;
+	struct module		*owner;
+	struct list_head	list;
+	struct phy * (*of_xlate)(struct device *dev,
+		struct of_phandle_args *args);
+};
+
+#if IS_ENABLED(CONFIG_GENERIC_PHY)
+extern struct phy *phy_get(struct device *dev, const char *string);
+extern struct phy *devm_phy_get(struct device *dev, const char *string);
+extern void phy_put(struct phy *phy);
+extern void devm_phy_put(struct device *dev, struct phy *phy);
+extern struct phy *of_phy_simple_xlate(struct device *dev,
+	struct of_phandle_args *args);
+extern struct phy *phy_create(struct device *dev, u8 id,
+	const struct phy_ops *ops, void *priv);
+extern struct phy *devm_phy_create(struct device *dev, u8 id,
+	const struct phy_ops *ops, void *priv);
+extern void phy_destroy(struct phy *phy);
+extern void devm_phy_destroy(struct device *dev, struct phy *phy);
+extern struct phy_provider *of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args));
+extern struct phy_provider *devm_of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args));
+extern void of_phy_provider_unregister(struct phy_provider *phy_provider);
+extern void devm_of_phy_provider_unregister(struct device *dev,
+	struct phy_provider *phy_provider);
+#else
+static inline struct phy *phy_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 void phy_put(struct phy *phy)
+{
+}
+
+static inline void devm_phy_put(struct device *dev, struct phy *phy)
+{
+}
+
+static inline struct phy *of_phy_simple_xlate(struct device *dev,
+	struct of_phandle_args *args)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy *phy_create(struct device *dev, u8 id,
+	const struct phy_ops *ops, void *priv)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy *devm_phy_create(struct device *dev, u8 id,
+	const struct phy_ops *ops, void *priv)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void phy_destroy(struct phy *phy)
+{
+}
+
+static inline void devm_phy_destroy(struct device *dev, struct phy *phy)
+{
+}
+
+static inline struct phy_provider *of_phy_provider_register(struct device *dev,
+	struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args))
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline struct phy_provider *devm_of_phy_provider_register(struct device
+	*dev, struct module *owner, struct phy * (*of_xlate)(struct device *dev,
+	struct of_phandle_args *args))
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void of_phy_provider_unregister(struct phy_provider *phy_provider)
+{
+}
+
+static inline void devm_of_phy_provider_unregister(struct device *dev,
+	struct phy_provider *phy_provider)
+{
+}
+#endif
+
+static inline int phy_init(struct phy *phy)
+{
+	pm_runtime_get_sync(&phy->dev);
+
+	if (phy->ops->init)
+		return phy->ops->init(phy);
+
+	return -EINVAL;
+}
+
+static inline int phy_exit(struct phy *phy)
+{
+	int ret = -EINVAL;
+
+	if (phy->ops->exit)
+		ret = phy->ops->exit(phy);
+
+	pm_runtime_put_sync(&phy->dev);
+
+	return ret;
+}
+
+static inline int phy_power_on(struct phy *phy)
+{
+	if (phy->ops->power_on)
+		return phy->ops->power_on(phy);
+
+	return -EINVAL;
+}
+
+static inline int phy_power_off(struct phy *phy)
+{
+	if (phy->ops->power_off)
+		return phy->ops->power_off(phy);
+
+	return -EINVAL;
+}
+
+static inline int phy_pm_runtime_get(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return -EINVAL;
+
+	return pm_runtime_get(&phy->dev);
+}
+
+static inline int phy_pm_runtime_get_sync(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return -EINVAL;
+
+	return pm_runtime_get_sync(&phy->dev);
+}
+
+static inline int phy_pm_runtime_put(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return -EINVAL;
+
+	return pm_runtime_put(&phy->dev);
+}
+
+static inline int phy_pm_runtime_put_sync(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return -EINVAL;
+
+	return pm_runtime_put_sync(&phy->dev);
+}
+
+static inline void phy_pm_runtime_allow(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return;
+
+	pm_runtime_allow(&phy->dev);
+}
+
+static inline void phy_pm_runtime_forbid(struct phy *phy)
+{
+	if (WARN(IS_ERR(phy), "Invalid PHY reference\n"))
+		return;
+
+	pm_runtime_forbid(&phy->dev);
+}
+#endif /* __DRIVERS_PHY_H */