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