/* * HS USB Host-mode HSET driver for Mentor USB Controller * * Copyright (C) 2005 Mentor Graphics Corporation * Copyright (C) 2008 Texas Instruments, Inc. * Nishant Kamat * Vikram Pandita * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. * * This driver is based on the USB Skeleton driver-2.0 * (drivers/usb/usb-skeleton.c) written by Greg Kroah-Hartman (greg@kroah.com) * * Notes: * Host-mode HSET is tested by attaching a HS OPT (OTG Protocol Tester) card. * The OPT test application contains scripts to test each mode. * Each script attaches the OPT with a distinct VID/PID. Depending on * the VID/PID this driver go into a particular test mode. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../core/usb.h" #include "musb_regs.h" #include "musb_core.h" #define usb_sndaddr0pipe() (PIPE_CONTROL<<30) #define usb_rcvaddr0pipe() (PIPE_CONTROL<<30 | USB_DIR_IN) extern u8 musb_test_packet[53]; /*---------------------------------------------------------------------------*/ /* Test routines */ static void test_musb(struct musb *musb, u8 mode) { void __iomem *regs = musb->endpoints[0].regs; if (mode == MUSB_TEST_PACKET) { musb_ep_select(musb->mregs, 0); musb_writew(regs, MUSB_CSR0, 0); musb_write_fifo(musb->endpoints, sizeof(musb_test_packet), musb_test_packet); /* need to set test mode before enabling FIFO, as otherwise * the packet goes out and the FIFO empties before the test * mode is set */ musb_writeb(musb->mregs, MUSB_TESTMODE, mode); musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY); } else musb_writeb(musb->mregs, MUSB_TESTMODE, mode); } static inline void test_se0_nak(struct musb *musb) { printk(KERN_INFO "%s\n", __FUNCTION__); test_musb(musb, MUSB_TEST_SE0_NAK); } static inline void test_j(struct musb *musb) { printk(KERN_ERR "%s\n", __FUNCTION__); test_musb(musb, MUSB_TEST_J); } static inline void test_k(struct musb *musb) { printk(KERN_INFO "%s\n", __FUNCTION__); test_musb(musb, MUSB_TEST_K); } static inline void test_packet(struct musb *musb) { printk(KERN_INFO "%s\n", __FUNCTION__); test_musb(musb, MUSB_TEST_PACKET); } static inline void test_force_enable(struct musb *musb) { printk(KERN_INFO "%s\n", __FUNCTION__); test_musb(musb, MUSB_TEST_FORCE_HOST); } static void suspend(struct musb *musb) { void __iomem *mbase = musb->mregs; u8 power; printk(KERN_INFO "%s\n", __FUNCTION__); power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, power | MUSB_POWER_SUSPENDM); } static void resume(struct musb *musb) { void __iomem *mbase = musb->mregs; u8 power; printk(KERN_INFO "%s\n", __FUNCTION__); power = musb_readb(mbase, MUSB_POWER); if (power & MUSB_POWER_SUSPENDM) { power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); musb_writeb(mbase, MUSB_POWER, power |MUSB_POWER_RESUME ); msleep(10); power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESUME); } else printk(KERN_DEBUG "not suspended??\n"); } static void test_suspend_resume(struct musb *musb) { printk(KERN_INFO "%s\n", __FUNCTION__); printk("waiting for 15s of SOF\n"); mdelay(15000); suspend(musb); msleep(15000); /* Wait for 15 sec */ resume(musb); msleep(15000); } static void test_single_step_get_dev_desc(struct musb *musb, struct usb_device *udev) { unsigned int retval; retval = usb_control_msg(udev, usb_rcvaddr0pipe(), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE<<8, 0, &udev->descriptor,sizeof(udev->descriptor), USB_CTRL_GET_TIMEOUT); printk("\n retval = %x, %d",retval, sizeof(udev->descriptor)); if (retval < (signed)sizeof(udev->descriptor)) printk("device descriptor read/%s, error %d\n","all", retval); else{ printk(" bLength=%d\n",udev->descriptor.bLength); printk(" bDescriptorType=%x\n",udev->descriptor.bDescriptorType); printk(" bcdUSB=%x\n",cpu_to_le16(udev->descriptor.bcdUSB)); printk(" bDeviceClass=%x\n",udev->descriptor.bDeviceClass); printk(" bDeviceSubClass=%x\n",udev->descriptor.bDeviceSubClass); printk(" bDeviceProtocol=%x\n",udev->descriptor.bDeviceProtocol); printk(" bMaxPacketSize0=%x\n",udev->descriptor.bMaxPacketSize0); printk(" idVendor=%x\n",cpu_to_le16(udev->descriptor.idVendor)); printk(" idProduct=%x\n",cpu_to_le16(udev->descriptor.idProduct)); printk(" bcdDevice=%x\n",cpu_to_le16(udev->descriptor.bcdDevice)); printk(" iManufacturer=%x\n",udev->descriptor.iManufacturer); printk(" iProduct=%x\n",udev->descriptor.iProduct); printk(" iSerialNumber=%x\n",udev->descriptor.iSerialNumber); printk(" bNumConfigurations=%x\n",udev->descriptor.bNumConfigurations); } } static void test_single_step_set_feature(struct musb *musb, struct usb_device *udev) { printk(KERN_INFO "%s\n", __FUNCTION__); if (!udev) { printk(KERN_DEBUG "No device connected.\n"); return; } usb_control_msg(udev, usb_sndaddr0pipe(), USB_REQ_SET_FEATURE, 0, 0, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); } void host_mode_test(u16 idVendor, u16 idProduct, struct usb_hcd *hcd, struct usb_device *udev) { struct musb *musb = hcd_to_musb(hcd); u8 devctl; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); musb_writeb(musb->mregs, MUSB_DEVCTL, devctl | 1); mdelay(10); switch( idProduct ) { case 0x0101: test_se0_nak(musb); break; case 0x0102: test_j(musb); break; case 0x0103: test_k(musb); break; case 0x0104: test_packet(musb); break; case 0x0105: test_force_enable(musb); break; case 0x0106: test_suspend_resume(musb); break; case 0x0107: msleep(15000); /* SOFs for 15 sec */ test_single_step_get_dev_desc(musb, udev); break; case 0x0108: test_single_step_get_dev_desc(musb, udev); printk("waiting for 15s of SOF\n"); msleep(15000); test_single_step_set_feature(musb,udev); break; default: printk("Not supported\n"); break; }; }