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.

phy: qcom: Introduce M31 USB PHY driver

Add the M31 USB2 phy driver for the USB M31 PHY
(https://www.m31tech.com) found in Qualcomm IPQ5018, IPQ5332
SoCs.

Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
Reviewed-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/c8821bb0124a54cc774a2ff7b9c40df28eb7711e.1691999761.git.quic_varada@quicinc.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Varadarajan Narayanan and committed by
Vinod Koul
08e49af5 f444491c

+306
+11
drivers/phy/qualcomm/Kconfig
··· 143 143 PMICs. The repeater is paired with a Synopsys eUSB2 Phy 144 144 on Qualcomm SOCs. 145 145 146 + config PHY_QCOM_M31_USB 147 + tristate "Qualcomm M31 HS PHY driver support" 148 + depends on USB && (ARCH_QCOM || COMPILE_TEST) 149 + select GENERIC_PHY 150 + help 151 + Enable this to support M31 HS PHY transceivers on Qualcomm chips 152 + with DWC3 USB core. It handles PHY initialization, clock 153 + management required after resetting the hardware and power 154 + management. This driver is required even for peripheral only or 155 + host only mode configurations. 156 + 146 157 config PHY_QCOM_USB_HS 147 158 tristate "Qualcomm USB HS PHY module" 148 159 depends on USB_ULPI_BUS
+1
drivers/phy/qualcomm/Makefile
··· 4 4 obj-$(CONFIG_PHY_QCOM_EDP) += phy-qcom-edp.o 5 5 obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o 6 6 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o 7 + obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o 7 8 obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o 8 9 9 10 obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o
+294
drivers/phy/qualcomm/phy-qcom-m31.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (c) 2014-2023, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/delay.h> 8 + #include <linux/err.h> 9 + #include <linux/io.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/of.h> 13 + #include <linux/phy/phy.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/reset.h> 16 + #include <linux/slab.h> 17 + 18 + #define USB2PHY_PORT_UTMI_CTRL1 0x40 19 + 20 + #define USB2PHY_PORT_UTMI_CTRL2 0x44 21 + #define UTMI_ULPI_SEL BIT(7) 22 + #define UTMI_TEST_MUX_SEL BIT(6) 23 + 24 + #define HS_PHY_CTRL_REG 0x10 25 + #define UTMI_OTG_VBUS_VALID BIT(20) 26 + #define SW_SESSVLD_SEL BIT(28) 27 + 28 + #define USB_PHY_UTMI_CTRL0 0x3c 29 + 30 + #define USB_PHY_UTMI_CTRL5 0x50 31 + #define POR_EN BIT(1) 32 + 33 + #define USB_PHY_HS_PHY_CTRL_COMMON0 0x54 34 + #define COMMONONN BIT(7) 35 + #define FSEL BIT(4) 36 + #define RETENABLEN BIT(3) 37 + #define FREQ_24MHZ (BIT(6) | BIT(4)) 38 + 39 + #define USB_PHY_HS_PHY_CTRL2 0x64 40 + #define USB2_SUSPEND_N_SEL BIT(3) 41 + #define USB2_SUSPEND_N BIT(2) 42 + #define USB2_UTMI_CLK_EN BIT(1) 43 + 44 + #define USB_PHY_CFG0 0x94 45 + #define UTMI_PHY_OVERRIDE_EN BIT(1) 46 + 47 + #define USB_PHY_REFCLK_CTRL 0xa0 48 + #define CLKCORE BIT(1) 49 + 50 + #define USB2PHY_PORT_POWERDOWN 0xa4 51 + #define POWER_UP BIT(0) 52 + #define POWER_DOWN 0 53 + 54 + #define USB_PHY_FSEL_SEL 0xb8 55 + #define FREQ_SEL BIT(0) 56 + 57 + #define USB2PHY_USB_PHY_M31_XCFGI_1 0xbc 58 + #define USB2_0_TX_ENABLE BIT(2) 59 + 60 + #define USB2PHY_USB_PHY_M31_XCFGI_4 0xc8 61 + #define HSTX_SLEW_RATE_565PS GENMASK(1, 0) 62 + #define PLL_CHARGING_PUMP_CURRENT_35UA GENMASK(4, 3) 63 + #define ODT_VALUE_38_02_OHM GENMASK(7, 6) 64 + 65 + #define USB2PHY_USB_PHY_M31_XCFGI_5 0xcc 66 + #define ODT_VALUE_45_02_OHM BIT(2) 67 + #define HSTX_PRE_EMPHASIS_LEVEL_0_55MA BIT(0) 68 + 69 + #define USB2PHY_USB_PHY_M31_XCFGI_11 0xe4 70 + #define XCFG_COARSE_TUNE_NUM BIT(1) 71 + #define XCFG_FINE_TUNE_NUM BIT(3) 72 + 73 + struct m31_phy_regs { 74 + u32 off; 75 + u32 val; 76 + u32 delay; 77 + }; 78 + 79 + struct m31_priv_data { 80 + bool ulpi_mode; 81 + const struct m31_phy_regs *regs; 82 + unsigned int nregs; 83 + }; 84 + 85 + struct m31_phy_regs m31_ipq5332_regs[] = { 86 + { 87 + USB_PHY_CFG0, 88 + UTMI_PHY_OVERRIDE_EN, 89 + 0 90 + }, 91 + { 92 + USB_PHY_UTMI_CTRL5, 93 + POR_EN, 94 + 15 95 + }, 96 + { 97 + USB_PHY_FSEL_SEL, 98 + FREQ_SEL, 99 + 0 100 + }, 101 + { 102 + USB_PHY_HS_PHY_CTRL_COMMON0, 103 + COMMONONN | FREQ_24MHZ | RETENABLEN, 104 + 0 105 + }, 106 + { 107 + USB_PHY_UTMI_CTRL5, 108 + POR_EN, 109 + 0 110 + }, 111 + { 112 + USB_PHY_HS_PHY_CTRL2, 113 + USB2_SUSPEND_N_SEL | USB2_SUSPEND_N | USB2_UTMI_CLK_EN, 114 + 0 115 + }, 116 + { 117 + USB2PHY_USB_PHY_M31_XCFGI_11, 118 + XCFG_COARSE_TUNE_NUM | XCFG_FINE_TUNE_NUM, 119 + 0 120 + }, 121 + { 122 + USB2PHY_USB_PHY_M31_XCFGI_4, 123 + HSTX_SLEW_RATE_565PS | PLL_CHARGING_PUMP_CURRENT_35UA | ODT_VALUE_38_02_OHM, 124 + 0 125 + }, 126 + { 127 + USB2PHY_USB_PHY_M31_XCFGI_1, 128 + USB2_0_TX_ENABLE, 129 + 0 130 + }, 131 + { 132 + USB2PHY_USB_PHY_M31_XCFGI_5, 133 + ODT_VALUE_45_02_OHM | HSTX_PRE_EMPHASIS_LEVEL_0_55MA, 134 + 4 135 + }, 136 + { 137 + USB_PHY_UTMI_CTRL5, 138 + 0x0, 139 + 0 140 + }, 141 + { 142 + USB_PHY_HS_PHY_CTRL2, 143 + USB2_SUSPEND_N | USB2_UTMI_CLK_EN, 144 + 0 145 + }, 146 + }; 147 + 148 + struct m31usb_phy { 149 + struct phy *phy; 150 + void __iomem *base; 151 + const struct m31_phy_regs *regs; 152 + int nregs; 153 + 154 + struct regulator *vreg; 155 + struct clk *clk; 156 + struct reset_control *reset; 157 + 158 + bool ulpi_mode; 159 + }; 160 + 161 + static int m31usb_phy_init(struct phy *phy) 162 + { 163 + struct m31usb_phy *qphy = phy_get_drvdata(phy); 164 + const struct m31_phy_regs *regs = qphy->regs; 165 + int i, ret; 166 + 167 + ret = regulator_enable(qphy->vreg); 168 + if (ret) { 169 + dev_err(&phy->dev, "failed to enable regulator, %d\n", ret); 170 + return ret; 171 + } 172 + 173 + ret = clk_prepare_enable(qphy->clk); 174 + if (ret) { 175 + if (qphy->vreg) 176 + regulator_disable(qphy->vreg); 177 + dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret); 178 + return ret; 179 + } 180 + 181 + /* Perform phy reset */ 182 + reset_control_assert(qphy->reset); 183 + udelay(5); 184 + reset_control_deassert(qphy->reset); 185 + 186 + /* configure for ULPI mode if requested */ 187 + if (qphy->ulpi_mode) 188 + writel(0x0, qphy->base + USB2PHY_PORT_UTMI_CTRL2); 189 + 190 + /* Enable the PHY */ 191 + writel(POWER_UP, qphy->base + USB2PHY_PORT_POWERDOWN); 192 + 193 + /* Turn on phy ref clock */ 194 + for (i = 0; i < qphy->nregs; i++) { 195 + writel(regs[i].val, qphy->base + regs[i].off); 196 + if (regs[i].delay) 197 + udelay(regs[i].delay); 198 + } 199 + 200 + return 0; 201 + } 202 + 203 + static int m31usb_phy_shutdown(struct phy *phy) 204 + { 205 + struct m31usb_phy *qphy = phy_get_drvdata(phy); 206 + 207 + /* Disable the PHY */ 208 + writel_relaxed(POWER_DOWN, qphy->base + USB2PHY_PORT_POWERDOWN); 209 + 210 + clk_disable_unprepare(qphy->clk); 211 + 212 + regulator_disable(qphy->vreg); 213 + 214 + return 0; 215 + } 216 + 217 + static const struct phy_ops m31usb_phy_gen_ops = { 218 + .power_on = m31usb_phy_init, 219 + .power_off = m31usb_phy_shutdown, 220 + .owner = THIS_MODULE, 221 + }; 222 + 223 + static int m31usb_phy_probe(struct platform_device *pdev) 224 + { 225 + struct phy_provider *phy_provider; 226 + const struct m31_priv_data *data; 227 + struct device *dev = &pdev->dev; 228 + struct m31usb_phy *qphy; 229 + 230 + qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); 231 + if (!qphy) 232 + return -ENOMEM; 233 + 234 + qphy->base = devm_platform_ioremap_resource(pdev, 0); 235 + if (IS_ERR(qphy->base)) 236 + return PTR_ERR(qphy->base); 237 + 238 + qphy->reset = devm_reset_control_get_exclusive_by_index(dev, 0); 239 + if (IS_ERR(qphy->reset)) 240 + return PTR_ERR(qphy->reset); 241 + 242 + qphy->clk = devm_clk_get(dev, NULL); 243 + if (IS_ERR(qphy->clk)) 244 + return dev_err_probe(dev, PTR_ERR(qphy->clk), 245 + "failed to get clk\n"); 246 + 247 + data = of_device_get_match_data(dev); 248 + qphy->regs = data->regs; 249 + qphy->nregs = data->nregs; 250 + qphy->ulpi_mode = data->ulpi_mode; 251 + 252 + qphy->phy = devm_phy_create(dev, NULL, &m31usb_phy_gen_ops); 253 + if (IS_ERR(qphy->phy)) 254 + return dev_err_probe(dev, PTR_ERR(qphy->phy), 255 + "failed to create phy\n"); 256 + 257 + qphy->vreg = devm_regulator_get(dev, "vdda-phy"); 258 + if (IS_ERR(qphy->vreg)) 259 + return dev_err_probe(dev, PTR_ERR(qphy->phy), 260 + "failed to get vreg\n"); 261 + 262 + phy_set_drvdata(qphy->phy, qphy); 263 + 264 + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 265 + if (!IS_ERR(phy_provider)) 266 + dev_info(dev, "Registered M31 USB phy\n"); 267 + 268 + return PTR_ERR_OR_ZERO(phy_provider); 269 + } 270 + 271 + static const struct m31_priv_data m31_ipq5332_data = { 272 + .ulpi_mode = false, 273 + .regs = m31_ipq5332_regs, 274 + .nregs = ARRAY_SIZE(m31_ipq5332_regs), 275 + }; 276 + 277 + static const struct of_device_id m31usb_phy_id_table[] = { 278 + { .compatible = "qcom,ipq5332-usb-hsphy", .data = &m31_ipq5332_data }, 279 + { }, 280 + }; 281 + MODULE_DEVICE_TABLE(of, m31usb_phy_id_table); 282 + 283 + static struct platform_driver m31usb_phy_driver = { 284 + .probe = m31usb_phy_probe, 285 + .driver = { 286 + .name = "qcom-m31usb-phy", 287 + .of_match_table = m31usb_phy_id_table, 288 + }, 289 + }; 290 + 291 + module_platform_driver(m31usb_phy_driver); 292 + 293 + MODULE_DESCRIPTION("USB2 Qualcomm M31 HSPHY driver"); 294 + MODULE_LICENSE("GPL");