ci13xxx_udc.c revision ca9cfea09fc5802074f79d086547c6363ddc894b
1aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* 2aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ci13xxx_udc.c - MIPS USB IP core family device controller 3aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 4aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. 5aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 6aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Author: David Lopo 7aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 8aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This program is free software; you can redistribute it and/or modify 9aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * it under the terms of the GNU General Public License version 2 as 10aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * published by the Free Software Foundation. 11aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 12aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 13aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* 14aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Description: MIPS USB IP core family device controller 15aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Currently it only supports IP part number CI13412 16aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 17aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This driver is composed of several blocks: 18aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - HW: hardware interface 19aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - DBG: debug facilities (optional) 20aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - UTIL: utilities 21aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - ISR: interrupts handling 22aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - ENDPT: endpoint operations (Gadget API) 23aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - GADGET: gadget operations (Gadget API) 24aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - BUS: bus glue code, bus abstraction layer 25aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 26aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Compile Options 27aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities 28aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - STALL_IN: non-empty bulk-in pipes cannot be halted 29aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * if defined mass storage compliance succeeds but with warnings 30aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * => case 4: Hi > Dn 31aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * => case 5: Hi > Di 32aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * => case 8: Hi <> Do 33aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * if undefined usbtest 13 fails 34aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - TRACE: enable function tracing (depends on DEBUG) 35aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 36aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Main Features 37aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Chapter 9 & Mass Storage Compliance with Gadget File Storage 38aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) 39aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Normal & LPM support 40aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 41aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * USBTEST Report 42aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - OK: 0-12, 13 (STALL_IN defined) & 14 43aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Not Supported: 15 & 16 (ISO) 44aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 45aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * TODO List 46aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - OTG 47aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Isochronous & Interrupt Traffic 48aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Handle requests which spawns into several TDs 49aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - GET_STATUS(device) - always reports 0 50aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Gadget API (majority of optional features) 51aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * - Suspend & Remote Wakeup 52aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 5336825a2deca913a11915893b6ecf5e1d817b6e75Matthias Kaehlcke#include <linux/delay.h> 54aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/device.h> 55aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/dmapool.h> 56aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/dma-mapping.h> 57aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/init.h> 58aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/interrupt.h> 59aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/io.h> 60aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/irq.h> 61aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/kernel.h> 625a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 63c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti#include <linux/pm_runtime.h> 64aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/usb/ch9.h> 65aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include <linux/usb/gadget.h> 66f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#include <linux/usb/otg.h> 67aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 68aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#include "ci13xxx_udc.h" 69aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 70aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 71aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 72aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * DEFINE 73aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 74aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* ctrl register bank access */ 75aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEFINE_SPINLOCK(udc_lock); 76aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 77aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* control endpoint description */ 78aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic const struct usb_endpoint_descriptor 79ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetictrl_endpt_out_desc = { 80aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bLength = USB_DT_ENDPOINT_SIZE, 81aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bDescriptorType = USB_DT_ENDPOINT, 82aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 83ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bEndpointAddress = USB_DIR_OUT, 84ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 85ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), 86ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti}; 87ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 88ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic const struct usb_endpoint_descriptor 89ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetictrl_endpt_in_desc = { 90ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bLength = USB_DT_ENDPOINT_SIZE, 91ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bDescriptorType = USB_DT_ENDPOINT, 92ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 93ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bEndpointAddress = USB_DIR_IN, 94aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 95aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), 96aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo}; 97aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 98aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* UDC descriptor */ 99aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct ci13xxx *_udc; 100aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 101aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* Interrupt statistics */ 102aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ISR_MASK 0x1F 103aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct { 104aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 test; 105aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 ui; 106aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 uei; 107aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 pci; 108aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 uri; 109aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 sli; 110aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 none; 111aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct { 112aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 cnt; 113aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 buf[ISR_MASK+1]; 114aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 idx; 115aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } hndl; 116aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} isr_statistics; 117aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 118aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 119aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ffs_nr: find first (least significant) bit set 120aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @x: the word to search 121aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 122aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns bit number (instead of position) 123aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 124aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ffs_nr(u32 x) 125aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 126aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = ffs(x); 127aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 128aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n ? n-1 : 32; 129aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 130aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 131aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 132aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * HW block 133aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 134aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* register bank descriptor */ 135aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct { 136aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned lpm; /* is LPM? */ 137aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo void __iomem *abs; /* bus map offset */ 138aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo void __iomem *cap; /* bus map offset + CAP offset + CAP data */ 139aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo size_t size; /* bank size */ 140aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} hw_bank; 141aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 142f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti/* MSM specific */ 143f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#define ABS_AHBBURST (0x0090UL) 144f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#define ABS_AHBMODE (0x0098UL) 145aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* UDC register map */ 146aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_CAPLENGTH (0x100UL) 147aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_HCCPARAMS (0x108UL) 148aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_DCCPARAMS (0x124UL) 149aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) 150aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* offset to CAPLENTGH (addr + data) */ 151aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBCMD (0x000UL) 152aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBSTS (0x004UL) 153aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBINTR (0x008UL) 154aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_DEVICEADDR (0x014UL) 155aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTLISTADDR (0x018UL) 156aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_PORTSC (0x044UL) 157f23e649bb605523b960434c5e18c8e9ad3f0b5bdDavid Lopo#define CAP_DEVLC (0x084UL) 158aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) 159aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) 160aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) 161aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) 162aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) 163aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) 164aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) 165aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) 166aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 167aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* maximum number of enpoints: valid only after hw_device_reset() */ 168aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic unsigned hw_ep_max; 169aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 170aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 171aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_bit: calculates the bit number 172aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 173aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 174aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 175aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns bit number 176aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 177aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic inline int hw_ep_bit(int num, int dir) 178aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 179aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return num + (dir ? 16 : 0); 180aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 181aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 182aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 183aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_aread: reads from register bitfield 184aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to bus map 185aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 186aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 187aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 188aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 189aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_aread(u32 addr, u32 mask) 190aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 191aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ioread32(addr + hw_bank.abs) & mask; 192aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 193aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 194aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 195aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_awrite: writes to register bitfield 196aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to bus map 197aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 198aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 199aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 200aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void hw_awrite(u32 addr, u32 mask, u32 data) 201aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 202aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(hw_aread(addr, ~mask) | (data & mask), 203aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr + hw_bank.abs); 204aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 205aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 206aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 207aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_cread: reads from register bitfield 208aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 209aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 210aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 211aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 212aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 213aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_cread(u32 addr, u32 mask) 214aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 215aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ioread32(addr + hw_bank.cap) & mask; 216aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 217aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 218aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 219aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_cwrite: writes to register bitfield 220aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 221aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 222aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 223aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 224aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void hw_cwrite(u32 addr, u32 mask, u32 data) 225aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 226aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(hw_cread(addr, ~mask) | (data & mask), 227aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr + hw_bank.cap); 228aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 229aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 230aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 231aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ctest_and_clear: tests & clears register bitfield 232aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 233aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 234aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 235aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_ctest_and_clear(u32 addr, u32 mask) 238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_cread(addr, mask); 240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 241aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(reg, addr + hw_bank.cap); 242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return reg; 243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ctest_and_write: tests & writes register bitfield 247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 250aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 251aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 252aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 253aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) 254aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 255aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_cread(addr, ~0); 256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 257aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); 258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return (reg & mask) >> ffs_nr(mask); 259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 261f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int hw_device_init(void __iomem *base) 262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg; 264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 265aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* bank is a module variable */ 266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.abs = base; 267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap = hw_bank.abs; 269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap += ABS_CAPLENGTH; 270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap += ioread8(hw_bank.cap); 271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); 273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.lpm = reg; 274aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size = hw_bank.cap - hw_bank.abs; 275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size += CAP_LAST; 276aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size /= sizeof(u32); 277aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 278f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); 279ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 280f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 281ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) 282ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti return -ENODEV; 283f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 284f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* setup lock mode ? */ 285f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 286f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* ENDPTSETUPSTAT is '0' by default */ 287f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 288f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 289f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 290f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return 0; 291f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti} 292f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti/** 293f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * hw_device_reset: resets chip (execute without interruption) 294f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * @base: register base address 295f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * 296f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * This function returns an error code 297f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti */ 298f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int hw_device_reset(struct ci13xxx *udc) 299f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti{ 300aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* should flush & stop before reset */ 301aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); 302aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); 303aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 304aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); 305aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_USBCMD, USBCMD_RST)) 306aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udelay(10); /* not RTOS friendly */ 307aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 308f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 309f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 310f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 311f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_RESET_EVENT); 312f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 313f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING) 314f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS); 315f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 316aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* USBMODE should be configured step by step */ 317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 318aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); 319aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ 320aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 321aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { 322aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo pr_err("cannot enter in device mode"); 323aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo pr_err("lpm = %i", hw_bank.lpm); 324aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENODEV; 325aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 326aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 327aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 328aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 329aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 330aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 331aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_device_state: enables/disables interrupts & starts/stops device (execute 332aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 333aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dma: 0 => disable, !0 => enable and set dma engine 334aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 335aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 337aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_device_state(u32 dma) 338aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 339aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dma) { 340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); 341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* interrupt, error, port change, reset, sleep/suspend */ 342aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, ~0, 343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); 344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); 345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 346aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); 347aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, ~0, 0); 348aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 349aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 350aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 351aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 352aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 353aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_flush: flush endpoint fifo (execute without interruption) 354aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 355aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 356aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 357aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 358aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 359aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_flush(int num, int dir) 360aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 361aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = hw_ep_bit(num, dir); 362aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 363aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 364aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* flush any pending transfer */ 365aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); 366aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) 367aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo cpu_relax(); 368aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); 369aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 370aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 371aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 372aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 373aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 374aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_disable: disables endpoint (execute without interruption) 375aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 376aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 377aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 378aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 379aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_disable(int num, int dir) 381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(num, dir); 383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), 384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); 385aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 386aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 387aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_enable: enables endpoint (execute without interruption) 390aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 391aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 392aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @type: endpoint type 393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 394aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 395aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_enable(int num, int dir, int type) 397aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 398aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask, data; 399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dir) { 401aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask = ENDPTCTRL_TXT; /* type */ 402aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data = type << ffs_nr(mask); 403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXS; /* unstall */ 405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXR; /* reset data toggle */ 406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_TXR; 407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXE; /* enable */ 408aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_TXE; 409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask = ENDPTCTRL_RXT; /* type */ 411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data = type << ffs_nr(mask); 412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXS; /* unstall */ 414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXR; /* reset data toggle */ 415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_RXR; 416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXE; /* enable */ 417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_RXE; 418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); 420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 422aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_get_halt: return endpoint halt status 425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 428aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns 1 if endpoint halted 429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_get_halt(int num, int dir) 431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; 433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; 435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_is_primed: test if endpoint is primed (execute without interruption) 439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 442aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns true if endpoint primed 443aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 444aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_is_primed(int num, int dir) 445aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 446aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_cread(CAP_ENDPTPRIME, ~0) | hw_cread(CAP_ENDPTSTAT, ~0); 447aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 448aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return test_bit(hw_ep_bit(num, dir), (void *)®); 449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 450aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 451aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 452aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_setup_status: test & clear setup status (execute without 453aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 454aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: bit number (endpoint) 455aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 456aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns setup status 457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 458aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_setup_status(int n) 459aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 460aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); 461aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 462aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 463aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 464aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_prime: primes endpoint (execute without interruption) 465aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 466aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 467aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @is_ctrl: true if control endpoint 468aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 469aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 470aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 471aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_prime(int num, int dir, int is_ctrl) 472aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 473aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = hw_ep_bit(num, dir); 474aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 475aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* the caller should flush first */ 476aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_ep_is_primed(num, dir)) 477aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 478aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 479aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) 480aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 481aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 482aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); 483aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 484aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTPRIME, BIT(n))) 485aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo cpu_relax(); 486aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) 487aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 488aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 489aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* status shoult be tested according with manual but it doesn't work */ 490aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 491aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 492aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 493aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 494aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute 495aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 496aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 497aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 498aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @value: true => stall, false => unstall 499aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 500aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 501aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 502aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_set_halt(int num, int dir, int value) 503aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 504aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (value != 0 && value != 1) 505aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 506aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 507aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 508aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); 509aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; 510aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; 511aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 512aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* data toggle - reserved for EP0 but it's in ESS */ 513aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); 514aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 515aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (value != hw_ep_get_halt(num, dir)); 516aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 517aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 518aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 519aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 520aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 521aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_intr_clear: disables interrupt & clears interrupt status (execute without 522aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 523aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: interrupt bit 524aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 525aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 526aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 527aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_intr_clear(int n) 528aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 529aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (n >= REG_BITS) 530aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 531aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 532aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, BIT(n), 0); 533aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); 534aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 535aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 536aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 537aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 538aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_intr_force: enables interrupt & forces interrupt status (execute without 539aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 540aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: interrupt bit 541aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 542aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 543aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 544aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_intr_force(int n) 545aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 546aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (n >= REG_BITS) 547aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 548aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 549aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); 550aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); 551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); 552aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); 553aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 554aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 555aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 556aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 557aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_is_port_high_speed: test if port is high speed 558aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 559aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns true if high speed port 560aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 561aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_port_is_high_speed(void) 562aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 563aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : 564aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cread(CAP_PORTSC, PORTSC_HSP); 565aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 566aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 568aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_port_test_get: reads port test mode value 569aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 570aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns port test mode value 571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 572aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u8 hw_port_test_get(void) 573aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); 575aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_port_test_set: writes port test mode (execute without interruption) 579aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mode: new value 580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 581aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_port_test_set(u8 mode) 584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const u8 TEST_MODE_MAX = 7; 586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mode > TEST_MODE_MAX) 588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); 591aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 594aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 595aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_read_intr_enable: returns interrupt enable register 596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 597aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register data 598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_read_intr_enable(void) 600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_USBINTR, ~0); 602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 603aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 604aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_read_intr_status: returns interrupt status register 606aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 607aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register data 608aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 609aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_read_intr_status(void) 610aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 611aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_USBSTS, ~0); 612aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 613aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 614aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_register_read: reads all device registers (execute without interruption) 616aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @buf: destination buffer 617aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @size: buffer size 618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 619aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns number of registers read 620aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 621aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic size_t hw_register_read(u32 *buf, size_t size) 622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 623aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 624aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 625aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (size > hw_bank.size) 626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo size = hw_bank.size; 627aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 628aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < size; i++) 629aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo buf[i] = hw_aread(i * sizeof(u32), ~0); 630aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 631aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return size; 632aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 635aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_register_write: writes to register 636aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: register address 637aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: register value 638aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 639aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 640aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_register_write(u16 addr, u32 data) 642aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 643aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* align */ 644aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr /= sizeof(u32); 645aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 646aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (addr >= hw_bank.size) 647aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 648aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 649aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* align */ 650aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr *= sizeof(u32); 651aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 652aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(addr, ~0, data); 653aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 654aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 655aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 656aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_complete: test & clear complete status (execute without 658aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: bit number (endpoint) 660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 661aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns complete status 662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 663aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_complete(int n) 664aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 665aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); 666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_intr_active: test & clear active interrupts (execute 670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 672aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns active interrutps 673aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 674aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_test_and_clear_intr_active(void) 675aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 676aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_read_intr_status() & hw_read_intr_enable(); 677aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 678aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, ~0, reg); 679aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return reg; 680aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 681aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 682aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 683aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_setup_guard: test & clear setup guard (execute without 684aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 685aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 686aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns guard value 687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 688aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_setup_guard(void) 689aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 690aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); 691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 692aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 693aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 694aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_set_setup_guard: test & set setup guard (execute without 695aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 696aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns guard value 698aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_set_setup_guard(void) 700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 701aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); 702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 703aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 704aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 705aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_usb_set_address: configures USB address (execute without interruption) 706aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @value: new USB address 707aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 708aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 709aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 710aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_usb_set_address(u8 value) 711aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 712aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* advance */ 713aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, 714aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); 715aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 716aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 717aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 718aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 719aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_usb_reset: restart device after a bus reset (execute without 720aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 721aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 722aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 723aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 724aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_usb_reset(void) 725aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 726aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_usb_set_address(0); 727aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 728aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* ESS flushes only at end?!? */ 729aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ 730aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 731aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* clear setup token semaphores */ 732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ 733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* clear complete status */ 735aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ 736aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 737aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* wait until all bits cleared */ 738aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTPRIME, ~0)) 739aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udelay(10); /* not RTOS friendly */ 740aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 741aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* reset all endpoints ? */ 742aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 743aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* reset internal status and wait for further instructions 744aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo no need to verify the port reset status (ESS does it) */ 745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 747aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 750aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * DBG block 751aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 752aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 753aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_device: prints information about device capabilities and status 754aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 755aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 756aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 757aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_device(struct device *dev, struct device_attribute *attr, 758aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 759aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_gadget *gadget = &udc->gadget; 762aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = 0; 763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 764aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 766aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 769aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 770aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", 771aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->speed); 772aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", 773aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->is_dualspeed); 774aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", 775aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->is_otg); 776aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", 777aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->is_a_peripheral); 778aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", 779aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->b_hnp_enable); 780aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", 781aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->a_hnp_support); 782aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", 783aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->a_alt_hnp_support); 784aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", 785aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo (gadget->name ? gadget->name : "")); 786aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 787aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 788aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 789aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(device, S_IRUSR, show_device, NULL); 790aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 791aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 792aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_driver: prints information about attached gadget (if any) 793aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 794aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 795aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 796aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_driver(struct device *dev, struct device_attribute *attr, 797aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 798aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 799aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 800aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_gadget_driver *driver = udc->driver; 801aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = 0; 802aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 803aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 804aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 805aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 806aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 807aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 808aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 809aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (driver == NULL) 810aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return scnprintf(buf, PAGE_SIZE, 811aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "There is no gadget attached!\n"); 812aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 813aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", 814aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo (driver->function ? driver->function : "")); 815aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", 816aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->speed); 817aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 818aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 819aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 820aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); 821aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 822aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* Maximum event message length */ 823aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define DBG_DATA_MSG 64UL 824aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 825aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* Maximum event messages */ 826aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define DBG_DATA_MAX 128UL 827aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 828aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* Event buffer descriptor */ 829aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct { 830aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ 831aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned idx; /* index */ 832aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned tty; /* print to console? */ 833aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rwlock_t lck; /* lock */ 834aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} dbg_data = { 835aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .idx = 0, 836aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .tty = 0, 837aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .lck = __RW_LOCK_UNLOCKED(lck) 838aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo}; 839aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 840aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 841aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_dec: decrements debug event index 842aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @idx: buffer index 843aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 844aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_dec(unsigned *idx) 845aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 846aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *idx = (*idx - 1) & (DBG_DATA_MAX-1); 847aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 848aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 849aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 850aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_inc: increments debug event index 851aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @idx: buffer index 852aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 853aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_inc(unsigned *idx) 854aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 855aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *idx = (*idx + 1) & (DBG_DATA_MAX-1); 856aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 857aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 858aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 859aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_print: prints the common part of the event 860aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: endpoint address 861aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @name: event name 862aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @status: status 863aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @extra: extra information 864aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 865aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_print(u8 addr, const char *name, int status, const char *extra) 866aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 867aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct timeval tval; 868aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned int stamp; 869aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 870aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 871aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo write_lock_irqsave(&dbg_data.lck, flags); 872aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 873aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do_gettimeofday(&tval); 874aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ 875aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo stamp = stamp * 1000000 + tval.tv_usec; 876aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 877aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, 878aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "%04X\t� %02X %-7.7s %4i �\t%s\n", 879aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo stamp, addr, name, status, extra); 880aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 881aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_inc(&dbg_data.idx); 882aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 883aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo write_unlock_irqrestore(&dbg_data.lck, flags); 884aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 885aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dbg_data.tty != 0) 886aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo pr_notice("%04X\t� %02X %-7.7s %4i �\t%s\n", 887aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo stamp, addr, name, status, extra); 888aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 889aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 890aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 891aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_done: prints a DONE event 892aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: endpoint address 893aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @td: transfer descriptor 894aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @status: status 895aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 896aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_done(u8 addr, const u32 token, int status) 897aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 898aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char msg[DBG_DATA_MSG]; 899aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 900aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo scnprintf(msg, sizeof(msg), "%d %02X", 901aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), 902aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); 903aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_print(addr, "DONE", status, msg); 904aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 905aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 906aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 907aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_event: prints a generic event 908aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: endpoint address 909aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @name: event name 910aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @status: status 911aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 912aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_event(u8 addr, const char *name, int status) 913aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 914aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (name != NULL) 915aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_print(addr, name, status, ""); 916aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 917aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 918aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* 919aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_queue: prints a QUEUE event 920aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: endpoint address 921aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @req: USB request 922aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @status: status 923aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 924aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_queue(u8 addr, const struct usb_request *req, int status) 925aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 926aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char msg[DBG_DATA_MSG]; 927aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 928aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req != NULL) { 929aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo scnprintf(msg, sizeof(msg), 930aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "%d %d", !req->no_interrupt, req->length); 931aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_print(addr, "QUEUE", status, msg); 932aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 933aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 934aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 935aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 936aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_setup: prints a SETUP event 937aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: endpoint address 938aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @req: setup request 939aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 940aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) 941aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 942aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char msg[DBG_DATA_MSG]; 943aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 944aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req != NULL) { 945aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo scnprintf(msg, sizeof(msg), 946aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "%02X %02X %04X %04X %d", req->bRequestType, 947aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->bRequest, le16_to_cpu(req->wValue), 948aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); 949aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_print(addr, "SETUP", 0, msg); 950aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 951aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 952aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 953aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 954aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_events: displays the event buffer 955aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 956aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 957aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 958aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_events(struct device *dev, struct device_attribute *attr, 959aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 960aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 961aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 962aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i, j, n = 0; 963aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 964aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 965aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 966aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 967aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 968aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 969aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 970aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo read_lock_irqsave(&dbg_data.lck, flags); 971aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 972aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo i = dbg_data.idx; 973aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { 974aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += strlen(dbg_data.buf[i]); 975aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (n >= PAGE_SIZE) { 976aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n -= strlen(dbg_data.buf[i]); 977aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 978aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 979aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 980aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) 981aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo j += scnprintf(buf + j, PAGE_SIZE - j, 982aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "%s", dbg_data.buf[i]); 983aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 984aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo read_unlock_irqrestore(&dbg_data.lck, flags); 985aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 986aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 987aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 988aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 989aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 990aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * store_events: configure if events are going to be also printed to console 991aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 992aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 993aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 994aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t store_events(struct device *dev, struct device_attribute *attr, 995aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const char *buf, size_t count) 996aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 997aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned tty; 998aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 999aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p, %d\n", __func__, buf, count); 1000aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1001aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1002aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1003aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1004aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1005aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { 1006aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "<1|0>: enable|disable console log\n"); 1007aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1008aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1009aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1010aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_data.tty = tty; 1011aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_info(dev, "tty = %u", dbg_data.tty); 1012aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1013aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1014aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return count; 1015aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1016aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); 1017aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1018aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1019aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_inters: interrupt status, enable status and historic 1020aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1021aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1022aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1023aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_inters(struct device *dev, struct device_attribute *attr, 1024aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 1025aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1026aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1027aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1028aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 intr; 1029aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i, j, n = 0; 1030aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1031aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1032aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1033aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1034aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1035aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1036aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1037aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1038aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1039aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1040aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "status = %08x\n", hw_read_intr_status()); 1041aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1042aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "enable = %08x\n", hw_read_intr_enable()); 1043aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1044aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", 1045aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.test); 1046aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "� ui = %d\n", 1047aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.ui); 1048aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "� uei = %d\n", 1049aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uei); 1050aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "� pci = %d\n", 1051aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.pci); 1052aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "� uri = %d\n", 1053aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uri); 1054aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "� sli = %d\n", 1055aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.sli); 1056aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", 1057aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.none); 1058aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", 1059aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.cnt); 1060aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1061aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { 1062aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo i &= ISR_MASK; 1063aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr = isr_statistics.hndl.buf[i]; 1064aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1065aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UI & intr) 1066aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); 1067aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr &= ~USBi_UI; 1068aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UEI & intr) 1069aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); 1070aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr &= ~USBi_UEI; 1071aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_PCI & intr) 1072aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); 1073aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr &= ~USBi_PCI; 1074aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_URI & intr) 1075aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); 1076aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr &= ~USBi_URI; 1077aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_SLI & intr) 1078aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); 1079aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr &= ~USBi_SLI; 1080aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (intr) 1081aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); 1082aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (isr_statistics.hndl.buf[i]) 1083aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); 1084aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1085aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1086aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1087aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1088aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1089aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1090aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1091aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1092aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * store_inters: enable & force or disable an individual interrutps 1093aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * (to be used for test purposes only) 1094aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1095aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1096aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1097aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t store_inters(struct device *dev, struct device_attribute *attr, 1098aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const char *buf, size_t count) 1099aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1100aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1101aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1102aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned en, bit; 1103aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1104aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p, %d\n", __func__, buf, count); 1105aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1106aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1107aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1108aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1109aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1110aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { 1111aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "<1|0> <bit>: enable|disable interrupt"); 1112aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1113aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1114aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1115aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1116aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (en) { 1117aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_intr_force(bit)) 1118aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "invalid bit number\n"); 1119aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else 1120aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.test++; 1121aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 1122aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_intr_clear(bit)) 1123aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "invalid bit number\n"); 1124aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1125aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1126aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1127aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1128aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return count; 1129aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1130aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); 1131aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1132aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1133aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_port_test: reads port test mode 1134aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1135aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1136aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1137aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_port_test(struct device *dev, 1138aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, char *buf) 1139aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1140aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1141aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1142aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned mode; 1143aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1144aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1145aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1146aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1147aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1148aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1149aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1150aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1151aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mode = hw_port_test_get(); 1152aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1153aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1154aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); 1155aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1156aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1157aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1158aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * store_port_test: writes port test mode 1159aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1160aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1161aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1162aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t store_port_test(struct device *dev, 1163aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, 1164aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const char *buf, size_t count) 1165aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1166aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1167aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1168aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned mode; 1169aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1170aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p, %d\n", __func__, buf, count); 1171aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1172aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1173aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1174aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1175aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1176aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (sscanf(buf, "%u", &mode) != 1) { 1177aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "<mode>: set port test mode"); 1178aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1179aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1180aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1181aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1182aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_port_test_set(mode)) 1183aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "invalid mode\n"); 1184aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1185aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1186aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1187aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return count; 1188aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1189aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, 1190aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo show_port_test, store_port_test); 1191aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1192aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1193aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_qheads: DMA contents of all queue heads 1194aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1195aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1196aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1197aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_qheads(struct device *dev, struct device_attribute *attr, 1198aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 1199aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1200aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1201aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1202aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i, j, n = 0; 1203aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1204aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1205aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1206aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1207aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1208aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1209aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1210aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1211ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (i = 0; i < hw_ep_max/2; i++) { 1212ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; 1213ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2]; 1214aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1215aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "EP=%02i: RX=%08X TX=%08X\n", 1216ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); 1217aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { 1218aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1219aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo " %04X: %08X %08X\n", j, 1220ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti *((u32 *)mEpRx->qh.ptr + j), 1221ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti *((u32 *)mEpTx->qh.ptr + j)); 1222aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1223aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1224aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1225aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1226aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1227aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1228aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); 1229aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1230aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1231aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_registers: dumps all registers 1232aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1233aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1234aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1235aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_registers(struct device *dev, 1236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, char *buf) 1237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 dump[512]; 1241aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i, k, n = 0; 1242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1250aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo k = hw_register_read(dump, sizeof(dump)/sizeof(u32)); 1251aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1252aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1253aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < k; i++) { 1254aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1255aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "reg[0x%04X] = 0x%08X\n", 1256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo i * (unsigned)sizeof(u32), dump[i]); 1257aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1261aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * store_registers: writes value to register address 1264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1265aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t store_registers(struct device *dev, 1268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, 1269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const char *buf, size_t count) 1270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long addr, data, flags; 1273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1274aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p, %d\n", __func__, buf, count); 1275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1276aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1277aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1278aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1279aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1280aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (sscanf(buf, "%li %li", &addr, &data) != 2) { 1281aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "<addr> <data>: write data to register address"); 1282aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1283aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1284aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1285aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1286aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_register_write(addr, data)) 1287aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "invalid address range\n"); 1288aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1289aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1290aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1291aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return count; 1292aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1293aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, 1294aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo show_registers, store_registers); 1295aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1296aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1297aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_requests: DMA contents of all requests currently queued (all endpts) 1298aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1299aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1300aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1301aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_requests(struct device *dev, struct device_attribute *attr, 1302aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 1303aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1304aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1305aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1306aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct list_head *ptr = NULL; 1307aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *req = NULL; 1308ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); 1309aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1310aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1311aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1312aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1313aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1314aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1315aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1316aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) 1318ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) 1319ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti { 1320ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti req = list_entry(ptr, struct ci13xxx_req, queue); 1321aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1322ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti n += scnprintf(buf + n, PAGE_SIZE - n, 1323ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti "EP=%02i: TD=%08X %s\n", 1324ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti i % hw_ep_max/2, (u32)req->dma, 1325ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti ((i < hw_ep_max/2) ? "RX" : "TX")); 1326ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1327ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (j = 0; j < qSize; j++) 1328aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1329ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti " %04X: %08X\n", j, 1330ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti *((u32 *)req->ptr + j)); 1331ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti } 1332aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1333aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1334aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1335aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); 1337aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1338aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1339aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_create_files: initializes the attribute interface 1340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 1341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1342aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__maybe_unused static int dbg_create_files(struct device *dev) 1345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1346aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 1347aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1348aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 1349aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1350aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_device); 1351aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1352aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1353aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_driver); 1354aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1355aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_device; 1356aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_events); 1357aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1358aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_driver; 1359aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_inters); 1360aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1361aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_events; 1362aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_port_test); 1363aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1364aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_inters; 1365aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_qheads); 1366aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1367aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_port_test; 1368aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_registers); 1369aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1370aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_qheads; 1371aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_requests); 1372aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1373aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_registers; 1374aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1375aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1376aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_registers: 1377aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_registers); 1378aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_qheads: 1379aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_qheads); 1380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_port_test: 1381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_port_test); 1382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_inters: 1383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_inters); 1384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_events: 1385aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_events); 1386aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_driver: 1387aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_driver); 1388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_device: 1389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_device); 1390aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1391aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1392aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1394aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1395aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_remove_files: destroys the attribute interface 1396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 1397aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1398aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__maybe_unused static int dbg_remove_files(struct device *dev) 1401aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1402aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 1403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_requests); 1405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_registers); 1406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_qheads); 1407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_port_test); 1408aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_inters); 1409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_events); 1410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_driver); 1411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_device); 1412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 1416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * UTIL block 1417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 1418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _usb_addr: calculates endpoint address from direction & number 1420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @ep: endpoint 1421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1422aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic inline u8 _usb_addr(struct ci13xxx_ep *ep) 1423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; 1425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1428aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _hardware_queue: configures a request at hardware level 1429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) 1435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 1437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, mReq); 1439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* don't queue twice */ 1441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.status == -EALREADY) 1442aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EALREADY; 1443aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1444aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_ep_is_primed(mEp->num, mEp->dir)) 1445aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 1446aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1447aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -EALREADY; 1448aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.length && !mReq->req.dma) { 1450aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.dma = \ 1451aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_map_single(mEp->device, mReq->req.buf, 1452aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.length, mEp->dir ? 1453aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo DMA_TO_DEVICE : DMA_FROM_DEVICE); 1454aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.dma == 0) 1455aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 1456aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->map = 1; 1458aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1459aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1460aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* 1461aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * TD configuration 1462aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * TODO - handle requests which spawns into several TDs 1463aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1464aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo memset(mReq->ptr, 0, sizeof(*mReq->ptr)); 1465aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->next |= TD_TERMINATE; 1466aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token = mReq->req.length << ffs_nr(TD_TOTAL_BYTES); 1467aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token &= TD_TOTAL_BYTES; 1468aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token |= TD_IOC; 1469aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token |= TD_STATUS_ACTIVE; 1470aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->page[0] = mReq->req.dma; 1471aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 1; i < 5; i++) 1472aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->page[i] = 14730a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; 1474aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1475aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* 1476aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * QH configuration 1477aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * At this point it's guaranteed exclusive access to qhead 1478aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * (endpt is not primed) so it's no need to use tripwire 1479aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1480ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ 1481ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ 1482aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.zero == 0) 1483ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap |= QH_ZLT; 1484aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else 1485ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap &= ~QH_ZLT; 1486aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1487aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo wmb(); /* synchronize before ep prime */ 1488aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1489aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ep_prime(mEp->num, mEp->dir, 1490aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->type == USB_ENDPOINT_XFER_CONTROL); 1491aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1492aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1493aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1494aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _hardware_dequeue: handles a request at hardware level 1495aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1496aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1497aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1498aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1499aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1500aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) 1501aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1502aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, mReq); 1503aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1504aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.status != -EALREADY) 1505aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1506aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1507aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_ep_is_primed(mEp->num, mEp->dir)) 1508aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(mEp->num, mEp->dir); 1509aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1510aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = 0; 1511aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1512aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->map) { 1513aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, 1514aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1515aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.dma = 0; 1516aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->map = 0; 1517aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1518aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1519aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = mReq->ptr->token & TD_STATUS; 1520aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if ((TD_STATUS_ACTIVE & mReq->req.status) != 0) 1521aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -ECONNRESET; 1522aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if ((TD_STATUS_HALTED & mReq->req.status) != 0) 1523aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1524aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) 1525aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1526aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) 1527aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1528aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1529aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; 1530aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); 1531aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->req.length - mReq->req.actual; 1532aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; 1533aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1534aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return mReq->req.actual; 1535aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1536aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1537aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1538aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _ep_nuke: dequeues all endpoint requests 1539aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1540aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1541aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1542aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must hold lock 1543aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1544aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _ep_nuke(struct ci13xxx_ep *mEp) 1545aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1546aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1547aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1548aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", mEp); 1549aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1550aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp == NULL) 1551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1552aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1553aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(mEp->num, mEp->dir); 1554aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1555ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti while (!list_empty(&mEp->qh.queue)) { 1556aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1557aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* pop oldest request */ 1558aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = \ 1559ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_entry(mEp->qh.queue.next, 1560aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req, queue); 1561aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mReq->queue); 1562aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -ESHUTDOWN; 1563aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 15647c25a82684364da44643cbe3bdbd0f8835293767Artem Leonenko if (mReq->req.complete != NULL) { 1565aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1566aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.complete(&mEp->ep, &mReq->req); 1567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1568aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1569aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1570aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1572aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1573aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts 1575aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must hold lock 1579aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _gadget_stop_activity(struct usb_gadget *gadget) 1581aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ep *ep; 1583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); 1584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", gadget); 1586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (gadget == NULL) 1588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* flush all endpoints */ 1591aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget_for_each_ep(ep, gadget) { 1592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_fifo_flush(ep); 1593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1594ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_fifo_flush(&udc->ep0out.ep); 1595ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_fifo_flush(&udc->ep0in.ep); 1596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1597aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->driver->disconnect(gadget); 1598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* make sure to disable all endpoints */ 1600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget_for_each_ep(ep, gadget) { 1601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_disable(ep); 1602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1603ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_disable(&udc->ep0out.ep); 1604ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_disable(&udc->ep0in.ep); 1605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1606ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (udc->status != NULL) { 1607ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_free_request(&udc->ep0in.ep, udc->status); 1608ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->status = NULL; 1609aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1610aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1611aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1612aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1613aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1614aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 1615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ISR block 1616aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 1617aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_reset_handler: USB reset interrupt handler 1619aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @udc: UDC device 1620aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1621aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function resets USB engine after a bus reset occurred 1622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1623aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_reset_handler(struct ci13xxx *udc) 1624aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(udc->lock) 1625aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(udc->lock) 1626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1627aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval; 1628aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1629aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", udc); 1630aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1631aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 1632aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1635aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1636aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(0xFF, "BUS RST", 0); 1637aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1638f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock(udc->lock); 1639aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = _gadget_stop_activity(&udc->gadget); 1640aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1642aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1643aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = hw_usb_reset(); 1644aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1645aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1646aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1647ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc); 1648ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (retval) 1649ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti goto done; 1650ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1651ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc); 1652aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!retval) { 1653ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); 1654ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (udc->status == NULL) { 1655ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_disable(&udc->ep0out.ep); 1656aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -ENOMEM; 1657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1658aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1661aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1663aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: %i", retval); 1664aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1665aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_get_status_complete: get_status request complete function 1668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @ep: endpoint 1669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @req: request handled 1670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must release lock 1672aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1673aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) 1674aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1675aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 1676aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1677aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL) { 1678aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1679aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1680aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1681aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1682aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(req->buf); 1683aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_free_request(ep, req); 1684aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1685aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1686aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_get_status_response: get_status request response 1688ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * @udc: udc struct 1689aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @setup: setup request packet 1690aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1692aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1693ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic int isr_get_status_response(struct ci13xxx *udc, 1694aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ctrlrequest *setup) 1695aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1696aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1698ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp = &udc->ep0in; 1699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_request *req = NULL; 1700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gfp_t gfp_flags = GFP_ATOMIC; 1701aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int dir, num, retval; 1702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1703aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, setup); 1704aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1705aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp == NULL || setup == NULL) 1706aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1707aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1708aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1709aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req = usb_ep_alloc_request(&mEp->ep, gfp_flags); 1710aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1711aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req == NULL) 1712aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 1713aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1714aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->complete = isr_get_status_complete; 1715aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->length = 2; 1716aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->buf = kzalloc(req->length, gfp_flags); 1717aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req->buf == NULL) { 1718aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -ENOMEM; 1719aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto err_free_req; 1720aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1721aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1722aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { 1723aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* TODO: D1 - Remote Wakeup; D0 - Self Powered */ 1724aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 1725aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else if ((setup->bRequestType & USB_RECIP_MASK) \ 1726aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo == USB_RECIP_ENDPOINT) { 1727aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? 1728aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo TX : RX; 1729aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; 1730aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *((u16 *)req->buf) = hw_ep_get_halt(num, dir); 1731aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* else do nothing; reserved for future use */ 1733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1735aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = usb_ep_queue(&mEp->ep, req, gfp_flags); 1736aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1737aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1738aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto err_free_buf; 1739aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1740aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1741aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1742aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err_free_buf: 1743aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(req->buf); 1744aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err_free_req: 1745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_free_request(&mEp->ep, req); 1747aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1750aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1751aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1752aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_setup_status_phase: queues the status phase of a setup transation 1753ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * @udc: udc struct 1754aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1755aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1756aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1757ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic int isr_setup_status_phase(struct ci13xxx *udc) 1758aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1759aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval; 1762ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp; 1763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1764ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti trace("%p", udc); 1765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1766ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; 1767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1769ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); 1770aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1771aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1772aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1773aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1774aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1775aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1776aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_tr_complete_low: transaction complete low level handler 1777aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1778aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1779aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1780aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must hold lock 1781aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1782aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int isr_tr_complete_low(struct ci13xxx_ep *mEp) 1783aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1784aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1785aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1786aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq; 1787aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval; 1788aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1789aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", mEp); 1790aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1791ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (list_empty(&mEp->qh.queue)) 1792aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1793aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1794aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* pop oldest request */ 1795ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mReq = list_entry(mEp->qh.queue.next, 1796aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req, queue); 1797aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mReq->queue); 1798aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1799aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = _hardware_dequeue(mEp, mReq); 1800aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval < 0) { 1801aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "DONE", retval); 1802aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1803aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1804aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1805aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); 1806aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1807ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (!list_empty(&mEp->qh.queue)) { 1808d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko struct ci13xxx_req* mReqEnq; 1809d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko 1810ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mReqEnq = list_entry(mEp->qh.queue.next, 1811d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko struct ci13xxx_req, queue); 1812d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko _hardware_enqueue(mEp, mReqEnq); 1813d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko } 1814d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko 18157c25a82684364da44643cbe3bdbd0f8835293767Artem Leonenko if (mReq->req.complete != NULL) { 1816aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1817aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.complete(&mEp->ep, &mReq->req); 1818aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1819aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1820aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1821aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1822aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1823aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1824aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1825aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1826aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_tr_complete_handler: transaction complete interrupt handler 1827aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @udc: UDC descriptor 1828aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1829aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function handles traffic events 1830aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1831aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_tr_complete_handler(struct ci13xxx *udc) 1832aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(udc->lock) 1833aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(udc->lock) 1834aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1835aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 1836aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1837aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", udc); 1838aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1839aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 1840aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1841aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1842aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1843aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1844aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) { 1845aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; 1846aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int type, num, err = -EINVAL; 1847aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ctrlrequest req; 1848aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1849aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->desc == NULL) 1850aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; /* not configured */ 1851aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1852ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (hw_test_and_clear_complete(i)) { 1853aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = isr_tr_complete_low(mEp); 1854aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { 1855aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err > 0) /* needs status phase */ 1856ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 1857aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err < 0) { 1858aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), 1859aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "ERROR", err); 1860aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1861aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (usb_ep_set_halt(&mEp->ep)) 1862aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: ep_set_halt"); 1863aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1864aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1865aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1866aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1867aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1868aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type != USB_ENDPOINT_XFER_CONTROL || 1869aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo !hw_test_and_clear_setup_status(i)) 1870aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; 1871aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1872aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (i != 0) { 1873aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("ctrl traffic received at endpoint"); 1874aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; 1875aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1876aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1877ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti /* 1878ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * Flush data and handshake transactions of previous 1879ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * setup packet. 1880ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti */ 1881ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti _ep_nuke(&udc->ep0out); 1882ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti _ep_nuke(&udc->ep0in); 1883ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1884aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* read_setup_packet */ 1885aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 1886aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_test_and_set_setup_guard(); 1887ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); 1888aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (!hw_test_and_clear_setup_guard()); 1889aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1890aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type = req.bRequestType; 1891aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1892ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; 1893aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1894aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_setup(_usb_addr(mEp), &req); 1895aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1896aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo switch (req.bRequest) { 1897aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_CLEAR_FEATURE: 1898aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 1899aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) 1900aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 1901aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req.wLength != 0) 1902aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1903aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num = le16_to_cpu(req.wIndex); 1904aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num &= USB_ENDPOINT_NUMBER_MASK; 1905aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!udc->ci13xxx_ep[num].wedge) { 1906aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1907aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = usb_ep_clear_halt( 1908aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo &udc->ci13xxx_ep[num].ep); 1909aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1910aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err) 1911aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1912aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1913ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 1914aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1915aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_GET_STATUS: 1916aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && 1917aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && 1918aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type != (USB_DIR_IN|USB_RECIP_INTERFACE)) 1919aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 1920aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (le16_to_cpu(req.wLength) != 2 || 1921aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wValue) != 0) 1922aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1923ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_get_status_response(udc, &req); 1924aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1925aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_SET_ADDRESS: 1926aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) 1927aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 1928aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (le16_to_cpu(req.wLength) != 0 || 1929aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wIndex) != 0) 1930aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1931aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); 1932aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err) 1933aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1934ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 1935aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1936aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_SET_FEATURE: 1937aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 1938aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT) 1939aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 1940aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req.wLength != 0) 1941aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1942aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num = le16_to_cpu(req.wIndex); 1943aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num &= USB_ENDPOINT_NUMBER_MASK; 1944aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1945aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1946aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); 1947aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1948aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err) 1949aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1950ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 1951aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1952aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo default: 1953aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopodelegate: 1954aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req.wLength == 0) /* no data phase */ 1955ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->ep0_dir = TX; 1956aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1957aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1958aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = udc->driver->setup(&udc->gadget, &req); 1959aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1960aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1961aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1962aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1963aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err < 0) { 1964aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "ERROR", err); 1965aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1966aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1967aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (usb_ep_set_halt(&mEp->ep)) 1968aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: ep_set_halt"); 1969aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1970aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1971aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1972aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1973aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1974aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 1975aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ENDPT block 1976aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 1977aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1978aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_enable: configure endpoint, making it usable 1979aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1980aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_enable() at "usb_gadget.h" for details 1981aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1982aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_enable(struct usb_ep *ep, 1983aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const struct usb_endpoint_descriptor *desc) 1984aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1985aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 1986ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int retval = 0; 1987aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1988aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1989aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, desc); 1990aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1991aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || desc == NULL) 1992aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1993aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1994aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 1995aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1996aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* only internal SW should enable ctrl endpts */ 1997aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1998aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->desc = desc; 1999aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2000ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (!list_empty(&mEp->qh.queue)) 2001aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("enabling a non-empty endpoint!"); 2002aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 200315739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; 200415739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->num = usb_endpoint_num(desc); 200515739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->type = usb_endpoint_type(desc); 2006aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2007aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); 2008aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2009ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti dbg_event(_usb_addr(mEp), "ENABLE", 0); 2010aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2011ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap = 0; 2012aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2013ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2014ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap |= QH_IOS; 2015ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti else if (mEp->type == USB_ENDPOINT_XFER_ISOC) 2016ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap &= ~QH_MULT; 2017ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti else 2018ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap &= ~QH_ZLT; 2019aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2020ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap |= 2021ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; 2022ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ 2023aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2024ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); 2025aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2026aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2027aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2028aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2029aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2030aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2031aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_disable: endpoint is no longer usable 2032aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2033aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_disable() at "usb_gadget.h" for details 2034aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2035aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_disable(struct usb_ep *ep) 2036aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2037aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2038aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int direction, retval = 0; 2039aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2040aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2041aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2042aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2043aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) 2044aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2045aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (mEp->desc == NULL) 2046aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 2047aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2048aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2049aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2050aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* only internal SW should disable ctrl endpts */ 2051aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2052aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo direction = mEp->dir; 2053aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 2054aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "DISABLE", 0); 2055aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2056aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= _ep_nuke(mEp); 2057aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= hw_ep_disable(mEp->num, mEp->dir); 2058aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2059aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2060aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir = (mEp->dir == TX) ? RX : TX; 2061aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2062aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (mEp->dir != direction); 2063aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2064aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->desc = NULL; 2065aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2066aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2067aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2068aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2069aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2070aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2071aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_alloc_request: allocate a request object to use with this endpoint 2072aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2073aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_alloc_request() at "usb_gadget.h" for details 2074aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2075aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) 2076aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2077aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2078aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = NULL; 2079aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2080aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %i", ep, gfp_flags); 2081aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2082aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) { 2083aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2084aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return NULL; 2085aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2086aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2087aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); 2088aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq != NULL) { 2089aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo INIT_LIST_HEAD(&mReq->queue); 2090aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2091aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, 2092aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo &mReq->dma); 2093aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->ptr == NULL) { 2094aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(mReq); 2095aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq = NULL; 2096aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2097aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2098aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2099aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); 2100aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2101aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return (mReq == NULL) ? NULL : &mReq->req; 2102aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2103aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2104aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2105aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_free_request: frees a request object 2106aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2107aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_free_request() at "usb_gadget.h" for details 2108aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2109aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void ep_free_request(struct usb_ep *ep, struct usb_request *req) 2110aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2111aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2112aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2113aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2114aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2115aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 2116aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2117aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL) { 2118aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2119aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2120aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else if (!list_empty(&mReq->queue)) { 2121aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EBUSY"); 2122aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2123aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2124aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2125aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2126aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2127aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->ptr) 2128aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); 2129aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(mReq); 2130aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2131aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "FREE", 0); 2132aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2133aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2134aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2135aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2136aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2137aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_queue: queues (submits) an I/O request to an endpoint 2138aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2139aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_queue()* at usb_gadget.h" for details 2140aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2141aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_queue(struct usb_ep *ep, struct usb_request *req, 2142aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gfp_t __maybe_unused gfp_flags) 2143aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2144aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2145aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2146aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 2147aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2148aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2149aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p, %X", ep, req, gfp_flags); 2150aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2151aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL || mEp->desc == NULL) 2152aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2153aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2154aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2155aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2156aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL && 2157ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti !list_empty(&mEp->qh.queue)) { 2158aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _ep_nuke(mEp); 2159aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -EOVERFLOW; 2160aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("endpoint ctrl %X nuked", _usb_addr(mEp)); 2161aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2162aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2163aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* first nuke then test link, e.g. previous status has not sent */ 2164aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!list_empty(&mReq->queue)) { 2165aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -EBUSY; 2166aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("request already in queue"); 2167aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2168aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2169aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 21700a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko if (req->length > (4 * CI13XXX_PAGE_SIZE)) { 21710a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko req->length = (4 * CI13XXX_PAGE_SIZE); 2172aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -EMSGSIZE; 2173aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("request length truncated"); 2174aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2175aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2176aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_queue(_usb_addr(mEp), req, retval); 2177aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2178aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* push request */ 2179aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -EINPROGRESS; 2180aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = 0; 2181ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_add_tail(&mReq->queue, &mEp->qh.queue); 2182aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2183ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (list_is_singular(&mEp->qh.queue)) 2184d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko retval = _hardware_enqueue(mEp, mReq); 2185d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko 2186d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko if (retval == -EALREADY) { 2187aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "QUEUE", retval); 2188aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 2189aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2190aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2191aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 2192aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2193aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2194aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2195aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2196aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2197aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint 2198aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2199aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_dequeue() at "usb_gadget.h" for details 2200aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2201aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_dequeue(struct usb_ep *ep, struct usb_request *req) 2202aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2203aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2204aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2205aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2206aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2207aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 2208aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2209aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL || mEp->desc == NULL || 2210ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_empty(&mReq->queue) || list_empty(&mEp->qh.queue)) 2211aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2212aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2213aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2214aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2215aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "DEQUEUE", 0); 2216aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2217aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.status == -EALREADY) 2218aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _hardware_dequeue(mEp, mReq); 2219aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2220aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* pop request */ 2221aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mReq->queue); 2222aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->status = -ECONNRESET; 2223aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 22247c25a82684364da44643cbe3bdbd0f8835293767Artem Leonenko if (mReq->req.complete != NULL) { 2225aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 2226aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.complete(&mEp->ep, &mReq->req); 2227aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 2228aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2229aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2230aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2231aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 2232aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2233aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2234aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2235aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_set_halt: sets the endpoint halt feature 2236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_set_halt() at "usb_gadget.h" for details 2238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_set_halt(struct usb_ep *ep, int value) 2240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2241aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int direction, retval = 0; 2243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %i", ep, value); 2246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || mEp->desc == NULL) 2248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2250aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2251aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2252aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifndef STALL_IN 2253aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ 2254aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && 2255ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti !list_empty(&mEp->qh.queue)) { 2256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2257aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 2258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2261aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo direction = mEp->dir; 2262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 2263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "HALT", value); 2264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); 2265aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!value) 2267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->wedge = 0; 2268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir = (mEp->dir == TX) ? RX : TX; 2271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (mEp->dir != direction); 2273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2274aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2276aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2277aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2278aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2279aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_set_wedge: sets the halt feature and ignores clear requests 2280aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2281aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_set_wedge() at "usb_gadget.h" for details 2282aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2283aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_set_wedge(struct usb_ep *ep) 2284aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2285aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2286aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2287aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2288aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2289aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2290aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || mEp->desc == NULL) 2291aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2292aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2293aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2294aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2295aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "WEDGE", 0); 2296aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->wedge = 1; 2297aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2298aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2299aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2300aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return usb_ep_set_halt(ep); 2301aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2302aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2303aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2304aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_fifo_flush: flushes contents of a fifo 2305aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2306aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_fifo_flush() at "usb_gadget.h" for details 2307aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2308aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void ep_fifo_flush(struct usb_ep *ep) 2309aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2310aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2311aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2312aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2313aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2314aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2315aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) { 2316aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("%02X: -EINVAL", _usb_addr(mEp)); 2317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2318aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2319aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2320aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2321aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2322aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "FFLUSH", 0); 2323aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(mEp->num, mEp->dir); 2324aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2325aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2326aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2327aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2328aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2329aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Endpoint-specific part of the API to the USB controller hardware 2330aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "usb_gadget.h" for details 2331aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2332aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic const struct usb_ep_ops usb_ep_ops = { 2333aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .enable = ep_enable, 2334aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .disable = ep_disable, 2335aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .alloc_request = ep_alloc_request, 2336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .free_request = ep_free_request, 2337aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .queue = ep_queue, 2338aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .dequeue = ep_dequeue, 2339aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .set_halt = ep_set_halt, 2340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .set_wedge = ep_set_wedge, 2341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .fifo_flush = ep_fifo_flush, 2342aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo}; 2343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 2345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * GADGET block 2346aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 2347f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) 2348f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti{ 2349f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); 2350f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti unsigned long flags; 2351f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti int gadget_ready = 0; 2352f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2353f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) 2354f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return -EOPNOTSUPP; 2355f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2356f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2357f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->vbus_active = is_active; 2358f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->driver) 2359f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti gadget_ready = 1; 2360f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2361f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2362f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (gadget_ready) { 2363f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (is_active) { 2364c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_get_sync(&_gadget->dev); 2365f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_reset(udc); 2366ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti hw_device_state(udc->ep0out.qh.dma); 2367f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } else { 2368f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_state(0); 2369f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 2370f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 2371f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_STOPPED_EVENT); 2372f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti _gadget_stop_activity(&udc->gadget); 2373c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&_gadget->dev); 2374f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2375f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2376f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2377f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return 0; 2378f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti} 2379f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Device operations part of the API to the USB controller hardware, 2382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * which don't involve endpoints (or i/o) 2383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "usb_gadget.h" for details 2384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2385f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic const struct usb_gadget_ops usb_gadget_ops = { 2386f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti .vbus_session = ci13xxx_vbus_session, 2387f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti}; 2388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2390b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * usb_gadget_probe_driver: register a gadget driver 2391b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * @driver: the driver being registered 2392b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * @bind: the driver's bind callback 2393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2394b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details. 2395b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * Interrupts are enabled here. 2396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2397b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-Königint usb_gadget_probe_driver(struct usb_gadget_driver *driver, 2398b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König int (*bind)(struct usb_gadget *)) 2399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2401ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned long flags; 2402ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int i, j; 2403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = -ENOMEM; 2404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", driver); 2406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (driver == NULL || 2408b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König bind == NULL || 2409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->setup == NULL || 2410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->disconnect == NULL || 2411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->suspend == NULL || 2412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->resume == NULL) 2413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (udc == NULL) 2415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENODEV; 2416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (udc->driver != NULL) 2417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 2418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* alloc resources */ 2420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, 2421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo sizeof(struct ci13xxx_qh), 24220a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko 64, CI13XXX_PAGE_SIZE); 2423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->qh_pool == NULL) 2424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, 2427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo sizeof(struct ci13xxx_td), 24280a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko 64, CI13XXX_PAGE_SIZE); 2429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->td_pool == NULL) { 2430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->qh_pool); 2431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = NULL; 2432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo info("hw_ep_max = %d", hw_ep_max); 2438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = NULL; 2440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 2442ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (i = 0; i < hw_ep_max/2; i++) { 2443ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (j = RX; j <= TX; j++) { 2444ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int k = i + j * hw_ep_max/2; 2445ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; 2446aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2447ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, 2448ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti (j == TX) ? "in" : "out"); 2449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2450ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->lock = udc->lock; 2451ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->device = &udc->gadget.dev; 2452ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->td_pool = udc->td_pool; 2453aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2454ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.name = mEp->name; 2455ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.ops = &usb_ep_ops; 2456ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; 2457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2458ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti INIT_LIST_HEAD(&mEp->qh.queue); 24590a91efa2f951d790969dec96fb675ca7869eca83Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2460ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, 2461ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti &mEp->qh.dma); 24620a91efa2f951d790969dec96fb675ca7869eca83Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2463ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->qh.ptr == NULL) 2464aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -ENOMEM; 2465aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else 2466ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); 2467ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 2468ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti /* skip ep0 out and in endpoints */ 2469ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (i == 0) 2470ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti continue; 2471ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 2472aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); 2473ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti } 2474aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2475aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 2476aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2477aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2478ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->gadget.ep0 = &udc->ep0in.ep; 2479aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* bind gadget */ 2480aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->driver.bus = NULL; 2481aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = &driver->driver; 2482aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2483aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2484b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König retval = bind(&udc->gadget); /* MAY SLEEP */ 2485aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2486aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2487aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) { 2488aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = NULL; 2489aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2490aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2491aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 249249d3df53a80deed2251b91f50ae9e1c5caf7ded7Pavankumar Kondeti udc->driver = driver; 2493c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_get_sync(&udc->gadget.dev); 2494f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { 2495f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->vbus_active) { 2496f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) 2497f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_reset(udc); 2498f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } else { 2499c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&udc->gadget.dev); 2500f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto done; 2501f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2502f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2503f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2504ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = hw_device_state(udc->ep0out.qh.dma); 2505c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti if (retval) 2506c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&udc->gadget.dev); 2507aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2508aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 2509aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2510aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2511aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2512b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-KönigEXPORT_SYMBOL(usb_gadget_probe_driver); 2513aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2514aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2515aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * usb_gadget_unregister_driver: unregister a gadget driver 2516aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2517aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details 2518aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2519aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopoint usb_gadget_unregister_driver(struct usb_gadget_driver *driver) 2520aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2521aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2522ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned long i, flags; 2523aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2524aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", driver); 2525aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2526aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (driver == NULL || 2527aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->unbind == NULL || 2528aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->setup == NULL || 2529aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->disconnect == NULL || 2530aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->suspend == NULL || 2531aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->resume == NULL || 2532aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver != udc->driver) 2533aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2534aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2535aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2536aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2537f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || 2538f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->vbus_active) { 2539f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_state(0); 2540f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 2541f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 2542f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_STOPPED_EVENT); 2543aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _gadget_stop_activity(&udc->gadget); 2544c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put(&udc->gadget.dev); 2545f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2546aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2547f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* unbind gadget */ 2548f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2549f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti driver->unbind(&udc->gadget); /* MAY SLEEP */ 2550f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2552f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.dev.driver = NULL; 2553aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2554aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* free resources */ 2555aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) { 2556aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; 2557aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2558ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (!list_empty(&mEp->ep.ep_list)) 2559aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mEp->ep.ep_list); 2560aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2561ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->qh.ptr != NULL) 2562ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); 2563aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2564aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2565ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->gadget.ep0 = NULL; 2566aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->driver = NULL; 2567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2568aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2569aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2570aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->td_pool != NULL) { 2571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->td_pool); 2572aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->td_pool = NULL; 2573aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->qh_pool != NULL) { 2575aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->qh_pool); 2576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = NULL; 2577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2579aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 2580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2581aa69a8093ff985873cb44fe1157bd6db29a20fe4David LopoEXPORT_SYMBOL(usb_gadget_unregister_driver); 2582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 2584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * BUS block 2585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 2586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_irq: global interrupt handler 2588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns IRQ_HANDLED if the IRQ has been handled 2590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * It locks access to registers 2591aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic irqreturn_t udc_irq(void) 2593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2594aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2595aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo irqreturn_t retval; 2596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 intr; 2597aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace(); 2599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 2601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("ENODEV"); 2602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return IRQ_HANDLED; 2603aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2604aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 2606f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2607f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { 2608f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (hw_cread(CAP_USBMODE, USBMODE_CM) != 2609f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti USBMODE_CM_DEVICE) { 2610f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock(udc->lock); 2611f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return IRQ_NONE; 2612f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2613f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2614aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr = hw_test_and_clear_intr_active(); 2615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (intr) { 2616aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; 2617aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.idx &= ISR_MASK; 2618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.cnt++; 2619aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2620aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* order defines priority - do NOT change it */ 2621aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_URI & intr) { 2622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uri++; 2623aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_reset_handler(udc); 2624aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2625aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_PCI & intr) { 2626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.pci++; 2627aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.speed = hw_port_is_high_speed() ? 2628aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo USB_SPEED_HIGH : USB_SPEED_FULL; 2629aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2630aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UEI & intr) 2631aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uei++; 2632aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UI & intr) { 2633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.ui++; 2634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_tr_complete_handler(udc); 2635aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2636aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_SLI & intr) 2637aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.sli++; 2638aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = IRQ_HANDLED; 2639aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 2640aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.none++; 2641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = IRQ_NONE; 2642aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2643aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 2644aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2645aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2646aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2647aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2648aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2649aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_release: driver release function 2650aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 2651aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2652aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Currently does nothing 2653aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2654aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void udc_release(struct device *dev) 2655aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2656aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", dev); 2657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2658aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 2659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2661aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2663aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_probe: parent probe must call this to initialize UDC 2664aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: parent device 2665aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @regs: registers base address 2666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @name: driver name 2667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 2669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * No interrupts active, the IRQ has not been requested yet 2670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask 2671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2672f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, 2673f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti void __iomem *regs) 2674aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2675aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc; 2676aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 2677aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2678aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p, %p", dev, regs, name); 2679aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2680f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (dev == NULL || regs == NULL || driver == NULL || 2681f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti driver->name == NULL) 2682aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2683aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2684aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); 2685aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) 2686aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2688aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->lock = &udc_lock; 2689f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->regs = regs; 2690f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver = driver; 2691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2692f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.ops = &usb_gadget_ops; 2693aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.speed = USB_SPEED_UNKNOWN; 2694aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.is_dualspeed = 1; 2695aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.is_otg = 0; 2696f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.name = driver->name; 2697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2698aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo INIT_LIST_HEAD(&udc->gadget.ep_list); 2699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.ep0 = NULL; 2700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 27015df5852446196c9713e897ab5f9b8a168d971a00Kay Sievers dev_set_name(&udc->gadget.dev, "gadget"); 2702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.dma_mask = dev->dma_mask; 270361948ee4d525174cceee2135a38a482124fcc02cPavankumar Kondeti udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; 2704aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.parent = dev; 2705aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.release = udc_release; 2706aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2707f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = hw_device_init(regs); 2708f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval < 0) 2709f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto free_udc; 2710f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2711f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->transceiver = otg_get_transceiver(); 2712f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2713f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { 2714f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver == NULL) { 2715f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = -ENODEV; 2716f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto free_udc; 2717f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2718f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2719f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2720f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { 2721f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = hw_device_reset(udc); 2722f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2723f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto put_transceiver; 2724f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2725f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2726aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_register(&udc->gadget.dev); 2727f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) { 2728f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti put_device(&udc->gadget.dev); 2729f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto put_transceiver; 2730f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2731aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = dbg_create_files(&udc->gadget.dev); 2734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2735f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2736f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto unreg_device; 2737f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2738f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) { 2739f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = otg_set_peripheral(udc->transceiver, &udc->gadget); 2740f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2741f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto remove_dbg; 2742aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2743c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_no_callbacks(&udc->gadget.dev); 2744c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_enable(&udc->gadget.dev); 2745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = udc; 2747aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error = %i", retval); 2750f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiremove_dbg: 2751f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2752f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti dbg_remove_files(&udc->gadget.dev); 2753f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#endif 2754f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiunreg_device: 2755f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti device_unregister(&udc->gadget.dev); 2756f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiput_transceiver: 2757f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) 2758f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_put_transceiver(udc->transceiver); 2759f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetifree_udc: 2760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(udc); 2761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = NULL; 2762aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2764aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2766aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_remove: parent remove must call this to remove UDC 2767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * No interrupts active, the IRQ has been released 2769aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2770aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void udc_remove(void) 2771aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2772aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2773aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2774aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 2775aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2776aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2777aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2778aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2779f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) { 2780f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_set_peripheral(udc->transceiver, &udc->gadget); 2781f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_put_transceiver(udc->transceiver); 2782f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2783aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2784aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_remove_files(&udc->gadget.dev); 2785aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2786aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_unregister(&udc->gadget.dev); 2787aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2788aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(udc); 2789aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = NULL; 2790aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2791