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:
Greg Kroah-Hartman 2016-05-03 14:49:46 -07:00
commit e6c037bfca
19 changed files with 1032 additions and 380 deletions

View File

@ -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";
};

View File

@ -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>;

View File

@ -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

View File

@ -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>;

View File

@ -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>;
};

View File

@ -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
-------------------------------------------------

View File

@ -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"

View File

@ -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

View File

@ -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");

412
drivers/phy/phy-brcm-sata.c Normal file
View File

@ -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");

View File

@ -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");

View File

@ -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);

View File

@ -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 @@ put_child:
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 = {

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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>

View File

@ -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_ */

View File

@ -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)