1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * phy-google-usb.c - Google USB PHY driver 4 * 5 * Copyright (C) 2025, Google LLC 6 */ 7 8 #include <linux/bitfield.h> 9 #include <linux/cleanup.h> 10 #include <linux/clk.h> 11 #include <linux/io.h> 12 #include <linux/kernel.h> 13 #include <linux/mfd/syscon.h> 14 #include <linux/module.h> 15 #include <linux/mutex.h> 16 #include <linux/of.h> 17 #include <linux/phy/phy.h> 18 #include <linux/platform_device.h> 19 #include <linux/regmap.h> 20 #include <linux/reset.h> 21 #include <linux/usb/typec_mux.h> 22 23 #define USBCS_USB2PHY_CFG19_OFFSET 0x0 24 #define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8) 25 26 #define USBCS_USB2PHY_CFG21_OFFSET 0x8 27 #define USBCS_USB2PHY_CFG21_PHY_ENABLE BIT(12) 28 #define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13) 29 #define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19) 30 31 #define USBCS_PHY_CFG1_OFFSET 0x28 32 #define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17) 33 34 enum google_usb_phy_id { 35 GOOGLE_USB2_PHY, 36 GOOGLE_USB_PHY_NUM, 37 }; 38 39 struct google_usb_phy_instance { 40 struct google_usb_phy *parent; 41 unsigned int index; 42 struct phy *phy; 43 unsigned int num_clks; 44 struct clk_bulk_data *clks; 45 unsigned int num_rsts; 46 struct reset_control_bulk_data *rsts; 47 }; 48 49 struct google_usb_phy { 50 struct device *dev; 51 struct regmap *usb_cfg_regmap; 52 unsigned int usb2_cfg_offset; 53 void __iomem *usbdp_top_base; 54 struct google_usb_phy_instance *insts; 55 /* 56 * Protect phy registers from concurrent access, specifically via 57 * google_usb_set_orientation callback. 58 */ 59 struct mutex phy_mutex; 60 struct typec_switch_dev *sw; 61 enum typec_orientation orientation; 62 }; 63 64 static void set_vbus_valid(struct google_usb_phy *gphy) 65 { 66 u32 reg; 67 68 if (gphy->orientation == TYPEC_ORIENTATION_NONE) { 69 reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET); 70 reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID; 71 writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET); 72 } else { 73 reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET); 74 reg |= USBCS_PHY_CFG1_SYS_VBUSVALID; 75 writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET); 76 } 77 } 78 79 static int google_usb_set_orientation(struct typec_switch_dev *sw, 80 enum typec_orientation orientation) 81 { 82 struct google_usb_phy *gphy = typec_switch_get_drvdata(sw); 83 84 dev_dbg(gphy->dev, "set orientation %d\n", orientation); 85 86 gphy->orientation = orientation; 87 88 if (pm_runtime_suspended(gphy->dev)) 89 return 0; 90 91 guard(mutex)(&gphy->phy_mutex); 92 93 set_vbus_valid(gphy); 94 95 return 0; 96 } 97 98 static int google_usb2_phy_init(struct phy *_phy) 99 { 100 struct google_usb_phy_instance *inst = phy_get_drvdata(_phy); 101 struct google_usb_phy *gphy = inst->parent; 102 u32 reg; 103 int ret; 104 105 dev_dbg(gphy->dev, "initializing usb2 phy\n"); 106 107 guard(mutex)(&gphy->phy_mutex); 108 109 regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, ®); 110 reg &= ~USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL; 111 reg &= ~USBCS_USB2PHY_CFG21_REF_FREQ_SEL; 112 reg |= FIELD_PREP(USBCS_USB2PHY_CFG21_REF_FREQ_SEL, 0); 113 regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg); 114 115 regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, ®); 116 reg &= ~USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV; 117 reg |= FIELD_PREP(USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV, 368); 118 regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG19_OFFSET, reg); 119 120 set_vbus_valid(gphy); 121 122 ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks); 123 if (ret) 124 return ret; 125 126 ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts); 127 if (ret) { 128 clk_bulk_disable_unprepare(inst->num_clks, inst->clks); 129 return ret; 130 } 131 132 regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, ®); 133 reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE; 134 regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg); 135 136 return 0; 137 } 138 139 static int google_usb2_phy_exit(struct phy *_phy) 140 { 141 struct google_usb_phy_instance *inst = phy_get_drvdata(_phy); 142 struct google_usb_phy *gphy = inst->parent; 143 u32 reg; 144 145 dev_dbg(gphy->dev, "exiting usb2 phy\n"); 146 147 guard(mutex)(&gphy->phy_mutex); 148 149 regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, ®); 150 reg &= ~USBCS_USB2PHY_CFG21_PHY_ENABLE; 151 regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg); 152 153 reset_control_bulk_assert(inst->num_rsts, inst->rsts); 154 clk_bulk_disable_unprepare(inst->num_clks, inst->clks); 155 156 return 0; 157 } 158 159 static const struct phy_ops google_usb2_phy_ops = { 160 .init = google_usb2_phy_init, 161 .exit = google_usb2_phy_exit, 162 }; 163 164 static struct phy *google_usb_phy_xlate(struct device *dev, 165 const struct of_phandle_args *args) 166 { 167 struct google_usb_phy *gphy = dev_get_drvdata(dev); 168 169 if (args->args[0] >= GOOGLE_USB_PHY_NUM) { 170 dev_err(dev, "invalid PHY index requested from DT\n"); 171 return ERR_PTR(-ENODEV); 172 } 173 return gphy->insts[args->args[0]].phy; 174 } 175 176 static int google_usb_phy_probe(struct platform_device *pdev) 177 { 178 struct typec_switch_desc sw_desc = { }; 179 struct google_usb_phy_instance *inst; 180 struct phy_provider *phy_provider; 181 struct device *dev = &pdev->dev; 182 struct google_usb_phy *gphy; 183 struct phy *phy; 184 u32 args[1]; 185 int ret; 186 187 gphy = devm_kzalloc(dev, sizeof(*gphy), GFP_KERNEL); 188 if (!gphy) 189 return -ENOMEM; 190 191 dev_set_drvdata(dev, gphy); 192 gphy->dev = dev; 193 194 ret = devm_mutex_init(dev, &gphy->phy_mutex); 195 if (ret) 196 return ret; 197 198 gphy->usb_cfg_regmap = 199 syscon_regmap_lookup_by_phandle_args(dev->of_node, 200 "google,usb-cfg-csr", 201 ARRAY_SIZE(args), args); 202 if (IS_ERR(gphy->usb_cfg_regmap)) { 203 return dev_err_probe(dev, PTR_ERR(gphy->usb_cfg_regmap), 204 "invalid usb cfg csr\n"); 205 } 206 207 gphy->usb2_cfg_offset = args[0]; 208 209 gphy->usbdp_top_base = devm_platform_ioremap_resource_byname(pdev, 210 "usbdp_top"); 211 if (IS_ERR(gphy->usbdp_top_base)) 212 return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base), 213 "invalid usbdp top\n"); 214 215 gphy->insts = devm_kcalloc(dev, GOOGLE_USB_PHY_NUM, sizeof(*gphy->insts), GFP_KERNEL); 216 if (!gphy->insts) 217 return -ENOMEM; 218 219 inst = &gphy->insts[GOOGLE_USB2_PHY]; 220 inst->parent = gphy; 221 inst->index = GOOGLE_USB2_PHY; 222 phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops); 223 if (IS_ERR(phy)) 224 return dev_err_probe(dev, PTR_ERR(phy), 225 "failed to create usb2 phy instance\n"); 226 inst->phy = phy; 227 phy_set_drvdata(phy, inst); 228 229 inst->num_clks = 2; 230 inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL); 231 if (!inst->clks) 232 return -ENOMEM; 233 inst->clks[0].id = "usb2"; 234 inst->clks[1].id = "usb2_apb"; 235 ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks); 236 if (ret) 237 return dev_err_probe(dev, ret, "failed to get u2 phy clks\n"); 238 239 inst->num_rsts = 2; 240 inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL); 241 if (!inst->rsts) 242 return -ENOMEM; 243 inst->rsts[0].id = "usb2"; 244 inst->rsts[1].id = "usb2_apb"; 245 ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts); 246 if (ret) 247 return dev_err_probe(dev, ret, "failed to get u2 phy resets\n"); 248 249 phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate); 250 if (IS_ERR(phy_provider)) 251 return dev_err_probe(dev, PTR_ERR(phy_provider), 252 "failed to register phy provider\n"); 253 254 pm_runtime_enable(dev); 255 256 sw_desc.fwnode = dev_fwnode(dev); 257 sw_desc.drvdata = gphy; 258 sw_desc.name = fwnode_get_name(dev_fwnode(dev)); 259 sw_desc.set = google_usb_set_orientation; 260 261 gphy->sw = typec_switch_register(dev, &sw_desc); 262 if (IS_ERR(gphy->sw)) 263 return dev_err_probe(dev, PTR_ERR(gphy->sw), 264 "failed to register typec switch\n"); 265 266 return 0; 267 } 268 269 static void google_usb_phy_remove(struct platform_device *pdev) 270 { 271 struct google_usb_phy *gphy = dev_get_drvdata(&pdev->dev); 272 273 typec_switch_unregister(gphy->sw); 274 pm_runtime_disable(&pdev->dev); 275 } 276 277 static const struct of_device_id google_usb_phy_of_match[] = { 278 { 279 .compatible = "google,lga-usb-phy", 280 }, 281 { } 282 }; 283 MODULE_DEVICE_TABLE(of, google_usb_phy_of_match); 284 285 static struct platform_driver google_usb_phy = { 286 .probe = google_usb_phy_probe, 287 .remove = google_usb_phy_remove, 288 .driver = { 289 .name = "google-usb-phy", 290 .of_match_table = google_usb_phy_of_match, 291 } 292 }; 293 294 module_platform_driver(google_usb_phy); 295 MODULE_LICENSE("GPL"); 296 MODULE_DESCRIPTION("Google USB phy driver"); 297