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