Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Add MSM OTG Controller driver

This driver implements PHY initialization, clock management, ULPI IO ops
and simple OTG state machine to kick host/peripheral based on Id/VBUS
line status. VBUS/Id lines are tied to a reference voltage on some boards.
Hence provide debugfs interface to select host/peripheral mode.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Pavankumar Kondeti and committed by
Greg Kroah-Hartman
e0c201f3 05570297

+1025
+10
drivers/usb/otg/Kconfig
··· 81 81 To compile this driver as a module, choose M here: the 82 82 module will be called langwell_otg. 83 83 84 + config USB_MSM_OTG_72K 85 + tristate "OTG support for Qualcomm on-chip USB controller" 86 + depends on (USB || USB_GADGET) && ARCH_MSM 87 + select USB_OTG_UTILS 88 + help 89 + Enable this to support the USB OTG transceiver on MSM chips. It 90 + handles PHY initialization, clock management, and workarounds 91 + required after resetting the hardware. This driver is required 92 + even for peripheral only or host only mode configuration. 93 + 84 94 endif # USB || OTG
+1
drivers/usb/otg/Makefile
··· 15 15 obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o 16 16 obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o 17 17 obj-$(CONFIG_USB_ULPI) += ulpi.o 18 + obj-$(CONFIG_USB_MSM_OTG_72K) += msm72k_otg.o
+850
drivers/usb/otg/msm72k_otg.c
··· 1 + /* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License version 2 and 5 + * only version 2 as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program; if not, write to the Free Software 14 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 + * 02110-1301, USA. 16 + * 17 + */ 18 + 19 + #include <linux/module.h> 20 + #include <linux/device.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/clk.h> 23 + #include <linux/slab.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/err.h> 26 + #include <linux/delay.h> 27 + #include <linux/io.h> 28 + #include <linux/ioport.h> 29 + #include <linux/uaccess.h> 30 + #include <linux/debugfs.h> 31 + #include <linux/seq_file.h> 32 + 33 + #include <linux/usb.h> 34 + #include <linux/usb/otg.h> 35 + #include <linux/usb/ulpi.h> 36 + #include <linux/usb/gadget.h> 37 + #include <linux/usb/hcd.h> 38 + #include <linux/usb/msm_hsusb.h> 39 + #include <linux/usb/msm_hsusb_hw.h> 40 + 41 + #include <mach/clk.h> 42 + 43 + #define MSM_USB_BASE (motg->regs) 44 + #define DRIVER_NAME "msm_otg" 45 + 46 + #define ULPI_IO_TIMEOUT_USEC (10 * 1000) 47 + static int ulpi_read(struct otg_transceiver *otg, u32 reg) 48 + { 49 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 50 + int cnt = 0; 51 + 52 + /* initiate read operation */ 53 + writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), 54 + USB_ULPI_VIEWPORT); 55 + 56 + /* wait for completion */ 57 + while (cnt < ULPI_IO_TIMEOUT_USEC) { 58 + if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) 59 + break; 60 + udelay(1); 61 + cnt++; 62 + } 63 + 64 + if (cnt >= ULPI_IO_TIMEOUT_USEC) { 65 + dev_err(otg->dev, "ulpi_read: timeout %08x\n", 66 + readl(USB_ULPI_VIEWPORT)); 67 + return -ETIMEDOUT; 68 + } 69 + return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT)); 70 + } 71 + 72 + static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg) 73 + { 74 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 75 + int cnt = 0; 76 + 77 + /* initiate write operation */ 78 + writel(ULPI_RUN | ULPI_WRITE | 79 + ULPI_ADDR(reg) | ULPI_DATA(val), 80 + USB_ULPI_VIEWPORT); 81 + 82 + /* wait for completion */ 83 + while (cnt < ULPI_IO_TIMEOUT_USEC) { 84 + if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) 85 + break; 86 + udelay(1); 87 + cnt++; 88 + } 89 + 90 + if (cnt >= ULPI_IO_TIMEOUT_USEC) { 91 + dev_err(otg->dev, "ulpi_write: timeout\n"); 92 + return -ETIMEDOUT; 93 + } 94 + return 0; 95 + } 96 + 97 + static struct otg_io_access_ops msm_otg_io_ops = { 98 + .read = ulpi_read, 99 + .write = ulpi_write, 100 + }; 101 + 102 + static void ulpi_init(struct msm_otg *motg) 103 + { 104 + struct msm_otg_platform_data *pdata = motg->pdata; 105 + int *seq = pdata->phy_init_seq; 106 + 107 + if (!seq) 108 + return; 109 + 110 + while (seq[0] >= 0) { 111 + dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n", 112 + seq[0], seq[1]); 113 + ulpi_write(&motg->otg, seq[0], seq[1]); 114 + seq += 2; 115 + } 116 + } 117 + 118 + static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) 119 + { 120 + int ret; 121 + 122 + if (assert) { 123 + ret = clk_reset(motg->clk, CLK_RESET_ASSERT); 124 + if (ret) 125 + dev_err(motg->otg.dev, "usb hs_clk assert failed\n"); 126 + } else { 127 + ret = clk_reset(motg->clk, CLK_RESET_DEASSERT); 128 + if (ret) 129 + dev_err(motg->otg.dev, "usb hs_clk deassert failed\n"); 130 + } 131 + return ret; 132 + } 133 + 134 + static int msm_otg_phy_clk_reset(struct msm_otg *motg) 135 + { 136 + int ret; 137 + 138 + ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT); 139 + if (ret) { 140 + dev_err(motg->otg.dev, "usb phy clk assert failed\n"); 141 + return ret; 142 + } 143 + usleep_range(10000, 12000); 144 + ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT); 145 + if (ret) 146 + dev_err(motg->otg.dev, "usb phy clk deassert failed\n"); 147 + return ret; 148 + } 149 + 150 + static int msm_otg_phy_reset(struct msm_otg *motg) 151 + { 152 + u32 val; 153 + int ret; 154 + int retries; 155 + 156 + ret = msm_otg_link_clk_reset(motg, 1); 157 + if (ret) 158 + return ret; 159 + ret = msm_otg_phy_clk_reset(motg); 160 + if (ret) 161 + return ret; 162 + ret = msm_otg_link_clk_reset(motg, 0); 163 + if (ret) 164 + return ret; 165 + 166 + val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; 167 + writel(val | PORTSC_PTS_ULPI, USB_PORTSC); 168 + 169 + for (retries = 3; retries > 0; retries--) { 170 + ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM, 171 + ULPI_CLR(ULPI_FUNC_CTRL)); 172 + if (!ret) 173 + break; 174 + ret = msm_otg_phy_clk_reset(motg); 175 + if (ret) 176 + return ret; 177 + } 178 + if (!retries) 179 + return -ETIMEDOUT; 180 + 181 + /* This reset calibrates the phy, if the above write succeeded */ 182 + ret = msm_otg_phy_clk_reset(motg); 183 + if (ret) 184 + return ret; 185 + 186 + for (retries = 3; retries > 0; retries--) { 187 + ret = ulpi_read(&motg->otg, ULPI_DEBUG); 188 + if (ret != -ETIMEDOUT) 189 + break; 190 + ret = msm_otg_phy_clk_reset(motg); 191 + if (ret) 192 + return ret; 193 + } 194 + if (!retries) 195 + return -ETIMEDOUT; 196 + 197 + dev_info(motg->otg.dev, "phy_reset: success\n"); 198 + return 0; 199 + } 200 + 201 + #define LINK_RESET_TIMEOUT_USEC (250 * 1000) 202 + static int msm_otg_reset(struct otg_transceiver *otg) 203 + { 204 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 205 + struct msm_otg_platform_data *pdata = motg->pdata; 206 + int cnt = 0; 207 + int ret; 208 + u32 val = 0; 209 + u32 ulpi_val = 0; 210 + 211 + ret = msm_otg_phy_reset(motg); 212 + if (ret) { 213 + dev_err(otg->dev, "phy_reset failed\n"); 214 + return ret; 215 + } 216 + 217 + ulpi_init(motg); 218 + 219 + writel(USBCMD_RESET, USB_USBCMD); 220 + while (cnt < LINK_RESET_TIMEOUT_USEC) { 221 + if (!(readl(USB_USBCMD) & USBCMD_RESET)) 222 + break; 223 + udelay(1); 224 + cnt++; 225 + } 226 + if (cnt >= LINK_RESET_TIMEOUT_USEC) 227 + return -ETIMEDOUT; 228 + 229 + /* select ULPI phy */ 230 + writel(0x80000000, USB_PORTSC); 231 + 232 + msleep(100); 233 + 234 + writel(0x0, USB_AHBBURST); 235 + writel(0x00, USB_AHBMODE); 236 + 237 + if (pdata->otg_control == OTG_PHY_CONTROL) { 238 + val = readl(USB_OTGSC); 239 + if (pdata->mode == USB_OTG) { 240 + ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID; 241 + val |= OTGSC_IDIE | OTGSC_BSVIE; 242 + } else if (pdata->mode == USB_PERIPHERAL) { 243 + ulpi_val = ULPI_INT_SESS_VALID; 244 + val |= OTGSC_BSVIE; 245 + } 246 + writel(val, USB_OTGSC); 247 + ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE); 248 + ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL); 249 + } 250 + 251 + return 0; 252 + } 253 + 254 + static void msm_otg_start_host(struct otg_transceiver *otg, int on) 255 + { 256 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 257 + struct msm_otg_platform_data *pdata = motg->pdata; 258 + struct usb_hcd *hcd; 259 + 260 + if (!otg->host) 261 + return; 262 + 263 + hcd = bus_to_hcd(otg->host); 264 + 265 + if (on) { 266 + dev_dbg(otg->dev, "host on\n"); 267 + 268 + if (pdata->vbus_power) 269 + pdata->vbus_power(1); 270 + /* 271 + * Some boards have a switch cotrolled by gpio 272 + * to enable/disable internal HUB. Enable internal 273 + * HUB before kicking the host. 274 + */ 275 + if (pdata->setup_gpio) 276 + pdata->setup_gpio(OTG_STATE_A_HOST); 277 + #ifdef CONFIG_USB 278 + usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); 279 + #endif 280 + } else { 281 + dev_dbg(otg->dev, "host off\n"); 282 + 283 + #ifdef CONFIG_USB 284 + usb_remove_hcd(hcd); 285 + #endif 286 + if (pdata->setup_gpio) 287 + pdata->setup_gpio(OTG_STATE_UNDEFINED); 288 + if (pdata->vbus_power) 289 + pdata->vbus_power(0); 290 + } 291 + } 292 + 293 + static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) 294 + { 295 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 296 + struct usb_hcd *hcd; 297 + 298 + /* 299 + * Fail host registration if this board can support 300 + * only peripheral configuration. 301 + */ 302 + if (motg->pdata->mode == USB_PERIPHERAL) { 303 + dev_info(otg->dev, "Host mode is not supported\n"); 304 + return -ENODEV; 305 + } 306 + 307 + if (!host) { 308 + if (otg->state == OTG_STATE_A_HOST) { 309 + msm_otg_start_host(otg, 0); 310 + otg->host = NULL; 311 + otg->state = OTG_STATE_UNDEFINED; 312 + schedule_work(&motg->sm_work); 313 + } else { 314 + otg->host = NULL; 315 + } 316 + 317 + return 0; 318 + } 319 + 320 + hcd = bus_to_hcd(host); 321 + hcd->power_budget = motg->pdata->power_budget; 322 + 323 + otg->host = host; 324 + dev_dbg(otg->dev, "host driver registered w/ tranceiver\n"); 325 + 326 + /* 327 + * Kick the state machine work, if peripheral is not supported 328 + * or peripheral is already registered with us. 329 + */ 330 + if (motg->pdata->mode == USB_HOST || otg->gadget) 331 + schedule_work(&motg->sm_work); 332 + 333 + return 0; 334 + } 335 + 336 + static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on) 337 + { 338 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 339 + struct msm_otg_platform_data *pdata = motg->pdata; 340 + 341 + if (!otg->gadget) 342 + return; 343 + 344 + if (on) { 345 + dev_dbg(otg->dev, "gadget on\n"); 346 + /* 347 + * Some boards have a switch cotrolled by gpio 348 + * to enable/disable internal HUB. Disable internal 349 + * HUB before kicking the gadget. 350 + */ 351 + if (pdata->setup_gpio) 352 + pdata->setup_gpio(OTG_STATE_B_PERIPHERAL); 353 + usb_gadget_vbus_connect(otg->gadget); 354 + } else { 355 + dev_dbg(otg->dev, "gadget off\n"); 356 + usb_gadget_vbus_disconnect(otg->gadget); 357 + if (pdata->setup_gpio) 358 + pdata->setup_gpio(OTG_STATE_UNDEFINED); 359 + } 360 + 361 + } 362 + 363 + static int msm_otg_set_peripheral(struct otg_transceiver *otg, 364 + struct usb_gadget *gadget) 365 + { 366 + struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 367 + 368 + /* 369 + * Fail peripheral registration if this board can support 370 + * only host configuration. 371 + */ 372 + if (motg->pdata->mode == USB_HOST) { 373 + dev_info(otg->dev, "Peripheral mode is not supported\n"); 374 + return -ENODEV; 375 + } 376 + 377 + if (!gadget) { 378 + if (otg->state == OTG_STATE_B_PERIPHERAL) { 379 + msm_otg_start_peripheral(otg, 0); 380 + otg->gadget = NULL; 381 + otg->state = OTG_STATE_UNDEFINED; 382 + schedule_work(&motg->sm_work); 383 + } else { 384 + otg->gadget = NULL; 385 + } 386 + 387 + return 0; 388 + } 389 + otg->gadget = gadget; 390 + dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n"); 391 + 392 + /* 393 + * Kick the state machine work, if host is not supported 394 + * or host is already registered with us. 395 + */ 396 + if (motg->pdata->mode == USB_PERIPHERAL || otg->host) 397 + schedule_work(&motg->sm_work); 398 + 399 + return 0; 400 + } 401 + 402 + /* 403 + * We support OTG, Peripheral only and Host only configurations. In case 404 + * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen 405 + * via Id pin status or user request (debugfs). Id/BSV interrupts are not 406 + * enabled when switch is controlled by user and default mode is supplied 407 + * by board file, which can be changed by userspace later. 408 + */ 409 + static void msm_otg_init_sm(struct msm_otg *motg) 410 + { 411 + struct msm_otg_platform_data *pdata = motg->pdata; 412 + u32 otgsc = readl(USB_OTGSC); 413 + 414 + switch (pdata->mode) { 415 + case USB_OTG: 416 + if (pdata->otg_control == OTG_PHY_CONTROL) { 417 + if (otgsc & OTGSC_ID) 418 + set_bit(ID, &motg->inputs); 419 + else 420 + clear_bit(ID, &motg->inputs); 421 + 422 + if (otgsc & OTGSC_BSV) 423 + set_bit(B_SESS_VLD, &motg->inputs); 424 + else 425 + clear_bit(B_SESS_VLD, &motg->inputs); 426 + } else if (pdata->otg_control == OTG_USER_CONTROL) { 427 + if (pdata->default_mode == USB_HOST) { 428 + clear_bit(ID, &motg->inputs); 429 + } else if (pdata->default_mode == USB_PERIPHERAL) { 430 + set_bit(ID, &motg->inputs); 431 + set_bit(B_SESS_VLD, &motg->inputs); 432 + } else { 433 + set_bit(ID, &motg->inputs); 434 + clear_bit(B_SESS_VLD, &motg->inputs); 435 + } 436 + } 437 + break; 438 + case USB_HOST: 439 + clear_bit(ID, &motg->inputs); 440 + break; 441 + case USB_PERIPHERAL: 442 + set_bit(ID, &motg->inputs); 443 + if (otgsc & OTGSC_BSV) 444 + set_bit(B_SESS_VLD, &motg->inputs); 445 + else 446 + clear_bit(B_SESS_VLD, &motg->inputs); 447 + break; 448 + default: 449 + break; 450 + } 451 + } 452 + 453 + static void msm_otg_sm_work(struct work_struct *w) 454 + { 455 + struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); 456 + struct otg_transceiver *otg = &motg->otg; 457 + 458 + switch (otg->state) { 459 + case OTG_STATE_UNDEFINED: 460 + dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n"); 461 + msm_otg_reset(otg); 462 + msm_otg_init_sm(motg); 463 + otg->state = OTG_STATE_B_IDLE; 464 + /* FALL THROUGH */ 465 + case OTG_STATE_B_IDLE: 466 + dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n"); 467 + if (!test_bit(ID, &motg->inputs) && otg->host) { 468 + /* disable BSV bit */ 469 + writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); 470 + msm_otg_start_host(otg, 1); 471 + otg->state = OTG_STATE_A_HOST; 472 + } else if (test_bit(B_SESS_VLD, &motg->inputs) && otg->gadget) { 473 + msm_otg_start_peripheral(otg, 1); 474 + otg->state = OTG_STATE_B_PERIPHERAL; 475 + } 476 + break; 477 + case OTG_STATE_B_PERIPHERAL: 478 + dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n"); 479 + if (!test_bit(B_SESS_VLD, &motg->inputs) || 480 + !test_bit(ID, &motg->inputs)) { 481 + msm_otg_start_peripheral(otg, 0); 482 + otg->state = OTG_STATE_B_IDLE; 483 + msm_otg_reset(otg); 484 + schedule_work(w); 485 + } 486 + break; 487 + case OTG_STATE_A_HOST: 488 + dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n"); 489 + if (test_bit(ID, &motg->inputs)) { 490 + msm_otg_start_host(otg, 0); 491 + otg->state = OTG_STATE_B_IDLE; 492 + msm_otg_reset(otg); 493 + schedule_work(w); 494 + } 495 + break; 496 + default: 497 + break; 498 + } 499 + } 500 + 501 + static irqreturn_t msm_otg_irq(int irq, void *data) 502 + { 503 + struct msm_otg *motg = data; 504 + struct otg_transceiver *otg = &motg->otg; 505 + u32 otgsc = 0; 506 + 507 + otgsc = readl(USB_OTGSC); 508 + if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS))) 509 + return IRQ_NONE; 510 + 511 + if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) { 512 + if (otgsc & OTGSC_ID) 513 + set_bit(ID, &motg->inputs); 514 + else 515 + clear_bit(ID, &motg->inputs); 516 + dev_dbg(otg->dev, "ID set/clear\n"); 517 + } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) { 518 + if (otgsc & OTGSC_BSV) 519 + set_bit(B_SESS_VLD, &motg->inputs); 520 + else 521 + clear_bit(B_SESS_VLD, &motg->inputs); 522 + dev_dbg(otg->dev, "BSV set/clear\n"); 523 + } 524 + 525 + writel(otgsc, USB_OTGSC); 526 + schedule_work(&motg->sm_work); 527 + return IRQ_HANDLED; 528 + } 529 + 530 + static int msm_otg_mode_show(struct seq_file *s, void *unused) 531 + { 532 + struct msm_otg *motg = s->private; 533 + struct otg_transceiver *otg = &motg->otg; 534 + 535 + switch (otg->state) { 536 + case OTG_STATE_A_HOST: 537 + seq_printf(s, "host\n"); 538 + break; 539 + case OTG_STATE_B_PERIPHERAL: 540 + seq_printf(s, "peripheral\n"); 541 + break; 542 + default: 543 + seq_printf(s, "none\n"); 544 + break; 545 + } 546 + 547 + return 0; 548 + } 549 + 550 + static int msm_otg_mode_open(struct inode *inode, struct file *file) 551 + { 552 + return single_open(file, msm_otg_mode_show, inode->i_private); 553 + } 554 + 555 + static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, 556 + size_t count, loff_t *ppos) 557 + { 558 + struct msm_otg *motg = file->private_data; 559 + char buf[16]; 560 + struct otg_transceiver *otg = &motg->otg; 561 + int status = count; 562 + enum usb_mode_type req_mode; 563 + 564 + memset(buf, 0x00, sizeof(buf)); 565 + 566 + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) { 567 + status = -EFAULT; 568 + goto out; 569 + } 570 + 571 + if (!strncmp(buf, "host", 4)) { 572 + req_mode = USB_HOST; 573 + } else if (!strncmp(buf, "peripheral", 10)) { 574 + req_mode = USB_PERIPHERAL; 575 + } else if (!strncmp(buf, "none", 4)) { 576 + req_mode = USB_NONE; 577 + } else { 578 + status = -EINVAL; 579 + goto out; 580 + } 581 + 582 + switch (req_mode) { 583 + case USB_NONE: 584 + switch (otg->state) { 585 + case OTG_STATE_A_HOST: 586 + case OTG_STATE_B_PERIPHERAL: 587 + set_bit(ID, &motg->inputs); 588 + clear_bit(B_SESS_VLD, &motg->inputs); 589 + break; 590 + default: 591 + goto out; 592 + } 593 + break; 594 + case USB_PERIPHERAL: 595 + switch (otg->state) { 596 + case OTG_STATE_B_IDLE: 597 + case OTG_STATE_A_HOST: 598 + set_bit(ID, &motg->inputs); 599 + set_bit(B_SESS_VLD, &motg->inputs); 600 + break; 601 + default: 602 + goto out; 603 + } 604 + break; 605 + case USB_HOST: 606 + switch (otg->state) { 607 + case OTG_STATE_B_IDLE: 608 + case OTG_STATE_B_PERIPHERAL: 609 + clear_bit(ID, &motg->inputs); 610 + break; 611 + default: 612 + goto out; 613 + } 614 + break; 615 + default: 616 + goto out; 617 + } 618 + 619 + schedule_work(&motg->sm_work); 620 + out: 621 + return status; 622 + } 623 + 624 + const struct file_operations msm_otg_mode_fops = { 625 + .open = msm_otg_mode_open, 626 + .read = seq_read, 627 + .write = msm_otg_mode_write, 628 + .llseek = seq_lseek, 629 + .release = single_release, 630 + }; 631 + 632 + static struct dentry *msm_otg_dbg_root; 633 + static struct dentry *msm_otg_dbg_mode; 634 + 635 + static int msm_otg_debugfs_init(struct msm_otg *motg) 636 + { 637 + msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL); 638 + 639 + if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root)) 640 + return -ENODEV; 641 + 642 + msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR, 643 + msm_otg_dbg_root, motg, &msm_otg_mode_fops); 644 + if (!msm_otg_dbg_mode) { 645 + debugfs_remove(msm_otg_dbg_root); 646 + msm_otg_dbg_root = NULL; 647 + return -ENODEV; 648 + } 649 + 650 + return 0; 651 + } 652 + 653 + static void msm_otg_debugfs_cleanup(void) 654 + { 655 + debugfs_remove(msm_otg_dbg_mode); 656 + debugfs_remove(msm_otg_dbg_root); 657 + } 658 + 659 + static int __init msm_otg_probe(struct platform_device *pdev) 660 + { 661 + int ret = 0; 662 + struct resource *res; 663 + struct msm_otg *motg; 664 + struct otg_transceiver *otg; 665 + 666 + dev_info(&pdev->dev, "msm_otg probe\n"); 667 + if (!pdev->dev.platform_data) { 668 + dev_err(&pdev->dev, "No platform data given. Bailing out\n"); 669 + return -ENODEV; 670 + } 671 + 672 + motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); 673 + if (!motg) { 674 + dev_err(&pdev->dev, "unable to allocate msm_otg\n"); 675 + return -ENOMEM; 676 + } 677 + 678 + motg->pdata = pdev->dev.platform_data; 679 + otg = &motg->otg; 680 + otg->dev = &pdev->dev; 681 + 682 + motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); 683 + if (IS_ERR(motg->phy_reset_clk)) { 684 + dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); 685 + ret = PTR_ERR(motg->phy_reset_clk); 686 + goto free_motg; 687 + } 688 + 689 + motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); 690 + if (IS_ERR(motg->clk)) { 691 + dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); 692 + ret = PTR_ERR(motg->clk); 693 + goto put_phy_reset_clk; 694 + } 695 + 696 + motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); 697 + if (IS_ERR(motg->pclk)) { 698 + dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); 699 + ret = PTR_ERR(motg->pclk); 700 + goto put_clk; 701 + } 702 + 703 + /* 704 + * USB core clock is not present on all MSM chips. This 705 + * clock is introduced to remove the dependency on AXI 706 + * bus frequency. 707 + */ 708 + motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); 709 + if (IS_ERR(motg->core_clk)) 710 + motg->core_clk = NULL; 711 + 712 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 713 + if (!res) { 714 + dev_err(&pdev->dev, "failed to get platform resource mem\n"); 715 + ret = -ENODEV; 716 + goto put_core_clk; 717 + } 718 + 719 + motg->regs = ioremap(res->start, resource_size(res)); 720 + if (!motg->regs) { 721 + dev_err(&pdev->dev, "ioremap failed\n"); 722 + ret = -ENOMEM; 723 + goto put_core_clk; 724 + } 725 + dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); 726 + 727 + motg->irq = platform_get_irq(pdev, 0); 728 + if (!motg->irq) { 729 + dev_err(&pdev->dev, "platform_get_irq failed\n"); 730 + ret = -ENODEV; 731 + goto free_regs; 732 + } 733 + 734 + clk_enable(motg->clk); 735 + clk_enable(motg->pclk); 736 + if (motg->core_clk) 737 + clk_enable(motg->core_clk); 738 + 739 + writel(0, USB_USBINTR); 740 + writel(0, USB_OTGSC); 741 + 742 + INIT_WORK(&motg->sm_work, msm_otg_sm_work); 743 + ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, 744 + "msm_otg", motg); 745 + if (ret) { 746 + dev_err(&pdev->dev, "request irq failed\n"); 747 + goto disable_clks; 748 + } 749 + 750 + otg->init = msm_otg_reset; 751 + otg->set_host = msm_otg_set_host; 752 + otg->set_peripheral = msm_otg_set_peripheral; 753 + 754 + otg->io_ops = &msm_otg_io_ops; 755 + 756 + ret = otg_set_transceiver(&motg->otg); 757 + if (ret) { 758 + dev_err(&pdev->dev, "otg_set_transceiver failed\n"); 759 + goto free_irq; 760 + } 761 + 762 + platform_set_drvdata(pdev, motg); 763 + device_init_wakeup(&pdev->dev, 1); 764 + 765 + if (motg->pdata->mode == USB_OTG && 766 + motg->pdata->otg_control == OTG_USER_CONTROL) { 767 + ret = msm_otg_debugfs_init(motg); 768 + if (ret) 769 + dev_dbg(&pdev->dev, "mode debugfs file is" 770 + "not available\n"); 771 + } 772 + 773 + return 0; 774 + 775 + free_irq: 776 + free_irq(motg->irq, motg); 777 + disable_clks: 778 + clk_disable(motg->pclk); 779 + clk_disable(motg->clk); 780 + free_regs: 781 + iounmap(motg->regs); 782 + put_core_clk: 783 + if (motg->core_clk) 784 + clk_put(motg->core_clk); 785 + clk_put(motg->pclk); 786 + put_clk: 787 + clk_put(motg->clk); 788 + put_phy_reset_clk: 789 + clk_put(motg->phy_reset_clk); 790 + free_motg: 791 + kfree(motg); 792 + return ret; 793 + } 794 + 795 + static int __devexit msm_otg_remove(struct platform_device *pdev) 796 + { 797 + struct msm_otg *motg = platform_get_drvdata(pdev); 798 + struct otg_transceiver *otg = &motg->otg; 799 + 800 + if (otg->host || otg->gadget) 801 + return -EBUSY; 802 + 803 + msm_otg_debugfs_cleanup(); 804 + cancel_work_sync(&motg->sm_work); 805 + device_init_wakeup(&pdev->dev, 0); 806 + otg_set_transceiver(NULL); 807 + 808 + free_irq(motg->irq, motg); 809 + 810 + clk_disable(motg->pclk); 811 + clk_disable(motg->clk); 812 + if (motg->core_clk) 813 + clk_disable(motg->core_clk); 814 + 815 + iounmap(motg->regs); 816 + 817 + clk_put(motg->phy_reset_clk); 818 + clk_put(motg->pclk); 819 + clk_put(motg->clk); 820 + if (motg->core_clk) 821 + clk_put(motg->core_clk); 822 + 823 + kfree(motg); 824 + 825 + return 0; 826 + } 827 + 828 + static struct platform_driver msm_otg_driver = { 829 + .remove = __devexit_p(msm_otg_remove), 830 + .driver = { 831 + .name = DRIVER_NAME, 832 + .owner = THIS_MODULE, 833 + }, 834 + }; 835 + 836 + static int __init msm_otg_init(void) 837 + { 838 + return platform_driver_probe(&msm_otg_driver, msm_otg_probe); 839 + } 840 + 841 + static void __exit msm_otg_exit(void) 842 + { 843 + platform_driver_unregister(&msm_otg_driver); 844 + } 845 + 846 + module_init(msm_otg_init); 847 + module_exit(msm_otg_exit); 848 + 849 + MODULE_LICENSE("GPL v2"); 850 + MODULE_DESCRIPTION("MSM USB transceiver driver");
+108
include/linux/usb/msm_hsusb.h
··· 1 + /* linux/include/asm-arm/arch-msm/hsusb.h 2 + * 3 + * Copyright (C) 2008 Google, Inc. 4 + * Author: Brian Swetland <swetland@google.com> 5 + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. 6 + * 7 + * This software is licensed under the terms of the GNU General Public 8 + * License version 2, as published by the Free Software Foundation, and 9 + * may be copied, distributed, and modified under those terms. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + */ 17 + 18 + #ifndef __ASM_ARCH_MSM_HSUSB_H 19 + #define __ASM_ARCH_MSM_HSUSB_H 20 + 21 + #include <linux/types.h> 22 + #include <linux/usb/otg.h> 23 + 24 + /** 25 + * Supported USB modes 26 + * 27 + * USB_PERIPHERAL Only peripheral mode is supported. 28 + * USB_HOST Only host mode is supported. 29 + * USB_OTG OTG mode is supported. 30 + * 31 + */ 32 + enum usb_mode_type { 33 + USB_NONE = 0, 34 + USB_PERIPHERAL, 35 + USB_HOST, 36 + USB_OTG, 37 + }; 38 + 39 + /** 40 + * OTG control 41 + * 42 + * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host 43 + * only configuration. 44 + * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. 45 + * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. 46 + * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. 47 + * 48 + */ 49 + enum otg_control_type { 50 + OTG_NO_CONTROL = 0, 51 + OTG_PHY_CONTROL, 52 + OTG_PMIC_CONTROL, 53 + OTG_USER_CONTROL, 54 + }; 55 + 56 + /** 57 + * struct msm_otg_platform_data - platform device data 58 + * for msm72k_otg driver. 59 + * @phy_init_seq: PHY configuration sequence. val, reg pairs 60 + * terminated by -1. 61 + * @vbus_power: VBUS power on/off routine. 62 + * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). 63 + * @mode: Supported mode (OTG/peripheral/host). 64 + * @otg_control: OTG switch controlled by user/Id pin 65 + * @default_mode: Default operational mode. Applicable only if 66 + * OTG switch is controller by user. 67 + * 68 + */ 69 + struct msm_otg_platform_data { 70 + int *phy_init_seq; 71 + void (*vbus_power)(bool on); 72 + unsigned power_budget; 73 + enum usb_mode_type mode; 74 + enum otg_control_type otg_control; 75 + enum usb_mode_type default_mode; 76 + void (*setup_gpio)(enum usb_otg_state state); 77 + }; 78 + 79 + /** 80 + * struct msm_otg: OTG driver data. Shared by HCD and DCD. 81 + * @otg: USB OTG Transceiver structure. 82 + * @pdata: otg device platform data. 83 + * @irq: IRQ number assigned for HSUSB controller. 84 + * @clk: clock struct of usb_hs_clk. 85 + * @pclk: clock struct of usb_hs_pclk. 86 + * @phy_reset_clk: clock struct of usb_phy_clk. 87 + * @core_clk: clock struct of usb_hs_core_clk. 88 + * @regs: ioremapped register base address. 89 + * @inputs: OTG state machine inputs(Id, SessValid etc). 90 + * @sm_work: OTG state machine work. 91 + * 92 + */ 93 + struct msm_otg { 94 + struct otg_transceiver otg; 95 + struct msm_otg_platform_data *pdata; 96 + int irq; 97 + struct clk *clk; 98 + struct clk *pclk; 99 + struct clk *phy_reset_clk; 100 + struct clk *core_clk; 101 + void __iomem *regs; 102 + #define ID 0 103 + #define B_SESS_VLD 1 104 + unsigned long inputs; 105 + struct work_struct sm_work; 106 + }; 107 + 108 + #endif
+56
include/linux/usb/msm_hsusb_hw.h
··· 1 + /* 2 + * Copyright (C) 2007 Google, Inc. 3 + * Author: Brian Swetland <swetland@google.com> 4 + * 5 + * This software is licensed under the terms of the GNU General Public 6 + * License version 2, as published by the Free Software Foundation, and 7 + * may be copied, distributed, and modified under those terms. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + */ 15 + 16 + #ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__ 17 + #define __LINUX_USB_GADGET_MSM72K_UDC_H__ 18 + 19 + #ifdef CONFIG_ARCH_MSM7X00A 20 + #define USB_SBUSCFG (MSM_USB_BASE + 0x0090) 21 + #else 22 + #define USB_AHBBURST (MSM_USB_BASE + 0x0090) 23 + #define USB_AHBMODE (MSM_USB_BASE + 0x0098) 24 + #endif 25 + #define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */ 26 + 27 + #define USB_USBCMD (MSM_USB_BASE + 0x0140) 28 + #define USB_PORTSC (MSM_USB_BASE + 0x0184) 29 + #define USB_OTGSC (MSM_USB_BASE + 0x01A4) 30 + #define USB_USBMODE (MSM_USB_BASE + 0x01A8) 31 + 32 + #define USBCMD_RESET 2 33 + #define USB_USBINTR (MSM_USB_BASE + 0x0148) 34 + 35 + #define PORTSC_PHCD (1 << 23) /* phy suspend mode */ 36 + #define PORTSC_PTS_MASK (3 << 30) 37 + #define PORTSC_PTS_ULPI (3 << 30) 38 + 39 + #define USB_ULPI_VIEWPORT (MSM_USB_BASE + 0x0170) 40 + #define ULPI_RUN (1 << 30) 41 + #define ULPI_WRITE (1 << 29) 42 + #define ULPI_READ (0 << 29) 43 + #define ULPI_ADDR(n) (((n) & 255) << 16) 44 + #define ULPI_DATA(n) ((n) & 255) 45 + #define ULPI_DATA_READ(n) (((n) >> 8) & 255) 46 + 47 + /* OTG definitions */ 48 + #define OTGSC_INTSTS_MASK (0x7f << 16) 49 + #define OTGSC_ID (1 << 8) 50 + #define OTGSC_BSV (1 << 11) 51 + #define OTGSC_IDIS (1 << 16) 52 + #define OTGSC_BSVIS (1 << 19) 53 + #define OTGSC_IDIE (1 << 24) 54 + #define OTGSC_BSVIE (1 << 27) 55 + 56 + #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */