Improvements in phy-core specifically on PHY core finds the PHY in the case

of non-dt boot. Adds three new PHY drivers using the PHY framework and some
 miscellaneous fixes and cleanups.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJUdsDPAAoJEA5ceFyATYLZvxMP/2xNqB8P51jzoPDH3ZhubINg
 0A0nuzjPhYRDMYsPMEydno7h2X5qeJtY6NanjE5Z9N3jLzSvhN60SkYXqTBX5MYB
 WweSug/grQOTBlo3vtFgih2bPax8qAV24BPDCGgQ71zTctU2Ni/DsJoejQbxDDuJ
 BaC3cRhje8tljygS+wqqEWNyh1SezhqPKmI3tkEpCaZ3gcK1wvvTnLc5kkZW/855
 27HiqAcWZKbczv5qGUqVoYWd/psgjF2o/8nqPz0A+uMrh3RaaMMgTjh6LQW9nVrd
 IiWCbyLwwDsdVQL7PIziD+NBn8ISPMKyf9j1Exxt41wkluBYfJVlE6KGALKRatv6
 /ZxiwW3iU1pMFZaTnfasH0ChJTP13IQafX/Dne8BNoUhVr/PjGwXN3mJfBTpyTjN
 E10+cPpVKWCKyDtvqRUPeQp//+th2oXxNSJ++ealrr/xARamjWpUVxjTZwhmAS2C
 7tTOierElhVyk3XNhrdGPhn7B9I5zquIVv0AALU3D7GWWLsIBbEKihYCDSClkKgl
 iLykw7W7Uj0PDzkeSGYmwd3vVLrDvcnDyzJby4hojyrCZ0N/873iz2APJGrWdSMg
 j+JBRAXI9LMXDMfhD3oRaq1uDxGhg7BIm903V3r38L2MmG7902pKK2iBaYwpRc7o
 dE8iljdnygp7Rat/4vTo
 =oo3u
 -----END PGP SIGNATURE-----

Merge tag 'for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-testing

Kishon writes:

Improvements in phy-core specifically on PHY core finds the PHY in the case
of non-dt boot. Adds three new PHY drivers using the PHY framework and some
miscellaneous fixes and cleanups.
This commit is contained in:
Greg Kroah-Hartman 2014-11-27 08:25:20 -08:00
commit 842f57baab
39 changed files with 2207 additions and 201 deletions

View File

@ -6,11 +6,17 @@ Required Properties:
- interrupts : Interrupt controller is using - interrupts : Interrupt controller is using
- nr-ports : Number of SATA ports in use. - nr-ports : Number of SATA ports in use.
Optional Properties:
- phys : List of phandles to sata phys
- phy-names : Should be "0", "1", etc, one number per phandle
Example: Example:
sata@80000 { sata@80000 {
compatible = "marvell,orion-sata"; compatible = "marvell,orion-sata";
reg = <0x80000 0x5000>; reg = <0x80000 0x5000>;
interrupts = <21>; interrupts = <21>;
phys = <&sata_phy0>, <&sata_phy1>;
phy-names = "0", "1";
nr-ports = <2>; nr-ports = <2>;
} }

View File

@ -2,7 +2,9 @@ Berlin SATA PHY
--------------- ---------------
Required properties: Required properties:
- compatible: should be "marvell,berlin2q-sata-phy" - compatible: should be one of
"marvell,berlin2-sata-phy"
"marvell,berlin2q-sata-phy"
- address-cells: should be 1 - address-cells: should be 1
- size-cells: should be 0 - size-cells: should be 0
- phy-cells: from the generic PHY bindings, must be 1 - phy-cells: from the generic PHY bindings, must be 1

View File

@ -0,0 +1,16 @@
* Marvell Berlin USB PHY
Required properties:
- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy"
- reg: base address and length of the registers
- #phys-cells: should be 0
- resets: reference to the reset controller
Example:
usb-phy@f774000 {
compatible = "marvell,berlin2-usb-phy";
reg = <0xf774000 0x128>;
#phy-cells = <0>;
resets = <&chip 0x104 14>;
};

View File

@ -0,0 +1,128 @@
STMicroelectronics STi MIPHY28LP PHY binding
============================================
This binding describes a miphy device that is used to control PHY hardware
for SATA, PCIe or USB3.
Required properties (controller (parent) node):
- compatible : Should be "st,miphy28lp-phy".
- st,syscfg : Should be a phandle of the system configuration register group
which contain the SATA, PCIe or USB3 mode setting bits.
Required nodes : A sub-node is required for each channel the controller
provides. Address range information including the usual
'reg' and 'reg-names' properties are used inside these
nodes to describe the controller's topology. These nodes
are translated by the driver's .xlate() function.
Required properties (port (child) node):
- #phy-cells : Should be 1 (See second example)
Cell after port phandle is device type from:
- PHY_TYPE_SATA
- PHY_TYPE_PCI
- PHY_TYPE_USB3
- reg : Address and length of the register set for the device.
- reg-names : The names of the register addresses corresponding to the registers
filled in "reg". It can also contain the offset of the system configuration
registers used as glue-logic to setup the device for SATA/PCIe or USB3
devices.
- resets : phandle to the parent reset controller.
- reset-names : Associated name must be "miphy-sw-rst".
Optional properties (port (child) node):
- st,osc-rdy : to check the MIPHY0_OSC_RDY status in the glue-logic. This
is not available in all the MiPHY. For example, for STiH407, only the
MiPHY0 has this bit.
- st,osc-force-ext : to select the external oscillator. This can change from
different MiPHY inside the same SoC.
- st,sata_gen : to select which SATA_SPDMODE has to be set in the SATA system config
register.
- st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive
line).
- st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe).
- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values.
example:
miphy28lp_phy: miphy28lp@9b22000 {
compatible = "st,miphy28lp-phy";
st,syscfg = <&syscfg_core>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
phy_port0: port@9b22000 {
reg = <0x9b22000 0xff>,
<0x9b09000 0xff>,
<0x9b04000 0xff>,
<0x114 0x4>, /* sysctrl MiPHY cntrl */
<0x818 0x4>, /* sysctrl MiPHY status*/
<0xe0 0x4>, /* sysctrl PCIe */
<0xec 0x4>; /* sysctrl SATA */
reg-names = "sata-up",
"pcie-up",
"pipew",
"miphy-ctrl-glue",
"miphy-status-glue",
"pcie-glue",
"sata-glue";
#phy-cells = <1>;
st,osc-rdy;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY0_SOFTRESET>;
};
phy_port1: port@9b2a000 {
reg = <0x9b2a000 0xff>,
<0x9b19000 0xff>,
<0x9b14000 0xff>,
<0x118 0x4>,
<0x81c 0x4>,
<0xe4 0x4>,
<0xf0 0x4>;
reg-names = "sata-up",
"pcie-up",
"pipew",
"miphy-ctrl-glue",
"miphy-status-glue",
"pcie-glue",
"sata-glue";
#phy-cells = <1>;
st,osc-force-ext;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY1_SOFTRESET>;
};
phy_port2: port@8f95000 {
reg = <0x8f95000 0xff>,
<0x8f90000 0xff>,
<0x11c 0x4>,
<0x820 0x4>;
reg-names = "pipew",
"usb3-up",
"miphy-ctrl-glue",
"miphy-status-glue";
#phy-cells = <1>;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
};
};
Specifying phy control of devices
=================================
Device nodes should specify the configuration required in their "phys"
property, containing a phandle to the miphy device node and an index
specifying which configuration to use, as described in phy-bindings.txt.
example:
sata0: sata@9b20000 {
...
phys = <&phy_port0 PHY_TYPE_SATA>;
...
};
Macro definitions for the supported miphy configuration can be found in:
include/dt-bindings/phy/phy-miphy28lp.h

View File

@ -0,0 +1,43 @@
* Marvell MVEBU SATA PHY
Power control for the SATA phy found on Marvell MVEBU SoCs.
This document extends the binding described in phy-bindings.txt
Required properties :
- reg : Offset and length of the register set for the SATA device
- compatible : Should be "marvell,mvebu-sata-phy"
- clocks : phandle of clock and specifier that supplies the device
- clock-names : Should be "sata"
Example:
sata-phy@84000 {
compatible = "marvell,mvebu-sata-phy";
reg = <0x84000 0x0334>;
clocks = <&gate_clk 15>;
clock-names = "sata";
#phy-cells = <0>;
status = "ok";
};
Armada 375 USB cluster
----------------------
Armada 375 comes with an USB2 host and device controller and an USB3
controller. The USB cluster control register allows to manage common
features of both USB controllers.
Required properties:
- compatible: "marvell,armada-375-usb-cluster"
- reg: Should contain usb cluster register location and length.
- #phy-cells : from the generic phy bindings, must be 1. Possible
values are 1 (USB2), 2 (USB3).
Example:
usbcluster: usb-cluster@18400 {
compatible = "marvell,armada-375-usb-cluster";
reg = <0x18400 0x4>;
#phy-cells = <1>
};

View File

@ -128,6 +128,7 @@ Required properties:
- compatible : Should be set to one of the following supported values: - compatible : Should be set to one of the following supported values:
- "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC,
- "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC.
- "samsung,exynos7-usbdrd-phy" - for exynos7 SoC.
- reg : Register offset and length of USB DRD PHY register set; - reg : Register offset and length of USB DRD PHY register set;
- clocks: Clock IDs array as required by the controller - clocks: Clock IDs array as required by the controller
- clock-names: names of clocks correseponding to IDs in the clock property; - clock-names: names of clocks correseponding to IDs in the clock property;
@ -138,6 +139,11 @@ Required properties:
PHY operations, associated by phy name. It is used to PHY operations, associated by phy name. It is used to
determine bit values for clock settings register. determine bit values for clock settings register.
For Exynos5420 this is given as 'sclk_usbphy30' in CMU. For Exynos5420 this is given as 'sclk_usbphy30' in CMU.
- optional clocks: Exynos7 SoC has now following additional
gate clocks available:
- phy_pipe: for PIPE3 phy
- phy_utmi: for UTMI+ phy
- itp: for ITP generation
- samsung,pmu-syscon: phandle for PMU system controller interface, used to - samsung,pmu-syscon: phandle for PMU system controller interface, used to
control pmu registers for power isolation. control pmu registers for power isolation.
- #phy-cells : from the generic PHY bindings, must be 1; - #phy-cells : from the generic PHY bindings, must be 1;

View File

@ -54,18 +54,14 @@ 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. 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, struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops);
struct phy_init_data *init_data);
struct phy *devm_phy_create(struct device *dev, struct device_node *node, struct phy *devm_phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops);
struct phy_init_data *init_data);
The PHY drivers can use one of the above 2 APIs to create the PHY by passing The PHY drivers can use one of the above 2 APIs to create the PHY by passing
the device pointer, phy ops and init_data. the device pointer and phy ops.
phy_ops is a set of function pointers for performing PHY operations such as phy_ops is a set of function pointers for performing PHY operations such as
init, exit, power_on and power_off. *init_data* is mandatory to get a reference init, exit, power_on and power_off.
to the PHY in the case of non-dt boot. See section *Board File Initialization*
on how init_data should be used.
Inorder to dereference the private data (in phy_ops), the phy provider driver 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 can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
@ -137,42 +133,18 @@ 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_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
phy_pm_runtime_forbid for performing PM operations. phy_pm_runtime_forbid for performing PM operations.
8. Board File Initialization 8. PHY Mappings
Certain board file initialization is necessary in order to get a reference In order to get reference to a PHY without help from DeviceTree, the framework
to the PHY in the case of non-dt boot. offers lookups which can be compared to clkdev that allow clk structures to be
Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe, bound to devices. A lookup can be made be made during runtime when a handle to
then in the board file the following initialization should be done. the struct phy already exists.
struct phy_consumer consumers[] = { The framework offers the following API for registering and unregistering the
PHY_CONSUMER("dwc3.0", "usb"), lookups.
PHY_CONSUMER("pcie.0", "pcie"),
PHY_CONSUMER("sata.0", "sata"),
};
PHY_CONSUMER takes 2 parameters, first is the device name of the controller
(PHY consumer) and second is the port name.
struct phy_init_data init_data = { int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
.consumers = consumers, void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
.num_consumers = ARRAY_SIZE(consumers),
};
static const struct platform_device pipe3_phy_dev = {
.name = "pipe3-phy",
.id = -1,
.dev = {
.platform_data = {
.init_data = &init_data,
},
},
};
then, while doing phy_create, the PHY driver should pass this init_data
phy_create(dev, ops, pdata->init_data);
and the controller driver (phy consumer) should pass the port name along with
the device to get a reference to the PHY
phy_get(dev, "pcie");
9. DeviceTree Binding 9. DeviceTree Binding

View File

@ -15,6 +15,13 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this phy users can obtain reference to the PHY. All the users of this
framework should select this config. framework should select this config.
config PHY_BERLIN_USB
tristate "Marvell Berlin USB PHY Driver"
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
select GENERIC_PHY
help
Enable this to support the USB PHY on Marvell Berlin SoCs.
config PHY_BERLIN_SATA config PHY_BERLIN_SATA
tristate "Marvell Berlin SATA PHY driver" tristate "Marvell Berlin SATA PHY driver"
depends on ARCH_BERLIN && HAS_IOMEM && OF depends on ARCH_BERLIN && HAS_IOMEM && OF
@ -22,6 +29,12 @@ config PHY_BERLIN_SATA
help help
Enable this to support the SATA PHY on Marvell Berlin SoCs. Enable this to support the SATA PHY on Marvell Berlin SoCs.
config ARMADA375_USBCLUSTER_PHY
def_bool y
depends on MACH_ARMADA_375 || COMPILE_TEST
depends on OF
select GENERIC_PHY
config PHY_EXYNOS_MIPI_VIDEO config PHY_EXYNOS_MIPI_VIDEO
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
depends on HAS_IOMEM depends on HAS_IOMEM
@ -38,6 +51,14 @@ config PHY_MVEBU_SATA
depends on OF depends on OF
select GENERIC_PHY select GENERIC_PHY
config PHY_MIPHY28LP
tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407"
depends on ARCH_STI
select GENERIC_PHY
help
Enable this to support the miphy transceiver (for SATA/PCIE/USB3)
that is part of STMicroelectronics STiH407 SoC.
config PHY_MIPHY365X config PHY_MIPHY365X
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
depends on ARCH_STI depends on ARCH_STI
@ -193,7 +214,7 @@ config PHY_EXYNOS5250_USB2
config PHY_EXYNOS5_USBDRD config PHY_EXYNOS5_USBDRD
tristate "Exynos5 SoC series USB DRD PHY driver" tristate "Exynos5 SoC series USB DRD PHY driver"
depends on ARCH_EXYNOS5 && OF depends on ARCH_EXYNOS && OF
depends on HAS_IOMEM depends on HAS_IOMEM
depends on USB_DWC3_EXYNOS depends on USB_DWC3_EXYNOS
select GENERIC_PHY select GENERIC_PHY

View File

@ -3,11 +3,14 @@
# #
obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o

View File

@ -0,0 +1,158 @@
/*
* USB cluster support for Armada 375 platform.
*
* Copyright (C) 2014 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*
* Armada 375 comes with an USB2 host and device controller and an
* USB3 controller. The USB cluster control register allows to manage
* common features of both USB controllers.
*/
#include <dt-bindings/phy/phy.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define USB2_PHY_CONFIG_DISABLE BIT(0)
struct armada375_cluster_phy {
struct phy *phy;
void __iomem *reg;
bool use_usb3;
int phy_provided;
};
static int armada375_usb_phy_init(struct phy *phy)
{
struct armada375_cluster_phy *cluster_phy;
u32 reg;
cluster_phy = dev_get_drvdata(phy->dev.parent);
if (!cluster_phy)
return -ENODEV;
reg = readl(cluster_phy->reg);
if (cluster_phy->use_usb3)
reg |= USB2_PHY_CONFIG_DISABLE;
else
reg &= ~USB2_PHY_CONFIG_DISABLE;
writel(reg, cluster_phy->reg);
return 0;
}
static struct phy_ops armada375_usb_phy_ops = {
.init = armada375_usb_phy_init,
.owner = THIS_MODULE,
};
/*
* Only one controller can use this PHY. We shouldn't have the case
* when two controllers want to use this PHY. But if this case occurs
* then we provide a phy to the first one and return an error for the
* next one. This error has also to be an error returned by
* devm_phy_optional_get() so different from ENODEV for USB2. In the
* USB3 case it still optional and we use ENODEV.
*/
static struct phy *armada375_usb_phy_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev);
if (!cluster_phy)
return ERR_PTR(-ENODEV);
/*
* Either the phy had never been requested and then the first
* usb claiming it can get it, or it had already been
* requested in this case, we only allow to use it with the
* same configuration.
*/
if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) &&
(cluster_phy->phy_provided != args->args[0]))) {
dev_err(dev, "This PHY has already been provided!\n");
dev_err(dev, "Check your device tree, only one controller can use it\n.");
if (args->args[0] == PHY_TYPE_USB2)
return ERR_PTR(-EBUSY);
else
return ERR_PTR(-ENODEV);
}
if (args->args[0] == PHY_TYPE_USB2)
cluster_phy->use_usb3 = false;
else if (args->args[0] == PHY_TYPE_USB3)
cluster_phy->use_usb3 = true;
else {
dev_err(dev, "Invalid PHY mode\n");
return ERR_PTR(-ENODEV);
}
/* Store which phy mode is used for next test */
cluster_phy->phy_provided = args->args[0];
return cluster_phy->phy;
}
static int armada375_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *usb_cluster_base;
struct resource *res;
struct armada375_cluster_phy *cluster_phy;
cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL);
if (!cluster_phy)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
if (!usb_cluster_base)
return -ENOMEM;
phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy);
}
cluster_phy->phy = phy;
cluster_phy->reg = usb_cluster_base;
dev_set_drvdata(dev, cluster_phy);
phy_provider = devm_of_phy_provider_register(&pdev->dev,
armada375_usb_phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id of_usb_cluster_table[] = {
{ .compatible = "marvell,armada-375-usb-cluster", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_usb_cluster_table);
static struct platform_driver armada375_usb_phy_driver = {
.probe = armada375_usb_phy_probe,
.driver = {
.of_match_table = of_usb_cluster_table,
.name = "armada-375-usb-cluster",
.owner = THIS_MODULE,
}
};
module_platform_driver(armada375_usb_phy_driver);
MODULE_DESCRIPTION("Armada 375 USB cluster driver");
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
MODULE_LICENSE("GPL");

View File

@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy); platform_set_drvdata(pdev, phy);
gphy = devm_phy_create(dev, NULL, &ops, NULL); gphy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(gphy)) if (IS_ERR(gphy))
return PTR_ERR(gphy); return PTR_ERR(gphy);

View File

@ -30,7 +30,8 @@
#define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16) #define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16)
#define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19) #define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19)
#define PHY_BASE 0x200 #define BG2_PHY_BASE 0x080
#define BG2Q_PHY_BASE 0x200
/* register 0x01 */ /* register 0x01 */
#define REF_FREF_SEL_25 BIT(0) #define REF_FREF_SEL_25 BIT(0)
@ -61,15 +62,16 @@ struct phy_berlin_priv {
struct clk *clk; struct clk *clk;
struct phy_berlin_desc **phys; struct phy_berlin_desc **phys;
unsigned nphys; unsigned nphys;
u32 phy_base;
}; };
static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg, static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg,
u32 mask, u32 val) u32 phy_base, u32 reg, u32 mask, u32 val)
{ {
u32 regval; u32 regval;
/* select register */ /* select register */
writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR); writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR);
/* set bits */ /* set bits */
regval = readl(ctrl_reg + PORT_VSR_DATA); regval = readl(ctrl_reg + PORT_VSR_DATA);
@ -103,17 +105,20 @@ static int phy_berlin_sata_power_on(struct phy *phy)
writel(regval, priv->base + HOST_VSA_DATA); writel(regval, priv->base + HOST_VSA_DATA);
/* set PHY mode and ref freq to 25 MHz */ /* set PHY mode and ref freq to 25 MHz */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff, phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01,
REF_FREF_SEL_25 | PHY_MODE_SATA); 0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA);
/* set PHY up to 6 Gbps */ /* set PHY up to 6 Gbps */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0); phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25,
0x0c00, PHY_GEN_MAX_6_0);
/* set 40 bits width */ /* set 40 bits width */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40); phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x23,
0x0c00, DATA_BIT_WIDTH_40);
/* use max pll rate */ /* use max pll rate */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE); phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x02,
0x0000, USE_MAX_PLL_RATE);
/* set Gen3 controller speed */ /* set Gen3 controller speed */
regval = readl(ctrl_reg + PORT_SCR_CTL); regval = readl(ctrl_reg + PORT_SCR_CTL);
@ -218,6 +223,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!priv->phys) if (!priv->phys)
return -ENOMEM; return -ENOMEM;
if (of_device_is_compatible(dev->of_node, "marvell,berlin2-sata-phy"))
priv->phy_base = BG2_PHY_BASE;
else
priv->phy_base = BG2Q_PHY_BASE;
dev_set_drvdata(dev, priv); dev_set_drvdata(dev, priv);
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
@ -239,7 +249,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!phy_desc) if (!phy_desc)
return -ENOMEM; return -ENOMEM;
phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL); phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", phy_id); dev_err(dev, "failed to create PHY %d\n", phy_id);
return PTR_ERR(phy); return PTR_ERR(phy);
@ -258,13 +268,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
phy_provider = phy_provider =
devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate); devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
if (IS_ERR(phy_provider)) return PTR_ERR_OR_ZERO(phy_provider);
return PTR_ERR(phy_provider);
return 0;
} }
static const struct of_device_id phy_berlin_sata_of_match[] = { static const struct of_device_id phy_berlin_sata_of_match[] = {
{ .compatible = "marvell,berlin2-sata-phy" },
{ .compatible = "marvell,berlin2q-sata-phy" }, { .compatible = "marvell,berlin2q-sata-phy" },
{ }, { },
}; };

View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Tenart <antoine.tenart@free-electrons.com>
* Jisheng Zhang <jszhang@marvell.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#define USB_PHY_PLL 0x04
#define USB_PHY_PLL_CONTROL 0x08
#define USB_PHY_TX_CTRL0 0x10
#define USB_PHY_TX_CTRL1 0x14
#define USB_PHY_TX_CTRL2 0x18
#define USB_PHY_RX_CTRL 0x20
#define USB_PHY_ANALOG 0x34
/* USB_PHY_PLL */
#define CLK_REF_DIV(x) ((x) << 4)
#define FEEDBACK_CLK_DIV(x) ((x) << 8)
/* USB_PHY_PLL_CONTROL */
#define CLK_STABLE BIT(0)
#define PLL_CTRL_PIN BIT(1)
#define PLL_CTRL_REG BIT(2)
#define PLL_ON BIT(3)
#define PHASE_OFF_TOL_125 (0x0 << 5)
#define PHASE_OFF_TOL_250 BIT(5)
#define KVC0_CALIB (0x0 << 9)
#define KVC0_REG_CTRL BIT(9)
#define KVC0_HIGH (0x0 << 10)
#define KVC0_LOW (0x3 << 10)
#define CLK_BLK_EN BIT(13)
/* USB_PHY_TX_CTRL0 */
#define EXT_HS_RCAL_EN BIT(3)
#define EXT_FS_RCAL_EN BIT(4)
#define IMPCAL_VTH_DIV(x) ((x) << 5)
#define EXT_RS_RCAL_DIV(x) ((x) << 8)
#define EXT_FS_RCAL_DIV(x) ((x) << 12)
/* USB_PHY_TX_CTRL1 */
#define TX_VDD15_14 (0x0 << 4)
#define TX_VDD15_15 BIT(4)
#define TX_VDD15_16 (0x2 << 4)
#define TX_VDD15_17 (0x3 << 4)
#define TX_VDD12_VDD (0x0 << 6)
#define TX_VDD12_11 BIT(6)
#define TX_VDD12_12 (0x2 << 6)
#define TX_VDD12_13 (0x3 << 6)
#define LOW_VDD_EN BIT(8)
#define TX_OUT_AMP(x) ((x) << 9)
/* USB_PHY_TX_CTRL2 */
#define TX_CHAN_CTRL_REG(x) ((x) << 0)
#define DRV_SLEWRATE(x) ((x) << 4)
#define IMP_CAL_FS_HS_DLY_0 (0x0 << 6)
#define IMP_CAL_FS_HS_DLY_1 BIT(6)
#define IMP_CAL_FS_HS_DLY_2 (0x2 << 6)
#define IMP_CAL_FS_HS_DLY_3 (0x3 << 6)
#define FS_DRV_EN_MASK(x) ((x) << 8)
#define HS_DRV_EN_MASK(x) ((x) << 12)
/* USB_PHY_RX_CTRL */
#define PHASE_FREEZE_DLY_2_CL (0x0 << 0)
#define PHASE_FREEZE_DLY_4_CL BIT(0)
#define ACK_LENGTH_8_CL (0x0 << 2)
#define ACK_LENGTH_12_CL BIT(2)
#define ACK_LENGTH_16_CL (0x2 << 2)
#define ACK_LENGTH_20_CL (0x3 << 2)
#define SQ_LENGTH_3 (0x0 << 4)
#define SQ_LENGTH_6 BIT(4)
#define SQ_LENGTH_9 (0x2 << 4)
#define SQ_LENGTH_12 (0x3 << 4)
#define DISCON_THRESHOLD_260 (0x0 << 6)
#define DISCON_THRESHOLD_270 BIT(6)
#define DISCON_THRESHOLD_280 (0x2 << 6)
#define DISCON_THRESHOLD_290 (0x3 << 6)
#define SQ_THRESHOLD(x) ((x) << 8)
#define LPF_COEF(x) ((x) << 12)
#define INTPL_CUR_10 (0x0 << 14)
#define INTPL_CUR_20 BIT(14)
#define INTPL_CUR_30 (0x2 << 14)
#define INTPL_CUR_40 (0x3 << 14)
/* USB_PHY_ANALOG */
#define ANA_PWR_UP BIT(1)
#define ANA_PWR_DOWN BIT(2)
#define V2I_VCO_RATIO(x) ((x) << 7)
#define R_ROTATE_90 (0x0 << 10)
#define R_ROTATE_0 BIT(10)
#define MODE_TEST_EN BIT(11)
#define ANA_TEST_DC_CTRL(x) ((x) << 12)
#define to_phy_berlin_usb_priv(p) \
container_of((p), struct phy_berlin_usb_priv, phy)
static const u32 phy_berlin_pll_dividers[] = {
/* Berlin 2 */
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
/* Berlin 2CD */
CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
};
struct phy_berlin_usb_priv {
void __iomem *base;
struct phy *phy;
struct reset_control *rst_ctrl;
u32 pll_divider;
};
static int phy_berlin_usb_power_on(struct phy *phy)
{
struct phy_berlin_usb_priv *priv = dev_get_drvdata(phy->dev.parent);
reset_control_reset(priv->rst_ctrl);
writel(priv->pll_divider,
priv->base + USB_PHY_PLL);
writel(CLK_STABLE | PLL_CTRL_REG | PHASE_OFF_TOL_250 | KVC0_REG_CTRL |
CLK_BLK_EN, priv->base + USB_PHY_PLL_CONTROL);
writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5),
priv->base + USB_PHY_ANALOG);
writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 |
DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL);
writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
priv->base + USB_PHY_TX_CTRL0);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4) |
EXT_FS_RCAL_DIV(0x2), priv->base + USB_PHY_TX_CTRL0);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
priv->base + USB_PHY_TX_CTRL0);
writel(TX_CHAN_CTRL_REG(0xf) | DRV_SLEWRATE(0x3) | IMP_CAL_FS_HS_DLY_3 |
FS_DRV_EN_MASK(0xd), priv->base + USB_PHY_TX_CTRL2);
return 0;
}
static struct phy_ops phy_berlin_usb_ops = {
.power_on = phy_berlin_usb_power_on,
.owner = THIS_MODULE,
};
static const struct of_device_id phy_berlin_sata_of_match[] = {
{
.compatible = "marvell,berlin2-usb-phy",
.data = &phy_berlin_pll_dividers[0],
},
{
.compatible = "marvell,berlin2cd-usb-phy",
.data = &phy_berlin_pll_dividers[1],
},
{ },
};
MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
static int phy_berlin_usb_probe(struct platform_device *pdev)
{
const struct of_device_id *match =
of_match_device(phy_berlin_sata_of_match, &pdev->dev);
struct phy_berlin_usb_priv *priv;
struct resource *res;
struct phy_provider *phy_provider;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
priv->rst_ctrl = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(priv->rst_ctrl))
return PTR_ERR(priv->rst_ctrl);
priv->pll_divider = *((u32 *)match->data);
priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops);
if (IS_ERR(priv->phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(priv->phy);
}
platform_set_drvdata(pdev, priv);
phy_provider =
devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
return 0;
}
static struct platform_driver phy_berlin_usb_driver = {
.probe = phy_berlin_usb_probe,
.driver = {
.name = "phy-berlin-usb",
.owner = THIS_MODULE,
.of_match_table = phy_berlin_sata_of_match,
},
};
module_platform_driver(phy_berlin_usb_driver);
MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
MODULE_DESCRIPTION("Marvell Berlin PHY driver for USB");
MODULE_LICENSE("GPL");

View File

@ -26,6 +26,7 @@
static struct class *phy_class; static struct class *phy_class;
static DEFINE_MUTEX(phy_provider_mutex); static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list); static LIST_HEAD(phy_provider_list);
static LIST_HEAD(phys);
static DEFINE_IDA(phy_ida); static DEFINE_IDA(phy_ida);
static void devm_phy_release(struct device *dev, void *res) static void devm_phy_release(struct device *dev, void *res)
@ -54,34 +55,79 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data)
return res == match_data; return res == match_data;
} }
static struct phy *phy_lookup(struct device *device, const char *port) /**
* phy_create_lookup() - allocate and register PHY/device association
* @phy: the phy of the association
* @con_id: connection ID string on device
* @dev_id: the device of the association
*
* Creates and registers phy_lookup entry.
*/
int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{ {
unsigned int count; struct phy_lookup *pl;
struct phy *phy;
struct device *dev;
struct phy_consumer *consumers;
struct class_dev_iter iter;
class_dev_iter_init(&iter, phy_class, NULL, NULL); if (!phy || !dev_id || !con_id)
while ((dev = class_dev_iter_next(&iter))) { return -EINVAL;
phy = to_phy(dev);
if (!phy->init_data) pl = kzalloc(sizeof(*pl), GFP_KERNEL);
continue; if (!pl)
count = phy->init_data->num_consumers; return -ENOMEM;
consumers = phy->init_data->consumers;
while (count--) { pl->dev_id = dev_id;
if (!strcmp(consumers->dev_name, dev_name(device)) && pl->con_id = con_id;
!strcmp(consumers->port, port)) { pl->phy = phy;
class_dev_iter_exit(&iter);
return phy; mutex_lock(&phy_provider_mutex);
} list_add_tail(&pl->node, &phys);
consumers++; mutex_unlock(&phy_provider_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(phy_create_lookup);
/**
* phy_remove_lookup() - find and remove PHY/device association
* @phy: the phy of the association
* @con_id: connection ID string on device
* @dev_id: the device of the association
*
* Finds and unregisters phy_lookup entry that was created with
* phy_create_lookup().
*/
void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{
struct phy_lookup *pl;
if (!phy || !dev_id || !con_id)
return;
mutex_lock(&phy_provider_mutex);
list_for_each_entry(pl, &phys, node)
if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) &&
!strcmp(pl->con_id, con_id)) {
list_del(&pl->node);
kfree(pl);
break;
} }
} mutex_unlock(&phy_provider_mutex);
}
EXPORT_SYMBOL_GPL(phy_remove_lookup);
class_dev_iter_exit(&iter); static struct phy *phy_find(struct device *dev, const char *con_id)
return ERR_PTR(-ENODEV); {
const char *dev_id = dev_name(dev);
struct phy_lookup *p, *pl = NULL;
mutex_lock(&phy_provider_mutex);
list_for_each_entry(p, &phys, node)
if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) {
pl = p;
break;
}
mutex_unlock(&phy_provider_mutex);
return pl ? pl->phy : ERR_PTR(-ENODEV);
} }
static struct phy_provider *of_phy_provider_lookup(struct device_node *node) static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
@ -414,21 +460,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args
{ {
struct phy *phy; struct phy *phy;
struct class_dev_iter iter; struct class_dev_iter iter;
struct device_node *node = dev->of_node;
struct device_node *child;
class_dev_iter_init(&iter, phy_class, NULL, NULL); class_dev_iter_init(&iter, phy_class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) { while ((dev = class_dev_iter_next(&iter))) {
phy = to_phy(dev); phy = to_phy(dev);
if (node != phy->dev.of_node) { if (args->np != phy->dev.of_node)
for_each_child_of_node(node, child) {
if (child == phy->dev.of_node)
goto phy_found;
}
continue; continue;
}
phy_found:
class_dev_iter_exit(&iter); class_dev_iter_exit(&iter);
return phy; return phy;
} }
@ -463,7 +501,7 @@ struct phy *phy_get(struct device *dev, const char *string)
string); string);
phy = _of_phy_get(dev->of_node, index); phy = _of_phy_get(dev->of_node, index);
} else { } else {
phy = phy_lookup(dev, string); phy = phy_find(dev, string);
} }
if (IS_ERR(phy)) if (IS_ERR(phy))
return phy; return phy;
@ -588,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
* @dev: device that is creating the new phy * @dev: device that is creating the new phy
* @node: device node of the phy * @node: device node of the phy
* @ops: function pointers for performing phy operations * @ops: function pointers for performing phy operations
* @init_data: contains the list of PHY consumers or NULL
* *
* Called to create a phy using phy framework. * Called to create a phy using phy framework.
*/ */
struct phy *phy_create(struct device *dev, struct device_node *node, struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops)
struct phy_init_data *init_data)
{ {
int ret; int ret;
int id; int id;
@ -632,7 +668,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
phy->dev.of_node = node ?: dev->of_node; phy->dev.of_node = node ?: dev->of_node;
phy->id = id; phy->id = id;
phy->ops = ops; phy->ops = ops;
phy->init_data = init_data;
ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id); ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id);
if (ret) if (ret)
@ -667,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create);
* @dev: device that is creating the new phy * @dev: device that is creating the new phy
* @node: device node of the phy * @node: device node of the phy
* @ops: function pointers for performing phy operations * @ops: function pointers for performing phy operations
* @init_data: contains the list of PHY consumers or NULL
* *
* Creates a new PHY device adding it to the PHY class. * Creates a new PHY device adding it to the PHY class.
* While at that, it also associates the device with the phy using devres. * While at that, it also associates the device with the phy using devres.
@ -675,8 +709,7 @@ EXPORT_SYMBOL_GPL(phy_create);
* then, devres data is freed. * then, devres data is freed.
*/ */
struct phy *devm_phy_create(struct device *dev, struct device_node *node, struct phy *devm_phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops)
struct phy_init_data *init_data)
{ {
struct phy **ptr, *phy; struct phy **ptr, *phy;
@ -684,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node,
if (!ptr) if (!ptr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
phy = phy_create(dev, node, ops, init_data); phy = phy_create(dev, node, ops);
if (!IS_ERR(phy)) { if (!IS_ERR(phy)) {
*ptr = phy; *ptr = phy;
devres_add(dev, ptr); devres_add(dev, ptr);

View File

@ -112,7 +112,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node); match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node);
state->drvdata = match->data; state->drvdata = match->data;
phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL); phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n"); dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy); return PTR_ERR(phy);

View File

@ -137,7 +137,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL, struct phy *phy = devm_phy_create(dev, NULL,
&exynos_mipi_video_phy_ops, NULL); &exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", i); dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy); return PTR_ERR(phy);

View File

@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata {
const struct exynos5_usbdrd_phy_config *phy_cfg; const struct exynos5_usbdrd_phy_config *phy_cfg;
u32 pmu_offset_usbdrd0_phy; u32 pmu_offset_usbdrd0_phy;
u32 pmu_offset_usbdrd1_phy; u32 pmu_offset_usbdrd1_phy;
bool has_common_clk_gate;
}; };
/** /**
@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata {
* @dev: pointer to device instance of this platform device * @dev: pointer to device instance of this platform device
* @reg_phy: usb phy controller register memory base * @reg_phy: usb phy controller register memory base
* @clk: phy clock for register access * @clk: phy clock for register access
* @pipeclk: clock for pipe3 phy
* @utmiclk: clock for utmi+ phy
* @itpclk: clock for ITP generation
* @drv_data: pointer to SoC level driver data structure * @drv_data: pointer to SoC level driver data structure
* @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'. * instances each with its 'phy' and 'phy_cfg'.
@ -155,12 +159,16 @@ struct exynos5_usbdrd_phy_drvdata {
* reference clocks' for SS and HS operations * reference clocks' for SS and HS operations
* @ref_clk: reference clock to PHY block from which PHY's * @ref_clk: reference clock to PHY block from which PHY's
* operational clocks are derived * operational clocks are derived
* @ref_rate: rate of above reference clock * vbus: VBUS regulator for phy
* vbus_boost: Boost regulator for VBUS present on few Exynos boards
*/ */
struct exynos5_usbdrd_phy { struct exynos5_usbdrd_phy {
struct device *dev; struct device *dev;
void __iomem *reg_phy; void __iomem *reg_phy;
struct clk *clk; struct clk *clk;
struct clk *pipeclk;
struct clk *utmiclk;
struct clk *itpclk;
const struct exynos5_usbdrd_phy_drvdata *drv_data; const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct phy_usb_instance { struct phy_usb_instance {
struct phy *phy; struct phy *phy;
@ -172,6 +180,7 @@ struct exynos5_usbdrd_phy {
u32 extrefclk; u32 extrefclk;
struct clk *ref_clk; struct clk *ref_clk;
struct regulator *vbus; struct regulator *vbus;
struct regulator *vbus_boost;
}; };
static inline static inline
@ -447,13 +456,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
clk_prepare_enable(phy_drd->ref_clk); clk_prepare_enable(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_prepare_enable(phy_drd->pipeclk);
clk_prepare_enable(phy_drd->utmiclk);
clk_prepare_enable(phy_drd->itpclk);
}
/* Enable VBUS supply */ /* Enable VBUS supply */
if (phy_drd->vbus_boost) {
ret = regulator_enable(phy_drd->vbus_boost);
if (ret) {
dev_err(phy_drd->dev,
"Failed to enable VBUS boost supply\n");
goto fail_vbus;
}
}
if (phy_drd->vbus) { if (phy_drd->vbus) {
ret = regulator_enable(phy_drd->vbus); ret = regulator_enable(phy_drd->vbus);
if (ret) { if (ret) {
dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
goto fail_vbus; goto fail_vbus_boost;
} }
} }
@ -462,8 +485,17 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
return 0; return 0;
fail_vbus_boost:
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
fail_vbus: fail_vbus:
clk_disable_unprepare(phy_drd->ref_clk); clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->utmiclk);
clk_disable_unprepare(phy_drd->pipeclk);
}
return ret; return ret;
} }
@ -481,8 +513,15 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
/* Disable VBUS supply */ /* Disable VBUS supply */
if (phy_drd->vbus) if (phy_drd->vbus)
regulator_disable(phy_drd->vbus); regulator_disable(phy_drd->vbus);
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
clk_disable_unprepare(phy_drd->ref_clk); clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->pipeclk);
clk_disable_unprepare(phy_drd->utmiclk);
}
return 0; return 0;
} }
@ -506,6 +545,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
{
unsigned long ref_rate;
int ret;
phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
if (IS_ERR(phy_drd->clk)) {
dev_err(phy_drd->dev, "Failed to get phy clock\n");
return PTR_ERR(phy_drd->clk);
}
phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {
dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
return PTR_ERR(phy_drd->ref_clk);
}
ref_rate = clk_get_rate(phy_drd->ref_clk);
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (ret) {
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
ref_rate);
return ret;
}
if (!phy_drd->drv_data->has_common_clk_gate) {
phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
if (IS_ERR(phy_drd->pipeclk)) {
dev_info(phy_drd->dev,
"PIPE3 phy operational clock not specified\n");
phy_drd->pipeclk = NULL;
}
phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
if (IS_ERR(phy_drd->utmiclk)) {
dev_info(phy_drd->dev,
"UTMI phy operational clock not specified\n");
phy_drd->utmiclk = NULL;
}
phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
if (IS_ERR(phy_drd->itpclk)) {
dev_info(phy_drd->dev,
"ITP clock from main OSC not specified\n");
phy_drd->itpclk = NULL;
}
}
return 0;
}
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
{ {
.id = EXYNOS5_DRDPHY_UTMI, .id = EXYNOS5_DRDPHY_UTMI,
@ -525,11 +615,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5, .phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
.has_common_clk_gate = true,
}; };
static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5, .phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = true,
};
static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = false,
}; };
static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
@ -539,6 +637,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, { }, {
.compatible = "samsung,exynos5420-usbdrd-phy", .compatible = "samsung,exynos5420-usbdrd-phy",
.data = &exynos5420_usbdrd_phy .data = &exynos5420_usbdrd_phy
}, {
.compatible = "samsung,exynos7-usbdrd-phy",
.data = &exynos7_usbdrd_phy
}, },
{ }, { },
}; };
@ -555,7 +656,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
const struct exynos5_usbdrd_phy_drvdata *drv_data; const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct regmap *reg_pmu; struct regmap *reg_pmu;
u32 pmu_offset; u32 pmu_offset;
unsigned long ref_rate;
int i, ret; int i, ret;
int channel; int channel;
@ -576,23 +676,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
drv_data = match->data; drv_data = match->data;
phy_drd->drv_data = drv_data; phy_drd->drv_data = drv_data;
phy_drd->clk = devm_clk_get(dev, "phy"); ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
if (IS_ERR(phy_drd->clk)) {
dev_err(dev, "Failed to get clock of phy controller\n");
return PTR_ERR(phy_drd->clk);
}
phy_drd->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {
dev_err(dev, "Failed to get reference clock of usbdrd phy\n");
return PTR_ERR(phy_drd->ref_clk);
}
ref_rate = clk_get_rate(phy_drd->ref_clk);
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (ret) { if (ret) {
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", dev_err(dev, "Failed to initialize clocks\n");
ref_rate);
return ret; return ret;
} }
@ -622,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
break; break;
} }
/* Get Vbus regulator */ /* Get Vbus regulators */
phy_drd->vbus = devm_regulator_get(dev, "vbus"); phy_drd->vbus = devm_regulator_get(dev, "vbus");
if (IS_ERR(phy_drd->vbus)) { if (IS_ERR(phy_drd->vbus)) {
ret = PTR_ERR(phy_drd->vbus); ret = PTR_ERR(phy_drd->vbus);
@ -633,12 +719,21 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
phy_drd->vbus = NULL; phy_drd->vbus = NULL;
} }
phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
if (IS_ERR(phy_drd->vbus_boost)) {
ret = PTR_ERR(phy_drd->vbus_boost);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
phy_drd->vbus_boost = NULL;
}
dev_vdbg(dev, "Creating usbdrd_phy phy\n"); dev_vdbg(dev, "Creating usbdrd_phy phy\n");
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL, struct phy *phy = devm_phy_create(dev, NULL,
&exynos5_usbdrd_phy_ops, &exynos5_usbdrd_phy_ops);
NULL);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "Failed to create usbdrd_phy phy\n"); dev_err(dev, "Failed to create usbdrd_phy phy\n");
return PTR_ERR(phy); return PTR_ERR(phy);

View File

@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev)
return ret; return ret;
} }
sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL); sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
if (IS_ERR(sata_phy->phy)) { if (IS_ERR(sata_phy->phy)) {
clk_disable_unprepare(sata_phy->phyclk); clk_disable_unprepare(sata_phy->phyclk);
dev_err(dev, "failed to create PHY\n"); dev_err(dev, "failed to create PHY\n");

View File

@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(priv->peri_ctrl)) if (IS_ERR(priv->peri_ctrl))
priv->peri_ctrl = NULL; priv->peri_ctrl = NULL;
phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL); phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n"); dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy); return PTR_ERR(phy);
@ -164,10 +164,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, priv); phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) return PTR_ERR_OR_ZERO(phy_provider);
return PTR_ERR(phy_provider);
return 0;
} }
static const struct of_device_id hix5hd2_sata_phy_of_match[] = { static const struct of_device_id hix5hd2_sata_phy_of_match[] = {

1283
drivers/phy/phy-miphy28lp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -593,7 +593,7 @@ static int miphy365x_probe(struct platform_device *pdev)
miphy_dev->phys[port] = miphy_phy; miphy_dev->phys[port] = miphy_phy;
phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL); phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n"); dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(phy); return PTR_ERR(phy);
@ -610,10 +610,7 @@ static int miphy365x_probe(struct platform_device *pdev)
} }
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
if (IS_ERR(provider)) return PTR_ERR_OR_ZERO(provider);
return PTR_ERR(provider);
return 0;
} }
static const struct of_device_id miphy365x_of_match[] = { static const struct of_device_id miphy365x_of_match[] = {

View File

@ -101,7 +101,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk)) if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk); return PTR_ERR(priv->clk);
phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL); phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);
if (IS_ERR(phy)) if (IS_ERR(phy))
return PTR_ERR(phy); return PTR_ERR(phy);

View File

@ -256,7 +256,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy); platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev); pm_runtime_enable(phy->dev);
generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy)) { if (IS_ERR(generic_phy)) {
pm_runtime_disable(phy->dev); pm_runtime_disable(phy->dev);
return PTR_ERR(generic_phy); return PTR_ERR(generic_phy);

View File

@ -228,8 +228,7 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio)) if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio); return PTR_ERR(phy->mmio);
generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops, generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops);
NULL);
if (IS_ERR(generic_phy)) { if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__); dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy); return PTR_ERR(generic_phy);

View File

@ -150,8 +150,7 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio)) if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio); return PTR_ERR(phy->mmio);
generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops, generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);
NULL);
if (IS_ERR(generic_phy)) { if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__); dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy); return PTR_ERR(generic_phy);

View File

@ -304,7 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
phy->select_value = select_value[channel_num][n]; phy->select_value = select_value[channel_num][n];
phy->phy = devm_phy_create(dev, NULL, phy->phy = devm_phy_create(dev, NULL,
&rcar_gen2_phy_ops, NULL); &rcar_gen2_phy_ops);
if (IS_ERR(phy->phy)) { if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n"); dev_err(dev, "Failed to create PHY\n");
return PTR_ERR(phy->phy); return PTR_ERR(phy->phy);

View File

@ -202,8 +202,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
struct samsung_usb2_phy_instance *p = &drv->instances[i]; struct samsung_usb2_phy_instance *p = &drv->instances[i];
dev_dbg(dev, "Creating phy \"%s\"\n", label); dev_dbg(dev, "Creating phy \"%s\"\n", label);
p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops, p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);
NULL);
if (IS_ERR(p->phy)) { if (IS_ERR(p->phy)) {
dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n", dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
label); label);

View File

@ -227,7 +227,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL); priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops);
if (IS_ERR(priv->phy)) { if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n"); dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy); return PTR_ERR(priv->phy);

View File

@ -259,7 +259,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev)
return PTR_ERR(priv->misc); return PTR_ERR(priv->misc);
} }
priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL); priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops);
if (IS_ERR(priv->phy)) { if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n"); dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy); return PTR_ERR(priv->phy);

View File

@ -137,7 +137,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
} }
phy_dev->param = res->start; phy_dev->param = res->start;
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data, NULL); phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n"); dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy); return PTR_ERR(phy);

View File

@ -148,7 +148,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy_dev->clk); return PTR_ERR(phy_dev->clk);
} }
phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops, NULL); phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n"); dev_err(dev, "failed to create phy\n");
@ -160,10 +160,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, phy_dev); phy_set_drvdata(phy, phy_dev);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) return PTR_ERR_OR_ZERO(phy_provider);
return PTR_ERR(phy_provider);
return 0;
} }
static const struct of_device_id stih41x_usb_phy_of_match[] = { static const struct of_device_id stih41x_usb_phy_of_match[] = {

View File

@ -157,6 +157,10 @@ static int sun4i_usb_phy_init(struct phy *_phy)
return ret; return ret;
} }
/* Enable USB 45 Ohm resistor calibration */
if (phy->index == 0)
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
/* Adjust PHY's magnitude and rate */ /* Adjust PHY's magnitude and rate */
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
@ -213,7 +217,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
{ {
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys)) if (args->args[0] >= data->num_phys)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
return data->phys[args->args[0]].phy; return data->phys[args->args[0]].phy;
@ -255,8 +259,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
if (IS_ERR(data->base)) if (IS_ERR(data->base))
return PTR_ERR(data->base); return PTR_ERR(data->base);
/* Skip 0, 0 is the phy for otg which is not yet supported. */ for (i = 0; i < data->num_phys; i++) {
for (i = 1; i < data->num_phys; i++) {
struct sun4i_usb_phy *phy = data->phys + i; struct sun4i_usb_phy *phy = data->phys + i;
char name[16]; char name[16];
@ -295,7 +298,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->pmu); return PTR_ERR(phy->pmu);
} }
phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL); phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops);
if (IS_ERR(phy->phy)) { if (IS_ERR(phy->phy)) {
dev_err(dev, "failed to create PHY %d\n", i); dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy->phy); return PTR_ERR(phy->phy);

View File

@ -399,7 +399,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy); platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev); pm_runtime_enable(phy->dev);
generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL); generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy)) if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy); return PTR_ERR(generic_phy);

View File

@ -644,7 +644,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct usb_otg *otg; struct usb_otg *otg;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct phy_init_data *init_data = NULL;
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL); twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl) if (!twl)
@ -655,7 +654,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
(enum twl4030_usb_mode *)&twl->usb_mode); (enum twl4030_usb_mode *)&twl->usb_mode);
else if (pdata) { else if (pdata) {
twl->usb_mode = pdata->usb_mode; twl->usb_mode = pdata->usb_mode;
init_data = pdata->init_data;
} else { } else {
dev_err(&pdev->dev, "twl4030 initialized without pdata\n"); dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
return -EINVAL; return -EINVAL;
@ -680,7 +678,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
otg->set_host = twl4030_set_host; otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral; otg->set_peripheral = twl4030_set_peripheral;
phy = devm_phy_create(twl->dev, NULL, &ops, init_data); phy = devm_phy_create(twl->dev, NULL, &ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n"); dev_dbg(&pdev->dev, "Failed to create PHY\n");
return PTR_ERR(phy); return PTR_ERR(phy);
@ -733,6 +731,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return status; return status;
} }
if (pdata)
err = phy_create_lookup(phy, "usb", "musb-hdrc.0");
if (err)
return err;
pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(twl->dev); pm_runtime_put_autosuspend(twl->dev);

View File

@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev)
ctx->dev = &pdev->dev; ctx->dev = &pdev->dev;
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL); ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
if (IS_ERR(ctx->phy)) { if (IS_ERR(ctx->phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n"); dev_dbg(&pdev->dev, "Failed to create PHY\n");
rc = PTR_ERR(ctx->phy); rc = PTR_ERR(ctx->phy);

View File

@ -910,7 +910,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
goto reset; goto reset;
} }
phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL); phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
err = PTR_ERR(phy); err = PTR_ERR(phy);
goto unregister; goto unregister;
@ -919,7 +919,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy; padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
phy_set_drvdata(phy, padctl); phy_set_drvdata(phy, padctl);
phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL); phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
err = PTR_ERR(phy); err = PTR_ERR(phy);
goto unregister; goto unregister;

View File

@ -29,8 +29,7 @@ int dwc3_host_init(struct dwc3 *dwc)
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) { if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n"); dev_err(dwc->dev, "couldn't allocate xHCI device\n");
ret = -ENOMEM; return -ENOMEM;
goto err0;
} }
dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
@ -60,22 +59,33 @@ int dwc3_host_init(struct dwc3 *dwc)
goto err1; goto err1;
} }
phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
dev_name(&xhci->dev));
phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
dev_name(&xhci->dev));
ret = platform_device_add(xhci); ret = platform_device_add(xhci);
if (ret) { if (ret) {
dev_err(dwc->dev, "failed to register xHCI device\n"); dev_err(dwc->dev, "failed to register xHCI device\n");
goto err1; goto err2;
} }
return 0; return 0;
err2:
phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
dev_name(&xhci->dev));
phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
dev_name(&xhci->dev));
err1: err1:
platform_device_put(xhci); platform_device_put(xhci);
err0:
return ret; return ret;
} }
void dwc3_host_exit(struct dwc3 *dwc) void dwc3_host_exit(struct dwc3 *dwc)
{ {
phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
dev_name(&dwc->xhci->dev));
phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
dev_name(&dwc->xhci->dev));
platform_device_unregister(dwc->xhci); platform_device_unregister(dwc->xhci);
} }

View File

@ -0,0 +1,19 @@
/*
*
* This header provides constants for the phy framework
*
* Copyright (C) 2014 STMicroelectronics
* Author: Gabriel Fernandez <gabriel.fernandez@st.com>
* License terms: GNU General Public License (GPL), version 2
*/
#ifndef _DT_BINDINGS_PHY
#define _DT_BINDINGS_PHY
#define PHY_NONE 0
#define PHY_TYPE_SATA 1
#define PHY_TYPE_PCIE 2
#define PHY_TYPE_USB2 3
#define PHY_TYPE_USB3 4
#endif /* _DT_BINDINGS_PHY */

View File

@ -61,7 +61,6 @@ struct phy {
struct device dev; struct device dev;
int id; int id;
const struct phy_ops *ops; const struct phy_ops *ops;
struct phy_init_data *init_data;
struct mutex mutex; struct mutex mutex;
int init_count; int init_count;
int power_count; int power_count;
@ -84,33 +83,14 @@ struct phy_provider {
struct of_phandle_args *args); struct of_phandle_args *args);
}; };
/** struct phy_lookup {
* struct phy_consumer - represents the phy consumer struct list_head node;
* @dev_name: the device name of the controller that will use this PHY device const char *dev_id;
* @port: name given to the consumer port const char *con_id;
*/ struct phy *phy;
struct phy_consumer {
const char *dev_name;
const char *port;
}; };
/** #define to_phy(a) (container_of((a), struct phy, dev))
* struct phy_init_data - contains the list of PHY consumers
* @num_consumers: number of consumers for this PHY device
* @consumers: list of PHY consumers
*/
struct phy_init_data {
unsigned int num_consumers;
struct phy_consumer *consumers;
};
#define PHY_CONSUMER(_dev_name, _port) \
{ \
.dev_name = _dev_name, \
.port = _port, \
}
#define to_phy(dev) (container_of((dev), struct phy, dev))
#define of_phy_provider_register(dev, xlate) \ #define of_phy_provider_register(dev, xlate) \
__of_phy_provider_register((dev), THIS_MODULE, (xlate)) __of_phy_provider_register((dev), THIS_MODULE, (xlate))
@ -159,10 +139,9 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device *dev, struct phy *of_phy_simple_xlate(struct device *dev,
struct of_phandle_args *args); struct of_phandle_args *args);
struct phy *phy_create(struct device *dev, struct device_node *node, struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops);
struct phy_init_data *init_data);
struct phy *devm_phy_create(struct device *dev, struct device_node *node, struct phy *devm_phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops, struct phy_init_data *init_data); const struct phy_ops *ops);
void phy_destroy(struct phy *phy); void phy_destroy(struct phy *phy);
void devm_phy_destroy(struct device *dev, struct phy *phy); void devm_phy_destroy(struct device *dev, struct phy *phy);
struct phy_provider *__of_phy_provider_register(struct device *dev, struct phy_provider *__of_phy_provider_register(struct device *dev,
@ -174,6 +153,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
void of_phy_provider_unregister(struct phy_provider *phy_provider); void of_phy_provider_unregister(struct phy_provider *phy_provider);
void devm_of_phy_provider_unregister(struct device *dev, void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider); struct phy_provider *phy_provider);
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);
#else #else
static inline int phy_pm_runtime_get(struct phy *phy) static inline int phy_pm_runtime_get(struct phy *phy)
{ {
@ -301,16 +282,14 @@ static inline struct phy *of_phy_simple_xlate(struct device *dev,
static inline struct phy *phy_create(struct device *dev, static inline struct phy *phy_create(struct device *dev,
struct device_node *node, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops)
struct phy_init_data *init_data)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
static inline struct phy *devm_phy_create(struct device *dev, static inline struct phy *devm_phy_create(struct device *dev,
struct device_node *node, struct device_node *node,
const struct phy_ops *ops, const struct phy_ops *ops)
struct phy_init_data *init_data)
{ {
return ERR_PTR(-ENOSYS); return ERR_PTR(-ENOSYS);
} }
@ -345,6 +324,13 @@ static inline void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider) struct phy_provider *phy_provider)
{ {
} }
static inline int
phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{
return 0;
}
static inline void phy_remove_lookup(struct phy *phy, const char *con_id,
const char *dev_id) { }
#endif #endif
#endif /* __DRIVERS_PHY_H */ #endif /* __DRIVERS_PHY_H */