1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 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 and 6 * only version 2 as published by the Free Software Foundation. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/usb/chipidea.h> 13 #include <linux/clk.h> 14 #include <linux/reset.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/regmap.h> 17 #include <linux/io.h> 18 #include <linux/reset-controller.h> 19 #include <linux/extcon.h> 20 #include <linux/of.h> 21 22 #include "ci.h" 23 24 #define HS_PHY_AHB_MODE 0x0098 25 26 #define HS_PHY_GENCONFIG 0x009c 27 #define HS_PHY_TXFIFO_IDLE_FORCE_DIS BIT(4) 28 29 #define HS_PHY_GENCONFIG_2 0x00a0 30 #define HS_PHY_SESS_VLD_CTRL_EN BIT(7) 31 #define HS_PHY_ULPI_TX_PKT_EN_CLR_FIX BIT(19) 32 33 #define HSPHY_SESS_VLD_CTRL BIT(25) 34 35 /* Vendor base starts at 0x200 beyond CI base */ 36 #define HS_PHY_CTRL 0x0040 37 #define HS_PHY_SEC_CTRL 0x0078 38 #define HS_PHY_DIG_CLAMP_N BIT(16) 39 #define HS_PHY_POR_ASSERT BIT(0) 40 41 struct ci_hdrc_msm { 42 struct platform_device *ci; 43 struct clk *core_clk; 44 struct clk *iface_clk; 45 struct clk *fs_clk; 46 struct ci_hdrc_platform_data pdata; 47 struct reset_controller_dev rcdev; 48 bool secondary_phy; 49 bool hsic; 50 void __iomem *base; 51 }; 52 53 static int 54 ci_hdrc_msm_por_reset(struct reset_controller_dev *r, unsigned long id) 55 { 56 struct ci_hdrc_msm *ci_msm = container_of(r, struct ci_hdrc_msm, rcdev); 57 void __iomem *addr = ci_msm->base; 58 u32 val; 59 60 if (id) 61 addr += HS_PHY_SEC_CTRL; 62 else 63 addr += HS_PHY_CTRL; 64 65 val = readl_relaxed(addr); 66 val |= HS_PHY_POR_ASSERT; 67 writel(val, addr); 68 /* 69 * wait for minimum 10 microseconds as suggested by manual. 70 * Use a slightly larger value since the exact value didn't 71 * work 100% of the time. 72 */ 73 udelay(12); 74 val &= ~HS_PHY_POR_ASSERT; 75 writel(val, addr); 76 77 return 0; 78 } 79 80 static const struct reset_control_ops ci_hdrc_msm_reset_ops = { 81 .reset = ci_hdrc_msm_por_reset, 82 }; 83 84 static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) 85 { 86 struct device *dev = ci->dev->parent; 87 struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev); 88 int ret; 89 90 switch (event) { 91 case CI_HDRC_CONTROLLER_RESET_EVENT: 92 dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); 93 94 hw_phymode_configure(ci); 95 if (msm_ci->secondary_phy) { 96 u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL); 97 val |= HS_PHY_DIG_CLAMP_N; 98 writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL); 99 } 100 101 ret = phy_init(ci->phy); 102 if (ret) 103 return ret; 104 105 ret = phy_power_on(ci->phy); 106 if (ret) { 107 phy_exit(ci->phy); 108 return ret; 109 } 110 111 /* use AHB transactor, allow posted data writes */ 112 hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0xffffffff, 0x8); 113 114 /* workaround for rx buffer collision issue */ 115 hw_write_id_reg(ci, HS_PHY_GENCONFIG, 116 HS_PHY_TXFIFO_IDLE_FORCE_DIS, 0); 117 118 if (!msm_ci->hsic) 119 hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, 120 HS_PHY_ULPI_TX_PKT_EN_CLR_FIX, 0); 121 122 if (!IS_ERR(ci->platdata->vbus_extcon.edev)) { 123 hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, 124 HS_PHY_SESS_VLD_CTRL_EN, 125 HS_PHY_SESS_VLD_CTRL_EN); 126 hw_write(ci, OP_USBCMD, HSPHY_SESS_VLD_CTRL, 127 HSPHY_SESS_VLD_CTRL); 128 129 } 130 break; 131 case CI_HDRC_CONTROLLER_STOPPED_EVENT: 132 dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); 133 phy_power_off(ci->phy); 134 phy_exit(ci->phy); 135 break; 136 default: 137 dev_dbg(dev, "unknown ci_hdrc event\n"); 138 break; 139 } 140 141 return 0; 142 } 143 144 static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci, 145 struct platform_device *pdev) 146 { 147 struct regmap *regmap; 148 struct device *dev = &pdev->dev; 149 struct of_phandle_args args; 150 u32 val; 151 int ret; 152 153 ret = of_parse_phandle_with_fixed_args(dev->of_node, "phy-select", 2, 0, 154 &args); 155 if (ret) 156 return 0; 157 158 regmap = syscon_node_to_regmap(args.np); 159 of_node_put(args.np); 160 if (IS_ERR(regmap)) 161 return PTR_ERR(regmap); 162 163 ret = regmap_write(regmap, args.args[0], args.args[1]); 164 if (ret) 165 return ret; 166 167 ci->secondary_phy = !!args.args[1]; 168 if (ci->secondary_phy) { 169 val = readl_relaxed(ci->base + HS_PHY_SEC_CTRL); 170 val |= HS_PHY_DIG_CLAMP_N; 171 writel_relaxed(val, ci->base + HS_PHY_SEC_CTRL); 172 } 173 174 return 0; 175 } 176 177 static int ci_hdrc_msm_probe(struct platform_device *pdev) 178 { 179 struct ci_hdrc_msm *ci; 180 struct platform_device *plat_ci; 181 struct clk *clk; 182 struct reset_control *reset; 183 struct resource *res; 184 int ret; 185 struct device_node *ulpi_node, *phy_node; 186 187 dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); 188 189 ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL); 190 if (!ci) 191 return -ENOMEM; 192 platform_set_drvdata(pdev, ci); 193 194 ci->pdata.name = "ci_hdrc_msm"; 195 ci->pdata.capoffset = DEF_CAPOFFSET; 196 ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING | 197 CI_HDRC_OVERRIDE_AHB_BURST | 198 CI_HDRC_OVERRIDE_PHY_CONTROL; 199 ci->pdata.notify_event = ci_hdrc_msm_notify_event; 200 201 reset = devm_reset_control_get(&pdev->dev, "core"); 202 if (IS_ERR(reset)) 203 return PTR_ERR(reset); 204 205 ci->core_clk = clk = devm_clk_get(&pdev->dev, "core"); 206 if (IS_ERR(clk)) 207 return PTR_ERR(clk); 208 209 ci->iface_clk = clk = devm_clk_get(&pdev->dev, "iface"); 210 if (IS_ERR(clk)) 211 return PTR_ERR(clk); 212 213 ci->fs_clk = clk = devm_clk_get(&pdev->dev, "fs"); 214 if (IS_ERR(clk)) { 215 if (PTR_ERR(clk) == -EPROBE_DEFER) 216 return -EPROBE_DEFER; 217 ci->fs_clk = NULL; 218 } 219 220 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 221 ci->base = devm_ioremap_resource(&pdev->dev, res); 222 if (IS_ERR(ci->base)) 223 return PTR_ERR(ci->base); 224 225 ci->rcdev.owner = THIS_MODULE; 226 ci->rcdev.ops = &ci_hdrc_msm_reset_ops; 227 ci->rcdev.of_node = pdev->dev.of_node; 228 ci->rcdev.nr_resets = 2; 229 ret = reset_controller_register(&ci->rcdev); 230 if (ret) 231 return ret; 232 233 ret = clk_prepare_enable(ci->fs_clk); 234 if (ret) 235 goto err_fs; 236 237 reset_control_assert(reset); 238 usleep_range(10000, 12000); 239 reset_control_deassert(reset); 240 241 clk_disable_unprepare(ci->fs_clk); 242 243 ret = clk_prepare_enable(ci->core_clk); 244 if (ret) 245 goto err_fs; 246 247 ret = clk_prepare_enable(ci->iface_clk); 248 if (ret) 249 goto err_iface; 250 251 ret = ci_hdrc_msm_mux_phy(ci, pdev); 252 if (ret) 253 goto err_mux; 254 255 ulpi_node = of_find_node_by_name(of_node_get(pdev->dev.of_node), "ulpi"); 256 if (ulpi_node) { 257 phy_node = of_get_next_available_child(ulpi_node, NULL); 258 ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy"); 259 of_node_put(phy_node); 260 } 261 of_node_put(ulpi_node); 262 263 plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource, 264 pdev->num_resources, &ci->pdata); 265 if (IS_ERR(plat_ci)) { 266 ret = PTR_ERR(plat_ci); 267 if (ret != -EPROBE_DEFER) 268 dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); 269 goto err_mux; 270 } 271 272 ci->ci = plat_ci; 273 274 pm_runtime_set_active(&pdev->dev); 275 pm_runtime_no_callbacks(&pdev->dev); 276 pm_runtime_enable(&pdev->dev); 277 278 return 0; 279 280 err_mux: 281 clk_disable_unprepare(ci->iface_clk); 282 err_iface: 283 clk_disable_unprepare(ci->core_clk); 284 err_fs: 285 reset_controller_unregister(&ci->rcdev); 286 return ret; 287 } 288 289 static int ci_hdrc_msm_remove(struct platform_device *pdev) 290 { 291 struct ci_hdrc_msm *ci = platform_get_drvdata(pdev); 292 293 pm_runtime_disable(&pdev->dev); 294 ci_hdrc_remove_device(ci->ci); 295 clk_disable_unprepare(ci->iface_clk); 296 clk_disable_unprepare(ci->core_clk); 297 reset_controller_unregister(&ci->rcdev); 298 299 return 0; 300 } 301 302 static const struct of_device_id msm_ci_dt_match[] = { 303 { .compatible = "qcom,ci-hdrc", }, 304 { } 305 }; 306 MODULE_DEVICE_TABLE(of, msm_ci_dt_match); 307 308 static struct platform_driver ci_hdrc_msm_driver = { 309 .probe = ci_hdrc_msm_probe, 310 .remove = ci_hdrc_msm_remove, 311 .driver = { 312 .name = "msm_hsusb", 313 .of_match_table = msm_ci_dt_match, 314 }, 315 }; 316 317 module_platform_driver(ci_hdrc_msm_driver); 318 319 MODULE_ALIAS("platform:msm_hsusb"); 320 MODULE_ALIAS("platform:ci13xxx_msm"); 321 MODULE_LICENSE("GPL v2"); 322