^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016 Linaro Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/ulpi/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/ulpi/regs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/phy/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/pinctrl/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/pinctrl/pinctrl-state.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define ULPI_HSIC_CFG 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define ULPI_HSIC_IO_CAL 0x33
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct qcom_usb_hsic_phy {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct ulpi *ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct pinctrl *pctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct clk *phy_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct clk *cal_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct clk *cal_sleep_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int qcom_usb_hsic_phy_power_on(struct phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct ulpi *ulpi = uphy->ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct pinctrl_state *pins_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ret = clk_prepare_enable(uphy->phy_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ret = clk_prepare_enable(uphy->cal_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) goto err_cal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ret = clk_prepare_enable(uphy->cal_sleep_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) goto err_sleep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) goto err_ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Enable periodic IO calibration in HSIC_CFG register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) goto err_ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* Configure pins for HSIC functionality */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (IS_ERR(pins_default))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return PTR_ERR(pins_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ret = pinctrl_select_state(uphy->pctl, pins_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) goto err_ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* Enable HSIC mode in HSIC_CFG register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) goto err_ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Disable auto-resume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ULPI_IFC_CTRL_AUTORESUME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) goto err_ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) err_ulpi:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) clk_disable_unprepare(uphy->cal_sleep_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) err_sleep:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) clk_disable_unprepare(uphy->cal_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) err_cal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) clk_disable_unprepare(uphy->phy_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int qcom_usb_hsic_phy_power_off(struct phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) clk_disable_unprepare(uphy->cal_sleep_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) clk_disable_unprepare(uphy->cal_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) clk_disable_unprepare(uphy->phy_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static const struct phy_ops qcom_usb_hsic_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .power_on = qcom_usb_hsic_phy_power_on,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .power_off = qcom_usb_hsic_phy_power_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct qcom_usb_hsic_phy *uphy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct phy_provider *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!uphy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ulpi_set_drvdata(ulpi, uphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) uphy->ulpi = ulpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) uphy->pctl = devm_pinctrl_get(&ulpi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (IS_ERR(uphy->pctl))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return PTR_ERR(uphy->pctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) &qcom_usb_hsic_phy_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (IS_ERR(uphy->phy))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return PTR_ERR(uphy->phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) phy_set_drvdata(uphy->phy, uphy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return PTR_ERR_OR_ZERO(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static const struct of_device_id qcom_usb_hsic_phy_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) { .compatible = "qcom,usb-hsic-phy", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static struct ulpi_driver qcom_usb_hsic_phy_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .probe = qcom_usb_hsic_phy_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .name = "qcom_usb_hsic_phy",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .of_match_table = qcom_usb_hsic_phy_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) module_ulpi_driver(qcom_usb_hsic_phy_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) MODULE_DESCRIPTION("Qualcomm USB HSIC phy");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) MODULE_LICENSE("GPL v2");