Commit 48ab6f53 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-4.9-updated_v1' of...

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

Kishon writes:

phy: for 4.9 (with extcon merge resolution)

updated tag for 4.9 based on usb-next along with extcon merge
resolution

phy updates includes:
*) phy driver for USB 3.0 PHY on Northstar
*) phy driver for Rockchip usb2phy
*) phy driver for the Rockchip SoC internal PCIe PHY
*) phy driver for USB Type-C PHY on rk3399
*) phy_reset() API
*) support for Allwinner A64 usb phy, usb2 phy in r8a7796
*) Fixes in twl4030-usb, tegra phy, sun4i-usb phy, da8xx-usb phy
   and omap-usb2 phy
*) other misc cleanups
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parents 5ee05309 cb9850d0
Driver for Broadcom Northstar USB 3.0 PHY
Required properties:
- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy".
- reg: register mappings for DMP (Device Management Plugin) and ChipCommon B
MMI.
- reg-names: "dmp" and "ccb-mii"
Initialization of USB 3.0 PHY depends on Northstar version. There are currently
three known series: Ax, Bx and Cx.
Known A0: BCM4707 rev 0
Known B0: BCM4707 rev 4, BCM53573 rev 2
Known B1: BCM4707 rev 6
Known C0: BCM47094 rev 0
Example:
usb3-phy {
compatible = "brcm,ns-ax-usb3-phy";
reg = <0x18105000 0x1000>, <0x18003000 0x1000>;
reg-names = "dmp", "ccb-mii";
#phy-cells = <0>;
};
ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
Required properties (phy (parent) node):
- compatible : should be one of the listed compatibles:
* "rockchip,rk3366-usb2phy"
* "rockchip,rk3399-usb2phy"
- reg : the address offset of grf for usb-phy configuration.
- #clock-cells : should be 0.
- clock-output-names : specify the 480m output clock name.
Optional properties:
- clocks : phandle + phy specifier pair, for the input clock of phy.
- clock-names : input clock name of phy, must be "phyclk".
Required nodes : a sub-node is required for each port the phy provides.
The sub-node name is used to identify host or otg port,
and shall be the following entries:
* "otg-port" : the name of otg port.
* "host-port" : the name of host port.
Required properties (port (child) node):
- #phy-cells : must be 0. See ./phy-bindings.txt for details.
- interrupts : specify an interrupt for each entry in interrupt-names.
- interrupt-names : a list which shall be the following entries:
* "otg-id" : for the otg id interrupt.
* "otg-bvalid" : for the otg vbus interrupt.
* "linestate" : for the host/otg linestate interrupt.
Optional properties:
- phy-supply : phandle to a regulator that provides power to VBUS.
See ./phy-bindings.txt for details.
Example:
grf: syscon@ff770000 {
compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
...
u2phy: usb2-phy@700 {
compatible = "rockchip,rk3366-usb2phy";
reg = <0x700 0x2c>;
#clock-cells = <0>;
clock-output-names = "sclk_otgphy0_480m";
u2phy_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "otg-id", "otg-bvalid", "linestate";
status = "okay";
};
u2phy_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "linestate";
status = "okay";
};
};
};
* ROCKCHIP type-c PHY
---------------------
Required properties:
- compatible : must be "rockchip,rk3399-typec-phy"
- reg: Address and length of the usb phy control register set
- rockchip,grf : phandle to the syscon managing the "general
register files"
- clocks : phandle + clock specifier for the phy clocks
- clock-names : string, clock name, must be "tcpdcore", "tcpdphy-ref";
- assigned-clocks: main clock, should be <&cru SCLK_UPHY0_TCPDCORE> or
<&cru SCLK_UPHY1_TCPDCORE>;
- assigned-clock-rates : the phy core clk frequency, shall be: 50000000
- resets : a list of phandle + reset specifier pairs
- reset-names : string reset name, must be:
"uphy", "uphy-pipe", "uphy-tcphy"
- extcon : extcon specifier for the Power Delivery
Note, there are 2 type-c phys for RK3399, and they are almost identical, except
these registers(description below), every register node contains 3 sections:
offset, enable bit, write mask bit.
- rockchip,typec-conn-dir : the register of type-c connector direction,
for type-c phy0, it must be <0xe580 0 16>;
for type-c phy1, it must be <0xe58c 0 16>;
- rockchip,usb3tousb2-en : the register of type-c force usb3 to usb2 enable
control.
for type-c phy0, it must be <0xe580 3 19>;
for type-c phy1, it must be <0xe58c 3 19>;
- rockchip,external-psm : the register of type-c phy external psm clock
selection.
for type-c phy0, it must be <0xe588 14 30>;
for type-c phy1, it must be <0xe594 14 30>;
- rockchip,pipe-status : the register of type-c phy pipe status.
for type-c phy0, it must be <0xe5c0 0 0>;
for type-c phy1, it must be <0xe5c0 16 16>;
Required nodes : a sub-node is required for each port the phy provides.
The sub-node name is used to identify dp or usb3 port,
and shall be the following entries:
* "dp-port" : the name of DP port.
* "usb3-port" : the name of USB3 port.
Required properties (port (child) node):
- #phy-cells : must be 0, See ./phy-bindings.txt for details.
Example:
tcphy0: phy@ff7c0000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff7c0000 0x0 0x40000>;
rockchip,grf = <&grf>;
extcon = <&fusb0>;
clocks = <&cru SCLK_UPHY0_TCPDCORE>,
<&cru SCLK_UPHY0_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
assigned-clock-rates = <50000000>;
resets = <&cru SRST_UPHY0>,
<&cru SRST_UPHY0_PIPE_L00>,
<&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe580 0 16>;
rockchip,usb3tousb2-en = <0xe580 3 19>;
rockchip,external-psm = <0xe588 14 30>;
rockchip,pipe-status = <0xe5c0 0 0>;
tcphy0_dp: dp-port {
#phy-cells = <0>;
};
tcphy0_usb3: usb3-port {
#phy-cells = <0>;
};
};
tcphy1: phy@ff800000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff800000 0x0 0x40000>;
rockchip,grf = <&grf>;
extcon = <&fusb1>;
clocks = <&cru SCLK_UPHY1_TCPDCORE>,
<&cru SCLK_UPHY1_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>;
assigned-clock-rates = <50000000>;
resets = <&cru SRST_UPHY1>,
<&cru SRST_UPHY1_PIPE_L00>,
<&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe58c 0 16>;
rockchip,usb3tousb2-en = <0xe58c 3 19>;
rockchip,external-psm = <0xe594 14 30>;
rockchip,pipe-status = <0xe5c0 16 16>;
tcphy1_dp: dp-port {
#phy-cells = <0>;
};
tcphy1_usb3: usb3-port {
#phy-cells = <0>;
};
};
...@@ -5,6 +5,8 @@ This file provides information on what the device node for the R-Car generation ...@@ -5,6 +5,8 @@ This file provides information on what the device node for the R-Car generation
Required properties: Required properties:
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC.
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
SoC. SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
...@@ -30,11 +32,11 @@ Example (R-Car H3): ...@@ -30,11 +32,11 @@ Example (R-Car H3):
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee080200 0 0x700>; reg = <0 0xee080200 0 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; clocks = <&cpg CPG_MOD 703>;
}; };
usb-phy@ee0a0200 { usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee0a0200 0 0x700>; reg = <0 0xee0a0200 0 0x700>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; clocks = <&cpg CPG_MOD 702>;
}; };
Rockchip PCIE PHY
-----------------------
Required properties:
- compatible: rockchip,rk3399-pcie-phy
- #phy-cells: must be 0
- clocks: Must contain an entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names: Must be "refclk"
- resets: Must contain an entry in reset-names.
See ../reset/reset.txt for details.
- reset-names: Must be "phy"
Example:
grf: syscon@ff770000 {
compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
...
pcie_phy: pcie-phy {
compatible = "rockchip,rk3399-pcie-phy";
#phy-cells = <0>;
clocks = <&cru SCLK_PCIEPHY_REF>;
clock-names = "refclk";
resets = <&cru SRST_PCIEPHY>;
reset-names = "phy";
};
};
...@@ -27,6 +27,9 @@ Optional Properties: ...@@ -27,6 +27,9 @@ Optional Properties:
- clocks : phandle + clock specifier for the phy clocks - clocks : phandle + clock specifier for the phy clocks
- clock-names: string, clock name, must be "phyclk" - clock-names: string, clock name, must be "phyclk"
- #clock-cells: for users of the phy-pll, should be 0 - #clock-cells: for users of the phy-pll, should be 0
- reset-names: Only allow the following entries:
- phy-reset
- resets: Must contain an entry for each entry in reset-names.
Example: Example:
......
...@@ -10,6 +10,7 @@ Required properties: ...@@ -10,6 +10,7 @@ Required properties:
* allwinner,sun8i-a23-usb-phy * allwinner,sun8i-a23-usb-phy
* allwinner,sun8i-a33-usb-phy * allwinner,sun8i-a33-usb-phy
* allwinner,sun8i-h3-usb-phy * allwinner,sun8i-h3-usb-phy
* allwinner,sun50i-a64-usb-phy
- reg : a list of offset + length pairs - reg : a list of offset + length pairs
- reg-names : - reg-names :
* "phy_ctrl" * "phy_ctrl"
......
...@@ -31,6 +31,8 @@ OMAP USB2 PHY ...@@ -31,6 +31,8 @@ OMAP USB2 PHY
Required properties: Required properties:
- compatible: Should be "ti,omap-usb2" - compatible: Should be "ti,omap-usb2"
Should be "ti,dra7x-usb2" for the 1st instance of USB2 PHY on
DRA7x
Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY
in DRA7x in DRA7x
- reg : Address and length of the register set for the device. - reg : Address and length of the register set for the device.
......
...@@ -49,6 +49,7 @@ static void gpio_extcon_work(struct work_struct *work) ...@@ -49,6 +49,7 @@ static void gpio_extcon_work(struct work_struct *work)
state = gpiod_get_value_cansleep(data->id_gpiod); state = gpiod_get_value_cansleep(data->id_gpiod);
if (data->pdata->gpio_active_low) if (data->pdata->gpio_active_low)
state = !state; state = !state;
extcon_set_state_sync(data->edev, data->pdata->extcon_id, state); extcon_set_state_sync(data->edev, data->pdata->extcon_id, state);
} }
......
...@@ -24,6 +24,15 @@ config PHY_BCM_NS_USB2 ...@@ -24,6 +24,15 @@ config PHY_BCM_NS_USB2
Enable this to support Broadcom USB 2.0 PHY connected to the USB Enable this to support Broadcom USB 2.0 PHY connected to the USB
controller on Northstar family. controller on Northstar family.
config PHY_BCM_NS_USB3
tristate "Broadcom Northstar USB 3.0 PHY Driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on HAS_IOMEM && OF
select GENERIC_PHY
help
Enable this to support Broadcom USB 3.0 PHY connected to the USB
controller on Northstar family.
config PHY_BERLIN_USB config PHY_BERLIN_USB
tristate "Marvell Berlin USB PHY Driver" tristate "Marvell Berlin USB PHY Driver"
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
...@@ -258,7 +267,9 @@ config PHY_SUN4I_USB ...@@ -258,7 +267,9 @@ config PHY_SUN4I_USB
depends on RESET_CONTROLLER depends on RESET_CONTROLLER
depends on EXTCON depends on EXTCON
depends on POWER_SUPPLY depends on POWER_SUPPLY
depends on USB_SUPPORT
select GENERIC_PHY select GENERIC_PHY
select USB_COMMON
help help
Enable this to support the transceiver that is part of Allwinner Enable this to support the transceiver that is part of Allwinner
sunxi SoCs. sunxi SoCs.
...@@ -358,6 +369,14 @@ config PHY_ROCKCHIP_USB ...@@ -358,6 +369,14 @@ config PHY_ROCKCHIP_USB
help help
Enable this to support the Rockchip USB 2.0 PHY. Enable this to support the Rockchip USB 2.0 PHY.
config PHY_ROCKCHIP_INNO_USB2
tristate "Rockchip INNO USB2PHY Driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
depends on COMMON_CLK
select GENERIC_PHY
help
Support for Rockchip USB2.0 PHY with Innosilicon IP block.
config PHY_ROCKCHIP_EMMC config PHY_ROCKCHIP_EMMC
tristate "Rockchip EMMC PHY Driver" tristate "Rockchip EMMC PHY Driver"
depends on ARCH_ROCKCHIP && OF depends on ARCH_ROCKCHIP && OF
...@@ -372,6 +391,23 @@ config PHY_ROCKCHIP_DP ...@@ -372,6 +391,23 @@ config PHY_ROCKCHIP_DP
help help
Enable this to support the Rockchip Display Port PHY. Enable this to support the Rockchip Display Port PHY.
config PHY_ROCKCHIP_PCIE
tristate "Rockchip PCIe PHY Driver"
depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
select GENERIC_PHY
select MFD_SYSCON
help
Enable this to support the Rockchip PCIe PHY.
config PHY_ROCKCHIP_TYPEC
tristate "Rockchip TYPEC PHY Driver"
depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
select EXTCON
select GENERIC_PHY
select RESET_CONTROLLER
help
Enable this to support the Rockchip USB TYPEC PHY.
config PHY_ST_SPEAR1310_MIPHY config PHY_ST_SPEAR1310_MIPHY
tristate "ST SPEAR1310-MIPHY driver" tristate "ST SPEAR1310-MIPHY driver"
select GENERIC_PHY select GENERIC_PHY
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.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_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
...@@ -39,8 +40,11 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o ...@@ -39,8 +40,11 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
......
/*
* Broadcom Northstar USB 3.0 PHY Driver
*
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
*
* All magic values used for initialization (and related comments) were obtained
* from Broadcom's SDK:
* Copyright (c) Broadcom Corp, 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bcma/bcma.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/slab.h>
#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */
enum bcm_ns_family {
BCM_NS_UNKNOWN,
BCM_NS_AX,
BCM_NS_BX,
};
struct bcm_ns_usb3 {
struct device *dev;
enum bcm_ns_family family;
void __iomem *dmp;
void __iomem *ccb_mii;
struct phy *phy;
};
static const struct of_device_id bcm_ns_usb3_id_table[] = {
{
.compatible = "brcm,ns-ax-usb3-phy",
.data = (int *)BCM_NS_AX,
},
{
.compatible = "brcm,ns-bx-usb3-phy",
.data = (int *)BCM_NS_BX,
},
{},
};
MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table);
static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr,
u32 mask, u32 value, unsigned long timeout)
{
unsigned long deadline = jiffies + timeout;
u32 val;
do {
val = readl(addr);
if ((val & mask) == value)
return 0;
cpu_relax();
udelay(10);
} while (!time_after_eq(jiffies, deadline));
dev_err(usb3->dev, "Timeout waiting for register %p\n", addr);
return -EBUSY;
}
static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3)
{
return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL,
0x0100, 0x0000,
usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US));
}
static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
{
int err;
err = bcm_ns_usb3_mii_mng_wait_idle(usb3);
if (err < 0) {
dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value);
return err;
}
writel(value, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA);
return 0;
}
static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
{
int err;
/* Enable MDIO. Setting MDCDIV as 26 */
writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL);
/* Wait for MDIO? */
udelay(2);
/* USB3 PLL Block */
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
if (err < 0)
return err;
/* Assert Ana_Pllseq start */
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061000);
/* Assert CML Divider ratio to 26 */
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
/* Asserting PLL Reset */
bcm_ns_usb3_mii_mng_write32(usb3, 0x582ec000);
/* Deaaserting PLL Reset */
bcm_ns_usb3_mii_mng_write32(usb3, 0x582e8000);
/* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3);
/* Deasserting USB3 system reset */
writel(0, usb3->dmp + BCMA_RESET_CTL);
/* PLL frequency monitor enable */
bcm_ns_usb3_mii_mng_write32(usb3, 0x58069000);
/* PIPE Block */
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8060);
/* CMPMAX & CMPMINTH setting */
bcm_ns_usb3_mii_mng_write32(usb3, 0x580af30d);
/* DEGLITCH MIN & MAX setting */
bcm_ns_usb3_mii_mng_write32(usb3, 0x580e6302);
/* TXPMD block */
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
/* Enabling SSC */
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
/* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3);
return 0;
}
static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)
{
int err;
/* Enable MDIO. Setting MDCDIV as 26 */
writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL);
/* Wait for MDIO? */
udelay(2);
/* PLL30 block */
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
if (err < 0)
return err;
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e80e0);
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a009c);
/* Enable SSC */
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a21d3);
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
/* Waiting MII Mgt interface idle */
bcm_ns_usb3_mii_mng_wait_idle(usb3);
/* Deasserting USB3 system reset */
writel(0, usb3->dmp + BCMA_RESET_CTL);
return 0;
}
static int bcm_ns_usb3_phy_init(struct phy *phy)
{
struct bcm_ns_usb3 *usb3 = phy_get_drvdata(phy);
int err;
/* Perform USB3 system soft reset */
writel(BCMA_RESET_CTL_RESET, usb3->dmp + BCMA_RESET_CTL);
switch (usb3->family) {
case BCM_NS_AX:
err = bcm_ns_usb3_phy_init_ns_ax(usb3);
break;
case BCM_NS_BX:
err = bcm_ns_usb3_phy_init_ns_bx(usb3);
break;
default:
WARN_ON(1);
err = -ENOTSUPP;
}
return err;
}
static const struct phy_ops ops = {
.init = bcm_ns_usb3_phy_init,
.owner = THIS_MODULE,
};
static int bcm_ns_usb3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
struct bcm_ns_usb3 *usb3;
struct resource *res;
struct phy_provider *phy_provider;
usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL);
if (!usb3)
return -ENOMEM;
usb3->dev = dev;
of_id = of_match_device(bcm_ns_usb3_id_table, dev);
if (!of_id)
return -EINVAL;
usb3->family = (enum bcm_ns_family)of_id->data;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmp");
usb3->dmp = devm_ioremap_resource(dev, res);
if (IS_ERR(usb3->dmp)) {
dev_err(dev, "Failed to map DMP regs\n");
return PTR_ERR(usb3->dmp);
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccb-mii");
usb3->ccb_mii = devm_ioremap_resource(dev, res);
if (IS_ERR(usb3->ccb_mii)) {
dev_err(dev, "Failed to map ChipCommon B MII regs\n");
return PTR_ERR(usb3->ccb_mii);
}
usb3->phy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(usb3->phy)) {
dev_err(dev, "Failed to create PHY\n");
return PTR_ERR(usb3->phy);
}
phy_set_drvdata(usb3->phy, usb3);
platform_set_drvdata(pdev, usb3);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider))
dev_info(dev, "Registered Broadcom Northstar USB 3.0 PHY driver\n");
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver bcm_ns_usb3_driver = {
.probe = bcm_ns_usb3_probe,
.driver = {
.name = "bcm_ns_usb3",
.of_match_table = bcm_ns_usb3_id_table,
},
};
module_platform_driver(bcm_ns_usb3_driver);
MODULE_LICENSE("GPL v2");
...@@ -18,11 +18,6 @@ ...@@ -18,11 +18,6 @@
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
struct ns2_pci_phy {
struct mdio_device *mdiodev;
struct phy *phy;
};
#define BLK_ADDR_REG_OFFSET 0x1f #define BLK_ADDR_REG_OFFSET 0x1f
#define PLL_AFE1_100MHZ_BLK 0x2100 #define PLL_AFE1_100MHZ_BLK 0x2100
#define PLL_CLK_AMP_OFFSET 0x03 #define PLL_CLK_AMP_OFFSET 0x03
...@@ -30,17 +25,17 @@ struct ns2_pci_phy { ...@@ -30,17 +25,17 @@ struct ns2_pci_phy {
static int ns2_pci_phy_init(struct phy *p) static int ns2_pci_phy_init(struct phy *p)
{ {
struct ns2_pci_phy *phy = phy_get_drvdata(p); struct mdio_device *mdiodev = phy_get_drvdata(p);
int rc; int rc;
/* select the AFE 100MHz block page */ /* select the AFE 100MHz block page */
rc = mdiobus_write(phy->mdiodev->bus, phy->mdiodev->addr, rc = mdiobus_write(mdiodev->bus, mdiodev->addr,
BLK_ADDR_REG_OFFSET, PLL_AFE1_100MHZ_BLK); BLK_ADDR_REG_OFFSET, PLL_AFE1_100MHZ_BLK);
if (rc) if (rc)
goto err; goto err;
/* set the 100 MHz reference clock amplitude to 2.05 v */ /* set the 100 MHz reference clock amplitude to 2.05 v */
rc = mdiobus_write(phy->mdiodev->bus, phy->mdiodev->addr, rc = mdiobus_write(mdiodev->bus, mdiodev->addr,
PLL_CLK_AMP_OFFSET, PLL_CLK_AMP_2P05V); PLL_CLK_AMP_OFFSET, PLL_CLK_AMP_2P05V);
if (rc) if (rc)
goto err; goto err;
...@@ -48,19 +43,19 @@ static int ns2_pci_phy_init(struct phy *p) ...@@ -48,19 +43,19 @@ static int ns2_pci_phy_init(struct phy *p)
return 0; return 0;
err: err:
dev_err(&phy->mdiodev->dev, "Error %d writing to phy\n", rc); dev_err(&mdiodev->dev, "Error %d writing to phy\n", rc);
return rc; return rc;
} }
static struct phy_ops ns2_pci_phy_ops = { static const struct phy_ops ns2_pci_phy_ops = {
.init = ns2_pci_phy_init, .init = ns2_pci_phy_init,
.owner = THIS_MODULE,
}; };
static int ns2_pci_phy_probe(struct mdio_device *mdiodev) static int ns2_pci_phy_probe(struct mdio_device *mdiodev)
{ {
struct device *dev = &mdiodev->dev; struct device *dev = &mdiodev->dev;
struct phy_provider *provider; struct phy_provider *provider;
struct ns2_pci_phy *p;
struct phy *phy; struct phy *phy;
phy = devm_phy_create(dev, dev->of_node, &ns2_pci_phy_ops); phy = devm_phy_create(dev, dev->of_node, &ns2_pci_phy_ops);
...@@ -69,16 +64,7 @@ static int ns2_pci_phy_probe(struct mdio_device *mdiodev) ...@@ -69,16 +64,7 @@ static int ns2_pci_phy_probe(struct mdio_device *mdiodev)
return PTR_ERR(phy); return PTR_ERR(phy);
} }
p = devm_kmalloc(dev, sizeof(struct ns2_pci_phy), phy_set_drvdata(phy, mdiodev);
GFP_KERNEL);
if (!p)
return -ENOMEM;
p->mdiodev = mdiodev;
dev_set_drvdata(dev, p);
p->phy = phy;
phy_set_drvdata(phy, p);
provider = devm_of_phy_provider_register(&phy->dev, provider = devm_of_phy_provider_register(&phy->dev,
of_phy_simple_xlate); of_phy_simple_xlate);
......
...@@ -357,6 +357,21 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode) ...@@ -357,6 +357,21 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode)
} }
EXPORT_SYMBOL_GPL(phy_set_mode); EXPORT_SYMBOL_GPL(phy_set_mode);
int phy_reset(struct phy *phy)
{
int ret;
if (!phy || !phy->ops->reset)
return 0;
mutex_lock(&phy->mutex);
ret = phy->ops->reset(phy);
mutex_unlock(&phy->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(phy_reset);
/** /**
* _of_phy_get() - lookup and obtain a reference to a phy by phandle * _of_phy_get() - lookup and obtain a reference to a phy by phandle
* @np: device_node for which to get the phy * @np: device_node for which to get the phy
......
...@@ -154,7 +154,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) ...@@ -154,7 +154,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
d_phy->regmap = syscon_regmap_lookup_by_compatible( d_phy->regmap = syscon_regmap_lookup_by_compatible(
"ti,da830-cfgchip"); "ti,da830-cfgchip");
else else
d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0"); d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon");
if (IS_ERR(d_phy->regmap)) { if (IS_ERR(d_phy->regmap)) {
dev_err(dev, "Failed to get syscon\n"); dev_err(dev, "Failed to get syscon\n");
return PTR_ERR(d_phy->regmap); return PTR_ERR(d_phy->regmap);
......
...@@ -249,7 +249,7 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, ...@@ -249,7 +249,7 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
static unsigned int static unsigned int
exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
{ {
static u32 reg; u32 reg;
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
/* restore any previous reference clock settings */ /* restore any previous reference clock settings */
...@@ -295,7 +295,7 @@ exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) ...@@ -295,7 +295,7 @@ exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
static unsigned int static unsigned int
exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst) exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
{ {
static u32 reg; u32 reg;
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
/* restore any previous reference clock settings */ /* restore any previous reference clock settings */
......
...@@ -133,11 +133,49 @@ static int omap_usb_power_on(struct phy *x) ...@@ -133,11 +133,49 @@ static int omap_usb_power_on(struct phy *x)
return omap_usb_phy_power(phy, true); return omap_usb_phy_power(phy, true);
} }
static int omap_usb2_disable_clocks(struct omap_usb *phy)
{
clk_disable(phy->wkupclk);
if (!IS_ERR(phy->optclk))
clk_disable(phy->optclk);
return 0;
}
static int omap_usb2_enable_clocks(struct omap_usb *phy)
{
int ret;
ret = clk_enable(phy->wkupclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
goto err0;
}
if (!IS_ERR(phy->optclk)) {
ret = clk_enable(phy->optclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
goto err1;
}
}
return 0;
err1:
clk_disable(phy->wkupclk);
err0:
return ret;
}
static int omap_usb_init(struct phy *x) static int omap_usb_init(struct phy *x)
{ {
struct omap_usb *phy = phy_get_drvdata(x); struct omap_usb *phy = phy_get_drvdata(x);
u32 val; u32 val;
omap_usb2_enable_clocks(phy);
if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
/* /*
* *
...@@ -155,8 +193,16 @@ static int omap_usb_init(struct phy *x) ...@@ -155,8 +193,16 @@ static int omap_usb_init(struct phy *x)
return 0; return 0;
} }
static int omap_usb_exit(struct phy *x)
{
struct omap_usb *phy = phy_get_drvdata(x);
return omap_usb2_disable_clocks(phy);
}
static const struct phy_ops ops = { static const struct phy_ops ops = {
.init = omap_usb_init, .init = omap_usb_init,
.exit = omap_usb_exit,
.power_on = omap_usb_power_on, .power_on = omap_usb_power_on,
.power_off = omap_usb_power_off, .power_off = omap_usb_power_off,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -376,65 +422,11 @@ static int omap_usb2_remove(struct platform_device *pdev) ...@@ -376,65 +422,11 @@ static int omap_usb2_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int omap_usb2_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_usb *phy = platform_get_drvdata(pdev);
clk_disable(phy->wkupclk);
if (!IS_ERR(phy->optclk))
clk_disable(phy->optclk);
return 0;
}
static int omap_usb2_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_usb *phy = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(phy->wkupclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
goto err0;
}
if (!IS_ERR(phy->optclk)) {
ret = clk_enable(phy->optclk);
if (ret < 0) {
dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
goto err1;
}
}
return 0;
err1:
clk_disable(phy->wkupclk);
err0:
return ret;
}
static const struct dev_pm_ops omap_usb2_pm_ops = {
SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume,
NULL)
};
#define DEV_PM_OPS (&omap_usb2_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver omap_usb2_driver = { static struct platform_driver omap_usb2_driver = {
.probe = omap_usb2_probe, .probe = omap_usb2_probe,
.remove = omap_usb2_remove, .remove = omap_usb2_remove,
.driver = { .driver = {
.name = "omap-usb2", .name = "omap-usb2",
.pm = DEV_PM_OPS,
.of_match_table = omap_usb2_id_table, .of_match_table = omap_usb2_id_table,
}, },
}; };
......
...@@ -283,10 +283,8 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy, ...@@ -283,10 +283,8 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy,
err = 0; err = 0;
} }
snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
if (of_get_property(dev->of_node, prop_name, NULL)) vreg->is_always_on = of_property_read_bool(dev->of_node,
vreg->is_always_on = true; prop_name);
else
vreg->is_always_on = false;
} }
if (!strcmp(name, "vdda-pll")) { if (!strcmp(name, "vdda-pll")) {
......
...@@ -280,6 +280,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) ...@@ -280,6 +280,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
{ .compatible = "renesas,usb2-phy-r8a7795" }, { .compatible = "renesas,usb2-phy-r8a7795" },
{ .compatible = "renesas,usb2-phy-r8a7796" },
{ .compatible = "renesas,rcar-gen3-usb2-phy" }, { .compatible = "renesas,rcar-gen3-usb2-phy" },
{ } { }
}; };
......
This diff is collapsed.
/*
* Rockchip PCIe PHY driver
*
* Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
* Copyright (C) 2016 ROCKCHIP, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
/*
* The higher 16-bit of this register is used for write protection
* only if BIT(x + 16) set to 1 the BIT(x) can be written.
*/
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
#define PHY_MAX_LANE_NUM 4
#define PHY_CFG_DATA_SHIFT 7
#define PHY_CFG_ADDR_SHIFT 1
#define PHY_CFG_DATA_MASK 0xf
#define PHY_CFG_ADDR_MASK 0x3f
#define PHY_CFG_RD_MASK 0x3ff
#define PHY_CFG_WR_ENABLE 1
#define PHY_CFG_WR_DISABLE 1
#define PHY_CFG_WR_SHIFT 0
#define PHY_CFG_WR_MASK 1
#define PHY_CFG_PLL_LOCK 0x10
#define PHY_CFG_CLK_TEST 0x10
#define PHY_CFG_CLK_SCC 0x12
#define PHY_CFG_SEPE_RATE BIT(3)
#define PHY_CFG_PLL_100M BIT(3)
#define PHY_PLL_LOCKED BIT(9)
#define PHY_PLL_OUTPUT BIT(10)
#define PHY_LANE_A_STATUS 0x30
#define PHY_LANE_B_STATUS 0x31
#define PHY_LANE_C_STATUS 0x32
#define PHY_LANE_D_STATUS 0x33
#define PHY_LANE_RX_DET_SHIFT 11
#define PHY_LANE_RX_DET_TH 0x1
#define PHY_LANE_IDLE_OFF 0x1
#define PHY_LANE_IDLE_MASK 0x1
#define PHY_LANE_IDLE_A_SHIFT 3
#define PHY_LANE_IDLE_B_SHIFT 4
#define PHY_LANE_IDLE_C_SHIFT 5
#define PHY_LANE_IDLE_D_SHIFT 6
struct rockchip_pcie_data {
unsigned int pcie_conf;
unsigned int pcie_status;
unsigned int pcie_laneoff;
};
struct rockchip_pcie_phy {
struct rockchip_pcie_data *phy_data;
struct regmap *reg_base;
struct reset_control *phy_rst;
struct clk *clk_pciephy_ref;
};
static inline void phy_wr_cfg(struct rockchip_pcie_phy *rk_phy,
u32 addr, u32 data)
{
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(data,
PHY_CFG_DATA_MASK,
PHY_CFG_DATA_SHIFT) |
HIWORD_UPDATE(addr,
PHY_CFG_ADDR_MASK,
PHY_CFG_ADDR_SHIFT));
udelay(1);
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(PHY_CFG_WR_ENABLE,
PHY_CFG_WR_MASK,
PHY_CFG_WR_SHIFT));
udelay(1);
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(PHY_CFG_WR_DISABLE,
PHY_CFG_WR_MASK,
PHY_CFG_WR_SHIFT));
}
static inline u32 phy_rd_cfg(struct rockchip_pcie_phy *rk_phy,
u32 addr)
{
u32 val;
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(addr,
PHY_CFG_RD_MASK,
PHY_CFG_ADDR_SHIFT));
regmap_read(rk_phy->reg_base,
rk_phy->phy_data->pcie_status,
&val);
return val;
}
static int rockchip_pcie_phy_power_off(struct phy *phy)
{
struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy);
int err = 0;
err = reset_control_assert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "assert phy_rst err %d\n", err);
return err;
}
return 0;
}
static int rockchip_pcie_phy_power_on(struct phy *phy)
{
struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy);
int err = 0;
u32 status;
unsigned long timeout;
err = reset_control_deassert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "deassert phy_rst err %d\n", err);
return err;
}
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
PHY_CFG_ADDR_MASK,
PHY_CFG_ADDR_SHIFT));
/*
* No documented timeout value for phy operation below,
* so we make it large enough here. And we use loop-break
* method which should not be harmful.
*/
timeout = jiffies + msecs_to_jiffies(1000);
err = -EINVAL;
while (time_before(jiffies, timeout)) {
regmap_read(rk_phy->reg_base,
rk_phy->phy_data->pcie_status,
&status);
if (status & PHY_PLL_LOCKED) {
dev_dbg(&phy->dev, "pll locked!\n");
err = 0;
break;
}
msleep(20);
}
if (err) {
dev_err(&phy->dev, "pll lock timeout!\n");
goto err_pll_lock;
}
phy_wr_cfg(rk_phy, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
phy_wr_cfg(rk_phy, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
err = -ETIMEDOUT;
while (time_before(jiffies, timeout)) {
regmap_read(rk_phy->reg_base,
rk_phy->phy_data->pcie_status,
&status);
if (!(status & PHY_PLL_OUTPUT)) {
dev_dbg(&phy->dev, "pll output enable done!\n");
err = 0;
break;
}
msleep(20);
}
if (err) {
dev_err(&phy->dev, "pll output enable timeout!\n");
goto err_pll_lock;
}
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
PHY_CFG_ADDR_MASK,
PHY_CFG_ADDR_SHIFT));
err = -EINVAL;
while (time_before(jiffies, timeout)) {
regmap_read(rk_phy->reg_base,
rk_phy->phy_data->pcie_status,
&status);
if (status & PHY_PLL_LOCKED) {
dev_dbg(&phy->dev, "pll relocked!\n");
err = 0;
break;
}
msleep(20);
}
if (err) {
dev_err(&phy->dev, "pll relock timeout!\n");
goto err_pll_lock;
}
return 0;
err_pll_lock:
reset_control_assert(rk_phy->phy_rst);
return err;
}
static int rockchip_pcie_phy_init(struct phy *phy)
{
struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy);
int err = 0;
err = clk_prepare_enable(rk_phy->clk_pciephy_ref);
if (err) {
dev_err(&phy->dev, "Fail to enable pcie ref clock.\n");
goto err_refclk;
}
err = reset_control_assert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "assert phy_rst err %d\n", err);
goto err_reset;
}
return err;
err_reset:
clk_disable_unprepare(rk_phy->clk_pciephy_ref);
err_refclk:
return err;
}
static int rockchip_pcie_phy_exit(struct phy *phy)
{
struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy);
int err = 0;
clk_disable_unprepare(rk_phy->clk_pciephy_ref);
err = reset_control_deassert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "deassert phy_rst err %d\n", err);
goto err_reset;
}
return err;
err_reset:
clk_prepare_enable(rk_phy->clk_pciephy_ref);
return err;
}
static const struct phy_ops ops = {
.init = rockchip_pcie_phy_init,
.exit = rockchip_pcie_phy_exit,
.power_on = rockchip_pcie_phy_power_on,
.power_off = rockchip_pcie_phy_power_off,
.owner = THIS_MODULE,
};
static const struct rockchip_pcie_data rk3399_pcie_data = {
.pcie_conf = 0xe220,
.pcie_status = 0xe2a4,
.pcie_laneoff = 0xe214,
};
static const struct of_device_id rockchip_pcie_phy_dt_ids[] = {
{
.compatible = "rockchip,rk3399-pcie-phy",
.data = &rk3399_pcie_data,
},
{}
};
MODULE_DEVICE_TABLE(of, rockchip_pcie_phy_dt_ids);
static int rockchip_pcie_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rockchip_pcie_phy *rk_phy;
struct phy *generic_phy;
struct phy_provider *phy_provider;
struct regmap *grf;
const struct of_device_id *of_id;
grf = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(grf)) {
dev_err(dev, "Cannot find GRF syscon\n");
return PTR_ERR(grf);
}
rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
if (!rk_phy)
return -ENOMEM;
of_id = of_match_device(rockchip_pcie_phy_dt_ids, &pdev->dev);
if (!of_id)
return -EINVAL;
rk_phy->phy_data = (struct rockchip_pcie_data *)of_id->data;
rk_phy->reg_base = grf;
rk_phy->phy_rst = devm_reset_control_get(dev, "phy");
if (IS_ERR(rk_phy->phy_rst)) {
if (PTR_ERR(rk_phy->phy_rst) != -EPROBE_DEFER)
dev_err(dev,
"missing phy property for reset controller\n");
return PTR_ERR(rk_phy->phy_rst);
}
rk_phy->clk_pciephy_ref = devm_clk_get(dev, "refclk");
if (IS_ERR(rk_phy->clk_pciephy_ref)) {
dev_err(dev, "refclk not found.\n");
return PTR_ERR(rk_phy->clk_pciephy_ref);
}
generic_phy = devm_phy_create(dev, dev->of_node, &ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(generic_phy);
}
phy_set_drvdata(generic_phy, rk_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static struct platform_driver rockchip_pcie_driver = {
.probe = rockchip_pcie_phy_probe,
.driver = {
.name = "rockchip-pcie-phy",
.of_match_table = rockchip_pcie_phy_dt_ids,
},
};
module_platform_driver(rockchip_pcie_driver);
MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip PCIe PHY driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/delay.h>
static int enable_usb_uart; static int enable_usb_uart;
...@@ -64,6 +65,7 @@ struct rockchip_usb_phy { ...@@ -64,6 +65,7 @@ struct rockchip_usb_phy {
struct clk_hw clk480m_hw; struct clk_hw clk480m_hw;
struct phy *phy; struct phy *phy;
bool uart_enabled; bool uart_enabled;
struct reset_control *reset;
}; };
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
...@@ -144,9 +146,23 @@ static int rockchip_usb_phy_power_on(struct phy *_phy) ...@@ -144,9 +146,23 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
return clk_prepare_enable(phy->clk480m); return clk_prepare_enable(phy->clk480m);
} }
static int rockchip_usb_phy_reset(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
if (phy->reset) {
reset_control_assert(phy->reset);
udelay(10);
reset_control_deassert(phy->reset);
}
return 0;
}
static const struct phy_ops ops = { static const struct phy_ops ops = {
.power_on = rockchip_usb_phy_power_on, .power_on = rockchip_usb_phy_power_on,
.power_off = rockchip_usb_phy_power_off, .power_off = rockchip_usb_phy_power_off,
.reset = rockchip_usb_phy_reset,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -185,6 +201,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, ...@@ -185,6 +201,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
return -EINVAL; return -EINVAL;
} }
rk_phy->reset = of_reset_control_get(child, "phy-reset");
if (IS_ERR(rk_phy->reset))
rk_phy->reset = NULL;
rk_phy->reg_offset = reg_offset; rk_phy->reg_offset = reg_offset;
rk_phy->clk = of_clk_get_by_name(child, "phyclk"); rk_phy->clk = of_clk_get_by_name(child, "phyclk");
......
This diff is collapsed.
...@@ -172,6 +172,7 @@ struct twl4030_usb { ...@@ -172,6 +172,7 @@ struct twl4030_usb {
int irq; int irq;
enum musb_vbus_id_status linkstat; enum musb_vbus_id_status linkstat;
bool vbus_supplied; bool vbus_supplied;
bool musb_mailbox_pending;
struct delayed_work id_workaround_work; struct delayed_work id_workaround_work;
}; };
...@@ -439,6 +440,17 @@ static int __maybe_unused twl4030_usb_runtime_resume(struct device *dev) ...@@ -439,6 +440,17 @@ static int __maybe_unused twl4030_usb_runtime_resume(struct device *dev)
(PHY_CLK_CTRL_CLOCKGATING_EN | (PHY_CLK_CTRL_CLOCKGATING_EN |
PHY_CLK_CTRL_CLK32K_EN)); PHY_CLK_CTRL_CLK32K_EN));
twl4030_i2c_access(twl, 1);
twl4030_usb_set_mode(twl, twl->usb_mode);
if (twl->usb_mode == T2_USB_MODE_ULPI)
twl4030_i2c_access(twl, 0);
/*
* According to the TPS65950 TRM, there has to be at least 50ms
* delay between setting POWER_CTRL_OTG_ENAB and enabling charging
* so wait here so that a fully enabled phy can be expected after
* resume
*/
msleep(50);
return 0; return 0;
} }
...@@ -459,11 +471,6 @@ static int twl4030_phy_power_on(struct phy *phy) ...@@ -459,11 +471,6 @@ static int twl4030_phy_power_on(struct phy *phy)
dev_dbg(twl->dev, "%s\n", __func__); dev_dbg(twl->dev, "%s\n", __func__);
pm_runtime_get_sync(twl->dev); pm_runtime_get_sync(twl->dev);
twl4030_i2c_access(twl, 1);
twl4030_usb_set_mode(twl, twl->usb_mode);
if (twl->usb_mode == T2_USB_MODE_ULPI)
twl4030_i2c_access(twl, 0);
twl->linkstat = MUSB_UNKNOWN;
schedule_delayed_work(&twl->id_workaround_work, HZ); schedule_delayed_work(&twl->id_workaround_work, HZ);
return 0; return 0;
...@@ -569,9 +576,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) ...@@ -569,9 +576,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
pm_runtime_mark_last_busy(twl->dev); pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev); pm_runtime_put_autosuspend(twl->dev);
} }
twl->musb_mailbox_pending = true;
}
if (twl->musb_mailbox_pending) {
err = musb_mailbox(status); err = musb_mailbox(status);
if (err) if (!err)
twl->linkstat = MUSB_UNKNOWN; twl->musb_mailbox_pending = false;
} }
/* don't schedule during sleep - irq works right then */ /* don't schedule during sleep - irq works right then */
...@@ -676,6 +686,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) ...@@ -676,6 +686,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->irq = platform_get_irq(pdev, 0); twl->irq = platform_get_irq(pdev, 0);
twl->vbus_supplied = false; twl->vbus_supplied = false;
twl->linkstat = MUSB_UNKNOWN; twl->linkstat = MUSB_UNKNOWN;
twl->musb_mailbox_pending = false;
twl->phy.dev = twl->dev; twl->phy.dev = twl->dev;
twl->phy.label = "twl4030"; twl->phy.label = "twl4030";
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/reset.h> #include <linux/reset.h>
...@@ -101,7 +102,8 @@ tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index) ...@@ -101,7 +102,8 @@ tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index)
return of_find_node_by_name(np, pad->soc->lanes[index].name); return of_find_node_by_name(np, pad->soc->lanes[index].name);
} }
int tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane, static int
tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane,
const char *function) const char *function)
{ {
unsigned int i; unsigned int i;
......
...@@ -249,7 +249,6 @@ extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, ...@@ -249,7 +249,6 @@ extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
bool cable_state); bool cable_state);
extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
bool cable_state); bool cable_state);
/* /*
* Synchronize the state and property data for a specific external connector. * Synchronize the state and property data for a specific external connector.
*/ */
...@@ -359,10 +358,27 @@ static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id ...@@ -359,10 +358,27 @@ static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id
} }
static inline int extcon_sync(struct extcon_dev *edev, unsigned int id) static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
<<<<<<< HEAD
=======
{
return 0;
}
static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value *prop_val)
{
return 0;
}
static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop,
union extcon_property_value prop_val)
>>>>>>> next
{ {
return 0; return 0;
} }
<<<<<<< HEAD
static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop, unsigned int prop,
union extcon_property_value *prop_val) union extcon_property_value *prop_val)
...@@ -371,24 +387,36 @@ static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, ...@@ -371,24 +387,36 @@ static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
} }
static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
unsigned int prop, unsigned int prop,
=======
static inline int extcon_set_property_sync(struct extcon_dev *edev,
unsigned int id, unsigned int prop,
>>>>>>> next
union extcon_property_value prop_val) union extcon_property_value prop_val)
{ {
return 0; return 0;
} }
<<<<<<< HEAD
static inline int extcon_set_property_sync(struct extcon_dev *edev, static inline int extcon_set_property_sync(struct extcon_dev *edev,
unsigned int id, unsigned int prop, unsigned int id, unsigned int prop,
union extcon_property_value prop_val) union extcon_property_value prop_val)
=======
static inline int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop)
>>>>>>> next
{ {
return 0; return 0;
} }
<<<<<<< HEAD
static inline int extcon_get_property_capability(struct extcon_dev *edev, static inline int extcon_get_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop) unsigned int id, unsigned int prop)
{ {
return 0; return 0;
} }
=======
>>>>>>> next
static inline int extcon_set_property_capability(struct extcon_dev *edev, static inline int extcon_set_property_capability(struct extcon_dev *edev,
unsigned int id, unsigned int prop) unsigned int id, unsigned int prop)
{ {
......
...@@ -36,6 +36,7 @@ enum phy_mode { ...@@ -36,6 +36,7 @@ enum phy_mode {
* @power_on: powering on the phy * @power_on: powering on the phy
* @power_off: powering off the phy * @power_off: powering off the phy
* @set_mode: set the mode of the phy * @set_mode: set the mode of the phy
* @reset: resetting the phy
* @owner: the module owner containing the ops * @owner: the module owner containing the ops
*/ */
struct phy_ops { struct phy_ops {
...@@ -44,6 +45,7 @@ struct phy_ops { ...@@ -44,6 +45,7 @@ struct phy_ops {
int (*power_on)(struct phy *phy); int (*power_on)(struct phy *phy);
int (*power_off)(struct phy *phy); int (*power_off)(struct phy *phy);
int (*set_mode)(struct phy *phy, enum phy_mode mode); int (*set_mode)(struct phy *phy, enum phy_mode mode);
int (*reset)(struct phy *phy);
struct module *owner; struct module *owner;
}; };
...@@ -136,6 +138,7 @@ int phy_exit(struct phy *phy); ...@@ -136,6 +138,7 @@ int phy_exit(struct phy *phy);
int phy_power_on(struct phy *phy); int phy_power_on(struct phy *phy);
int phy_power_off(struct phy *phy); int phy_power_off(struct phy *phy);
int phy_set_mode(struct phy *phy, enum phy_mode mode); int phy_set_mode(struct phy *phy, enum phy_mode mode);
int phy_reset(struct phy *phy);
static inline int phy_get_bus_width(struct phy *phy) static inline int phy_get_bus_width(struct phy *phy)
{ {
return phy->attrs.bus_width; return phy->attrs.bus_width;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment