Commit 6b629f28 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-3.20' of...

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

Kishon writes:

Adds a new Rockchip PHY driver and contains miscellaneous fixes.
parents dd321740 bbd3ce86
...@@ -26,6 +26,7 @@ Required properties (port (child) node): ...@@ -26,6 +26,7 @@ Required properties (port (child) node):
filled in "reg". It can also contain the offset of the system configuration 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 registers used as glue-logic to setup the device for SATA/PCIe or USB3
devices. devices.
- st,syscfg : Offset of the parent configuration register.
- resets : phandle to the parent reset controller. - resets : phandle to the parent reset controller.
- reset-names : Associated name must be "miphy-sw-rst". - reset-names : Associated name must be "miphy-sw-rst".
...@@ -54,18 +55,12 @@ example: ...@@ -54,18 +55,12 @@ example:
phy_port0: port@9b22000 { phy_port0: port@9b22000 {
reg = <0x9b22000 0xff>, reg = <0x9b22000 0xff>,
<0x9b09000 0xff>, <0x9b09000 0xff>,
<0x9b04000 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", reg-names = "sata-up",
"pcie-up", "pcie-up",
"pipew", "pipew";
"miphy-ctrl-glue",
"miphy-status-glue", st,syscfg = <0x114 0x818 0xe0 0xec>;
"pcie-glue",
"sata-glue";
#phy-cells = <1>; #phy-cells = <1>;
st,osc-rdy; st,osc-rdy;
reset-names = "miphy-sw-rst"; reset-names = "miphy-sw-rst";
...@@ -75,18 +70,13 @@ example: ...@@ -75,18 +70,13 @@ example:
phy_port1: port@9b2a000 { phy_port1: port@9b2a000 {
reg = <0x9b2a000 0xff>, reg = <0x9b2a000 0xff>,
<0x9b19000 0xff>, <0x9b19000 0xff>,
<0x9b14000 0xff>, <0x9b14000 0xff>;
<0x118 0x4>,
<0x81c 0x4>,
<0xe4 0x4>,
<0xf0 0x4>;
reg-names = "sata-up", reg-names = "sata-up",
"pcie-up", "pcie-up",
"pipew", "pipew";
"miphy-ctrl-glue",
"miphy-status-glue", st,syscfg = <0x118 0x81c 0xe4 0xf0>;
"pcie-glue",
"sata-glue";
#phy-cells = <1>; #phy-cells = <1>;
st,osc-force-ext; st,osc-force-ext;
reset-names = "miphy-sw-rst"; reset-names = "miphy-sw-rst";
...@@ -95,13 +85,12 @@ example: ...@@ -95,13 +85,12 @@ example:
phy_port2: port@8f95000 { phy_port2: port@8f95000 {
reg = <0x8f95000 0xff>, reg = <0x8f95000 0xff>,
<0x8f90000 0xff>, <0x8f90000 0xff>;
<0x11c 0x4>,
<0x820 0x4>;
reg-names = "pipew", reg-names = "pipew",
"usb3-up", "usb3-up";
"miphy-ctrl-glue",
"miphy-status-glue"; st,syscfg = <0x11c 0x820>;
#phy-cells = <1>; #phy-cells = <1>;
reset-names = "miphy-sw-rst"; reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY2_SOFTRESET>; resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
...@@ -125,4 +114,4 @@ example: ...@@ -125,4 +114,4 @@ example:
Macro definitions for the supported miphy configuration can be found in: Macro definitions for the supported miphy configuration can be found in:
include/dt-bindings/phy/phy-miphy28lp.h include/dt-bindings/phy/phy.h
...@@ -6,8 +6,10 @@ for SATA and PCIe. ...@@ -6,8 +6,10 @@ for SATA and PCIe.
Required properties (controller (parent) node): Required properties (controller (parent) node):
- compatible : Should be "st,miphy365x-phy" - compatible : Should be "st,miphy365x-phy"
- st,syscfg : Should be a phandle of the system configuration register group - st,syscfg : Phandle / integer array property. Phandle of sysconfig group
which contain the SATA, PCIe mode setting bits containing the miphy registers and integer array should contain
an entry for each port sub-node, specifying the control
register offset inside the sysconfig group.
Required nodes : A sub-node is required for each channel the controller Required nodes : A sub-node is required for each channel the controller
provides. Address range information including the usual provides. Address range information including the usual
...@@ -26,7 +28,6 @@ Required properties (port (child) node): ...@@ -26,7 +28,6 @@ Required properties (port (child) node):
registers filled in "reg": registers filled in "reg":
- sata: For SATA devices - sata: For SATA devices
- pcie: For PCIe devices - pcie: For PCIe devices
- syscfg: To specify the syscfg based config register
Optional properties (port (child) node): Optional properties (port (child) node):
- st,sata-gen : Generation of locally attached SATA IP. Expected values - st,sata-gen : Generation of locally attached SATA IP. Expected values
...@@ -39,20 +40,20 @@ Example: ...@@ -39,20 +40,20 @@ Example:
miphy365x_phy: miphy365x@fe382000 { miphy365x_phy: miphy365x@fe382000 {
compatible = "st,miphy365x-phy"; compatible = "st,miphy365x-phy";
st,syscfg = <&syscfg_rear>; st,syscfg = <&syscfg_rear 0x824 0x828>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
ranges; ranges;
phy_port0: port@fe382000 { phy_port0: port@fe382000 {
reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>; reg = <0xfe382000 0x100>, <0xfe394000 0x100>;
reg-names = "sata", "pcie", "syscfg"; reg-names = "sata", "pcie";
#phy-cells = <1>; #phy-cells = <1>;
st,sata-gen = <3>; st,sata-gen = <3>;
}; };
phy_port1: port@fe38a000 { phy_port1: port@fe38a000 {
reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>;; reg = <0xfe38a000 0x100>, <0xfe804000 0x100>;;
reg-names = "sata", "pcie", "syscfg"; reg-names = "sata", "pcie", "syscfg";
#phy-cells = <1>; #phy-cells = <1>;
st,pcie-tx-pol-inv; st,pcie-tx-pol-inv;
......
...@@ -5,10 +5,7 @@ host controllers (when controlling usb2/1.1 devices) available on STiH407 SoC fa ...@@ -5,10 +5,7 @@ host controllers (when controlling usb2/1.1 devices) available on STiH407 SoC fa
Required properties: Required properties:
- compatible : should be "st,stih407-usb2-phy" - compatible : should be "st,stih407-usb2-phy"
- reg : contain the offset and length of the system configuration registers - st,syscfg : phandle of sysconfig bank plus integer array containing phyparam and phyctrl register offsets
used as glue logic to control & parameter phy
- reg-names : the names of the system configuration registers in "reg", should be "param" and "reg"
- st,syscfg : sysconfig register to manage phy parameter at driver level
- resets : list of phandle and reset specifier pairs. There should be two entries, one - resets : list of phandle and reset specifier pairs. There should be two entries, one
for the whole phy and one for the port for the whole phy and one for the port
- reset-names : list of reset signal names. Should be "global" and "port" - reset-names : list of reset signal names. Should be "global" and "port"
...@@ -19,11 +16,8 @@ Example: ...@@ -19,11 +16,8 @@ Example:
usb2_picophy0: usbpicophy@f8 { usb2_picophy0: usbpicophy@f8 {
compatible = "st,stih407-usb2-phy"; compatible = "st,stih407-usb2-phy";
reg = <0xf8 0x04>, /* syscfg 5062 */
<0xf4 0x04>; /* syscfg 5061 */
reg-names = "param", "ctrl";
#phy-cells = <0>; #phy-cells = <0>;
st,syscfg = <&syscfg_core>; st,syscfg = <&syscfg_core 0x100 0xf4>;
resets = <&softreset STIH407_PICOPHY_SOFTRESET>, resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
<&picophyreset STIH407_PICOPHY0_RESET>; <&picophyreset STIH407_PICOPHY0_RESET>;
reset-names = "global", "port"; reset-names = "global", "port";
......
ROCKCHIP USB2 PHY
Required properties:
- compatible: rockchip,rk3288-usb-phy
- rockchip,grf : phandle to the syscon managing the "general
register files"
- #address-cells: should be 1
- #size-cells: should be 0
Sub-nodes:
Each PHY should be represented as a sub-node.
Sub-nodes
required properties:
- #phy-cells: should be 0
- reg: PHY configure reg address offset in GRF
"0x320" - for PHY attach to OTG controller
"0x334" - for PHY attach to HOST0 controller
"0x348" - for PHY attach to HOST1 controller
Optional Properties:
- clocks : phandle + clock specifier for the phy clocks
- clock-names: string, clock name, must be "phyclk"
Example:
usbphy: phy {
compatible = "rockchip,rk3288-usb-phy";
rockchip,grf = <&grf>;
#address-cells = <1>;
#size-cells = <0>;
usbphy0: usb-phy0 {
#phy-cells = <0>;
reg = <0x320>;
};
};
...@@ -3,8 +3,8 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY ...@@ -3,8 +3,8 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY
Required properties: Required properties:
- compatible : should be "samsung,s5pv210-mipi-video-phy"; - compatible : should be "samsung,s5pv210-mipi-video-phy";
- reg : offset and length of the MIPI DPHY register set;
- #phy-cells : from the generic phy bindings, must be 1; - #phy-cells : from the generic phy bindings, must be 1;
- syscon - phandle to the PMU system controller;
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
the PHY specifier identifies the PHY and its meaning is as follows: the PHY specifier identifies the PHY and its meaning is as follows:
......
...@@ -283,21 +283,21 @@ mmc1: sdhci@fe81f000 { ...@@ -283,21 +283,21 @@ mmc1: sdhci@fe81f000 {
miphy365x_phy: phy@fe382000 { miphy365x_phy: phy@fe382000 {
compatible = "st,miphy365x-phy"; compatible = "st,miphy365x-phy";
st,syscfg = <&syscfg_rear>; st,syscfg = <&syscfg_rear 0x824 0x828>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
ranges; ranges;
phy_port0: port@fe382000 { phy_port0: port@fe382000 {
#phy-cells = <1>; #phy-cells = <1>;
reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>; reg = <0xfe382000 0x100>, <0xfe394000 0x100>;
reg-names = "sata", "pcie", "syscfg"; reg-names = "sata", "pcie";
}; };
phy_port1: port@fe38a000 { phy_port1: port@fe38a000 {
#phy-cells = <1>; #phy-cells = <1>;
reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>; reg = <0xfe38a000 0x100>, <0xfe804000 0x100>;
reg-names = "sata", "pcie", "syscfg"; reg-names = "sata", "pcie";
}; };
}; };
......
...@@ -239,6 +239,13 @@ config PHY_QCOM_IPQ806X_SATA ...@@ -239,6 +239,13 @@ config PHY_QCOM_IPQ806X_SATA
depends on OF depends on OF
select GENERIC_PHY select GENERIC_PHY
config PHY_ROCKCHIP_USB
tristate "Rockchip USB2 PHY Driver"
depends on ARCH_ROCKCHIP && OF
select GENERIC_PHY
help
Enable this to support the Rockchip USB 2.0 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
......
...@@ -28,6 +28,7 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o ...@@ -28,6 +28,7 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o 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_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
......
...@@ -118,8 +118,8 @@ static int armada375_usb_phy_probe(struct platform_device *pdev) ...@@ -118,8 +118,8 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
usb_cluster_base = devm_ioremap_resource(&pdev->dev, res); usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
if (!usb_cluster_base) if (IS_ERR(usb_cluster_base))
return -ENOMEM; return PTR_ERR(usb_cluster_base);
phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops); phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
......
...@@ -12,19 +12,18 @@ ...@@ -12,19 +12,18 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/syscon/exynos4-pmu.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mfd/syscon.h>
/* MIPI_PHYn_CONTROL register offset: n = 0..1 */ /* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4) #define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4)
#define EXYNOS_MIPI_PHY_ENABLE (1 << 0)
#define EXYNOS_MIPI_PHY_SRESETN (1 << 1)
#define EXYNOS_MIPI_PHY_MRESETN (1 << 2)
#define EXYNOS_MIPI_PHY_RESET_MASK (3 << 1)
enum exynos_mipi_phy_id { enum exynos_mipi_phy_id {
EXYNOS_MIPI_PHY_ID_CSIS0, EXYNOS_MIPI_PHY_ID_CSIS0,
...@@ -38,43 +37,62 @@ enum exynos_mipi_phy_id { ...@@ -38,43 +37,62 @@ enum exynos_mipi_phy_id {
((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) ((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
struct exynos_mipi_video_phy { struct exynos_mipi_video_phy {
spinlock_t slock;
struct video_phy_desc { struct video_phy_desc {
struct phy *phy; struct phy *phy;
unsigned int index; unsigned int index;
} phys[EXYNOS_MIPI_PHYS_NUM]; } phys[EXYNOS_MIPI_PHYS_NUM];
spinlock_t slock;
void __iomem *regs; void __iomem *regs;
struct mutex mutex;
struct regmap *regmap;
}; };
static int __set_phy_state(struct exynos_mipi_video_phy *state, static int __set_phy_state(struct exynos_mipi_video_phy *state,
enum exynos_mipi_phy_id id, unsigned int on) enum exynos_mipi_phy_id id, unsigned int on)
{ {
const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
void __iomem *addr; void __iomem *addr;
u32 reg, reset; u32 val, reset;
addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
if (is_mipi_dsim_phy_id(id)) if (is_mipi_dsim_phy_id(id))
reset = EXYNOS_MIPI_PHY_MRESETN; reset = EXYNOS4_MIPI_PHY_MRESETN;
else
reset = EXYNOS_MIPI_PHY_SRESETN;
spin_lock(&state->slock);
reg = readl(addr);
if (on)
reg |= reset;
else else
reg &= ~reset; reset = EXYNOS4_MIPI_PHY_SRESETN;
writel(reg, addr);
if (state->regmap) {
/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set. */ mutex_lock(&state->mutex);
if (on) regmap_read(state->regmap, offset, &val);
reg |= EXYNOS_MIPI_PHY_ENABLE; if (on)
else if (!(reg & EXYNOS_MIPI_PHY_RESET_MASK)) val |= reset;
reg &= ~EXYNOS_MIPI_PHY_ENABLE; else
val &= ~reset;
regmap_write(state->regmap, offset, val);
if (on)
val |= EXYNOS4_MIPI_PHY_ENABLE;
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE;
regmap_write(state->regmap, offset, val);
mutex_unlock(&state->mutex);
} else {
addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
spin_lock(&state->slock);
val = readl(addr);
if (on)
val |= reset;
else
val &= ~reset;
writel(val, addr);
/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */
if (on)
val |= EXYNOS4_MIPI_PHY_ENABLE;
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE;
writel(val, addr);
spin_unlock(&state->slock);
}
writel(reg, addr);
spin_unlock(&state->slock);
return 0; return 0;
} }
...@@ -118,7 +136,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) ...@@ -118,7 +136,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
{ {
struct exynos_mipi_video_phy *state; struct exynos_mipi_video_phy *state;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
unsigned int i; unsigned int i;
...@@ -126,14 +143,22 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) ...@@ -126,14 +143,22 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
if (!state) if (!state)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
if (IS_ERR(state->regmap)) {
struct resource *res;
state->regs = devm_ioremap_resource(dev, res); dev_info(dev, "regmap lookup failed: %ld\n",
if (IS_ERR(state->regs)) PTR_ERR(state->regmap));
return PTR_ERR(state->regs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
state->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
}
dev_set_drvdata(dev, state); dev_set_drvdata(dev, state);
spin_lock_init(&state->slock); spin_lock_init(&state->slock);
mutex_init(&state->mutex);
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL, struct phy *phy = devm_phy_create(dev, NULL,
......
...@@ -194,6 +194,14 @@ ...@@ -194,6 +194,14 @@
#define MIPHY_SATA_BANK_NB 3 #define MIPHY_SATA_BANK_NB 3
#define MIPHY_PCIE_BANK_NB 2 #define MIPHY_PCIE_BANK_NB 2
enum {
SYSCFG_CTRL,
SYSCFG_STATUS,
SYSCFG_PCI,
SYSCFG_SATA,
SYSCFG_REG_MAX,
};
struct miphy28lp_phy { struct miphy28lp_phy {
struct phy *phy; struct phy *phy;
struct miphy28lp_dev *phydev; struct miphy28lp_dev *phydev;
...@@ -211,10 +219,7 @@ struct miphy28lp_phy { ...@@ -211,10 +219,7 @@ struct miphy28lp_phy {
u32 sata_gen; u32 sata_gen;
/* Sysconfig registers offsets needed to configure the device */ /* Sysconfig registers offsets needed to configure the device */
u32 syscfg_miphy_ctrl; u32 syscfg_reg[SYSCFG_REG_MAX];
u32 syscfg_miphy_status;
u32 syscfg_pci;
u32 syscfg_sata;
u8 type; u8 type;
}; };
...@@ -834,12 +839,12 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy) ...@@ -834,12 +839,12 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
if (!miphy_phy->osc_rdy) if (!miphy_phy->osc_rdy)
return 0; return 0;
if (!miphy_phy->syscfg_miphy_status) if (!miphy_phy->syscfg_reg[SYSCFG_STATUS])
return -EINVAL; return -EINVAL;
do { do {
regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status, regmap_read(miphy_dev->regmap,
&val); miphy_phy->syscfg_reg[SYSCFG_STATUS], &val);
if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY) if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
cpu_relax(); cpu_relax();
...@@ -888,7 +893,7 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val) ...@@ -888,7 +893,7 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
int err; int err;
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
if (!miphy_phy->syscfg_miphy_ctrl) if (!miphy_phy->syscfg_reg[SYSCFG_CTRL])
return -EINVAL; return -EINVAL;
err = reset_control_assert(miphy_phy->miphy_rst); err = reset_control_assert(miphy_phy->miphy_rst);
...@@ -900,7 +905,8 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val) ...@@ -900,7 +905,8 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
if (miphy_phy->osc_force_ext) if (miphy_phy->osc_force_ext)
miphy_val |= MIPHY_OSC_FORCE_EXT; miphy_val |= MIPHY_OSC_FORCE_EXT;
regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl, regmap_update_bits(miphy_dev->regmap,
miphy_phy->syscfg_reg[SYSCFG_CTRL],
MIPHY_CTRL_MASK, miphy_val); MIPHY_CTRL_MASK, miphy_val);
err = reset_control_deassert(miphy_phy->miphy_rst); err = reset_control_deassert(miphy_phy->miphy_rst);
...@@ -917,8 +923,9 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy) ...@@ -917,8 +923,9 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
int err, sata_conf = SATA_CTRL_SELECT_SATA; int err, sata_conf = SATA_CTRL_SELECT_SATA;
if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci) if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
|| (!miphy_phy->base)) (!miphy_phy->syscfg_reg[SYSCFG_PCI]) ||
(!miphy_phy->base))
return -EINVAL; return -EINVAL;
dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base); dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
...@@ -926,10 +933,11 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy) ...@@ -926,10 +933,11 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
/* Configure the glue-logic */ /* Configure the glue-logic */
sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE); sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata, regmap_update_bits(miphy_dev->regmap,
miphy_phy->syscfg_reg[SYSCFG_SATA],
SATA_CTRL_MASK, sata_conf); SATA_CTRL_MASK, sata_conf);
regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci, regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE); PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
/* MiPHY path and clocking init */ /* MiPHY path and clocking init */
...@@ -951,17 +959,19 @@ static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy) ...@@ -951,17 +959,19 @@ static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy)
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev; struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
int err; int err;
if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci) if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
(!miphy_phy->syscfg_reg[SYSCFG_PCI])
|| (!miphy_phy->base) || (!miphy_phy->pipebase)) || (!miphy_phy->base) || (!miphy_phy->pipebase))
return -EINVAL; return -EINVAL;
dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base); dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
/* Configure the glue-logic */ /* Configure the glue-logic */
regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata, regmap_update_bits(miphy_dev->regmap,
miphy_phy->syscfg_reg[SYSCFG_SATA],
SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE); SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci, regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL); PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
/* MiPHY path and clocking init */ /* MiPHY path and clocking init */
...@@ -1156,7 +1166,8 @@ static int miphy28lp_probe_resets(struct device_node *node, ...@@ -1156,7 +1166,8 @@ static int miphy28lp_probe_resets(struct device_node *node,
static int miphy28lp_of_probe(struct device_node *np, static int miphy28lp_of_probe(struct device_node *np,
struct miphy28lp_phy *miphy_phy) struct miphy28lp_phy *miphy_phy)
{ {
struct resource res; int i;
u32 ctrlreg;
miphy_phy->osc_force_ext = miphy_phy->osc_force_ext =
of_property_read_bool(np, "st,osc-force-ext"); of_property_read_bool(np, "st,osc-force-ext");
...@@ -1175,18 +1186,10 @@ static int miphy28lp_of_probe(struct device_node *np, ...@@ -1175,18 +1186,10 @@ static int miphy28lp_of_probe(struct device_node *np,
if (!miphy_phy->sata_gen) if (!miphy_phy->sata_gen)
miphy_phy->sata_gen = SATA_GEN1; miphy_phy->sata_gen = SATA_GEN1;
if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res)) for (i = 0; i < SYSCFG_REG_MAX; i++) {
miphy_phy->syscfg_miphy_ctrl = res.start; if (!of_property_read_u32_index(np, "st,syscfg", i, &ctrlreg))
miphy_phy->syscfg_reg[i] = ctrlreg;
if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res)) }
miphy_phy->syscfg_miphy_status = res.start;
if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res))
miphy_phy->syscfg_pci = res.start;
if (!miphy28lp_get_resource_byname(np, "sata-glue", &res))
miphy_phy->syscfg_sata = res.start;
return 0; return 0;
} }
......
...@@ -141,7 +141,7 @@ struct miphy365x_phy { ...@@ -141,7 +141,7 @@ struct miphy365x_phy {
bool pcie_tx_pol_inv; bool pcie_tx_pol_inv;
bool sata_tx_pol_inv; bool sata_tx_pol_inv;
u32 sata_gen; u32 sata_gen;
u64 ctrlreg; u32 ctrlreg;
u8 type; u8 type;
}; };
...@@ -179,7 +179,7 @@ static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, ...@@ -179,7 +179,7 @@ static int miphy365x_set_path(struct miphy365x_phy *miphy_phy,
bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); bool sata = (miphy_phy->type == MIPHY_TYPE_SATA);
return regmap_update_bits(miphy_dev->regmap, return regmap_update_bits(miphy_dev->regmap,
(unsigned int)miphy_phy->ctrlreg, miphy_phy->ctrlreg,
SYSCFG_SELECT_SATA_MASK, SYSCFG_SELECT_SATA_MASK,
sata << SYSCFG_SELECT_SATA_POS); sata << SYSCFG_SELECT_SATA_POS);
} }
...@@ -445,7 +445,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, ...@@ -445,7 +445,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
{ {
struct device_node *phynode = miphy_phy->phy->dev.of_node; struct device_node *phynode = miphy_phy->phy->dev.of_node;
const char *name; const char *name;
const __be32 *taddr;
int type = miphy_phy->type; int type = miphy_phy->type;
int ret; int ret;
...@@ -455,22 +454,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, ...@@ -455,22 +454,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
return ret; return ret;
} }
if (!strncmp(name, "syscfg", 6)) {
taddr = of_get_address(phynode, index, NULL, NULL);
if (!taddr) {
dev_err(dev, "failed to fetch syscfg address\n");
return -EINVAL;
}
miphy_phy->ctrlreg = of_translate_address(phynode, taddr);
if (miphy_phy->ctrlreg == OF_BAD_ADDR) {
dev_err(dev, "failed to translate syscfg address\n");
return -EINVAL;
}
return 0;
}
if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) ||
(!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE)))
return 0; return 0;
...@@ -606,7 +589,15 @@ static int miphy365x_probe(struct platform_device *pdev) ...@@ -606,7 +589,15 @@ static int miphy365x_probe(struct platform_device *pdev)
return ret; return ret;
phy_set_drvdata(phy, miphy_dev->phys[port]); phy_set_drvdata(phy, miphy_dev->phys[port]);
port++; port++;
/* sysconfig offsets are indexed from 1 */
ret = of_property_read_u32_index(np, "st,syscfg", port,
&miphy_phy->ctrlreg);
if (ret) {
dev_err(&pdev->dev, "No sysconfig offset found\n");
return ret;
}
} }
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
......
/*
* Rockchip usb PHY driver
*
* Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
* Copyright (C) 2014 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/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
/*
* The higher 16-bit of this register is used for write protection
* only if BIT(13 + 16) set to 1 the BIT(13) can be written.
*/
#define SIDDQ_WRITE_ENA BIT(29)
#define SIDDQ_ON BIT(13)
#define SIDDQ_OFF (0 << 13)
struct rockchip_usb_phy {
unsigned int reg_offset;
struct regmap *reg_base;
struct clk *clk;
struct phy *phy;
};
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
bool siddq)
{
return regmap_write(phy->reg_base, phy->reg_offset,
SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
}
static int rockchip_usb_phy_power_off(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
int ret = 0;
/* Power down usb phy analog blocks by set siddq 1 */
ret = rockchip_usb_phy_power(phy, 1);
if (ret)
return ret;
clk_disable_unprepare(phy->clk);
if (ret)
return ret;
return 0;
}
static int rockchip_usb_phy_power_on(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
int ret = 0;
ret = clk_prepare_enable(phy->clk);
if (ret)
return ret;
/* Power up usb phy analog blocks by set siddq 0 */
ret = rockchip_usb_phy_power(phy, 0);
if (ret)
return ret;
return 0;
}
static struct phy_ops ops = {
.power_on = rockchip_usb_phy_power_on,
.power_off = rockchip_usb_phy_power_off,
.owner = THIS_MODULE,
};
static int rockchip_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rockchip_usb_phy *rk_phy;
struct phy_provider *phy_provider;
struct device_node *child;
struct regmap *grf;
unsigned int reg_offset;
grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
if (IS_ERR(grf)) {
dev_err(&pdev->dev, "Missing rockchip,grf property\n");
return PTR_ERR(grf);
}
for_each_available_child_of_node(dev->of_node, child) {
rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
if (!rk_phy)
return -ENOMEM;
if (of_property_read_u32(child, "reg", &reg_offset)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
return -EINVAL;
}
rk_phy->reg_offset = reg_offset;
rk_phy->reg_base = grf;
rk_phy->clk = of_clk_get_by_name(child, "phyclk");
if (IS_ERR(rk_phy->clk))
rk_phy->clk = NULL;
rk_phy->phy = devm_phy_create(dev, child, &ops);
if (IS_ERR(rk_phy->phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(rk_phy->phy);
}
phy_set_drvdata(rk_phy->phy, rk_phy);
}
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
{ .compatible = "rockchip,rk3288-usb-phy" },
{}
};
MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
static struct platform_driver rockchip_usb_driver = {
.probe = rockchip_usb_phy_probe,
.driver = {
.name = "rockchip-usb-phy",
.owner = THIS_MODULE,
.of_match_table = rockchip_usb_phy_dt_ids,
},
};
module_platform_driver(rockchip_usb_driver);
MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
MODULE_LICENSE("GPL v2");
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#define PHYPARAM_REG 1
#define PHYCTRL_REG 2
/* Default PHY_SEL and REFCLKSEL configuration */ /* Default PHY_SEL and REFCLKSEL configuration */
#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6 #define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
#define STIH407_USB_PICOPHY_CTRL_PORT_MASK 0x1f #define STIH407_USB_PICOPHY_CTRL_PORT_MASK 0x1f
...@@ -93,7 +96,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) ...@@ -93,7 +96,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct phy *phy; struct phy *phy;
struct resource *res; int ret;
phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL); phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
if (!phy_dev) if (!phy_dev)
...@@ -123,19 +126,19 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) ...@@ -123,19 +126,19 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
return PTR_ERR(phy_dev->regmap); return PTR_ERR(phy_dev->regmap);
} }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); ret = of_property_read_u32_index(np, "st,syscfg", PHYPARAM_REG,
if (!res) { &phy_dev->param);
dev_err(dev, "No ctrl reg found\n"); if (ret) {
return -ENXIO; dev_err(dev, "can't get phyparam offset (%d)\n", ret);
return ret;
} }
phy_dev->ctrl = res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "param"); ret = of_property_read_u32_index(np, "st,syscfg", PHYCTRL_REG,
if (!res) { &phy_dev->ctrl);
dev_err(dev, "No param reg found\n"); if (ret) {
return -ENXIO; dev_err(dev, "can't get phyctrl offset (%d)\n", ret);
return ret;
} }
phy_dev->param = res->start;
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data); phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/phy/omap_control_phy.h> #include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/spinlock.h>
#define PLL_STATUS 0x00000004 #define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008 #define PLL_GO 0x00000008
...@@ -82,6 +83,10 @@ struct ti_pipe3 { ...@@ -82,6 +83,10 @@ struct ti_pipe3 {
struct clk *refclk; struct clk *refclk;
struct clk *div_clk; struct clk *div_clk;
struct pipe3_dpll_map *dpll_map; struct pipe3_dpll_map *dpll_map;
bool enabled;
spinlock_t lock; /* serialize clock enable/disable */
/* the below flag is needed specifically for SATA */
bool refclk_enabled;
}; };
static struct pipe3_dpll_map dpll_map_usb[] = { static struct pipe3_dpll_map dpll_map_usb[] = {
...@@ -307,6 +312,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -307,6 +312,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
phy->dev = &pdev->dev; phy->dev = &pdev->dev;
spin_lock_init(&phy->lock);
if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
match = of_match_device(of_match_ptr(ti_pipe3_id_table), match = of_match_device(of_match_ptr(ti_pipe3_id_table),
...@@ -333,21 +339,24 @@ static int ti_pipe3_probe(struct platform_device *pdev) ...@@ -333,21 +339,24 @@ static int ti_pipe3_probe(struct platform_device *pdev)
} }
} }
phy->refclk = devm_clk_get(phy->dev, "refclk");
if (IS_ERR(phy->refclk)) {
dev_err(&pdev->dev, "unable to get refclk\n");
/* older DTBs have missing refclk in SATA PHY
* so don't bail out in case of SATA PHY.
*/
if (!of_device_is_compatible(node, "ti,phy-pipe3-sata"))
return PTR_ERR(phy->refclk);
}
if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) { if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get wkupclk\n"); dev_err(&pdev->dev, "unable to get wkupclk\n");
return PTR_ERR(phy->wkupclk); return PTR_ERR(phy->wkupclk);
} }
phy->refclk = devm_clk_get(phy->dev, "refclk");
if (IS_ERR(phy->refclk)) {
dev_err(&pdev->dev, "unable to get refclk\n");
return PTR_ERR(phy->refclk);
}
} else { } else {
phy->wkupclk = ERR_PTR(-ENODEV); phy->wkupclk = ERR_PTR(-ENODEV);
phy->refclk = ERR_PTR(-ENODEV);
} }
if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
...@@ -426,33 +435,42 @@ static int ti_pipe3_remove(struct platform_device *pdev) ...@@ -426,33 +435,42 @@ static int ti_pipe3_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
static int ti_pipe3_runtime_suspend(struct device *dev)
{ {
struct ti_pipe3 *phy = dev_get_drvdata(dev); if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
int ret;
if (!IS_ERR(phy->wkupclk)) ret = clk_prepare_enable(phy->refclk);
clk_disable_unprepare(phy->wkupclk); if (ret) {
dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
return ret;
}
phy->refclk_enabled = true;
}
return 0;
}
static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
{
if (!IS_ERR(phy->refclk)) if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk);
return 0; phy->refclk_enabled = false;
} }
static int ti_pipe3_runtime_resume(struct device *dev) static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
{ {
u32 ret = 0; int ret = 0;
struct ti_pipe3 *phy = dev_get_drvdata(dev); unsigned long flags;
if (!IS_ERR(phy->refclk)) { spin_lock_irqsave(&phy->lock, flags);
ret = clk_prepare_enable(phy->refclk); if (phy->enabled)
if (ret) { goto err1;
dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
goto err1; ret = ti_pipe3_enable_refclk(phy);
} if (ret)
} goto err1;
if (!IS_ERR(phy->wkupclk)) { if (!IS_ERR(phy->wkupclk)) {
ret = clk_prepare_enable(phy->wkupclk); ret = clk_prepare_enable(phy->wkupclk);
...@@ -469,6 +487,9 @@ static int ti_pipe3_runtime_resume(struct device *dev) ...@@ -469,6 +487,9 @@ static int ti_pipe3_runtime_resume(struct device *dev)
goto err3; goto err3;
} }
} }
phy->enabled = true;
spin_unlock_irqrestore(&phy->lock, flags);
return 0; return 0;
err3: err3:
...@@ -479,20 +500,80 @@ static int ti_pipe3_runtime_resume(struct device *dev) ...@@ -479,20 +500,80 @@ static int ti_pipe3_runtime_resume(struct device *dev)
if (!IS_ERR(phy->refclk)) if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk); clk_disable_unprepare(phy->refclk);
ti_pipe3_disable_refclk(phy);
err1: err1:
spin_unlock_irqrestore(&phy->lock, flags);
return ret; return ret;
} }
static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
{
unsigned long flags;
spin_lock_irqsave(&phy->lock, flags);
if (!phy->enabled) {
spin_unlock_irqrestore(&phy->lock, flags);
return;
}
if (!IS_ERR(phy->wkupclk))
clk_disable_unprepare(phy->wkupclk);
/* Don't disable refclk for SATA PHY due to Errata i783 */
if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
ti_pipe3_disable_refclk(phy);
if (!IS_ERR(phy->div_clk))
clk_disable_unprepare(phy->div_clk);
phy->enabled = false;
spin_unlock_irqrestore(&phy->lock, flags);
}
static int ti_pipe3_runtime_suspend(struct device *dev)
{
struct ti_pipe3 *phy = dev_get_drvdata(dev);
ti_pipe3_disable_clocks(phy);
return 0;
}
static int ti_pipe3_runtime_resume(struct device *dev)
{
struct ti_pipe3 *phy = dev_get_drvdata(dev);
int ret = 0;
ret = ti_pipe3_enable_clocks(phy);
return ret;
}
static int ti_pipe3_suspend(struct device *dev)
{
struct ti_pipe3 *phy = dev_get_drvdata(dev);
ti_pipe3_disable_clocks(phy);
return 0;
}
static int ti_pipe3_resume(struct device *dev)
{
struct ti_pipe3 *phy = dev_get_drvdata(dev);
int ret;
ret = ti_pipe3_enable_clocks(phy);
if (ret)
return ret;
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
}
#endif
static const struct dev_pm_ops ti_pipe3_pm_ops = { static const struct dev_pm_ops ti_pipe3_pm_ops = {
SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend, SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
ti_pipe3_runtime_resume, NULL) ti_pipe3_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
}; };
#define DEV_PM_OPS (&ti_pipe3_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id ti_pipe3_id_table[] = { static const struct of_device_id ti_pipe3_id_table[] = {
{ {
...@@ -520,7 +601,7 @@ static struct platform_driver ti_pipe3_driver = { ...@@ -520,7 +601,7 @@ static struct platform_driver ti_pipe3_driver = {
.remove = ti_pipe3_remove, .remove = ti_pipe3_remove,
.driver = { .driver = {
.name = "ti-pipe3", .name = "ti-pipe3",
.pm = DEV_PM_OPS, .pm = &ti_pipe3_pm_ops,
.of_match_table = of_match_ptr(ti_pipe3_id_table), .of_match_table = of_match_ptr(ti_pipe3_id_table),
}, },
}; };
......
/*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_
#define _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_
/* Exynos4 PMU register definitions */
/* MIPI_PHYn_CONTROL register offset: n = 0..1 */
#define EXYNOS4_MIPI_PHY_CONTROL(n) (0x710 + (n) * 4)
#define EXYNOS4_MIPI_PHY_ENABLE (1 << 0)
#define EXYNOS4_MIPI_PHY_SRESETN (1 << 1)
#define EXYNOS4_MIPI_PHY_MRESETN (1 << 2)
#define EXYNOS4_MIPI_PHY_RESET_MASK (3 << 1)
#endif /* _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_ */
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