Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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