Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Linaro Ltd
0004  */
0005 #include <linux/module.h>
0006 #include <linux/ulpi/driver.h>
0007 #include <linux/ulpi/regs.h>
0008 #include <linux/phy/phy.h>
0009 #include <linux/pinctrl/consumer.h>
0010 #include <linux/pinctrl/pinctrl-state.h>
0011 #include <linux/delay.h>
0012 #include <linux/clk.h>
0013 
0014 #define ULPI_HSIC_CFG       0x30
0015 #define ULPI_HSIC_IO_CAL    0x33
0016 
0017 struct qcom_usb_hsic_phy {
0018     struct ulpi *ulpi;
0019     struct phy *phy;
0020     struct pinctrl *pctl;
0021     struct clk *phy_clk;
0022     struct clk *cal_clk;
0023     struct clk *cal_sleep_clk;
0024 };
0025 
0026 static int qcom_usb_hsic_phy_power_on(struct phy *phy)
0027 {
0028     struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
0029     struct ulpi *ulpi = uphy->ulpi;
0030     struct pinctrl_state *pins_default;
0031     int ret;
0032 
0033     ret = clk_prepare_enable(uphy->phy_clk);
0034     if (ret)
0035         return ret;
0036 
0037     ret = clk_prepare_enable(uphy->cal_clk);
0038     if (ret)
0039         goto err_cal;
0040 
0041     ret = clk_prepare_enable(uphy->cal_sleep_clk);
0042     if (ret)
0043         goto err_sleep;
0044 
0045     /* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
0046     ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff);
0047     if (ret)
0048         goto err_ulpi;
0049 
0050     /* Enable periodic IO calibration in HSIC_CFG register */
0051     ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8);
0052     if (ret)
0053         goto err_ulpi;
0054 
0055     /* Configure pins for HSIC functionality */
0056     pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT);
0057     if (IS_ERR(pins_default))
0058         return PTR_ERR(pins_default);
0059 
0060     ret = pinctrl_select_state(uphy->pctl, pins_default);
0061     if (ret)
0062         goto err_ulpi;
0063 
0064      /* Enable HSIC mode in HSIC_CFG register */
0065     ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01);
0066     if (ret)
0067         goto err_ulpi;
0068 
0069     /* Disable auto-resume */
0070     ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL),
0071              ULPI_IFC_CTRL_AUTORESUME);
0072     if (ret)
0073         goto err_ulpi;
0074 
0075     return ret;
0076 err_ulpi:
0077     clk_disable_unprepare(uphy->cal_sleep_clk);
0078 err_sleep:
0079     clk_disable_unprepare(uphy->cal_clk);
0080 err_cal:
0081     clk_disable_unprepare(uphy->phy_clk);
0082     return ret;
0083 }
0084 
0085 static int qcom_usb_hsic_phy_power_off(struct phy *phy)
0086 {
0087     struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
0088 
0089     clk_disable_unprepare(uphy->cal_sleep_clk);
0090     clk_disable_unprepare(uphy->cal_clk);
0091     clk_disable_unprepare(uphy->phy_clk);
0092 
0093     return 0;
0094 }
0095 
0096 static const struct phy_ops qcom_usb_hsic_phy_ops = {
0097     .power_on = qcom_usb_hsic_phy_power_on,
0098     .power_off = qcom_usb_hsic_phy_power_off,
0099     .owner = THIS_MODULE,
0100 };
0101 
0102 static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi)
0103 {
0104     struct qcom_usb_hsic_phy *uphy;
0105     struct phy_provider *p;
0106     struct clk *clk;
0107 
0108     uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
0109     if (!uphy)
0110         return -ENOMEM;
0111     ulpi_set_drvdata(ulpi, uphy);
0112 
0113     uphy->ulpi = ulpi;
0114     uphy->pctl = devm_pinctrl_get(&ulpi->dev);
0115     if (IS_ERR(uphy->pctl))
0116         return PTR_ERR(uphy->pctl);
0117 
0118     uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy");
0119     if (IS_ERR(clk))
0120         return PTR_ERR(clk);
0121 
0122     uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal");
0123     if (IS_ERR(clk))
0124         return PTR_ERR(clk);
0125 
0126     uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep");
0127     if (IS_ERR(clk))
0128         return PTR_ERR(clk);
0129 
0130     uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
0131                     &qcom_usb_hsic_phy_ops);
0132     if (IS_ERR(uphy->phy))
0133         return PTR_ERR(uphy->phy);
0134     phy_set_drvdata(uphy->phy, uphy);
0135 
0136     p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
0137     return PTR_ERR_OR_ZERO(p);
0138 }
0139 
0140 static const struct of_device_id qcom_usb_hsic_phy_match[] = {
0141     { .compatible = "qcom,usb-hsic-phy", },
0142     { }
0143 };
0144 MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match);
0145 
0146 static struct ulpi_driver qcom_usb_hsic_phy_driver = {
0147     .probe = qcom_usb_hsic_phy_probe,
0148     .driver = {
0149         .name = "qcom_usb_hsic_phy",
0150         .of_match_table = qcom_usb_hsic_phy_match,
0151     },
0152 };
0153 module_ulpi_driver(qcom_usb_hsic_phy_driver);
0154 
0155 MODULE_DESCRIPTION("Qualcomm USB HSIC phy");
0156 MODULE_LICENSE("GPL v2");