ci13xxx_udc.c revision 7177aed44f515d949f587170e0e177ce17e74793
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 *****************************************************************************/ 74954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik 75954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik#define DMA_ADDR_INVALID (~(dma_addr_t)0) 76954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik 77aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* ctrl register bank access */ 78aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEFINE_SPINLOCK(udc_lock); 79aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 80aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* control endpoint description */ 81aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic const struct usb_endpoint_descriptor 82ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetictrl_endpt_out_desc = { 83aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bLength = USB_DT_ENDPOINT_SIZE, 84aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bDescriptorType = USB_DT_ENDPOINT, 85aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 86ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bEndpointAddress = USB_DIR_OUT, 87ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 88ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), 89ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti}; 90ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 91ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic const struct usb_endpoint_descriptor 92ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetictrl_endpt_in_desc = { 93ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bLength = USB_DT_ENDPOINT_SIZE, 94ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bDescriptorType = USB_DT_ENDPOINT, 95ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 96ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti .bEndpointAddress = USB_DIR_IN, 97aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 98aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), 99aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo}; 100aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 101aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* UDC descriptor */ 102aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct ci13xxx *_udc; 103aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 104aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* Interrupt statistics */ 105aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ISR_MASK 0x1F 106aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct { 107aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 test; 108aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 ui; 109aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 uei; 110aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 pci; 111aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 uri; 112aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 sli; 113aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 none; 114aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct { 115aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 cnt; 116aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 buf[ISR_MASK+1]; 117aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 idx; 118aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } hndl; 119aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} isr_statistics; 120aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 121aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 122aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ffs_nr: find first (least significant) bit set 123aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @x: the word to search 124aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 125aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns bit number (instead of position) 126aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 127aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ffs_nr(u32 x) 128aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 129aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = ffs(x); 130aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 131aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n ? n-1 : 32; 132aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 133aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 134aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 135aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * HW block 136aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 137aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* register bank descriptor */ 138aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct { 139aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned lpm; /* is LPM? */ 140aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo void __iomem *abs; /* bus map offset */ 141aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo void __iomem *cap; /* bus map offset + CAP offset + CAP data */ 142aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo size_t size; /* bank size */ 143aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} hw_bank; 144aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 145f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti/* MSM specific */ 146f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#define ABS_AHBBURST (0x0090UL) 147f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#define ABS_AHBMODE (0x0098UL) 148aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* UDC register map */ 149aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_CAPLENGTH (0x100UL) 150aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_HCCPARAMS (0x108UL) 151aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_DCCPARAMS (0x124UL) 152aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) 153aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* offset to CAPLENTGH (addr + data) */ 154aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBCMD (0x000UL) 155aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBSTS (0x004UL) 156aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBINTR (0x008UL) 157aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_DEVICEADDR (0x014UL) 158aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTLISTADDR (0x018UL) 159aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_PORTSC (0x044UL) 160f23e649bb605523b960434c5e18c8e9ad3f0b5bdDavid Lopo#define CAP_DEVLC (0x084UL) 161aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) 162aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) 163aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) 164aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) 165aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) 166aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) 167aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) 168aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) 169aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 170aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/* maximum number of enpoints: valid only after hw_device_reset() */ 171aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic unsigned hw_ep_max; 172aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 173aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 174aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_bit: calculates the bit number 175aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 176aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 177aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 178aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns bit number 179aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 180aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic inline int hw_ep_bit(int num, int dir) 181aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 182aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return num + (dir ? 16 : 0); 183aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 184aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 185dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Buddestatic int ep_to_bit(int n) 186dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde{ 187dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde int fill = 16 - hw_ep_max / 2; 188dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde 189dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde if (n >= hw_ep_max / 2) 190dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde n += fill; 191dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde 192dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde return n; 193dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde} 194dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde 195aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 196aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_aread: reads from register bitfield 197aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to bus map 198aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 199aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 200aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 201aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 202aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_aread(u32 addr, u32 mask) 203aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 204aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ioread32(addr + hw_bank.abs) & mask; 205aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 206aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 207aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 208aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_awrite: writes to register bitfield 209aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to bus map 210aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 211aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 212aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 213aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void hw_awrite(u32 addr, u32 mask, u32 data) 214aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 215aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(hw_aread(addr, ~mask) | (data & mask), 216aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr + hw_bank.abs); 217aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 218aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 219aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 220aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_cread: reads from register bitfield 221aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 222aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 223aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 224aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 225aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 226aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_cread(u32 addr, u32 mask) 227aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 228aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ioread32(addr + hw_bank.cap) & mask; 229aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 230aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 231aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 232aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_cwrite: writes to register bitfield 233aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 234aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 235aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void hw_cwrite(u32 addr, u32 mask, u32 data) 238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(hw_cread(addr, ~mask) | (data & mask), 240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr + hw_bank.cap); 241aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ctest_and_clear: tests & clears register bitfield 245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 250aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_ctest_and_clear(u32 addr, u32 mask) 251aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 252aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_cread(addr, mask); 253aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 254aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32(reg, addr + hw_bank.cap); 255aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return reg; 256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 257aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ctest_and_write: tests & writes register bitfield 260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: address relative to CAP offset plus content 261aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mask: bitfield mask 262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: new data 263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register bitfield data 265aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) 267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_cread(addr, ~0); 269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); 271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return (reg & mask) >> ffs_nr(mask); 272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 274f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int hw_device_init(void __iomem *base) 275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 276aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg; 277aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 278aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* bank is a module variable */ 279aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.abs = base; 280aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 281aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap = hw_bank.abs; 282aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap += ABS_CAPLENGTH; 283aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.cap += ioread8(hw_bank.cap); 284aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 285aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); 286aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.lpm = reg; 287aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size = hw_bank.cap - hw_bank.abs; 288aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size += CAP_LAST; 289aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_bank.size /= sizeof(u32); 290aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 291f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); 292ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 293f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 294ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) 295ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti return -ENODEV; 296f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 297f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* setup lock mode ? */ 298f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 299f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* ENDPTSETUPSTAT is '0' by default */ 300f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 301f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 302f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 303f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return 0; 304f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti} 305f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti/** 306f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * hw_device_reset: resets chip (execute without interruption) 307f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * @base: register base address 308f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * 309f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti * This function returns an error code 310f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti */ 311f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int hw_device_reset(struct ci13xxx *udc) 312f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti{ 313aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* should flush & stop before reset */ 314aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); 315aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); 316aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); 318aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_USBCMD, USBCMD_RST)) 319aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udelay(10); /* not RTOS friendly */ 320aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 321f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 322f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 323f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 324f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_RESET_EVENT); 325f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 3268c2387a71ccbae699cfdc315382afc9a89b01b2dPavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING) 327f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS); 328f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 329aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* USBMODE should be configured step by step */ 330aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 331aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); 332aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ 333aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 334aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { 335aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo pr_err("cannot enter in device mode"); 336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo pr_err("lpm = %i", hw_bank.lpm); 337aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENODEV; 338aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 339aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 342aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_device_state: enables/disables interrupts & starts/stops device (execute 345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 346aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dma: 0 => disable, !0 => enable and set dma engine 347aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 348aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 349aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 350aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_device_state(u32 dma) 351aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 352aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dma) { 353aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); 354aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* interrupt, error, port change, reset, sleep/suspend */ 355aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, ~0, 356aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); 357aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); 358aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 359aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); 360aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, ~0, 0); 361aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 362aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 363aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 364aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 365aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 366aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_flush: flush endpoint fifo (execute without interruption) 367aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 368aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 369aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 370aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 371aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 372aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_flush(int num, int dir) 373aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 374aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = hw_ep_bit(num, dir); 375aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 376aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 377aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* flush any pending transfer */ 378aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); 379aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) 380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo cpu_relax(); 381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); 382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 385aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 386aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 387aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_disable: disables endpoint (execute without interruption) 388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 390aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 391aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 392aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_disable(int num, int dir) 394aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 395aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(num, dir); 396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), 397aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); 398aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 401aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 402aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_enable: enables endpoint (execute without interruption) 403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @type: endpoint type 406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 408aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_enable(int num, int dir, int type) 410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask, data; 412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dir) { 414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask = ENDPTCTRL_TXT; /* type */ 415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data = type << ffs_nr(mask); 416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXS; /* unstall */ 418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXR; /* reset data toggle */ 419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_TXR; 420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_TXE; /* enable */ 421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_TXE; 422aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask = ENDPTCTRL_RXT; /* type */ 424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data = type << ffs_nr(mask); 425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXS; /* unstall */ 427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXR; /* reset data toggle */ 428aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_RXR; 429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mask |= ENDPTCTRL_RXE; /* enable */ 430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo data |= ENDPTCTRL_RXE; 431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); 433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_get_halt: return endpoint halt status 438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns 1 if endpoint halted 442aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 443aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_get_halt(int num, int dir) 444aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 445aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; 446aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 447aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; 448aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 450aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 451aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_setup_status: test & clear setup status (execute without 452aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 453dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde * @n: endpoint number 454aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 455aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns setup status 456aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_setup_status(int n) 458aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 459dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde n = ep_to_bit(n); 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 if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) 476aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 477aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 478aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); 479aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 480aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTPRIME, BIT(n))) 481aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo cpu_relax(); 482aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) 483aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 484aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 485aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* status shoult be tested according with manual but it doesn't work */ 486aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 487aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 488aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 489aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 490aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute 491aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 492aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @num: endpoint number 493aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dir: endpoint direction 494aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @value: true => stall, false => unstall 495aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 496aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 497aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 498aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_ep_set_halt(int num, int dir, int value) 499aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 500aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (value != 0 && value != 1) 501aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 502aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 503aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 504aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); 505aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; 506aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; 507aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 508aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* data toggle - reserved for EP0 but it's in ESS */ 509aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); 510aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 511aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (value != hw_ep_get_halt(num, dir)); 512aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 513aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 514aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 515aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 516aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 517aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_intr_clear: disables interrupt & clears interrupt status (execute without 518aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 519aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: interrupt bit 520aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 521aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 522aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 523aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_intr_clear(int n) 524aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 525aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (n >= REG_BITS) 526aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 527aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 528aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, BIT(n), 0); 529aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); 530aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 531aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 532aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 533aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 534aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_intr_force: enables interrupt & forces interrupt status (execute without 535aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 536aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @n: interrupt bit 537aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 538aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 539aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 540aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_intr_force(int n) 541aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 542aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (n >= REG_BITS) 543aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 544aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 545aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); 546aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); 547aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); 548aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); 549aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 550aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 552aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 553aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_is_port_high_speed: test if port is high speed 554aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 555aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns true if high speed port 556aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 557aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_port_is_high_speed(void) 558aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 559aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : 560aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cread(CAP_PORTSC, PORTSC_HSP); 561aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 562aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 563aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 564aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_port_test_get: reads port test mode value 565aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 566aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns port test mode value 567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 568aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u8 hw_port_test_get(void) 569aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 570aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); 571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 572aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 573aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_port_test_set: writes port test mode (execute without interruption) 575aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mode: new value 576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 579aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_port_test_set(u8 mode) 580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 581aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const u8 TEST_MODE_MAX = 7; 582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mode > TEST_MODE_MAX) 584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); 587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 591aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_read_intr_enable: returns interrupt enable register 592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register data 594aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 595aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_read_intr_enable(void) 596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 597aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_USBINTR, ~0); 598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_read_intr_status: returns interrupt status register 602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 603aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns register data 604aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_read_intr_status(void) 606aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 607aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_cread(CAP_USBSTS, ~0); 608aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 609aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 610aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 611aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_register_read: reads all device registers (execute without interruption) 612aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @buf: destination buffer 613aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @size: buffer size 614aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns number of registers read 616aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 617aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic size_t hw_register_read(u32 *buf, size_t size) 618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 619aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 620aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 621aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (size > hw_bank.size) 622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo size = hw_bank.size; 623aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 624aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < size; i++) 625aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo buf[i] = hw_aread(i * sizeof(u32), ~0); 626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 627aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return size; 628aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 629aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 630aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 631aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_register_write: writes to register 632aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @addr: register address 633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @data: register value 634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 635aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 636aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 637aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_register_write(u16 addr, u32 data) 638aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 639aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* align */ 640aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr /= sizeof(u32); 641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 642aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (addr >= hw_bank.size) 643aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 644aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 645aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* align */ 646aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo addr *= sizeof(u32); 647aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 648aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_awrite(addr, ~0, data); 649aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 650aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 651aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 652aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 653aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_complete: test & clear complete status (execute without 654aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 655dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde * @n: endpoint number 656aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns complete status 658aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_complete(int n) 660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 661dd39c358dff41394f20b623fc68be857b6d702adMarc Kleine-Budde n = ep_to_bit(n); 662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); 663aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 664aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 665aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_intr_active: test & clear active interrupts (execute 667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * without interruption) 668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns active interrutps 670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic u32 hw_test_and_clear_intr_active(void) 672aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 673aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 reg = hw_read_intr_status() & hw_read_intr_enable(); 674aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 675aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_USBSTS, ~0, reg); 676aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return reg; 677aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 678aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 679aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 680aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_clear_setup_guard: test & clear setup guard (execute without 681aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 682aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 683aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns guard value 684aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 685aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_clear_setup_guard(void) 686aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); 688aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 689aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 690aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_test_and_set_setup_guard: test & set setup guard (execute without 692aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 693aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 694aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns guard value 695aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 696aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_test_and_set_setup_guard(void) 697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 698aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); 699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 701aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_usb_set_address: configures USB address (execute without interruption) 703aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @value: new USB address 704aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 705aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 706aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 707aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_usb_set_address(u8 value) 708aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 709aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* advance */ 710aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, 711aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); 712aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 713aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 714aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 715aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 716aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * hw_usb_reset: restart device after a bus reset (execute without 717aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * interruption) 718aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 719aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 720aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 721aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int hw_usb_reset(void) 722aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 723aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_usb_set_address(0); 724aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 725aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* ESS flushes only at end?!? */ 726aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ 727aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 728aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* clear setup token semaphores */ 729aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ 730aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 731aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* clear complete status */ 732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ 733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* wait until all bits cleared */ 735aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo while (hw_cread(CAP_ENDPTPRIME, ~0)) 736aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udelay(10); /* not RTOS friendly */ 737aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 738aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* reset all endpoints ? */ 739aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 740aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* reset internal status and wait for further instructions 741aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo no need to verify the port reset status (ESS does it) */ 742aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 743aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 744aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 747aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * DBG block 748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 750aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_device: prints information about device capabilities and status 751aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 752aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 753aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 754aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_device(struct device *dev, struct device_attribute *attr, 755aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 756aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 757aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 758aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_gadget *gadget = &udc->gadget; 759aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int n = 0; 760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 762aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 764aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 766aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", 768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget->speed); 769d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", 770d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz gadget->max_speed); 771d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz /* TODO: Scheduled for removal in 3.8. */ 772aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", 773d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz gadget_is_dualspeed(gadget)); 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", 8167177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz driver->max_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, 8780f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior "%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) 8860f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 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); 10460f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", 1047aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.ui); 10480f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", 1049aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uei); 10500f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", 1051aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.pci); 10520f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", 1053aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uri); 10540f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 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 */ 1235c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior#define DUMP_ENTRIES 512 1236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_registers(struct device *dev, 1237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, char *buf) 1238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1241c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior u32 *dump; 1242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i, k, n = 0; 1243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1250c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); 1251c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior if (!dump) { 1252c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior dev_err(dev, "%s: out of memory\n", __func__); 1253c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior return 0; 1254c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior } 1255c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior 1256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1257c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior k = hw_register_read(dump, DUMP_ENTRIES); 1258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < k; i++) { 1261aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "reg[0x%04X] = 0x%08X\n", 1263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo i * (unsigned)sizeof(u32), dump[i]); 1264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1265c2b65f8422a3f51435c9f60f9752a6ed82d47e13Sebastian Andrzej Siewior kfree(dump); 1266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * store_registers: writes value to register address 1272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1274aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t store_registers(struct device *dev, 1276aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct device_attribute *attr, 1277aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const char *buf, size_t count) 1278aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1279aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1280aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long addr, data, flags; 1281aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1282aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p, %d\n", __func__, buf, count); 1283aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1284aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1285aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1286aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1287aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1288aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (sscanf(buf, "%li %li", &addr, &data) != 2) { 1289aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "<addr> <data>: write data to register address"); 1290aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1291aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1292aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1293aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1294aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (hw_register_write(addr, data)) 1295aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "invalid address range\n"); 1296aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1297aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1298aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1299aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return count; 1300aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1301aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, 1302aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo show_registers, store_registers); 1303aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1304aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1305aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * show_requests: DMA contents of all requests currently queued (all endpts) 1306aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1307aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "device.h" for details 1308aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1309aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic ssize_t show_requests(struct device *dev, struct device_attribute *attr, 1310aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo char *buf) 1311aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1312aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); 1313aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 1314aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct list_head *ptr = NULL; 1315aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *req = NULL; 1316ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); 1317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1318aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_trace("[%s] %p\n", __func__, buf); 1319aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (attr == NULL || buf == NULL) { 1320aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dev_err(dev, "[%s] EINVAL\n", __func__); 1321aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1322aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1323aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1324aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 1325aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) 1326ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) 1327ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti { 1328ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti req = list_entry(ptr, struct ci13xxx_req, queue); 1329aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1330ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti n += scnprintf(buf + n, PAGE_SIZE - n, 1331ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti "EP=%02i: TD=%08X %s\n", 1332ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti i % hw_ep_max/2, (u32)req->dma, 1333ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti ((i < hw_ep_max/2) ? "RX" : "TX")); 1334ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1335ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (j = 0; j < qSize; j++) 1336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo n += scnprintf(buf + n, PAGE_SIZE - n, 1337ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti " %04X: %08X\n", j, 1338ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti *((u32 *)req->ptr + j)); 1339ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti } 1340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 1341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1342aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return n; 1343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); 1345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1346aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1347aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_create_files: initializes the attribute interface 1348aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 1349aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1350aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1351aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1352aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__maybe_unused static int dbg_create_files(struct device *dev) 1353aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1354aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 1355aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1356aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 1357aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1358aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_device); 1359aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1360aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1361aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_driver); 1362aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1363aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_device; 1364aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_events); 1365aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1366aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_driver; 1367aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_inters); 1368aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1369aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_events; 1370aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_port_test); 1371aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1372aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_inters; 1373aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_qheads); 1374aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1375aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_port_test; 1376aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_registers); 1377aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1378aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_qheads; 1379aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_create_file(dev, &dev_attr_requests); 1380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto rm_registers; 1382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_registers: 1385aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_registers); 1386aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_qheads: 1387aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_qheads); 1388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_port_test: 1389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_port_test); 1390aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_inters: 1391aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_inters); 1392aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_events: 1393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_events); 1394aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_driver: 1395aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_driver); 1396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo rm_device: 1397aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_device); 1398aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1401aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1402aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * dbg_remove_files: destroys the attribute interface 1404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 1405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1408aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__maybe_unused static int dbg_remove_files(struct device *dev) 1409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 1411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_requests); 1413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_registers); 1414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_qheads); 1415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_port_test); 1416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_inters); 1417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_events); 1418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_driver); 1419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_remove_file(dev, &dev_attr_device); 1420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1422aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 1424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * UTIL block 1425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 1426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _usb_addr: calculates endpoint address from direction & number 1428aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @ep: endpoint 1429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic inline u8 _usb_addr(struct ci13xxx_ep *ep) 1431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; 1433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _hardware_queue: configures a request at hardware level 1437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1442aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) 1443aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1444aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 14450e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti int ret = 0; 14460e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti unsigned length = mReq->req.length; 1447aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1448aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, mReq); 1449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1450aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* don't queue twice */ 1451aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.status == -EALREADY) 1452aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EALREADY; 1453aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1454aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -EALREADY; 1455954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik if (length && mReq->req.dma == DMA_ADDR_INVALID) { 1456aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.dma = \ 1457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_map_single(mEp->device, mReq->req.buf, 14580e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti length, mEp->dir ? DMA_TO_DEVICE : 14590e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti DMA_FROM_DEVICE); 1460aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.dma == 0) 1461aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 1462aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1463aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->map = 1; 1464aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1465aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 14660e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { 14670e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, 14680e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti &mReq->zdma); 14690e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->zptr == NULL) { 14700e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->map) { 14710e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti dma_unmap_single(mEp->device, mReq->req.dma, 14720e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti length, mEp->dir ? DMA_TO_DEVICE : 14730e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti DMA_FROM_DEVICE); 1474954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik mReq->req.dma = DMA_ADDR_INVALID; 14750e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->map = 0; 14760e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 14770e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti return -ENOMEM; 14780e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 14790e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti memset(mReq->zptr, 0, sizeof(*mReq->zptr)); 14800e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->zptr->next = TD_TERMINATE; 14810e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->zptr->token = TD_STATUS_ACTIVE; 14820e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (!mReq->req.no_interrupt) 14830e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->zptr->token |= TD_IOC; 14840e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 1485aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* 1486aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * TD configuration 1487aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * TODO - handle requests which spawns into several TDs 1488aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1489aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo memset(mReq->ptr, 0, sizeof(*mReq->ptr)); 14900e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); 1491aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token &= TD_TOTAL_BYTES; 1492aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->token |= TD_STATUS_ACTIVE; 14930e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->zptr) { 14940e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->ptr->next = mReq->zdma; 14950e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } else { 14960e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->ptr->next = TD_TERMINATE; 14970e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (!mReq->req.no_interrupt) 14980e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->ptr->token |= TD_IOC; 14990e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 1500aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->page[0] = mReq->req.dma; 1501aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 1; i < 5; i++) 1502aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr->page[i] = 15030a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; 1504aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 15050e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (!list_empty(&mEp->qh.queue)) { 15060e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti struct ci13xxx_req *mReqPrev; 15070e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti int n = hw_ep_bit(mEp->num, mEp->dir); 15080e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti int tmp_stat; 15090e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti 15100e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReqPrev = list_entry(mEp->qh.queue.prev, 15110e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti struct ci13xxx_req, queue); 15120e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReqPrev->zptr) 15130e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; 15140e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti else 15150e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; 15160e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti wmb(); 15170e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (hw_cread(CAP_ENDPTPRIME, BIT(n))) 15180e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti goto done; 15190e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti do { 15200e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); 15210e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n)); 15220e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW)); 15230e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0); 15240e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (tmp_stat) 15250e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti goto done; 15260e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 15270e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti 15280e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti /* QH configuration */ 1529ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ 1530ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ 15310e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mEp->qh.ptr->cap |= QH_ZLT; 1532aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1533aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo wmb(); /* synchronize before ep prime */ 1534aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 15350e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti ret = hw_ep_prime(mEp->num, mEp->dir, 1536aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->type == USB_ENDPOINT_XFER_CONTROL); 15370e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondetidone: 15380e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti return ret; 1539aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1540aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1541aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1542aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _hardware_dequeue: handles a request at hardware level 1543aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1544aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1545aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1546aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1547aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1548aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) 1549aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1550aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, mReq); 1551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1552aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->req.status != -EALREADY) 1553aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1554aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 15550e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) 15560e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti return -EBUSY; 15570e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti 15580e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->zptr) { 15590e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) 15600e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti return -EBUSY; 15610e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); 15620e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->zptr = NULL; 15630e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 1564aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1565aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = 0; 1566aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->map) { 1568aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, 1569aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1570954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik mReq->req.dma = DMA_ADDR_INVALID; 1571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->map = 0; 1572aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1573aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = mReq->ptr->token & TD_STATUS; 15750e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if ((TD_STATUS_HALTED & mReq->req.status) != 0) 1576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) 1578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1579aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) 1580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -1; 1581aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; 1583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); 1584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->req.length - mReq->req.actual; 1585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; 1586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return mReq->req.actual; 1588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1591aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _ep_nuke: dequeues all endpoint requests 1592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1594aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1595aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must hold lock 1596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1597aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _ep_nuke(struct ci13xxx_ep *mEp) 1598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", mEp); 1602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1603aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp == NULL) 1604aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1606aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(mEp->num, mEp->dir); 1607aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1608ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti while (!list_empty(&mEp->qh.queue)) { 1609aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1610aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* pop oldest request */ 1611aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = \ 1612ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti list_entry(mEp->qh.queue.next, 1613aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req, queue); 1614aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mReq->queue); 1615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -ESHUTDOWN; 1616aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 16177c25a82684364da44643cbe3bdbd0f8835293767Artem Leonenko if (mReq->req.complete != NULL) { 1618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1619aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.complete(&mEp->ep, &mReq->req); 1620aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1621aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1623aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1624aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1625aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1627aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts 1628aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @gadget: gadget 1629aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1630aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1631aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1632aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int _gadget_stop_activity(struct usb_gadget *gadget) 1633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ep *ep; 1635aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); 1636e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti unsigned long flags; 1637aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1638aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", gadget); 1639aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1640aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (gadget == NULL) 1641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1642aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1643e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 1644e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->gadget.speed = USB_SPEED_UNKNOWN; 1645e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->remote_wakeup = 0; 1646e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->suspended = 0; 1647e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 1648e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti 1649aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* flush all endpoints */ 1650aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget_for_each_ep(ep, gadget) { 1651aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_fifo_flush(ep); 1652aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1653ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_fifo_flush(&udc->ep0out.ep); 1654ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_fifo_flush(&udc->ep0in.ep); 1655aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1656aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->driver->disconnect(gadget); 1657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1658aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* make sure to disable all endpoints */ 1659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gadget_for_each_ep(ep, gadget) { 1660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_disable(ep); 1661aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1663ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (udc->status != NULL) { 1664ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti usb_ep_free_request(&udc->ep0in.ep, udc->status); 1665ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->status = NULL; 1666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 1672aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ISR block 1673aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 1674aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1675aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_reset_handler: USB reset interrupt handler 1676aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @udc: UDC device 1677aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1678aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function resets USB engine after a bus reset occurred 1679aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1680aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_reset_handler(struct ci13xxx *udc) 1681aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(udc->lock) 1682aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(udc->lock) 1683aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1684aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval; 1685aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1686aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", udc); 1687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1688aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 1689aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1690aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1692aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1693aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(0xFF, "BUS RST", 0); 1694aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1695f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock(udc->lock); 1696aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = _gadget_stop_activity(&udc->gadget); 1697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1698aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = hw_usb_reset(); 1701aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 1703aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1704ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); 1705ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala if (udc->status == NULL) 1706ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala retval = -ENOMEM; 1707ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1708aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1709aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1710aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 1711aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1712aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: %i", retval); 1713aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1714aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1715aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1716aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_get_status_complete: get_status request complete function 1717aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @ep: endpoint 1718aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @req: request handled 1719aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1720aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must release lock 1721aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1722aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) 1723aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1724aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 1725aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1726aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL) { 1727aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1728aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1729aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1730aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1731aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(req->buf); 1732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_free_request(ep, req); 1733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1735aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1736aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_get_status_response: get_status request response 1737ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * @udc: udc struct 1738aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @setup: setup request packet 1739aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1740aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1741aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1742ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic int isr_get_status_response(struct ci13xxx *udc, 1743aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ctrlrequest *setup) 1744aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1747ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp = &udc->ep0in; 1748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_request *req = NULL; 1749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gfp_t gfp_flags = GFP_ATOMIC; 1750aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int dir, num, retval; 1751aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1752aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", mEp, setup); 1753aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1754aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp == NULL || setup == NULL) 1755aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1756aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1757aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1758aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req = usb_ep_alloc_request(&mEp->ep, gfp_flags); 1759aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req == NULL) 1761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 1762aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->complete = isr_get_status_complete; 1764aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->length = 2; 1765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->buf = kzalloc(req->length, gfp_flags); 1766aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req->buf == NULL) { 1767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -ENOMEM; 1768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto err_free_req; 1769aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1770aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1771aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { 1772e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti /* Assume that device is bus powered for now. */ 1773e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti *((u16 *)req->buf) = _udc->remote_wakeup << 1; 1774aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 1775aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else if ((setup->bRequestType & USB_RECIP_MASK) \ 1776aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo == USB_RECIP_ENDPOINT) { 1777aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? 1778aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo TX : RX; 1779aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; 1780aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *((u16 *)req->buf) = hw_ep_get_halt(num, dir); 1781aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1782aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* else do nothing; reserved for future use */ 1783aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1784aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1785aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = usb_ep_queue(&mEp->ep, req, gfp_flags); 1786aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1787aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 1788aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto err_free_buf; 1789aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1790aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 1791aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1792aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err_free_buf: 1793aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(req->buf); 1794aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err_free_req: 1795aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1796aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo usb_ep_free_request(&mEp->ep, req); 1797aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1798aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1799aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1800aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1801aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1802541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * isr_setup_status_complete: setup_status request complete function 1803541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * @ep: endpoint 1804541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * @req: request handled 1805541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * 1806541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * Caller must release lock. Put the port in test mode if test mode 1807541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti * feature is selected. 1808541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti */ 1809541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondetistatic void 1810541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondetiisr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) 1811541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti{ 1812541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti struct ci13xxx *udc = req->context; 1813541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti unsigned long flags; 1814541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti 1815541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti trace("%p, %p", ep, req); 1816541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti 1817541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 1818541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti if (udc->test_mode) 1819541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti hw_port_test_set(udc->test_mode); 1820541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 1821541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti} 1822541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti 1823541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti/** 1824aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_setup_status_phase: queues the status phase of a setup transation 1825ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * @udc: udc struct 1826aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1827aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1828aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1829ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondetistatic int isr_setup_status_phase(struct ci13xxx *udc) 1830aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1831aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1832aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1833aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval; 1834ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp; 1835aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1836ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti trace("%p", udc); 1837aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1838ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; 1839541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti udc->status->context = udc; 1840541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti udc->status->complete = isr_setup_status_complete; 1841aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1842aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 1843ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); 1844aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 1845aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1846aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1847aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1848aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1849aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1850aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_tr_complete_low: transaction complete low level handler 1851aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @mEp: endpoint 1852aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1853aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 1854aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Caller must hold lock 1855aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1856aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int isr_tr_complete_low(struct ci13xxx_ep *mEp) 1857aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(mEp->lock) 1858aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(mEp->lock) 1859aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 18600e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti struct ci13xxx_req *mReq, *mReqTemp; 186176cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti struct ci13xxx_ep *mEpTemp = mEp; 1862986b11b8c7ac3d8752790654637bd944ea18ee79Pavankumar Kondeti int uninitialized_var(retval); 1863aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1864aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", mEp); 1865aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1866ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (list_empty(&mEp->qh.queue)) 1867aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 1868aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 18690e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, 18700e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti queue) { 18710e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti retval = _hardware_dequeue(mEp, mReq); 18720e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (retval < 0) 18730e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti break; 18740e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti list_del_init(&mReq->queue); 18750e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); 18760e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->req.complete != NULL) { 18770e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti spin_unlock(mEp->lock); 187876cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && 187976cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti mReq->req.length) 188076cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti mEpTemp = &_udc->ep0in; 188176cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti mReq->req.complete(&mEpTemp->ep, &mReq->req); 18820e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti spin_lock(mEp->lock); 18830e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 1884d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko } 1885d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko 1886ef90748216d80f4afc95657925873a6fc3d3d6e2Pavankumar Kondeti if (retval == -EBUSY) 18870e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti retval = 0; 18880e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (retval < 0) 18890e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti dbg_event(_usb_addr(mEp), "DONE", retval); 1890aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1891aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 1892aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 1893aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1894aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 1895aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * isr_tr_complete_handler: transaction complete interrupt handler 1896aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @udc: UDC descriptor 1897aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 1898aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function handles traffic events 1899aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 1900aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void isr_tr_complete_handler(struct ci13xxx *udc) 1901aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__releases(udc->lock) 1902aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo__acquires(udc->lock) 1903aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 1904aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned i; 1905541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti u8 tmode = 0; 1906aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1907aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", udc); 1908aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1909aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 1910aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 1911aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 1912aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1913aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1914aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) { 1915aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; 19164c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti int type, num, dir, err = -EINVAL; 1917aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct usb_ctrlrequest req; 1918aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1919aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->desc == NULL) 1920aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; /* not configured */ 1921aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1922ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (hw_test_and_clear_complete(i)) { 1923aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = isr_tr_complete_low(mEp); 1924aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { 1925aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err > 0) /* needs status phase */ 1926ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 1927aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err < 0) { 1928aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), 1929aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo "ERROR", err); 1930aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 1931aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (usb_ep_set_halt(&mEp->ep)) 1932aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: ep_set_halt"); 1933aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 1934aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1935aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1936aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1937aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1938aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type != USB_ENDPOINT_XFER_CONTROL || 1939aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo !hw_test_and_clear_setup_status(i)) 1940aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; 1941aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1942aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (i != 0) { 1943aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("ctrl traffic received at endpoint"); 1944aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo continue; 1945aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1946aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1947ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti /* 1948ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * Flush data and handshake transactions of previous 1949ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti * setup packet. 1950ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti */ 1951ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti _ep_nuke(&udc->ep0out); 1952ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti _ep_nuke(&udc->ep0in); 1953ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 1954aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* read_setup_packet */ 1955aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 1956aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_test_and_set_setup_guard(); 1957ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); 1958aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (!hw_test_and_clear_setup_guard()); 1959aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1960aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type = req.bRequestType; 1961aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1962ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; 1963aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1964aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_setup(_usb_addr(mEp), &req); 1965aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 1966aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo switch (req.bRequest) { 1967aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_CLEAR_FEATURE: 1968e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 1969e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti le16_to_cpu(req.wValue) == 1970e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti USB_ENDPOINT_HALT) { 1971e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (req.wLength != 0) 1972e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti break; 1973e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti num = le16_to_cpu(req.wIndex); 19744c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti dir = num & USB_ENDPOINT_DIR_MASK; 1975e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti num &= USB_ENDPOINT_NUMBER_MASK; 19764c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti if (dir) /* TX */ 19774c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti num += hw_ep_max/2; 1978e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (!udc->ci13xxx_ep[num].wedge) { 1979e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock(udc->lock); 1980e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti err = usb_ep_clear_halt( 1981e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti &udc->ci13xxx_ep[num].ep); 1982e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock(udc->lock); 1983e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (err) 1984e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti break; 1985e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 1986e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti err = isr_setup_status_phase(udc); 1987e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && 1988e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti le16_to_cpu(req.wValue) == 1989e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti USB_DEVICE_REMOTE_WAKEUP) { 1990e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (req.wLength != 0) 1991aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1992e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->remote_wakeup = 0; 1993e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti err = isr_setup_status_phase(udc); 1994e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } else { 1995e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti goto delegate; 1996aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 1997aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 1998aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_GET_STATUS: 1999aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && 2000aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && 2001aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo type != (USB_DIR_IN|USB_RECIP_INTERFACE)) 2002aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 2003aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (le16_to_cpu(req.wLength) != 2 || 2004aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wValue) != 0) 2005aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2006ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_get_status_response(udc, &req); 2007aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2008aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_SET_ADDRESS: 2009aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) 2010aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto delegate; 2011aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (le16_to_cpu(req.wLength) != 0 || 2012aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo le16_to_cpu(req.wIndex) != 0) 2013aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2014aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); 2015aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err) 2016aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2017ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti err = isr_setup_status_phase(udc); 2018aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2019aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo case USB_REQ_SET_FEATURE: 2020e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && 2021e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti le16_to_cpu(req.wValue) == 2022e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti USB_ENDPOINT_HALT) { 2023e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (req.wLength != 0) 2024e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti break; 2025e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti num = le16_to_cpu(req.wIndex); 20264c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti dir = num & USB_ENDPOINT_DIR_MASK; 2027e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti num &= USB_ENDPOINT_NUMBER_MASK; 20284c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti if (dir) /* TX */ 20294c5212b7688955075b166def5ce08b34beb87a9cPavankumar Kondeti num += hw_ep_max/2; 2030aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2031e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock(udc->lock); 2032e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); 2033e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock(udc->lock); 2034e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (!err) 2035541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti isr_setup_status_phase(udc); 2036541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { 2037e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (req.wLength != 0) 2038e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti break; 2039541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti switch (le16_to_cpu(req.wValue)) { 2040541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case USB_DEVICE_REMOTE_WAKEUP: 2041541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti udc->remote_wakeup = 1; 2042541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti err = isr_setup_status_phase(udc); 2043541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti break; 2044541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case USB_DEVICE_TEST_MODE: 2045541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti tmode = le16_to_cpu(req.wIndex) >> 8; 2046541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti switch (tmode) { 2047541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case TEST_J: 2048541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case TEST_K: 2049541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case TEST_SE0_NAK: 2050541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case TEST_PACKET: 2051541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti case TEST_FORCE_EN: 2052541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti udc->test_mode = tmode; 2053541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti err = isr_setup_status_phase( 2054541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti udc); 2055541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti break; 2056541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti default: 2057541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti break; 2058541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti } 2059541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti default: 2060541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti goto delegate; 2061541cace8cd619808424ffaf1c8f7a006e5d55742Pavankumar Kondeti } 2062e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } else { 2063e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti goto delegate; 2064e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2065aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2066aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo default: 2067aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopodelegate: 2068aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (req.wLength == 0) /* no data phase */ 2069ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->ep0_dir = TX; 2070aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2071aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 2072aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err = udc->driver->setup(&udc->gadget, &req); 2073aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 2074aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo break; 2075aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2076aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2077aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (err < 0) { 2078aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "ERROR", err); 2079aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2080aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 2081aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (usb_ep_set_halt(&mEp->ep)) 2082aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error: ep_set_halt"); 2083aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 2084aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2085aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2086aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2087aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2088aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 2089aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ENDPT block 2090aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 2091aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2092aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_enable: configure endpoint, making it usable 2093aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2094aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_enable() at "usb_gadget.h" for details 2095aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2096aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_enable(struct usb_ep *ep, 2097aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo const struct usb_endpoint_descriptor *desc) 2098aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2099aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2100ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int retval = 0; 2101aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2102aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2103aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, desc); 2104aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2105aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || desc == NULL) 2106aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2107aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2108aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2109aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2110aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* only internal SW should enable ctrl endpts */ 2111aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2112aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->desc = desc; 2113aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2114ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (!list_empty(&mEp->qh.queue)) 2115aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("enabling a non-empty endpoint!"); 2116aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 211715739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; 211815739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->num = usb_endpoint_num(desc); 211915739bb5023ab9373e0c6c7c703dc8c50ead9ecaMatthias Kaehlcke mEp->type = usb_endpoint_type(desc); 2120aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 212129cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto mEp->ep.maxpacket = usb_endpoint_maxp(desc); 2122aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2123ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti dbg_event(_usb_addr(mEp), "ENABLE", 0); 2124aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2125ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap = 0; 2126aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2127ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2128ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap |= QH_IOS; 2129ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti else if (mEp->type == USB_ENDPOINT_XFER_ISOC) 2130ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap &= ~QH_MULT; 2131ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti else 2132ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap &= ~QH_ZLT; 2133aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2134ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->cap |= 2135ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; 2136ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ 2137aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2138ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala /* 2139ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala * Enable endpoints in the HW other than ep0 as ep0 2140ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala * is always enabled 2141ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala */ 2142ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala if (mEp->num) 2143ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); 2144aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2145aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2146aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2147aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2148aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2149aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2150aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_disable: endpoint is no longer usable 2151aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2152aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_disable() at "usb_gadget.h" for details 2153aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2154aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_disable(struct usb_ep *ep) 2155aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2156aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2157aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int direction, retval = 0; 2158aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2159aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2160aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2161aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2162aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) 2163aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2164aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (mEp->desc == NULL) 2165aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 2166aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2167aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2168aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2169aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* only internal SW should disable ctrl endpts */ 2170aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2171aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo direction = mEp->dir; 2172aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 2173aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "DISABLE", 0); 2174aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2175aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= _ep_nuke(mEp); 2176aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= hw_ep_disable(mEp->num, mEp->dir); 2177aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2178aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2179aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir = (mEp->dir == TX) ? RX : TX; 2180aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2181aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (mEp->dir != direction); 2182aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2183aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->desc = NULL; 2184aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2185aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2186aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2187aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2188aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2189aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2190aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_alloc_request: allocate a request object to use with this endpoint 2191aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2192aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_alloc_request() at "usb_gadget.h" for details 2193aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2194aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) 2195aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2196aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2197aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = NULL; 2198aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2199aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %i", ep, gfp_flags); 2200aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2201aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) { 2202aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2203aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return NULL; 2204aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2205aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2206aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); 2207aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq != NULL) { 2208aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo INIT_LIST_HEAD(&mReq->queue); 2209954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik mReq->req.dma = DMA_ADDR_INVALID; 2210aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2211aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, 2212aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo &mReq->dma); 2213aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->ptr == NULL) { 2214aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(mReq); 2215aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq = NULL; 2216aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2217aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2218aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2219aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); 2220aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2221aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return (mReq == NULL) ? NULL : &mReq->req; 2222aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2223aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2224aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2225aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_free_request: frees a request object 2226aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2227aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_free_request() at "usb_gadget.h" for details 2228aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2229aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void ep_free_request(struct usb_ep *ep, struct usb_request *req) 2230aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2231aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2232aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2233aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2234aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2235aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 2236aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2237aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL) { 2238aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2239aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2240aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else if (!list_empty(&mReq->queue)) { 2241aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EBUSY"); 2242aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2243aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2244aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2245aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2246aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2247aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mReq->ptr) 2248aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); 2249aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(mReq); 2250aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2251aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "FREE", 0); 2252aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2253aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2254aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2255aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2256aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2257aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_queue: queues (submits) an I/O request to an endpoint 2258aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2259aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_queue()* at usb_gadget.h" for details 2260aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2261aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_queue(struct usb_ep *ep, struct usb_request *req, 2262aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo gfp_t __maybe_unused gfp_flags) 2263aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2264aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2265aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2266aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 2267aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2268aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2269aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p, %X", ep, req, gfp_flags); 2270aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2271aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || req == NULL || mEp->desc == NULL) 2272aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2273aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2274aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2275aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 227676cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { 227776cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti if (req->length) 227876cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti mEp = (_udc->ep0_dir == RX) ? 227976cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti &_udc->ep0out : &_udc->ep0in; 228076cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti if (!list_empty(&mEp->qh.queue)) { 228176cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti _ep_nuke(mEp); 228276cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti retval = -EOVERFLOW; 228376cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti warn("endpoint ctrl %X nuked", _usb_addr(mEp)); 228476cd9cfb2e022d19bfc008a6e993e1e407034241Pavankumar Kondeti } 2285aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2286aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2287aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* first nuke then test link, e.g. previous status has not sent */ 2288aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!list_empty(&mReq->queue)) { 2289aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -EBUSY; 2290aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("request already in queue"); 2291aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2292aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2293aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 22940a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko if (req->length > (4 * CI13XXX_PAGE_SIZE)) { 22950a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko req->length = (4 * CI13XXX_PAGE_SIZE); 2296aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -EMSGSIZE; 2297aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo warn("request length truncated"); 2298aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2299aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2300aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_queue(_usb_addr(mEp), req, retval); 2301aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2302aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* push request */ 2303aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.status = -EINPROGRESS; 2304aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.actual = 0; 2305aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 23060e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti retval = _hardware_enqueue(mEp, mReq); 2307d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko 2308d9bb9c1820cb2a7aeb5e42a5470cf208002d9aa8Artem Leonenko if (retval == -EALREADY) { 2309aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "QUEUE", retval); 2310aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 2311aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 23120e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (!retval) 23130e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti list_add_tail(&mReq->queue, &mEp->qh.queue); 2314aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2315aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 2316aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2317aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2318aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2319aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2320aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2321aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint 2322aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2323aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_dequeue() at "usb_gadget.h" for details 2324aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2325aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_dequeue(struct usb_ep *ep, struct usb_request *req) 2326aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2327aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2328aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); 2329aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2330aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2331aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %p", ep, req); 2332aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 23330e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || 23340e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mEp->desc == NULL || list_empty(&mReq->queue) || 23350e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti list_empty(&mEp->qh.queue)) 2336aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2337aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2338aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2339aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2340aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "DEQUEUE", 0); 2341aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 23420e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti hw_ep_flush(mEp->num, mEp->dir); 2343aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2344aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* pop request */ 2345aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mReq->queue); 23460e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti if (mReq->map) { 23470e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, 23480e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 2349954aad8cd18c928e2db5229f6fa71c80d1c3d8b5Michael Grzeschik mReq->req.dma = DMA_ADDR_INVALID; 23500e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti mReq->map = 0; 23510e6ca1998e4c803b0be98f97a1d1e1ea562b8964Pavankumar Kondeti } 2352aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo req->status = -ECONNRESET; 2353aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 23547c25a82684364da44643cbe3bdbd0f8835293767Artem Leonenko if (mReq->req.complete != NULL) { 2355aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(mEp->lock); 2356aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mReq->req.complete(&mEp->ep, &mReq->req); 2357aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(mEp->lock); 2358aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2359aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2360aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2361aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 2362aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2363aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2364aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2365aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_set_halt: sets the endpoint halt feature 2366aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2367aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_set_halt() at "usb_gadget.h" for details 2368aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2369aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_set_halt(struct usb_ep *ep, int value) 2370aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2371aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2372aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int direction, retval = 0; 2373aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2374aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2375aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p, %i", ep, value); 2376aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2377aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || mEp->desc == NULL) 2378aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2379aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2380aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2381aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2382aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifndef STALL_IN 2383aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ 2384aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && 2385ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti !list_empty(&mEp->qh.queue)) { 2386aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2387aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EAGAIN; 2388aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2389aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2390aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2391aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo direction = mEp->dir; 2392aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo do { 2393aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "HALT", value); 2394aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); 2395aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2396aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (!value) 2397aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->wedge = 0; 2398aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2399aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (mEp->type == USB_ENDPOINT_XFER_CONTROL) 2400aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->dir = (mEp->dir == TX) ? RX : TX; 2401aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2402aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } while (mEp->dir != direction); 2403aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2404aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2405aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2406aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2407aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2408aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2409aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_set_wedge: sets the halt feature and ignores clear requests 2410aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2411aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_set_wedge() at "usb_gadget.h" for details 2412aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2413aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic int ep_set_wedge(struct usb_ep *ep) 2414aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2415aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2416aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2417aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2418aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2419aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2420aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL || mEp->desc == NULL) 2421aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2422aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2423aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2424aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2425aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "WEDGE", 0); 2426aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo mEp->wedge = 1; 2427aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2428aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2429aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2430aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return usb_ep_set_halt(ep); 2431aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2432aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2433aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2434aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * ep_fifo_flush: flushes contents of a fifo 2435aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2436aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_ep_fifo_flush() at "usb_gadget.h" for details 2437aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2438aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void ep_fifo_flush(struct usb_ep *ep) 2439aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2440aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); 2441aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo unsigned long flags; 2442aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2443aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", ep); 2444aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2445aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (ep == NULL) { 2446aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("%02X: -EINVAL", _usb_addr(mEp)); 2447aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2448aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2449aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2450aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(mEp->lock, flags); 2451aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2452aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_event(_usb_addr(mEp), "FFLUSH", 0); 2453aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo hw_ep_flush(mEp->num, mEp->dir); 2454aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2455aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(mEp->lock, flags); 2456aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2457aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2458aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2459aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Endpoint-specific part of the API to the USB controller hardware 2460aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "usb_gadget.h" for details 2461aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2462aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic const struct usb_ep_ops usb_ep_ops = { 2463aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .enable = ep_enable, 2464aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .disable = ep_disable, 2465aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .alloc_request = ep_alloc_request, 2466aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .free_request = ep_free_request, 2467aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .queue = ep_queue, 2468aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .dequeue = ep_dequeue, 2469aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .set_halt = ep_set_halt, 2470aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .set_wedge = ep_set_wedge, 2471aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo .fifo_flush = ep_fifo_flush, 2472aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo}; 2473aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2474aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 2475aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * GADGET block 2476aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 2477f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) 2478f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti{ 2479f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); 2480f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti unsigned long flags; 2481f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti int gadget_ready = 0; 2482f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2483f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) 2484f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return -EOPNOTSUPP; 2485f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2486f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2487f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->vbus_active = is_active; 2488f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->driver) 2489f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti gadget_ready = 1; 2490f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2491f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2492f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (gadget_ready) { 2493f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (is_active) { 2494c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_get_sync(&_gadget->dev); 2495f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_reset(udc); 2496ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti hw_device_state(udc->ep0out.qh.dma); 2497f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } else { 2498f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_state(0); 2499f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 2500f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 2501f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_STOPPED_EVENT); 2502f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti _gadget_stop_activity(&udc->gadget); 2503c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&_gadget->dev); 2504f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2505f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2506f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2507f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return 0; 2508f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti} 2509f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2510e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondetistatic int ci13xxx_wakeup(struct usb_gadget *_gadget) 2511e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti{ 2512e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); 2513e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti unsigned long flags; 2514e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti int ret = 0; 2515e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti 2516e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti trace(); 2517e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti 2518e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2519e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (!udc->remote_wakeup) { 2520e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti ret = -EOPNOTSUPP; 2521194fa47ef629df07d87064ca4aa973939fa6fb4dMarc Kleine-Budde trace("remote wakeup feature is not enabled\n"); 2522e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti goto out; 2523e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2524e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { 2525e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti ret = -EINVAL; 2526194fa47ef629df07d87064ca4aa973939fa6fb4dMarc Kleine-Budde trace("port is not suspended\n"); 2527e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti goto out; 2528e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2529e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); 2530e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondetiout: 2531e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2532e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti return ret; 2533e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti} 2534e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti 2535d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondetistatic int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) 2536d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti{ 2537d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); 2538d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti 2539d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti if (udc->transceiver) 2540d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti return otg_set_power(udc->transceiver, mA); 2541d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti return -ENOTSUPP; 2542d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti} 2543d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti 25440f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int ci13xxx_start(struct usb_gadget_driver *driver, 25450f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior int (*bind)(struct usb_gadget *)); 25460f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int ci13xxx_stop(struct usb_gadget_driver *driver); 2547aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2548aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Device operations part of the API to the USB controller hardware, 2549aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * which don't involve endpoints (or i/o) 2550aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check "usb_gadget.h" for details 2551aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2552f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic const struct usb_gadget_ops usb_gadget_ops = { 2553f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti .vbus_session = ci13xxx_vbus_session, 2554e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti .wakeup = ci13xxx_wakeup, 2555d860852e087eed7eadbea64f1a8db9a231c5e9b3Pavankumar Kondeti .vbus_draw = ci13xxx_vbus_draw, 25560f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .start = ci13xxx_start, 25570f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .stop = ci13xxx_stop, 2558f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti}; 2559aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2560aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 25610f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior * ci13xxx_start: register a gadget driver 2562b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * @driver: the driver being registered 2563b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * @bind: the driver's bind callback 2564aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 25650f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior * Check ci13xxx_start() at <linux/usb/gadget.h> for details. 2566b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König * Interrupts are enabled here. 2567aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 25680f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int ci13xxx_start(struct usb_gadget_driver *driver, 2569b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König int (*bind)(struct usb_gadget *)) 2570aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2571aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2572ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned long flags; 2573ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int i, j; 2574aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = -ENOMEM; 2575aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2576aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", driver); 2577aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2578aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (driver == NULL || 2579b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König bind == NULL || 2580aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->setup == NULL || 25817bb4fdc602c6cc763185d88f58ed75c84eb32158Marc Kleine-Budde driver->disconnect == NULL) 2582aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2583aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (udc == NULL) 2584aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENODEV; 2585aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else if (udc->driver != NULL) 2586aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EBUSY; 2587aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2588aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* alloc resources */ 2589aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, 2590aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo sizeof(struct ci13xxx_qh), 25910a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko 64, CI13XXX_PAGE_SIZE); 2592aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->qh_pool == NULL) 2593aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2594aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2595aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, 2596aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo sizeof(struct ci13xxx_td), 25970a313c4d2435ed0d86cf2295514f02de34cecd88Artem Leonenko 64, CI13XXX_PAGE_SIZE); 2598aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->td_pool == NULL) { 2599aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->qh_pool); 2600aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = NULL; 2601aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2602aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2603aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2604aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2605aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2606aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo info("hw_ep_max = %d", hw_ep_max); 2607aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2608aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = NULL; 2609aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2610aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = 0; 2611ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (i = 0; i < hw_ep_max/2; i++) { 2612ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti for (j = RX; j <= TX; j++) { 2613ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti int k = i + j * hw_ep_max/2; 2614ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; 2615aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2616ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, 2617ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti (j == TX) ? "in" : "out"); 2618aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2619ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->lock = udc->lock; 2620ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->device = &udc->gadget.dev; 2621ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->td_pool = udc->td_pool; 2622aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2623ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.name = mEp->name; 2624ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.ops = &usb_ep_ops; 2625ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; 2626aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2627ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti INIT_LIST_HEAD(&mEp->qh.queue); 26280a91efa2f951d790969dec96fb675ca7869eca83Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2629ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, 2630ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti &mEp->qh.dma); 26310a91efa2f951d790969dec96fb675ca7869eca83Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2632ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->qh.ptr == NULL) 2633aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = -ENOMEM; 2634aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo else 2635ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); 2636ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 2637ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti /* skip ep0 out and in endpoints */ 2638ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (i == 0) 2639ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti continue; 2640ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti 2641aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); 2642ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti } 2643aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2644aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) 2645aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2646ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala spin_unlock_irqrestore(udc->lock, flags); 2647877c1f5408a94cd8a0fa1de4e4806830c1839e8dFelipe Balbi udc->ep0out.ep.desc = &ctrl_endpt_out_desc; 2648877c1f5408a94cd8a0fa1de4e4806830c1839e8dFelipe Balbi retval = usb_ep_enable(&udc->ep0out.ep); 2649ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala if (retval) 2650ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala return retval; 2651877c1f5408a94cd8a0fa1de4e4806830c1839e8dFelipe Balbi 2652877c1f5408a94cd8a0fa1de4e4806830c1839e8dFelipe Balbi udc->ep0in.ep.desc = &ctrl_endpt_in_desc; 2653877c1f5408a94cd8a0fa1de4e4806830c1839e8dFelipe Balbi retval = usb_ep_enable(&udc->ep0in.ep); 2654ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala if (retval) 2655ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala return retval; 2656ac1aa6a21747d02a93b1becb4ab19f1fc9de2bebAnji jonnala spin_lock_irqsave(udc->lock, flags); 2657aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2658ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->gadget.ep0 = &udc->ep0in.ep; 2659aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* bind gadget */ 2660aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->driver.bus = NULL; 2661aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = &driver->driver; 2662aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2663aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2664b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König retval = bind(&udc->gadget); /* MAY SLEEP */ 2665aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2666aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2667aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (retval) { 2668aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.driver = NULL; 2669aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo goto done; 2670aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2671aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 267249d3df53a80deed2251b91f50ae9e1c5caf7ded7Pavankumar Kondeti udc->driver = driver; 2673c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_get_sync(&udc->gadget.dev); 2674f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { 2675f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->vbus_active) { 2676f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) 2677f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_reset(udc); 2678f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } else { 2679c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&udc->gadget.dev); 2680f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto done; 2681f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2682f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2683f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2684ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti retval = hw_device_state(udc->ep0out.qh.dma); 2685c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti if (retval) 2686c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put_sync(&udc->gadget.dev); 2687aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2688aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo done: 2689aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2690aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2691aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2692aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2693aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 26940f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior * ci13xxx_stop: unregister a gadget driver 2695aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2696aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details 2697aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 26980f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int ci13xxx_stop(struct usb_gadget_driver *driver) 2699aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2700aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2701ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti unsigned long i, flags; 2702aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2703aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", driver); 2704aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2705aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (driver == NULL || 2706aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->unbind == NULL || 2707aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->setup == NULL || 2708aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver->disconnect == NULL || 2709aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo driver != udc->driver) 2710aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2711aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2712aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock_irqsave(udc->lock, flags); 2713aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2714f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || 2715f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->vbus_active) { 2716f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti hw_device_state(0); 2717f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->notify_event) 2718f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver->notify_event(udc, 2719f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti CI13XXX_CONTROLLER_STOPPED_EVENT); 2720fd537c041b7f2cbceb5a21c37946e017006edd1cMarc Kleine-Budde spin_unlock_irqrestore(udc->lock, flags); 2721aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _gadget_stop_activity(&udc->gadget); 2722fd537c041b7f2cbceb5a21c37946e017006edd1cMarc Kleine-Budde spin_lock_irqsave(udc->lock, flags); 2723c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_put(&udc->gadget.dev); 2724f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2725aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2726f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti /* unbind gadget */ 2727f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock_irqrestore(udc->lock, flags); 2728f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti driver->unbind(&udc->gadget); /* MAY SLEEP */ 2729f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_lock_irqsave(udc->lock, flags); 2730aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2731f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.dev.driver = NULL; 2732aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2733aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* free resources */ 2734aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo for (i = 0; i < hw_ep_max; i++) { 2735aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; 2736aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2737ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (!list_empty(&mEp->ep.ep_list)) 2738aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo list_del_init(&mEp->ep.ep_list); 2739aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2740ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti if (mEp->qh.ptr != NULL) 2741ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); 2742aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2743aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2744ca9cfea09fc5802074f79d086547c6363ddc894bPavankumar Kondeti udc->gadget.ep0 = NULL; 2745aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->driver = NULL; 2746aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2747aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock_irqrestore(udc->lock, flags); 2748aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2749aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->td_pool != NULL) { 2750aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->td_pool); 2751aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->td_pool = NULL; 2752aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2753aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc->qh_pool != NULL) { 2754aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dma_pool_destroy(udc->qh_pool); 2755aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->qh_pool = NULL; 2756aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2757aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2758aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return 0; 2759aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2760aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2761aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/****************************************************************************** 2762aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * BUS block 2763aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo *****************************************************************************/ 2764aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2765aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_irq: global interrupt handler 2766aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2767aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns IRQ_HANDLED if the IRQ has been handled 2768aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * It locks access to registers 2769aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2770aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic irqreturn_t udc_irq(void) 2771aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2772aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2773aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo irqreturn_t retval; 2774aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo u32 intr; 2775aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2776aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace(); 2777aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2778aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 2779aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("ENODEV"); 2780aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return IRQ_HANDLED; 2781aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2782aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2783aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_lock(udc->lock); 2784f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2785f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { 2786f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (hw_cread(CAP_USBMODE, USBMODE_CM) != 2787f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti USBMODE_CM_DEVICE) { 2788f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti spin_unlock(udc->lock); 2789f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti return IRQ_NONE; 2790f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2791f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2792aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo intr = hw_test_and_clear_intr_active(); 2793aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (intr) { 2794aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; 2795aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.idx &= ISR_MASK; 2796aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.hndl.cnt++; 2797aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2798aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo /* order defines priority - do NOT change it */ 2799aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_URI & intr) { 2800aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uri++; 2801aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_reset_handler(udc); 2802aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2803aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_PCI & intr) { 2804aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.pci++; 2805aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.speed = hw_port_is_high_speed() ? 2806aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo USB_SPEED_HIGH : USB_SPEED_FULL; 28077bb4fdc602c6cc763185d88f58ed75c84eb32158Marc Kleine-Budde if (udc->suspended && udc->driver->resume) { 2808e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock(udc->lock); 2809e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->driver->resume(&udc->gadget); 2810e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock(udc->lock); 2811e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->suspended = 0; 2812e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2813aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2814aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UEI & intr) 2815aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.uei++; 2816aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (USBi_UI & intr) { 2817aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.ui++; 2818aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_tr_complete_handler(udc); 2819aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2820e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti if (USBi_SLI & intr) { 28217bb4fdc602c6cc763185d88f58ed75c84eb32158Marc Kleine-Budde if (udc->gadget.speed != USB_SPEED_UNKNOWN && 28227bb4fdc602c6cc763185d88f58ed75c84eb32158Marc Kleine-Budde udc->driver->suspend) { 2823e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->suspended = 1; 2824e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_unlock(udc->lock); 2825e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti udc->driver->suspend(&udc->gadget); 2826e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti spin_lock(udc->lock); 2827e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2828aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.sli++; 2829e2b61c1df650595d0216c6d086024b5a98d949c7Pavankumar Kondeti } 2830aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = IRQ_HANDLED; 2831aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } else { 2832aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo isr_statistics.none++; 2833aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = IRQ_NONE; 2834aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 2835aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo spin_unlock(udc->lock); 2836aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2837aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2838aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2839aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2840aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2841aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_release: driver release function 2842aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: device 2843aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2844aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Currently does nothing 2845aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2846aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void udc_release(struct device *dev) 2847aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2848aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo trace("%p", dev); 2849aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2850aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (dev == NULL) 2851aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2852aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2853aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2854aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2855aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_probe: parent probe must call this to initialize UDC 2856aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @dev: parent device 2857aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @regs: registers base address 2858aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * @name: driver name 2859aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2860aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * This function returns an error code 2861aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * No interrupts active, the IRQ has not been requested yet 2862aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask 2863aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2864f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetistatic int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, 2865f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti void __iomem *regs) 2866aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2867aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc; 2868aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo int retval = 0; 2869aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2870194fa47ef629df07d87064ca4aa973939fa6fb4dMarc Kleine-Budde trace("%p, %p, %p", dev, regs, driver->name); 2871aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2872f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (dev == NULL || regs == NULL || driver == NULL || 2873f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti driver->name == NULL) 2874aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -EINVAL; 2875aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2876aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); 2877aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) 2878aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return -ENOMEM; 2879aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2880aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->lock = &udc_lock; 2881f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->regs = regs; 2882f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->udc_driver = driver; 2883aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2884f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.ops = &usb_gadget_ops; 2885aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.speed = USB_SPEED_UNKNOWN; 2886d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz udc->gadget.max_speed = USB_SPEED_HIGH; 2887aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.is_otg = 0; 2888f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->gadget.name = driver->name; 2889aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2890aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo INIT_LIST_HEAD(&udc->gadget.ep_list); 2891aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.ep0 = NULL; 2892aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 28935df5852446196c9713e897ab5f9b8a168d971a00Kay Sievers dev_set_name(&udc->gadget.dev, "gadget"); 2894aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.dma_mask = dev->dma_mask; 289561948ee4d525174cceee2135a38a482124fcc02cPavankumar Kondeti udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; 2896aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.parent = dev; 2897aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo udc->gadget.dev.release = udc_release; 2898aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2899f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = hw_device_init(regs); 2900f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval < 0) 2901f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto free_udc; 2902f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2903f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti udc->transceiver = otg_get_transceiver(); 2904f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2905f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { 2906f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver == NULL) { 2907f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = -ENODEV; 2908f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto free_udc; 2909f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2910f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2911f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2912f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { 2913f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = hw_device_reset(udc); 2914f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2915f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto put_transceiver; 2916f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2917f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2918aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = device_register(&udc->gadget.dev); 2919f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) { 2920f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti put_device(&udc->gadget.dev); 2921f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto put_transceiver; 2922f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2923aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2924aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2925aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo retval = dbg_create_files(&udc->gadget.dev); 2926aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2927f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2928f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto unreg_device; 2929f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti 2930f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) { 2931f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti retval = otg_set_peripheral(udc->transceiver, &udc->gadget); 2932f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (retval) 2933f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti goto remove_dbg; 2934aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 29350f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 29360f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior retval = usb_add_gadget_udc(dev, &udc->gadget); 29370f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior if (retval) 29380f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior goto remove_trans; 29390f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 2940c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_no_callbacks(&udc->gadget.dev); 2941c036019ed2b729cb9517806c2b388b4f4323a904Pavankumar Kondeti pm_runtime_enable(&udc->gadget.dev); 2942aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2943aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = udc; 2944aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2945aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 29460f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorremove_trans: 29470f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior if (udc->transceiver) { 29480f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior otg_set_peripheral(udc->transceiver, &udc->gadget); 29490f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior otg_put_transceiver(udc->transceiver); 29500f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior } 29510f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 2952aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("error = %i", retval); 2953f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiremove_dbg: 2954f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2955f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti dbg_remove_files(&udc->gadget.dev); 2956f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti#endif 2957f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiunreg_device: 2958f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti device_unregister(&udc->gadget.dev); 2959f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetiput_transceiver: 2960f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) 2961f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_put_transceiver(udc->transceiver); 2962f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondetifree_udc: 2963aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(udc); 2964aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = NULL; 2965aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return retval; 2966aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2967aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2968aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo/** 2969aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * udc_remove: parent remove must call this to remove UDC 2970aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * 2971aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo * No interrupts active, the IRQ has been released 2972aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo */ 2973aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopostatic void udc_remove(void) 2974aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo{ 2975aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo struct ci13xxx *udc = _udc; 2976aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2977aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo if (udc == NULL) { 2978aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo err("EINVAL"); 2979aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo return; 2980aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo } 29810f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&udc->gadget); 2982aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2983f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti if (udc->transceiver) { 2984f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_set_peripheral(udc->transceiver, &udc->gadget); 2985f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti otg_put_transceiver(udc->transceiver); 2986f01ef5748f4c4dcd2e49ccb7d75dc113219559d2Pavankumar Kondeti } 2987aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#ifdef CONFIG_USB_GADGET_DEBUG_FILES 2988aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo dbg_remove_files(&udc->gadget.dev); 2989aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo#endif 2990aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo device_unregister(&udc->gadget.dev); 2991aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo 2992aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo kfree(udc); 2993aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo _udc = NULL; 2994aa69a8093ff985873cb44fe1157bd6db29a20fe4David Lopo} 2995