1 /* 2 * drivers/usb/otg/nop-usb-xceiv.c 3 * 4 * NOP USB transceiver for all USB transceiver which are either built-in 5 * into USB IP or which are mostly autonomous. 6 * 7 * Copyright (C) 2009 Texas Instruments Inc 8 * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 * 24 * Current status: 25 * This provides a "nop" transceiver for PHYs which are 26 * autonomous such as isp1504, isp1707, etc. 27 */ 28 29 #include <linux/module.h> 30 #include <linux/platform_device.h> 31 #include <linux/dma-mapping.h> 32 #include <linux/usb/otg.h> 33 #include <linux/usb/usb_phy_gen_xceiv.h> 34 #include <linux/slab.h> 35 #include <linux/clk.h> 36 #include <linux/regulator/consumer.h> 37 #include <linux/of.h> 38 39 #include "phy-generic.h" 40 41 static struct platform_device *pd; 42 43 void usb_nop_xceiv_register(void) 44 { 45 if (pd) 46 return; 47 pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); 48 if (!pd) { 49 pr_err("Unable to register generic usb transceiver\n"); 50 return; 51 } 52 } 53 EXPORT_SYMBOL(usb_nop_xceiv_register); 54 55 void usb_nop_xceiv_unregister(void) 56 { 57 platform_device_unregister(pd); 58 pd = NULL; 59 } 60 EXPORT_SYMBOL(usb_nop_xceiv_unregister); 61 62 static int nop_set_suspend(struct usb_phy *x, int suspend) 63 { 64 return 0; 65 } 66 67 int usb_gen_phy_init(struct usb_phy *phy) 68 { 69 struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); 70 71 if (!IS_ERR(nop->vcc)) { 72 if (regulator_enable(nop->vcc)) 73 dev_err(phy->dev, "Failed to enable power\n"); 74 } 75 76 if (!IS_ERR(nop->clk)) 77 clk_enable(nop->clk); 78 79 if (!IS_ERR(nop->reset)) { 80 /* De-assert RESET */ 81 if (regulator_enable(nop->reset)) 82 dev_err(phy->dev, "Failed to de-assert reset\n"); 83 } 84 85 return 0; 86 } 87 EXPORT_SYMBOL_GPL(usb_gen_phy_init); 88 89 void usb_gen_phy_shutdown(struct usb_phy *phy) 90 { 91 struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); 92 93 if (!IS_ERR(nop->reset)) { 94 /* Assert RESET */ 95 if (regulator_disable(nop->reset)) 96 dev_err(phy->dev, "Failed to assert reset\n"); 97 } 98 99 if (!IS_ERR(nop->clk)) 100 clk_disable(nop->clk); 101 102 if (!IS_ERR(nop->vcc)) { 103 if (regulator_disable(nop->vcc)) 104 dev_err(phy->dev, "Failed to disable power\n"); 105 } 106 } 107 EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown); 108 109 static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) 110 { 111 if (!otg) 112 return -ENODEV; 113 114 if (!gadget) { 115 otg->gadget = NULL; 116 return -ENODEV; 117 } 118 119 otg->gadget = gadget; 120 otg->phy->state = OTG_STATE_B_IDLE; 121 return 0; 122 } 123 124 static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) 125 { 126 if (!otg) 127 return -ENODEV; 128 129 if (!host) { 130 otg->host = NULL; 131 return -ENODEV; 132 } 133 134 otg->host = host; 135 return 0; 136 } 137 138 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, 139 enum usb_phy_type type, u32 clk_rate, bool needs_vcc, 140 bool needs_reset) 141 { 142 int err; 143 144 nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), 145 GFP_KERNEL); 146 if (!nop->phy.otg) 147 return -ENOMEM; 148 149 nop->clk = devm_clk_get(dev, "main_clk"); 150 if (IS_ERR(nop->clk)) { 151 dev_dbg(dev, "Can't get phy clock: %ld\n", 152 PTR_ERR(nop->clk)); 153 } 154 155 if (!IS_ERR(nop->clk) && clk_rate) { 156 err = clk_set_rate(nop->clk, clk_rate); 157 if (err) { 158 dev_err(dev, "Error setting clock rate\n"); 159 return err; 160 } 161 } 162 163 if (!IS_ERR(nop->clk)) { 164 err = clk_prepare(nop->clk); 165 if (err) { 166 dev_err(dev, "Error preparing clock\n"); 167 return err; 168 } 169 } 170 171 nop->vcc = devm_regulator_get(dev, "vcc"); 172 if (IS_ERR(nop->vcc)) { 173 dev_dbg(dev, "Error getting vcc regulator: %ld\n", 174 PTR_ERR(nop->vcc)); 175 if (needs_vcc) 176 return -EPROBE_DEFER; 177 } 178 179 nop->reset = devm_regulator_get(dev, "reset"); 180 if (IS_ERR(nop->reset)) { 181 dev_dbg(dev, "Error getting reset regulator: %ld\n", 182 PTR_ERR(nop->reset)); 183 if (needs_reset) 184 return -EPROBE_DEFER; 185 } 186 187 nop->dev = dev; 188 nop->phy.dev = nop->dev; 189 nop->phy.label = "nop-xceiv"; 190 nop->phy.set_suspend = nop_set_suspend; 191 nop->phy.state = OTG_STATE_UNDEFINED; 192 nop->phy.type = type; 193 194 nop->phy.otg->phy = &nop->phy; 195 nop->phy.otg->set_host = nop_set_host; 196 nop->phy.otg->set_peripheral = nop_set_peripheral; 197 198 ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); 199 return 0; 200 } 201 EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); 202 203 void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) 204 { 205 if (!IS_ERR(nop->clk)) 206 clk_unprepare(nop->clk); 207 } 208 EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); 209 210 static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) 211 { 212 struct device *dev = &pdev->dev; 213 struct usb_phy_gen_xceiv_platform_data *pdata = 214 dev_get_platdata(&pdev->dev); 215 struct usb_phy_gen_xceiv *nop; 216 enum usb_phy_type type = USB_PHY_TYPE_USB2; 217 int err; 218 u32 clk_rate = 0; 219 bool needs_vcc = false; 220 bool needs_reset = false; 221 222 if (dev->of_node) { 223 struct device_node *node = dev->of_node; 224 225 if (of_property_read_u32(node, "clock-frequency", &clk_rate)) 226 clk_rate = 0; 227 228 needs_vcc = of_property_read_bool(node, "vcc-supply"); 229 needs_reset = of_property_read_bool(node, "reset-supply"); 230 231 } else if (pdata) { 232 type = pdata->type; 233 clk_rate = pdata->clk_rate; 234 needs_vcc = pdata->needs_vcc; 235 needs_reset = pdata->needs_reset; 236 } 237 238 nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); 239 if (!nop) 240 return -ENOMEM; 241 242 243 err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, 244 needs_reset); 245 if (err) 246 return err; 247 248 nop->phy.init = usb_gen_phy_init; 249 nop->phy.shutdown = usb_gen_phy_shutdown; 250 251 err = usb_add_phy_dev(&nop->phy); 252 if (err) { 253 dev_err(&pdev->dev, "can't register transceiver, err: %d\n", 254 err); 255 goto err_add; 256 } 257 258 platform_set_drvdata(pdev, nop); 259 260 return 0; 261 262 err_add: 263 usb_phy_gen_cleanup_phy(nop); 264 return err; 265 } 266 267 static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) 268 { 269 struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); 270 271 usb_phy_gen_cleanup_phy(nop); 272 usb_remove_phy(&nop->phy); 273 274 return 0; 275 } 276 277 static const struct of_device_id nop_xceiv_dt_ids[] = { 278 { .compatible = "usb-nop-xceiv" }, 279 { } 280 }; 281 282 MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); 283 284 static struct platform_driver usb_phy_gen_xceiv_driver = { 285 .probe = usb_phy_gen_xceiv_probe, 286 .remove = usb_phy_gen_xceiv_remove, 287 .driver = { 288 .name = "usb_phy_gen_xceiv", 289 .owner = THIS_MODULE, 290 .of_match_table = nop_xceiv_dt_ids, 291 }, 292 }; 293 294 static int __init usb_phy_gen_xceiv_init(void) 295 { 296 return platform_driver_register(&usb_phy_gen_xceiv_driver); 297 } 298 subsys_initcall(usb_phy_gen_xceiv_init); 299 300 static void __exit usb_phy_gen_xceiv_exit(void) 301 { 302 platform_driver_unregister(&usb_phy_gen_xceiv_driver); 303 } 304 module_exit(usb_phy_gen_xceiv_exit); 305 306 MODULE_ALIAS("platform:usb_phy_gen_xceiv"); 307 MODULE_AUTHOR("Texas Instruments Inc"); 308 MODULE_DESCRIPTION("NOP USB Transceiver driver"); 309 MODULE_LICENSE("GPL"); 310