1*c339d3e0SKunihiko Hayashi // SPDX-License-Identifier: GPL-2.0 2*c339d3e0SKunihiko Hayashi /* 3*c339d3e0SKunihiko Hayashi * phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller 4*c339d3e0SKunihiko Hayashi * Copyright 2015-2018 Socionext Inc. 5*c339d3e0SKunihiko Hayashi * Author: 6*c339d3e0SKunihiko Hayashi * Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 7*c339d3e0SKunihiko Hayashi */ 8*c339d3e0SKunihiko Hayashi 9*c339d3e0SKunihiko Hayashi #include <linux/mfd/syscon.h> 10*c339d3e0SKunihiko Hayashi #include <linux/module.h> 11*c339d3e0SKunihiko Hayashi #include <linux/of.h> 12*c339d3e0SKunihiko Hayashi #include <linux/of_platform.h> 13*c339d3e0SKunihiko Hayashi #include <linux/phy/phy.h> 14*c339d3e0SKunihiko Hayashi #include <linux/platform_device.h> 15*c339d3e0SKunihiko Hayashi #include <linux/regmap.h> 16*c339d3e0SKunihiko Hayashi #include <linux/regulator/consumer.h> 17*c339d3e0SKunihiko Hayashi 18*c339d3e0SKunihiko Hayashi #define SG_USBPHY1CTRL 0x500 19*c339d3e0SKunihiko Hayashi #define SG_USBPHY1CTRL2 0x504 20*c339d3e0SKunihiko Hayashi #define SG_USBPHY2CTRL 0x508 21*c339d3e0SKunihiko Hayashi #define SG_USBPHY2CTRL2 0x50c /* LD11 */ 22*c339d3e0SKunihiko Hayashi #define SG_USBPHY12PLL 0x50c /* Pro4 */ 23*c339d3e0SKunihiko Hayashi #define SG_USBPHY3CTRL 0x510 24*c339d3e0SKunihiko Hayashi #define SG_USBPHY3CTRL2 0x514 25*c339d3e0SKunihiko Hayashi #define SG_USBPHY4CTRL 0x518 /* Pro4 */ 26*c339d3e0SKunihiko Hayashi #define SG_USBPHY4CTRL2 0x51c /* Pro4 */ 27*c339d3e0SKunihiko Hayashi #define SG_USBPHY34PLL 0x51c /* Pro4 */ 28*c339d3e0SKunihiko Hayashi 29*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_param { 30*c339d3e0SKunihiko Hayashi u32 offset; 31*c339d3e0SKunihiko Hayashi u32 value; 32*c339d3e0SKunihiko Hayashi }; 33*c339d3e0SKunihiko Hayashi 34*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_soc_data { 35*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_param config0; 36*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_param config1; 37*c339d3e0SKunihiko Hayashi }; 38*c339d3e0SKunihiko Hayashi 39*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv { 40*c339d3e0SKunihiko Hayashi struct regmap *regmap; 41*c339d3e0SKunihiko Hayashi struct phy *phy; 42*c339d3e0SKunihiko Hayashi struct regulator *vbus; 43*c339d3e0SKunihiko Hayashi const struct uniphier_u2phy_soc_data *data; 44*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *next; 45*c339d3e0SKunihiko Hayashi }; 46*c339d3e0SKunihiko Hayashi 47*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_power_on(struct phy *phy) 48*c339d3e0SKunihiko Hayashi { 49*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); 50*c339d3e0SKunihiko Hayashi int ret = 0; 51*c339d3e0SKunihiko Hayashi 52*c339d3e0SKunihiko Hayashi if (priv->vbus) 53*c339d3e0SKunihiko Hayashi ret = regulator_enable(priv->vbus); 54*c339d3e0SKunihiko Hayashi 55*c339d3e0SKunihiko Hayashi return ret; 56*c339d3e0SKunihiko Hayashi } 57*c339d3e0SKunihiko Hayashi 58*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_power_off(struct phy *phy) 59*c339d3e0SKunihiko Hayashi { 60*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); 61*c339d3e0SKunihiko Hayashi 62*c339d3e0SKunihiko Hayashi if (priv->vbus) 63*c339d3e0SKunihiko Hayashi regulator_disable(priv->vbus); 64*c339d3e0SKunihiko Hayashi 65*c339d3e0SKunihiko Hayashi return 0; 66*c339d3e0SKunihiko Hayashi } 67*c339d3e0SKunihiko Hayashi 68*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_init(struct phy *phy) 69*c339d3e0SKunihiko Hayashi { 70*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy); 71*c339d3e0SKunihiko Hayashi 72*c339d3e0SKunihiko Hayashi if (!priv->data) 73*c339d3e0SKunihiko Hayashi return 0; 74*c339d3e0SKunihiko Hayashi 75*c339d3e0SKunihiko Hayashi regmap_write(priv->regmap, priv->data->config0.offset, 76*c339d3e0SKunihiko Hayashi priv->data->config0.value); 77*c339d3e0SKunihiko Hayashi regmap_write(priv->regmap, priv->data->config1.offset, 78*c339d3e0SKunihiko Hayashi priv->data->config1.value); 79*c339d3e0SKunihiko Hayashi 80*c339d3e0SKunihiko Hayashi return 0; 81*c339d3e0SKunihiko Hayashi } 82*c339d3e0SKunihiko Hayashi 83*c339d3e0SKunihiko Hayashi static struct phy *uniphier_u2phy_xlate(struct device *dev, 84*c339d3e0SKunihiko Hayashi struct of_phandle_args *args) 85*c339d3e0SKunihiko Hayashi { 86*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev); 87*c339d3e0SKunihiko Hayashi 88*c339d3e0SKunihiko Hayashi while (priv && args->np != priv->phy->dev.of_node) 89*c339d3e0SKunihiko Hayashi priv = priv->next; 90*c339d3e0SKunihiko Hayashi 91*c339d3e0SKunihiko Hayashi if (!priv) { 92*c339d3e0SKunihiko Hayashi dev_err(dev, "Failed to find appropriate phy\n"); 93*c339d3e0SKunihiko Hayashi return ERR_PTR(-EINVAL); 94*c339d3e0SKunihiko Hayashi } 95*c339d3e0SKunihiko Hayashi 96*c339d3e0SKunihiko Hayashi return priv->phy; 97*c339d3e0SKunihiko Hayashi } 98*c339d3e0SKunihiko Hayashi 99*c339d3e0SKunihiko Hayashi static const struct phy_ops uniphier_u2phy_ops = { 100*c339d3e0SKunihiko Hayashi .init = uniphier_u2phy_init, 101*c339d3e0SKunihiko Hayashi .power_on = uniphier_u2phy_power_on, 102*c339d3e0SKunihiko Hayashi .power_off = uniphier_u2phy_power_off, 103*c339d3e0SKunihiko Hayashi .owner = THIS_MODULE, 104*c339d3e0SKunihiko Hayashi }; 105*c339d3e0SKunihiko Hayashi 106*c339d3e0SKunihiko Hayashi static int uniphier_u2phy_probe(struct platform_device *pdev) 107*c339d3e0SKunihiko Hayashi { 108*c339d3e0SKunihiko Hayashi struct device *dev = &pdev->dev; 109*c339d3e0SKunihiko Hayashi struct device_node *parent, *child; 110*c339d3e0SKunihiko Hayashi struct uniphier_u2phy_priv *priv = NULL, *next = NULL; 111*c339d3e0SKunihiko Hayashi struct phy_provider *phy_provider; 112*c339d3e0SKunihiko Hayashi struct regmap *regmap; 113*c339d3e0SKunihiko Hayashi const struct uniphier_u2phy_soc_data *data; 114*c339d3e0SKunihiko Hayashi int ret, data_idx, ndatas; 115*c339d3e0SKunihiko Hayashi 116*c339d3e0SKunihiko Hayashi data = of_device_get_match_data(dev); 117*c339d3e0SKunihiko Hayashi if (WARN_ON(!data)) 118*c339d3e0SKunihiko Hayashi return -EINVAL; 119*c339d3e0SKunihiko Hayashi 120*c339d3e0SKunihiko Hayashi /* get number of data */ 121*c339d3e0SKunihiko Hayashi for (ndatas = 0; data[ndatas].config0.offset; ndatas++) 122*c339d3e0SKunihiko Hayashi ; 123*c339d3e0SKunihiko Hayashi 124*c339d3e0SKunihiko Hayashi parent = of_get_parent(dev->of_node); 125*c339d3e0SKunihiko Hayashi regmap = syscon_node_to_regmap(parent); 126*c339d3e0SKunihiko Hayashi of_node_put(parent); 127*c339d3e0SKunihiko Hayashi if (IS_ERR(regmap)) { 128*c339d3e0SKunihiko Hayashi dev_err(dev, "Failed to get regmap\n"); 129*c339d3e0SKunihiko Hayashi return PTR_ERR(regmap); 130*c339d3e0SKunihiko Hayashi } 131*c339d3e0SKunihiko Hayashi 132*c339d3e0SKunihiko Hayashi for_each_child_of_node(dev->of_node, child) { 133*c339d3e0SKunihiko Hayashi priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 134*c339d3e0SKunihiko Hayashi if (!priv) { 135*c339d3e0SKunihiko Hayashi ret = -ENOMEM; 136*c339d3e0SKunihiko Hayashi goto out_put_child; 137*c339d3e0SKunihiko Hayashi } 138*c339d3e0SKunihiko Hayashi priv->regmap = regmap; 139*c339d3e0SKunihiko Hayashi 140*c339d3e0SKunihiko Hayashi priv->vbus = devm_regulator_get_optional(dev, "vbus"); 141*c339d3e0SKunihiko Hayashi if (IS_ERR(priv->vbus)) { 142*c339d3e0SKunihiko Hayashi if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) { 143*c339d3e0SKunihiko Hayashi ret = PTR_ERR(priv->vbus); 144*c339d3e0SKunihiko Hayashi goto out_put_child; 145*c339d3e0SKunihiko Hayashi } 146*c339d3e0SKunihiko Hayashi priv->vbus = NULL; 147*c339d3e0SKunihiko Hayashi } 148*c339d3e0SKunihiko Hayashi 149*c339d3e0SKunihiko Hayashi priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops); 150*c339d3e0SKunihiko Hayashi if (IS_ERR(priv->phy)) { 151*c339d3e0SKunihiko Hayashi dev_err(dev, "Failed to create phy\n"); 152*c339d3e0SKunihiko Hayashi ret = PTR_ERR(priv->phy); 153*c339d3e0SKunihiko Hayashi goto out_put_child; 154*c339d3e0SKunihiko Hayashi } 155*c339d3e0SKunihiko Hayashi 156*c339d3e0SKunihiko Hayashi ret = of_property_read_u32(child, "reg", &data_idx); 157*c339d3e0SKunihiko Hayashi if (ret) { 158*c339d3e0SKunihiko Hayashi dev_err(dev, "Failed to get reg property\n"); 159*c339d3e0SKunihiko Hayashi goto out_put_child; 160*c339d3e0SKunihiko Hayashi } 161*c339d3e0SKunihiko Hayashi 162*c339d3e0SKunihiko Hayashi if (data_idx < ndatas) 163*c339d3e0SKunihiko Hayashi priv->data = &data[data_idx]; 164*c339d3e0SKunihiko Hayashi else 165*c339d3e0SKunihiko Hayashi dev_warn(dev, "No phy configuration: %s\n", 166*c339d3e0SKunihiko Hayashi child->full_name); 167*c339d3e0SKunihiko Hayashi 168*c339d3e0SKunihiko Hayashi phy_set_drvdata(priv->phy, priv); 169*c339d3e0SKunihiko Hayashi priv->next = next; 170*c339d3e0SKunihiko Hayashi next = priv; 171*c339d3e0SKunihiko Hayashi } 172*c339d3e0SKunihiko Hayashi 173*c339d3e0SKunihiko Hayashi dev_set_drvdata(dev, priv); 174*c339d3e0SKunihiko Hayashi phy_provider = devm_of_phy_provider_register(dev, 175*c339d3e0SKunihiko Hayashi uniphier_u2phy_xlate); 176*c339d3e0SKunihiko Hayashi return PTR_ERR_OR_ZERO(phy_provider); 177*c339d3e0SKunihiko Hayashi 178*c339d3e0SKunihiko Hayashi out_put_child: 179*c339d3e0SKunihiko Hayashi of_node_put(child); 180*c339d3e0SKunihiko Hayashi 181*c339d3e0SKunihiko Hayashi return ret; 182*c339d3e0SKunihiko Hayashi } 183*c339d3e0SKunihiko Hayashi 184*c339d3e0SKunihiko Hayashi static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = { 185*c339d3e0SKunihiko Hayashi { 186*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY1CTRL, 0x05142400 }, 187*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY12PLL, 0x00010010 }, 188*c339d3e0SKunihiko Hayashi }, 189*c339d3e0SKunihiko Hayashi { 190*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY2CTRL, 0x05142400 }, 191*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY12PLL, 0x00010010 }, 192*c339d3e0SKunihiko Hayashi }, 193*c339d3e0SKunihiko Hayashi { 194*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY3CTRL, 0x05142400 }, 195*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY34PLL, 0x00010010 }, 196*c339d3e0SKunihiko Hayashi }, 197*c339d3e0SKunihiko Hayashi { 198*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY4CTRL, 0x05142400 }, 199*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY34PLL, 0x00010010 }, 200*c339d3e0SKunihiko Hayashi }, 201*c339d3e0SKunihiko Hayashi { /* sentinel */ } 202*c339d3e0SKunihiko Hayashi }; 203*c339d3e0SKunihiko Hayashi 204*c339d3e0SKunihiko Hayashi static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = { 205*c339d3e0SKunihiko Hayashi { 206*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY1CTRL, 0x82280000 }, 207*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY1CTRL2, 0x00000106 }, 208*c339d3e0SKunihiko Hayashi }, 209*c339d3e0SKunihiko Hayashi { 210*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY2CTRL, 0x82280000 }, 211*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY2CTRL2, 0x00000106 }, 212*c339d3e0SKunihiko Hayashi }, 213*c339d3e0SKunihiko Hayashi { 214*c339d3e0SKunihiko Hayashi .config0 = { SG_USBPHY3CTRL, 0x82280000 }, 215*c339d3e0SKunihiko Hayashi .config1 = { SG_USBPHY3CTRL2, 0x00000106 }, 216*c339d3e0SKunihiko Hayashi }, 217*c339d3e0SKunihiko Hayashi { /* sentinel */ } 218*c339d3e0SKunihiko Hayashi }; 219*c339d3e0SKunihiko Hayashi 220*c339d3e0SKunihiko Hayashi static const struct of_device_id uniphier_u2phy_match[] = { 221*c339d3e0SKunihiko Hayashi { 222*c339d3e0SKunihiko Hayashi .compatible = "socionext,uniphier-pro4-usb2-phy", 223*c339d3e0SKunihiko Hayashi .data = &uniphier_pro4_data, 224*c339d3e0SKunihiko Hayashi }, 225*c339d3e0SKunihiko Hayashi { 226*c339d3e0SKunihiko Hayashi .compatible = "socionext,uniphier-ld11-usb2-phy", 227*c339d3e0SKunihiko Hayashi .data = &uniphier_ld11_data, 228*c339d3e0SKunihiko Hayashi }, 229*c339d3e0SKunihiko Hayashi { /* sentinel */ } 230*c339d3e0SKunihiko Hayashi }; 231*c339d3e0SKunihiko Hayashi MODULE_DEVICE_TABLE(of, uniphier_u2phy_match); 232*c339d3e0SKunihiko Hayashi 233*c339d3e0SKunihiko Hayashi static struct platform_driver uniphier_u2phy_driver = { 234*c339d3e0SKunihiko Hayashi .probe = uniphier_u2phy_probe, 235*c339d3e0SKunihiko Hayashi .driver = { 236*c339d3e0SKunihiko Hayashi .name = "uniphier-usb2-phy", 237*c339d3e0SKunihiko Hayashi .of_match_table = uniphier_u2phy_match, 238*c339d3e0SKunihiko Hayashi }, 239*c339d3e0SKunihiko Hayashi }; 240*c339d3e0SKunihiko Hayashi module_platform_driver(uniphier_u2phy_driver); 241*c339d3e0SKunihiko Hayashi 242*c339d3e0SKunihiko Hayashi MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 243*c339d3e0SKunihiko Hayashi MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller"); 244*c339d3e0SKunihiko Hayashi MODULE_LICENSE("GPL v2"); 245