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 #include <linux/of_gpio.h> 39 #include <linux/gpio.h> 40 #include <linux/delay.h> 41 42 #include "phy-generic.h" 43 44 static struct platform_device *pd; 45 46 void usb_nop_xceiv_register(void) 47 { 48 if (pd) 49 return; 50 pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); 51 if (IS_ERR(pd)) { 52 pr_err("Unable to register generic usb transceiver\n"); 53 pd = NULL; 54 return; 55 } 56 } 57 EXPORT_SYMBOL(usb_nop_xceiv_register); 58 59 void usb_nop_xceiv_unregister(void) 60 { 61 platform_device_unregister(pd); 62 pd = NULL; 63 } 64 EXPORT_SYMBOL(usb_nop_xceiv_unregister); 65 66 static int nop_set_suspend(struct usb_phy *x, int suspend) 67 { 68 return 0; 69 } 70 71 static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) 72 { 73 int value; 74 75 if (!gpio_is_valid(nop->gpio_reset)) 76 return; 77 78 value = asserted; 79 if (nop->reset_active_low) 80 value = !value; 81 82 gpio_set_value_cansleep(nop->gpio_reset, value); 83 84 if (!asserted) 85 usleep_range(10000, 20000); 86 } 87 88 int usb_gen_phy_init(struct usb_phy *phy) 89 { 90 struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); 91 92 if (!IS_ERR(nop->vcc)) { 93 if (regulator_enable(nop->vcc)) 94 dev_err(phy->dev, "Failed to enable power\n"); 95 } 96 97 if (!IS_ERR(nop->clk)) 98 clk_prepare_enable(nop->clk); 99 100 /* De-assert RESET */ 101 nop_reset_set(nop, 0); 102 103 return 0; 104 } 105 EXPORT_SYMBOL_GPL(usb_gen_phy_init); 106 107 void usb_gen_phy_shutdown(struct usb_phy *phy) 108 { 109 struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); 110 111 /* Assert RESET */ 112 nop_reset_set(nop, 1); 113 114 if (!IS_ERR(nop->clk)) 115 clk_disable_unprepare(nop->clk); 116 117 if (!IS_ERR(nop->vcc)) { 118 if (regulator_disable(nop->vcc)) 119 dev_err(phy->dev, "Failed to disable power\n"); 120 } 121 } 122 EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown); 123 124 static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) 125 { 126 if (!otg) 127 return -ENODEV; 128 129 if (!gadget) { 130 otg->gadget = NULL; 131 return -ENODEV; 132 } 133 134 otg->gadget = gadget; 135 otg->phy->state = OTG_STATE_B_IDLE; 136 return 0; 137 } 138 139 static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) 140 { 141 if (!otg) 142 return -ENODEV; 143 144 if (!host) { 145 otg->host = NULL; 146 return -ENODEV; 147 } 148 149 otg->host = host; 150 return 0; 151 } 152 153 int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, 154 struct usb_phy_gen_xceiv_platform_data *pdata) 155 { 156 enum usb_phy_type type = USB_PHY_TYPE_USB2; 157 int err; 158 159 u32 clk_rate = 0; 160 bool needs_vcc = false; 161 162 nop->reset_active_low = true; /* default behaviour */ 163 164 if (dev->of_node) { 165 struct device_node *node = dev->of_node; 166 enum of_gpio_flags flags = 0; 167 168 if (of_property_read_u32(node, "clock-frequency", &clk_rate)) 169 clk_rate = 0; 170 171 needs_vcc = of_property_read_bool(node, "vcc-supply"); 172 nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", 173 0, &flags); 174 if (nop->gpio_reset == -EPROBE_DEFER) 175 return -EPROBE_DEFER; 176 177 nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; 178 179 } else if (pdata) { 180 type = pdata->type; 181 clk_rate = pdata->clk_rate; 182 needs_vcc = pdata->needs_vcc; 183 nop->gpio_reset = pdata->gpio_reset; 184 } else { 185 nop->gpio_reset = -1; 186 } 187 188 nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg), 189 GFP_KERNEL); 190 if (!nop->phy.otg) 191 return -ENOMEM; 192 193 nop->clk = devm_clk_get(dev, "main_clk"); 194 if (IS_ERR(nop->clk)) { 195 dev_dbg(dev, "Can't get phy clock: %ld\n", 196 PTR_ERR(nop->clk)); 197 } 198 199 if (!IS_ERR(nop->clk) && clk_rate) { 200 err = clk_set_rate(nop->clk, clk_rate); 201 if (err) { 202 dev_err(dev, "Error setting clock rate\n"); 203 return err; 204 } 205 } 206 207 nop->vcc = devm_regulator_get(dev, "vcc"); 208 if (IS_ERR(nop->vcc)) { 209 dev_dbg(dev, "Error getting vcc regulator: %ld\n", 210 PTR_ERR(nop->vcc)); 211 if (needs_vcc) 212 return -EPROBE_DEFER; 213 } 214 215 if (gpio_is_valid(nop->gpio_reset)) { 216 unsigned long gpio_flags; 217 218 /* Assert RESET */ 219 if (nop->reset_active_low) 220 gpio_flags = GPIOF_OUT_INIT_LOW; 221 else 222 gpio_flags = GPIOF_OUT_INIT_HIGH; 223 224 err = devm_gpio_request_one(dev, nop->gpio_reset, 225 gpio_flags, dev_name(dev)); 226 if (err) { 227 dev_err(dev, "Error requesting RESET GPIO %d\n", 228 nop->gpio_reset); 229 return err; 230 } 231 } 232 233 nop->dev = dev; 234 nop->phy.dev = nop->dev; 235 nop->phy.label = "nop-xceiv"; 236 nop->phy.set_suspend = nop_set_suspend; 237 nop->phy.state = OTG_STATE_UNDEFINED; 238 nop->phy.type = type; 239 240 nop->phy.otg->phy = &nop->phy; 241 nop->phy.otg->set_host = nop_set_host; 242 nop->phy.otg->set_peripheral = nop_set_peripheral; 243 244 ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); 245 return 0; 246 } 247 EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); 248 249 static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) 250 { 251 struct device *dev = &pdev->dev; 252 struct usb_phy_gen_xceiv *nop; 253 int err; 254 255 nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); 256 if (!nop) 257 return -ENOMEM; 258 259 err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev)); 260 if (err) 261 return err; 262 263 nop->phy.init = usb_gen_phy_init; 264 nop->phy.shutdown = usb_gen_phy_shutdown; 265 266 err = usb_add_phy_dev(&nop->phy); 267 if (err) { 268 dev_err(&pdev->dev, "can't register transceiver, err: %d\n", 269 err); 270 return err; 271 } 272 273 platform_set_drvdata(pdev, nop); 274 275 return 0; 276 } 277 278 static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) 279 { 280 struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); 281 282 usb_remove_phy(&nop->phy); 283 284 return 0; 285 } 286 287 static const struct of_device_id nop_xceiv_dt_ids[] = { 288 { .compatible = "usb-nop-xceiv" }, 289 { } 290 }; 291 292 MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); 293 294 static struct platform_driver usb_phy_gen_xceiv_driver = { 295 .probe = usb_phy_gen_xceiv_probe, 296 .remove = usb_phy_gen_xceiv_remove, 297 .driver = { 298 .name = "usb_phy_gen_xceiv", 299 .owner = THIS_MODULE, 300 .of_match_table = nop_xceiv_dt_ids, 301 }, 302 }; 303 304 static int __init usb_phy_gen_xceiv_init(void) 305 { 306 return platform_driver_register(&usb_phy_gen_xceiv_driver); 307 } 308 subsys_initcall(usb_phy_gen_xceiv_init); 309 310 static void __exit usb_phy_gen_xceiv_exit(void) 311 { 312 platform_driver_unregister(&usb_phy_gen_xceiv_driver); 313 } 314 module_exit(usb_phy_gen_xceiv_exit); 315 316 MODULE_ALIAS("platform:usb_phy_gen_xceiv"); 317 MODULE_AUTHOR("Texas Instruments Inc"); 318 MODULE_DESCRIPTION("NOP USB Transceiver driver"); 319 MODULE_LICENSE("GPL"); 320