diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-05-03 17:49:46 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-05-03 17:49:46 -0400 |
commit | e6c037bfcafad1b401a6c02ba05a3f1b87925860 (patch) | |
tree | 572f796d9ca71afb4ecd776a7f9dca0c3b3ca306 /drivers/phy | |
parent | 681fef8380eb818c0b845fca5d2ab1dcbab114ee (diff) | |
parent | 71f5c63c07e5be7abdce40891778ffbf3cec04f0 (diff) |
Merge tag 'phy-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-testing
Kishon writes:
phy: for 4.7
*) Add a new PHY driver for USB2 PHY on Northstar SoC
*) Add support for Broadcom NS2 SATA3 PHY in existing
Broadcom SATA3 PHY driver
*) Add support for MIPI DPHYs in Exynos5420-compatible
(5420, 5422 and 5800) and Exynos5433 SoCs
*) Add support for USB3 PHY on mt2701
*) Add extcon support for Renesas R-car USB2 PHY driver
*) Misc cleanups
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/Kconfig | 30 | ||||
-rw-r--r-- | drivers/phy/Makefile | 3 | ||||
-rw-r--r-- | drivers/phy/phy-bcm-ns-usb2.c | 137 | ||||
-rw-r--r-- | drivers/phy/phy-brcm-sata.c | 412 | ||||
-rw-r--r-- | drivers/phy/phy-brcmstb-sata.c | 250 | ||||
-rw-r--r-- | drivers/phy/phy-exynos-mipi-video.c | 321 | ||||
-rw-r--r-- | drivers/phy/phy-mt65xx-usb3.c | 77 | ||||
-rw-r--r-- | drivers/phy/phy-rcar-gen2.c | 1 | ||||
-rw-r--r-- | drivers/phy/phy-rcar-gen3-usb2.c | 88 | ||||
-rw-r--r-- | drivers/phy/phy-rockchip-usb.c | 2 |
10 files changed, 950 insertions, 371 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e92b97cd6056..a83ed81d8df8 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -15,6 +15,15 @@ config GENERIC_PHY | |||
15 | phy users can obtain reference to the PHY. All the users of this | 15 | phy users can obtain reference to the PHY. All the users of this |
16 | framework should select this config. | 16 | framework should select this config. |
17 | 17 | ||
18 | config PHY_BCM_NS_USB2 | ||
19 | tristate "Broadcom Northstar USB 2.0 PHY Driver" | ||
20 | depends on ARCH_BCM_IPROC || COMPILE_TEST | ||
21 | depends on HAS_IOMEM && OF | ||
22 | select GENERIC_PHY | ||
23 | help | ||
24 | Enable this to support Broadcom USB 2.0 PHY connected to the USB | ||
25 | controller on Northstar family. | ||
26 | |||
18 | config PHY_BERLIN_USB | 27 | config PHY_BERLIN_USB |
19 | tristate "Marvell Berlin USB PHY Driver" | 28 | tristate "Marvell Berlin USB PHY Driver" |
20 | depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF | 29 | depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF |
@@ -113,14 +122,15 @@ config PHY_MIPHY365X | |||
113 | 122 | ||
114 | config PHY_RCAR_GEN2 | 123 | config PHY_RCAR_GEN2 |
115 | tristate "Renesas R-Car generation 2 USB PHY driver" | 124 | tristate "Renesas R-Car generation 2 USB PHY driver" |
116 | depends on ARCH_SHMOBILE | 125 | depends on ARCH_RENESAS |
117 | depends on GENERIC_PHY | 126 | depends on GENERIC_PHY |
118 | help | 127 | help |
119 | Support for USB PHY found on Renesas R-Car generation 2 SoCs. | 128 | Support for USB PHY found on Renesas R-Car generation 2 SoCs. |
120 | 129 | ||
121 | config PHY_RCAR_GEN3_USB2 | 130 | config PHY_RCAR_GEN3_USB2 |
122 | tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" | 131 | tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" |
123 | depends on OF && ARCH_SHMOBILE | 132 | depends on ARCH_RENESAS |
133 | depends on EXTCON | ||
124 | select GENERIC_PHY | 134 | select GENERIC_PHY |
125 | help | 135 | help |
126 | Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. | 136 | Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. |
@@ -218,9 +228,8 @@ config PHY_MT65XX_USB3 | |||
218 | depends on ARCH_MEDIATEK && OF | 228 | depends on ARCH_MEDIATEK && OF |
219 | select GENERIC_PHY | 229 | select GENERIC_PHY |
220 | help | 230 | help |
221 | Say 'Y' here to add support for Mediatek USB3.0 PHY driver | 231 | Say 'Y' here to add support for Mediatek USB3.0 PHY driver, |
222 | for mt65xx SoCs. it supports two usb2.0 ports and | 232 | it supports multiple usb2.0 and usb3.0 ports. |
223 | one usb3.0 port. | ||
224 | 233 | ||
225 | config PHY_HI6220_USB | 234 | config PHY_HI6220_USB |
226 | tristate "hi6220 USB PHY support" | 235 | tristate "hi6220 USB PHY support" |
@@ -404,14 +413,15 @@ config PHY_TUSB1210 | |||
404 | help | 413 | help |
405 | Support for TI TUSB1210 USB ULPI PHY. | 414 | Support for TI TUSB1210 USB ULPI PHY. |
406 | 415 | ||
407 | config PHY_BRCMSTB_SATA | 416 | config PHY_BRCM_SATA |
408 | tristate "Broadcom STB SATA PHY driver" | 417 | tristate "Broadcom SATA PHY driver" |
409 | depends on ARCH_BRCMSTB || BMIPS_GENERIC | 418 | depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST |
410 | depends on OF | 419 | depends on OF |
411 | select GENERIC_PHY | 420 | select GENERIC_PHY |
421 | default ARCH_BCM_IPROC | ||
412 | help | 422 | help |
413 | Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs. | 423 | Enable this to support the Broadcom SATA PHY. |
414 | Likely useful only with CONFIG_SATA_BRCMSTB enabled. | 424 | If unsure, say N. |
415 | 425 | ||
416 | config PHY_CYGNUS_PCIE | 426 | config PHY_CYGNUS_PCIE |
417 | tristate "Broadcom Cygnus PCIe PHY driver" | 427 | tristate "Broadcom Cygnus PCIe PHY driver" |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 24596a96a887..0de09e13fdbc 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o | 5 | obj-$(CONFIG_GENERIC_PHY) += phy-core.o |
6 | obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o | ||
6 | obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o | 7 | obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o |
7 | obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o | 8 | obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o |
8 | obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o | 9 | obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o |
@@ -49,6 +50,6 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o | |||
49 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o | 50 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o |
50 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o | 51 | obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o |
51 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o | 52 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o |
52 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o | 53 | obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o |
53 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o | 54 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o |
54 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o | 55 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o |
diff --git a/drivers/phy/phy-bcm-ns-usb2.c b/drivers/phy/phy-bcm-ns-usb2.c new file mode 100644 index 000000000000..95ab6b2a0de5 --- /dev/null +++ b/drivers/phy/phy-bcm-ns-usb2.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Broadcom Northstar USB 2.0 PHY Driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/bcma/bcma.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/phy/phy.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | struct bcm_ns_usb2 { | ||
24 | struct device *dev; | ||
25 | struct clk *ref_clk; | ||
26 | struct phy *phy; | ||
27 | void __iomem *dmu; | ||
28 | }; | ||
29 | |||
30 | static int bcm_ns_usb2_phy_init(struct phy *phy) | ||
31 | { | ||
32 | struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy); | ||
33 | struct device *dev = usb2->dev; | ||
34 | void __iomem *dmu = usb2->dmu; | ||
35 | u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv; | ||
36 | int err = 0; | ||
37 | |||
38 | err = clk_prepare_enable(usb2->ref_clk); | ||
39 | if (err < 0) { | ||
40 | dev_err(dev, "Failed to prepare ref clock: %d\n", err); | ||
41 | goto err_out; | ||
42 | } | ||
43 | |||
44 | ref_clk_rate = clk_get_rate(usb2->ref_clk); | ||
45 | if (!ref_clk_rate) { | ||
46 | dev_err(dev, "Failed to get ref clock rate\n"); | ||
47 | err = -EINVAL; | ||
48 | goto err_clk_off; | ||
49 | } | ||
50 | |||
51 | usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL); | ||
52 | |||
53 | if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) { | ||
54 | usb_pll_pdiv = usb2ctl; | ||
55 | usb_pll_pdiv &= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK; | ||
56 | usb_pll_pdiv >>= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT; | ||
57 | } else { | ||
58 | usb_pll_pdiv = 1 << 3; | ||
59 | } | ||
60 | |||
61 | /* Calculate ndiv based on a solid 1920 MHz that is for USB2 PHY */ | ||
62 | usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate; | ||
63 | |||
64 | /* Unlock DMU PLL settings with some magic value */ | ||
65 | writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY); | ||
66 | |||
67 | /* Write USB 2.0 PLL control setting */ | ||
68 | usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK; | ||
69 | usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT; | ||
70 | writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL); | ||
71 | |||
72 | /* Lock DMU PLL settings */ | ||
73 | writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY); | ||
74 | |||
75 | err_clk_off: | ||
76 | clk_disable_unprepare(usb2->ref_clk); | ||
77 | err_out: | ||
78 | return err; | ||
79 | } | ||
80 | |||
81 | static const struct phy_ops ops = { | ||
82 | .init = bcm_ns_usb2_phy_init, | ||
83 | .owner = THIS_MODULE, | ||
84 | }; | ||
85 | |||
86 | static int bcm_ns_usb2_probe(struct platform_device *pdev) | ||
87 | { | ||
88 | struct device *dev = &pdev->dev; | ||
89 | struct bcm_ns_usb2 *usb2; | ||
90 | struct resource *res; | ||
91 | struct phy_provider *phy_provider; | ||
92 | |||
93 | usb2 = devm_kzalloc(&pdev->dev, sizeof(*usb2), GFP_KERNEL); | ||
94 | if (!usb2) | ||
95 | return -ENOMEM; | ||
96 | usb2->dev = dev; | ||
97 | |||
98 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu"); | ||
99 | usb2->dmu = devm_ioremap_resource(dev, res); | ||
100 | if (IS_ERR(usb2->dmu)) { | ||
101 | dev_err(dev, "Failed to map DMU regs\n"); | ||
102 | return PTR_ERR(usb2->dmu); | ||
103 | } | ||
104 | |||
105 | usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk"); | ||
106 | if (IS_ERR(usb2->ref_clk)) { | ||
107 | dev_err(dev, "Clock not defined\n"); | ||
108 | return PTR_ERR(usb2->ref_clk); | ||
109 | } | ||
110 | |||
111 | usb2->phy = devm_phy_create(dev, NULL, &ops); | ||
112 | if (IS_ERR(dev)) | ||
113 | return PTR_ERR(dev); | ||
114 | |||
115 | phy_set_drvdata(usb2->phy, usb2); | ||
116 | platform_set_drvdata(pdev, usb2); | ||
117 | |||
118 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
119 | return PTR_ERR_OR_ZERO(phy_provider); | ||
120 | } | ||
121 | |||
122 | static const struct of_device_id bcm_ns_usb2_id_table[] = { | ||
123 | { .compatible = "brcm,ns-usb2-phy", }, | ||
124 | {}, | ||
125 | }; | ||
126 | MODULE_DEVICE_TABLE(of, bcm_ns_usb2_id_table); | ||
127 | |||
128 | static struct platform_driver bcm_ns_usb2_driver = { | ||
129 | .probe = bcm_ns_usb2_probe, | ||
130 | .driver = { | ||
131 | .name = "bcm_ns_usb2", | ||
132 | .of_match_table = bcm_ns_usb2_id_table, | ||
133 | }, | ||
134 | }; | ||
135 | module_platform_driver(bcm_ns_usb2_driver); | ||
136 | |||
137 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/phy-brcm-sata.c b/drivers/phy/phy-brcm-sata.c new file mode 100644 index 000000000000..6c4c5cb791ca --- /dev/null +++ b/drivers/phy/phy-brcm-sata.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * Broadcom SATA3 AHCI Controller PHY Driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Broadcom | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/phy/phy.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | |||
28 | #define SATA_PCB_BANK_OFFSET 0x23c | ||
29 | #define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4) | ||
30 | |||
31 | #define MAX_PORTS 2 | ||
32 | |||
33 | /* Register offset between PHYs in PCB space */ | ||
34 | #define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000 | ||
35 | |||
36 | /* The older SATA PHY registers duplicated per port registers within the map, | ||
37 | * rather than having a separate map per port. | ||
38 | */ | ||
39 | #define SATA_PCB_REG_40NM_SPACE_SIZE 0x10 | ||
40 | |||
41 | /* Register offset between PHYs in PHY control space */ | ||
42 | #define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8 | ||
43 | |||
44 | enum brcm_sata_phy_version { | ||
45 | BRCM_SATA_PHY_STB_28NM, | ||
46 | BRCM_SATA_PHY_STB_40NM, | ||
47 | BRCM_SATA_PHY_IPROC_NS2, | ||
48 | }; | ||
49 | |||
50 | struct brcm_sata_port { | ||
51 | int portnum; | ||
52 | struct phy *phy; | ||
53 | struct brcm_sata_phy *phy_priv; | ||
54 | bool ssc_en; | ||
55 | }; | ||
56 | |||
57 | struct brcm_sata_phy { | ||
58 | struct device *dev; | ||
59 | void __iomem *phy_base; | ||
60 | void __iomem *ctrl_base; | ||
61 | enum brcm_sata_phy_version version; | ||
62 | |||
63 | struct brcm_sata_port phys[MAX_PORTS]; | ||
64 | }; | ||
65 | |||
66 | enum sata_phy_regs { | ||
67 | BLOCK0_REG_BANK = 0x000, | ||
68 | BLOCK0_XGXSSTATUS = 0x81, | ||
69 | BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12), | ||
70 | BLOCK0_SPARE = 0x8d, | ||
71 | BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3, | ||
72 | BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1, | ||
73 | |||
74 | PLL_REG_BANK_0 = 0x050, | ||
75 | PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, | ||
76 | |||
77 | PLL1_REG_BANK = 0x060, | ||
78 | PLL1_ACTRL2 = 0x82, | ||
79 | PLL1_ACTRL3 = 0x83, | ||
80 | PLL1_ACTRL4 = 0x84, | ||
81 | |||
82 | OOB_REG_BANK = 0x150, | ||
83 | OOB_CTRL1 = 0x80, | ||
84 | OOB_CTRL1_BURST_MAX_MASK = 0xf, | ||
85 | OOB_CTRL1_BURST_MAX_SHIFT = 12, | ||
86 | OOB_CTRL1_BURST_MIN_MASK = 0xf, | ||
87 | OOB_CTRL1_BURST_MIN_SHIFT = 8, | ||
88 | OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf, | ||
89 | OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4, | ||
90 | OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf, | ||
91 | OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0, | ||
92 | OOB_CTRL2 = 0x81, | ||
93 | OOB_CTRL2_SEL_ENA_SHIFT = 15, | ||
94 | OOB_CTRL2_SEL_ENA_RC_SHIFT = 14, | ||
95 | OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f, | ||
96 | OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8, | ||
97 | OOB_CTRL2_BURST_CNT_MASK = 0x3, | ||
98 | OOB_CTRL2_BURST_CNT_SHIFT = 6, | ||
99 | OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f, | ||
100 | OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0, | ||
101 | |||
102 | TXPMD_REG_BANK = 0x1a0, | ||
103 | TXPMD_CONTROL1 = 0x81, | ||
104 | TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), | ||
105 | TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1), | ||
106 | TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82, | ||
107 | TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83, | ||
108 | TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff, | ||
109 | TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84, | ||
110 | TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, | ||
111 | }; | ||
112 | |||
113 | enum sata_phy_ctrl_regs { | ||
114 | PHY_CTRL_1 = 0x0, | ||
115 | PHY_CTRL_1_RESET = BIT(0), | ||
116 | }; | ||
117 | |||
118 | static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) | ||
119 | { | ||
120 | struct brcm_sata_phy *priv = port->phy_priv; | ||
121 | u32 size = 0; | ||
122 | |||
123 | switch (priv->version) { | ||
124 | case BRCM_SATA_PHY_STB_28NM: | ||
125 | case BRCM_SATA_PHY_IPROC_NS2: | ||
126 | size = SATA_PCB_REG_28NM_SPACE_SIZE; | ||
127 | break; | ||
128 | case BRCM_SATA_PHY_STB_40NM: | ||
129 | size = SATA_PCB_REG_40NM_SPACE_SIZE; | ||
130 | break; | ||
131 | default: | ||
132 | dev_err(priv->dev, "invalid phy version\n"); | ||
133 | break; | ||
134 | }; | ||
135 | |||
136 | return priv->phy_base + (port->portnum * size); | ||
137 | } | ||
138 | |||
139 | static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port) | ||
140 | { | ||
141 | struct brcm_sata_phy *priv = port->phy_priv; | ||
142 | u32 size = 0; | ||
143 | |||
144 | switch (priv->version) { | ||
145 | case BRCM_SATA_PHY_IPROC_NS2: | ||
146 | size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE; | ||
147 | break; | ||
148 | default: | ||
149 | dev_err(priv->dev, "invalid phy version\n"); | ||
150 | break; | ||
151 | }; | ||
152 | |||
153 | return priv->ctrl_base + (port->portnum * size); | ||
154 | } | ||
155 | |||
156 | static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank, | ||
157 | u32 ofs, u32 msk, u32 value) | ||
158 | { | ||
159 | u32 tmp; | ||
160 | |||
161 | writel(bank, pcb_base + SATA_PCB_BANK_OFFSET); | ||
162 | tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs)); | ||
163 | tmp = (tmp & msk) | value; | ||
164 | writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs)); | ||
165 | } | ||
166 | |||
167 | static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs) | ||
168 | { | ||
169 | writel(bank, pcb_base + SATA_PCB_BANK_OFFSET); | ||
170 | return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs)); | ||
171 | } | ||
172 | |||
173 | /* These defaults were characterized by H/W group */ | ||
174 | #define STB_FMIN_VAL_DEFAULT 0x3df | ||
175 | #define STB_FMAX_VAL_DEFAULT 0x3df | ||
176 | #define STB_FMAX_VAL_SSC 0x83 | ||
177 | |||
178 | static int brcm_stb_sata_init(struct brcm_sata_port *port) | ||
179 | { | ||
180 | void __iomem *base = brcm_sata_pcb_base(port); | ||
181 | struct brcm_sata_phy *priv = port->phy_priv; | ||
182 | u32 tmp; | ||
183 | |||
184 | /* override the TX spread spectrum setting */ | ||
185 | tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; | ||
186 | brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); | ||
187 | |||
188 | /* set fixed min freq */ | ||
189 | brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, | ||
190 | ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, | ||
191 | STB_FMIN_VAL_DEFAULT); | ||
192 | |||
193 | /* set fixed max freq depending on SSC config */ | ||
194 | if (port->ssc_en) { | ||
195 | dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum); | ||
196 | tmp = STB_FMAX_VAL_SSC; | ||
197 | } else { | ||
198 | tmp = STB_FMAX_VAL_DEFAULT; | ||
199 | } | ||
200 | |||
201 | brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, | ||
202 | ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | /* NS2 SATA PLL1 defaults were characterized by H/W group */ | ||
208 | #define NS2_PLL1_ACTRL2_MAGIC 0x1df8 | ||
209 | #define NS2_PLL1_ACTRL3_MAGIC 0x2b00 | ||
210 | #define NS2_PLL1_ACTRL4_MAGIC 0x8824 | ||
211 | |||
212 | static int brcm_ns2_sata_init(struct brcm_sata_port *port) | ||
213 | { | ||
214 | int try; | ||
215 | unsigned int val; | ||
216 | void __iomem *base = brcm_sata_pcb_base(port); | ||
217 | void __iomem *ctrl_base = brcm_sata_ctrl_base(port); | ||
218 | struct device *dev = port->phy_priv->dev; | ||
219 | |||
220 | /* Configure OOB control */ | ||
221 | val = 0x0; | ||
222 | val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT); | ||
223 | val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT); | ||
224 | val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT); | ||
225 | val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT); | ||
226 | brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val); | ||
227 | val = 0x0; | ||
228 | val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT); | ||
229 | val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT); | ||
230 | val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT); | ||
231 | brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val); | ||
232 | |||
233 | /* Configure PHY PLL register bank 1 */ | ||
234 | val = NS2_PLL1_ACTRL2_MAGIC; | ||
235 | brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val); | ||
236 | val = NS2_PLL1_ACTRL3_MAGIC; | ||
237 | brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val); | ||
238 | val = NS2_PLL1_ACTRL4_MAGIC; | ||
239 | brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val); | ||
240 | |||
241 | /* Configure PHY BLOCK0 register bank */ | ||
242 | /* Set oob_clk_sel to refclk/2 */ | ||
243 | brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE, | ||
244 | ~BLOCK0_SPARE_OOB_CLK_SEL_MASK, | ||
245 | BLOCK0_SPARE_OOB_CLK_SEL_REFBY2); | ||
246 | |||
247 | /* Strobe PHY reset using PHY control register */ | ||
248 | writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1); | ||
249 | mdelay(1); | ||
250 | writel(0x0, ctrl_base + PHY_CTRL_1); | ||
251 | mdelay(1); | ||
252 | |||
253 | /* Wait for PHY PLL lock by polling pll_lock bit */ | ||
254 | try = 50; | ||
255 | while (try) { | ||
256 | val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, | ||
257 | BLOCK0_XGXSSTATUS); | ||
258 | if (val & BLOCK0_XGXSSTATUS_PLL_LOCK) | ||
259 | break; | ||
260 | msleep(20); | ||
261 | try--; | ||
262 | } | ||
263 | if (!try) { | ||
264 | /* PLL did not lock; give up */ | ||
265 | dev_err(dev, "port%d PLL did not lock\n", port->portnum); | ||
266 | return -ETIMEDOUT; | ||
267 | } | ||
268 | |||
269 | dev_dbg(dev, "port%d initialized\n", port->portnum); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int brcm_sata_phy_init(struct phy *phy) | ||
275 | { | ||
276 | int rc; | ||
277 | struct brcm_sata_port *port = phy_get_drvdata(phy); | ||
278 | |||
279 | switch (port->phy_priv->version) { | ||
280 | case BRCM_SATA_PHY_STB_28NM: | ||
281 | case BRCM_SATA_PHY_STB_40NM: | ||
282 | rc = brcm_stb_sata_init(port); | ||
283 | break; | ||
284 | case BRCM_SATA_PHY_IPROC_NS2: | ||
285 | rc = brcm_ns2_sata_init(port); | ||
286 | break; | ||
287 | default: | ||
288 | rc = -ENODEV; | ||
289 | }; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static const struct phy_ops phy_ops = { | ||
295 | .init = brcm_sata_phy_init, | ||
296 | .owner = THIS_MODULE, | ||
297 | }; | ||
298 | |||
299 | static const struct of_device_id brcm_sata_phy_of_match[] = { | ||
300 | { .compatible = "brcm,bcm7445-sata-phy", | ||
301 | .data = (void *)BRCM_SATA_PHY_STB_28NM }, | ||
302 | { .compatible = "brcm,bcm7425-sata-phy", | ||
303 | .data = (void *)BRCM_SATA_PHY_STB_40NM }, | ||
304 | { .compatible = "brcm,iproc-ns2-sata-phy", | ||
305 | .data = (void *)BRCM_SATA_PHY_IPROC_NS2 }, | ||
306 | {}, | ||
307 | }; | ||
308 | MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); | ||
309 | |||
310 | static int brcm_sata_phy_probe(struct platform_device *pdev) | ||
311 | { | ||
312 | struct device *dev = &pdev->dev; | ||
313 | struct device_node *dn = dev->of_node, *child; | ||
314 | const struct of_device_id *of_id; | ||
315 | struct brcm_sata_phy *priv; | ||
316 | struct resource *res; | ||
317 | struct phy_provider *provider; | ||
318 | int ret, count = 0; | ||
319 | |||
320 | if (of_get_child_count(dn) == 0) | ||
321 | return -ENODEV; | ||
322 | |||
323 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
324 | if (!priv) | ||
325 | return -ENOMEM; | ||
326 | dev_set_drvdata(dev, priv); | ||
327 | priv->dev = dev; | ||
328 | |||
329 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); | ||
330 | priv->phy_base = devm_ioremap_resource(dev, res); | ||
331 | if (IS_ERR(priv->phy_base)) | ||
332 | return PTR_ERR(priv->phy_base); | ||
333 | |||
334 | of_id = of_match_node(brcm_sata_phy_of_match, dn); | ||
335 | if (of_id) | ||
336 | priv->version = (enum brcm_sata_phy_version)of_id->data; | ||
337 | else | ||
338 | priv->version = BRCM_SATA_PHY_STB_28NM; | ||
339 | |||
340 | if (priv->version == BRCM_SATA_PHY_IPROC_NS2) { | ||
341 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
342 | "phy-ctrl"); | ||
343 | priv->ctrl_base = devm_ioremap_resource(dev, res); | ||
344 | if (IS_ERR(priv->ctrl_base)) | ||
345 | return PTR_ERR(priv->ctrl_base); | ||
346 | } | ||
347 | |||
348 | for_each_available_child_of_node(dn, child) { | ||
349 | unsigned int id; | ||
350 | struct brcm_sata_port *port; | ||
351 | |||
352 | if (of_property_read_u32(child, "reg", &id)) { | ||
353 | dev_err(dev, "missing reg property in node %s\n", | ||
354 | child->name); | ||
355 | ret = -EINVAL; | ||
356 | goto put_child; | ||
357 | } | ||
358 | |||
359 | if (id >= MAX_PORTS) { | ||
360 | dev_err(dev, "invalid reg: %u\n", id); | ||
361 | ret = -EINVAL; | ||
362 | goto put_child; | ||
363 | } | ||
364 | if (priv->phys[id].phy) { | ||
365 | dev_err(dev, "already registered port %u\n", id); | ||
366 | ret = -EINVAL; | ||
367 | goto put_child; | ||
368 | } | ||
369 | |||
370 | port = &priv->phys[id]; | ||
371 | port->portnum = id; | ||
372 | port->phy_priv = priv; | ||
373 | port->phy = devm_phy_create(dev, child, &phy_ops); | ||
374 | port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); | ||
375 | if (IS_ERR(port->phy)) { | ||
376 | dev_err(dev, "failed to create PHY\n"); | ||
377 | ret = PTR_ERR(port->phy); | ||
378 | goto put_child; | ||
379 | } | ||
380 | |||
381 | phy_set_drvdata(port->phy, port); | ||
382 | count++; | ||
383 | } | ||
384 | |||
385 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
386 | if (IS_ERR(provider)) { | ||
387 | dev_err(dev, "could not register PHY provider\n"); | ||
388 | return PTR_ERR(provider); | ||
389 | } | ||
390 | |||
391 | dev_info(dev, "registered %d port(s)\n", count); | ||
392 | |||
393 | return 0; | ||
394 | put_child: | ||
395 | of_node_put(child); | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | static struct platform_driver brcm_sata_phy_driver = { | ||
400 | .probe = brcm_sata_phy_probe, | ||
401 | .driver = { | ||
402 | .of_match_table = brcm_sata_phy_of_match, | ||
403 | .name = "brcm-sata-phy", | ||
404 | } | ||
405 | }; | ||
406 | module_platform_driver(brcm_sata_phy_driver); | ||
407 | |||
408 | MODULE_DESCRIPTION("Broadcom SATA PHY driver"); | ||
409 | MODULE_LICENSE("GPL"); | ||
410 | MODULE_AUTHOR("Marc Carino"); | ||
411 | MODULE_AUTHOR("Brian Norris"); | ||
412 | MODULE_ALIAS("platform:phy-brcm-sata"); | ||
diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c deleted file mode 100644 index a23172ff40e3..000000000000 --- a/drivers/phy/phy-brcmstb-sata.c +++ /dev/null | |||
@@ -1,250 +0,0 @@ | |||
1 | /* | ||
2 | * Broadcom SATA3 AHCI Controller PHY Driver | ||
3 | * | ||
4 | * Copyright © 2009-2015 Broadcom Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/phy/phy.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | #define SATA_MDIO_BANK_OFFSET 0x23c | ||
28 | #define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) | ||
29 | |||
30 | #define MAX_PORTS 2 | ||
31 | |||
32 | /* Register offset between PHYs in PCB space */ | ||
33 | #define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000 | ||
34 | |||
35 | /* The older SATA PHY registers duplicated per port registers within the map, | ||
36 | * rather than having a separate map per port. | ||
37 | */ | ||
38 | #define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10 | ||
39 | |||
40 | enum brcm_sata_phy_version { | ||
41 | BRCM_SATA_PHY_28NM, | ||
42 | BRCM_SATA_PHY_40NM, | ||
43 | }; | ||
44 | |||
45 | struct brcm_sata_port { | ||
46 | int portnum; | ||
47 | struct phy *phy; | ||
48 | struct brcm_sata_phy *phy_priv; | ||
49 | bool ssc_en; | ||
50 | }; | ||
51 | |||
52 | struct brcm_sata_phy { | ||
53 | struct device *dev; | ||
54 | void __iomem *phy_base; | ||
55 | enum brcm_sata_phy_version version; | ||
56 | |||
57 | struct brcm_sata_port phys[MAX_PORTS]; | ||
58 | }; | ||
59 | |||
60 | enum sata_mdio_phy_regs { | ||
61 | PLL_REG_BANK_0 = 0x50, | ||
62 | PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, | ||
63 | |||
64 | TXPMD_REG_BANK = 0x1a0, | ||
65 | TXPMD_CONTROL1 = 0x81, | ||
66 | TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), | ||
67 | TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1), | ||
68 | TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82, | ||
69 | TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83, | ||
70 | TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff, | ||
71 | TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84, | ||
72 | TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, | ||
73 | }; | ||
74 | |||
75 | static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) | ||
76 | { | ||
77 | struct brcm_sata_phy *priv = port->phy_priv; | ||
78 | u32 offset = 0; | ||
79 | |||
80 | if (priv->version == BRCM_SATA_PHY_28NM) | ||
81 | offset = SATA_MDIO_REG_28NM_SPACE_SIZE; | ||
82 | else if (priv->version == BRCM_SATA_PHY_40NM) | ||
83 | offset = SATA_MDIO_REG_40NM_SPACE_SIZE; | ||
84 | else | ||
85 | dev_err(priv->dev, "invalid phy version\n"); | ||
86 | |||
87 | return priv->phy_base + (port->portnum * offset); | ||
88 | } | ||
89 | |||
90 | static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, | ||
91 | u32 msk, u32 value) | ||
92 | { | ||
93 | u32 tmp; | ||
94 | |||
95 | writel(bank, addr + SATA_MDIO_BANK_OFFSET); | ||
96 | tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); | ||
97 | tmp = (tmp & msk) | value; | ||
98 | writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); | ||
99 | } | ||
100 | |||
101 | /* These defaults were characterized by H/W group */ | ||
102 | #define FMIN_VAL_DEFAULT 0x3df | ||
103 | #define FMAX_VAL_DEFAULT 0x3df | ||
104 | #define FMAX_VAL_SSC 0x83 | ||
105 | |||
106 | static void brcm_sata_cfg_ssc(struct brcm_sata_port *port) | ||
107 | { | ||
108 | void __iomem *base = brcm_sata_phy_base(port); | ||
109 | struct brcm_sata_phy *priv = port->phy_priv; | ||
110 | u32 tmp; | ||
111 | |||
112 | /* override the TX spread spectrum setting */ | ||
113 | tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; | ||
114 | brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); | ||
115 | |||
116 | /* set fixed min freq */ | ||
117 | brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, | ||
118 | ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, | ||
119 | FMIN_VAL_DEFAULT); | ||
120 | |||
121 | /* set fixed max freq depending on SSC config */ | ||
122 | if (port->ssc_en) { | ||
123 | dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); | ||
124 | tmp = FMAX_VAL_SSC; | ||
125 | } else { | ||
126 | tmp = FMAX_VAL_DEFAULT; | ||
127 | } | ||
128 | |||
129 | brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, | ||
130 | ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); | ||
131 | } | ||
132 | |||
133 | static int brcm_sata_phy_init(struct phy *phy) | ||
134 | { | ||
135 | struct brcm_sata_port *port = phy_get_drvdata(phy); | ||
136 | |||
137 | brcm_sata_cfg_ssc(port); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static const struct phy_ops phy_ops = { | ||
143 | .init = brcm_sata_phy_init, | ||
144 | .owner = THIS_MODULE, | ||
145 | }; | ||
146 | |||
147 | static const struct of_device_id brcm_sata_phy_of_match[] = { | ||
148 | { .compatible = "brcm,bcm7445-sata-phy", | ||
149 | .data = (void *)BRCM_SATA_PHY_28NM }, | ||
150 | { .compatible = "brcm,bcm7425-sata-phy", | ||
151 | .data = (void *)BRCM_SATA_PHY_40NM }, | ||
152 | {}, | ||
153 | }; | ||
154 | MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); | ||
155 | |||
156 | static int brcm_sata_phy_probe(struct platform_device *pdev) | ||
157 | { | ||
158 | struct device *dev = &pdev->dev; | ||
159 | struct device_node *dn = dev->of_node, *child; | ||
160 | const struct of_device_id *of_id; | ||
161 | struct brcm_sata_phy *priv; | ||
162 | struct resource *res; | ||
163 | struct phy_provider *provider; | ||
164 | int ret, count = 0; | ||
165 | |||
166 | if (of_get_child_count(dn) == 0) | ||
167 | return -ENODEV; | ||
168 | |||
169 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
170 | if (!priv) | ||
171 | return -ENOMEM; | ||
172 | dev_set_drvdata(dev, priv); | ||
173 | priv->dev = dev; | ||
174 | |||
175 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); | ||
176 | priv->phy_base = devm_ioremap_resource(dev, res); | ||
177 | if (IS_ERR(priv->phy_base)) | ||
178 | return PTR_ERR(priv->phy_base); | ||
179 | |||
180 | of_id = of_match_node(brcm_sata_phy_of_match, dn); | ||
181 | if (of_id) | ||
182 | priv->version = (enum brcm_sata_phy_version)of_id->data; | ||
183 | else | ||
184 | priv->version = BRCM_SATA_PHY_28NM; | ||
185 | |||
186 | for_each_available_child_of_node(dn, child) { | ||
187 | unsigned int id; | ||
188 | struct brcm_sata_port *port; | ||
189 | |||
190 | if (of_property_read_u32(child, "reg", &id)) { | ||
191 | dev_err(dev, "missing reg property in node %s\n", | ||
192 | child->name); | ||
193 | ret = -EINVAL; | ||
194 | goto put_child; | ||
195 | } | ||
196 | |||
197 | if (id >= MAX_PORTS) { | ||
198 | dev_err(dev, "invalid reg: %u\n", id); | ||
199 | ret = -EINVAL; | ||
200 | goto put_child; | ||
201 | } | ||
202 | if (priv->phys[id].phy) { | ||
203 | dev_err(dev, "already registered port %u\n", id); | ||
204 | ret = -EINVAL; | ||
205 | goto put_child; | ||
206 | } | ||
207 | |||
208 | port = &priv->phys[id]; | ||
209 | port->portnum = id; | ||
210 | port->phy_priv = priv; | ||
211 | port->phy = devm_phy_create(dev, child, &phy_ops); | ||
212 | port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); | ||
213 | if (IS_ERR(port->phy)) { | ||
214 | dev_err(dev, "failed to create PHY\n"); | ||
215 | ret = PTR_ERR(port->phy); | ||
216 | goto put_child; | ||
217 | } | ||
218 | |||
219 | phy_set_drvdata(port->phy, port); | ||
220 | count++; | ||
221 | } | ||
222 | |||
223 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
224 | if (IS_ERR(provider)) { | ||
225 | dev_err(dev, "could not register PHY provider\n"); | ||
226 | return PTR_ERR(provider); | ||
227 | } | ||
228 | |||
229 | dev_info(dev, "registered %d port(s)\n", count); | ||
230 | |||
231 | return 0; | ||
232 | put_child: | ||
233 | of_node_put(child); | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static struct platform_driver brcm_sata_phy_driver = { | ||
238 | .probe = brcm_sata_phy_probe, | ||
239 | .driver = { | ||
240 | .of_match_table = brcm_sata_phy_of_match, | ||
241 | .name = "brcmstb-sata-phy", | ||
242 | } | ||
243 | }; | ||
244 | module_platform_driver(brcm_sata_phy_driver); | ||
245 | |||
246 | MODULE_DESCRIPTION("Broadcom STB SATA PHY driver"); | ||
247 | MODULE_LICENSE("GPL"); | ||
248 | MODULE_AUTHOR("Marc Carino"); | ||
249 | MODULE_AUTHOR("Brian Norris"); | ||
250 | MODULE_ALIAS("platform:phy-brcmstb-sata"); | ||
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 2a54caba93b4..cc093ebfda94 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver | 2 | * Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | 4 | * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd. |
5 | * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> | 5 | * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -13,96 +13,276 @@ | |||
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/mfd/syscon/exynos4-pmu.h> | 15 | #include <linux/mfd/syscon/exynos4-pmu.h> |
16 | #include <linux/mfd/syscon/exynos5-pmu.h> | ||
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
17 | #include <linux/of.h> | 18 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
20 | #include <linux/of_device.h> | ||
19 | #include <linux/phy/phy.h> | 21 | #include <linux/phy/phy.h> |
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | #include <linux/mfd/syscon.h> | 24 | #include <linux/mfd/syscon.h> |
24 | 25 | ||
25 | /* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */ | ||
26 | #define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4) | ||
27 | |||
28 | enum exynos_mipi_phy_id { | 26 | enum exynos_mipi_phy_id { |
27 | EXYNOS_MIPI_PHY_ID_NONE = -1, | ||
29 | EXYNOS_MIPI_PHY_ID_CSIS0, | 28 | EXYNOS_MIPI_PHY_ID_CSIS0, |
30 | EXYNOS_MIPI_PHY_ID_DSIM0, | 29 | EXYNOS_MIPI_PHY_ID_DSIM0, |
31 | EXYNOS_MIPI_PHY_ID_CSIS1, | 30 | EXYNOS_MIPI_PHY_ID_CSIS1, |
32 | EXYNOS_MIPI_PHY_ID_DSIM1, | 31 | EXYNOS_MIPI_PHY_ID_DSIM1, |
32 | EXYNOS_MIPI_PHY_ID_CSIS2, | ||
33 | EXYNOS_MIPI_PHYS_NUM | 33 | EXYNOS_MIPI_PHYS_NUM |
34 | }; | 34 | }; |
35 | 35 | ||
36 | #define is_mipi_dsim_phy_id(id) \ | 36 | enum exynos_mipi_phy_regmap_id { |
37 | ((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) | 37 | EXYNOS_MIPI_REGMAP_PMU, |
38 | EXYNOS_MIPI_REGMAP_DISP, | ||
39 | EXYNOS_MIPI_REGMAP_CAM0, | ||
40 | EXYNOS_MIPI_REGMAP_CAM1, | ||
41 | EXYNOS_MIPI_REGMAPS_NUM | ||
42 | }; | ||
43 | |||
44 | struct mipi_phy_device_desc { | ||
45 | int num_phys; | ||
46 | int num_regmaps; | ||
47 | const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM]; | ||
48 | struct exynos_mipi_phy_desc { | ||
49 | enum exynos_mipi_phy_id coupled_phy_id; | ||
50 | u32 enable_val; | ||
51 | unsigned int enable_reg; | ||
52 | enum exynos_mipi_phy_regmap_id enable_map; | ||
53 | u32 resetn_val; | ||
54 | unsigned int resetn_reg; | ||
55 | enum exynos_mipi_phy_regmap_id resetn_map; | ||
56 | } phys[EXYNOS_MIPI_PHYS_NUM]; | ||
57 | }; | ||
58 | |||
59 | static const struct mipi_phy_device_desc s5pv210_mipi_phy = { | ||
60 | .num_regmaps = 1, | ||
61 | .regmap_names = {"syscon"}, | ||
62 | .num_phys = 4, | ||
63 | .phys = { | ||
64 | { | ||
65 | /* EXYNOS_MIPI_PHY_ID_CSIS0 */ | ||
66 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, | ||
67 | .enable_val = EXYNOS4_MIPI_PHY_ENABLE, | ||
68 | .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0), | ||
69 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
70 | .resetn_val = EXYNOS4_MIPI_PHY_SRESETN, | ||
71 | .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0), | ||
72 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
73 | }, { | ||
74 | /* EXYNOS_MIPI_PHY_ID_DSIM0 */ | ||
75 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, | ||
76 | .enable_val = EXYNOS4_MIPI_PHY_ENABLE, | ||
77 | .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0), | ||
78 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
79 | .resetn_val = EXYNOS4_MIPI_PHY_MRESETN, | ||
80 | .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0), | ||
81 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
82 | }, { | ||
83 | /* EXYNOS_MIPI_PHY_ID_CSIS1 */ | ||
84 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, | ||
85 | .enable_val = EXYNOS4_MIPI_PHY_ENABLE, | ||
86 | .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1), | ||
87 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
88 | .resetn_val = EXYNOS4_MIPI_PHY_SRESETN, | ||
89 | .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1), | ||
90 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
91 | }, { | ||
92 | /* EXYNOS_MIPI_PHY_ID_DSIM1 */ | ||
93 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, | ||
94 | .enable_val = EXYNOS4_MIPI_PHY_ENABLE, | ||
95 | .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1), | ||
96 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
97 | .resetn_val = EXYNOS4_MIPI_PHY_MRESETN, | ||
98 | .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1), | ||
99 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
100 | }, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | static const struct mipi_phy_device_desc exynos5420_mipi_phy = { | ||
105 | .num_regmaps = 1, | ||
106 | .regmap_names = {"syscon"}, | ||
107 | .num_phys = 5, | ||
108 | .phys = { | ||
109 | { | ||
110 | /* EXYNOS_MIPI_PHY_ID_CSIS0 */ | ||
111 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, | ||
112 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
113 | .enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, | ||
114 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
115 | .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, | ||
116 | .resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, | ||
117 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
118 | }, { | ||
119 | /* EXYNOS_MIPI_PHY_ID_DSIM0 */ | ||
120 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, | ||
121 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
122 | .enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, | ||
123 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
124 | .resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, | ||
125 | .resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, | ||
126 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
127 | }, { | ||
128 | /* EXYNOS_MIPI_PHY_ID_CSIS1 */ | ||
129 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, | ||
130 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
131 | .enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, | ||
132 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
133 | .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, | ||
134 | .resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, | ||
135 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
136 | }, { | ||
137 | /* EXYNOS_MIPI_PHY_ID_DSIM1 */ | ||
138 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, | ||
139 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
140 | .enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, | ||
141 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
142 | .resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, | ||
143 | .resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, | ||
144 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
145 | }, { | ||
146 | /* EXYNOS_MIPI_PHY_ID_CSIS2 */ | ||
147 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, | ||
148 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
149 | .enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL, | ||
150 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
151 | .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, | ||
152 | .resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL, | ||
153 | .resetn_map = EXYNOS_MIPI_REGMAP_PMU, | ||
154 | }, | ||
155 | }, | ||
156 | }; | ||
157 | |||
158 | #define EXYNOS5433_SYSREG_DISP_MIPI_PHY 0x100C | ||
159 | #define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON 0x1014 | ||
160 | #define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON 0x1020 | ||
161 | |||
162 | static const struct mipi_phy_device_desc exynos5433_mipi_phy = { | ||
163 | .num_regmaps = 4, | ||
164 | .regmap_names = { | ||
165 | "samsung,pmu-syscon", | ||
166 | "samsung,disp-sysreg", | ||
167 | "samsung,cam0-sysreg", | ||
168 | "samsung,cam1-sysreg" | ||
169 | }, | ||
170 | .num_phys = 5, | ||
171 | .phys = { | ||
172 | { | ||
173 | /* EXYNOS_MIPI_PHY_ID_CSIS0 */ | ||
174 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, | ||
175 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
176 | .enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, | ||
177 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
178 | .resetn_val = BIT(0), | ||
179 | .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, | ||
180 | .resetn_map = EXYNOS_MIPI_REGMAP_CAM0, | ||
181 | }, { | ||
182 | /* EXYNOS_MIPI_PHY_ID_DSIM0 */ | ||
183 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, | ||
184 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
185 | .enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, | ||
186 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
187 | .resetn_val = BIT(0), | ||
188 | .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, | ||
189 | .resetn_map = EXYNOS_MIPI_REGMAP_DISP, | ||
190 | }, { | ||
191 | /* EXYNOS_MIPI_PHY_ID_CSIS1 */ | ||
192 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, | ||
193 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
194 | .enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, | ||
195 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
196 | .resetn_val = BIT(1), | ||
197 | .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, | ||
198 | .resetn_map = EXYNOS_MIPI_REGMAP_CAM0, | ||
199 | }, { | ||
200 | /* EXYNOS_MIPI_PHY_ID_DSIM1 */ | ||
201 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, | ||
202 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
203 | .enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, | ||
204 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
205 | .resetn_val = BIT(1), | ||
206 | .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, | ||
207 | .resetn_map = EXYNOS_MIPI_REGMAP_DISP, | ||
208 | }, { | ||
209 | /* EXYNOS_MIPI_PHY_ID_CSIS2 */ | ||
210 | .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, | ||
211 | .enable_val = EXYNOS5_PHY_ENABLE, | ||
212 | .enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL, | ||
213 | .enable_map = EXYNOS_MIPI_REGMAP_PMU, | ||
214 | .resetn_val = BIT(0), | ||
215 | .resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON, | ||
216 | .resetn_map = EXYNOS_MIPI_REGMAP_CAM1, | ||
217 | }, | ||
218 | }, | ||
219 | }; | ||
38 | 220 | ||
39 | struct exynos_mipi_video_phy { | 221 | struct exynos_mipi_video_phy { |
222 | struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM]; | ||
223 | int num_phys; | ||
40 | struct video_phy_desc { | 224 | struct video_phy_desc { |
41 | struct phy *phy; | 225 | struct phy *phy; |
42 | unsigned int index; | 226 | unsigned int index; |
227 | const struct exynos_mipi_phy_desc *data; | ||
43 | } phys[EXYNOS_MIPI_PHYS_NUM]; | 228 | } phys[EXYNOS_MIPI_PHYS_NUM]; |
44 | spinlock_t slock; | 229 | spinlock_t slock; |
45 | void __iomem *regs; | ||
46 | struct regmap *regmap; | ||
47 | }; | 230 | }; |
48 | 231 | ||
49 | static int __set_phy_state(struct exynos_mipi_video_phy *state, | 232 | static inline int __is_running(const struct exynos_mipi_phy_desc *data, |
50 | enum exynos_mipi_phy_id id, unsigned int on) | 233 | struct exynos_mipi_video_phy *state) |
51 | { | 234 | { |
52 | const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2); | 235 | u32 val; |
53 | void __iomem *addr; | ||
54 | u32 val, reset; | ||
55 | 236 | ||
56 | if (is_mipi_dsim_phy_id(id)) | 237 | regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); |
57 | reset = EXYNOS4_MIPI_PHY_MRESETN; | 238 | return val & data->resetn_val; |
58 | else | 239 | } |
59 | reset = EXYNOS4_MIPI_PHY_SRESETN; | 240 | |
241 | static int __set_phy_state(const struct exynos_mipi_phy_desc *data, | ||
242 | struct exynos_mipi_video_phy *state, unsigned int on) | ||
243 | { | ||
244 | u32 val; | ||
60 | 245 | ||
61 | spin_lock(&state->slock); | 246 | spin_lock(&state->slock); |
62 | 247 | ||
63 | if (!IS_ERR(state->regmap)) { | 248 | /* disable in PMU sysreg */ |
64 | regmap_read(state->regmap, offset, &val); | 249 | if (!on && data->coupled_phy_id >= 0 && |
65 | if (on) | 250 | !__is_running(state->phys[data->coupled_phy_id].data, state)) { |
66 | val |= reset; | 251 | regmap_read(state->regmaps[data->enable_map], data->enable_reg, |
67 | else | 252 | &val); |
68 | val &= ~reset; | 253 | val &= ~data->enable_val; |
69 | regmap_write(state->regmap, offset, val); | 254 | regmap_write(state->regmaps[data->enable_map], data->enable_reg, |
70 | if (on) | 255 | val); |
71 | val |= EXYNOS4_MIPI_PHY_ENABLE; | 256 | } |
72 | else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) | 257 | |
73 | val &= ~EXYNOS4_MIPI_PHY_ENABLE; | 258 | /* PHY reset */ |
74 | regmap_write(state->regmap, offset, val); | 259 | regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); |
75 | } else { | 260 | val = on ? (val | data->resetn_val) : (val & ~data->resetn_val); |
76 | addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2); | 261 | regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val); |
77 | 262 | ||
78 | val = readl(addr); | 263 | /* enable in PMU sysreg */ |
79 | if (on) | 264 | if (on) { |
80 | val |= reset; | 265 | regmap_read(state->regmaps[data->enable_map], data->enable_reg, |
81 | else | 266 | &val); |
82 | val &= ~reset; | 267 | val |= data->enable_val; |
83 | writel(val, addr); | 268 | regmap_write(state->regmaps[data->enable_map], data->enable_reg, |
84 | /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */ | 269 | val); |
85 | if (on) | ||
86 | val |= EXYNOS4_MIPI_PHY_ENABLE; | ||
87 | else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) | ||
88 | val &= ~EXYNOS4_MIPI_PHY_ENABLE; | ||
89 | |||
90 | writel(val, addr); | ||
91 | } | 270 | } |
92 | 271 | ||
93 | spin_unlock(&state->slock); | 272 | spin_unlock(&state->slock); |
273 | |||
94 | return 0; | 274 | return 0; |
95 | } | 275 | } |
96 | 276 | ||
97 | #define to_mipi_video_phy(desc) \ | 277 | #define to_mipi_video_phy(desc) \ |
98 | container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]); | 278 | container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]) |
99 | 279 | ||
100 | static int exynos_mipi_video_phy_power_on(struct phy *phy) | 280 | static int exynos_mipi_video_phy_power_on(struct phy *phy) |
101 | { | 281 | { |
102 | struct video_phy_desc *phy_desc = phy_get_drvdata(phy); | 282 | struct video_phy_desc *phy_desc = phy_get_drvdata(phy); |
103 | struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); | 283 | struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); |
104 | 284 | ||
105 | return __set_phy_state(state, phy_desc->index, 1); | 285 | return __set_phy_state(phy_desc->data, state, 1); |
106 | } | 286 | } |
107 | 287 | ||
108 | static int exynos_mipi_video_phy_power_off(struct phy *phy) | 288 | static int exynos_mipi_video_phy_power_off(struct phy *phy) |
@@ -110,7 +290,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy) | |||
110 | struct video_phy_desc *phy_desc = phy_get_drvdata(phy); | 290 | struct video_phy_desc *phy_desc = phy_get_drvdata(phy); |
111 | struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); | 291 | struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); |
112 | 292 | ||
113 | return __set_phy_state(state, phy_desc->index, 0); | 293 | return __set_phy_state(phy_desc->data, state, 0); |
114 | } | 294 | } |
115 | 295 | ||
116 | static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, | 296 | static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, |
@@ -118,7 +298,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, | |||
118 | { | 298 | { |
119 | struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); | 299 | struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); |
120 | 300 | ||
121 | if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM)) | 301 | if (WARN_ON(args->args[0] >= state->num_phys)) |
122 | return ERR_PTR(-ENODEV); | 302 | return ERR_PTR(-ENODEV); |
123 | 303 | ||
124 | return state->phys[args->args[0]].phy; | 304 | return state->phys[args->args[0]].phy; |
@@ -132,32 +312,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = { | |||
132 | 312 | ||
133 | static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | 313 | static int exynos_mipi_video_phy_probe(struct platform_device *pdev) |
134 | { | 314 | { |
315 | const struct mipi_phy_device_desc *phy_dev; | ||
135 | struct exynos_mipi_video_phy *state; | 316 | struct exynos_mipi_video_phy *state; |
136 | struct device *dev = &pdev->dev; | 317 | struct device *dev = &pdev->dev; |
318 | struct device_node *np = dev->of_node; | ||
137 | struct phy_provider *phy_provider; | 319 | struct phy_provider *phy_provider; |
138 | unsigned int i; | 320 | unsigned int i; |
139 | 321 | ||
322 | phy_dev = of_device_get_match_data(dev); | ||
323 | if (!phy_dev) | ||
324 | return -ENODEV; | ||
325 | |||
140 | state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); | 326 | state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); |
141 | if (!state) | 327 | if (!state) |
142 | return -ENOMEM; | 328 | return -ENOMEM; |
143 | 329 | ||
144 | state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); | 330 | for (i = 0; i < phy_dev->num_regmaps; i++) { |
145 | if (IS_ERR(state->regmap)) { | 331 | state->regmaps[i] = syscon_regmap_lookup_by_phandle(np, |
146 | struct resource *res; | 332 | phy_dev->regmap_names[i]); |
147 | 333 | if (IS_ERR(state->regmaps[i])) | |
148 | dev_info(dev, "regmap lookup failed: %ld\n", | 334 | return PTR_ERR(state->regmaps[i]); |
149 | PTR_ERR(state->regmap)); | ||
150 | |||
151 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
152 | state->regs = devm_ioremap_resource(dev, res); | ||
153 | if (IS_ERR(state->regs)) | ||
154 | return PTR_ERR(state->regs); | ||
155 | } | 335 | } |
336 | state->num_phys = phy_dev->num_phys; | ||
337 | spin_lock_init(&state->slock); | ||
156 | 338 | ||
157 | dev_set_drvdata(dev, state); | 339 | dev_set_drvdata(dev, state); |
158 | spin_lock_init(&state->slock); | ||
159 | 340 | ||
160 | for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { | 341 | for (i = 0; i < state->num_phys; i++) { |
161 | struct phy *phy = devm_phy_create(dev, NULL, | 342 | struct phy *phy = devm_phy_create(dev, NULL, |
162 | &exynos_mipi_video_phy_ops); | 343 | &exynos_mipi_video_phy_ops); |
163 | if (IS_ERR(phy)) { | 344 | if (IS_ERR(phy)) { |
@@ -167,6 +348,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
167 | 348 | ||
168 | state->phys[i].phy = phy; | 349 | state->phys[i].phy = phy; |
169 | state->phys[i].index = i; | 350 | state->phys[i].index = i; |
351 | state->phys[i].data = &phy_dev->phys[i]; | ||
170 | phy_set_drvdata(phy, &state->phys[i]); | 352 | phy_set_drvdata(phy, &state->phys[i]); |
171 | } | 353 | } |
172 | 354 | ||
@@ -177,8 +359,17 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) | |||
177 | } | 359 | } |
178 | 360 | ||
179 | static const struct of_device_id exynos_mipi_video_phy_of_match[] = { | 361 | static const struct of_device_id exynos_mipi_video_phy_of_match[] = { |
180 | { .compatible = "samsung,s5pv210-mipi-video-phy" }, | 362 | { |
181 | { }, | 363 | .compatible = "samsung,s5pv210-mipi-video-phy", |
364 | .data = &s5pv210_mipi_phy, | ||
365 | }, { | ||
366 | .compatible = "samsung,exynos5420-mipi-video-phy", | ||
367 | .data = &exynos5420_mipi_phy, | ||
368 | }, { | ||
369 | .compatible = "samsung,exynos5433-mipi-video-phy", | ||
370 | .data = &exynos5433_mipi_phy, | ||
371 | }, | ||
372 | { /* sentinel */ }, | ||
182 | }; | 373 | }; |
183 | MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match); | 374 | MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match); |
184 | 375 | ||
diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c index c0e7b4b0cf5c..4d85e730ccab 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/phy-mt65xx-usb3.c | |||
@@ -134,6 +134,11 @@ | |||
134 | #define U3P_SR_COEF_DIVISOR 1000 | 134 | #define U3P_SR_COEF_DIVISOR 1000 |
135 | #define U3P_FM_DET_CYCLE_CNT 1024 | 135 | #define U3P_FM_DET_CYCLE_CNT 1024 |
136 | 136 | ||
137 | struct mt65xx_phy_pdata { | ||
138 | /* avoid RX sensitivity level degradation only for mt8173 */ | ||
139 | bool avoid_rx_sen_degradation; | ||
140 | }; | ||
141 | |||
137 | struct mt65xx_phy_instance { | 142 | struct mt65xx_phy_instance { |
138 | struct phy *phy; | 143 | struct phy *phy; |
139 | void __iomem *port_base; | 144 | void __iomem *port_base; |
@@ -145,6 +150,7 @@ struct mt65xx_u3phy { | |||
145 | struct device *dev; | 150 | struct device *dev; |
146 | void __iomem *sif_base; /* include sif2, but exclude port's */ | 151 | void __iomem *sif_base; /* include sif2, but exclude port's */ |
147 | struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */ | 152 | struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */ |
153 | const struct mt65xx_phy_pdata *pdata; | ||
148 | struct mt65xx_phy_instance **phys; | 154 | struct mt65xx_phy_instance **phys; |
149 | int nphys; | 155 | int nphys; |
150 | }; | 156 | }; |
@@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, | |||
241 | tmp = readl(port_base + U3P_U2PHYACR4); | 247 | tmp = readl(port_base + U3P_U2PHYACR4); |
242 | tmp &= ~P2C_U2_GPIO_CTR_MSK; | 248 | tmp &= ~P2C_U2_GPIO_CTR_MSK; |
243 | writel(tmp, port_base + U3P_U2PHYACR4); | 249 | writel(tmp, port_base + U3P_U2PHYACR4); |
250 | } | ||
244 | 251 | ||
245 | tmp = readl(port_base + U3P_USBPHYACR2); | 252 | if (u3phy->pdata->avoid_rx_sen_degradation) { |
246 | tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; | 253 | if (!index) { |
247 | writel(tmp, port_base + U3P_USBPHYACR2); | 254 | tmp = readl(port_base + U3P_USBPHYACR2); |
248 | 255 | tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; | |
249 | tmp = readl(port_base + U3D_U2PHYDCR0); | 256 | writel(tmp, port_base + U3P_USBPHYACR2); |
250 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; | 257 | |
251 | writel(tmp, port_base + U3D_U2PHYDCR0); | 258 | tmp = readl(port_base + U3D_U2PHYDCR0); |
252 | } else { | 259 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; |
253 | tmp = readl(port_base + U3D_U2PHYDCR0); | 260 | writel(tmp, port_base + U3D_U2PHYDCR0); |
254 | tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; | 261 | } else { |
255 | writel(tmp, port_base + U3D_U2PHYDCR0); | 262 | tmp = readl(port_base + U3D_U2PHYDCR0); |
256 | 263 | tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; | |
257 | tmp = readl(port_base + U3P_U2PHYDTM0); | 264 | writel(tmp, port_base + U3D_U2PHYDCR0); |
258 | tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM; | 265 | |
259 | writel(tmp, port_base + U3P_U2PHYDTM0); | 266 | tmp = readl(port_base + U3P_U2PHYDTM0); |
267 | tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM; | ||
268 | writel(tmp, port_base + U3P_U2PHYDTM0); | ||
269 | } | ||
260 | } | 270 | } |
261 | 271 | ||
262 | tmp = readl(port_base + U3P_USBPHYACR6); | 272 | tmp = readl(port_base + U3P_USBPHYACR6); |
@@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, | |||
318 | tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD; | 328 | tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD; |
319 | writel(tmp, u3phy->sif_base + U3P_XTALCTL3); | 329 | writel(tmp, u3phy->sif_base + U3P_XTALCTL3); |
320 | 330 | ||
321 | /* [mt8173]switch 100uA current to SSUSB */ | 331 | /* switch 100uA current to SSUSB */ |
322 | tmp = readl(port_base + U3P_USBPHYACR5); | 332 | tmp = readl(port_base + U3P_USBPHYACR5); |
323 | tmp |= PA5_RG_U2_HS_100U_U3_EN; | 333 | tmp |= PA5_RG_U2_HS_100U_U3_EN; |
324 | writel(tmp, port_base + U3P_USBPHYACR5); | 334 | writel(tmp, port_base + U3P_USBPHYACR5); |
@@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, | |||
335 | tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4); | 345 | tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4); |
336 | writel(tmp, port_base + U3P_USBPHYACR5); | 346 | writel(tmp, port_base + U3P_USBPHYACR5); |
337 | 347 | ||
338 | if (index) { | 348 | if (u3phy->pdata->avoid_rx_sen_degradation && index) { |
339 | tmp = readl(port_base + U3D_U2PHYDCR0); | 349 | tmp = readl(port_base + U3D_U2PHYDCR0); |
340 | tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; | 350 | tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; |
341 | writel(tmp, port_base + U3D_U2PHYDCR0); | 351 | writel(tmp, port_base + U3D_U2PHYDCR0); |
@@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, | |||
386 | tmp = readl(port_base + U3P_U3_PHYA_REG0); | 396 | tmp = readl(port_base + U3P_U3_PHYA_REG0); |
387 | tmp &= ~P3A_RG_U3_VUSB10_ON; | 397 | tmp &= ~P3A_RG_U3_VUSB10_ON; |
388 | writel(tmp, port_base + U3P_U3_PHYA_REG0); | 398 | writel(tmp, port_base + U3P_U3_PHYA_REG0); |
389 | } else { | 399 | } |
400 | |||
401 | if (u3phy->pdata->avoid_rx_sen_degradation && index) { | ||
390 | tmp = readl(port_base + U3D_U2PHYDCR0); | 402 | tmp = readl(port_base + U3D_U2PHYDCR0); |
391 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; | 403 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; |
392 | writel(tmp, port_base + U3D_U2PHYDCR0); | 404 | writel(tmp, port_base + U3D_U2PHYDCR0); |
@@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy, | |||
402 | u32 index = instance->index; | 414 | u32 index = instance->index; |
403 | u32 tmp; | 415 | u32 tmp; |
404 | 416 | ||
405 | if (index) { | 417 | if (u3phy->pdata->avoid_rx_sen_degradation && index) { |
406 | tmp = readl(port_base + U3D_U2PHYDCR0); | 418 | tmp = readl(port_base + U3D_U2PHYDCR0); |
407 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; | 419 | tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; |
408 | writel(tmp, port_base + U3D_U2PHYDCR0); | 420 | writel(tmp, port_base + U3D_U2PHYDCR0); |
@@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = { | |||
502 | .owner = THIS_MODULE, | 514 | .owner = THIS_MODULE, |
503 | }; | 515 | }; |
504 | 516 | ||
517 | static const struct mt65xx_phy_pdata mt2701_pdata = { | ||
518 | .avoid_rx_sen_degradation = false, | ||
519 | }; | ||
520 | |||
521 | static const struct mt65xx_phy_pdata mt8173_pdata = { | ||
522 | .avoid_rx_sen_degradation = true, | ||
523 | }; | ||
524 | |||
525 | static const struct of_device_id mt65xx_u3phy_id_table[] = { | ||
526 | { .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata }, | ||
527 | { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, | ||
528 | { }, | ||
529 | }; | ||
530 | MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table); | ||
531 | |||
505 | static int mt65xx_u3phy_probe(struct platform_device *pdev) | 532 | static int mt65xx_u3phy_probe(struct platform_device *pdev) |
506 | { | 533 | { |
534 | const struct of_device_id *match; | ||
507 | struct device *dev = &pdev->dev; | 535 | struct device *dev = &pdev->dev; |
508 | struct device_node *np = dev->of_node; | 536 | struct device_node *np = dev->of_node; |
509 | struct device_node *child_np; | 537 | struct device_node *child_np; |
@@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) | |||
513 | struct resource res; | 541 | struct resource res; |
514 | int port, retval; | 542 | int port, retval; |
515 | 543 | ||
544 | match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node); | ||
545 | if (!match) | ||
546 | return -EINVAL; | ||
547 | |||
516 | u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); | 548 | u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); |
517 | if (!u3phy) | 549 | if (!u3phy) |
518 | return -ENOMEM; | 550 | return -ENOMEM; |
519 | 551 | ||
552 | u3phy->pdata = match->data; | ||
520 | u3phy->nphys = of_get_child_count(np); | 553 | u3phy->nphys = of_get_child_count(np); |
521 | u3phy->phys = devm_kcalloc(dev, u3phy->nphys, | 554 | u3phy->phys = devm_kcalloc(dev, u3phy->nphys, |
522 | sizeof(*u3phy->phys), GFP_KERNEL); | 555 | sizeof(*u3phy->phys), GFP_KERNEL); |
@@ -587,12 +620,6 @@ put_child: | |||
587 | return retval; | 620 | return retval; |
588 | } | 621 | } |
589 | 622 | ||
590 | static const struct of_device_id mt65xx_u3phy_id_table[] = { | ||
591 | { .compatible = "mediatek,mt8173-u3phy", }, | ||
592 | { }, | ||
593 | }; | ||
594 | MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table); | ||
595 | |||
596 | static struct platform_driver mt65xx_u3phy_driver = { | 623 | static struct platform_driver mt65xx_u3phy_driver = { |
597 | .probe = mt65xx_u3phy_probe, | 624 | .probe = mt65xx_u3phy_probe, |
598 | .driver = { | 625 | .driver = { |
diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index c7a05996d5c1..97d4dd6ea924 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c | |||
@@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = { | |||
195 | { .compatible = "renesas,usb-phy-r8a7790" }, | 195 | { .compatible = "renesas,usb-phy-r8a7790" }, |
196 | { .compatible = "renesas,usb-phy-r8a7791" }, | 196 | { .compatible = "renesas,usb-phy-r8a7791" }, |
197 | { .compatible = "renesas,usb-phy-r8a7794" }, | 197 | { .compatible = "renesas,usb-phy-r8a7794" }, |
198 | { .compatible = "renesas,rcar-gen2-usb-phy" }, | ||
198 | { } | 199 | { } |
199 | }; | 200 | }; |
200 | MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); | 201 | MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); |
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index bc4f7dd821aa..76bb88f0700a 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/extcon.h> | ||
15 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
16 | #include <linux/io.h> | 17 | #include <linux/io.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
@@ -19,6 +20,7 @@ | |||
19 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
20 | #include <linux/phy/phy.h> | 21 | #include <linux/phy/phy.h> |
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/regulator/consumer.h> | ||
22 | 24 | ||
23 | /******* USB2.0 Host registers (original offset is +0x200) *******/ | 25 | /******* USB2.0 Host registers (original offset is +0x200) *******/ |
24 | #define USB2_INT_ENABLE 0x000 | 26 | #define USB2_INT_ENABLE 0x000 |
@@ -74,20 +76,17 @@ | |||
74 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ | 76 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ |
75 | #define USB2_ADPCTRL_DRVVBUS BIT(4) | 77 | #define USB2_ADPCTRL_DRVVBUS BIT(4) |
76 | 78 | ||
77 | struct rcar_gen3_data { | ||
78 | void __iomem *base; | ||
79 | struct clk *clk; | ||
80 | }; | ||
81 | |||
82 | struct rcar_gen3_chan { | 79 | struct rcar_gen3_chan { |
83 | struct rcar_gen3_data usb2; | 80 | void __iomem *base; |
81 | struct extcon_dev *extcon; | ||
84 | struct phy *phy; | 82 | struct phy *phy; |
83 | struct regulator *vbus; | ||
85 | bool has_otg; | 84 | bool has_otg; |
86 | }; | 85 | }; |
87 | 86 | ||
88 | static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) | 87 | static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) |
89 | { | 88 | { |
90 | void __iomem *usb2_base = ch->usb2.base; | 89 | void __iomem *usb2_base = ch->base; |
91 | u32 val = readl(usb2_base + USB2_COMMCTRL); | 90 | u32 val = readl(usb2_base + USB2_COMMCTRL); |
92 | 91 | ||
93 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); | 92 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); |
@@ -100,7 +99,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) | |||
100 | 99 | ||
101 | static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) | 100 | static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) |
102 | { | 101 | { |
103 | void __iomem *usb2_base = ch->usb2.base; | 102 | void __iomem *usb2_base = ch->base; |
104 | u32 val = readl(usb2_base + USB2_LINECTRL1); | 103 | u32 val = readl(usb2_base + USB2_LINECTRL1); |
105 | 104 | ||
106 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); | 105 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); |
@@ -114,7 +113,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) | |||
114 | 113 | ||
115 | static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) | 114 | static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) |
116 | { | 115 | { |
117 | void __iomem *usb2_base = ch->usb2.base; | 116 | void __iomem *usb2_base = ch->base; |
118 | u32 val = readl(usb2_base + USB2_ADPCTRL); | 117 | u32 val = readl(usb2_base + USB2_ADPCTRL); |
119 | 118 | ||
120 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); | 119 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); |
@@ -130,6 +129,9 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) | |||
130 | rcar_gen3_set_linectrl(ch, 1, 1); | 129 | rcar_gen3_set_linectrl(ch, 1, 1); |
131 | rcar_gen3_set_host_mode(ch, 1); | 130 | rcar_gen3_set_host_mode(ch, 1); |
132 | rcar_gen3_enable_vbus_ctrl(ch, 1); | 131 | rcar_gen3_enable_vbus_ctrl(ch, 1); |
132 | |||
133 | extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); | ||
134 | extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); | ||
133 | } | 135 | } |
134 | 136 | ||
135 | static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) | 137 | static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) |
@@ -137,17 +139,20 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) | |||
137 | rcar_gen3_set_linectrl(ch, 0, 1); | 139 | rcar_gen3_set_linectrl(ch, 0, 1); |
138 | rcar_gen3_set_host_mode(ch, 0); | 140 | rcar_gen3_set_host_mode(ch, 0); |
139 | rcar_gen3_enable_vbus_ctrl(ch, 0); | 141 | rcar_gen3_enable_vbus_ctrl(ch, 0); |
142 | |||
143 | extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); | ||
144 | extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); | ||
140 | } | 145 | } |
141 | 146 | ||
142 | static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) | 147 | static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) |
143 | { | 148 | { |
144 | return !!(readl(ch->usb2.base + USB2_ADPCTRL) & | 149 | return !!(readl(ch->base + USB2_ADPCTRL) & |
145 | USB2_ADPCTRL_OTGSESSVLD); | 150 | USB2_ADPCTRL_OTGSESSVLD); |
146 | } | 151 | } |
147 | 152 | ||
148 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) | 153 | static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) |
149 | { | 154 | { |
150 | return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); | 155 | return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); |
151 | } | 156 | } |
152 | 157 | ||
153 | static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) | 158 | static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) |
@@ -166,7 +171,7 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) | |||
166 | 171 | ||
167 | static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) | 172 | static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) |
168 | { | 173 | { |
169 | void __iomem *usb2_base = ch->usb2.base; | 174 | void __iomem *usb2_base = ch->base; |
170 | u32 val; | 175 | u32 val; |
171 | 176 | ||
172 | val = readl(usb2_base + USB2_VBCTRL); | 177 | val = readl(usb2_base + USB2_VBCTRL); |
@@ -187,7 +192,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) | |||
187 | static int rcar_gen3_phy_usb2_init(struct phy *p) | 192 | static int rcar_gen3_phy_usb2_init(struct phy *p) |
188 | { | 193 | { |
189 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 194 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
190 | void __iomem *usb2_base = channel->usb2.base; | 195 | void __iomem *usb2_base = channel->base; |
191 | 196 | ||
192 | /* Initialize USB2 part */ | 197 | /* Initialize USB2 part */ |
193 | writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); | 198 | writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); |
@@ -205,7 +210,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) | |||
205 | { | 210 | { |
206 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 211 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
207 | 212 | ||
208 | writel(0, channel->usb2.base + USB2_INT_ENABLE); | 213 | writel(0, channel->base + USB2_INT_ENABLE); |
209 | 214 | ||
210 | return 0; | 215 | return 0; |
211 | } | 216 | } |
@@ -213,8 +218,15 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) | |||
213 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) | 218 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) |
214 | { | 219 | { |
215 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 220 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); |
216 | void __iomem *usb2_base = channel->usb2.base; | 221 | void __iomem *usb2_base = channel->base; |
217 | u32 val; | 222 | u32 val; |
223 | int ret; | ||
224 | |||
225 | if (channel->vbus) { | ||
226 | ret = regulator_enable(channel->vbus); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | } | ||
218 | 230 | ||
219 | val = readl(usb2_base + USB2_USBCTR); | 231 | val = readl(usb2_base + USB2_USBCTR); |
220 | val |= USB2_USBCTR_PLL_RST; | 232 | val |= USB2_USBCTR_PLL_RST; |
@@ -225,17 +237,29 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) | |||
225 | return 0; | 237 | return 0; |
226 | } | 238 | } |
227 | 239 | ||
240 | static int rcar_gen3_phy_usb2_power_off(struct phy *p) | ||
241 | { | ||
242 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | ||
243 | int ret = 0; | ||
244 | |||
245 | if (channel->vbus) | ||
246 | ret = regulator_disable(channel->vbus); | ||
247 | |||
248 | return ret; | ||
249 | } | ||
250 | |||
228 | static struct phy_ops rcar_gen3_phy_usb2_ops = { | 251 | static struct phy_ops rcar_gen3_phy_usb2_ops = { |
229 | .init = rcar_gen3_phy_usb2_init, | 252 | .init = rcar_gen3_phy_usb2_init, |
230 | .exit = rcar_gen3_phy_usb2_exit, | 253 | .exit = rcar_gen3_phy_usb2_exit, |
231 | .power_on = rcar_gen3_phy_usb2_power_on, | 254 | .power_on = rcar_gen3_phy_usb2_power_on, |
255 | .power_off = rcar_gen3_phy_usb2_power_off, | ||
232 | .owner = THIS_MODULE, | 256 | .owner = THIS_MODULE, |
233 | }; | 257 | }; |
234 | 258 | ||
235 | static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | 259 | static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) |
236 | { | 260 | { |
237 | struct rcar_gen3_chan *ch = _ch; | 261 | struct rcar_gen3_chan *ch = _ch; |
238 | void __iomem *usb2_base = ch->usb2.base; | 262 | void __iomem *usb2_base = ch->base; |
239 | u32 status = readl(usb2_base + USB2_OBINTSTA); | 263 | u32 status = readl(usb2_base + USB2_OBINTSTA); |
240 | irqreturn_t ret = IRQ_NONE; | 264 | irqreturn_t ret = IRQ_NONE; |
241 | 265 | ||
@@ -251,10 +275,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | |||
251 | 275 | ||
252 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { | 276 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { |
253 | { .compatible = "renesas,usb2-phy-r8a7795" }, | 277 | { .compatible = "renesas,usb2-phy-r8a7795" }, |
278 | { .compatible = "renesas,rcar-gen3-usb2-phy" }, | ||
254 | { } | 279 | { } |
255 | }; | 280 | }; |
256 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); | 281 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); |
257 | 282 | ||
283 | static const unsigned int rcar_gen3_phy_cable[] = { | ||
284 | EXTCON_USB, | ||
285 | EXTCON_USB_HOST, | ||
286 | EXTCON_NONE, | ||
287 | }; | ||
288 | |||
258 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | 289 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) |
259 | { | 290 | { |
260 | struct device *dev = &pdev->dev; | 291 | struct device *dev = &pdev->dev; |
@@ -273,18 +304,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
273 | return -ENOMEM; | 304 | return -ENOMEM; |
274 | 305 | ||
275 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 306 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
276 | channel->usb2.base = devm_ioremap_resource(dev, res); | 307 | channel->base = devm_ioremap_resource(dev, res); |
277 | if (IS_ERR(channel->usb2.base)) | 308 | if (IS_ERR(channel->base)) |
278 | return PTR_ERR(channel->usb2.base); | 309 | return PTR_ERR(channel->base); |
279 | 310 | ||
280 | /* call request_irq for OTG */ | 311 | /* call request_irq for OTG */ |
281 | irq = platform_get_irq(pdev, 0); | 312 | irq = platform_get_irq(pdev, 0); |
282 | if (irq >= 0) { | 313 | if (irq >= 0) { |
314 | int ret; | ||
315 | |||
283 | irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, | 316 | irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, |
284 | IRQF_SHARED, dev_name(dev), channel); | 317 | IRQF_SHARED, dev_name(dev), channel); |
285 | if (irq < 0) | 318 | if (irq < 0) |
286 | dev_err(dev, "No irq handler (%d)\n", irq); | 319 | dev_err(dev, "No irq handler (%d)\n", irq); |
287 | channel->has_otg = true; | 320 | channel->has_otg = true; |
321 | channel->extcon = devm_extcon_dev_allocate(dev, | ||
322 | rcar_gen3_phy_cable); | ||
323 | if (IS_ERR(channel->extcon)) | ||
324 | return PTR_ERR(channel->extcon); | ||
325 | |||
326 | ret = devm_extcon_dev_register(dev, channel->extcon); | ||
327 | if (ret < 0) { | ||
328 | dev_err(dev, "Failed to register extcon\n"); | ||
329 | return ret; | ||
330 | } | ||
288 | } | 331 | } |
289 | 332 | ||
290 | /* devm_phy_create() will call pm_runtime_enable(dev); */ | 333 | /* devm_phy_create() will call pm_runtime_enable(dev); */ |
@@ -294,6 +337,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
294 | return PTR_ERR(channel->phy); | 337 | return PTR_ERR(channel->phy); |
295 | } | 338 | } |
296 | 339 | ||
340 | channel->vbus = devm_regulator_get_optional(dev, "vbus"); | ||
341 | if (IS_ERR(channel->vbus)) { | ||
342 | if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) | ||
343 | return PTR_ERR(channel->vbus); | ||
344 | channel->vbus = NULL; | ||
345 | } | ||
346 | |||
297 | phy_set_drvdata(channel->phy, channel); | 347 | phy_set_drvdata(channel->phy, channel); |
298 | 348 | ||
299 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | 349 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index f62d899063a3..d60b149cff0f 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c | |||
@@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, | |||
216 | init.parent_names = &clk_name; | 216 | init.parent_names = &clk_name; |
217 | init.num_parents = 1; | 217 | init.num_parents = 1; |
218 | } else { | 218 | } else { |
219 | init.flags = CLK_IS_ROOT; | 219 | init.flags = 0; |
220 | init.parent_names = NULL; | 220 | init.parent_names = NULL; |
221 | init.num_parents = 0; | 221 | init.num_parents = 0; |
222 | } | 222 | } |