Commit 1859a772 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-5.9' of...

Merge tag 'phy-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into char-misc-next

Vinod writes:

phy for 5.9

 - New PHY Drivers:
   - Samsung UFS
   - Qcom USB DWC for ipq806x
   - Xilinx ZynqMP Gigabit Transceiver
   - Qcom USB QMP for IPQ8074
   - BCM63xx USBH

 - Removed:
   - Qcom ufs qmp phy driver

 - Updates:
   - Support for Qcom SM8250 QMP V4 USB3 UNIPHY
   - qcom-snps runtime pm support
   - Cleanup of W=1 warns in the subsystem

* tag 'phy-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (46 commits)
  phy: qualcomm: fix setting of tx_deamp_3_5db when device property read fails
  phy: bcm63xx-usbh: Add BCM63xx USBH driver
  dt-bindings: phy: add bcm63xx-usbh bindings
  phy: armada-38x: fix NETA lockup when repeatedly switching speeds
  dt: update Marvell Armada 38x COMPHY binding
  phy: samsung-ufs: Fix IS_ERR argument
  dt-bindings: phy: renesas,usb3-phy: Add r8a774e1 support
  dt-bindings: phy: renesas,usb2-phy: Add r8a774e1 support
  phy: renesas: rcar-gen3-usb2: exit if request_irq() failed
  phy: renesas: rcar-gen3-usb2: move irq registration to init
  devicetree: bindings: phy: Document ipq806x dwc3 qcom phy
  phy: qualcomm: add qcom ipq806x dwc usb phy driver
  phy: samsung-ufs: add UFS PHY driver for samsung SoC
  dt-bindings: phy: Document Samsung UFS PHY bindings
  phy: sun4i-usb: explicitly include gpio/consumer.h
  phy: stm32: use NULL instead of zero
  phy: exynos5-usbdrd: use correct format for structure description
  phy: rockchip-typec: use correct format for structure description
  phy: xgene: remove unsigned integer comparison with less than zero
  phy: mapphone-mdm6600: Add missing description for some structure fields
  ...
parents 4e74eeb2 3d7b0ca5
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: BCM63xx USBH PHY
maintainers:
- Álvaro Fernández Rojas <noltari@gmail.com>
properties:
compatible:
enum:
- brcm,bcm6318-usbh-phy
- brcm,bcm6328-usbh-phy
- brcm,bcm6358-usbh-phy
- brcm,bcm6362-usbh-phy
- brcm,bcm6368-usbh-phy
- brcm,bcm63268-usbh-phy
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: usbh
- const: usb_ref
resets:
maxItems: 1
"#phy-cells":
const: 1
additionalProperties: false
required:
- compatible
- reg
- clocks
- clock-names
- resets
- "#phy-cells"
if:
properties:
compatible:
enum:
- brcm,bcm6318-usbh-phy
- brcm,bcm6328-usbh-phy
- brcm,bcm6362-usbh-phy
- brcm,bcm63268-usbh-phy
then:
properties:
power-domains:
maxItems: 1
required:
- power-domains
else:
properties:
power-domains: false
examples:
- |
usbh: usb-phy@10001700 {
compatible = "brcm,bcm6368-usbh-phy";
reg = <0x10001700 0x38>;
clocks = <&periph_clk 15>;
clock-names = "usbh";
resets = <&periph_rst 12>;
#phy-cells = <1>;
};
...@@ -12,6 +12,13 @@ Required properties: ...@@ -12,6 +12,13 @@ Required properties:
- #address-cells: should be 1. - #address-cells: should be 1.
- #size-cells: should be 0. - #size-cells: should be 0.
Optional properties:
- reg-names: must be "comphy" as the first name, and "conf".
- reg: must contain the comphy register location and length as the first
pair, followed by an optional configuration register address and
length pair.
A sub-node is required for each comphy lane provided by the comphy. A sub-node is required for each comphy lane provided by the comphy.
Required properties (child nodes): Required properties (child nodes):
...@@ -24,7 +31,8 @@ Example: ...@@ -24,7 +31,8 @@ Example:
comphy: phy@18300 { comphy: phy@18300 {
compatible = "marvell,armada-380-comphy"; compatible = "marvell,armada-380-comphy";
reg = <0x18300 0x100>; reg-names = "comphy", "conf";
reg = <0x18300 0x100>, <0x18460 4>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-hs.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm ipq806x usb DWC3 HS PHY CONTROLLER
maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
description:
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
controllers used in ipq806x. Each DWC3 PHY controller should have its
own node.
properties:
compatible:
const: qcom,ipq806x-usb-phy-hs
"#phy-cells":
const: 0
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: ref
- const: xo
required:
- compatible
- "#phy-cells"
- reg
- clocks
- clock-names
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
hs_phy_0: phy@110f8800 {
compatible = "qcom,ipq806x-usb-phy-hs";
reg = <0x110f8800 0x30>;
clocks = <&gcc USB30_0_UTMI_CLK>;
clock-names = "ref";
#phy-cells = <0>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-ss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm ipq806x usb DWC3 SS PHY CONTROLLER
maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
description:
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
controllers used in ipq806x. Each DWC3 PHY controller should have its
own node.
properties:
compatible:
const: qcom,ipq806x-usb-phy-ss
"#phy-cells":
const: 0
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: ref
- const: xo
qcom,rx-eq:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for rx_eq.
default: 4
maximum: 7
qcom,tx-deamp-3_5db:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for transmit preemphasis.
default: 23
maximum: 63
qcom,mpll:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for mpll.
default: 0
maximum: 7
required:
- compatible
- "#phy-cells"
- reg
- clocks
- clock-names
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
ss_phy_0: phy@110f8830 {
compatible = "qcom,ipq806x-usb-phy-ss";
reg = <0x110f8830 0x30>;
clocks = <&gcc USB30_0_MASTER_CLK>;
clock-names = "ref";
#phy-cells = <0>;
};
...@@ -18,6 +18,7 @@ properties: ...@@ -18,6 +18,7 @@ properties:
compatible: compatible:
enum: enum:
- qcom,ipq8074-qmp-pcie-phy - qcom,ipq8074-qmp-pcie-phy
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-pcie-phy - qcom,msm8996-qmp-pcie-phy
- qcom,msm8996-qmp-ufs-phy - qcom,msm8996-qmp-ufs-phy
- qcom,msm8996-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy
...@@ -161,6 +162,7 @@ allOf: ...@@ -161,6 +162,7 @@ allOf:
compatible: compatible:
contains: contains:
enum: enum:
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-pcie-phy - qcom,msm8998-qmp-pcie-phy
- qcom,msm8998-qmp-usb3-phy - qcom,msm8998-qmp-usb3-phy
......
...@@ -18,6 +18,7 @@ properties: ...@@ -18,6 +18,7 @@ properties:
oneOf: oneOf:
- items: - items:
- enum: - enum:
- qcom,ipq8074-qusb2-phy
- qcom,msm8996-qusb2-phy - qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy - qcom,msm8998-qusb2-phy
- items: - items:
......
...@@ -21,6 +21,7 @@ properties: ...@@ -21,6 +21,7 @@ properties:
- renesas,usb2-phy-r8a774a1 # RZ/G2M - renesas,usb2-phy-r8a774a1 # RZ/G2M
- renesas,usb2-phy-r8a774b1 # RZ/G2N - renesas,usb2-phy-r8a774b1 # RZ/G2N
- renesas,usb2-phy-r8a774c0 # RZ/G2E - renesas,usb2-phy-r8a774c0 # RZ/G2E
- renesas,usb2-phy-r8a774e1 # RZ/G2H
- renesas,usb2-phy-r8a7795 # R-Car H3 - renesas,usb2-phy-r8a7795 # R-Car H3
- renesas,usb2-phy-r8a7796 # R-Car M3-W - renesas,usb2-phy-r8a7796 # R-Car M3-W
- renesas,usb2-phy-r8a77961 # R-Car M3-W+ - renesas,usb2-phy-r8a77961 # R-Car M3-W+
......
...@@ -15,6 +15,7 @@ properties: ...@@ -15,6 +15,7 @@ properties:
- enum: - enum:
- renesas,r8a774a1-usb3-phy # RZ/G2M - renesas,r8a774a1-usb3-phy # RZ/G2M
- renesas,r8a774b1-usb3-phy # RZ/G2N - renesas,r8a774b1-usb3-phy # RZ/G2N
- renesas,r8a774e1-usb3-phy # RZ/G2H
- renesas,r8a7795-usb3-phy # R-Car H3 - renesas,r8a7795-usb3-phy # R-Car H3
- renesas,r8a7796-usb3-phy # R-Car M3-W - renesas,r8a7796-usb3-phy # R-Car M3-W
- renesas,r8a77961-usb3-phy # R-Car M3-W+ - renesas,r8a77961-usb3-phy # R-Car M3-W+
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/samsung,ufs-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series UFS PHY Device Tree Bindings
maintainers:
- Alim Akhtar <alim.akhtar@samsung.com>
properties:
"#phy-cells":
const: 0
compatible:
enum:
- samsung,exynos7-ufs-phy
reg:
maxItems: 1
reg-names:
items:
- const: phy-pma
clocks:
items:
- description: PLL reference clock
- description: symbol clock for input symbol ( rx0-ch0 symbol clock)
- description: symbol clock for input symbol ( rx1-ch1 symbol clock)
- description: symbol clock for output symbol ( tx0 symbol clock)
clock-names:
items:
- const: ref_clk
- const: rx1_symbol_clk
- const: rx0_symbol_clk
- const: tx0_symbol_clk
samsung,pmu-syscon:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for PMU system controller interface, used to
control pmu registers bits for ufs m-phy
required:
- "#phy-cells"
- compatible
- reg
- reg-names
- clocks
- clock-names
- samsung,pmu-syscon
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos7-clk.h>
ufs_phy: ufs-phy@15571800 {
compatible = "samsung,exynos7-ufs-phy";
reg = <0x15571800 0x240>;
reg-names = "phy-pma";
samsung,pmu-syscon = <&pmu_system_controller>;
#phy-cells = <0>;
clocks = <&clock_fsys1 SCLK_COMBO_PHY_EMBEDDED_26M>,
<&clock_fsys1 PHYCLK_UFS20_RX1_SYMBOL_USER>,
<&clock_fsys1 PHYCLK_UFS20_RX0_SYMBOL_USER>,
<&clock_fsys1 PHYCLK_UFS20_TX0_SYMBOL_USER>;
clock-names = "ref_clk", "rx1_symbol_clk",
"rx0_symbol_clk", "tx0_symbol_clk";
};
...
...@@ -31,12 +31,16 @@ properties: ...@@ -31,12 +31,16 @@ properties:
clocks: clocks:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 3
clock-names: clock-names:
oneOf: oneOf:
- const: link # for PXs2 - const: link # for PXs2
- items: # for PXs3 - items: # for PXs3 with phy-ext
- const: link
- const: phy
- const: phy-ext
- items: # for others
- const: link - const: link
- const: phy - const: phy
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/xlnx,zynqmp-psgtr.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx ZynqMP Gigabit Transceiver PHY Device Tree Bindings
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
description: |
This binding describes the Xilinx ZynqMP Gigabit Transceiver (GTR) PHY. The
GTR provides four lanes and is used by USB, SATA, PCIE, Display port and
Ethernet SGMII controllers.
properties:
"#phy-cells":
const: 4
description: |
The cells contain the following arguments.
- description: The GTR lane
minimum: 0
maximum: 3
- description: The PHY type
enum:
- PHY_TYPE_DP
- PHY_TYPE_PCIE
- PHY_TYPE_SATA
- PHY_TYPE_SGMII
- PHY_TYPE_USB
- description: The PHY instance
minimum: 0
maximum: 1 # for DP, SATA or USB
maximum: 3 # for PCIE or SGMII
- description: The reference clock number
minimum: 0
maximum: 3
compatible:
enum:
- xlnx,zynqmp-psgtr-v1.1
- xlnx,zynqmp-psgtr
clocks:
minItems: 1
maxItems: 4
description: |
Clock for each PS_MGTREFCLK[0-3] reference clock input. Unconnected
inputs shall not have an entry.
clock-names:
minItems: 1
maxItems: 4
items:
pattern: "^ref[0-3]$"
reg:
items:
- description: SERDES registers block
- description: SIOU registers block
reg-names:
items:
- const: serdes
- const: siou
xlnx,tx-termination-fix:
description: |
Include this for fixing functional issue with the TX termination
resistance in GT, which can be out of spec for the XCZU9EG silicon
version.
type: boolean
required:
- "#phy-cells"
- compatible
- reg
- reg-names
if:
properties:
compatible:
const: xlnx,zynqmp-psgtr-v1.1
then:
properties:
xlnx,tx-termination-fix: false
additionalProperties: false
examples:
- |
phy: phy@fd400000 {
compatible = "xlnx,zynqmp-psgtr-v1.1";
reg = <0xfd400000 0x40000>,
<0xfd3d0000 0x1000>;
reg-names = "serdes", "siou";
clocks = <&refclks 3>, <&refclks 2>, <&refclks 0>;
clock-names = "ref1", "ref2", "ref3";
#phy-cells = <4>;
};
...
...@@ -18862,6 +18862,15 @@ F: Documentation/devicetree/bindings/media/xilinx/ ...@@ -18862,6 +18862,15 @@ F: Documentation/devicetree/bindings/media/xilinx/
F: drivers/media/platform/xilinx/ F: drivers/media/platform/xilinx/
F: include/uapi/linux/xilinx-v4l2-controls.h F: include/uapi/linux/xilinx-v4l2-controls.h
XILINX ZYNQMP PSGTR PHY DRIVER
M: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-kernel@vger.kernel.org
S: Supported
T: git https://github.com/Xilinx/linux-xlnx.git
F: Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
F: drivers/phy/xilinx/phy-zynqmp.c
XILLYBUS DRIVER XILLYBUS DRIVER
M: Eli Billauer <eli.billauer@gmail.com> M: Eli Billauer <eli.billauer@gmail.com>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
......
...@@ -70,5 +70,6 @@ source "drivers/phy/st/Kconfig" ...@@ -70,5 +70,6 @@ source "drivers/phy/st/Kconfig"
source "drivers/phy/tegra/Kconfig" source "drivers/phy/tegra/Kconfig"
source "drivers/phy/ti/Kconfig" source "drivers/phy/ti/Kconfig"
source "drivers/phy/intel/Kconfig" source "drivers/phy/intel/Kconfig"
source "drivers/phy/xilinx/Kconfig"
endmenu endmenu
...@@ -8,24 +8,25 @@ obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o ...@@ -8,24 +8,25 @@ obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_ARCH_SUNXI) += allwinner/ obj-y += allwinner/ \
obj-$(CONFIG_ARCH_MESON) += amlogic/ amlogic/ \
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ broadcom/ \
obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += broadcom/ \
cadence/ \ cadence/ \
freescale/ \ freescale/ \
hisilicon/ \ hisilicon/ \
intel/ \ intel/ \
lantiq/ \ lantiq/ \
marvell/ \ marvell/ \
mediatek/ \
motorola/ \ motorola/ \
mscc/ \ mscc/ \
qualcomm/ \ qualcomm/ \
ralink/ \ ralink/ \
renesas/ \
rockchip/ \
samsung/ \ samsung/ \
socionext/ \ socionext/ \
st/ \ st/ \
ti/ tegra/ \
ti/ \
xilinx/
...@@ -22,7 +22,7 @@ config PHY_SUN4I_USB ...@@ -22,7 +22,7 @@ config PHY_SUN4I_USB
config PHY_SUN6I_MIPI_DPHY config PHY_SUN6I_MIPI_DPHY
tristate "Allwinner A31 MIPI D-PHY Support" tristate "Allwinner A31 MIPI D-PHY Support"
depends on ARCH_SUNXI || COMPILE_TEST depends on ARCH_SUNXI || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM && COMMON_CLK
depends on RESET_CONTROLLER depends on RESET_CONTROLLER
select GENERIC_PHY select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY select GENERIC_PHY_MIPI_DPHY
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Based on code from * Based on code from
* Allwinner Technology Co., Ltd. <www.allwinnertech.com> * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* *
* Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver * Modelled after: Samsung S5P/Exynos SoC series MIPI CSIS/DSIM DPHY driver
* Copyright (C) 2013 Samsung Electronics Co., Ltd. * Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com> * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
*/ */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/extcon-provider.h> #include <linux/extcon-provider.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -233,7 +233,7 @@ static int sun6i_dphy_exit(struct phy *phy) ...@@ -233,7 +233,7 @@ static int sun6i_dphy_exit(struct phy *phy)
} }
static struct phy_ops sun6i_dphy_ops = { static const struct phy_ops sun6i_dphy_ops = {
.configure = sun6i_dphy_configure, .configure = sun6i_dphy_configure,
.power_on = sun6i_dphy_power_on, .power_on = sun6i_dphy_power_on,
.power_off = sun6i_dphy_power_off, .power_off = sun6i_dphy_power_off,
...@@ -241,7 +241,7 @@ static struct phy_ops sun6i_dphy_ops = { ...@@ -241,7 +241,7 @@ static struct phy_ops sun6i_dphy_ops = {
.exit = sun6i_dphy_exit, .exit = sun6i_dphy_exit,
}; };
static struct regmap_config sun6i_dphy_regmap_config = { static const struct regmap_config sun6i_dphy_regmap_config = {
.reg_bits = 32, .reg_bits = 32,
.val_bits = 32, .val_bits = 32,
.reg_stride = 4, .reg_stride = 4,
......
...@@ -2,6 +2,14 @@ ...@@ -2,6 +2,14 @@
# #
# Phy drivers for Broadcom platforms # Phy drivers for Broadcom platforms
# #
config PHY_BCM63XX_USBH
tristate "BCM63xx USBH PHY driver"
depends on BMIPS_GENERIC || COMPILE_TEST
select GENERIC_PHY
help
Enable this to support the BCM63xx USBH PHY driver.
If unsure, say N.
config PHY_CYGNUS_PCIE config PHY_CYGNUS_PCIE
tristate "Broadcom Cygnus PCIe PHY driver" tristate "Broadcom Cygnus PCIe PHY driver"
depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST)
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_BCM63XX_USBH) += phy-bcm63xx-usbh.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
......
This diff is collapsed.
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
#define TB_ADDR_TX_RCVDETSC_CTRL 0x4124 #define TB_ADDR_TX_RCVDETSC_CTRL 0x4124
/* TB_ADDR_TX_RCVDETSC_CTRL */ /* TB_ADDR_TX_RCVDETSC_CTRL */
#define RXDET_IN_P3_32KHZ BIT(1) #define RXDET_IN_P3_32KHZ BIT(0)
struct cdns_reg_pairs { struct cdns_reg_pairs {
u16 val; u16 val;
......
...@@ -41,6 +41,7 @@ struct a38x_comphy_lane { ...@@ -41,6 +41,7 @@ struct a38x_comphy_lane {
struct a38x_comphy { struct a38x_comphy {
void __iomem *base; void __iomem *base;
void __iomem *conf;
struct device *dev; struct device *dev;
struct a38x_comphy_lane lane[MAX_A38X_COMPHY]; struct a38x_comphy_lane lane[MAX_A38X_COMPHY];
}; };
...@@ -54,6 +55,21 @@ static const u8 gbe_mux[MAX_A38X_COMPHY][MAX_A38X_PORTS] = { ...@@ -54,6 +55,21 @@ static const u8 gbe_mux[MAX_A38X_COMPHY][MAX_A38X_PORTS] = {
{ 0, 0, 3 }, { 0, 0, 3 },
}; };
static void a38x_set_conf(struct a38x_comphy_lane *lane, bool enable)
{
struct a38x_comphy *priv = lane->priv;
u32 conf;
if (priv->conf) {
conf = readl_relaxed(priv->conf);
if (enable)
conf |= BIT(lane->port);
else
conf &= ~BIT(lane->port);
writel(conf, priv->conf);
}
}
static void a38x_comphy_set_reg(struct a38x_comphy_lane *lane, static void a38x_comphy_set_reg(struct a38x_comphy_lane *lane,
unsigned int offset, u32 mask, u32 value) unsigned int offset, u32 mask, u32 value)
{ {
...@@ -97,6 +113,7 @@ static int a38x_comphy_set_mode(struct phy *phy, enum phy_mode mode, int sub) ...@@ -97,6 +113,7 @@ static int a38x_comphy_set_mode(struct phy *phy, enum phy_mode mode, int sub)
{ {
struct a38x_comphy_lane *lane = phy_get_drvdata(phy); struct a38x_comphy_lane *lane = phy_get_drvdata(phy);
unsigned int gen; unsigned int gen;
int ret;
if (mode != PHY_MODE_ETHERNET) if (mode != PHY_MODE_ETHERNET)
return -EINVAL; return -EINVAL;
...@@ -115,13 +132,20 @@ static int a38x_comphy_set_mode(struct phy *phy, enum phy_mode mode, int sub) ...@@ -115,13 +132,20 @@ static int a38x_comphy_set_mode(struct phy *phy, enum phy_mode mode, int sub)
return -EINVAL; return -EINVAL;
} }
a38x_set_conf(lane, false);
a38x_comphy_set_speed(lane, gen, gen); a38x_comphy_set_speed(lane, gen, gen);
return a38x_comphy_poll(lane, COMPHY_STAT1, ret = a38x_comphy_poll(lane, COMPHY_STAT1,
COMPHY_STAT1_PLL_RDY_TX | COMPHY_STAT1_PLL_RDY_TX |
COMPHY_STAT1_PLL_RDY_RX, COMPHY_STAT1_PLL_RDY_RX,
COMPHY_STAT1_PLL_RDY_TX | COMPHY_STAT1_PLL_RDY_TX |
COMPHY_STAT1_PLL_RDY_RX); COMPHY_STAT1_PLL_RDY_RX);
if (ret == 0)
a38x_set_conf(lane, true);
return ret;
} }
static const struct phy_ops a38x_comphy_ops = { static const struct phy_ops a38x_comphy_ops = {
...@@ -174,14 +198,21 @@ static int a38x_comphy_probe(struct platform_device *pdev) ...@@ -174,14 +198,21 @@ static int a38x_comphy_probe(struct platform_device *pdev)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_platform_ioremap_resource(pdev, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_ERR(base); return PTR_ERR(base);
priv->dev = &pdev->dev; priv->dev = &pdev->dev;
priv->base = base; priv->base = base;
/* Optional */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "conf");
if (res) {
priv->conf = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->conf))
return PTR_ERR(priv->conf);
}
for_each_available_child_of_node(pdev->dev.of_node, child) { for_each_available_child_of_node(pdev->dev.of_node, child) {
struct phy *phy; struct phy *phy;
int ret; int ret;
......
...@@ -72,7 +72,7 @@ struct mvebu_a3700_utmi_caps { ...@@ -72,7 +72,7 @@ struct mvebu_a3700_utmi_caps {
* struct mvebu_a3700_utmi - PHY driver data * struct mvebu_a3700_utmi - PHY driver data
* *
* @regs: PHY registers * @regs: PHY registers
* @usb_mis: Regmap with USB miscellaneous registers including PHY ones * @usb_misc: Regmap with USB miscellaneous registers including PHY ones
* @caps: PHY capabilities * @caps: PHY capabilities
* @phy: PHY handle * @phy: PHY handle
*/ */
......
...@@ -178,6 +178,7 @@ static const struct phy_ops gpio_usb_ops = { ...@@ -178,6 +178,7 @@ static const struct phy_ops gpio_usb_ops = {
/** /**
* phy_mdm6600_cmd() - send a command request to mdm6600 * phy_mdm6600_cmd() - send a command request to mdm6600
* @ddata: device driver data * @ddata: device driver data
* @val: value of cmd to be set
* *
* Configures the three command request GPIOs to the specified value. * Configures the three command request GPIOs to the specified value.
*/ */
...@@ -194,7 +195,7 @@ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) ...@@ -194,7 +195,7 @@ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
/** /**
* phy_mdm6600_status() - read mdm6600 status lines * phy_mdm6600_status() - read mdm6600 status lines
* @ddata: device driver data * @work: work structure
*/ */
static void phy_mdm6600_status(struct work_struct *work) static void phy_mdm6600_status(struct work_struct *work)
{ {
......
...@@ -1062,6 +1062,7 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register); ...@@ -1062,6 +1062,7 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register);
* __devm_of_phy_provider_register() - create/register phy provider with the * __devm_of_phy_provider_register() - create/register phy provider with the
* framework * framework
* @dev: struct device of the phy provider * @dev: struct device of the phy provider
* @children: device node containing children (if different from dev->of_node)
* @owner: the module owner containing of_xlate * @owner: the module owner containing of_xlate
* @of_xlate: function pointer to obtain phy instance from phy provider * @of_xlate: function pointer to obtain phy instance from phy provider
* *
...@@ -1117,12 +1118,14 @@ EXPORT_SYMBOL_GPL(of_phy_provider_unregister); ...@@ -1117,12 +1118,14 @@ EXPORT_SYMBOL_GPL(of_phy_provider_unregister);
/** /**
* devm_of_phy_provider_unregister() - remove phy provider from the framework * devm_of_phy_provider_unregister() - remove phy provider from the framework
* @dev: struct device of the phy provider * @dev: struct device of the phy provider
* @phy_provider: phy provider returned by of_phy_provider_register()
* *
* destroys the devres associated with this phy provider and invokes * destroys the devres associated with this phy provider and invokes
* of_phy_provider_unregister to unregister the phy provider. * of_phy_provider_unregister to unregister the phy provider.
*/ */
void devm_of_phy_provider_unregister(struct device *dev, void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider) { struct phy_provider *phy_provider)
{
int r; int r;
r = devres_destroy(dev, devm_phy_provider_release, devm_phy_match, r = devres_destroy(dev, devm_phy_provider_release, devm_phy_match,
......
...@@ -1615,7 +1615,7 @@ static struct phy *xgene_phy_xlate(struct device *dev, ...@@ -1615,7 +1615,7 @@ static struct phy *xgene_phy_xlate(struct device *dev,
if (args->args_count <= 0) if (args->args_count <= 0)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (args->args[0] < MODE_SATA || args->args[0] >= MODE_MAX) if (args->args[0] >= MODE_MAX)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
ctx->mode = args->args[0]; ctx->mode = args->args[0];
......
...@@ -59,30 +59,6 @@ config PHY_QCOM_QUSB2 ...@@ -59,30 +59,6 @@ config PHY_QCOM_QUSB2
PHY which is usually paired with either the ChipIdea or Synopsys DWC3 PHY which is usually paired with either the ChipIdea or Synopsys DWC3
USB IPs on MSM SOCs. USB IPs on MSM SOCs.
config PHY_QCOM_UFS
tristate "Qualcomm UFS PHY driver"
depends on OF && ARCH_QCOM
select GENERIC_PHY
help
Support for UFS PHY on QCOM chipsets.
if PHY_QCOM_UFS
config PHY_QCOM_UFS_14NM
tristate
default PHY_QCOM_UFS
help
Support for 14nm UFS QMP phy present on QCOM chipsets.
config PHY_QCOM_UFS_20NM
tristate
default PHY_QCOM_UFS
depends on BROKEN
help
Support for 20nm UFS QMP phy present on QCOM chipsets.
endif
config PHY_QCOM_USB_HS config PHY_QCOM_USB_HS
tristate "Qualcomm USB HS PHY module" tristate "Qualcomm USB HS PHY module"
depends on USB_ULPI_BUS depends on USB_ULPI_BUS
...@@ -128,3 +104,13 @@ config PHY_QCOM_USB_SS ...@@ -128,3 +104,13 @@ config PHY_QCOM_USB_SS
help help
Enable this to support the Super-Speed USB transceiver on various Enable this to support the Super-Speed USB transceiver on various
Qualcomm chipsets. Qualcomm chipsets.
config PHY_QCOM_IPQ806X_USB
tristate "Qualcomm IPQ806x DWC3 USB PHY driver"
depends on HAS_IOMEM
depends on OF && (ARCH_QCOM || COMPILE_TEST)
select GENERIC_PHY
help
This option enables support for the Synopsis PHYs present inside the
Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports
both HS and SS PHY controllers.
...@@ -6,11 +6,9 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o ...@@ -6,11 +6,9 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.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_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o
obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2)+= phy-qcom-snps-femto-v2.o obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2)+= phy-qcom-snps-femto-v2.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o
This diff is collapsed.
This diff is collapsed.
...@@ -363,7 +363,10 @@ ...@@ -363,7 +363,10 @@
/* Only for QMP V4 PHY - TX registers */ /* Only for QMP V4 PHY - TX registers */
#define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34 #define QSERDES_V4_TX_RES_CODE_LANE_TX 0x34
#define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38 #define QSERDES_V4_TX_RES_CODE_LANE_RX 0x38
#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x3c
#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x40
#define QSERDES_V4_TX_LANE_MODE_1 0x84 #define QSERDES_V4_TX_LANE_MODE_1 0x84
#define QSERDES_V4_TX_LANE_MODE_2 0x88
#define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c #define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x9c
#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8 #define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0xd8
#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC #define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0xdC
...@@ -709,6 +712,10 @@ ...@@ -709,6 +712,10 @@
#define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x354 #define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x354
#define QPHY_V4_PCS_USB3_TEST_CONTROL 0x358 #define QPHY_V4_PCS_USB3_TEST_CONTROL 0x358
/* Only for QMP V4 PHY - UNI has 0x300 offset for PCS_USB3 regs */
#define QPHY_V4_PCS_USB3_UNI_LFPS_DET_HIGH_COUNT_VAL 0x618
#define QPHY_V4_PCS_USB3_UNI_RXEQTRAINING_DFE_TIME_S2 0x638
/* Only for QMP V4 PHY - PCS_MISC registers */ /* Only for QMP V4 PHY - PCS_MISC registers */
#define QPHY_V4_PCS_MISC_TYPEC_CTRL 0x00 #define QPHY_V4_PCS_MISC_TYPEC_CTRL 0x00
#define QPHY_V4_PCS_MISC_TYPEC_PWRDN_CTRL 0x04 #define QPHY_V4_PCS_MISC_TYPEC_PWRDN_CTRL 0x04
......
...@@ -810,6 +810,9 @@ static const struct phy_ops qusb2_phy_gen_ops = { ...@@ -810,6 +810,9 @@ static const struct phy_ops qusb2_phy_gen_ops = {
static const struct of_device_id qusb2_phy_of_match_table[] = { static const struct of_device_id qusb2_phy_of_match_table[] = {
{ {
.compatible = "qcom,ipq8074-qusb2-phy",
.data = &msm8996_phy_cfg,
}, {
.compatible = "qcom,msm8996-qusb2-phy", .compatible = "qcom,msm8996-qusb2-phy",
.data = &msm8996_phy_cfg, .data = &msm8996_phy_cfg,
}, { }, {
......
...@@ -77,6 +77,7 @@ static const char * const qcom_snps_hsphy_vreg_names[] = { ...@@ -77,6 +77,7 @@ static const char * const qcom_snps_hsphy_vreg_names[] = {
* @phy_reset: phy reset control * @phy_reset: phy reset control
* @vregs: regulator supplies bulk data * @vregs: regulator supplies bulk data
* @phy_initialized: if PHY has been initialized correctly * @phy_initialized: if PHY has been initialized correctly
* @mode: contains the current mode the PHY is in
*/ */
struct qcom_snps_hsphy { struct qcom_snps_hsphy {
struct phy *phy; struct phy *phy;
...@@ -88,6 +89,7 @@ struct qcom_snps_hsphy { ...@@ -88,6 +89,7 @@ struct qcom_snps_hsphy {
struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS]; struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
bool phy_initialized; bool phy_initialized;
enum phy_mode mode;
}; };
static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
...@@ -104,6 +106,72 @@ static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, ...@@ -104,6 +106,72 @@ static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
readl_relaxed(base + offset); readl_relaxed(base + offset);
} }
static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
{
dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n");
if (hsphy->mode == PHY_MODE_USB_HOST) {
/* Enable auto-resume to meet remote wakeup timing */
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL2,
USB2_AUTO_RESUME,
USB2_AUTO_RESUME);
usleep_range(500, 1000);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL2,
0, USB2_AUTO_RESUME);
}
clk_disable_unprepare(hsphy->cfg_ahb_clk);
return 0;
}
static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
{
int ret;
dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
if (ret) {
dev_err(&hsphy->phy->dev, "failed to enable cfg ahb clock\n");
return ret;
}
return 0;
}
static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
{
struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
if (!hsphy->phy_initialized)
return 0;
qcom_snps_hsphy_suspend(hsphy);
return 0;
}
static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
{
struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
if (!hsphy->phy_initialized)
return 0;
qcom_snps_hsphy_resume(hsphy);
return 0;
}
static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
hsphy->mode = mode;
return 0;
}
static int qcom_snps_hsphy_init(struct phy *phy) static int qcom_snps_hsphy_init(struct phy *phy)
{ {
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
...@@ -201,6 +269,7 @@ static int qcom_snps_hsphy_exit(struct phy *phy) ...@@ -201,6 +269,7 @@ static int qcom_snps_hsphy_exit(struct phy *phy)
static const struct phy_ops qcom_snps_hsphy_gen_ops = { static const struct phy_ops qcom_snps_hsphy_gen_ops = {
.init = qcom_snps_hsphy_init, .init = qcom_snps_hsphy_init,
.exit = qcom_snps_hsphy_exit, .exit = qcom_snps_hsphy_exit,
.set_mode = qcom_snps_hsphy_set_mode,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -212,6 +281,11 @@ static const struct of_device_id qcom_snps_hsphy_of_match_table[] = { ...@@ -212,6 +281,11 @@ static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
}; };
MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table); MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend,
qcom_snps_hsphy_runtime_resume, NULL)
};
static int qcom_snps_hsphy_probe(struct platform_device *pdev) static int qcom_snps_hsphy_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -255,6 +329,14 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) ...@@ -255,6 +329,14 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
return ret; return ret;
} }
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
/*
* Prevent runtime pm from being ON by default. Users can enable
* it using power/control in sysfs.
*/
pm_runtime_forbid(dev);
generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops); generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
if (IS_ERR(generic_phy)) { if (IS_ERR(generic_phy)) {
ret = PTR_ERR(generic_phy); ret = PTR_ERR(generic_phy);
...@@ -269,6 +351,8 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) ...@@ -269,6 +351,8 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider)) if (!IS_ERR(phy_provider))
dev_dbg(dev, "Registered Qcom-SNPS HS phy\n"); dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
else
pm_runtime_disable(dev);
return PTR_ERR_OR_ZERO(phy_provider); return PTR_ERR_OR_ZERO(phy_provider);
} }
...@@ -277,6 +361,7 @@ static struct platform_driver qcom_snps_hsphy_driver = { ...@@ -277,6 +361,7 @@ static struct platform_driver qcom_snps_hsphy_driver = {
.probe = qcom_snps_hsphy_probe, .probe = qcom_snps_hsphy_probe,
.driver = { .driver = {
.name = "qcom-snps-hs-femto-v2-phy", .name = "qcom-snps-hs-femto-v2-phy",
.pm = &qcom_snps_hsphy_pm_ops,
.of_match_table = qcom_snps_hsphy_of_match_table, .of_match_table = qcom_snps_hsphy_of_match_table,
}, },
}; };
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*/
#ifndef UFS_QCOM_PHY_I_H_
#define UFS_QCOM_PHY_I_H_
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/phy/phy.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \
{ \
.reg_offset = reg, \
.cfg_value = val, \
}
#define UFS_QCOM_PHY_NAME_LEN 30
enum {
MASK_SERDES_START = 0x1,
MASK_PCS_READY = 0x1,
};
enum {
OFFSET_SERDES_START = 0x0,
};
struct ufs_qcom_phy_stored_attributes {
u32 att;
u32 value;
};
struct ufs_qcom_phy_calibration {
u32 reg_offset;
u32 cfg_value;
};
struct ufs_qcom_phy_vreg {
const char *name;
struct regulator *reg;
int max_uA;
int min_uV;
int max_uV;
bool enabled;
};
struct ufs_qcom_phy {
struct list_head list;
struct device *dev;
void __iomem *mmio;
void __iomem *dev_ref_clk_ctrl_mmio;
struct clk *tx_iface_clk;
struct clk *rx_iface_clk;
bool is_iface_clk_enabled;
struct clk *ref_clk_src;
struct clk *ref_clk_parent;
struct clk *ref_clk;
bool is_ref_clk_enabled;
bool is_dev_ref_clk_enabled;
struct ufs_qcom_phy_vreg vdda_pll;
struct ufs_qcom_phy_vreg vdda_phy;
struct ufs_qcom_phy_vreg vddp_ref_clk;
unsigned int quirks;
/*
* If UFS link is put into Hibern8 and if UFS PHY analog hardware is
* power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8
* exit might fail even after powering on UFS PHY analog hardware.
* Enabling this quirk will help to solve above issue by doing
* custom PHY settings just before PHY analog power collapse.
*/
#define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE BIT(0)
u8 host_ctrl_rev_major;
u16 host_ctrl_rev_minor;
u16 host_ctrl_rev_step;
char name[UFS_QCOM_PHY_NAME_LEN];
struct ufs_qcom_phy_calibration *cached_regs;
int cached_regs_table_size;
struct ufs_qcom_phy_specific_ops *phy_spec_ops;
enum phy_mode mode;
struct reset_control *ufs_reset;
};
/**
* struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a
* specific implementation per phy. Each UFS phy, should implement
* those functions according to its spec and requirements
* @start_serdes: pointer to a function that starts the serdes
* @is_physical_coding_sublayer_ready: pointer to a function that
* checks pcs readiness. returns 0 for success and non-zero for error.
* @set_tx_lane_enable: pointer to a function that enable tx lanes
* @power_control: pointer to a function that controls analog rail of phy
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
*/
struct ufs_qcom_phy_specific_ops {
int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B);
void (*start_serdes)(struct ufs_qcom_phy *phy);
int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
void (*power_control)(struct ufs_qcom_phy *phy, bool val);
};
struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
int ufs_qcom_phy_power_on(struct phy *generic_phy);
int ufs_qcom_phy_power_off(struct phy *generic_phy);
int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_remove(struct phy *generic_phy,
struct ufs_qcom_phy *ufs_qcom_phy);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg,
const struct phy_ops *ufs_qcom_phy_gen_ops,
struct ufs_qcom_phy_specific_ops *phy_spec_ops);
int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
bool is_rate_B);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*/
#include "phy-qcom-ufs-qmp-14nm.h"
#define UFS_PHY_NAME "ufs_phy_qmp_14nm"
#define UFS_PHY_VDDA_PHY_UV (925000)
static
int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
bool is_rate_B)
{
int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
int err;
err = ufs_qcom_phy_calibrate(ufs_qcom_phy, phy_cal_table_rate_A,
tbl_size_A, phy_cal_table_rate_B, tbl_size_B, is_rate_B);
if (err)
dev_err(ufs_qcom_phy->dev,
"%s: ufs_qcom_phy_calibrate() failed %d\n",
__func__, err);
return err;
}
static
void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
{
phy_common->quirks =
UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
}
static
int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy,
enum phy_mode mode, int submode)
{
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
phy_common->mode = PHY_MODE_INVALID;
if (mode > 0)
phy_common->mode = mode;
return 0;
}
static
void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val)
{
writel_relaxed(val ? 0x1 : 0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
/*
* Before any transactions involving PHY, ensure PHY knows
* that it's analog rail is powered ON (or OFF).
*/
mb();
}
static inline
void ufs_qcom_phy_qmp_14nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
{
/*
* 14nm PHY does not have TX_LANE_ENABLE register.
* Implement this function so as not to propagate error to caller.
*/
}
static inline void ufs_qcom_phy_qmp_14nm_start_serdes(struct ufs_qcom_phy *phy)
{
u32 tmp;
tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
tmp &= ~MASK_SERDES_START;
tmp |= (1 << OFFSET_SERDES_START);
writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
/* Ensure register value is committed */
mb();
}
static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
{
int err = 0;
u32 val;
err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
val, (val & MASK_PCS_READY), 10, 1000000);
if (err)
dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
__func__, err);
return err;
}
static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
.power_on = ufs_qcom_phy_power_on,
.power_off = ufs_qcom_phy_power_off,
.set_mode = ufs_qcom_phy_qmp_14nm_set_mode,
.owner = THIS_MODULE,
};
static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
.calibrate = ufs_qcom_phy_qmp_14nm_phy_calibrate,
.start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes,
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
.set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
.power_control = ufs_qcom_phy_qmp_14nm_power_control,
};
static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy *generic_phy;
struct ufs_qcom_phy_qmp_14nm *phy;
struct ufs_qcom_phy *phy_common;
int err = 0;
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
err = -ENOMEM;
goto out;
}
phy_common = &phy->common_cfg;
generic_phy = ufs_qcom_phy_generic_probe(pdev, phy_common,
&ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops);
if (!generic_phy) {
err = -EIO;
goto out;
}
err = ufs_qcom_phy_init_clks(phy_common);
if (err)
goto out;
err = ufs_qcom_phy_init_vregulators(phy_common);
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;
ufs_qcom_phy_qmp_14nm_advertise_quirks(phy_common);
phy_set_drvdata(generic_phy, phy);
strlcpy(phy_common->name, UFS_PHY_NAME, sizeof(phy_common->name));
out:
return err;
}
static const struct of_device_id ufs_qcom_phy_qmp_14nm_of_match[] = {
{.compatible = "qcom,ufs-phy-qmp-14nm"},
{.compatible = "qcom,msm8996-ufs-phy-qmp-14nm"},
{},
};
MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_14nm_of_match);
static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = {
.probe = ufs_qcom_phy_qmp_14nm_probe,
.driver = {
.of_match_table = ufs_qcom_phy_qmp_14nm_of_match,
.name = "ufs_qcom_phy_qmp_14nm",
},
};
module_platform_driver(ufs_qcom_phy_qmp_14nm_driver);
MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 14nm");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*/
#ifndef UFS_QCOM_PHY_QMP_14NM_H_
#define UFS_QCOM_PHY_QMP_14NM_H_
#include "phy-qcom-ufs-i.h"
/* QCOM UFS PHY control registers */
#define COM_OFF(x) (0x000 + x)
#define PHY_OFF(x) (0xC00 + x)
#define TX_OFF(n, x) (0x400 + (0x400 * n) + x)
#define RX_OFF(n, x) (0x600 + (0x400 * n) + x)
/* UFS PHY QSERDES COM registers */
#define QSERDES_COM_BG_TIMER COM_OFF(0x0C)
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34)
#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C)
#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0x4C)
#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0x50)
#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0x54)
#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0x58)
#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0x5C)
#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0x60)
#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78)
#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C)
#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84)
#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88)
#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90)
#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94)
#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC)
#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4)
#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8)
#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC)
#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0)
#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4)
#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC)
#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0)
#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4)
#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8)
#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC)
#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0)
#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108)
#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C)
#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110)
#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114)
#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124)
#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128)
#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C)
#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130)
#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134)
#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138)
#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144)
#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148)
#define QSERDES_COM_CLK_SELECT COM_OFF(0x174)
#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178)
#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184)
#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C)
#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194)
#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C)
#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC)
/* UFS PHY registers */
#define UFS_PHY_PHY_START PHY_OFF(0x00)
#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168)
/* UFS PHY TX registers */
#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0, 0x68)
#define QSERDES_TX_LANE_MODE TX_OFF(0, 0x94)
/* UFS PHY RX registers */
#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0, 0x40)
#define QSERDES_RX_RX_TERM_BW RX_OFF(0, 0x90)
#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0, 0xC4)
#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0, 0xC8)
#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0, 0xCC)
#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0, 0xD0)
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0, 0xD8)
#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0, 0x114)
#define QSERDES_RX_SIGDET_LVL RX_OFF(0, 0x118)
#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x11C)
#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0, 0x12C)
/*
* This structure represents the 14nm specific phy.
* common_cfg MUST remain the first field in this structure
* in case extra fields are added. This way, when calling
* get_ufs_qcom_phy() of generic phy, we can extract the
* common phy structure (struct ufs_qcom_phy) out of it
* regardless of the relevant specific phy.
*/
struct ufs_qcom_phy_qmp_14nm {
struct ufs_qcom_phy common_cfg;
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x05),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x10),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x14),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0F),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x54),
};
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
*/
#include "phy-qcom-ufs-qmp-20nm.h"
#define UFS_PHY_NAME "ufs_phy_qmp_20nm"
static
int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
bool is_rate_B)
{
struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
int tbl_size_A, tbl_size_B;
u8 major = ufs_qcom_phy->host_ctrl_rev_major;
u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
u16 step = ufs_qcom_phy->host_ctrl_rev_step;
int err;
if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0);
tbl_A = phy_cal_table_rate_A_1_2_0;
} else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0);
tbl_A = phy_cal_table_rate_A_1_3_0;
} else {
dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n",
__func__);
err = -ENODEV;
goto out;
}
tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
tbl_B = phy_cal_table_rate_B;
err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A,
tbl_B, tbl_size_B, is_rate_B);
if (err)
dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n",
__func__, err);
out:
return err;
}
static
void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
{
phy_common->quirks =
UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
}
static
int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy,
enum phy_mode mode, int submode)
{
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
phy_common->mode = PHY_MODE_INVALID;
if (mode > 0)
phy_common->mode = mode;
return 0;
}
static
void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val)
{
bool hibern8_exit_after_pwr_collapse = phy->quirks &
UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
if (val) {
writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
/*
* Before any transactions involving PHY, ensure PHY knows
* that it's analog rail is powered ON.
*/
mb();
if (hibern8_exit_after_pwr_collapse) {
/*
* Give atleast 1us delay after restoring PHY analog
* power.
*/
usleep_range(1, 2);
writel_relaxed(0x0A, phy->mmio +
QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
writel_relaxed(0x08, phy->mmio +
QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
/*
* Make sure workaround is deactivated before proceeding
* with normal PHY operations.
*/
mb();
}
} else {
if (hibern8_exit_after_pwr_collapse) {
writel_relaxed(0x0A, phy->mmio +
QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
writel_relaxed(0x02, phy->mmio +
QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
/*
* Make sure that above workaround is activated before
* PHY analog power collapse.
*/
mb();
}
writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
/*
* ensure that PHY knows its PHY analog rail is going
* to be powered down
*/
mb();
}
}
static
void ufs_qcom_phy_qmp_20nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
{
writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK,
phy->mmio + UFS_PHY_TX_LANE_ENABLE);
mb();
}
static inline void ufs_qcom_phy_qmp_20nm_start_serdes(struct ufs_qcom_phy *phy)
{
u32 tmp;
tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
tmp &= ~MASK_SERDES_START;
tmp |= (1 << OFFSET_SERDES_START);
writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
mb();
}
static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
{
int err = 0;
u32 val;
err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
val, (val & MASK_PCS_READY), 10, 1000000);
if (err)
dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
__func__, err);
return err;
}
static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.power_on = ufs_qcom_phy_power_on,
.power_off = ufs_qcom_phy_power_off,
.set_mode = ufs_qcom_phy_qmp_20nm_set_mode,
.owner = THIS_MODULE,
};
static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
.calibrate = ufs_qcom_phy_qmp_20nm_phy_calibrate,
.start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
.set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
.power_control = ufs_qcom_phy_qmp_20nm_power_control,
};
static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy *generic_phy;
struct ufs_qcom_phy_qmp_20nm *phy;
struct ufs_qcom_phy *phy_common;
int err = 0;
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
err = -ENOMEM;
goto out;
}
phy_common = &phy->common_cfg;
generic_phy = ufs_qcom_phy_generic_probe(pdev, phy_common,
&ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops);
if (!generic_phy) {
err = -EIO;
goto out;
}
err = ufs_qcom_phy_init_clks(phy_common);
if (err)
goto out;
err = ufs_qcom_phy_init_vregulators(phy_common);
if (err)
goto out;
ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);
phy_set_drvdata(generic_phy, phy);
strlcpy(phy_common->name, UFS_PHY_NAME, sizeof(phy_common->name));
out:
return err;
}
static const struct of_device_id ufs_qcom_phy_qmp_20nm_of_match[] = {
{.compatible = "qcom,ufs-phy-qmp-20nm"},
{},
};
MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_20nm_of_match);
static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = {
.probe = ufs_qcom_phy_qmp_20nm_probe,
.driver = {
.of_match_table = ufs_qcom_phy_qmp_20nm_of_match,
.name = "ufs_qcom_phy_qmp_20nm",
},
};
module_platform_driver(ufs_qcom_phy_qmp_20nm_driver);
MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 20nm");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
...@@ -111,6 +111,7 @@ struct rcar_gen3_chan { ...@@ -111,6 +111,7 @@ struct rcar_gen3_chan {
struct work_struct work; struct work_struct work;
struct mutex lock; /* protects rphys[...].powered */ struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
int irq;
bool extcon_host; bool extcon_host;
bool is_otg_channel; bool is_otg_channel;
bool uses_otg_pins; bool uses_otg_pins;
...@@ -389,12 +390,40 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) ...@@ -389,12 +390,40 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
rcar_gen3_device_recognition(ch); rcar_gen3_device_recognition(ch);
} }
static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{
struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->base;
u32 status = readl(usb2_base + USB2_OBINTSTA);
irqreturn_t ret = IRQ_NONE;
if (status & USB2_OBINT_BITS) {
dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
rcar_gen3_device_recognition(ch);
ret = IRQ_HANDLED;
}
return ret;
}
static int rcar_gen3_phy_usb2_init(struct phy *p) static int rcar_gen3_phy_usb2_init(struct phy *p)
{ {
struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_phy *rphy = phy_get_drvdata(p);
struct rcar_gen3_chan *channel = rphy->ch; struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base; void __iomem *usb2_base = channel->base;
u32 val; u32 val;
int ret;
if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(channel->dev), channel);
if (ret < 0) {
dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
return ret;
}
}
/* Initialize USB2 part */ /* Initialize USB2 part */
val = readl(usb2_base + USB2_INT_ENABLE); val = readl(usb2_base + USB2_INT_ENABLE);
...@@ -433,6 +462,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) ...@@ -433,6 +462,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
val &= ~USB2_INT_ENABLE_UCOM_INTEN; val &= ~USB2_INT_ENABLE_UCOM_INTEN;
writel(val, usb2_base + USB2_INT_ENABLE); writel(val, usb2_base + USB2_INT_ENABLE);
if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
free_irq(channel->irq, channel);
return 0; return 0;
} }
...@@ -503,23 +535,6 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = { ...@@ -503,23 +535,6 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = {
.owner = THIS_MODULE, .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->base;
u32 status = readl(usb2_base + USB2_OBINTSTA);
irqreturn_t ret = IRQ_NONE;
if (status & USB2_OBINT_BITS) {
dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
rcar_gen3_device_recognition(ch);
ret = IRQ_HANDLED;
}
return ret;
}
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
{ {
.compatible = "renesas,usb2-phy-r8a77470", .compatible = "renesas,usb2-phy-r8a77470",
...@@ -598,7 +613,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -598,7 +613,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct phy_provider *provider; struct phy_provider *provider;
struct resource *res; struct resource *res;
const struct phy_ops *phy_usb2_ops; const struct phy_ops *phy_usb2_ops;
int irq, ret = 0, i; int ret = 0, i;
if (!dev->of_node) { if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n"); dev_err(dev, "This driver needs device tree\n");
...@@ -614,16 +629,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -614,16 +629,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (IS_ERR(channel->base)) if (IS_ERR(channel->base))
return PTR_ERR(channel->base); return PTR_ERR(channel->base);
/* call request_irq for OTG */ /* get irq number here and request_irq for OTG in phy_init */
irq = platform_get_irq_optional(pdev, 0); channel->irq = platform_get_irq_optional(pdev, 0);
if (irq >= 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
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->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
int ret; int ret;
......
...@@ -347,7 +347,7 @@ struct usb3phy_reg { ...@@ -347,7 +347,7 @@ struct usb3phy_reg {
}; };
/** /**
* struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration.
* @reg: the base address for usb3-phy config. * @reg: the base address for usb3-phy config.
* @typec_conn_dir: the register of type-c connector direction. * @typec_conn_dir: the register of type-c connector direction.
* @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
......
...@@ -3,23 +3,23 @@ ...@@ -3,23 +3,23 @@
# Phy drivers for Samsung platforms # Phy drivers for Samsung platforms
# #
config PHY_EXYNOS_DP_VIDEO config PHY_EXYNOS_DP_VIDEO
tristate "EXYNOS SoC series Display Port PHY driver" tristate "Exynos SoC series Display Port PHY driver"
depends on OF depends on OF
depends on ARCH_EXYNOS || COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST
default ARCH_EXYNOS default ARCH_EXYNOS
select GENERIC_PHY select GENERIC_PHY
help help
Support for Display Port PHY found on Samsung EXYNOS SoCs. Support for Display Port PHY found on Samsung Exynos SoCs.
config PHY_EXYNOS_MIPI_VIDEO config PHY_EXYNOS_MIPI_VIDEO
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" tristate "S5P/Exynos SoC series MIPI CSI-2/DSI PHY driver"
depends on HAS_IOMEM depends on HAS_IOMEM
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select GENERIC_PHY select GENERIC_PHY
default y if ARCH_S5PV210 || ARCH_EXYNOS default y if ARCH_S5PV210 || ARCH_EXYNOS
help help
Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
and EXYNOS SoCs. and Exynos SoCs.
config PHY_EXYNOS_PCIE config PHY_EXYNOS_PCIE
bool "Exynos PCIe PHY driver" bool "Exynos PCIe PHY driver"
...@@ -29,6 +29,15 @@ config PHY_EXYNOS_PCIE ...@@ -29,6 +29,15 @@ config PHY_EXYNOS_PCIE
Enable PCIe PHY support for Exynos SoC series. Enable PCIe PHY support for Exynos SoC series.
This driver provides PHY interface for Exynos PCIe controller. This driver provides PHY interface for Exynos PCIe controller.
config PHY_SAMSUNG_UFS
tristate "SAMSUNG SoC series UFS PHY driver"
depends on OF && (ARCH_EXYNOS || COMPILE_TEST)
select GENERIC_PHY
help
Enable this to support the Samsung UFS PHY driver for
Samsung SoCs. This driver provides the interface for UFS
host controller to do PHY related programming.
config PHY_SAMSUNG_USB2 config PHY_SAMSUNG_USB2
tristate "Samsung USB 2.0 PHY driver" tristate "Samsung USB 2.0 PHY driver"
depends on HAS_IOMEM depends on HAS_IOMEM
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o
obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-samsung-ufs.o
obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Samsung EXYNOS SoC series Display Port PHY driver * Samsung Exynos SoC series Display Port PHY driver
* *
* Copyright (C) 2013 Samsung Electronics Co., Ltd. * Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@samsung.com> * Author: Jingoo Han <jg1.han@samsung.com>
...@@ -115,5 +115,5 @@ static struct platform_driver exynos_dp_video_phy_driver = { ...@@ -115,5 +115,5 @@ static struct platform_driver exynos_dp_video_phy_driver = {
module_platform_driver(exynos_dp_video_phy_driver); module_platform_driver(exynos_dp_video_phy_driver);
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Samsung EXYNOS SoC DP PHY driver"); MODULE_DESCRIPTION("Samsung Exynos SoC DP PHY driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver * Samsung S5P/Exynos SoC series MIPI CSIS/DSIM DPHY driver
* *
* Copyright (C) 2013,2016 Samsung Electronics Co., Ltd. * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com> * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
...@@ -364,6 +364,6 @@ static struct platform_driver exynos_mipi_video_phy_driver = { ...@@ -364,6 +364,6 @@ static struct platform_driver exynos_mipi_video_phy_driver = {
}; };
module_platform_driver(exynos_mipi_video_phy_driver); module_platform_driver(exynos_mipi_video_phy_driver);
MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI CSI-2/DSI PHY driver"); MODULE_DESCRIPTION("Samsung S5P/Exynos SoC MIPI CSI-2/DSI PHY driver");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Samsung EXYNOS SoC series PCIe PHY driver * Samsung Exynos SoC series PCIe PHY driver
* *
* Phy provider for PCIe controller on Exynos SoC series * Phy provider for PCIe controller on Exynos SoC series
* *
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Samsung EXYNOS5 SoC series USB DRD PHY driver * Samsung Exynos5 SoC series USB DRD PHY driver
* *
* Phy provider for USB 3.0 DRD controller on Exynos5 SoC series * Phy provider for USB 3.0 DRD controller on Exynos5 SoC series
* *
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define EXYNOS5_FSEL_24MHZ 0x5 #define EXYNOS5_FSEL_24MHZ 0x5
#define EXYNOS5_FSEL_50MHZ 0x7 #define EXYNOS5_FSEL_50MHZ 0x7
/* EXYNOS5: USB 3.0 DRD PHY registers */ /* Exynos5: USB 3.0 DRD PHY registers */
#define EXYNOS5_DRD_LINKSYSTEM 0x04 #define EXYNOS5_DRD_LINKSYSTEM 0x04
#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) #define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
...@@ -180,14 +180,14 @@ struct exynos5_usbdrd_phy_drvdata { ...@@ -180,14 +180,14 @@ struct exynos5_usbdrd_phy_drvdata {
* @utmiclk: clock for utmi+ phy * @utmiclk: clock for utmi+ phy
* @itpclk: clock for ITP generation * @itpclk: clock for ITP generation
* @drv_data: pointer to SoC level driver data structure * @drv_data: pointer to SoC level driver data structure
* @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY * @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'. * instances each with its 'phy' and 'phy_cfg'.
* @extrefclk: frequency select settings when using 'separate * @extrefclk: frequency select settings when using 'separate
* reference clocks' for SS and HS operations * reference clocks' for SS and HS operations
* @ref_clk: reference clock to PHY block from which PHY's * @ref_clk: reference clock to PHY block from which PHY's
* operational clocks are derived * operational clocks are derived
* vbus: VBUS regulator for phy * @vbus: VBUS regulator for phy
* vbus_boost: Boost regulator for VBUS present on few Exynos boards * @vbus_boost: Boost regulator for VBUS present on few Exynos boards
*/ */
struct exynos5_usbdrd_phy { struct exynos5_usbdrd_phy {
struct device *dev; struct device *dev;
...@@ -714,7 +714,9 @@ static int exynos5_usbdrd_phy_calibrate(struct phy *phy) ...@@ -714,7 +714,9 @@ static int exynos5_usbdrd_phy_calibrate(struct phy *phy)
struct phy_usb_instance *inst = phy_get_drvdata(phy); struct phy_usb_instance *inst = phy_get_drvdata(phy);
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
return exynos5420_usbdrd_phy_calibrate(phy_drd); if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI)
return exynos5420_usbdrd_phy_calibrate(phy_drd);
return 0;
} }
static const struct phy_ops exynos5_usbdrd_phy_ops = { static const struct phy_ops exynos5_usbdrd_phy_ops = {
...@@ -958,7 +960,7 @@ static struct platform_driver exynos5_usb3drd_phy = { ...@@ -958,7 +960,7 @@ static struct platform_driver exynos5_usb3drd_phy = {
}; };
module_platform_driver(exynos5_usb3drd_phy); module_platform_driver(exynos5_usb3drd_phy);
MODULE_DESCRIPTION("Samsung EXYNOS5 SoCs USB 3.0 DRD controller PHY driver"); MODULE_DESCRIPTION("Samsung Exynos5 SoCs USB 3.0 DRD controller PHY driver");
MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>"); MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:exynos5_usb3drd_phy"); MODULE_ALIAS("platform:exynos5_usb3drd_phy");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS PHY driver data for Samsung EXYNOS7 SoC
*
* Copyright (C) 2020 Samsung Electronics Co., Ltd.
*/
#ifndef _PHY_EXYNOS7_UFS_H_
#define _PHY_EXYNOS7_UFS_H_
#include "phy-samsung-ufs.h"
#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL 0x720
#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1
#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0)
/* Calibration for phy initialization */
static const struct samsung_ufs_phy_cfg exynos7_pre_init_cfg[] = {
PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x017, 0x84, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x035, 0x58, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x037, 0x40, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x03b, 0x83, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x04c, 0x5b, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x05c, 0x14, PWR_MODE_ANY),
END_UFS_PHY_CFG
};
/* Calibration for HS mode series A/B */
static const struct samsung_ufs_phy_cfg exynos7_pre_pwr_hs_cfg[] = {
PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_HS_ANY),
PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_HS_ANY),
PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_HS_ANY),
/* Setting order: 1st(0x16, 2nd(0x15) */
PHY_COMN_REG_CFG(0x016, 0xff, PWR_MODE_HS_ANY),
PHY_COMN_REG_CFG(0x015, 0x80, PWR_MODE_HS_ANY),
PHY_COMN_REG_CFG(0x017, 0x94, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x037, 0x43, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x038, 0x3f, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_HS_G2_SER_A),
PHY_TRSV_REG_CFG(0x042, 0xbb, PWR_MODE_HS_G2_SER_B),
PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x034, 0x35, PWR_MODE_HS_G2_SER_A),
PHY_TRSV_REG_CFG(0x034, 0x36, PWR_MODE_HS_G2_SER_B),
PHY_TRSV_REG_CFG(0x035, 0x5b, PWR_MODE_HS_G2_SER_A),
PHY_TRSV_REG_CFG(0x035, 0x5c, PWR_MODE_HS_G2_SER_B),
END_UFS_PHY_CFG
};
/* Calibration for HS mode series A/B atfer PMC */
static const struct samsung_ufs_phy_cfg exynos7_post_pwr_hs_cfg[] = {
PHY_COMN_REG_CFG(0x015, 0x00, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_HS_ANY),
END_UFS_PHY_CFG
};
static const struct samsung_ufs_phy_cfg *exynos7_ufs_phy_cfgs[CFG_TAG_MAX] = {
[CFG_PRE_INIT] = exynos7_pre_init_cfg,
[CFG_PRE_PWR_HS] = exynos7_pre_pwr_hs_cfg,
[CFG_POST_PWR_HS] = exynos7_post_pwr_hs_cfg,
};
static struct samsung_ufs_phy_drvdata exynos7_ufs_phy = {
.cfg = exynos7_ufs_phy_cfgs,
.isol = {
.offset = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL,
.mask = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK,
.en = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN,
},
.has_symbol_clk = 1,
};
#endif /* _PHY_EXYNOS7_UFS_H_ */
// SPDX-License-Identifier: GPL-2.0-only
/*
* UFS PHY driver for Samsung SoC
*
* Copyright (C) 2020 Samsung Electronics Co., Ltd.
* Author: Seungwon Jeon <essuuj@gmail.com>
* Author: Alim Akhtar <alim.akhtar@samsung.com>
*
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "phy-samsung-ufs.h"
#define for_each_phy_lane(phy, i) \
for (i = 0; i < (phy)->lane_cnt; i++)
#define for_each_phy_cfg(cfg) \
for (; (cfg)->id; (cfg)++)
#define PHY_DEF_LANE_CNT 1
static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
const struct samsung_ufs_phy_cfg *cfg,
u8 lane)
{
enum {LANE_0, LANE_1}; /* lane index */
switch (lane) {
case LANE_0:
writel(cfg->val, (phy)->reg_pma + cfg->off_0);
break;
case LANE_1:
if (cfg->id == PHY_TRSV_BLK)
writel(cfg->val, (phy)->reg_pma + cfg->off_1);
break;
}
}
static int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy)
{
struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
const unsigned int timeout_us = 100000;
const unsigned int sleep_us = 10;
u32 val;
int err;
err = readl_poll_timeout(
ufs_phy->reg_pma + PHY_APB_ADDR(PHY_PLL_LOCK_STATUS),
val, (val & PHY_PLL_LOCK_BIT), sleep_us, timeout_us);
if (err) {
dev_err(ufs_phy->dev,
"failed to get phy pll lock acquisition %d\n", err);
goto out;
}
err = readl_poll_timeout(
ufs_phy->reg_pma + PHY_APB_ADDR(PHY_CDR_LOCK_STATUS),
val, (val & PHY_CDR_LOCK_BIT), sleep_us, timeout_us);
if (err)
dev_err(ufs_phy->dev,
"failed to get phy cdr lock acquisition %d\n", err);
out:
return err;
}
static int samsung_ufs_phy_calibrate(struct phy *phy)
{
struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
struct samsung_ufs_phy_cfg **cfgs = ufs_phy->cfg;
const struct samsung_ufs_phy_cfg *cfg;
int err = 0;
int i;
if (unlikely(ufs_phy->ufs_phy_state < CFG_PRE_INIT ||
ufs_phy->ufs_phy_state >= CFG_TAG_MAX)) {
dev_err(ufs_phy->dev, "invalid phy config index %d\n", ufs_phy->ufs_phy_state);
return -EINVAL;
}
cfg = cfgs[ufs_phy->ufs_phy_state];
if (!cfg)
goto out;
for_each_phy_cfg(cfg) {
for_each_phy_lane(ufs_phy, i) {
samsung_ufs_phy_config(ufs_phy, cfg, i);
}
}
if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS)
err = samsung_ufs_phy_wait_for_lock_acq(phy);
/**
* In Samsung ufshci, PHY need to be calibrated at different
* stages / state mainly before Linkstartup, after Linkstartup,
* before power mode change and after power mode change.
* Below state machine to make sure to calibrate PHY in each
* state. Here after configuring PHY in a given state, will
* change the state to next state so that next state phy
* calibration value can be programed
*/
out:
switch (ufs_phy->ufs_phy_state) {
case CFG_PRE_INIT:
ufs_phy->ufs_phy_state = CFG_POST_INIT;
break;
case CFG_POST_INIT:
ufs_phy->ufs_phy_state = CFG_PRE_PWR_HS;
break;
case CFG_PRE_PWR_HS:
ufs_phy->ufs_phy_state = CFG_POST_PWR_HS;
break;
case CFG_POST_PWR_HS:
/* Change back to INIT state */
ufs_phy->ufs_phy_state = CFG_PRE_INIT;
break;
default:
dev_err(ufs_phy->dev, "wrong state for phy calibration\n");
}
return err;
}
static int samsung_ufs_phy_symbol_clk_init(struct samsung_ufs_phy *phy)
{
int ret;
phy->tx0_symbol_clk = devm_clk_get(phy->dev, "tx0_symbol_clk");
if (IS_ERR(phy->tx0_symbol_clk)) {
dev_err(phy->dev, "failed to get tx0_symbol_clk clock\n");
return PTR_ERR(phy->tx0_symbol_clk);
}
phy->rx0_symbol_clk = devm_clk_get(phy->dev, "rx0_symbol_clk");
if (IS_ERR(phy->rx0_symbol_clk)) {
dev_err(phy->dev, "failed to get rx0_symbol_clk clock\n");
return PTR_ERR(phy->rx0_symbol_clk);
}
phy->rx1_symbol_clk = devm_clk_get(phy->dev, "rx1_symbol_clk");
if (IS_ERR(phy->rx1_symbol_clk)) {
dev_err(phy->dev, "failed to get rx1_symbol_clk clock\n");
return PTR_ERR(phy->rx1_symbol_clk);
}
ret = clk_prepare_enable(phy->tx0_symbol_clk);
if (ret) {
dev_err(phy->dev, "%s: tx0_symbol_clk enable failed %d\n", __func__, ret);
goto out;
}
ret = clk_prepare_enable(phy->rx0_symbol_clk);
if (ret) {
dev_err(phy->dev, "%s: rx0_symbol_clk enable failed %d\n", __func__, ret);
goto out_disable_tx0_clk;
}
ret = clk_prepare_enable(phy->rx1_symbol_clk);
if (ret) {
dev_err(phy->dev, "%s: rx1_symbol_clk enable failed %d\n", __func__, ret);
goto out_disable_rx0_clk;
}
return 0;
out_disable_rx0_clk:
clk_disable_unprepare(phy->rx0_symbol_clk);
out_disable_tx0_clk:
clk_disable_unprepare(phy->tx0_symbol_clk);
out:
return ret;
}
static int samsung_ufs_phy_clks_init(struct samsung_ufs_phy *phy)
{
int ret;
phy->ref_clk = devm_clk_get(phy->dev, "ref_clk");
if (IS_ERR(phy->ref_clk))
dev_err(phy->dev, "failed to get ref_clk clock\n");
ret = clk_prepare_enable(phy->ref_clk);
if (ret) {
dev_err(phy->dev, "%s: ref_clk enable failed %d\n", __func__, ret);
return ret;
}
dev_dbg(phy->dev, "UFS MPHY ref_clk_rate = %ld\n", clk_get_rate(phy->ref_clk));
return 0;
}
static int samsung_ufs_phy_init(struct phy *phy)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
int ret;
ss_phy->lane_cnt = phy->attrs.bus_width;
ss_phy->ufs_phy_state = CFG_PRE_INIT;
if (ss_phy->drvdata->has_symbol_clk) {
ret = samsung_ufs_phy_symbol_clk_init(ss_phy);
if (ret)
dev_err(ss_phy->dev, "failed to set ufs phy symbol clocks\n");
}
ret = samsung_ufs_phy_clks_init(ss_phy);
if (ret)
dev_err(ss_phy->dev, "failed to set ufs phy clocks\n");
ret = samsung_ufs_phy_calibrate(phy);
if (ret)
dev_err(ss_phy->dev, "ufs phy calibration failed\n");
return ret;
}
static int samsung_ufs_phy_power_on(struct phy *phy)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
samsung_ufs_phy_ctrl_isol(ss_phy, false);
return 0;
}
static int samsung_ufs_phy_power_off(struct phy *phy)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
samsung_ufs_phy_ctrl_isol(ss_phy, true);
return 0;
}
static int samsung_ufs_phy_set_mode(struct phy *generic_phy,
enum phy_mode mode, int submode)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(generic_phy);
ss_phy->mode = PHY_MODE_INVALID;
if (mode > 0)
ss_phy->mode = mode;
return 0;
}
static int samsung_ufs_phy_exit(struct phy *phy)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
clk_disable_unprepare(ss_phy->ref_clk);
if (ss_phy->drvdata->has_symbol_clk) {
clk_disable_unprepare(ss_phy->tx0_symbol_clk);
clk_disable_unprepare(ss_phy->rx0_symbol_clk);
clk_disable_unprepare(ss_phy->rx1_symbol_clk);
}
return 0;
}
static struct phy_ops samsung_ufs_phy_ops = {
.init = samsung_ufs_phy_init,
.exit = samsung_ufs_phy_exit,
.power_on = samsung_ufs_phy_power_on,
.power_off = samsung_ufs_phy_power_off,
.calibrate = samsung_ufs_phy_calibrate,
.set_mode = samsung_ufs_phy_set_mode,
.owner = THIS_MODULE,
};
static const struct of_device_id samsung_ufs_phy_match[];
static int samsung_ufs_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct samsung_ufs_phy *phy;
struct phy *gen_phy;
struct phy_provider *phy_provider;
const struct samsung_ufs_phy_drvdata *drvdata;
int err = 0;
match = of_match_node(samsung_ufs_phy_match, dev->of_node);
if (!match) {
err = -EINVAL;
dev_err(dev, "failed to get match_node\n");
goto out;
}
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
err = -ENOMEM;
goto out;
}
phy->reg_pma = devm_platform_ioremap_resource_byname(pdev, "phy-pma");
if (IS_ERR(phy->reg_pma)) {
err = PTR_ERR(phy->reg_pma);
goto out;
}
phy->reg_pmu = syscon_regmap_lookup_by_phandle(
dev->of_node, "samsung,pmu-syscon");
if (IS_ERR(phy->reg_pmu)) {
err = PTR_ERR(phy->reg_pmu);
dev_err(dev, "failed syscon remap for pmu\n");
goto out;
}
gen_phy = devm_phy_create(dev, NULL, &samsung_ufs_phy_ops);
if (IS_ERR(gen_phy)) {
err = PTR_ERR(gen_phy);
dev_err(dev, "failed to create PHY for ufs-phy\n");
goto out;
}
drvdata = match->data;
phy->dev = dev;
phy->drvdata = drvdata;
phy->cfg = (struct samsung_ufs_phy_cfg **)drvdata->cfg;
phy->isol = &drvdata->isol;
phy->lane_cnt = PHY_DEF_LANE_CNT;
phy_set_drvdata(gen_phy, phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) {
err = PTR_ERR(phy_provider);
dev_err(dev, "failed to register phy-provider\n");
goto out;
}
out:
return err;
}
static const struct of_device_id samsung_ufs_phy_match[] = {
{
.compatible = "samsung,exynos7-ufs-phy",
.data = &exynos7_ufs_phy,
},
{},
};
MODULE_DEVICE_TABLE(of, samsung_ufs_phy_match);
static struct platform_driver samsung_ufs_phy_driver = {
.probe = samsung_ufs_phy_probe,
.driver = {
.name = "samsung-ufs-phy",
.of_match_table = samsung_ufs_phy_match,
},
};
module_platform_driver(samsung_ufs_phy_driver);
MODULE_DESCRIPTION("Samsung SoC UFS PHY Driver");
MODULE_AUTHOR("Seungwon Jeon <essuuj@gmail.com>");
MODULE_AUTHOR("Alim Akhtar <alim.akhtar@samsung.com>");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS PHY driver for Samsung EXYNOS SoC
*
* Copyright (C) 2020 Samsung Electronics Co., Ltd.
* Author: Seungwon Jeon <essuuj@gmail.com>
* Author: Alim Akhtar <alim.akhtar@samsung.com>
*
*/
#ifndef _PHY_SAMSUNG_UFS_
#define _PHY_SAMSUNG_UFS_
#define PHY_COMN_BLK 1
#define PHY_TRSV_BLK 2
#define END_UFS_PHY_CFG { 0 }
#define PHY_TRSV_CH_OFFSET 0x30
#define PHY_APB_ADDR(off) ((off) << 2)
#define PHY_COMN_REG_CFG(o, v, d) { \
.off_0 = PHY_APB_ADDR((o)), \
.off_1 = 0, \
.val = (v), \
.desc = (d), \
.id = PHY_COMN_BLK, \
}
#define PHY_TRSV_REG_CFG(o, v, d) { \
.off_0 = PHY_APB_ADDR((o)), \
.off_1 = PHY_APB_ADDR((o) + PHY_TRSV_CH_OFFSET), \
.val = (v), \
.desc = (d), \
.id = PHY_TRSV_BLK, \
}
/* UFS PHY registers */
#define PHY_PLL_LOCK_STATUS 0x1e
#define PHY_CDR_LOCK_STATUS 0x5e
#define PHY_PLL_LOCK_BIT BIT(5)
#define PHY_CDR_LOCK_BIT BIT(4)
/* description for PHY calibration */
enum {
/* applicable to any */
PWR_DESC_ANY = 0,
/* mode */
PWR_DESC_PWM = 1,
PWR_DESC_HS = 2,
/* series */
PWR_DESC_SER_A = 1,
PWR_DESC_SER_B = 2,
/* gear */
PWR_DESC_G1 = 1,
PWR_DESC_G2 = 2,
PWR_DESC_G3 = 3,
/* field mask */
MD_MASK = 0x3,
SR_MASK = 0x3,
GR_MASK = 0x7,
};
#define PWR_MODE_HS_G1_ANY PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_ANY)
#define PWR_MODE_HS_G1_SER_A PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_A)
#define PWR_MODE_HS_G1_SER_B PWR_MODE_HS(PWR_DESC_G1, PWR_DESC_SER_B)
#define PWR_MODE_HS_G2_ANY PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_ANY)
#define PWR_MODE_HS_G2_SER_A PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_A)
#define PWR_MODE_HS_G2_SER_B PWR_MODE_HS(PWR_DESC_G2, PWR_DESC_SER_B)
#define PWR_MODE_HS_G3_ANY PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_ANY)
#define PWR_MODE_HS_G3_SER_A PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_A)
#define PWR_MODE_HS_G3_SER_B PWR_MODE_HS(PWR_DESC_G3, PWR_DESC_SER_B)
#define PWR_MODE(g, s, m) ((((g) & GR_MASK) << 4) |\
(((s) & SR_MASK) << 2) | ((m) & MD_MASK))
#define PWR_MODE_PWM_ANY PWR_MODE(PWR_DESC_ANY,\
PWR_DESC_ANY, PWR_DESC_PWM)
#define PWR_MODE_HS(g, s) ((((g) & GR_MASK) << 4) |\
(((s) & SR_MASK) << 2) | PWR_DESC_HS)
#define PWR_MODE_HS_ANY PWR_MODE(PWR_DESC_ANY,\
PWR_DESC_ANY, PWR_DESC_HS)
#define PWR_MODE_ANY PWR_MODE(PWR_DESC_ANY,\
PWR_DESC_ANY, PWR_DESC_ANY)
/* PHY calibration point/state */
enum {
CFG_PRE_INIT,
CFG_POST_INIT,
CFG_PRE_PWR_HS,
CFG_POST_PWR_HS,
CFG_TAG_MAX,
};
struct samsung_ufs_phy_cfg {
u32 off_0;
u32 off_1;
u32 val;
u8 desc;
u8 id;
};
struct samsung_ufs_phy_drvdata {
const struct samsung_ufs_phy_cfg **cfg;
struct pmu_isol {
u32 offset;
u32 mask;
u32 en;
} isol;
bool has_symbol_clk;
};
struct samsung_ufs_phy {
struct device *dev;
void __iomem *reg_pma;
struct regmap *reg_pmu;
struct clk *ref_clk;
struct clk *ref_clk_parent;
struct clk *tx0_symbol_clk;
struct clk *rx0_symbol_clk;
struct clk *rx1_symbol_clk;
const struct samsung_ufs_phy_drvdata *drvdata;
struct samsung_ufs_phy_cfg **cfg;
const struct pmu_isol *isol;
u8 lane_cnt;
int ufs_phy_state;
enum phy_mode mode;
};
static inline struct samsung_ufs_phy *get_samsung_ufs_phy(struct phy *phy)
{
return (struct samsung_ufs_phy *)phy_get_drvdata(phy);
}
static inline void samsung_ufs_phy_ctrl_isol(
struct samsung_ufs_phy *phy, u32 isol)
{
regmap_update_bits(phy->reg_pmu, phy->isol->offset,
phy->isol->mask, isol ? 0 : phy->isol->en);
}
#include "phy-exynos7-ufs.h"
#endif /* _PHY_SAMSUNG_UFS_ */
...@@ -255,7 +255,7 @@ static struct platform_driver samsung_usb2_phy_driver = { ...@@ -255,7 +255,7 @@ static struct platform_driver samsung_usb2_phy_driver = {
}; };
module_platform_driver(samsung_usb2_phy_driver); module_platform_driver(samsung_usb2_phy_driver);
MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver"); MODULE_DESCRIPTION("Samsung S5P/Exynos SoC USB PHY driver");
MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:samsung-usb2-phy"); MODULE_ALIAS("platform:samsung-usb2-phy");
...@@ -327,7 +327,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -327,7 +327,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
if (IS_ERR(usbphyc->base)) if (IS_ERR(usbphyc->base))
return PTR_ERR(usbphyc->base); return PTR_ERR(usbphyc->base);
usbphyc->clk = devm_clk_get(dev, 0); usbphyc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(usbphyc->clk)) { if (IS_ERR(usbphyc->clk)) {
ret = PTR_ERR(usbphyc->clk); ret = PTR_ERR(usbphyc->clk);
dev_err(dev, "clk get failed: %d\n", ret); dev_err(dev, "clk get failed: %d\n", ret);
...@@ -340,7 +340,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) ...@@ -340,7 +340,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
return ret; return ret;
} }
usbphyc->rst = devm_reset_control_get(dev, 0); usbphyc->rst = devm_reset_control_get(dev, NULL);
if (!IS_ERR(usbphyc->rst)) { if (!IS_ERR(usbphyc->rst)) {
reset_control_assert(usbphyc->rst); reset_control_assert(usbphyc->rst);
udelay(2); udelay(2);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
This diff is collapsed.
...@@ -18,5 +18,6 @@ ...@@ -18,5 +18,6 @@
#define PHY_TYPE_UFS 5 #define PHY_TYPE_UFS 5
#define PHY_TYPE_DP 6 #define PHY_TYPE_DP 6
#define PHY_TYPE_XPCS 7 #define PHY_TYPE_XPCS 7
#define PHY_TYPE_SGMII 8
#endif /* _DT_BINDINGS_PHY */ #endif /* _DT_BINDINGS_PHY */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment