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