1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller 4 * Copyright 2015-2018 Socionext Inc. 5 * Author: 6 * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 7 * Contributors: 8 * Motoya Tanigawa <tanigawa.motoya@socionext.com> 9 * Masami Hiramatsu <masami.hiramatsu@linaro.org> 10 */ 11 12 #include <linux/bitfield.h> 13 #include <linux/bitops.h> 14 #include <linux/clk.h> 15 #include <linux/io.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/of_platform.h> 19 #include <linux/phy/phy.h> 20 #include <linux/platform_device.h> 21 #include <linux/regulator/consumer.h> 22 #include <linux/reset.h> 23 24 #define SSPHY_TESTI 0x0 25 #define SSPHY_TESTO 0x4 26 #define TESTI_DAT_MASK GENMASK(13, 6) 27 #define TESTI_ADR_MASK GENMASK(5, 1) 28 #define TESTI_WR_EN BIT(0) 29 30 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) } 31 32 #define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */ 33 #define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */ 34 #define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */ 35 #define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */ 36 #define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */ 37 #define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */ 38 #define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */ 39 #define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */ 40 41 #define MAX_PHY_PARAMS 7 42 43 struct uniphier_u3ssphy_param { 44 struct { 45 int reg_no; 46 int msb; 47 int lsb; 48 } field; 49 u8 value; 50 }; 51 52 struct uniphier_u3ssphy_priv { 53 struct device *dev; 54 void __iomem *base; 55 struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio; 56 struct reset_control *rst, *rst_parent, *rst_parent_gio; 57 struct regulator *vbus; 58 const struct uniphier_u3ssphy_soc_data *data; 59 }; 60 61 struct uniphier_u3ssphy_soc_data { 62 bool is_legacy; 63 int nparams; 64 const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS]; 65 }; 66 67 static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv, 68 u32 data) 69 { 70 /* need to read TESTO twice after accessing TESTI */ 71 writel(data, priv->base + SSPHY_TESTI); 72 readl(priv->base + SSPHY_TESTO); 73 readl(priv->base + SSPHY_TESTO); 74 } 75 76 static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv, 77 const struct uniphier_u3ssphy_param *p) 78 { 79 u32 val; 80 u8 field_mask = GENMASK(p->field.msb, p->field.lsb); 81 u8 data; 82 83 /* read previous data */ 84 val = FIELD_PREP(TESTI_DAT_MASK, 1); 85 val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); 86 uniphier_u3ssphy_testio_write(priv, val); 87 val = readl(priv->base + SSPHY_TESTO); 88 89 /* update value */ 90 val &= ~FIELD_PREP(TESTI_DAT_MASK, field_mask); 91 data = field_mask & (p->value << p->field.lsb); 92 val = FIELD_PREP(TESTI_DAT_MASK, data); 93 val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); 94 uniphier_u3ssphy_testio_write(priv, val); 95 uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN); 96 uniphier_u3ssphy_testio_write(priv, val); 97 98 /* read current data as dummy */ 99 val = FIELD_PREP(TESTI_DAT_MASK, 1); 100 val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no); 101 uniphier_u3ssphy_testio_write(priv, val); 102 readl(priv->base + SSPHY_TESTO); 103 } 104 105 static int uniphier_u3ssphy_power_on(struct phy *phy) 106 { 107 struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); 108 int ret; 109 110 ret = clk_prepare_enable(priv->clk_ext); 111 if (ret) 112 return ret; 113 114 ret = clk_prepare_enable(priv->clk); 115 if (ret) 116 goto out_clk_ext_disable; 117 118 ret = reset_control_deassert(priv->rst); 119 if (ret) 120 goto out_clk_disable; 121 122 if (priv->vbus) { 123 ret = regulator_enable(priv->vbus); 124 if (ret) 125 goto out_rst_assert; 126 } 127 128 return 0; 129 130 out_rst_assert: 131 reset_control_assert(priv->rst); 132 out_clk_disable: 133 clk_disable_unprepare(priv->clk); 134 out_clk_ext_disable: 135 clk_disable_unprepare(priv->clk_ext); 136 137 return ret; 138 } 139 140 static int uniphier_u3ssphy_power_off(struct phy *phy) 141 { 142 struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); 143 144 if (priv->vbus) 145 regulator_disable(priv->vbus); 146 147 reset_control_assert(priv->rst); 148 clk_disable_unprepare(priv->clk); 149 clk_disable_unprepare(priv->clk_ext); 150 151 return 0; 152 } 153 154 static int uniphier_u3ssphy_init(struct phy *phy) 155 { 156 struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); 157 int i, ret; 158 159 ret = clk_prepare_enable(priv->clk_parent); 160 if (ret) 161 return ret; 162 163 ret = clk_prepare_enable(priv->clk_parent_gio); 164 if (ret) 165 goto out_clk_disable; 166 167 ret = reset_control_deassert(priv->rst_parent); 168 if (ret) 169 goto out_clk_gio_disable; 170 171 ret = reset_control_deassert(priv->rst_parent_gio); 172 if (ret) 173 goto out_rst_assert; 174 175 if (priv->data->is_legacy) 176 return 0; 177 178 for (i = 0; i < priv->data->nparams; i++) 179 uniphier_u3ssphy_set_param(priv, &priv->data->param[i]); 180 181 return 0; 182 183 out_rst_assert: 184 reset_control_assert(priv->rst_parent); 185 out_clk_gio_disable: 186 clk_disable_unprepare(priv->clk_parent_gio); 187 out_clk_disable: 188 clk_disable_unprepare(priv->clk_parent); 189 190 return ret; 191 } 192 193 static int uniphier_u3ssphy_exit(struct phy *phy) 194 { 195 struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy); 196 197 reset_control_assert(priv->rst_parent_gio); 198 reset_control_assert(priv->rst_parent); 199 clk_disable_unprepare(priv->clk_parent_gio); 200 clk_disable_unprepare(priv->clk_parent); 201 202 return 0; 203 } 204 205 static const struct phy_ops uniphier_u3ssphy_ops = { 206 .init = uniphier_u3ssphy_init, 207 .exit = uniphier_u3ssphy_exit, 208 .power_on = uniphier_u3ssphy_power_on, 209 .power_off = uniphier_u3ssphy_power_off, 210 .owner = THIS_MODULE, 211 }; 212 213 static int uniphier_u3ssphy_probe(struct platform_device *pdev) 214 { 215 struct device *dev = &pdev->dev; 216 struct uniphier_u3ssphy_priv *priv; 217 struct phy_provider *phy_provider; 218 struct phy *phy; 219 220 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 221 if (!priv) 222 return -ENOMEM; 223 224 priv->dev = dev; 225 priv->data = of_device_get_match_data(dev); 226 if (WARN_ON(!priv->data || 227 priv->data->nparams > MAX_PHY_PARAMS)) 228 return -EINVAL; 229 230 priv->base = devm_platform_ioremap_resource(pdev, 0); 231 if (IS_ERR(priv->base)) 232 return PTR_ERR(priv->base); 233 234 if (!priv->data->is_legacy) { 235 priv->clk = devm_clk_get(dev, "phy"); 236 if (IS_ERR(priv->clk)) 237 return PTR_ERR(priv->clk); 238 239 priv->clk_ext = devm_clk_get_optional(dev, "phy-ext"); 240 if (IS_ERR(priv->clk_ext)) 241 return PTR_ERR(priv->clk_ext); 242 243 priv->rst = devm_reset_control_get_shared(dev, "phy"); 244 if (IS_ERR(priv->rst)) 245 return PTR_ERR(priv->rst); 246 } else { 247 priv->clk_parent_gio = devm_clk_get(dev, "gio"); 248 if (IS_ERR(priv->clk_parent_gio)) 249 return PTR_ERR(priv->clk_parent_gio); 250 251 priv->rst_parent_gio = 252 devm_reset_control_get_shared(dev, "gio"); 253 if (IS_ERR(priv->rst_parent_gio)) 254 return PTR_ERR(priv->rst_parent_gio); 255 } 256 257 priv->clk_parent = devm_clk_get(dev, "link"); 258 if (IS_ERR(priv->clk_parent)) 259 return PTR_ERR(priv->clk_parent); 260 261 priv->rst_parent = devm_reset_control_get_shared(dev, "link"); 262 if (IS_ERR(priv->rst_parent)) 263 return PTR_ERR(priv->rst_parent); 264 265 priv->vbus = devm_regulator_get_optional(dev, "vbus"); 266 if (IS_ERR(priv->vbus)) { 267 if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) 268 return PTR_ERR(priv->vbus); 269 priv->vbus = NULL; 270 } 271 272 phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops); 273 if (IS_ERR(phy)) 274 return PTR_ERR(phy); 275 276 phy_set_drvdata(phy, priv); 277 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 278 279 return PTR_ERR_OR_ZERO(phy_provider); 280 } 281 282 static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = { 283 .is_legacy = true, 284 }; 285 286 static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = { 287 .is_legacy = false, 288 .nparams = 7, 289 .param = { 290 { CDR_CPD_TRIM, 10 }, 291 { CDR_CPF_TRIM, 3 }, 292 { TX_PLL_TRIM, 5 }, 293 { BGAP_TRIM, 9 }, 294 { CDR_TRIM, 2 }, 295 { VCOPLL_CTRL, 7 }, 296 { VCOPLL_CM, 1 }, 297 }, 298 }; 299 300 static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = { 301 .is_legacy = false, 302 .nparams = 3, 303 .param = { 304 { CDR_CPD_TRIM, 6 }, 305 { CDR_TRIM, 2 }, 306 { VCO_CTRL, 5 }, 307 }, 308 }; 309 310 static const struct of_device_id uniphier_u3ssphy_match[] = { 311 { 312 .compatible = "socionext,uniphier-pro4-usb3-ssphy", 313 .data = &uniphier_pro4_data, 314 }, 315 { 316 .compatible = "socionext,uniphier-pro5-usb3-ssphy", 317 .data = &uniphier_pro4_data, 318 }, 319 { 320 .compatible = "socionext,uniphier-pxs2-usb3-ssphy", 321 .data = &uniphier_pxs2_data, 322 }, 323 { 324 .compatible = "socionext,uniphier-ld20-usb3-ssphy", 325 .data = &uniphier_ld20_data, 326 }, 327 { 328 .compatible = "socionext,uniphier-pxs3-usb3-ssphy", 329 .data = &uniphier_ld20_data, 330 }, 331 { /* sentinel */ } 332 }; 333 MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match); 334 335 static struct platform_driver uniphier_u3ssphy_driver = { 336 .probe = uniphier_u3ssphy_probe, 337 .driver = { 338 .name = "uniphier-usb3-ssphy", 339 .of_match_table = uniphier_u3ssphy_match, 340 }, 341 }; 342 343 module_platform_driver(uniphier_u3ssphy_driver); 344 345 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 346 MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller"); 347 MODULE_LICENSE("GPL v2"); 348