1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Tahvo USB transceiver driver 4 * 5 * Copyright (C) 2005-2006 Nokia Corporation 6 * 7 * Parts copied from isp1301_omap.c. 8 * Copyright (C) 2004 Texas Instruments 9 * Copyright (C) 2004 David Brownell 10 * 11 * Original driver written by Juha Yrjölä, Tony Lindgren and Timo Teräs. 12 * Modified for Retu/Tahvo MFD by Aaro Koskinen. 13 */ 14 15 #include <linux/io.h> 16 #include <linux/clk.h> 17 #include <linux/usb.h> 18 #include <linux/extcon-provider.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/string_choices.h> 22 #include <linux/usb/otg.h> 23 #include <linux/mfd/retu.h> 24 #include <linux/usb/gadget.h> 25 #include <linux/platform_device.h> 26 27 #define DRIVER_NAME "tahvo-usb" 28 29 #define TAHVO_REG_IDSR 0x02 30 #define TAHVO_REG_USBR 0x06 31 32 #define USBR_SLAVE_CONTROL (1 << 8) 33 #define USBR_VPPVIO_SW (1 << 7) 34 #define USBR_SPEED (1 << 6) 35 #define USBR_REGOUT (1 << 5) 36 #define USBR_MASTER_SW2 (1 << 4) 37 #define USBR_MASTER_SW1 (1 << 3) 38 #define USBR_SLAVE_SW (1 << 2) 39 #define USBR_NSUSPEND (1 << 1) 40 #define USBR_SEMODE (1 << 0) 41 42 #define TAHVO_MODE_HOST 0 43 #define TAHVO_MODE_PERIPHERAL 1 44 45 struct tahvo_usb { 46 struct platform_device *pt_dev; 47 struct usb_phy phy; 48 int vbus_state; 49 struct mutex serialize; 50 struct clk *ick; 51 int irq; 52 int tahvo_mode; 53 struct extcon_dev *extcon; 54 }; 55 56 static const unsigned int tahvo_cable[] = { 57 EXTCON_USB, 58 EXTCON_USB_HOST, 59 60 EXTCON_NONE, 61 }; 62 63 static ssize_t vbus_show(struct device *device, 64 struct device_attribute *attr, char *buf) 65 { 66 struct tahvo_usb *tu = dev_get_drvdata(device); 67 return sprintf(buf, "%s\n", str_on_off(tu->vbus_state)); 68 } 69 static DEVICE_ATTR_RO(vbus); 70 71 static void check_vbus_state(struct tahvo_usb *tu) 72 { 73 struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); 74 int reg, prev_state; 75 76 reg = retu_read(rdev, TAHVO_REG_IDSR); 77 if (reg & TAHVO_STAT_VBUS) { 78 switch (tu->phy.otg->state) { 79 case OTG_STATE_B_IDLE: 80 /* Enable the gadget driver */ 81 if (tu->phy.otg->gadget) 82 usb_gadget_vbus_connect(tu->phy.otg->gadget); 83 tu->phy.otg->state = OTG_STATE_B_PERIPHERAL; 84 usb_phy_set_event(&tu->phy, USB_EVENT_ENUMERATED); 85 break; 86 case OTG_STATE_A_IDLE: 87 /* 88 * Session is now valid assuming the USB hub is driving 89 * Vbus. 90 */ 91 tu->phy.otg->state = OTG_STATE_A_HOST; 92 break; 93 default: 94 break; 95 } 96 dev_info(&tu->pt_dev->dev, "USB cable connected\n"); 97 } else { 98 switch (tu->phy.otg->state) { 99 case OTG_STATE_B_PERIPHERAL: 100 if (tu->phy.otg->gadget) 101 usb_gadget_vbus_disconnect(tu->phy.otg->gadget); 102 tu->phy.otg->state = OTG_STATE_B_IDLE; 103 usb_phy_set_event(&tu->phy, USB_EVENT_NONE); 104 break; 105 case OTG_STATE_A_HOST: 106 tu->phy.otg->state = OTG_STATE_A_IDLE; 107 break; 108 default: 109 break; 110 } 111 dev_info(&tu->pt_dev->dev, "USB cable disconnected\n"); 112 } 113 114 prev_state = tu->vbus_state; 115 tu->vbus_state = reg & TAHVO_STAT_VBUS; 116 if (prev_state != tu->vbus_state) { 117 extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); 118 sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); 119 } 120 } 121 122 static void tahvo_usb_become_host(struct tahvo_usb *tu) 123 { 124 struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); 125 126 extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, true); 127 128 /* Power up the transceiver in USB host mode */ 129 retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | 130 USBR_MASTER_SW2 | USBR_MASTER_SW1); 131 tu->phy.otg->state = OTG_STATE_A_IDLE; 132 133 check_vbus_state(tu); 134 } 135 136 static void tahvo_usb_stop_host(struct tahvo_usb *tu) 137 { 138 tu->phy.otg->state = OTG_STATE_A_IDLE; 139 } 140 141 static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) 142 { 143 struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); 144 145 extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, false); 146 147 /* Power up transceiver and set it in USB peripheral mode */ 148 retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | 149 USBR_NSUSPEND | USBR_SLAVE_SW); 150 tu->phy.otg->state = OTG_STATE_B_IDLE; 151 152 check_vbus_state(tu); 153 } 154 155 static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu) 156 { 157 if (tu->phy.otg->gadget) 158 usb_gadget_vbus_disconnect(tu->phy.otg->gadget); 159 tu->phy.otg->state = OTG_STATE_B_IDLE; 160 } 161 162 static void tahvo_usb_power_off(struct tahvo_usb *tu) 163 { 164 struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); 165 166 /* Disable gadget controller if any */ 167 if (tu->phy.otg->gadget) 168 usb_gadget_vbus_disconnect(tu->phy.otg->gadget); 169 170 /* Power off transceiver */ 171 retu_write(rdev, TAHVO_REG_USBR, 0); 172 tu->phy.otg->state = OTG_STATE_UNDEFINED; 173 } 174 175 static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend) 176 { 177 struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, phy); 178 struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); 179 u16 w; 180 181 dev_dbg(&tu->pt_dev->dev, "%s\n", __func__); 182 183 w = retu_read(rdev, TAHVO_REG_USBR); 184 if (suspend) 185 w &= ~USBR_NSUSPEND; 186 else 187 w |= USBR_NSUSPEND; 188 retu_write(rdev, TAHVO_REG_USBR, w); 189 190 return 0; 191 } 192 193 static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host) 194 { 195 struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb, 196 phy); 197 198 mutex_lock(&tu->serialize); 199 200 if (host == NULL) { 201 if (tu->tahvo_mode == TAHVO_MODE_HOST) 202 tahvo_usb_power_off(tu); 203 otg->host = NULL; 204 mutex_unlock(&tu->serialize); 205 return 0; 206 } 207 208 if (tu->tahvo_mode == TAHVO_MODE_HOST) { 209 otg->host = NULL; 210 tahvo_usb_become_host(tu); 211 } 212 213 otg->host = host; 214 215 mutex_unlock(&tu->serialize); 216 217 return 0; 218 } 219 220 static int tahvo_usb_set_peripheral(struct usb_otg *otg, 221 struct usb_gadget *gadget) 222 { 223 struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb, 224 phy); 225 226 mutex_lock(&tu->serialize); 227 228 if (!gadget) { 229 if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) 230 tahvo_usb_power_off(tu); 231 tu->phy.otg->gadget = NULL; 232 mutex_unlock(&tu->serialize); 233 return 0; 234 } 235 236 tu->phy.otg->gadget = gadget; 237 if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) 238 tahvo_usb_become_peripheral(tu); 239 240 mutex_unlock(&tu->serialize); 241 242 return 0; 243 } 244 245 static irqreturn_t tahvo_usb_vbus_interrupt(int irq, void *_tu) 246 { 247 struct tahvo_usb *tu = _tu; 248 249 mutex_lock(&tu->serialize); 250 check_vbus_state(tu); 251 mutex_unlock(&tu->serialize); 252 253 return IRQ_HANDLED; 254 } 255 256 static ssize_t otg_mode_show(struct device *device, 257 struct device_attribute *attr, char *buf) 258 { 259 struct tahvo_usb *tu = dev_get_drvdata(device); 260 261 switch (tu->tahvo_mode) { 262 case TAHVO_MODE_HOST: 263 return sprintf(buf, "host\n"); 264 case TAHVO_MODE_PERIPHERAL: 265 return sprintf(buf, "peripheral\n"); 266 } 267 268 return -EINVAL; 269 } 270 271 static ssize_t otg_mode_store(struct device *device, 272 struct device_attribute *attr, 273 const char *buf, size_t count) 274 { 275 struct tahvo_usb *tu = dev_get_drvdata(device); 276 int r; 277 278 mutex_lock(&tu->serialize); 279 if (count >= 4 && strncmp(buf, "host", 4) == 0) { 280 if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) 281 tahvo_usb_stop_peripheral(tu); 282 tu->tahvo_mode = TAHVO_MODE_HOST; 283 if (tu->phy.otg->host) { 284 dev_info(device, "HOST mode: host controller present\n"); 285 tahvo_usb_become_host(tu); 286 } else { 287 dev_info(device, "HOST mode: no host controller, powering off\n"); 288 tahvo_usb_power_off(tu); 289 } 290 r = strlen(buf); 291 } else if (count >= 10 && strncmp(buf, "peripheral", 10) == 0) { 292 if (tu->tahvo_mode == TAHVO_MODE_HOST) 293 tahvo_usb_stop_host(tu); 294 tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; 295 if (tu->phy.otg->gadget) { 296 dev_info(device, "PERIPHERAL mode: gadget driver present\n"); 297 tahvo_usb_become_peripheral(tu); 298 } else { 299 dev_info(device, "PERIPHERAL mode: no gadget driver, powering off\n"); 300 tahvo_usb_power_off(tu); 301 } 302 r = strlen(buf); 303 } else { 304 r = -EINVAL; 305 } 306 mutex_unlock(&tu->serialize); 307 308 return r; 309 } 310 static DEVICE_ATTR_RW(otg_mode); 311 312 static struct attribute *tahvo_attrs[] = { 313 &dev_attr_vbus.attr, 314 &dev_attr_otg_mode.attr, 315 NULL 316 }; 317 ATTRIBUTE_GROUPS(tahvo); 318 319 static int tahvo_usb_probe(struct platform_device *pdev) 320 { 321 struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); 322 struct tahvo_usb *tu; 323 int ret; 324 325 tu = devm_kzalloc(&pdev->dev, sizeof(*tu), GFP_KERNEL); 326 if (!tu) 327 return -ENOMEM; 328 329 tu->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*tu->phy.otg), 330 GFP_KERNEL); 331 if (!tu->phy.otg) 332 return -ENOMEM; 333 334 tu->pt_dev = pdev; 335 336 /* Default mode */ 337 #ifdef CONFIG_TAHVO_USB_HOST_BY_DEFAULT 338 tu->tahvo_mode = TAHVO_MODE_HOST; 339 #else 340 tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; 341 #endif 342 343 mutex_init(&tu->serialize); 344 345 tu->ick = devm_clk_get(&pdev->dev, "usb_l4_ick"); 346 if (!IS_ERR(tu->ick)) 347 clk_enable(tu->ick); 348 349 /* 350 * Set initial state, so that we generate kevents only on state changes. 351 */ 352 tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS; 353 354 tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable); 355 if (IS_ERR(tu->extcon)) { 356 dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); 357 ret = PTR_ERR(tu->extcon); 358 goto err_disable_clk; 359 } 360 361 ret = devm_extcon_dev_register(&pdev->dev, tu->extcon); 362 if (ret) { 363 dev_err(&pdev->dev, "could not register extcon device: %d\n", 364 ret); 365 goto err_disable_clk; 366 } 367 368 /* Set the initial cable state. */ 369 extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, 370 tu->tahvo_mode == TAHVO_MODE_HOST); 371 extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); 372 373 /* Create OTG interface */ 374 tahvo_usb_power_off(tu); 375 tu->phy.dev = &pdev->dev; 376 tu->phy.otg->state = OTG_STATE_UNDEFINED; 377 tu->phy.label = DRIVER_NAME; 378 tu->phy.set_suspend = tahvo_usb_set_suspend; 379 380 tu->phy.otg->usb_phy = &tu->phy; 381 tu->phy.otg->set_host = tahvo_usb_set_host; 382 tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral; 383 384 ret = usb_add_phy(&tu->phy, USB_PHY_TYPE_USB2); 385 if (ret < 0) { 386 dev_err(&pdev->dev, "cannot register USB transceiver: %d\n", 387 ret); 388 goto err_disable_clk; 389 } 390 391 dev_set_drvdata(&pdev->dev, tu); 392 393 tu->irq = ret = platform_get_irq(pdev, 0); 394 if (ret < 0) 395 goto err_remove_phy; 396 ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 397 IRQF_ONESHOT, 398 "tahvo-vbus", tu); 399 if (ret) { 400 dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n", 401 ret); 402 goto err_remove_phy; 403 } 404 405 return 0; 406 407 err_remove_phy: 408 usb_remove_phy(&tu->phy); 409 err_disable_clk: 410 if (!IS_ERR(tu->ick)) 411 clk_disable(tu->ick); 412 413 return ret; 414 } 415 416 static void tahvo_usb_remove(struct platform_device *pdev) 417 { 418 struct tahvo_usb *tu = platform_get_drvdata(pdev); 419 420 free_irq(tu->irq, tu); 421 usb_remove_phy(&tu->phy); 422 if (!IS_ERR(tu->ick)) 423 clk_disable(tu->ick); 424 } 425 426 static struct platform_driver tahvo_usb_driver = { 427 .probe = tahvo_usb_probe, 428 .remove = tahvo_usb_remove, 429 .driver = { 430 .name = "tahvo-usb", 431 .dev_groups = tahvo_groups, 432 }, 433 }; 434 module_platform_driver(tahvo_usb_driver); 435 436 MODULE_DESCRIPTION("Tahvo USB transceiver driver"); 437 MODULE_LICENSE("GPL"); 438 MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs"); 439 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); 440