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