1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * USB cluster support for Armada 375 platform. 4 * 5 * Copyright (C) 2014 Marvell 6 * 7 * Gregory CLEMENT <gregory.clement@free-electrons.com> 8 * 9 * Armada 375 comes with an USB2 host and device controller and an 10 * USB3 controller. The USB cluster control register allows to manage 11 * common features of both USB controllers. 12 */ 13 14 #include <dt-bindings/phy/phy.h> 15 #include <linux/init.h> 16 #include <linux/io.h> 17 #include <linux/kernel.h> 18 #include <linux/of_address.h> 19 #include <linux/phy/phy.h> 20 #include <linux/platform_device.h> 21 22 #define USB2_PHY_CONFIG_DISABLE BIT(0) 23 24 struct armada375_cluster_phy { 25 struct phy *phy; 26 void __iomem *reg; 27 bool use_usb3; 28 int phy_provided; 29 }; 30 31 static int armada375_usb_phy_init(struct phy *phy) 32 { 33 struct armada375_cluster_phy *cluster_phy; 34 u32 reg; 35 36 cluster_phy = phy_get_drvdata(phy); 37 if (!cluster_phy) 38 return -ENODEV; 39 40 reg = readl(cluster_phy->reg); 41 if (cluster_phy->use_usb3) 42 reg |= USB2_PHY_CONFIG_DISABLE; 43 else 44 reg &= ~USB2_PHY_CONFIG_DISABLE; 45 writel(reg, cluster_phy->reg); 46 47 return 0; 48 } 49 50 static const struct phy_ops armada375_usb_phy_ops = { 51 .init = armada375_usb_phy_init, 52 .owner = THIS_MODULE, 53 }; 54 55 /* 56 * Only one controller can use this PHY. We shouldn't have the case 57 * when two controllers want to use this PHY. But if this case occurs 58 * then we provide a phy to the first one and return an error for the 59 * next one. This error has also to be an error returned by 60 * devm_phy_optional_get() so different from ENODEV for USB2. In the 61 * USB3 case it still optional and we use ENODEV. 62 */ 63 static struct phy *armada375_usb_phy_xlate(struct device *dev, 64 struct of_phandle_args *args) 65 { 66 struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev); 67 68 if (!cluster_phy) 69 return ERR_PTR(-ENODEV); 70 71 /* 72 * Either the phy had never been requested and then the first 73 * usb claiming it can get it, or it had already been 74 * requested in this case, we only allow to use it with the 75 * same configuration. 76 */ 77 if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) && 78 (cluster_phy->phy_provided != args->args[0]))) { 79 dev_err(dev, "This PHY has already been provided!\n"); 80 dev_err(dev, "Check your device tree, only one controller can use it\n."); 81 if (args->args[0] == PHY_TYPE_USB2) 82 return ERR_PTR(-EBUSY); 83 else 84 return ERR_PTR(-ENODEV); 85 } 86 87 if (args->args[0] == PHY_TYPE_USB2) 88 cluster_phy->use_usb3 = false; 89 else if (args->args[0] == PHY_TYPE_USB3) 90 cluster_phy->use_usb3 = true; 91 else { 92 dev_err(dev, "Invalid PHY mode\n"); 93 return ERR_PTR(-ENODEV); 94 } 95 96 /* Store which phy mode is used for next test */ 97 cluster_phy->phy_provided = args->args[0]; 98 99 return cluster_phy->phy; 100 } 101 102 static int armada375_usb_phy_probe(struct platform_device *pdev) 103 { 104 struct device *dev = &pdev->dev; 105 struct phy *phy; 106 struct phy_provider *phy_provider; 107 void __iomem *usb_cluster_base; 108 struct resource *res; 109 struct armada375_cluster_phy *cluster_phy; 110 111 cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL); 112 if (!cluster_phy) 113 return -ENOMEM; 114 115 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 116 usb_cluster_base = devm_ioremap_resource(&pdev->dev, res); 117 if (IS_ERR(usb_cluster_base)) 118 return PTR_ERR(usb_cluster_base); 119 120 phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops); 121 if (IS_ERR(phy)) { 122 dev_err(dev, "failed to create PHY\n"); 123 return PTR_ERR(phy); 124 } 125 126 cluster_phy->phy = phy; 127 cluster_phy->reg = usb_cluster_base; 128 129 dev_set_drvdata(dev, cluster_phy); 130 phy_set_drvdata(phy, cluster_phy); 131 132 phy_provider = devm_of_phy_provider_register(&pdev->dev, 133 armada375_usb_phy_xlate); 134 return PTR_ERR_OR_ZERO(phy_provider); 135 } 136 137 static const struct of_device_id of_usb_cluster_table[] = { 138 { .compatible = "marvell,armada-375-usb-cluster", }, 139 { /* end of list */ }, 140 }; 141 142 static struct platform_driver armada375_usb_phy_driver = { 143 .probe = armada375_usb_phy_probe, 144 .driver = { 145 .of_match_table = of_usb_cluster_table, 146 .name = "armada-375-usb-cluster", 147 } 148 }; 149 builtin_platform_driver(armada375_usb_phy_driver); 150