docs: phy: place documentation under driver-api
This subsystem-specific documentation belongs to the driver-api. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
16
Documentation/driver-api/phy/index.rst
Normal file
16
Documentation/driver-api/phy/index.rst
Normal file
@@ -0,0 +1,16 @@
|
||||
=====================
|
||||
Generic PHY Framework
|
||||
=====================
|
||||
|
||||
.. toctree::
|
||||
|
||||
phy
|
||||
samsung-usb2
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
||||
|
197
Documentation/driver-api/phy/phy.rst
Normal file
197
Documentation/driver-api/phy/phy.rst
Normal file
@@ -0,0 +1,197 @@
|
||||
=============
|
||||
PHY subsystem
|
||||
=============
|
||||
|
||||
:Author: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
|
||||
This document explains the Generic PHY Framework along with the APIs provided,
|
||||
and how-to-use.
|
||||
|
||||
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
|
||||
controllers have PHY functionality embedded into it and others use an external
|
||||
PHY. Other peripherals that use 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 use external PHY (PHY
|
||||
functionality is not embedded within the controller).
|
||||
|
||||
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 its own implementation of of_xlate. of_xlate is used only for
|
||||
dt boot case.
|
||||
|
||||
::
|
||||
|
||||
#define of_phy_provider_register(dev, xlate) \
|
||||
__of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
|
||||
|
||||
#define devm_of_phy_provider_register(dev, xlate) \
|
||||
__devm_of_phy_provider_register((dev), NULL, THIS_MODULE,
|
||||
(xlate))
|
||||
|
||||
of_phy_provider_register and devm_of_phy_provider_register macros can be used to
|
||||
register the phy_provider and it takes device and of_xlate as
|
||||
arguments. For the dt boot case, all PHY providers should use one of the above
|
||||
2 macros to register the PHY provider.
|
||||
|
||||
Often the device tree nodes associated with a PHY provider will contain a set
|
||||
of children that each represent a single PHY. Some bindings may nest the child
|
||||
nodes within extra levels for context and extensibility, in which case the low
|
||||
level of_phy_provider_register_full() and devm_of_phy_provider_register_full()
|
||||
macros can be used to override the node containing the children.
|
||||
|
||||
::
|
||||
|
||||
#define of_phy_provider_register_full(dev, children, xlate) \
|
||||
__of_phy_provider_register(dev, children, THIS_MODULE, xlate)
|
||||
|
||||
#define devm_of_phy_provider_register_full(dev, children, xlate) \
|
||||
__devm_of_phy_provider_register_full(dev, children,
|
||||
THIS_MODULE, xlate)
|
||||
|
||||
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.
|
||||
|
||||
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, struct device_node *node,
|
||||
const struct phy_ops *ops);
|
||||
struct phy *devm_phy_create(struct device *dev,
|
||||
struct device_node *node,
|
||||
const struct phy_ops *ops);
|
||||
|
||||
The PHY drivers can use one of the above 2 APIs to create the PHY by passing
|
||||
the device pointer and phy ops.
|
||||
phy_ops is a set of function pointers for performing PHY operations such as
|
||||
init, exit, power_on and power_off.
|
||||
|
||||
Inorder to dereference the private data (in phy_ops), the phy provider driver
|
||||
can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
|
||||
phy_ops to get back the private data.
|
||||
|
||||
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 *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
|
||||
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 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.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,
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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 destroy the PHY and devm_phy_destroy destroys the devres
|
||||
associated with this PHY.
|
||||
|
||||
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).
|
||||
|
||||
So pm_runtime_get_sync of the phy_device created by this subsystem will invoke
|
||||
pm_runtime_get_sync of PHY provider device because of parent-child relationship.
|
||||
It should also be noted that phy_power_on and phy_power_off performs
|
||||
phy_pm_runtime_get_sync and phy_pm_runtime_put respectively.
|
||||
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 for performing PM operations.
|
||||
|
||||
PHY Mappings
|
||||
============
|
||||
|
||||
In order to get reference to a PHY without help from DeviceTree, the framework
|
||||
offers lookups which can be compared to clkdev that allow clk structures to be
|
||||
bound to devices. A lookup can be made be made during runtime when a handle to
|
||||
the struct phy already exists.
|
||||
|
||||
The framework offers the following API for registering and unregistering the
|
||||
lookups::
|
||||
|
||||
int phy_create_lookup(struct phy *phy, const char *con_id,
|
||||
const char *dev_id);
|
||||
void phy_remove_lookup(struct phy *phy, const char *con_id,
|
||||
const char *dev_id);
|
||||
|
||||
DeviceTree Binding
|
||||
==================
|
||||
|
||||
The documentation for PHY dt binding can be found @
|
||||
Documentation/devicetree/bindings/phy/phy-bindings.txt
|
137
Documentation/driver-api/phy/samsung-usb2.rst
Normal file
137
Documentation/driver-api/phy/samsung-usb2.rst
Normal file
@@ -0,0 +1,137 @@
|
||||
====================================
|
||||
Samsung USB 2.0 PHY adaptation layer
|
||||
====================================
|
||||
|
||||
1. Description
|
||||
--------------
|
||||
|
||||
The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
|
||||
among many SoCs. In spite of the similarities it proved difficult to
|
||||
create a one driver that would fit all these PHY controllers. Often
|
||||
the differences were minor and were found in particular bits of the
|
||||
registers of the PHY. In some rare cases the order of register writes or
|
||||
the PHY powering up process had to be altered. This adaptation layer is
|
||||
a compromise between having separate drivers and having a single driver
|
||||
with added support for many special cases.
|
||||
|
||||
2. Files description
|
||||
--------------------
|
||||
|
||||
- phy-samsung-usb2.c
|
||||
This is the main file of the adaptation layer. This file contains
|
||||
the probe function and provides two callbacks to the Generic PHY
|
||||
Framework. This two callbacks are used to power on and power off the
|
||||
phy. They carry out the common work that has to be done on all version
|
||||
of the PHY module. Depending on which SoC was chosen they execute SoC
|
||||
specific callbacks. The specific SoC version is selected by choosing
|
||||
the appropriate compatible string. In addition, this file contains
|
||||
struct of_device_id definitions for particular SoCs.
|
||||
|
||||
- phy-samsung-usb2.h
|
||||
This is the include file. It declares the structures used by this
|
||||
driver. In addition it should contain extern declarations for
|
||||
structures that describe particular SoCs.
|
||||
|
||||
3. Supporting SoCs
|
||||
------------------
|
||||
|
||||
To support a new SoC a new file should be added to the drivers/phy
|
||||
directory. Each SoC's configuration is stored in an instance of the
|
||||
struct samsung_usb2_phy_config::
|
||||
|
||||
struct samsung_usb2_phy_config {
|
||||
const struct samsung_usb2_common_phy *phys;
|
||||
int (*rate_to_clk)(unsigned long, u32 *);
|
||||
unsigned int num_phys;
|
||||
bool has_mode_switch;
|
||||
};
|
||||
|
||||
The num_phys is the number of phys handled by the driver. `*phys` is an
|
||||
array that contains the configuration for each phy. The has_mode_switch
|
||||
property is a boolean flag that determines whether the SoC has USB host
|
||||
and device on a single pair of pins. If so, a special register has to
|
||||
be modified to change the internal routing of these pins between a USB
|
||||
device or host module.
|
||||
|
||||
For example the configuration for Exynos 4210 is following::
|
||||
|
||||
const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
|
||||
.has_mode_switch = 0,
|
||||
.num_phys = EXYNOS4210_NUM_PHYS,
|
||||
.phys = exynos4210_phys,
|
||||
.rate_to_clk = exynos4210_rate_to_clk,
|
||||
}
|
||||
|
||||
- `int (*rate_to_clk)(unsigned long, u32 *)`
|
||||
|
||||
The rate_to_clk callback is to convert the rate of the clock
|
||||
used as the reference clock for the PHY module to the value
|
||||
that should be written in the hardware register.
|
||||
|
||||
The exynos4210_phys configuration array is as follows::
|
||||
|
||||
static const struct samsung_usb2_common_phy exynos4210_phys[] = {
|
||||
{
|
||||
.label = "device",
|
||||
.id = EXYNOS4210_DEVICE,
|
||||
.power_on = exynos4210_power_on,
|
||||
.power_off = exynos4210_power_off,
|
||||
},
|
||||
{
|
||||
.label = "host",
|
||||
.id = EXYNOS4210_HOST,
|
||||
.power_on = exynos4210_power_on,
|
||||
.power_off = exynos4210_power_off,
|
||||
},
|
||||
{
|
||||
.label = "hsic0",
|
||||
.id = EXYNOS4210_HSIC0,
|
||||
.power_on = exynos4210_power_on,
|
||||
.power_off = exynos4210_power_off,
|
||||
},
|
||||
{
|
||||
.label = "hsic1",
|
||||
.id = EXYNOS4210_HSIC1,
|
||||
.power_on = exynos4210_power_on,
|
||||
.power_off = exynos4210_power_off,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
- `int (*power_on)(struct samsung_usb2_phy_instance *);`
|
||||
`int (*power_off)(struct samsung_usb2_phy_instance *);`
|
||||
|
||||
These two callbacks are used to power on and power off the phy
|
||||
by modifying appropriate registers.
|
||||
|
||||
Final change to the driver is adding appropriate compatible value to the
|
||||
phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
|
||||
added to the struct of_device_id samsung_usb2_phy_of_match[] array::
|
||||
|
||||
#ifdef CONFIG_PHY_EXYNOS4210_USB2
|
||||
{
|
||||
.compatible = "samsung,exynos4210-usb2-phy",
|
||||
.data = &exynos4210_usb2_phy_config,
|
||||
},
|
||||
#endif
|
||||
|
||||
To add further flexibility to the driver the Kconfig file enables to
|
||||
include support for selected SoCs in the compiled driver. The Kconfig
|
||||
entry for Exynos 4210 is following::
|
||||
|
||||
config PHY_EXYNOS4210_USB2
|
||||
bool "Support for Exynos 4210"
|
||||
depends on PHY_SAMSUNG_USB2
|
||||
depends on CPU_EXYNOS4210
|
||||
help
|
||||
Enable USB PHY support for Exynos 4210. This option requires that
|
||||
Samsung USB 2.0 PHY driver is enabled and means that support for this
|
||||
particular SoC is compiled in the driver. In case of Exynos 4210 four
|
||||
phys are available - device, host, HSCI0 and HSCI1.
|
||||
|
||||
The newly created file that supports the new SoC has to be also added to the
|
||||
Makefile. In case of Exynos 4210 the added line is following::
|
||||
|
||||
obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
|
||||
|
||||
After completing these steps the support for the new SoC should be ready.
|
Reference in New Issue
Block a user