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