mirror of https://gitee.com/openkylin/linux.git
phy: for 4.11
*) Add USB HSIC and HS phy driver for Qualcomm's SoC *) Add USB3 PHY driver for Broadcom NSP SoC *) Make sun4i-usb-phy driver to be used for V3s USB PHY *) Misc fixes and cleanups Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJYjyY4AAoJEA5ceFyATYLZbsYP/1AtWPiZsu26sqCtPf8fQGn7 +ok36rdNw7sW9mTwQOswL+HdFj2XQ3QmI0v8fEAGp7JZtWssIXMWQDWNFo59u8RP GDfEJCodowqKN/Nca4VNBK3NvVQRFTr7NUY3VM8Vt28bb4iu3ZTOIcDuJQOsdvJO dAzkqBSeFU8qzCSCQSbPhmrMx1uEwBsP9VUmEtHi8MkFMmCGPUKUxTUZOR3M4nTU 3ge/OI2/R0ST6NELdca5OgDUfAsb9L8+hsfYFhIUXrjwuEISOzaukVLs6dwTpsMJ 6fCWCVfhb5LDsPo8pOJyO4nMBhnp1K8bVtGmgZNsFFdtOKH0GHwdHCOKmL3fWsZX lM4woTEmUkKvL9ToqyYoehR+07Z9vhenXtWgTHCFMyEyqJBlOs53VXwzB26/2W1j SW+tBuyf94hAmhUU8bjh9Kx7I9WMQbcYb2BuGgDn/eYI0jnZIDaJ0HPEPT9Y73vQ CmtDaCrp0QRbTEUbHF8bpH836Cx/x89OwfdhAWAvQfdolc064h51ORVKqygfpQvY Wmth7qLy0XsfNV7pl2Vh+kpgpgrXKUHFAFrITRANhvcgV4mz4ggpENf0bdmXJjEW HHF7nfSrB0cTLVwvtvxd96gnWJsu57XIFjTl5zDxcvNg3U5O+Sw6xxIVSLPjvqts yPu9z+/W9ubcR/qfz1pk =d19A -----END PGP SIGNATURE----- Merge tag 'phy-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next Kishon writes: phy: for 4.11 *) Add USB HSIC and HS phy driver for Qualcomm's SoC *) Add USB3 PHY driver for Broadcom NSP SoC *) Make sun4i-usb-phy driver to be used for V3s USB PHY *) Misc fixes and cleanups Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
commit
4f8c483ab4
|
@ -0,0 +1,39 @@
|
|||
Broadcom USB3 phy binding for northstar plus SoC
|
||||
The USB3 phy is internal to the SoC and is accessed using mdio interface.
|
||||
|
||||
Required mdio bus properties:
|
||||
- reg: Should be 0x0 for SoC internal USB3 phy
|
||||
- #address-cells: must be 1
|
||||
- #size-cells: must be 0
|
||||
|
||||
Required USB3 PHY properties:
|
||||
- compatible: should be "brcm,nsp-usb3-phy"
|
||||
- reg: USB3 Phy address on SoC internal MDIO bus and it should be 0x10.
|
||||
- usb3-ctrl-syscon: handler of syscon node defining physical address
|
||||
of usb3 control register.
|
||||
- #phy-cells: must be 0
|
||||
|
||||
Required usb3 control properties:
|
||||
- compatible: should be "brcm,nsp-usb3-ctrl"
|
||||
- reg: offset and length of the control registers
|
||||
|
||||
Example:
|
||||
|
||||
mdio@0 {
|
||||
reg = <0x0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usb3_phy: usb-phy@10 {
|
||||
compatible = "brcm,nsp-usb3-phy";
|
||||
reg = <0x10>;
|
||||
usb3-ctrl-syscon = <&usb3_ctrl>;
|
||||
#phy-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
usb3_ctrl: syscon@104408 {
|
||||
compatible = "brcm,nsp-usb3-ctrl", "syscon";
|
||||
reg = <0x104408 0x3fc>;
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
Qualcomm's USB HS PHY
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Should contain "qcom,usb-hs-phy" and more specifically one of the
|
||||
following:
|
||||
|
||||
"qcom,usb-hs-phy-apq8064"
|
||||
"qcom,usb-hs-phy-msm8916"
|
||||
"qcom,usb-hs-phy-msm8974"
|
||||
|
||||
- #phy-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Should contain 0
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain clock specifier for the reference and sleep
|
||||
clocks
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "ref" and "sleep" for the reference and sleep
|
||||
clocks respectively
|
||||
|
||||
- resets:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain the phy and POR resets
|
||||
|
||||
- reset-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "phy" and "por" for the phy and POR resets
|
||||
respectively
|
||||
|
||||
- v3p3-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: Should contain a reference to the 3.3V supply
|
||||
|
||||
- v1p8-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: Should contain a reference to the 1.8V supply
|
||||
|
||||
- extcon:
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain the vbus extcon
|
||||
|
||||
- qcom,init-seq:
|
||||
Usage: optional
|
||||
Value type: <u8 array>
|
||||
Definition: Should contain a sequence of ULPI address and value pairs to
|
||||
program into the ULPI_EXT_VENDOR_SPECIFIC area. This is related
|
||||
to Device Mode Eye Diagram test. The addresses are offsets
|
||||
from the ULPI_EXT_VENDOR_SPECIFIC address, for example,
|
||||
<0x1 0x53> would mean "write the value 0x53 to address 0x81".
|
||||
|
||||
EXAMPLE
|
||||
|
||||
otg: usb-controller {
|
||||
ulpi {
|
||||
phy {
|
||||
compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
|
||||
clock-names = "ref", "sleep";
|
||||
resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>;
|
||||
reset-names = "phy", "por";
|
||||
v3p3-supply = <&pm8941_l24>;
|
||||
v1p8-supply = <&pm8941_l6>;
|
||||
extcon = <&smbb>;
|
||||
qcom,init-seq = /bits/ 8 <0x1 0x63>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
Qualcomm's USB HSIC PHY
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Should contain "qcom,usb-hsic-phy" and more specifically one of the
|
||||
following:
|
||||
|
||||
"qcom,usb-hsic-phy-mdm9615"
|
||||
"qcom,usb-hsic-phy-msm8974"
|
||||
|
||||
- #phy-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Should contain 0
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain clock specifier for phy, calibration and
|
||||
a calibration sleep clock
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "phy, "cal" and "cal_sleep"
|
||||
|
||||
- pinctrl-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "init" and "default" in that order
|
||||
|
||||
- pinctrl-0:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: List of pinctrl settings to apply to keep HSIC pins in a glitch
|
||||
free state
|
||||
|
||||
- pinctrl-1:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: List of pinctrl settings to apply to mux out the HSIC pins
|
||||
|
||||
EXAMPLE
|
||||
|
||||
usb-controller {
|
||||
ulpi {
|
||||
phy {
|
||||
compatible = "qcom,usb-hsic-phy-msm8974",
|
||||
"qcom,usb-hsic-phy";
|
||||
#phy-cells = <0>;
|
||||
pinctrl-names = "init", "default";
|
||||
pinctrl-0 = <&hsic_sleep>;
|
||||
pinctrl-1 = <&hsic_default>;
|
||||
clocks = <&gcc GCC_USB_HSIC_CLK>,
|
||||
<&gcc GCC_USB_HSIC_IO_CAL_CLK>,
|
||||
<&gcc GCC_USB_HSIC_IO_CAL_SLEEP_CLK>;
|
||||
clock-names = "phy", "cal", "cal_sleep";
|
||||
assigned-clocks = <&gcc GCC_USB_HSIC_IO_CAL_CLK>;
|
||||
assigned-clock-rates = <960000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -10,6 +10,7 @@ Required properties:
|
|||
* allwinner,sun8i-a23-usb-phy
|
||||
* allwinner,sun8i-a33-usb-phy
|
||||
* allwinner,sun8i-h3-usb-phy
|
||||
* allwinner,sun8i-v3s-usb-phy
|
||||
* allwinner,sun50i-a64-usb-phy
|
||||
- reg : a list of offset + length pairs
|
||||
- reg-names :
|
||||
|
|
|
@ -29,7 +29,6 @@ Optional properties:
|
|||
- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
|
||||
- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply
|
||||
- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
|
||||
- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -363,6 +363,7 @@ config PHY_ROCKCHIP_INNO_USB2
|
|||
tristate "Rockchip INNO USB2PHY Driver"
|
||||
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
|
||||
depends on COMMON_CLK
|
||||
depends on EXTCON
|
||||
depends on USB_SUPPORT
|
||||
select GENERIC_PHY
|
||||
select USB_COMMON
|
||||
|
@ -437,6 +438,21 @@ config PHY_QCOM_UFS
|
|||
help
|
||||
Support for UFS PHY on QCOM chipsets.
|
||||
|
||||
config PHY_QCOM_USB_HS
|
||||
tristate "Qualcomm USB HS PHY module"
|
||||
depends on USB_ULPI_BUS
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Support for the USB high-speed ULPI compliant phy on Qualcomm
|
||||
chipsets.
|
||||
|
||||
config PHY_QCOM_USB_HSIC
|
||||
tristate "Qualcomm USB HSIC ULPI PHY module"
|
||||
depends on USB_ULPI_BUS
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Support for the USB HSIC ULPI compliant PHY on QCOM chipsets.
|
||||
|
||||
config PHY_TUSB1210
|
||||
tristate "TI TUSB1210 ULPI PHY module"
|
||||
depends on USB_ULPI_BUS
|
||||
|
@ -486,4 +502,12 @@ config PHY_MESON8B_USB2
|
|||
and GXBB SoCs.
|
||||
If unsure, say N.
|
||||
|
||||
config PHY_NSP_USB3
|
||||
tristate "Broadcom NorthStar plus USB3 PHY driver"
|
||||
depends on OF && (ARCH_BCM_NSP || COMPILE_TEST)
|
||||
select GENERIC_PHY
|
||||
default ARCH_BCM_NSP
|
||||
help
|
||||
Enable this to support the Broadcom Northstar plus USB3 PHY.
|
||||
If unsure, say N.
|
||||
endmenu
|
||||
|
|
|
@ -52,6 +52,8 @@ obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
|
|||
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_QCOM_USB_HS) += phy-qcom-usb-hs.o
|
||||
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
|
||||
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
|
||||
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
|
||||
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
|
||||
|
@ -59,3 +61,4 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
|
|||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
|
||||
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
|
||||
obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o
|
||||
|
|
|
@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p)
|
|||
return cygnus_pcie_power_config(phy, false);
|
||||
}
|
||||
|
||||
static struct phy_ops cygnus_pcie_phy_ops = {
|
||||
static const struct phy_ops cygnus_pcie_phy_ops = {
|
||||
.power_on = cygnus_pcie_phy_power_on,
|
||||
.power_off = cygnus_pcie_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; 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/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define NSP_USB3_RST_CTRL_OFFSET 0x3f8
|
||||
|
||||
/* mdio reg access */
|
||||
#define NSP_USB3_PHY_BASE_ADDR_REG 0x1f
|
||||
|
||||
#define NSP_USB3_PHY_PLL30_BLOCK 0x8000
|
||||
#define NSP_USB3_PLL_CONTROL 0x01
|
||||
#define NSP_USB3_PLLA_CONTROL0 0x0a
|
||||
#define NSP_USB3_PLLA_CONTROL1 0x0b
|
||||
|
||||
#define NSP_USB3_PHY_TX_PMD_BLOCK 0x8040
|
||||
#define NSP_USB3_TX_PMD_CONTROL1 0x01
|
||||
|
||||
#define NSP_USB3_PHY_PIPE_BLOCK 0x8060
|
||||
#define NSP_USB3_LFPS_CMP 0x02
|
||||
#define NSP_USB3_LFPS_DEGLITCH 0x03
|
||||
|
||||
struct nsp_usb3_phy {
|
||||
struct regmap *usb3_ctrl;
|
||||
struct phy *phy;
|
||||
struct mdio_device *mdiodev;
|
||||
};
|
||||
|
||||
static int nsp_usb3_phy_init(struct phy *phy)
|
||||
{
|
||||
struct nsp_usb3_phy *iphy = phy_get_drvdata(phy);
|
||||
struct mii_bus *bus = iphy->mdiodev->bus;
|
||||
int addr = iphy->mdiodev->addr;
|
||||
u32 data;
|
||||
int rc;
|
||||
|
||||
rc = regmap_read(iphy->usb3_ctrl, 0, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
data |= 1;
|
||||
rc = regmap_write(iphy->usb3_ctrl, 0, data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
|
||||
NSP_USB3_PHY_PLL30_BLOCK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x1000);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL0, 0x6400);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0xc000);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0x8000);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x9000);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
|
||||
NSP_USB3_PHY_PIPE_BLOCK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_CMP, 0xf30d);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_DEGLITCH, 0x6302);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
|
||||
NSP_USB3_PHY_TX_PMD_BLOCK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = mdiobus_write(bus, addr, NSP_USB3_TX_PMD_CONTROL1, 0x1003);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct phy_ops nsp_usb3_phy_ops = {
|
||||
.init = nsp_usb3_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int nsp_usb3_phy_probe(struct mdio_device *mdiodev)
|
||||
{
|
||||
struct device *dev = &mdiodev->dev;
|
||||
struct phy_provider *provider;
|
||||
struct nsp_usb3_phy *iphy;
|
||||
|
||||
iphy = devm_kzalloc(dev, sizeof(*iphy), GFP_KERNEL);
|
||||
if (!iphy)
|
||||
return -ENOMEM;
|
||||
iphy->mdiodev = mdiodev;
|
||||
|
||||
iphy->usb3_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"usb3-ctrl-syscon");
|
||||
if (IS_ERR(iphy->usb3_ctrl))
|
||||
return PTR_ERR(iphy->usb3_ctrl);
|
||||
|
||||
iphy->phy = devm_phy_create(dev, dev->of_node, &nsp_usb3_phy_ops);
|
||||
if (IS_ERR(iphy->phy)) {
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
return PTR_ERR(iphy->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(iphy->phy, iphy);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id nsp_usb3_phy_of_match[] = {
|
||||
{.compatible = "brcm,nsp-usb3-phy",},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct mdio_driver nsp_usb3_phy_driver = {
|
||||
.mdiodrv = {
|
||||
.driver = {
|
||||
.name = "nsp-usb3-phy",
|
||||
.of_match_table = nsp_usb3_phy_of_match,
|
||||
},
|
||||
},
|
||||
.probe = nsp_usb3_phy_probe,
|
||||
};
|
||||
|
||||
mdio_module_driver(nsp_usb3_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom NSP USB3 PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com");
|
|
@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy)
|
|||
return hi6220_phy_setup(priv, false);
|
||||
}
|
||||
|
||||
static struct phy_ops hi6220_phy_ops = {
|
||||
static const struct phy_ops hi6220_phy_ops = {
|
||||
.init = hi6220_phy_start,
|
||||
.exit = hi6220_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
|
|||
return instance->phy;
|
||||
}
|
||||
|
||||
static struct phy_ops mt65xx_u3phy_ops = {
|
||||
static const struct phy_ops mt65xx_u3phy_ops = {
|
||||
.init = mt65xx_phy_init,
|
||||
.exit = mt65xx_phy_exit,
|
||||
.power_on = mt65xx_phy_power_on,
|
||||
|
|
|
@ -77,7 +77,6 @@ struct ufs_qcom_phy_vreg {
|
|||
int min_uV;
|
||||
int max_uV;
|
||||
bool enabled;
|
||||
bool is_always_on;
|
||||
};
|
||||
|
||||
struct ufs_qcom_phy {
|
||||
|
|
|
@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
|
|||
&ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops);
|
||||
|
||||
if (!generic_phy) {
|
||||
dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
|
||||
__func__);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_qcom_phy_init_clks(phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev,
|
||||
"%s: ufs_qcom_phy_init_clks() failed %d\n",
|
||||
__func__, err);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_qcom_phy_init_vregulators(phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev,
|
||||
"%s: ufs_qcom_phy_init_vregulators() failed %d\n",
|
||||
__func__, err);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
|
||||
phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;
|
||||
|
||||
|
|
|
@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
|
|||
&ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops);
|
||||
|
||||
if (!generic_phy) {
|
||||
dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
|
||||
__func__);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_qcom_phy_init_clks(phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
|
||||
__func__, err);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_qcom_phy_init_vregulators(phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
|
||||
__func__, err);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);
|
||||
|
||||
|
|
|
@ -189,12 +189,12 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common)
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
skip_txrx_clk:
|
||||
err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src",
|
||||
&phy_common->ref_clk_src);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
skip_txrx_clk:
|
||||
/*
|
||||
* "ref_clk_parent" is optional hence don't abort init if it's not
|
||||
* found.
|
||||
|
@ -210,25 +210,19 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
|
||||
|
||||
static int __ufs_qcom_phy_init_vreg(struct device *dev,
|
||||
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
|
||||
static int ufs_qcom_phy_init_vreg(struct device *dev,
|
||||
struct ufs_qcom_phy_vreg *vreg,
|
||||
const char *name)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
char prop_name[MAX_PROP_NAME];
|
||||
|
||||
vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
|
||||
if (!vreg->name) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vreg->name = name;
|
||||
vreg->reg = devm_regulator_get(dev, name);
|
||||
if (IS_ERR(vreg->reg)) {
|
||||
err = PTR_ERR(vreg->reg);
|
||||
vreg->reg = NULL;
|
||||
if (!optional)
|
||||
dev_err(dev, "failed to get %s, %d\n", name, err);
|
||||
dev_err(dev, "failed to get %s, %d\n", name, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -248,9 +242,6 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev,
|
|||
}
|
||||
err = 0;
|
||||
}
|
||||
snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
|
||||
vreg->is_always_on = of_property_read_bool(dev->of_node,
|
||||
prop_name);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "vdda-pll")) {
|
||||
|
@ -265,17 +256,9 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev,
|
|||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
kfree(vreg->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufs_qcom_phy_init_vreg(struct device *dev,
|
||||
struct ufs_qcom_phy_vreg *vreg, const char *name)
|
||||
{
|
||||
return __ufs_qcom_phy_init_vreg(dev, vreg, name, false);
|
||||
}
|
||||
|
||||
int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
|
||||
{
|
||||
int err;
|
||||
|
@ -291,9 +274,9 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
/* vddp-ref-clk-* properties are optional */
|
||||
__ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk,
|
||||
"vddp-ref-clk", true);
|
||||
err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk,
|
||||
"vddp-ref-clk");
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -416,7 +399,7 @@ static int ufs_qcom_phy_disable_vreg(struct device *dev,
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!vreg || !vreg->enabled || vreg->is_always_on)
|
||||
if (!vreg || !vreg->enabled)
|
||||
goto out;
|
||||
|
||||
ret = regulator_disable(vreg->reg);
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/**
|
||||
* Copyright (C) 2016 Linaro Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/ulpi/driver.h>
|
||||
#include <linux/ulpi/regs.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include "ulpi_phy.h"
|
||||
|
||||
#define ULPI_PWR_CLK_MNG_REG 0x88
|
||||
# define ULPI_PWR_OTG_COMP_DISABLE BIT(0)
|
||||
|
||||
#define ULPI_MISC_A 0x96
|
||||
# define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1)
|
||||
# define ULPI_MISC_A_VBUSVLDEXT BIT(0)
|
||||
|
||||
|
||||
struct ulpi_seq {
|
||||
u8 addr;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct qcom_usb_hs_phy {
|
||||
struct ulpi *ulpi;
|
||||
struct phy *phy;
|
||||
struct clk *ref_clk;
|
||||
struct clk *sleep_clk;
|
||||
struct regulator *v1p8;
|
||||
struct regulator *v3p3;
|
||||
struct reset_control *reset;
|
||||
struct ulpi_seq *init_seq;
|
||||
struct extcon_dev *vbus_edev;
|
||||
struct notifier_block vbus_notify;
|
||||
};
|
||||
|
||||
static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||
{
|
||||
struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
|
||||
u8 addr;
|
||||
int ret;
|
||||
|
||||
if (!uphy->vbus_edev) {
|
||||
u8 val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case PHY_MODE_USB_OTG:
|
||||
case PHY_MODE_USB_HOST:
|
||||
val |= ULPI_INT_IDGRD;
|
||||
case PHY_MODE_USB_DEVICE:
|
||||
val |= ULPI_INT_SESS_VALID;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case PHY_MODE_USB_OTG:
|
||||
case PHY_MODE_USB_DEVICE:
|
||||
addr = ULPI_SET(ULPI_MISC_A);
|
||||
break;
|
||||
case PHY_MODE_USB_HOST:
|
||||
addr = ULPI_CLR(ULPI_MISC_A);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG),
|
||||
ULPI_PWR_OTG_COMP_DISABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct qcom_usb_hs_phy *uphy;
|
||||
u8 addr;
|
||||
|
||||
uphy = container_of(nb, struct qcom_usb_hs_phy, vbus_notify);
|
||||
|
||||
if (event)
|
||||
addr = ULPI_SET(ULPI_MISC_A);
|
||||
else
|
||||
addr = ULPI_CLR(ULPI_MISC_A);
|
||||
|
||||
return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT);
|
||||
}
|
||||
|
||||
static int qcom_usb_hs_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
|
||||
struct ulpi *ulpi = uphy->ulpi;
|
||||
const struct ulpi_seq *seq;
|
||||
int ret, state;
|
||||
|
||||
ret = clk_prepare_enable(uphy->ref_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(uphy->sleep_clk);
|
||||
if (ret)
|
||||
goto err_sleep;
|
||||
|
||||
ret = regulator_set_load(uphy->v1p8, 50000);
|
||||
if (ret < 0)
|
||||
goto err_1p8;
|
||||
|
||||
ret = regulator_enable(uphy->v1p8);
|
||||
if (ret)
|
||||
goto err_1p8;
|
||||
|
||||
ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000,
|
||||
3300000);
|
||||
if (ret)
|
||||
goto err_3p3;
|
||||
|
||||
ret = regulator_set_load(uphy->v3p3, 50000);
|
||||
if (ret < 0)
|
||||
goto err_3p3;
|
||||
|
||||
ret = regulator_enable(uphy->v3p3);
|
||||
if (ret)
|
||||
goto err_3p3;
|
||||
|
||||
for (seq = uphy->init_seq; seq->addr; seq++) {
|
||||
ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr,
|
||||
seq->val);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
}
|
||||
|
||||
if (uphy->reset) {
|
||||
ret = reset_control_reset(uphy->reset);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
}
|
||||
|
||||
if (uphy->vbus_edev) {
|
||||
state = extcon_get_cable_state_(uphy->vbus_edev, EXTCON_USB);
|
||||
/* setup initial state */
|
||||
qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state,
|
||||
uphy->vbus_edev);
|
||||
ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB,
|
||||
&uphy->vbus_notify);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_ulpi:
|
||||
regulator_disable(uphy->v3p3);
|
||||
err_3p3:
|
||||
regulator_disable(uphy->v1p8);
|
||||
err_1p8:
|
||||
clk_disable_unprepare(uphy->sleep_clk);
|
||||
err_sleep:
|
||||
clk_disable_unprepare(uphy->ref_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_usb_hs_phy_power_off(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
|
||||
|
||||
if (uphy->vbus_edev) {
|
||||
ret = extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB,
|
||||
&uphy->vbus_notify);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
regulator_disable(uphy->v3p3);
|
||||
regulator_disable(uphy->v1p8);
|
||||
clk_disable_unprepare(uphy->sleep_clk);
|
||||
clk_disable_unprepare(uphy->ref_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops qcom_usb_hs_phy_ops = {
|
||||
.power_on = qcom_usb_hs_phy_power_on,
|
||||
.power_off = qcom_usb_hs_phy_power_off,
|
||||
.set_mode = qcom_usb_hs_phy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
|
||||
{
|
||||
struct qcom_usb_hs_phy *uphy;
|
||||
struct phy_provider *p;
|
||||
struct clk *clk;
|
||||
struct regulator *reg;
|
||||
struct reset_control *reset;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
|
||||
if (!uphy)
|
||||
return -ENOMEM;
|
||||
ulpi_set_drvdata(ulpi, uphy);
|
||||
uphy->ulpi = ulpi;
|
||||
|
||||
size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq");
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1,
|
||||
sizeof(*uphy->init_seq), GFP_KERNEL);
|
||||
if (!uphy->init_seq)
|
||||
return -ENOMEM;
|
||||
ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq",
|
||||
(u8 *)uphy->init_seq, size);
|
||||
if (ret && size)
|
||||
return ret;
|
||||
/* NUL terminate */
|
||||
uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0;
|
||||
|
||||
uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
uphy->sleep_clk = clk = devm_clk_get(&ulpi->dev, "sleep");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
uphy->v1p8 = reg = devm_regulator_get(&ulpi->dev, "v1p8");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
uphy->v3p3 = reg = devm_regulator_get(&ulpi->dev, "v3p3");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por");
|
||||
if (IS_ERR(reset)) {
|
||||
if (PTR_ERR(reset) == -EPROBE_DEFER)
|
||||
return PTR_ERR(reset);
|
||||
uphy->reset = NULL;
|
||||
}
|
||||
|
||||
uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
|
||||
&qcom_usb_hs_phy_ops);
|
||||
if (IS_ERR(uphy->phy))
|
||||
return PTR_ERR(uphy->phy);
|
||||
|
||||
uphy->vbus_edev = extcon_get_edev_by_phandle(&ulpi->dev, 0);
|
||||
if (IS_ERR(uphy->vbus_edev)) {
|
||||
if (PTR_ERR(uphy->vbus_edev) != -ENODEV)
|
||||
return PTR_ERR(uphy->vbus_edev);
|
||||
uphy->vbus_edev = NULL;
|
||||
}
|
||||
|
||||
uphy->vbus_notify.notifier_call = qcom_usb_hs_phy_vbus_notifier;
|
||||
phy_set_drvdata(uphy->phy, uphy);
|
||||
|
||||
p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
|
||||
return PTR_ERR_OR_ZERO(p);
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_usb_hs_phy_match[] = {
|
||||
{ .compatible = "qcom,usb-hs-phy", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_usb_hs_phy_match);
|
||||
|
||||
static struct ulpi_driver qcom_usb_hs_phy_driver = {
|
||||
.probe = qcom_usb_hs_phy_probe,
|
||||
.driver = {
|
||||
.name = "qcom_usb_hs_phy",
|
||||
.of_match_table = qcom_usb_hs_phy_match,
|
||||
},
|
||||
};
|
||||
module_ulpi_driver(qcom_usb_hs_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm USB HS phy");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* Copyright (C) 2016 Linaro Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/ulpi/driver.h>
|
||||
#include <linux/ulpi/regs.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl-state.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "ulpi_phy.h"
|
||||
|
||||
#define ULPI_HSIC_CFG 0x30
|
||||
#define ULPI_HSIC_IO_CAL 0x33
|
||||
|
||||
struct qcom_usb_hsic_phy {
|
||||
struct ulpi *ulpi;
|
||||
struct phy *phy;
|
||||
struct pinctrl *pctl;
|
||||
struct clk *phy_clk;
|
||||
struct clk *cal_clk;
|
||||
struct clk *cal_sleep_clk;
|
||||
};
|
||||
|
||||
static int qcom_usb_hsic_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
|
||||
struct ulpi *ulpi = uphy->ulpi;
|
||||
struct pinctrl_state *pins_default;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(uphy->phy_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(uphy->cal_clk);
|
||||
if (ret)
|
||||
goto err_cal;
|
||||
|
||||
ret = clk_prepare_enable(uphy->cal_sleep_clk);
|
||||
if (ret)
|
||||
goto err_sleep;
|
||||
|
||||
/* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
|
||||
ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
|
||||
/* Enable periodic IO calibration in HSIC_CFG register */
|
||||
ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
|
||||
/* Configure pins for HSIC functionality */
|
||||
pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT);
|
||||
if (IS_ERR(pins_default))
|
||||
return PTR_ERR(pins_default);
|
||||
|
||||
ret = pinctrl_select_state(uphy->pctl, pins_default);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
|
||||
/* Enable HSIC mode in HSIC_CFG register */
|
||||
ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
|
||||
/* Disable auto-resume */
|
||||
ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL),
|
||||
ULPI_IFC_CTRL_AUTORESUME);
|
||||
if (ret)
|
||||
goto err_ulpi;
|
||||
|
||||
return ret;
|
||||
err_ulpi:
|
||||
clk_disable_unprepare(uphy->cal_sleep_clk);
|
||||
err_sleep:
|
||||
clk_disable_unprepare(uphy->cal_clk);
|
||||
err_cal:
|
||||
clk_disable_unprepare(uphy->phy_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_usb_hsic_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(uphy->cal_sleep_clk);
|
||||
clk_disable_unprepare(uphy->cal_clk);
|
||||
clk_disable_unprepare(uphy->phy_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops qcom_usb_hsic_phy_ops = {
|
||||
.power_on = qcom_usb_hsic_phy_power_on,
|
||||
.power_off = qcom_usb_hsic_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi)
|
||||
{
|
||||
struct qcom_usb_hsic_phy *uphy;
|
||||
struct phy_provider *p;
|
||||
struct clk *clk;
|
||||
|
||||
uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
|
||||
if (!uphy)
|
||||
return -ENOMEM;
|
||||
ulpi_set_drvdata(ulpi, uphy);
|
||||
|
||||
uphy->ulpi = ulpi;
|
||||
uphy->pctl = devm_pinctrl_get(&ulpi->dev);
|
||||
if (IS_ERR(uphy->pctl))
|
||||
return PTR_ERR(uphy->pctl);
|
||||
|
||||
uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
|
||||
&qcom_usb_hsic_phy_ops);
|
||||
if (IS_ERR(uphy->phy))
|
||||
return PTR_ERR(uphy->phy);
|
||||
phy_set_drvdata(uphy->phy, uphy);
|
||||
|
||||
p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
|
||||
return PTR_ERR_OR_ZERO(p);
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_usb_hsic_phy_match[] = {
|
||||
{ .compatible = "qcom,usb-hsic-phy", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match);
|
||||
|
||||
static struct ulpi_driver qcom_usb_hsic_phy_driver = {
|
||||
.probe = qcom_usb_hsic_phy_probe,
|
||||
.driver = {
|
||||
.name = "qcom_usb_hsic_phy",
|
||||
.of_match_table = qcom_usb_hsic_phy_match,
|
||||
},
|
||||
};
|
||||
module_ulpi_driver(qcom_usb_hsic_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm USB HSIC phy");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -94,11 +94,11 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
|||
work);
|
||||
|
||||
if (ch->extcon_host) {
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
|
||||
extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true);
|
||||
extcon_set_state_sync(ch->extcon, EXTCON_USB, false);
|
||||
} else {
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
|
||||
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
|
||||
extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false);
|
||||
extcon_set_state_sync(ch->extcon, EXTCON_USB, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct phy_ops rcar_gen3_phy_usb2_ops = {
|
||||
static const 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,
|
||||
|
|
|
@ -595,9 +595,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
|||
if (rport->vbus_attached != vbus_attach) {
|
||||
rport->vbus_attached = vbus_attach;
|
||||
|
||||
if (notify_charger && rphy->edev)
|
||||
if (notify_charger && rphy->edev) {
|
||||
extcon_set_cable_state_(rphy->edev,
|
||||
cable, vbus_attach);
|
||||
if (cable == EXTCON_CHG_USB_SDP)
|
||||
extcon_set_state_sync(rphy->edev,
|
||||
EXTCON_USB,
|
||||
vbus_attach);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_B_PERIPHERAL:
|
||||
|
|
|
@ -99,6 +99,7 @@ enum sun4i_usb_phy_type {
|
|||
sun6i_a31_phy,
|
||||
sun8i_a33_phy,
|
||||
sun8i_h3_phy,
|
||||
sun8i_v3s_phy,
|
||||
sun50i_a64_phy,
|
||||
};
|
||||
|
||||
|
@ -188,7 +189,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
|
|||
spin_lock_irqsave(&phy_data->reg_lock, flags);
|
||||
|
||||
if (phy_data->cfg->type == sun8i_a33_phy ||
|
||||
phy_data->cfg->type == sun50i_a64_phy) {
|
||||
phy_data->cfg->type == sun50i_a64_phy ||
|
||||
phy_data->cfg->type == sun8i_v3s_phy) {
|
||||
/* A33 or A64 needs us to set phyctl to 0 explicitly */
|
||||
writel(0, phyctl);
|
||||
}
|
||||
|
@ -534,7 +536,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
|||
mutex_unlock(&phy0->mutex);
|
||||
|
||||
if (id_notify) {
|
||||
extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
|
||||
extcon_set_state_sync(data->extcon, EXTCON_USB_HOST,
|
||||
!id_det);
|
||||
/* When leaving host mode force end the session here */
|
||||
if (force_session_end && id_det == 1) {
|
||||
|
@ -547,7 +549,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (vbus_notify)
|
||||
extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
|
||||
extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det);
|
||||
|
||||
if (sun4i_usb_phy0_poll(data))
|
||||
queue_delayed_work(system_wq, &data->detect, POLL_TIME);
|
||||
|
@ -825,6 +827,15 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
|
|||
.enable_pmu_unk1 = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
||||
.num_phys = 1,
|
||||
.type = sun8i_v3s_phy,
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
||||
.num_phys = 2,
|
||||
.type = sun50i_a64_phy,
|
||||
|
@ -842,6 +853,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
|||
{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
|
||||
{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
|
||||
{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
|
||||
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
|
||||
{ .compatible = "allwinner,sun50i-a64-usb-phy",
|
||||
.data = &sun50i_a64_cfg},
|
||||
{ },
|
||||
|
|
Loading…
Reference in New Issue