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 resource *res; 219 struct phy *phy; 220 221 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 222 if (!priv) 223 return -ENOMEM; 224 225 priv->dev = dev; 226 priv->data = of_device_get_match_data(dev); 227 if (WARN_ON(!priv->data || 228 priv->data->nparams > MAX_PHY_PARAMS)) 229 return -EINVAL; 230 231 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 232 priv->base = devm_ioremap_resource(dev, res); 233 if (IS_ERR(priv->base)) 234 return PTR_ERR(priv->base); 235 236 if (!priv->data->is_legacy) { 237 priv->clk = devm_clk_get(dev, "phy"); 238 if (IS_ERR(priv->clk)) 239 return PTR_ERR(priv->clk); 240 241 priv->clk_ext = devm_clk_get_optional(dev, "phy-ext"); 242 if (IS_ERR(priv->clk_ext)) 243 return PTR_ERR(priv->clk_ext); 244 245 priv->rst = devm_reset_control_get_shared(dev, "phy"); 246 if (IS_ERR(priv->rst)) 247 return PTR_ERR(priv->rst); 248 } else { 249 priv->clk_parent_gio = devm_clk_get(dev, "gio"); 250 if (IS_ERR(priv->clk_parent_gio)) 251 return PTR_ERR(priv->clk_parent_gio); 252 253 priv->rst_parent_gio = 254 devm_reset_control_get_shared(dev, "gio"); 255 if (IS_ERR(priv->rst_parent_gio)) 256 return PTR_ERR(priv->rst_parent_gio); 257 } 258 259 priv->clk_parent = devm_clk_get(dev, "link"); 260 if (IS_ERR(priv->clk_parent)) 261 return PTR_ERR(priv->clk_parent); 262 263 priv->rst_parent = devm_reset_control_get_shared(dev, "link"); 264 if (IS_ERR(priv->rst_parent)) 265 return PTR_ERR(priv->rst_parent); 266 267 priv->vbus = devm_regulator_get_optional(dev, "vbus"); 268 if (IS_ERR(priv->vbus)) { 269 if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) 270 return PTR_ERR(priv->vbus); 271 priv->vbus = NULL; 272 } 273 274 phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops); 275 if (IS_ERR(phy)) 276 return PTR_ERR(phy); 277 278 phy_set_drvdata(phy, priv); 279 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 280 281 return PTR_ERR_OR_ZERO(phy_provider); 282 } 283 284 static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = { 285 .is_legacy = true, 286 }; 287 288 static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = { 289 .is_legacy = false, 290 .nparams = 7, 291 .param = { 292 { CDR_CPD_TRIM, 10 }, 293 { CDR_CPF_TRIM, 3 }, 294 { TX_PLL_TRIM, 5 }, 295 { BGAP_TRIM, 9 }, 296 { CDR_TRIM, 2 }, 297 { VCOPLL_CTRL, 7 }, 298 { VCOPLL_CM, 1 }, 299 }, 300 }; 301 302 static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = { 303 .is_legacy = false, 304 .nparams = 3, 305 .param = { 306 { CDR_CPD_TRIM, 6 }, 307 { CDR_TRIM, 2 }, 308 { VCO_CTRL, 5 }, 309 }, 310 }; 311 312 static const struct of_device_id uniphier_u3ssphy_match[] = { 313 { 314 .compatible = "socionext,uniphier-pro4-usb3-ssphy", 315 .data = &uniphier_pro4_data, 316 }, 317 { 318 .compatible = "socionext,uniphier-pxs2-usb3-ssphy", 319 .data = &uniphier_pxs2_data, 320 }, 321 { 322 .compatible = "socionext,uniphier-ld20-usb3-ssphy", 323 .data = &uniphier_ld20_data, 324 }, 325 { 326 .compatible = "socionext,uniphier-pxs3-usb3-ssphy", 327 .data = &uniphier_ld20_data, 328 }, 329 { /* sentinel */ } 330 }; 331 MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match); 332 333 static struct platform_driver uniphier_u3ssphy_driver = { 334 .probe = uniphier_u3ssphy_probe, 335 .driver = { 336 .name = "uniphier-usb3-ssphy", 337 .of_match_table = uniphier_u3ssphy_match, 338 }, 339 }; 340 341 module_platform_driver(uniphier_u3ssphy_driver); 342 343 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 344 MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller"); 345 MODULE_LICENSE("GPL v2"); 346