mirror of https://gitee.com/openkylin/linux.git
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> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJXJNglAAoJEA5ceFyATYLZIDAP/Ror/l8L3JGyFS/EK/Z5GCGA cPAyMmh9RXUhFZyPdW/IAv5qlexYIP7/iv73ggeDQucCLriPo9P02Ec85FKk1X5W ePM35SWYfnc1698fZoNGacqgB3MFavwvaBgCGolM0vBPTglJlPQvng5Z5Sy8ajgc uZZMa/QRvmXpRiD7yUGBRo+l0MdYBiR8GtDEKvUj3I9uxq1CfAxDr1Cwrc9HhyMz 5L77ddFwdlgU993cQUwZiUw5T01lFS/NQVVc3lGXs2xDKXlt2u39yMPpQB5zW7BB 1YbCkbLCI5bzu3UeThOLJCIaHb70ZKes7GO5rbayoFeJ6a+voZpSiyM3lz6oiUqg B4ovB4gFwV/Zt+0rAJJgk+Z7Qx5E0GANd2iCnMrMwnRLAR+bR3m6ODIyDMlGKq5x DpdowbqZg7OQ/93/pQDFmkm1JrmuU1Mpy0c2z76TVCyOKudT49OSdNmZ1WA7QIsn RUqKNMBkxsNlkeWvIAbKORvG0MSUCtfFEAgFo6LwQ+qJpW1aF6BPmGKc5xY9VWiu HF83cFY5dHiMYUXHEaTenx3K1L+kYaOAJqfRmtyXBbDlCFHNR1MRJhpn1OmgON44 u1rVBJJGlhYaKixa0v+XhmVLXcqRDIFjfAp20kgfqtIs4bfh/lBubYZiPcigR/KA 4ztCeI2/8rpk+iJsmWO+ =uHWi -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
e6c037bfca
|
@ -0,0 +1,21 @@
|
|||
Driver for Broadcom Northstar USB 2.0 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: brcm,ns-usb2-phy
|
||||
- reg: iomem address range of DMU (Device Management Unit)
|
||||
- reg-names: "dmu", the only needed & supported reg right now
|
||||
- clocks: USB PHY reference clock
|
||||
- clock-names: "phy-ref-clk", the only needed & supported clock right now
|
||||
|
||||
To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it
|
||||
requires passing phandle to the USB PHY reference clock.
|
||||
|
||||
Example:
|
||||
usb2-phy {
|
||||
compatible = "brcm,ns-usb2-phy";
|
||||
reg = <0x1800c000 0x1000>;
|
||||
reg-names = "dmu";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
|
||||
clock-names = "phy-ref-clk";
|
||||
};
|
|
@ -1,14 +1,17 @@
|
|||
* Broadcom SATA3 PHY for STB
|
||||
* Broadcom SATA3 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one or more of
|
||||
"brcm,bcm7425-sata-phy"
|
||||
"brcm,bcm7445-sata-phy"
|
||||
"brcm,iproc-ns2-sata-phy"
|
||||
"brcm,phy-sata3"
|
||||
- address-cells: should be 1
|
||||
- size-cells: should be 0
|
||||
- reg: register range for the PHY PCB interface
|
||||
- reg-names: should be "phy"
|
||||
- reg: register ranges for the PHY PCB interface
|
||||
- reg-names: should be "phy" and "phy-ctrl"
|
||||
The "phy-ctrl" registers are only required for
|
||||
"brcm,iproc-ns2-sata-phy".
|
||||
|
||||
Sub-nodes:
|
||||
Each port's PHY should be represented as a sub-node.
|
||||
|
@ -16,12 +19,12 @@ Sub-nodes:
|
|||
Sub-nodes required properties:
|
||||
- reg: the PHY number
|
||||
- phy-cells: generic PHY binding; must be 0
|
||||
Optional:
|
||||
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
|
||||
|
||||
Sub-nodes optional properties:
|
||||
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
|
||||
This property is not applicable for "brcm,iproc-ns2-sata-phy".
|
||||
|
||||
Example:
|
||||
|
||||
sata-phy@f0458100 {
|
||||
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
|
||||
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
|
|
@ -4,7 +4,9 @@ mt65xx USB3.0 PHY binding
|
|||
This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
|
||||
|
||||
Required properties (controller (parent) node):
|
||||
- compatible : should be "mediatek,mt8173-u3phy"
|
||||
- compatible : should be one of
|
||||
"mediatek,mt2701-u3phy"
|
||||
"mediatek,mt8173-u3phy"
|
||||
- reg : offset and length of register for phy, exclude port's
|
||||
register.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
|
|
|
@ -7,6 +7,12 @@ Required properties:
|
|||
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
|
||||
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
|
||||
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
|
||||
"renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 compatible device.
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: offset and length of the register block.
|
||||
- #address-cells: number of address cells for the USB channel subnodes, must
|
||||
be <1>.
|
||||
|
@ -34,7 +40,7 @@ the USB channel; see the selector meanings below:
|
|||
Example (Lager board):
|
||||
|
||||
usb-phy@e6590100 {
|
||||
compatible = "renesas,usb-phy-r8a7790";
|
||||
compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy";
|
||||
reg = <0 0xe6590100 0 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
|
|
@ -6,6 +6,12 @@ This file provides information on what the device node for the R-Car generation
|
|||
Required properties:
|
||||
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
|
||||
SoC.
|
||||
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: offset and length of the partial USB 2.0 Host register block.
|
||||
- clocks: clock phandle and specifier pair(s).
|
||||
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
|
||||
|
@ -15,18 +21,20 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
|
|||
combined, the device tree node should set interrupt properties to use the
|
||||
channel as USB OTG:
|
||||
- interrupts: interrupt specifier for the PHY.
|
||||
- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
|
||||
regulator will be managed during the PHY power on/off sequence.
|
||||
|
||||
Example (R-Car H3):
|
||||
|
||||
usb-phy@ee080200 {
|
||||
compatible = "renesas,usb2-phy-r8a7795";
|
||||
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
|
||||
reg = <0 0xee080200 0 0x700>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
|
||||
};
|
||||
|
||||
usb-phy@ee0a0200 {
|
||||
compatible = "renesas,usb2-phy-r8a7795";
|
||||
compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
|
||||
reg = <0 0xee0a0200 0 0x700>;
|
||||
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
|
||||
};
|
||||
|
|
|
@ -2,9 +2,20 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY
|
|||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "samsung,s5pv210-mipi-video-phy";
|
||||
- compatible : should be one of the listed compatibles:
|
||||
- "samsung,s5pv210-mipi-video-phy"
|
||||
- "samsung,exynos5420-mipi-video-phy"
|
||||
- "samsung,exynos5433-mipi-video-phy"
|
||||
- #phy-cells : from the generic phy bindings, must be 1;
|
||||
- syscon - phandle to the PMU system controller;
|
||||
|
||||
In case of s5pv210 and exynos5420 compatible PHYs:
|
||||
- syscon - phandle to the PMU system controller
|
||||
|
||||
In case of exynos5433 compatible PHY:
|
||||
- samsung,pmu-syscon - phandle to the PMU system controller
|
||||
- samsung,disp-sysreg - phandle to the DISP system registers controller
|
||||
- samsung,cam0-sysreg - phandle to the CAM0 system registers controller
|
||||
- samsung,cam1-sysreg - phandle to the CAM1 system registers controller
|
||||
|
||||
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
|
||||
the PHY specifier identifies the PHY and its meaning is as follows:
|
||||
|
@ -12,6 +23,9 @@ the PHY specifier identifies the PHY and its meaning is as follows:
|
|||
1 - MIPI DSIM 0,
|
||||
2 - MIPI CSIS 1,
|
||||
3 - MIPI DSIM 1.
|
||||
"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy"
|
||||
supports additional fifth PHY:
|
||||
4 - MIPI CSIS 2.
|
||||
|
||||
Samsung EXYNOS SoC series Display Port PHY
|
||||
-------------------------------------------------
|
||||
|
|
|
@ -15,6 +15,15 @@ config GENERIC_PHY
|
|||
phy users can obtain reference to the PHY. All the users of this
|
||||
framework should select this config.
|
||||
|
||||
config PHY_BCM_NS_USB2
|
||||
tristate "Broadcom Northstar USB 2.0 PHY Driver"
|
||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
depends on HAS_IOMEM && OF
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Broadcom USB 2.0 PHY connected to the USB
|
||||
controller on Northstar family.
|
||||
|
||||
config PHY_BERLIN_USB
|
||||
tristate "Marvell Berlin USB PHY Driver"
|
||||
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
|
||||
|
@ -113,14 +122,15 @@ config PHY_MIPHY365X
|
|||
|
||||
config PHY_RCAR_GEN2
|
||||
tristate "Renesas R-Car generation 2 USB PHY driver"
|
||||
depends on ARCH_SHMOBILE
|
||||
depends on ARCH_RENESAS
|
||||
depends on GENERIC_PHY
|
||||
help
|
||||
Support for USB PHY found on Renesas R-Car generation 2 SoCs.
|
||||
|
||||
config PHY_RCAR_GEN3_USB2
|
||||
tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
|
||||
depends on OF && ARCH_SHMOBILE
|
||||
depends on ARCH_RENESAS
|
||||
depends on EXTCON
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
|
||||
|
@ -218,9 +228,8 @@ config PHY_MT65XX_USB3
|
|||
depends on ARCH_MEDIATEK && OF
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Say 'Y' here to add support for Mediatek USB3.0 PHY driver
|
||||
for mt65xx SoCs. it supports two usb2.0 ports and
|
||||
one usb3.0 port.
|
||||
Say 'Y' here to add support for Mediatek USB3.0 PHY driver,
|
||||
it supports multiple usb2.0 and usb3.0 ports.
|
||||
|
||||
config PHY_HI6220_USB
|
||||
tristate "hi6220 USB PHY support"
|
||||
|
@ -404,14 +413,15 @@ config PHY_TUSB1210
|
|||
help
|
||||
Support for TI TUSB1210 USB ULPI PHY.
|
||||
|
||||
config PHY_BRCMSTB_SATA
|
||||
tristate "Broadcom STB SATA PHY driver"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
config PHY_BRCM_SATA
|
||||
tristate "Broadcom SATA PHY driver"
|
||||
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST
|
||||
depends on OF
|
||||
select GENERIC_PHY
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs.
|
||||
Likely useful only with CONFIG_SATA_BRCMSTB enabled.
|
||||
Enable this to support the Broadcom SATA PHY.
|
||||
If unsure, say N.
|
||||
|
||||
config PHY_CYGNUS_PCIE
|
||||
tristate "Broadcom Cygnus PCIe PHY driver"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
|
||||
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
|
||||
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
|
||||
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
|
||||
obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
|
||||
|
@ -49,6 +50,6 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
|||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
|
||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
|
||||
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
|
||||
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
|
||||
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
|
||||
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
|
||||
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Broadcom Northstar USB 2.0 PHY Driver
|
||||
*
|
||||
* Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct bcm_ns_usb2 {
|
||||
struct device *dev;
|
||||
struct clk *ref_clk;
|
||||
struct phy *phy;
|
||||
void __iomem *dmu;
|
||||
};
|
||||
|
||||
static int bcm_ns_usb2_phy_init(struct phy *phy)
|
||||
{
|
||||
struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy);
|
||||
struct device *dev = usb2->dev;
|
||||
void __iomem *dmu = usb2->dmu;
|
||||
u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv;
|
||||
int err = 0;
|
||||
|
||||
err = clk_prepare_enable(usb2->ref_clk);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Failed to prepare ref clock: %d\n", err);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ref_clk_rate = clk_get_rate(usb2->ref_clk);
|
||||
if (!ref_clk_rate) {
|
||||
dev_err(dev, "Failed to get ref clock rate\n");
|
||||
err = -EINVAL;
|
||||
goto err_clk_off;
|
||||
}
|
||||
|
||||
usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
|
||||
if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) {
|
||||
usb_pll_pdiv = usb2ctl;
|
||||
usb_pll_pdiv &= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK;
|
||||
usb_pll_pdiv >>= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT;
|
||||
} else {
|
||||
usb_pll_pdiv = 1 << 3;
|
||||
}
|
||||
|
||||
/* Calculate ndiv based on a solid 1920 MHz that is for USB2 PHY */
|
||||
usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate;
|
||||
|
||||
/* Unlock DMU PLL settings with some magic value */
|
||||
writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
|
||||
/* Write USB 2.0 PLL control setting */
|
||||
usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK;
|
||||
usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT;
|
||||
writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL);
|
||||
|
||||
/* Lock DMU PLL settings */
|
||||
writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY);
|
||||
|
||||
err_clk_off:
|
||||
clk_disable_unprepare(usb2->ref_clk);
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct phy_ops ops = {
|
||||
.init = bcm_ns_usb2_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int bcm_ns_usb2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm_ns_usb2 *usb2;
|
||||
struct resource *res;
|
||||
struct phy_provider *phy_provider;
|
||||
|
||||
usb2 = devm_kzalloc(&pdev->dev, sizeof(*usb2), GFP_KERNEL);
|
||||
if (!usb2)
|
||||
return -ENOMEM;
|
||||
usb2->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu");
|
||||
usb2->dmu = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(usb2->dmu)) {
|
||||
dev_err(dev, "Failed to map DMU regs\n");
|
||||
return PTR_ERR(usb2->dmu);
|
||||
}
|
||||
|
||||
usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk");
|
||||
if (IS_ERR(usb2->ref_clk)) {
|
||||
dev_err(dev, "Clock not defined\n");
|
||||
return PTR_ERR(usb2->ref_clk);
|
||||
}
|
||||
|
||||
usb2->phy = devm_phy_create(dev, NULL, &ops);
|
||||
if (IS_ERR(dev))
|
||||
return PTR_ERR(dev);
|
||||
|
||||
phy_set_drvdata(usb2->phy, usb2);
|
||||
platform_set_drvdata(pdev, usb2);
|
||||
|
||||
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 bcm_ns_usb2_id_table[] = {
|
||||
{ .compatible = "brcm,ns-usb2-phy", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm_ns_usb2_id_table);
|
||||
|
||||
static struct platform_driver bcm_ns_usb2_driver = {
|
||||
.probe = bcm_ns_usb2_probe,
|
||||
.driver = {
|
||||
.name = "bcm_ns_usb2",
|
||||
.of_match_table = bcm_ns_usb2_id_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(bcm_ns_usb2_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* Broadcom SATA3 AHCI Controller PHY Driver
|
||||
*
|
||||
* Copyright (C) 2016 Broadcom
|
||||
*
|
||||
* 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define SATA_PCB_BANK_OFFSET 0x23c
|
||||
#define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4)
|
||||
|
||||
#define MAX_PORTS 2
|
||||
|
||||
/* Register offset between PHYs in PCB space */
|
||||
#define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000
|
||||
|
||||
/* The older SATA PHY registers duplicated per port registers within the map,
|
||||
* rather than having a separate map per port.
|
||||
*/
|
||||
#define SATA_PCB_REG_40NM_SPACE_SIZE 0x10
|
||||
|
||||
/* Register offset between PHYs in PHY control space */
|
||||
#define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
|
||||
|
||||
enum brcm_sata_phy_version {
|
||||
BRCM_SATA_PHY_STB_28NM,
|
||||
BRCM_SATA_PHY_STB_40NM,
|
||||
BRCM_SATA_PHY_IPROC_NS2,
|
||||
};
|
||||
|
||||
struct brcm_sata_port {
|
||||
int portnum;
|
||||
struct phy *phy;
|
||||
struct brcm_sata_phy *phy_priv;
|
||||
bool ssc_en;
|
||||
};
|
||||
|
||||
struct brcm_sata_phy {
|
||||
struct device *dev;
|
||||
void __iomem *phy_base;
|
||||
void __iomem *ctrl_base;
|
||||
enum brcm_sata_phy_version version;
|
||||
|
||||
struct brcm_sata_port phys[MAX_PORTS];
|
||||
};
|
||||
|
||||
enum sata_phy_regs {
|
||||
BLOCK0_REG_BANK = 0x000,
|
||||
BLOCK0_XGXSSTATUS = 0x81,
|
||||
BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12),
|
||||
BLOCK0_SPARE = 0x8d,
|
||||
BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3,
|
||||
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1,
|
||||
|
||||
PLL_REG_BANK_0 = 0x050,
|
||||
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
|
||||
|
||||
PLL1_REG_BANK = 0x060,
|
||||
PLL1_ACTRL2 = 0x82,
|
||||
PLL1_ACTRL3 = 0x83,
|
||||
PLL1_ACTRL4 = 0x84,
|
||||
|
||||
OOB_REG_BANK = 0x150,
|
||||
OOB_CTRL1 = 0x80,
|
||||
OOB_CTRL1_BURST_MAX_MASK = 0xf,
|
||||
OOB_CTRL1_BURST_MAX_SHIFT = 12,
|
||||
OOB_CTRL1_BURST_MIN_MASK = 0xf,
|
||||
OOB_CTRL1_BURST_MIN_SHIFT = 8,
|
||||
OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf,
|
||||
OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4,
|
||||
OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf,
|
||||
OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0,
|
||||
OOB_CTRL2 = 0x81,
|
||||
OOB_CTRL2_SEL_ENA_SHIFT = 15,
|
||||
OOB_CTRL2_SEL_ENA_RC_SHIFT = 14,
|
||||
OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f,
|
||||
OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8,
|
||||
OOB_CTRL2_BURST_CNT_MASK = 0x3,
|
||||
OOB_CTRL2_BURST_CNT_SHIFT = 6,
|
||||
OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f,
|
||||
OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0,
|
||||
|
||||
TXPMD_REG_BANK = 0x1a0,
|
||||
TXPMD_CONTROL1 = 0x81,
|
||||
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
|
||||
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
|
||||
};
|
||||
|
||||
enum sata_phy_ctrl_regs {
|
||||
PHY_CTRL_1 = 0x0,
|
||||
PHY_CTRL_1_RESET = BIT(0),
|
||||
};
|
||||
|
||||
static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
|
||||
{
|
||||
struct brcm_sata_phy *priv = port->phy_priv;
|
||||
u32 size = 0;
|
||||
|
||||
switch (priv->version) {
|
||||
case BRCM_SATA_PHY_STB_28NM:
|
||||
case BRCM_SATA_PHY_IPROC_NS2:
|
||||
size = SATA_PCB_REG_28NM_SPACE_SIZE;
|
||||
break;
|
||||
case BRCM_SATA_PHY_STB_40NM:
|
||||
size = SATA_PCB_REG_40NM_SPACE_SIZE;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "invalid phy version\n");
|
||||
break;
|
||||
};
|
||||
|
||||
return priv->phy_base + (port->portnum * size);
|
||||
}
|
||||
|
||||
static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
|
||||
{
|
||||
struct brcm_sata_phy *priv = port->phy_priv;
|
||||
u32 size = 0;
|
||||
|
||||
switch (priv->version) {
|
||||
case BRCM_SATA_PHY_IPROC_NS2:
|
||||
size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "invalid phy version\n");
|
||||
break;
|
||||
};
|
||||
|
||||
return priv->ctrl_base + (port->portnum * size);
|
||||
}
|
||||
|
||||
static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank,
|
||||
u32 ofs, u32 msk, u32 value)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
|
||||
tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
|
||||
tmp = (tmp & msk) | value;
|
||||
writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs));
|
||||
}
|
||||
|
||||
static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
|
||||
{
|
||||
writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
|
||||
return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
|
||||
}
|
||||
|
||||
/* These defaults were characterized by H/W group */
|
||||
#define STB_FMIN_VAL_DEFAULT 0x3df
|
||||
#define STB_FMAX_VAL_DEFAULT 0x3df
|
||||
#define STB_FMAX_VAL_SSC 0x83
|
||||
|
||||
static int brcm_stb_sata_init(struct brcm_sata_port *port)
|
||||
{
|
||||
void __iomem *base = brcm_sata_pcb_base(port);
|
||||
struct brcm_sata_phy *priv = port->phy_priv;
|
||||
u32 tmp;
|
||||
|
||||
/* override the TX spread spectrum setting */
|
||||
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
|
||||
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
|
||||
|
||||
/* set fixed min freq */
|
||||
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
|
||||
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
|
||||
STB_FMIN_VAL_DEFAULT);
|
||||
|
||||
/* set fixed max freq depending on SSC config */
|
||||
if (port->ssc_en) {
|
||||
dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum);
|
||||
tmp = STB_FMAX_VAL_SSC;
|
||||
} else {
|
||||
tmp = STB_FMAX_VAL_DEFAULT;
|
||||
}
|
||||
|
||||
brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
|
||||
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NS2 SATA PLL1 defaults were characterized by H/W group */
|
||||
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8
|
||||
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00
|
||||
#define NS2_PLL1_ACTRL4_MAGIC 0x8824
|
||||
|
||||
static int brcm_ns2_sata_init(struct brcm_sata_port *port)
|
||||
{
|
||||
int try;
|
||||
unsigned int val;
|
||||
void __iomem *base = brcm_sata_pcb_base(port);
|
||||
void __iomem *ctrl_base = brcm_sata_ctrl_base(port);
|
||||
struct device *dev = port->phy_priv->dev;
|
||||
|
||||
/* Configure OOB control */
|
||||
val = 0x0;
|
||||
val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT);
|
||||
val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT);
|
||||
val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
|
||||
val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
|
||||
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
|
||||
val = 0x0;
|
||||
val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
|
||||
val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT);
|
||||
val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
|
||||
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
|
||||
|
||||
/* Configure PHY PLL register bank 1 */
|
||||
val = NS2_PLL1_ACTRL2_MAGIC;
|
||||
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
|
||||
val = NS2_PLL1_ACTRL3_MAGIC;
|
||||
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
|
||||
val = NS2_PLL1_ACTRL4_MAGIC;
|
||||
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
|
||||
|
||||
/* Configure PHY BLOCK0 register bank */
|
||||
/* Set oob_clk_sel to refclk/2 */
|
||||
brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE,
|
||||
~BLOCK0_SPARE_OOB_CLK_SEL_MASK,
|
||||
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2);
|
||||
|
||||
/* Strobe PHY reset using PHY control register */
|
||||
writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1);
|
||||
mdelay(1);
|
||||
writel(0x0, ctrl_base + PHY_CTRL_1);
|
||||
mdelay(1);
|
||||
|
||||
/* Wait for PHY PLL lock by polling pll_lock bit */
|
||||
try = 50;
|
||||
while (try) {
|
||||
val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
|
||||
BLOCK0_XGXSSTATUS);
|
||||
if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
|
||||
break;
|
||||
msleep(20);
|
||||
try--;
|
||||
}
|
||||
if (!try) {
|
||||
/* PLL did not lock; give up */
|
||||
dev_err(dev, "port%d PLL did not lock\n", port->portnum);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "port%d initialized\n", port->portnum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcm_sata_phy_init(struct phy *phy)
|
||||
{
|
||||
int rc;
|
||||
struct brcm_sata_port *port = phy_get_drvdata(phy);
|
||||
|
||||
switch (port->phy_priv->version) {
|
||||
case BRCM_SATA_PHY_STB_28NM:
|
||||
case BRCM_SATA_PHY_STB_40NM:
|
||||
rc = brcm_stb_sata_init(port);
|
||||
break;
|
||||
case BRCM_SATA_PHY_IPROC_NS2:
|
||||
rc = brcm_ns2_sata_init(port);
|
||||
break;
|
||||
default:
|
||||
rc = -ENODEV;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops phy_ops = {
|
||||
.init = brcm_sata_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id brcm_sata_phy_of_match[] = {
|
||||
{ .compatible = "brcm,bcm7445-sata-phy",
|
||||
.data = (void *)BRCM_SATA_PHY_STB_28NM },
|
||||
{ .compatible = "brcm,bcm7425-sata-phy",
|
||||
.data = (void *)BRCM_SATA_PHY_STB_40NM },
|
||||
{ .compatible = "brcm,iproc-ns2-sata-phy",
|
||||
.data = (void *)BRCM_SATA_PHY_IPROC_NS2 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
|
||||
|
||||
static int brcm_sata_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *dn = dev->of_node, *child;
|
||||
const struct of_device_id *of_id;
|
||||
struct brcm_sata_phy *priv;
|
||||
struct resource *res;
|
||||
struct phy_provider *provider;
|
||||
int ret, count = 0;
|
||||
|
||||
if (of_get_child_count(dn) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, priv);
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
|
||||
priv->phy_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->phy_base))
|
||||
return PTR_ERR(priv->phy_base);
|
||||
|
||||
of_id = of_match_node(brcm_sata_phy_of_match, dn);
|
||||
if (of_id)
|
||||
priv->version = (enum brcm_sata_phy_version)of_id->data;
|
||||
else
|
||||
priv->version = BRCM_SATA_PHY_STB_28NM;
|
||||
|
||||
if (priv->version == BRCM_SATA_PHY_IPROC_NS2) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"phy-ctrl");
|
||||
priv->ctrl_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->ctrl_base))
|
||||
return PTR_ERR(priv->ctrl_base);
|
||||
}
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
unsigned int id;
|
||||
struct brcm_sata_port *port;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &id)) {
|
||||
dev_err(dev, "missing reg property in node %s\n",
|
||||
child->name);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
if (id >= MAX_PORTS) {
|
||||
dev_err(dev, "invalid reg: %u\n", id);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
if (priv->phys[id].phy) {
|
||||
dev_err(dev, "already registered port %u\n", id);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
port = &priv->phys[id];
|
||||
port->portnum = id;
|
||||
port->phy_priv = priv;
|
||||
port->phy = devm_phy_create(dev, child, &phy_ops);
|
||||
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
|
||||
if (IS_ERR(port->phy)) {
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
ret = PTR_ERR(port->phy);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
phy_set_drvdata(port->phy, port);
|
||||
count++;
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "could not register PHY provider\n");
|
||||
return PTR_ERR(provider);
|
||||
}
|
||||
|
||||
dev_info(dev, "registered %d port(s)\n", count);
|
||||
|
||||
return 0;
|
||||
put_child:
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver brcm_sata_phy_driver = {
|
||||
.probe = brcm_sata_phy_probe,
|
||||
.driver = {
|
||||
.of_match_table = brcm_sata_phy_of_match,
|
||||
.name = "brcm-sata-phy",
|
||||
}
|
||||
};
|
||||
module_platform_driver(brcm_sata_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom SATA PHY driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Carino");
|
||||
MODULE_AUTHOR("Brian Norris");
|
||||
MODULE_ALIAS("platform:phy-brcm-sata");
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* Broadcom SATA3 AHCI Controller PHY Driver
|
||||
*
|
||||
* Copyright © 2009-2015 Broadcom Corporation
|
||||
*
|
||||
* 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define SATA_MDIO_BANK_OFFSET 0x23c
|
||||
#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4)
|
||||
|
||||
#define MAX_PORTS 2
|
||||
|
||||
/* Register offset between PHYs in PCB space */
|
||||
#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000
|
||||
|
||||
/* The older SATA PHY registers duplicated per port registers within the map,
|
||||
* rather than having a separate map per port.
|
||||
*/
|
||||
#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10
|
||||
|
||||
enum brcm_sata_phy_version {
|
||||
BRCM_SATA_PHY_28NM,
|
||||
BRCM_SATA_PHY_40NM,
|
||||
};
|
||||
|
||||
struct brcm_sata_port {
|
||||
int portnum;
|
||||
struct phy *phy;
|
||||
struct brcm_sata_phy *phy_priv;
|
||||
bool ssc_en;
|
||||
};
|
||||
|
||||
struct brcm_sata_phy {
|
||||
struct device *dev;
|
||||
void __iomem *phy_base;
|
||||
enum brcm_sata_phy_version version;
|
||||
|
||||
struct brcm_sata_port phys[MAX_PORTS];
|
||||
};
|
||||
|
||||
enum sata_mdio_phy_regs {
|
||||
PLL_REG_BANK_0 = 0x50,
|
||||
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
|
||||
|
||||
TXPMD_REG_BANK = 0x1a0,
|
||||
TXPMD_CONTROL1 = 0x81,
|
||||
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
|
||||
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
|
||||
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
|
||||
};
|
||||
|
||||
static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port)
|
||||
{
|
||||
struct brcm_sata_phy *priv = port->phy_priv;
|
||||
u32 offset = 0;
|
||||
|
||||
if (priv->version == BRCM_SATA_PHY_28NM)
|
||||
offset = SATA_MDIO_REG_28NM_SPACE_SIZE;
|
||||
else if (priv->version == BRCM_SATA_PHY_40NM)
|
||||
offset = SATA_MDIO_REG_40NM_SPACE_SIZE;
|
||||
else
|
||||
dev_err(priv->dev, "invalid phy version\n");
|
||||
|
||||
return priv->phy_base + (port->portnum * offset);
|
||||
}
|
||||
|
||||
static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
|
||||
u32 msk, u32 value)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
writel(bank, addr + SATA_MDIO_BANK_OFFSET);
|
||||
tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs));
|
||||
tmp = (tmp & msk) | value;
|
||||
writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs));
|
||||
}
|
||||
|
||||
/* These defaults were characterized by H/W group */
|
||||
#define FMIN_VAL_DEFAULT 0x3df
|
||||
#define FMAX_VAL_DEFAULT 0x3df
|
||||
#define FMAX_VAL_SSC 0x83
|
||||
|
||||
static void brcm_sata_cfg_ssc(struct brcm_sata_port *port)
|
||||
{
|
||||
void __iomem *base = brcm_sata_phy_base(port);
|
||||
struct brcm_sata_phy *priv = port->phy_priv;
|
||||
u32 tmp;
|
||||
|
||||
/* override the TX spread spectrum setting */
|
||||
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
|
||||
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
|
||||
|
||||
/* set fixed min freq */
|
||||
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
|
||||
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
|
||||
FMIN_VAL_DEFAULT);
|
||||
|
||||
/* set fixed max freq depending on SSC config */
|
||||
if (port->ssc_en) {
|
||||
dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum);
|
||||
tmp = FMAX_VAL_SSC;
|
||||
} else {
|
||||
tmp = FMAX_VAL_DEFAULT;
|
||||
}
|
||||
|
||||
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
|
||||
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
|
||||
}
|
||||
|
||||
static int brcm_sata_phy_init(struct phy *phy)
|
||||
{
|
||||
struct brcm_sata_port *port = phy_get_drvdata(phy);
|
||||
|
||||
brcm_sata_cfg_ssc(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops phy_ops = {
|
||||
.init = brcm_sata_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id brcm_sata_phy_of_match[] = {
|
||||
{ .compatible = "brcm,bcm7445-sata-phy",
|
||||
.data = (void *)BRCM_SATA_PHY_28NM },
|
||||
{ .compatible = "brcm,bcm7425-sata-phy",
|
||||
.data = (void *)BRCM_SATA_PHY_40NM },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
|
||||
|
||||
static int brcm_sata_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *dn = dev->of_node, *child;
|
||||
const struct of_device_id *of_id;
|
||||
struct brcm_sata_phy *priv;
|
||||
struct resource *res;
|
||||
struct phy_provider *provider;
|
||||
int ret, count = 0;
|
||||
|
||||
if (of_get_child_count(dn) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, priv);
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
|
||||
priv->phy_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->phy_base))
|
||||
return PTR_ERR(priv->phy_base);
|
||||
|
||||
of_id = of_match_node(brcm_sata_phy_of_match, dn);
|
||||
if (of_id)
|
||||
priv->version = (enum brcm_sata_phy_version)of_id->data;
|
||||
else
|
||||
priv->version = BRCM_SATA_PHY_28NM;
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
unsigned int id;
|
||||
struct brcm_sata_port *port;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &id)) {
|
||||
dev_err(dev, "missing reg property in node %s\n",
|
||||
child->name);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
if (id >= MAX_PORTS) {
|
||||
dev_err(dev, "invalid reg: %u\n", id);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
if (priv->phys[id].phy) {
|
||||
dev_err(dev, "already registered port %u\n", id);
|
||||
ret = -EINVAL;
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
port = &priv->phys[id];
|
||||
port->portnum = id;
|
||||
port->phy_priv = priv;
|
||||
port->phy = devm_phy_create(dev, child, &phy_ops);
|
||||
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
|
||||
if (IS_ERR(port->phy)) {
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
ret = PTR_ERR(port->phy);
|
||||
goto put_child;
|
||||
}
|
||||
|
||||
phy_set_drvdata(port->phy, port);
|
||||
count++;
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "could not register PHY provider\n");
|
||||
return PTR_ERR(provider);
|
||||
}
|
||||
|
||||
dev_info(dev, "registered %d port(s)\n", count);
|
||||
|
||||
return 0;
|
||||
put_child:
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver brcm_sata_phy_driver = {
|
||||
.probe = brcm_sata_phy_probe,
|
||||
.driver = {
|
||||
.of_match_table = brcm_sata_phy_of_match,
|
||||
.name = "brcmstb-sata-phy",
|
||||
}
|
||||
};
|
||||
module_platform_driver(brcm_sata_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom STB SATA PHY driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Carino");
|
||||
MODULE_AUTHOR("Brian Norris");
|
||||
MODULE_ALIAS("platform:phy-brcmstb-sata");
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
|
||||
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -13,96 +13,276 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon/exynos4-pmu.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
|
||||
#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4)
|
||||
|
||||
enum exynos_mipi_phy_id {
|
||||
EXYNOS_MIPI_PHY_ID_NONE = -1,
|
||||
EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||
EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||
EXYNOS_MIPI_PHY_ID_CSIS2,
|
||||
EXYNOS_MIPI_PHYS_NUM
|
||||
};
|
||||
|
||||
#define is_mipi_dsim_phy_id(id) \
|
||||
((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
|
||||
enum exynos_mipi_phy_regmap_id {
|
||||
EXYNOS_MIPI_REGMAP_PMU,
|
||||
EXYNOS_MIPI_REGMAP_DISP,
|
||||
EXYNOS_MIPI_REGMAP_CAM0,
|
||||
EXYNOS_MIPI_REGMAP_CAM1,
|
||||
EXYNOS_MIPI_REGMAPS_NUM
|
||||
};
|
||||
|
||||
struct mipi_phy_device_desc {
|
||||
int num_phys;
|
||||
int num_regmaps;
|
||||
const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM];
|
||||
struct exynos_mipi_phy_desc {
|
||||
enum exynos_mipi_phy_id coupled_phy_id;
|
||||
u32 enable_val;
|
||||
unsigned int enable_reg;
|
||||
enum exynos_mipi_phy_regmap_id enable_map;
|
||||
u32 resetn_val;
|
||||
unsigned int resetn_reg;
|
||||
enum exynos_mipi_phy_regmap_id resetn_map;
|
||||
} phys[EXYNOS_MIPI_PHYS_NUM];
|
||||
};
|
||||
|
||||
static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
||||
.num_regmaps = 1,
|
||||
.regmap_names = {"syscon"},
|
||||
.num_phys = 4,
|
||||
.phys = {
|
||||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
|
||||
.num_regmaps = 1,
|
||||
.regmap_names = {"syscon"},
|
||||
.num_phys = 5,
|
||||
.phys = {
|
||||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
||||
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#define EXYNOS5433_SYSREG_DISP_MIPI_PHY 0x100C
|
||||
#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON 0x1014
|
||||
#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON 0x1020
|
||||
|
||||
static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
||||
.num_regmaps = 4,
|
||||
.regmap_names = {
|
||||
"samsung,pmu-syscon",
|
||||
"samsung,disp-sysreg",
|
||||
"samsung,cam0-sysreg",
|
||||
"samsung,cam1-sysreg"
|
||||
},
|
||||
.num_phys = 5,
|
||||
.phys = {
|
||||
{
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(1),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(1),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
|
||||
}, {
|
||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
||||
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL,
|
||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||
.resetn_val = BIT(0),
|
||||
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
|
||||
.resetn_map = EXYNOS_MIPI_REGMAP_CAM1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
struct exynos_mipi_video_phy {
|
||||
struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM];
|
||||
int num_phys;
|
||||
struct video_phy_desc {
|
||||
struct phy *phy;
|
||||
unsigned int index;
|
||||
const struct exynos_mipi_phy_desc *data;
|
||||
} phys[EXYNOS_MIPI_PHYS_NUM];
|
||||
spinlock_t slock;
|
||||
void __iomem *regs;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int __set_phy_state(struct exynos_mipi_video_phy *state,
|
||||
enum exynos_mipi_phy_id id, unsigned int on)
|
||||
static inline int __is_running(const struct exynos_mipi_phy_desc *data,
|
||||
struct exynos_mipi_video_phy *state)
|
||||
{
|
||||
const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
|
||||
void __iomem *addr;
|
||||
u32 val, reset;
|
||||
u32 val;
|
||||
|
||||
if (is_mipi_dsim_phy_id(id))
|
||||
reset = EXYNOS4_MIPI_PHY_MRESETN;
|
||||
else
|
||||
reset = EXYNOS4_MIPI_PHY_SRESETN;
|
||||
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
|
||||
return val & data->resetn_val;
|
||||
}
|
||||
|
||||
static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
|
||||
struct exynos_mipi_video_phy *state, unsigned int on)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
spin_lock(&state->slock);
|
||||
|
||||
if (!IS_ERR(state->regmap)) {
|
||||
regmap_read(state->regmap, offset, &val);
|
||||
if (on)
|
||||
val |= reset;
|
||||
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);
|
||||
} else {
|
||||
addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
|
||||
/* disable in PMU sysreg */
|
||||
if (!on && data->coupled_phy_id >= 0 &&
|
||||
!__is_running(state->phys[data->coupled_phy_id].data, state)) {
|
||||
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
|
||||
&val);
|
||||
val &= ~data->enable_val;
|
||||
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
|
||||
val);
|
||||
}
|
||||
|
||||
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;
|
||||
/* PHY reset */
|
||||
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
|
||||
val = on ? (val | data->resetn_val) : (val & ~data->resetn_val);
|
||||
regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val);
|
||||
|
||||
writel(val, addr);
|
||||
/* enable in PMU sysreg */
|
||||
if (on) {
|
||||
regmap_read(state->regmaps[data->enable_map], data->enable_reg,
|
||||
&val);
|
||||
val |= data->enable_val;
|
||||
regmap_write(state->regmaps[data->enable_map], data->enable_reg,
|
||||
val);
|
||||
}
|
||||
|
||||
spin_unlock(&state->slock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define to_mipi_video_phy(desc) \
|
||||
container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]);
|
||||
container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index])
|
||||
|
||||
static int exynos_mipi_video_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
|
||||
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
|
||||
|
||||
return __set_phy_state(state, phy_desc->index, 1);
|
||||
return __set_phy_state(phy_desc->data, state, 1);
|
||||
}
|
||||
|
||||
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)
|
|||
struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
|
||||
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
|
||||
|
||||
return __set_phy_state(state, phy_desc->index, 0);
|
||||
return __set_phy_state(phy_desc->data, state, 0);
|
||||
}
|
||||
|
||||
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,
|
|||
{
|
||||
struct exynos_mipi_video_phy *state = dev_get_drvdata(dev);
|
||||
|
||||
if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM))
|
||||
if (WARN_ON(args->args[0] >= state->num_phys))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return state->phys[args->args[0]].phy;
|
||||
|
@ -132,32 +312,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = {
|
|||
|
||||
static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct mipi_phy_device_desc *phy_dev;
|
||||
struct exynos_mipi_video_phy *state;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct phy_provider *phy_provider;
|
||||
unsigned int i;
|
||||
|
||||
phy_dev = of_device_get_match_data(dev);
|
||||
if (!phy_dev)
|
||||
return -ENODEV;
|
||||
|
||||
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
|
||||
if (IS_ERR(state->regmap)) {
|
||||
struct resource *res;
|
||||
|
||||
dev_info(dev, "regmap lookup failed: %ld\n",
|
||||
PTR_ERR(state->regmap));
|
||||
|
||||
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);
|
||||
for (i = 0; i < phy_dev->num_regmaps; i++) {
|
||||
state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,
|
||||
phy_dev->regmap_names[i]);
|
||||
if (IS_ERR(state->regmaps[i]))
|
||||
return PTR_ERR(state->regmaps[i]);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, state);
|
||||
state->num_phys = phy_dev->num_phys;
|
||||
spin_lock_init(&state->slock);
|
||||
|
||||
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
|
||||
dev_set_drvdata(dev, state);
|
||||
|
||||
for (i = 0; i < state->num_phys; i++) {
|
||||
struct phy *phy = devm_phy_create(dev, NULL,
|
||||
&exynos_mipi_video_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
|
@ -167,6 +348,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
|
|||
|
||||
state->phys[i].phy = phy;
|
||||
state->phys[i].index = i;
|
||||
state->phys[i].data = &phy_dev->phys[i];
|
||||
phy_set_drvdata(phy, &state->phys[i]);
|
||||
}
|
||||
|
||||
|
@ -177,8 +359,17 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id exynos_mipi_video_phy_of_match[] = {
|
||||
{ .compatible = "samsung,s5pv210-mipi-video-phy" },
|
||||
{ },
|
||||
{
|
||||
.compatible = "samsung,s5pv210-mipi-video-phy",
|
||||
.data = &s5pv210_mipi_phy,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5420-mipi-video-phy",
|
||||
.data = &exynos5420_mipi_phy,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5433-mipi-video-phy",
|
||||
.data = &exynos5433_mipi_phy,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);
|
||||
|
||||
|
|
|
@ -134,6 +134,11 @@
|
|||
#define U3P_SR_COEF_DIVISOR 1000
|
||||
#define U3P_FM_DET_CYCLE_CNT 1024
|
||||
|
||||
struct mt65xx_phy_pdata {
|
||||
/* avoid RX sensitivity level degradation only for mt8173 */
|
||||
bool avoid_rx_sen_degradation;
|
||||
};
|
||||
|
||||
struct mt65xx_phy_instance {
|
||||
struct phy *phy;
|
||||
void __iomem *port_base;
|
||||
|
@ -145,6 +150,7 @@ struct mt65xx_u3phy {
|
|||
struct device *dev;
|
||||
void __iomem *sif_base; /* include sif2, but exclude port's */
|
||||
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
|
||||
const struct mt65xx_phy_pdata *pdata;
|
||||
struct mt65xx_phy_instance **phys;
|
||||
int nphys;
|
||||
};
|
||||
|
@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
|||
tmp = readl(port_base + U3P_U2PHYACR4);
|
||||
tmp &= ~P2C_U2_GPIO_CTR_MSK;
|
||||
writel(tmp, port_base + U3P_U2PHYACR4);
|
||||
}
|
||||
|
||||
tmp = readl(port_base + U3P_USBPHYACR2);
|
||||
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR2);
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation) {
|
||||
if (!index) {
|
||||
tmp = readl(port_base + U3P_USBPHYACR2);
|
||||
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR2);
|
||||
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
} else {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
} else {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
||||
|
@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
|||
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
|
||||
writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
|
||||
|
||||
/* [mt8173]switch 100uA current to SSUSB */
|
||||
/* switch 100uA current to SSUSB */
|
||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
||||
tmp |= PA5_RG_U2_HS_100U_U3_EN;
|
||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
||||
|
@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
|||
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
|
||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
||||
|
||||
if (index) {
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
|
@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
|||
tmp = readl(port_base + U3P_U3_PHYA_REG0);
|
||||
tmp &= ~P3A_RG_U3_VUSB10_ON;
|
||||
writel(tmp, port_base + U3P_U3_PHYA_REG0);
|
||||
} else {
|
||||
}
|
||||
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
|
@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
|
|||
u32 index = instance->index;
|
||||
u32 tmp;
|
||||
|
||||
if (index) {
|
||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
||||
|
@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct mt65xx_phy_pdata mt2701_pdata = {
|
||||
.avoid_rx_sen_degradation = false,
|
||||
};
|
||||
|
||||
static const struct mt65xx_phy_pdata mt8173_pdata = {
|
||||
.avoid_rx_sen_degradation = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id mt65xx_u3phy_id_table[] = {
|
||||
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
|
||||
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
|
||||
|
||||
static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *child_np;
|
||||
|
@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||
struct resource res;
|
||||
int port, retval;
|
||||
|
||||
match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
|
||||
if (!u3phy)
|
||||
return -ENOMEM;
|
||||
|
||||
u3phy->pdata = match->data;
|
||||
u3phy->nphys = of_get_child_count(np);
|
||||
u3phy->phys = devm_kcalloc(dev, u3phy->nphys,
|
||||
sizeof(*u3phy->phys), GFP_KERNEL);
|
||||
|
@ -587,12 +620,6 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static const struct of_device_id mt65xx_u3phy_id_table[] = {
|
||||
{ .compatible = "mediatek,mt8173-u3phy", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
|
||||
|
||||
static struct platform_driver mt65xx_u3phy_driver = {
|
||||
.probe = mt65xx_u3phy_probe,
|
||||
.driver = {
|
||||
|
|
|
@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = {
|
|||
{ .compatible = "renesas,usb-phy-r8a7790" },
|
||||
{ .compatible = "renesas,usb-phy-r8a7791" },
|
||||
{ .compatible = "renesas,usb-phy-r8a7794" },
|
||||
{ .compatible = "renesas,rcar-gen2-usb-phy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/******* USB2.0 Host registers (original offset is +0x200) *******/
|
||||
#define USB2_INT_ENABLE 0x000
|
||||
|
@ -74,20 +76,17 @@
|
|||
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
|
||||
#define USB2_ADPCTRL_DRVVBUS BIT(4)
|
||||
|
||||
struct rcar_gen3_data {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
struct rcar_gen3_chan {
|
||||
struct rcar_gen3_data usb2;
|
||||
void __iomem *base;
|
||||
struct extcon_dev *extcon;
|
||||
struct phy *phy;
|
||||
struct regulator *vbus;
|
||||
bool has_otg;
|
||||
};
|
||||
|
||||
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
|
||||
{
|
||||
void __iomem *usb2_base = ch->usb2.base;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 val = readl(usb2_base + USB2_COMMCTRL);
|
||||
|
||||
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)
|
|||
|
||||
static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
|
||||
{
|
||||
void __iomem *usb2_base = ch->usb2.base;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 val = readl(usb2_base + USB2_LINECTRL1);
|
||||
|
||||
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)
|
|||
|
||||
static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
|
||||
{
|
||||
void __iomem *usb2_base = ch->usb2.base;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 val = readl(usb2_base + USB2_ADPCTRL);
|
||||
|
||||
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)
|
|||
rcar_gen3_set_linectrl(ch, 1, 1);
|
||||
rcar_gen3_set_host_mode(ch, 1);
|
||||
rcar_gen3_enable_vbus_ctrl(ch, 1);
|
||||
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
|
||||
}
|
||||
|
||||
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)
|
|||
rcar_gen3_set_linectrl(ch, 0, 1);
|
||||
rcar_gen3_set_host_mode(ch, 0);
|
||||
rcar_gen3_enable_vbus_ctrl(ch, 0);
|
||||
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
|
||||
}
|
||||
|
||||
static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
|
||||
{
|
||||
return !!(readl(ch->usb2.base + USB2_ADPCTRL) &
|
||||
return !!(readl(ch->base + USB2_ADPCTRL) &
|
||||
USB2_ADPCTRL_OTGSESSVLD);
|
||||
}
|
||||
|
||||
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
|
||||
{
|
||||
return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
|
||||
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
||||
{
|
||||
void __iomem *usb2_base = ch->usb2.base;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 val;
|
||||
|
||||
val = readl(usb2_base + USB2_VBCTRL);
|
||||
|
@ -187,7 +192,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
|||
static int rcar_gen3_phy_usb2_init(struct phy *p)
|
||||
{
|
||||
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
|
||||
void __iomem *usb2_base = channel->usb2.base;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
|
||||
/* Initialize USB2 part */
|
||||
writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
|
||||
|
@ -205,7 +210,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
|||
{
|
||||
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
|
||||
|
||||
writel(0, channel->usb2.base + USB2_INT_ENABLE);
|
||||
writel(0, channel->base + USB2_INT_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -213,8 +218,15 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
|
|||
static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
||||
{
|
||||
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
|
||||
void __iomem *usb2_base = channel->usb2.base;
|
||||
void __iomem *usb2_base = channel->base;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (channel->vbus) {
|
||||
ret = regulator_enable(channel->vbus);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = readl(usb2_base + USB2_USBCTR);
|
||||
val |= USB2_USBCTR_PLL_RST;
|
||||
|
@ -225,17 +237,29 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_gen3_phy_usb2_power_off(struct phy *p)
|
||||
{
|
||||
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
|
||||
int ret = 0;
|
||||
|
||||
if (channel->vbus)
|
||||
ret = regulator_disable(channel->vbus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct phy_ops rcar_gen3_phy_usb2_ops = {
|
||||
.init = rcar_gen3_phy_usb2_init,
|
||||
.exit = rcar_gen3_phy_usb2_exit,
|
||||
.power_on = rcar_gen3_phy_usb2_power_on,
|
||||
.power_off = rcar_gen3_phy_usb2_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
||||
{
|
||||
struct rcar_gen3_chan *ch = _ch;
|
||||
void __iomem *usb2_base = ch->usb2.base;
|
||||
void __iomem *usb2_base = ch->base;
|
||||
u32 status = readl(usb2_base + USB2_OBINTSTA);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
|
@ -251,10 +275,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
|
|||
|
||||
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
|
||||
{ .compatible = "renesas,usb2-phy-r8a7795" },
|
||||
{ .compatible = "renesas,rcar-gen3-usb2-phy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
|
||||
|
||||
static const unsigned int rcar_gen3_phy_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -273,18 +304,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
channel->usb2.base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(channel->usb2.base))
|
||||
return PTR_ERR(channel->usb2.base);
|
||||
channel->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(channel->base))
|
||||
return PTR_ERR(channel->base);
|
||||
|
||||
/* call request_irq for OTG */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0) {
|
||||
int ret;
|
||||
|
||||
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
|
||||
IRQF_SHARED, dev_name(dev), channel);
|
||||
if (irq < 0)
|
||||
dev_err(dev, "No irq handler (%d)\n", irq);
|
||||
channel->has_otg = true;
|
||||
channel->extcon = devm_extcon_dev_allocate(dev,
|
||||
rcar_gen3_phy_cable);
|
||||
if (IS_ERR(channel->extcon))
|
||||
return PTR_ERR(channel->extcon);
|
||||
|
||||
ret = devm_extcon_dev_register(dev, channel->extcon);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to register extcon\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* devm_phy_create() will call pm_runtime_enable(dev); */
|
||||
|
@ -294,6 +337,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(channel->phy);
|
||||
}
|
||||
|
||||
channel->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||
if (IS_ERR(channel->vbus)) {
|
||||
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
|
||||
return PTR_ERR(channel->vbus);
|
||||
channel->vbus = NULL;
|
||||
}
|
||||
|
||||
phy_set_drvdata(channel->phy, channel);
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
|
|
@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
|||
init.parent_names = &clk_name;
|
||||
init.num_parents = 1;
|
||||
} else {
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.flags = 0;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/bcma/bcma_driver_arm_c9.h>
|
||||
#include <linux/bcma/bcma_driver_chipcommon.h>
|
||||
#include <linux/bcma/bcma_driver_pci.h>
|
||||
#include <linux/bcma/bcma_driver_pcie2.h>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef LINUX_BCMA_DRIVER_ARM_C9_H_
|
||||
#define LINUX_BCMA_DRIVER_ARM_C9_H_
|
||||
|
||||
/* DMU (Device Management Unit) */
|
||||
#define BCMA_DMU_CRU_USB2_CONTROL 0x0164
|
||||
#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK 0x00000FFC
|
||||
#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT 2
|
||||
#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK 0x00007000
|
||||
#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT 12
|
||||
#define BCMA_DMU_CRU_CLKSET_KEY 0x0180
|
||||
#define BCMA_DMU_CRU_STRAPS_CTRL 0x02A0
|
||||
#define BCMA_DMU_CRU_STRAPS_CTRL_USB3 0x00000010
|
||||
#define BCMA_DMU_CRU_STRAPS_CTRL_4BYTE 0x00008000
|
||||
|
||||
#endif /* LINUX_BCMA_DRIVER_ARM_C9_H_ */
|
|
@ -38,6 +38,9 @@
|
|||
|
||||
/* Exynos5433 specific register definitions */
|
||||
#define EXYNOS5433_USBHOST30_PHY_CONTROL (0x728)
|
||||
#define EXYNOS5433_MIPI_PHY0_CONTROL (0x710)
|
||||
#define EXYNOS5433_MIPI_PHY1_CONTROL (0x714)
|
||||
#define EXYNOS5433_MIPI_PHY2_CONTROL (0x718)
|
||||
|
||||
#define EXYNOS5_PHY_ENABLE BIT(0)
|
||||
|
||||
|
|
Loading…
Reference in New Issue