mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
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:
commit
842f57baab
@ -6,11 +6,17 @@ Required Properties:
|
||||
- interrupts : Interrupt controller is using
|
||||
- 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:
|
||||
|
||||
sata@80000 {
|
||||
compatible = "marvell,orion-sata";
|
||||
reg = <0x80000 0x5000>;
|
||||
interrupts = <21>;
|
||||
phys = <&sata_phy0>, <&sata_phy1>;
|
||||
phy-names = "0", "1";
|
||||
nr-ports = <2>;
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ Berlin SATA PHY
|
||||
---------------
|
||||
|
||||
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
|
||||
- size-cells: should be 0
|
||||
- phy-cells: from the generic PHY bindings, must be 1
|
||||
|
16
Documentation/devicetree/bindings/phy/berlin-usb-phy.txt
Normal file
16
Documentation/devicetree/bindings/phy/berlin-usb-phy.txt
Normal 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>;
|
||||
};
|
128
Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
Normal file
128
Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
Normal 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
|
43
Documentation/devicetree/bindings/phy/phy-mvebu.txt
Normal file
43
Documentation/devicetree/bindings/phy/phy-mvebu.txt
Normal 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>
|
||||
};
|
@ -128,6 +128,7 @@ Required properties:
|
||||
- compatible : Should be set to one of the following supported values:
|
||||
- "samsung,exynos5250-usbdrd-phy" - for exynos5250 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;
|
||||
- clocks: Clock IDs array as required by the controller
|
||||
- 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
|
||||
determine bit values for clock settings register.
|
||||
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
|
||||
control pmu registers for power isolation.
|
||||
- #phy-cells : from the generic PHY bindings, must be 1;
|
||||
|
@ -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.
|
||||
|
||||
struct phy *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);
|
||||
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);
|
||||
|
||||
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
|
||||
init, exit, power_on and power_off. *init_data* is mandatory to get a reference
|
||||
to the PHY in the case of non-dt boot. See section *Board File Initialization*
|
||||
on how init_data should be used.
|
||||
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
|
||||
@ -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_forbid for performing PM operations.
|
||||
|
||||
8. Board File Initialization
|
||||
8. PHY Mappings
|
||||
|
||||
Certain board file initialization is necessary in order to get a reference
|
||||
to the PHY in the case of non-dt boot.
|
||||
Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe,
|
||||
then in the board file the following initialization should be done.
|
||||
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.
|
||||
|
||||
struct phy_consumer consumers[] = {
|
||||
PHY_CONSUMER("dwc3.0", "usb"),
|
||||
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.
|
||||
The framework offers the following API for registering and unregistering the
|
||||
lookups.
|
||||
|
||||
struct phy_init_data init_data = {
|
||||
.consumers = consumers,
|
||||
.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");
|
||||
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);
|
||||
|
||||
9. DeviceTree Binding
|
||||
|
||||
|
@ -15,6 +15,13 @@ config GENERIC_PHY
|
||||
phy users can obtain reference to the PHY. All the users of this
|
||||
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
|
||||
tristate "Marvell Berlin SATA PHY driver"
|
||||
depends on ARCH_BERLIN && HAS_IOMEM && OF
|
||||
@ -22,6 +29,12 @@ config PHY_BERLIN_SATA
|
||||
help
|
||||
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
|
||||
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
|
||||
depends on HAS_IOMEM
|
||||
@ -38,6 +51,14 @@ config PHY_MVEBU_SATA
|
||||
depends on OF
|
||||
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
|
||||
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
|
||||
depends on ARCH_STI
|
||||
@ -193,7 +214,7 @@ config PHY_EXYNOS5250_USB2
|
||||
|
||||
config PHY_EXYNOS5_USBDRD
|
||||
tristate "Exynos5 SoC series USB DRD PHY driver"
|
||||
depends on ARCH_EXYNOS5 && OF
|
||||
depends on ARCH_EXYNOS && OF
|
||||
depends on HAS_IOMEM
|
||||
depends on USB_DWC3_EXYNOS
|
||||
select GENERIC_PHY
|
||||
|
@ -3,11 +3,14 @@
|
||||
#
|
||||
|
||||
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_ARMADA375_USBCLUSTER_PHY) += phy-armada375-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_MIPI_VIDEO) += phy-exynos-mipi-video.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_RCAR_GEN2) += phy-rcar-gen2.o
|
||||
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
|
||||
|
158
drivers/phy/phy-armada375-usb2.c
Normal file
158
drivers/phy/phy-armada375-usb2.c
Normal 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");
|
@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, phy);
|
||||
|
||||
gphy = devm_phy_create(dev, NULL, &ops, NULL);
|
||||
gphy = devm_phy_create(dev, NULL, &ops);
|
||||
if (IS_ERR(gphy))
|
||||
return PTR_ERR(gphy);
|
||||
|
||||
|
@ -30,7 +30,8 @@
|
||||
#define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16)
|
||||
#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 */
|
||||
#define REF_FREF_SEL_25 BIT(0)
|
||||
@ -61,15 +62,16 @@ struct phy_berlin_priv {
|
||||
struct clk *clk;
|
||||
struct phy_berlin_desc **phys;
|
||||
unsigned nphys;
|
||||
u32 phy_base;
|
||||
};
|
||||
|
||||
static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg,
|
||||
u32 mask, u32 val)
|
||||
static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg,
|
||||
u32 phy_base, u32 reg, u32 mask, u32 val)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
/* select register */
|
||||
writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR);
|
||||
writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR);
|
||||
|
||||
/* set bits */
|
||||
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);
|
||||
|
||||
/* set PHY mode and ref freq to 25 MHz */
|
||||
phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff,
|
||||
REF_FREF_SEL_25 | PHY_MODE_SATA);
|
||||
phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01,
|
||||
0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA);
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
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 */
|
||||
regval = readl(ctrl_reg + PORT_SCR_CTL);
|
||||
@ -218,6 +223,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
|
||||
if (!priv->phys)
|
||||
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);
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
@ -239,7 +249,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
|
||||
if (!phy_desc)
|
||||
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)) {
|
||||
dev_err(dev, "failed to create PHY %d\n", phy_id);
|
||||
return PTR_ERR(phy);
|
||||
@ -258,13 +268,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
|
||||
|
||||
phy_provider =
|
||||
devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id phy_berlin_sata_of_match[] = {
|
||||
{ .compatible = "marvell,berlin2-sata-phy" },
|
||||
{ .compatible = "marvell,berlin2q-sata-phy" },
|
||||
{ },
|
||||
};
|
||||
|
223
drivers/phy/phy-berlin-usb.c
Normal file
223
drivers/phy/phy-berlin-usb.c
Normal 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");
|
@ -26,6 +26,7 @@
|
||||
static struct class *phy_class;
|
||||
static DEFINE_MUTEX(phy_provider_mutex);
|
||||
static LIST_HEAD(phy_provider_list);
|
||||
static LIST_HEAD(phys);
|
||||
static DEFINE_IDA(phy_ida);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 *phy;
|
||||
struct device *dev;
|
||||
struct phy_consumer *consumers;
|
||||
struct class_dev_iter iter;
|
||||
struct phy_lookup *pl;
|
||||
|
||||
class_dev_iter_init(&iter, phy_class, NULL, NULL);
|
||||
while ((dev = class_dev_iter_next(&iter))) {
|
||||
phy = to_phy(dev);
|
||||
if (!phy || !dev_id || !con_id)
|
||||
return -EINVAL;
|
||||
|
||||
if (!phy->init_data)
|
||||
continue;
|
||||
count = phy->init_data->num_consumers;
|
||||
consumers = phy->init_data->consumers;
|
||||
while (count--) {
|
||||
if (!strcmp(consumers->dev_name, dev_name(device)) &&
|
||||
!strcmp(consumers->port, port)) {
|
||||
class_dev_iter_exit(&iter);
|
||||
return phy;
|
||||
}
|
||||
consumers++;
|
||||
pl = kzalloc(sizeof(*pl), GFP_KERNEL);
|
||||
if (!pl)
|
||||
return -ENOMEM;
|
||||
|
||||
pl->dev_id = dev_id;
|
||||
pl->con_id = con_id;
|
||||
pl->phy = phy;
|
||||
|
||||
mutex_lock(&phy_provider_mutex);
|
||||
list_add_tail(&pl->node, &phys);
|
||||
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);
|
||||
return ERR_PTR(-ENODEV);
|
||||
static struct phy *phy_find(struct device *dev, const char *con_id)
|
||||
{
|
||||
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)
|
||||
@ -414,21 +460,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args
|
||||
{
|
||||
struct phy *phy;
|
||||
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);
|
||||
while ((dev = class_dev_iter_next(&iter))) {
|
||||
phy = to_phy(dev);
|
||||
if (node != phy->dev.of_node) {
|
||||
for_each_child_of_node(node, child) {
|
||||
if (child == phy->dev.of_node)
|
||||
goto phy_found;
|
||||
}
|
||||
if (args->np != phy->dev.of_node)
|
||||
continue;
|
||||
}
|
||||
|
||||
phy_found:
|
||||
class_dev_iter_exit(&iter);
|
||||
return phy;
|
||||
}
|
||||
@ -463,7 +501,7 @@ struct phy *phy_get(struct device *dev, const char *string)
|
||||
string);
|
||||
phy = _of_phy_get(dev->of_node, index);
|
||||
} else {
|
||||
phy = phy_lookup(dev, string);
|
||||
phy = phy_find(dev, string);
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return phy;
|
||||
@ -588,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
|
||||
* @dev: device that is creating the new phy
|
||||
* @node: device node of the phy
|
||||
* @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.
|
||||
*/
|
||||
struct phy *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)
|
||||
{
|
||||
int ret;
|
||||
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->id = id;
|
||||
phy->ops = ops;
|
||||
phy->init_data = init_data;
|
||||
|
||||
ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id);
|
||||
if (ret)
|
||||
@ -667,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create);
|
||||
* @dev: device that is creating the new phy
|
||||
* @node: device node of the phy
|
||||
* @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.
|
||||
* 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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct phy **ptr, *phy;
|
||||
|
||||
@ -684,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node,
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
phy = phy_create(dev, node, ops, init_data);
|
||||
phy = phy_create(dev, node, ops);
|
||||
if (!IS_ERR(phy)) {
|
||||
*ptr = phy;
|
||||
devres_add(dev, ptr);
|
||||
|
@ -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);
|
||||
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)) {
|
||||
dev_err(dev, "failed to create Display Port PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
|
@ -137,7 +137,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
|
||||
struct phy *phy = devm_phy_create(dev, NULL,
|
||||
&exynos_mipi_video_phy_ops, NULL);
|
||||
&exynos_mipi_video_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "failed to create PHY %d\n", i);
|
||||
return PTR_ERR(phy);
|
||||
|
@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata {
|
||||
const struct exynos5_usbdrd_phy_config *phy_cfg;
|
||||
u32 pmu_offset_usbdrd0_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
|
||||
* @reg_phy: usb phy controller register memory base
|
||||
* @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
|
||||
* @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
|
||||
* instances each with its 'phy' and 'phy_cfg'.
|
||||
@ -155,12 +159,16 @@ struct exynos5_usbdrd_phy_drvdata {
|
||||
* reference clocks' for SS and HS operations
|
||||
* @ref_clk: reference clock to PHY block from which PHY's
|
||||
* 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 device *dev;
|
||||
void __iomem *reg_phy;
|
||||
struct clk *clk;
|
||||
struct clk *pipeclk;
|
||||
struct clk *utmiclk;
|
||||
struct clk *itpclk;
|
||||
const struct exynos5_usbdrd_phy_drvdata *drv_data;
|
||||
struct phy_usb_instance {
|
||||
struct phy *phy;
|
||||
@ -172,6 +180,7 @@ struct exynos5_usbdrd_phy {
|
||||
u32 extrefclk;
|
||||
struct clk *ref_clk;
|
||||
struct regulator *vbus;
|
||||
struct regulator *vbus_boost;
|
||||
};
|
||||
|
||||
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");
|
||||
|
||||
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 */
|
||||
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) {
|
||||
ret = regulator_enable(phy_drd->vbus);
|
||||
if (ret) {
|
||||
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;
|
||||
|
||||
fail_vbus_boost:
|
||||
if (phy_drd->vbus_boost)
|
||||
regulator_disable(phy_drd->vbus_boost);
|
||||
|
||||
fail_vbus:
|
||||
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;
|
||||
}
|
||||
@ -481,8 +513,15 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
|
||||
/* Disable VBUS supply */
|
||||
if (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);
|
||||
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;
|
||||
}
|
||||
@ -506,6 +545,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = {
|
||||
.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[] = {
|
||||
{
|
||||
.id = EXYNOS5_DRDPHY_UTMI,
|
||||
@ -525,11 +615,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
|
||||
.phy_cfg = phy_cfg_exynos5,
|
||||
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_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 = {
|
||||
.phy_cfg = phy_cfg_exynos5,
|
||||
.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[] = {
|
||||
@ -539,6 +637,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
|
||||
}, {
|
||||
.compatible = "samsung,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;
|
||||
struct regmap *reg_pmu;
|
||||
u32 pmu_offset;
|
||||
unsigned long ref_rate;
|
||||
int i, ret;
|
||||
int channel;
|
||||
|
||||
@ -576,23 +676,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
drv_data = match->data;
|
||||
phy_drd->drv_data = drv_data;
|
||||
|
||||
phy_drd->clk = devm_clk_get(dev, "phy");
|
||||
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);
|
||||
ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
|
||||
if (ret) {
|
||||
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
|
||||
ref_rate);
|
||||
dev_err(dev, "Failed to initialize clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -622,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get Vbus regulator */
|
||||
/* Get Vbus regulators */
|
||||
phy_drd->vbus = devm_regulator_get(dev, "vbus");
|
||||
if (IS_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_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");
|
||||
|
||||
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
|
||||
struct phy *phy = devm_phy_create(dev, NULL,
|
||||
&exynos5_usbdrd_phy_ops,
|
||||
NULL);
|
||||
&exynos5_usbdrd_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "Failed to create usbdrd_phy phy\n");
|
||||
return PTR_ERR(phy);
|
||||
|
@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
clk_disable_unprepare(sata_phy->phyclk);
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
|
@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(priv->peri_ctrl))
|
||||
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)) {
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
@ -164,10 +164,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
|
||||
|
||||
phy_set_drvdata(phy, priv);
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id hix5hd2_sata_phy_of_match[] = {
|
||||
|
1283
drivers/phy/phy-miphy28lp.c
Normal file
1283
drivers/phy/phy-miphy28lp.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -593,7 +593,7 @@ static int miphy365x_probe(struct platform_device *pdev)
|
||||
|
||||
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)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
||||
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);
|
||||
if (IS_ERR(provider))
|
||||
return PTR_ERR(provider);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id miphy365x_of_match[] = {
|
||||
|
@ -101,7 +101,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
|
||||
if (IS_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))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
|
@ -256,7 +256,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, phy);
|
||||
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)) {
|
||||
pm_runtime_disable(phy->dev);
|
||||
return PTR_ERR(generic_phy);
|
||||
|
@ -228,8 +228,7 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(phy->mmio))
|
||||
return PTR_ERR(phy->mmio);
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops,
|
||||
NULL);
|
||||
generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
dev_err(dev, "%s: failed to create phy\n", __func__);
|
||||
return PTR_ERR(generic_phy);
|
||||
|
@ -150,8 +150,7 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(phy->mmio))
|
||||
return PTR_ERR(phy->mmio);
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops,
|
||||
NULL);
|
||||
generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
dev_err(dev, "%s: failed to create phy\n", __func__);
|
||||
return PTR_ERR(generic_phy);
|
||||
|
@ -304,7 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
|
||||
phy->select_value = select_value[channel_num][n];
|
||||
|
||||
phy->phy = devm_phy_create(dev, NULL,
|
||||
&rcar_gen2_phy_ops, NULL);
|
||||
&rcar_gen2_phy_ops);
|
||||
if (IS_ERR(phy->phy)) {
|
||||
dev_err(dev, "Failed to create PHY\n");
|
||||
return PTR_ERR(phy->phy);
|
||||
|
@ -202,8 +202,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
|
||||
struct samsung_usb2_phy_instance *p = &drv->instances[i];
|
||||
|
||||
dev_dbg(dev, "Creating phy \"%s\"\n", label);
|
||||
p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops,
|
||||
NULL);
|
||||
p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);
|
||||
if (IS_ERR(p->phy)) {
|
||||
dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
|
||||
label);
|
||||
|
@ -227,7 +227,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
dev_err(dev, "failed to create SATA PCIe PHY\n");
|
||||
return PTR_ERR(priv->phy);
|
||||
|
@ -259,7 +259,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
dev_err(dev, "failed to create SATA PCIe PHY\n");
|
||||
return PTR_ERR(priv->phy);
|
||||
|
@ -137,7 +137,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
|
||||
}
|
||||
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)) {
|
||||
dev_err(dev, "failed to create Display Port PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
|
@ -148,7 +148,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
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_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id stih41x_usb_phy_of_match[] = {
|
||||
|
@ -157,6 +157,10 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
||||
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 */
|
||||
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);
|
||||
|
||||
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 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))
|
||||
return PTR_ERR(data->base);
|
||||
|
||||
/* Skip 0, 0 is the phy for otg which is not yet supported. */
|
||||
for (i = 1; i < data->num_phys; i++) {
|
||||
for (i = 0; i < data->num_phys; i++) {
|
||||
struct sun4i_usb_phy *phy = data->phys + i;
|
||||
char name[16];
|
||||
|
||||
@ -295,7 +298,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
dev_err(dev, "failed to create PHY %d\n", i);
|
||||
return PTR_ERR(phy->phy);
|
||||
|
@ -399,7 +399,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, phy);
|
||||
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))
|
||||
return PTR_ERR(generic_phy);
|
||||
|
||||
|
@ -644,7 +644,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
|
||||
struct usb_otg *otg;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy_init_data *init_data = NULL;
|
||||
|
||||
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
|
||||
if (!twl)
|
||||
@ -655,7 +654,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
|
||||
(enum twl4030_usb_mode *)&twl->usb_mode);
|
||||
else if (pdata) {
|
||||
twl->usb_mode = pdata->usb_mode;
|
||||
init_data = pdata->init_data;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
|
||||
return -EINVAL;
|
||||
@ -680,7 +678,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
|
||||
otg->set_host = twl4030_set_host;
|
||||
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)) {
|
||||
dev_dbg(&pdev->dev, "Failed to create PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
@ -733,6 +731,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
|
||||
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_put_autosuspend(twl->dev);
|
||||
|
||||
|
@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev)
|
||||
ctx->dev = &pdev->dev;
|
||||
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)) {
|
||||
dev_dbg(&pdev->dev, "Failed to create PHY\n");
|
||||
rc = PTR_ERR(ctx->phy);
|
||||
|
@ -910,7 +910,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
|
||||
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)) {
|
||||
err = PTR_ERR(phy);
|
||||
goto unregister;
|
||||
@ -919,7 +919,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
|
||||
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
|
||||
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)) {
|
||||
err = PTR_ERR(phy);
|
||||
goto unregister;
|
||||
|
@ -29,8 +29,7 @@ int dwc3_host_init(struct dwc3 *dwc)
|
||||
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
|
||||
if (!xhci) {
|
||||
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
|
||||
@ -60,22 +59,33 @@ int dwc3_host_init(struct dwc3 *dwc)
|
||||
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);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register xHCI device\n");
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
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:
|
||||
platform_device_put(xhci);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
19
include/dt-bindings/phy/phy.h
Normal file
19
include/dt-bindings/phy/phy.h
Normal 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 */
|
@ -61,7 +61,6 @@ struct phy {
|
||||
struct device dev;
|
||||
int id;
|
||||
const struct phy_ops *ops;
|
||||
struct phy_init_data *init_data;
|
||||
struct mutex mutex;
|
||||
int init_count;
|
||||
int power_count;
|
||||
@ -84,33 +83,14 @@ struct phy_provider {
|
||||
struct of_phandle_args *args);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct phy_consumer - represents the phy consumer
|
||||
* @dev_name: the device name of the controller that will use this PHY device
|
||||
* @port: name given to the consumer port
|
||||
*/
|
||||
struct phy_consumer {
|
||||
const char *dev_name;
|
||||
const char *port;
|
||||
struct phy_lookup {
|
||||
struct list_head node;
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
struct phy *phy;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 to_phy(a) (container_of((a), struct phy, dev))
|
||||
|
||||
#define of_phy_provider_register(dev, 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 of_phandle_args *args);
|
||||
struct phy *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);
|
||||
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 devm_phy_destroy(struct device *dev, struct phy *phy);
|
||||
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 devm_of_phy_provider_unregister(struct device *dev,
|
||||
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
|
||||
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,
|
||||
struct device_node *node,
|
||||
const struct phy_ops *ops,
|
||||
struct phy_init_data *init_data)
|
||||
const struct phy_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline 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)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
@ -345,6 +324,13 @@ static inline void devm_of_phy_provider_unregister(struct device *dev,
|
||||
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 /* __DRIVERS_PHY_H */
|
||||
|
Loading…
Reference in New Issue
Block a user