* [PATCH v7 0/5] Support qcom's HSIC USB and rewrite USB2 HS support
@ 2017-01-20 18:50 Stephen Boyd
[not found] ` <20170120185057.16206-1-stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-01-20 18:50 ` [PATCH v7 5/5] phy: Add support for Qualcomm's USB HS phy Stephen Boyd
0 siblings, 2 replies; 3+ messages in thread
From: Stephen Boyd @ 2017-01-20 18:50 UTC (permalink / raw)
To: Peter Chen, Kishon Vijay Abraham I
Cc: linux-arm-kernel, linux-kernel, linux-arm-msm, linux-usb,
Andy Gross, Bjorn Andersson, Neil Armstrong, Arnd Bergmann,
Felipe Balbi, Greg Kroah-Hartman, devicetree
This patch series continues the usb chipidea rewrite for
Qualcommm platforms. I've dropped the patches that were applied
to Peter's tree for chipidea. Now the phy drivers are left,
along with a new hook to set the vbus in the phy and changes
to chipidea to call the new hook.
I've left the HSIC phy driver here, because it wasn't merged in
the last round. Nothing has changed in that driver, so I believe
it is ready to be merged now. The real changes are the new
set_vbus() hook and how we're supposed to handle that in the HS
phy driver.
The only dependencies between subsystems is the set_vbus callback.
If that can go into some stable branch in the phy tree, then Kishon
can apply the phy patches on top of that and Peter can apply the small
chipidea patch on top of that. Or everything can go in parallel, except
for the chipidea patch that adds the set_vbus hook. That hook can be
added after rc1 when dependencies merge.
Patches based on v4.10-rc1 + first 22 patches from v5. Full
branch is here[1].
Changes from v6:
* Dropped first 22 applied patches
* Rewrote phy_set_mode() patch to be msm specific
* New set_vbus() callback in phy framework
* Updated HS phy driver for set_vbus() callback
Changes from v5:
* Replaced "Emulate OTGSC interrupt enable path" patch with a patch
from Peter
* Updated HS phy driver to support set_mode callback to handle pullup
* New patch to set the mode to device or host in chipidea udc pullup
function to toggle the pullup for HS mode
* New patch to drop lock around event_notify callback to avoid lockdep
issues
* Removal of extcon usage from HS phy driver
* Picked up acks from Heikki and Peter on ULPI core patch
Changes from v4:
* Picked up Acks from Rob
* Updated HS phy init sequence DT property to restrict it to offsets
Changes from v3:
* Picked up Acks from Peter
* Updated extcon consolidation patch per Peter's comments
* Folded in simplification from Heikki for ULPI DT matching
Changes from v2:
* Added SoC specific compatibles in phy bindings
* Dropped AVVIS patch for OTG statemachine
* New patch to consolidate extcon handlers
* Picked up Acks from Peter
* Rebased onto v4.8-rc1
* Reworked ULPI OF code to look at vid == 0 instead of pid == 0
* Dropped ULPI bindings for vid and pid overrides
Changes from v1:
* Reworked ULPI device probing to keep using vendor/product ids that
come from DT if needed and falls back to OF style match when product id
is 0
* PHY init later patch was rejected so that moved to a quirk flag and
the msm wrapper started managing the phy on/off
* Updated clk requirements for HSIC phy in binding doc
* Added optional clk in wrapper for "housekeeping" found on older qcom
platforms
* Bug fix to OTGSC polling function
* Changed runtime PM patch to set as active instead of get/put
TODO:
* DMA fails on arm64 so we need something like [2] to make it work.
* The db410c needs a driver to toggle the onboard switch to connect
the usb hub instead of micro port when the usb cable is disconnected.
I've sent a patch set for this[3], which needs some further
discussion/development. The current plan is to reintroduce the usb
mux framework.
* apq8064 platforms need a vbus regulator to really use otg and I haven't
tried out the RPM based regulators yet
* The HSIC phy on the apq8074 dragonboard is connected to a usb4604
device which requires the i2c driver to probe and send an i2c
sequence before the HSIC controller enumerates or HSIC doesn't work.
Right now I have a hack to force the controller to probe defer
once so that usb4604 probes first. This needs a more proper solution
like having the DT describe a linkage between the controller and
the usb device so we can enforce probe ordering. My current plan
is to use DT graphs/endpoints for this.
[1] https://git.linaro.org/people/stephen.boyd/linux.git/log/?h=usb-hsic-8074
[2] https://patchwork.kernel.org/patch/9319527/
[3] https://lkml.kernel.org/r/20160914014246.31847-1-stephen.boyd@linaro.org
Stephen Boyd (5):
phy: Add support for Qualcomm's USB HSIC phy
usb: chipidea: msm: Configure phy for appropriate mode
phy: Add set_vbus callback
usb: chipidea: Signal vbus state to phy
phy: Add support for Qualcomm's USB HS phy
.../devicetree/bindings/phy/qcom,usb-hs-phy.txt | 78 +++++++
.../devicetree/bindings/phy/qcom,usb-hsic-phy.txt | 65 ++++++
drivers/phy/Kconfig | 15 ++
drivers/phy/Makefile | 2 +
drivers/phy/phy-core.c | 15 ++
drivers/phy/phy-qcom-usb-hs.c | 256 +++++++++++++++++++++
drivers/phy/phy-qcom-usb-hsic.c | 160 +++++++++++++
drivers/usb/chipidea/ci.h | 7 +-
drivers/usb/chipidea/ci_hdrc_msm.c | 4 +
drivers/usb/chipidea/otg.c | 7 +-
include/linux/phy/phy.h | 10 +
11 files changed, 615 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt
create mode 100644 Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt
create mode 100644 drivers/phy/phy-qcom-usb-hs.c
create mode 100644 drivers/phy/phy-qcom-usb-hsic.c
--
2.10.0.297.gf6727b0
^ permalink raw reply [flat|nested] 3+ messages in thread[parent not found: <20170120185057.16206-1-stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* [PATCH v7 1/5] phy: Add support for Qualcomm's USB HSIC phy [not found] ` <20170120185057.16206-1-stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2017-01-20 18:50 ` Stephen Boyd 0 siblings, 0 replies; 3+ messages in thread From: Stephen Boyd @ 2017-01-20 18:50 UTC (permalink / raw) To: Peter Chen, Kishon Vijay Abraham I Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Andy Gross, Bjorn Andersson, Neil Armstrong, Arnd Bergmann, Felipe Balbi, linux-usb-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA The HSIC USB controller on qcom SoCs has an integrated all digital phy controlled via the ULPI viewport. Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> Cc: <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org> Signed-off-by: Stephen Boyd <stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- No changes. .../devicetree/bindings/phy/qcom,usb-hsic-phy.txt | 65 +++++++++ drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-usb-hsic.c | 160 +++++++++++++++++++++ 4 files changed, 233 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt create mode 100644 drivers/phy/phy-qcom-usb-hsic.c diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt new file mode 100644 index 000000000000..3c7cb2be4b12 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt @@ -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>; + }; + }; +}; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8eb7f225a88..a430a64981d5 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -437,6 +437,13 @@ config PHY_QCOM_UFS help Support for UFS PHY on QCOM 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 diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 65eb2f436a41..c43c9df5d301 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -52,6 +52,7 @@ 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_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 diff --git a/drivers/phy/phy-qcom-usb-hsic.c b/drivers/phy/phy-qcom-usb-hsic.c new file mode 100644 index 000000000000..47690f9945b9 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hsic.c @@ -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"); -- 2.10.0.297.gf6727b0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v7 5/5] phy: Add support for Qualcomm's USB HS phy 2017-01-20 18:50 [PATCH v7 0/5] Support qcom's HSIC USB and rewrite USB2 HS support Stephen Boyd [not found] ` <20170120185057.16206-1-stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2017-01-20 18:50 ` Stephen Boyd 1 sibling, 0 replies; 3+ messages in thread From: Stephen Boyd @ 2017-01-20 18:50 UTC (permalink / raw) To: Peter Chen, Kishon Vijay Abraham I Cc: linux-arm-kernel, linux-kernel, linux-arm-msm, Andy Gross, Bjorn Andersson, Neil Armstrong, Arnd Bergmann, Felipe Balbi, linux-usb, devicetree The high-speed phy on qcom SoCs is controlled via the ULPI viewport. Cc: <devicetree@vger.kernel.org> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org> --- phy_set_mode() hook split up to toggle two bits independently with new set_vbus() hook. .../devicetree/bindings/phy/qcom,usb-hs-phy.txt | 78 +++++++ drivers/phy/Kconfig | 8 + drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-usb-hs.c | 256 +++++++++++++++++++++ 4 files changed, 343 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt create mode 100644 drivers/phy/phy-qcom-usb-hs.c diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt new file mode 100644 index 000000000000..bec77a74bd39 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt @@ -0,0 +1,78 @@ +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 + +- 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>; + qcom,init-seq = /bits/ 8 <0x1 0x63>; + }; + }; +}; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a430a64981d5..61a22e985831 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -437,6 +437,14 @@ 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 diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index c43c9df5d301..0e4259473d28 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -52,6 +52,7 @@ 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 diff --git a/drivers/phy/phy-qcom-usb-hs.c b/drivers/phy/phy-qcom-usb-hs.c new file mode 100644 index 000000000000..50cb40977737 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hs.c @@ -0,0 +1,256 @@ +/** + * 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/usb/of.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; + enum usb_dr_mode dr_mode; +}; + +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, val = 0; + int ret; + + switch (mode) { + case PHY_MODE_USB_OTG: + switch (uphy->dr_mode) { + case USB_DR_MODE_OTG: + val |= ULPI_INT_IDGRD; + case USB_DR_MODE_PERIPHERAL: + val |= ULPI_INT_SESS_VALID; + default: + break; + } + + ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val); + if (ret) + return ret; + return ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val); + 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; + } + + ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG), + ULPI_PWR_OTG_COMP_DISABLE); + return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL); +} + +static int qcom_usb_hs_phy_set_vbus(struct phy *phy, int on) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + u8 addr, val; + int ret; + + if (on) + 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; + + 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; + } + + 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) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + + 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, + .set_vbus = qcom_usb_hs_phy_set_vbus, + .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; + uphy->dr_mode = of_usb_get_dr_mode_by_phy(ulpi->dev.of_node, -1); + + 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); + + 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"); -- 2.10.0.297.gf6727b0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-01-20 18:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-01-20 18:50 [PATCH v7 0/5] Support qcom's HSIC USB and rewrite USB2 HS support Stephen Boyd
[not found] ` <20170120185057.16206-1-stephen.boyd-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-01-20 18:50 ` [PATCH v7 1/5] phy: Add support for Qualcomm's USB HSIC phy Stephen Boyd
2017-01-20 18:50 ` [PATCH v7 5/5] phy: Add support for Qualcomm's USB HS phy Stephen Boyd
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox