From 5e8c7c54a9b297dae0081dd19a7bb94e23040a3d Mon Sep 17 00:00:00 2001 From: Joshua Lock Date: Tue, 18 May 2010 14:51:13 +0100 Subject: linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0 Signed-off-by: Joshua Lock --- .../linux-2.6.34-pch-usbdev.patch | 7018 ++++++++++++++++++++ 1 file changed, 7018 insertions(+) create mode 100644 meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-usbdev.patch (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-usbdev.patch') diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-usbdev.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-usbdev.patch new file mode 100644 index 000000000..f9ea573a7 --- /dev/null +++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-usbdev.patch @@ -0,0 +1,7018 @@ +From: Masayuki Ohtake +Subject: OKI Semiconductor PCH USB Gadget driver + +This driver implements PCH Gadget controls for PCH. + +Signed-off-by: Masayuki Ohtake +Acked-by: Wang Qi + +--- + drivers/usb/gadget/gadget_chips.h | 8 ++ + drivers/usb/gadget/Kconfig | 16 + drivers/usb/gadget/Makefile | 6 + drivers/usb/gadget/pch_common.h | 146 + drivers/usb/gadget/pch_debug.h | 160 + drivers/usb/gadget/pch_udc.c | 2530 + drivers/usb/gadget/pch_udc.h | 172 + drivers/usb/gadget/pch_udc_hal.c | 1110 + drivers/usb/gadget/pch_udc_hal.h | 1829 + drivers/usb/gadget/pch_udc_intr.c | 396 + drivers/usb/gadget/pch_udc_pci.c | 549 + drivers/usb/gadget/pch_udc_pci.h | 97 ++++++++++++++++++++++++++++++++ 12 files changed, zz insertions(+) +--- + drivers/usb/gadget/Kconfig | 16 + drivers/usb/gadget/Makefile | 6 + drivers/usb/gadget/gadget_chips.h | 12 + drivers/usb/gadget/pch_common.h | 146 ++ + drivers/usb/gadget/pch_debug.h | 60 + drivers/usb/gadget/pch_udc.c | 2530 ++++++++++++++++++++++++++++++++++++++ + drivers/usb/gadget/pch_udc.h | 172 ++ + drivers/usb/gadget/pch_udc_hal.c | 1110 ++++++++++++++++ + drivers/usb/gadget/pch_udc_hal.h | 1829 +++++++++++++++++++++++++++ + drivers/usb/gadget/pch_udc_intr.c | 396 +++++ + drivers/usb/gadget/pch_udc_pci.c | 549 ++++++++ + drivers/usb/gadget/pch_udc_pci.h | 97 + + 12 files changed, 6923 insertions(+) + +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -220,6 +220,22 @@ config USB_OTG + + Select this only if your OMAP board has a Mini-AB connector. + ++config USB_GADGET_PCH ++ boolean "PCH USB Dev" ++ depends on PCI ++ select USB_GADGET_DUALSPEED ++ help ++ PCH USB device is a PCI based USB peripheral controller which ++ supports both full and high speed USB 2.0 data transfers. ++ ++config PCH_USBDEV ++ tristate ++ depends on USB_GADGET_PCH ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ ++ ++ + config USB_GADGET_PXA25X + boolean "PXA 25x or IXP 4xx" + depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -58,3 +58,9 @@ obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc + obj-$(CONFIG_USB_G_MULTI) += g_multi.o + obj-$(CONFIG_USB_STILL_IMAGE) += g_still_image.o + ++ifeq ($(CONFIG_USB_GADGET_DEBUG),y) ++ EXTRA_CFLAGS += -DDMA_PPB_MODE ++endif ++obj-$(CONFIG_PCH_USBDEV) += pch_usbdev.o ++pch_usbdev-objs := pch_udc_pci.o pch_udc.o pch_udc_hal.o pch_udc_intr.o ++ +--- a/drivers/usb/gadget/gadget_chips.h ++++ b/drivers/usb/gadget/gadget_chips.h +@@ -180,6 +180,14 @@ + #endif + + ++#ifdef CONFIG_USB_GADGET_PCH ++#define gadget_is_ioh(g) (!strcmp("ioh_udc", (g)->name)) ++#else ++#define gadget_is_ioh(g) 0 ++#endif ++ ++ ++ + /** + * usb_gadget_controller_number - support bcdDevice id convention + * @gadget: the controller being driven +@@ -247,6 +255,10 @@ static inline int usb_gadget_controller_ + return 0x24; + else if (gadget_is_r8a66597(gadget)) + return 0x25; ++ ++ else if (gadget_is_ioh(gadget)) ++ return 0x26; ++ + return -ENOENT; + } + +--- /dev/null ++++ b/drivers/usb/gadget/pch_common.h +@@ -0,0 +1,146 @@ ++/*! ++ * @file ioh_common.h ++ * @brief Provides the macro definitions used by all files. ++ * @version 1.0.0.0 ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * History: ++ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * WIPRO 03/07/2009 ++ * modified: ++ * WIPRO 05/08/2009 ++ * ++ */ ++ ++#ifndef __IOH_COMMON_H__ ++#define __IOH_COMMON_H__ ++ ++/*! @ingroup Global ++@def IOH_WRITE8 ++@brief Macro for writing 8 bit data to an io/mem address ++*/ ++#define IOH_WRITE8(val, addr) iowrite8((val), (void __iomem *)(addr)) ++/*! @ingroup Global ++@def IOH_LOG ++@brief Macro for writing 16 bit data to an io/mem address ++*/ ++#define IOH_WRITE16(val, addr) iowrite16((val), (void __iomem *)(addr)) ++/*! @ingroup Global ++@def IOH_LOG ++@brief Macro for writing 32 bit data to an io/mem address ++*/ ++#define IOH_WRITE32(val, addr) iowrite32((val), (void __iomem *)(addr)) ++ ++/*! @ingroup Global ++@def IOH_READ8 ++@brief Macro for reading 8 bit data from an io/mem address ++*/ ++#define IOH_READ8(addr) ioread8((void __iomem *)(addr)) ++/*! @ingroup Global ++@def IOH_READ16 ++@brief Macro for reading 16 bit data from an io/mem address ++*/ ++#define IOH_READ16(addr) ioread16((void __iomem *)(addr)) ++/*! @ingroup Global ++@def IOH_READ32 ++@brief Macro for reading 32 bit data from an io/mem address ++*/ ++#define IOH_READ32(addr) ioread32((void __iomem *)(addr)) ++/*! @ingroup Global ++@def IOH_WRITE32_F ++@brief Macro for writing 32 bit data to an io/mem address ++*/ ++#define IOH_WRITE32_F(val, addr) do \ ++ { IOH_WRITE32((val), (addr)); (void)IOH_READ32((addr)); } while (0); ++ ++/*! @ingroup Global ++@def IOH_WRITE_BYTE ++@brief Macro for writing 1 byte data to an io/mem address ++*/ ++#define IOH_WRITE_BYTE IOH_WRITE8 ++/*! @ingroup Global ++@def IOH_WRITE_WORD ++@brief Macro for writing 1 word data to an io/mem address ++*/ ++#define IOH_WRITE_WORD IOH_WRITE16 ++/*! @ingroup Global ++@def IOH_WRITE_LONG ++@brief Macro for writing long data to an io/mem address ++*/ ++#define IOH_WRITE_LONG IOH_WRITE32 ++ ++/*! @ingroup Global ++@def IOH_READ_BYTE ++@brief Macro for reading 1 byte data from an io/mem address ++*/ ++#define IOH_READ_BYTE IOH_READ8 ++/*! @ingroup Global ++@def IOH_READ_WORD ++@brief Macro for reading 1 word data from an io/mem address ++*/ ++#define IOH_READ_WORD IOH_READ16 ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief Macro for reading long data from an io/mem address ++*/ ++#define IOH_READ_LONG IOH_READ32 ++ ++/* Bit Manipulation Macros */ ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to set a specified bit(mask) at the ++ specified address ++*/ ++#define IOH_SET_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) |\ ++ (bitmask)), (addr)) ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to clear a specified bit(mask) at the specified address ++*/ ++#define IOH_CLR_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) &\ ++ ~(bitmask)), (addr)) ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to set a specified bitmask for a variable ++*/ ++#define IOH_SET_BITMSK(var, bitmask) ((var) |= (bitmask)) ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to clear a specified bitmask for a variable ++*/ ++#define IOH_CLR_BITMSK(var, bitmask) ((var) &= (~(bitmask))) ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to set a specified bit for a variable ++*/ ++#define IOH_SET_BIT(var, bit) ((var) |= (1<<(bit))) ++ ++/*! @ingroup Global ++@def IOH_READ_LONG ++@brief macro to clear a specified bit for a variable ++*/ ++#define IOH_CLR_BIT(var, bit) ((var) &= ~(1<<(bit))) ++ ++#endif +--- /dev/null ++++ b/drivers/usb/gadget/pch_debug.h +@@ -0,0 +1,60 @@ ++/*! ++ * @file ioh_debug.h ++ * @brief Provides the macro definitions used for debugging. ++ * @version 1.0.0.0 ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * History: ++ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * WIPRO 03/07/2009 ++ * modified: ++ * WIPRO 05/08/2009 ++ * ++ */ ++ ++#ifndef __IOH_DEBUG_H__ ++#define __IOH_DEBUG_H__ ++ ++#ifdef MODULE ++#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n",\ ++ THIS_MODULE->name, ##args) ++#else ++#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n" ,\ ++ __FILE__, ##args) ++#endif ++ ++ ++#ifdef DEBUG ++ #define IOH_DEBUG(fmt, args...) IOH_LOG(KERN_DEBUG, fmt, ##args) ++#else ++ #define IOH_DEBUG(fmt, args...) ++#endif ++ ++#ifdef IOH_TRACE_ENABLED ++ #define IOH_TRACE IOH_DEBUG ++#else ++ #define IOH_TRACE(fmt, args...) ++#endif ++ ++#define IOH_TRACE_ENTER IOH_TRACE("Enter %s", __func__) ++#define IOH_TRACE_EXIT IOH_TRACE("Exit %s", __func__) ++ ++ ++#endif +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc.c +@@ -0,0 +1,2530 @@ ++ /*! ++ *@file ioh_udc.c ++ *@brief This file contains the definitions for IOH UDC driver APIs. ++ * ++ *The IOH UDC is a USB High speed DMA capable USB device controller. ++ *It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or interrupt ++ * type). ++ * ++ *The IOH USB device controller driver provides required interface ++ *to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ *@version 0.96 ++ * ++ *@section ++ *This program is free software; you can redistribute it and/or modify ++ *it under the terms of the GNU General Public License as published by ++ *the Free Software Foundation; version 2 of the License. ++ * ++ *This program is distributed in the hope that it will be useful, ++ *but WITHOUT ANY WARRANTY; without even the implied warranty of ++ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ *GNU General Public License for more details. ++ * ++ *You should have received a copy of the GNU General Public License ++ *along with this program; if not, write to the Free Software ++ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ *History: ++ *Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ *All rights reserved. ++ * ++ *created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ *modified: ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pch_common.h" ++#include "pch_debug.h" ++ ++#include "pch_udc_hal.h" ++#include "pch_udc.h" ++ ++#if 0 /* statis as static */ ++#define static ++#endif ++ ++/* stall spin lock */ ++static DEFINE_SPINLOCK(udc_stall_spinlock); ++ ++/* function prototypes */ ++static int ioh_udc_pcd_get_frame(struct usb_gadget *gadget); ++static int ioh_udc_pcd_wakeup(struct usb_gadget *gadget); ++static int ioh_udc_pcd_selfpowered(struct usb_gadget *gadget, int value); ++static int ioh_udc_pcd_pullup(struct usb_gadget *gadget, int is_on); ++static int ioh_udc_pcd_vbus_session(struct usb_gadget *gadget, int is_active); ++static int ioh_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA); ++static void ioh_udc_pcd_reinit(struct ioh_udc_dev *dev); ++static void complete_req(struct ioh_udc_ep *ep, struct ioh_udc_request *req, ++ int status); ++static int ioh_udc_pcd_ep_enable(struct usb_ep *usbep, ++ const struct usb_endpoint_descriptor *desc); ++static int ioh_udc_pcd_ep_disable(struct usb_ep *usbep); ++static struct usb_request *ioh_udc_alloc_request(struct usb_ep *uep, gfp_t gfp); ++static int ioh_udc_free_dma_chain(struct ioh_udc_dev *dev, ++ struct ioh_udc_request *req); ++static int ioh_udc_create_dma_chain(struct ioh_udc_ep *ep, ++ struct ioh_udc_request *req, ++ unsigned long buf_len, gfp_t gfp_flags); ++static void ioh_udc_free_request(struct usb_ep *uep, struct usb_request *req); ++static int prepare_dma(struct ioh_udc_ep *ep, ++ struct ioh_udc_request *req, gfp_t gfp); ++static void process_zlp(struct ioh_udc_ep *ep, struct ioh_udc_request *req); ++static int ioh_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, ++ gfp_t gfp); ++static int ioh_udc_pcd_dequeue(struct usb_ep *usbep, ++ struct usb_request *usbreq); ++static int ioh_udc_pcd_set_halt(struct usb_ep *usbep, int halt); ++static int ioh_udc_pcd_set_wedge(struct usb_ep *usbep); ++static void ioh_udc_pcd_fifo_flush(struct usb_ep *usbep); ++static void ioh_udc_svc_data_out(struct ioh_udc_dev *dev, int ep_num); ++static void ioh_udc_svc_control_in(struct ioh_udc_dev *dev); ++static void ioh_udc_svc_control_out(struct ioh_udc_dev *dev); ++static void ioh_udc_svc_data_in(struct ioh_udc_dev *dev, int ep_num); ++static void ioh_udc_read_all_epstatus(struct ioh_udc_dev *dev, u32 ep_intr); ++static void ioh_udc_setup_ep0(struct ioh_udc_dev *dev); ++static void ioh_udc_init_setup_buff(struct ioh_udc_stp_dma_desc *td_stp); ++static void ioh_udc_complete_transfer(struct ioh_udc_ep *ep); ++static void ioh_udc_complete_receiver(struct ioh_udc_ep *ep); ++static void ioh_udc_start_next_txrequest(struct ioh_udc_ep *ep); ++static void ioh_udc_start_rxrequest(struct ioh_udc_ep *ep, ++ struct ioh_udc_request *req); ++static void ioh_udc_postsvc_epinters(struct ioh_udc_dev *dev, int ep_num); ++ ++/* gadget operations */ ++/*!@ingroup UDC_InterfaceLayer ++ *@struct ioh_udc_ops ++ *@brief specifies gadget operations possible ++ */ ++const struct usb_gadget_ops ioh_udc_ops = { ++ .get_frame = ioh_udc_pcd_get_frame, ++ .wakeup = ioh_udc_pcd_wakeup, ++ .set_selfpowered = ioh_udc_pcd_selfpowered, ++ .pullup = ioh_udc_pcd_pullup, ++ .vbus_session = ioh_udc_pcd_vbus_session, ++ .vbus_draw = ioh_udc_pcd_vbus_draw, ++}; ++ ++ ++/* endpoint interface */ ++/*!@ingroup UDC_InterfaceLayer ++ *@struct usb_ep_ops ioh_udc_ep_ops ++ *@brief specifies endpoint operations possible ++ */ ++static const struct usb_ep_ops ioh_udc_ep_ops = { ++ .enable = ioh_udc_pcd_ep_enable, ++ .disable = ioh_udc_pcd_ep_disable, ++ .alloc_request = ioh_udc_alloc_request, ++ .free_request = ioh_udc_free_request, ++ .queue = ioh_udc_pcd_queue, ++ .dequeue = ioh_udc_pcd_dequeue, ++ .set_halt = ioh_udc_pcd_set_halt, ++ .set_wedge = ioh_udc_pcd_set_wedge, ++ .fifo_status = NULL, ++ .fifo_flush = ioh_udc_pcd_fifo_flush, ++}; ++ ++/* received setup data */ ++static union ioh_udc_setup_data setup_data; ++static unsigned long ep0out_buf[64]; ++static dma_addr_t dma_addr; ++ ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_get_frame(struct usb_gadget *gadget) ++ *@brief This API is invoked to get the current frame number ++ *@remarks The following actions are performed: ++ * - If the argument is NULL, return -EINVAL ++ * - Return the frame number by invoking HAL API ++ * ioh_udc_get_frame ++ *@param gadget Reference to the gadget driver ++ *@return int [ the frame number ] -EINVAL [Invalid Arguments] ++ *@see ++ * - ioh_udc_get_frame ++ */ ++static int ioh_udc_pcd_get_frame(struct usb_gadget *gadget) ++{ ++ struct ioh_udc_dev *dev; ++ ++ IOH_DEBUG("ioh_udc_pcd_get_frame: enter"); ++ if (gadget == NULL) { ++ IOH_DEBUG("ioh_udc_pcd_get_frame: exit -EINVAL"); ++ return -EINVAL; ++ } ++ ++ dev = container_of(gadget, struct ioh_udc_dev, gadget); ++ ++ IOH_DEBUG("ioh_udc_pcd_get_frame: exit"); ++ return ioh_udc_get_frame(dev->regs); ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_wakeup(struct usb_gadget *gadget) ++ *@brief This API is invoked to initiate a remote wakeup ++ *@remarks The following actions are performed: ++ * - If the argument is NULL, return -EINVAL ++ * - Invoke HAL API ioh_udc_rmt_wakeup to start ++ * remote signaling ++ *@param gadget Reference to the gadget driver ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_rmt_wakeup ++ */ ++static int ioh_udc_pcd_wakeup(struct usb_gadget *gadget) ++{ ++ struct ioh_udc_dev *dev; ++ unsigned long flags; ++ ++ IOH_DEBUG("ioh_udc_pcd_wakeup: enter"); ++ if (gadget == NULL) { ++ IOH_DEBUG("ioh_udc_pcd_wakeup: exit -EINVAL"); ++ return -EINVAL; ++ } ++ ++ dev = container_of(gadget, struct ioh_udc_dev, gadget); ++ ++ IOH_DEBUG("ioh_udc_pcd_wakeup: initiate remote wakeup"); ++ spin_lock_irqsave(&dev->lock, flags); ++ ioh_udc_rmt_wakeup(dev->regs); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ IOH_DEBUG("ioh_udc_pcd_wakeup: exit"); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_selfpowered (struct usb_gadget *gadget, ++ * int value) ++ *@brief This API is invoked to specify whether the device is self ++ * powered or not ++ *@remarks The following actions are performed: ++ *- if value is 0, invoke HAL API ioh_udc_clear_selfpowered to clear the self ++ * powered feature ++ *- otherwise, invoke ioh_udc_set_selfpowered to set the self powered ++ * feature for the device ++ *@param gadget Reference to the gadget driver ++ *@param value specifies self powered or not ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_set_selfpowered ++ * - ioh_udc_clear_selfpowered ++ */ ++static int ioh_udc_pcd_selfpowered(struct usb_gadget *gadget, int value) ++{ ++ struct ioh_udc_dev *dev; ++ ++ IOH_DEBUG("ioh_udc_pcd_selfpowered: enter"); ++ if (gadget == NULL) { ++ IOH_DEBUG("ioh_udc_pcd_selfpowered: exit -EINVAL"); ++ return -EINVAL; ++ } ++ ++ dev = container_of(gadget, struct ioh_udc_dev, gadget); ++ if (value == 0) ++ ioh_udc_clear_selfpowered(dev->regs); ++ else ++ ioh_udc_set_selfpowered(dev->regs); ++ ++ IOH_DEBUG("ioh_udc_pcd_selfpowered: exit value=%d", value); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_pullup (struct usb_gadget *gadget, ++ * int is_on) ++ *@brief This API is invoked to make the device visible/invisible to the host ++ *@remarks The following actions are performed: ++ * - If gadget passed is NULL, return -EINVAL ++ * - If is_on is TRUE, call ioh_udc_clear_disconnect() ++ * to make the device visible to the host ++ * - Otherwise call the HAL API ioh_udc_set_disconnect() ++ * to make the device unavailable to the host ++ *@param gadget Reference to the gadget driver ++ *@param is_on specifies whether the pull up is made active ++ * or inactive ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_clear_disconnect ++ * - ioh_udc_set_disconnect ++ */ ++static int ioh_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) ++{ ++ struct ioh_udc_dev *dev; ++ ++ IOH_DEBUG("ioh_udc_pcd_pullup: enter"); ++ if (gadget == NULL) { ++ IOH_DEBUG("ioh_udc_pcd_pullup: exit -EINVAL"); ++ return -EINVAL; ++ } ++ ++ dev = container_of(gadget, struct ioh_udc_dev, gadget); ++ if (is_on == 0) ++ ioh_udc_set_disconnect(dev->regs); ++ else ++ ioh_udc_clear_disconnect(dev->regs); ++ ++ IOH_DEBUG("ioh_udc_pcd_pullup: exit is_on=%d", is_on); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_vbus_session (struct usb_gadget *gadget, ++ * int is_active) ++ *@brief This API is used by a driver for an external transceiver ++ * (or GPIO) that ++ * detects a VBUS power session starting/ending ++ *@remarks The following actions are performed: ++ * - If the gadget passed is NULL, return -EINVAL ++ * - Invoke the HAL API ioh_udc_vbus_session to notify ++ * the start/end of the vbus power ++ *@param gadget Reference to the gadget driver ++ *@param is_active specifies whether the session is starting or ending ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_vbus_session ++ */ ++static int ioh_udc_pcd_vbus_session(struct usb_gadget *gadget, int is_active) ++{ ++ struct ioh_udc_dev *dev; ++ ++ IOH_DEBUG("ioh_udc_pcd_vbus_session: enter"); ++ if (gadget == NULL) { ++ IOH_DEBUG("ioh_udc_pcd_vbus_session: exit -EINVAL"); ++ return -EINVAL; ++ } ++ dev = container_of(gadget, struct ioh_udc_dev, gadget); ++ ++ ioh_udc_vbus_session(dev->regs, is_active); ++ IOH_DEBUG("ioh_udc_pcd_vbus_session: exit"); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_vbus_draw (struct usb_gadget *gadget, ++ * unsigned int mA) ++ *@brief This API is used by gadget drivers during SET_CONFIGURATION ++ * calls to ++ * specify how much power the device can consume ++ *@remarks The following actions are performed: ++ * - If the gadget passed is NULL, return -EINVAL ++ * - Return -EOPNOTSUPP ++ *@param gadget Reference to the gadget driver ++ *@param mA specifies the current limit in 2mA unit ++ *@return int [ 0 on success and linux error number on failure ] ++ */ ++static int ioh_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) ++{ ++ IOH_DEBUG("ioh_udc_pcd_vbus_draw: enter"); ++ if ((gadget == NULL) || (mA > 250)) { /* Max is 250 in 2mA unit */ ++ IOH_DEBUG("ioh_udc_pcd_vbus_draw: exit -EINVAL"); ++ return -EINVAL; ++ } ++ IOH_DEBUG("ioh_udc_pcd_vbus_draw: exit -EOPNOTSUPP"); ++ ++ /* Could not find any regs where we can set the limit */ ++ return -EOPNOTSUPP; ++} ++ ++const char ep0_string[] = "ep0in"; ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_pcd_reinit(struct ioh_udc_dev *dev) ++ *@brief This API initializes the endpoint structures ++ *@remarks The following actions are performed: ++ *- Initialize gadgets speed as unknown ++ *- Initialize the gadget endpoint list (ep_list) ++ *- Assign name for each endpoint and their reference to endpoint operations ++ * to ioh_udc_ep_ops ++ *- Add all endpoints other than ep0 IN and ep0 OUT to the gadgete ep_list ++ *@param dev Reference to the driver structure ++ *@return none ++ */ ++static void ioh_udc_pcd_reinit(struct ioh_udc_dev *dev) ++{ ++ static const char *ep_string[] = { ++ ep0_string, "ep0out", ++ "ep1in", "ep1out", ++ "ep2in", "ep2out", ++ "ep3in", "ep3out", ++ "ep4in", "ep4out", ++ "ep5in", "ep5out", ++ "ep6in", "ep6out", ++ "ep7in", "ep7out", ++ "ep8in", "ep8out", ++ "ep9in", "ep9out", ++ "ep10in", "ep10out", ++ "ep11in", "ep11out", ++ "ep12in", "ep12out", ++ "ep13in", "ep13out", ++ "ep14in", "ep14out", ++ "ep15in", "ep15out", ++ }; ++ int i; ++ ++ IOH_DEBUG("ioh_udc_pcd_reinit: enter"); ++ ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ INIT_LIST_HEAD(&dev->gadget.ep_list); ++ ++ /* Initialize the endpoints structures */ ++ for (i = 0; i < IOH_UDC_EP_NUM; i++) { ++ struct ioh_udc_ep *ep = &dev->ep[i]; ++ memset(ep, 0, sizeof(*ep)); ++ ++ ep->desc = NULL; ++ ep->dev = dev; ++ ep->halted = 1; ++ ep->num = i / 2; ++ ep->in = ((i & 1) == 0) ? 1 : 0; ++ ++ ep->ep.name = ep_string[i]; ++ ep->ep.ops = &ioh_udc_ep_ops; ++ if (ep->in) ++ ep->regs = (struct ioh_udc_ep_regs *)\ ++ ((int)dev->ep_regs + ep->num * UDC_EP_REG_OFS); ++ else ++ ep->regs = (struct ioh_udc_ep_regs *)\ ++ ((int)dev->ep_regs + \ ++ (UDC_EPINT_OUT_EP0 + ep->num) * UDC_EP_REG_OFS); ++ ++ ep->dma = &ep->regs->epctl; ++ /* need to set ep->ep.maxpacket and set Default Configuration?*/ ++ ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; ++ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ++ INIT_LIST_HEAD(&ep->queue); ++ } ++ dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; ++ dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; ++ ++ dma_addr = pci_map_single(dev->pdev, ep0out_buf, ++ 256, PCI_DMA_FROMDEVICE); ++ ++ /* remove ep0 in and out from the list. They have own pointer */ ++ list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); ++ list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list); ++ ++ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; ++ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); ++ IOH_DEBUG("ioh_udc_pcd_reinit: exit"); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn int ioh_udc_pcd_init(struct ioh_udc_dev *dev) ++ *@brief This API initializes the driver structure ++ *@remarks The following actions are performed: ++ *- Set udc csr register base in dev->csr ++ *- Set Device Configuration Register base in dev->regs ++ *- Set Endpoint-specific CSR base in dev->ep_regs ++ *- Invoke ioh_udc_init to initialize registers, interrupts ++ *- Invoke ioh_udc_pcd_reinit to perform initialization of the endpoint ++ * structures ++ *- Return Success (0) ++ *@param dev Reference to the driver structure ++ *@return success ++ *@see ++ * - ioh_udc_init ++ * - ioh_udc_pcd_reinit ++ */ ++int ioh_udc_pcd_init(struct ioh_udc_dev *dev) ++{ ++ IOH_DEBUG("ioh_udc_pcd_init: enter"); ++ ++ /* udc csr registers base */ ++ dev->csr = dev->virt_addr + UDC_CSR_ADDR; ++ /* dev registers base */ ++ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; ++ /* ep registers base */ ++ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; ++ ++ /* init registers, interrupts, ... */ ++ ioh_udc_init(dev->regs); ++#ifdef IOH_PRINT_REG ++ ioh_udc_print_regs((u32)dev->virt_addr); ++#endif ++ ioh_udc_pcd_reinit(dev); ++ IOH_DEBUG("ioh_udc_pcd_init: exit"); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++ *@brief This API is used to make this driver available to the Linux USB ++ * gadget framework ++ *@remarks The following actions are performed: ++ *- If the argument is NULL or if it doesnt have necessary callbacks, ++ * return -EINVAL ++ *- If any class driver is already bound, return -EBUSY ++ *- If drivers structure is not allocated, return -ENODEV ++ *- Hook up the gadget driver by invoking the drivers bind routine ++ *- Invoke ioh_udc_setup_ep0 to get ready for endpoint 0 traffic ++ *- Enable the host detection and resume signaling on USB ++ *@param driver Reference to the USB gadget driver structure ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_setup_ep0 ++ * - ioh_udc_clear_disconnect ++ */ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct ioh_udc_dev *dev = ioh_udc; ++ int retval; ++ ++ IOH_DEBUG("usb_gadget_register_driver: enter"); ++ if ((driver == NULL) || (driver->speed == USB_SPEED_UNKNOWN) || ++ (driver->bind == NULL) || (driver->setup == NULL) || ++ (driver->unbind == NULL) || (driver->disconnect == NULL)) { ++ IOH_LOG(KERN_ERR, "usb_gadget_register_driver: invalid\ ++ driver parameter"); ++ return -EINVAL; ++ } ++ ++ if (dev == NULL) ++ return -ENODEV; ++ ++ if (dev->driver != NULL) { ++ IOH_LOG(KERN_ERR, "usb_gadget_register_driver: already bound"); ++ return -EBUSY; ++ } ++ driver->driver.bus = NULL; ++ dev->driver = driver; ++ dev->gadget.dev.driver = &driver->driver; ++ ++ /* Invoke the bind routine of the gadget driver */ ++ retval = driver->bind(&dev->gadget); ++ ++ if (retval != 0) { ++ IOH_LOG(KERN_ERR, "usb_gadget_register_driver: binding to\ ++ %s returning %d", ++ driver->driver.name, retval); ++ dev->driver = NULL; ++ dev->gadget.dev.driver = NULL; ++ return retval; ++ } ++ /* get ready for ep0 traffic */ ++ ioh_udc_setup_ep0(dev); ++ ++ /* clear SD */ ++ ioh_udc_clear_disconnect(dev->regs); ++ ++ dev->connected = 1; ++ ++ IOH_DEBUG("usb_gadget_register_driver: exit"); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++ *@brief This API is used to make this driver unavailable to the Linux ++ * USB gadget framework ++ *@remarks The following actions are performed: ++ * - If the argument is NULL or if it doesnt match ++ * with the driver already bound, return -EINVAL ++ * - Call the function drivers unbind method ++ * - Disable the host detection and stop signaling ++ *@param driver Reference to the USB gadget driver structure ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_set_disconnect ++ */ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct ioh_udc_dev *dev = ioh_udc; ++ ++ IOH_DEBUG("usb_gadget_unregister_driver: enter"); ++ if (dev == NULL) ++ return -ENODEV; ++ ++ if ((driver == NULL) || (driver != dev->driver)) { ++ IOH_LOG(KERN_ERR, "usb_gadget_unregister_driver: invalid\ ++ driver parameter"); ++ return -EINVAL; ++ } ++ ++ ioh_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK); ++ ++ /* Assues that there are no pending requets with this driver */ ++ driver->unbind(&dev->gadget); ++ dev->gadget.dev.driver = NULL; ++ dev->driver = NULL; ++ dev->connected = 0; ++ ++ /* set SD */ ++ ioh_udc_set_disconnect(dev->regs); ++ ++ IOH_DEBUG("usb_gadget_unregister_driver: %s: unregistered", ++ driver->driver.name); ++ ++ IOH_DEBUG("usb_gadget_unregister_driver: exit"); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++/* Completes request packet ... caller MUST hold lock */ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void complete_req(struct ioh_udc_ep *ep, struct ++ * ioh_udc_request *req, int status) ++ *@brief This API is invoked from the driver when processing of a ++ * request is complete ++ *@remarks The main functions performed by this function include: ++ - Delete the request from the endpoints request queue ++ - Update the requests status with the status passed ++ - Unmap the requests buffer ++ - Reset DMA mapping status ++ - Set endpoint halted status ++ - Invoke the requests completion handler specified by the gadget driver ++ *@param ep Reference to the endpoint structure ++ *@param req Reference to the request structure ++ *@param status indicates the success/failure of completion ++ *@return none ++ */ ++static void complete_req(struct ioh_udc_ep *ep, struct ioh_udc_request *req, ++ int status) ++{ ++ struct ioh_udc_dev *dev; ++ unsigned halted = ep->halted; ++ ++ list_del_init(&req->queue); ++ ++ /* set new status if pending */ ++ if (req->req.status == -EINPROGRESS) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ ++ dev = ep->dev; ++ if (req->dma_mapped) { ++ if (ep->in) { ++ pci_unmap_single(dev->pdev, req->req.dma, ++ req->req.length, ++ PCI_DMA_TODEVICE); ++ } else { ++ pci_unmap_single(dev->pdev, req->req.dma, ++ req->req.length, ++ PCI_DMA_FROMDEVICE); ++ } ++ req->dma_mapped = 0; ++ req->req.dma = DMA_ADDR_INVALID; ++ } ++ ep->halted = 1; ++ ++ IOH_DEBUG("complete %s req %p status %d len %u", ++ ep->ep.name, &req->req, status, req->req.length); ++ IOH_DEBUG("complete %s ioh-req 0x%08x req->queue 0x%08x", ++ ep->ep.name, (u32)req, (u32)(&(req->queue))); ++ spin_unlock(&dev->lock); ++ if (!ep->in) ++ ioh_udc_ep_clear_rrdy(ep->regs); ++ ++ req->req.complete(&ep->ep, &req->req); ++ ++ spin_lock(&dev->lock); ++ ep->halted = halted; ++} ++ ++/* Empty request queue of an endpoint; caller holds spinlock */ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn void empty_req_queue(struct ioh_udc_ep *ep) ++ *@brief This API empties the request queue of an endpoint ++ *@remarks The following actions are performed: ++ * - Set endpoint halted status as 1 in ep->halted ++ * - For each request in the endpoints queue, invoke ++ * the completion handler specified by the gadget driver ++ *@param ep Reference to the endpoint structure ++ *@return none ++ *@see ++ * - complete_req ++ */ ++void empty_req_queue(struct ioh_udc_ep *ep) ++{ ++ struct ioh_udc_request *req; ++ ++ ep->halted = 1; ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, struct ioh_udc_request, queue); ++ IOH_DEBUG("empty_req_queue: complete_req ep%d%s", ep->num, ++ (ep->in ? "in" : "out")); ++ complete_req(ep, req, -ESHUTDOWN); ++ } ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_ep_enable(struct usb_ep *usbep, ++ * const struct usb_endpoint_descriptor *desc) ++ *@brief This API enables the endpoint. It is called from gadget driver ++ *@remarks The following actions are performed: ++ * - If usbep or descriptor is NULL or the endpoint is 0, ++ * return error -EINVAL ++ * - If packet size not specified in the descriptor, ++ * return -ERANGE ++ * - Configure the endpoint by invoking ioh_udc_ep_enable() ++ * - Enable Endpoint interrupts by invoking ++ * ioh_udc_enable_ep_interrupts ++ *@param usbep Reference to the USB endpoint structure ++ *@param desc Reference to the USB endpoint descriptor structure ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_ep_enable ++ * - ioh_udc_enable_ep_interrupts ++ */ ++static int ioh_udc_pcd_ep_enable(struct usb_ep *usbep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_dev *dev; ++ unsigned long iflags; ++ ++ if ((usbep == NULL) || (usbep->name == ep0_string) || (desc == NULL) || ++ (desc->bDescriptorType != USB_DT_ENDPOINT) || ++ (desc->wMaxPacketSize == 0)) { ++ return -EINVAL; ++ } ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ dev = ep->dev; ++ ++ IOH_DEBUG("ioh_udc_pcd_ep_enable ep %d", ep->num); ++ if ((dev->driver == NULL) || (dev->gadget.speed == USB_SPEED_UNKNOWN)) ++ return -ESHUTDOWN; ++ ++ ++ spin_lock_irqsave(&dev->lock, iflags); ++ ep->desc = desc; ++ ep->halted = 0; ++ ioh_udc_ep_enable(ep->regs, &ep->dev->cfg_data, desc); ++ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ ++ IOH_DEBUG("ioh_udc_pcd_ep_enable: %s enabled", usbep->name); ++ ++ spin_unlock_irqrestore(&dev->lock, iflags); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_ep_disable(struct usb_ep *usbep) ++ *@brief This API disables endpoint and is called from gadget driver ++ *@remarks The following actions are performed: ++ *- If usbep or endpoints descriptor is NULL, return error -EINVAL ++ *- Empty request queue using empty_req_queue API ++ *- Un-configure the endpoint by invoking the HAL API ioh_udc_ep_disable API ++ *- Disable interrupts using ioh_udc_disable_ep_interrupts API ++ *- Set usb endpoint descriptor for the endpoint to NULL ++ *- Set ops method for endpoint request to ioh_udc_ep_ops ++ *- Initialize endpoint queue head using INIT_LIST_HEAD API ++ *@param usbep Reference to the USB endpoint structure ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - empty_req_queue ++ * - ioh_udc_ep_disable ++ * - ioh_udc_disable_ep_interrupts ++ */ ++static int ioh_udc_pcd_ep_disable(struct usb_ep *usbep) ++{ ++ struct ioh_udc_ep *ep = NULL; ++ unsigned long iflags; ++ ++ if (usbep == NULL) ++ return -EINVAL; ++ ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ if ((usbep->name == ep0_string) || (ep->desc == NULL)) ++ return -EINVAL; ++ ++ ++ IOH_DEBUG("ioh_udc_pcd_ep_disable: ep%d%s", ep->num, ++ (ep->in ? "in" : "out")); ++ spin_lock_irqsave(&ep->dev->lock, iflags); ++ empty_req_queue(ep); ++ ep->halted = 1; ++ ioh_udc_ep_disable(ep->regs); ++ ++ /* disable interrupt */ ++ ioh_udc_disable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ ep->desc = NULL; ++ ep->ep.ops = &ioh_udc_ep_ops; ++ INIT_LIST_HEAD(&ep->queue); ++ ++ spin_unlock_irqrestore(&ep->dev->lock, iflags); ++ ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static struct usb_request *ioh_udc_alloc_request ++ * (struct usb_ep *usbep, gfp_t gfp) ++ *@brief This function allocates request structure. It iscalled by gadget driver ++ *@remarks The following actions are performed: ++ *- If usbep is NULL, return NULL ++ *- Allocate and initialize memory for request structure ++ *- If allocation fails, return NULL ++ *- Initialize the linked list usbep->queue ++ *- If DMA mode is enabled, create data pool for EP0 IN requests. If it fails, ++ * release memory allocated for request structure ++ *- Set DMA descriptor status as HOST BUSY to prevent its usage ++ *@param usbep Reference to the USB endpoint structure ++ *@param gfp Flag to be used while allocating memory ++ *@return struct usb_request * ++ * [ NULL on failure and allocated address on success ] ++ *@see ++ * - pci_pool_alloc ++ */ ++static struct usb_request *ioh_udc_alloc_request(struct usb_ep *usbep, ++ gfp_t gfp) ++{ ++ struct ioh_udc_request *req; ++ struct ioh_udc_ep *ep; ++ ++ if (usbep == NULL) ++ return NULL; ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ IOH_DEBUG("ioh_udc_alloc_request: ep %s", usbep->name); ++ req = kzalloc(sizeof(struct ioh_udc_request), gfp); ++ if (req == NULL) { ++ IOH_DEBUG("ioh_udc_alloc_request: no memory for request"); ++ return NULL; ++ } ++ memset(req, 0, sizeof(struct ioh_udc_request)); ++ req->req.dma = DMA_ADDR_INVALID; ++ INIT_LIST_HEAD(&req->queue); ++ ++ if (ep->dma != NULL) { ++ struct ioh_udc_data_dma_desc *dma_desc; ++ ++ /* ep0 in requests are allocated from data pool here */ ++ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp, ++ &req->td_data_phys); ++ if (NULL == dma_desc) { ++ kfree(req); ++ return NULL; ++ } ++ ++ IOH_DEBUG("ioh_udc_alloc_request: req = 0x%p dma_desc = 0x%p, " ++ "td_phys = 0x%08lx", ++ req, dma_desc, (unsigned long)req->td_data_phys); ++ ++ /* prevent from using desc. - set HOST BUSY */ ++ dma_desc->status |= IOH_UDC_BS_HST_BSY; ++ dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID); ++ req->td_data = dma_desc; ++ req->td_data_last = dma_desc; ++ req->chain_len = 1; ++ } ++ ++ return &req->req; ++} ++ ++/* frees pci pool descriptors of a DMA chain */ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_free_dma_chain(struct ioh_udc_dev *dev, ++ * struct ioh_udc_request *req) ++ *@brief This function frees the DMA chain created for the request ++ *@remarks The following actions are performed: ++ *- Get the virtual address of second DMA descriptor, ++ * of the chain using phys_to_virt ++ *- Release the allocated block back into PCI pool using pci_pool_free ++ *- Get the virtual address of next DMA descriptor, ++ * of the chain using phys_to_virt ++ *- Repeat steps 2, 3 for the chain length ++ *@param dev Reference to the driver structure ++ *@param req Reference to the request to be freed ++ *@return success ++ */ ++static int ioh_udc_free_dma_chain(struct ioh_udc_dev *dev, ++ struct ioh_udc_request *req) ++{ ++ int ret_val = 0; ++ struct ioh_udc_data_dma_desc *td; ++ struct ioh_udc_data_dma_desc *td_last = NULL; ++ unsigned int i; ++ ++ /* do not free first desc., will be done by free for request */ ++ td_last = req->td_data; ++ td = phys_to_virt(td_last->next); ++ ++ for (i = 1; i < req->chain_len; i++) { ++ pci_pool_free(dev->data_requests, td, ++ (dma_addr_t) td_last->next); ++ td_last = td; ++ td = phys_to_virt(td_last->next); ++ } ++ ++ return ret_val; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_create_dma_chain(struct ioh_udc_ep *ep, ++ * struct ioh_udc_request *req, unsigned long buf_len, gfp_t gfp_flags) ++ *@brief This function creates or reinitializes a DMA chain ++ *@remarks The following actions are performed: ++ *- If the endpoint is output, set the first descriptor status as HOST_BUSY ++ *- Calculate the new chain length from the requested length and the maximum ++ * packet size available on the end point ++ *- Check if a shorter chain is already allocated (req->chain_len > 1). ++ * If TRUE, invoke ioh_udc_free_dma_chain to free the DMA chain. ++ *- Generate the required number of buffers and descriptors as follows: ++ *- Invoke pci_pool_alloc with the following arguments: ++ * DMA pool for data requests (ep->dev->data_requests), ++ * gfp_flags and a pointer to the DMA address. ++ *- If pci_pool_alloc fails, return -ENOMEM. ++ *- If the descriptor is valid, assign the DMA address corresponding ++ * to 'buf' in the current descriptors dataptr field (buffer descriptor). ++ *- Link the descriptor and assign the bytes to be transferred. ++ *- Set the byte count as well as the status (HOST_BUSY) for ++ * input endpoints. For Output endpoint, set the status alone. ++ *- For the last descriptor, set the last bit in the status field ++ * and update the next field to point to itself. ++ *- Return with IOH_UDC_SUCCESS ++ *@param ep Reference to the endpoint structure ++ *@param req Reference to the request ++ *@param buf_len The buffer length ++ *@param gfp_flags Flags to be used while mapping the data buffer ++ *@return success, -ENOMEM (pci_pool_alloc invocation fails) ++ *@see ++ * - ioh_udc_free_dma_chain ++ */ ++static int ioh_udc_create_dma_chain(struct ioh_udc_ep *ep, ++ struct ioh_udc_request *req, ++ unsigned long buf_len, gfp_t gfp_flags) ++{ ++ unsigned long bytes = req->req.length; ++ unsigned int i; ++ dma_addr_t dma_addr; ++ struct ioh_udc_data_dma_desc *td = NULL; ++ struct ioh_udc_data_dma_desc *last = NULL; ++ unsigned long txbytes; ++ unsigned len; ++ ++ IOH_DEBUG("ioh_udc_create_dma_chain: bytes = %ld buf_len = %ld", ++ bytes, buf_len); ++ /* unset L bit in first desc for OUT */ ++ if (!ep->in) ++ req->td_data->status = IOH_UDC_BS_HST_BSY; ++ ++ ++ /* alloc only new desc's if not already available */ ++ len = req->req.length / buf_len; ++ if (req->req.length % buf_len) ++ len++; ++ ++ /* shorter chain already allocated before */ ++ if (req->chain_len > 1) ++ ioh_udc_free_dma_chain(ep->dev, req); ++ ++ req->chain_len = len; ++ ++ td = req->td_data; ++ /* gen. required number of descriptors and buffers */ ++ for (i = buf_len; i < bytes; i += buf_len) { ++ dma_addr = DMA_ADDR_INVALID; ++ /* create or determine next desc. */ ++ td = pci_pool_alloc(ep->dev->data_requests, gfp_flags, ++ &dma_addr); ++ if (td == NULL) ++ return -ENOMEM; ++ ++ td->status = 0; ++ td->dataptr = req->req.dma + i; /* assign buffer */ ++ ++ if ((bytes - i) >= buf_len) { ++ txbytes = buf_len; ++ } else { /* short packet */ ++ txbytes = bytes - i; ++ } ++ /* link td and assign tx bytes */ ++ if (i == buf_len) { ++ req->td_data->next = dma_addr; ++ /* set the count bytes */ ++ if (ep->in) { ++ req->td_data->status = IOH_UDC_BS_HST_BSY | ++ buf_len; ++ /* second desc */ ++ td->status = IOH_UDC_BS_HST_BSY | txbytes; ++ } else { ++ td->status = IOH_UDC_BS_HST_BSY; ++ } ++ } else { ++ last->next = dma_addr; ++ if (ep->in) ++ td->status = IOH_UDC_BS_HST_BSY | txbytes; ++ else ++ td->status = IOH_UDC_BS_HST_BSY; ++ ++ } ++ last = td; ++ } ++ /* set last bit */ ++ if (td) { ++ td->status |= IOH_UDC_DMA_LAST; ++ /* last desc. points to itself */ ++ req->td_data_last = td; ++ td->next = req->td_data_phys; ++ } ++ return 0; ++} ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_free_request(struct usb_ep *usbep, ++ * struct usb_request *usbreq) ++ *@brief This function frees request structure. It is called by gadget driver ++ *@remarks The following actions are performed: ++ * - If any of the argument is NULL, return ++ * - Warn if req->queue is empty ++ * - Otherwise, if the chain length is greater than 1, ++ * invoke ioh_udc_free_dma_chain to free the DMA chain. ++ * - If the chain length is less than 1, ++ * release memory allocated for request structure and data pool ++ * by invoking pci_pool_free ++ *@param usbep Reference to the USB endpoint structure ++ *@param usbreq Reference to the USB request ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_free_dma_chain ++ */ ++static void ioh_udc_free_request(struct usb_ep *usbep, ++ struct usb_request *usbreq) ++{ ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_request *req; ++ ++ if ((usbep == NULL) || (usbreq == NULL)) ++ return; ++ ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ req = container_of(usbreq, struct ioh_udc_request, req); ++ IOH_DEBUG("ioh_udc_free_request: %s req = 0x%p", usbep->name, req); ++ ++ if (!list_empty(&req->queue)) ++ IOH_LOG(KERN_ERR, "ioh_udc_free_request: %s req = 0x%p\ ++ queue not empty", usbep->name, req); ++ ++ if (req->td_data != NULL) { ++ if (req->chain_len > 1) ++ ioh_udc_free_dma_chain(ep->dev, req); ++ else ++ pci_pool_free(ep->dev->data_requests, req->td_data, ++ req->td_data_phys); ++ ++ } ++ kfree(req); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static int prepare_dma(struct ioh_udc_ep *ep, ++ * struct ioh_udc_request *req, gfp_t gfp) ++ *@brief This function creates and initializes the DMA chain for the request ++ *@remarks The following actions are performed: ++ *- Set buffer pointer in req->td_data->dataptr and last descriptor ++ * indication status in req->td_data->status. ++ *- Allocate and create a DMA chain using ioh_udc_create_dma_chain. ++ *- If the allocation fails, return -ENOMEM. ++ *- If the request is on an IN endpoint, update the count in the first ++ *descriptors status and mark the status (req->td_data->status) as host busy ++ * - Return success ++ *@param ep Reference to the endpoint structure ++ *@param req Reference to the request ++ *@param gfp Flag to be used while mapping the data buffer ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_create_dma_chain ++ */ ++static int prepare_dma(struct ioh_udc_ep *ep, struct ioh_udc_request *req, ++ gfp_t gfp) ++{ ++ int retval = 0; ++ IOH_DEBUG("prepare_dma: enter req->req.dma = 0x%08x", req->req.dma); ++ ++ /* set buffer pointer */ ++ req->td_data->dataptr = req->req.dma; ++ /* set last bit */ ++ req->td_data->status |= IOH_UDC_DMA_LAST; ++ ++ /* Allocate and create a DMA chain */ ++ retval = ioh_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); ++ if (retval != 0) { ++ if (retval == -ENOMEM) ++ IOH_LOG(KERN_ERR, "prepare_dma: Out of DMA memory"); ++ ++ return retval; ++ } ++ if (ep->in) { ++ if (req->req.length <= ep->ep.maxpacket) { ++ /* write tx bytes */ ++ req->td_data->status = IOH_UDC_DMA_LAST | ++ IOH_UDC_BS_HST_BSY | req->req.length; ++ } ++ } ++ ++ if (ep->in) { ++ /* if bytes < max packet then tx bytes must ++ *be written in packet per buffer mode ++ */ ++ if ((req->req.length < ep->ep.maxpacket) || (ep->num == 0)) { ++ /* write the count */ ++ req->td_data->status = (req->td_data->status & ++ ~IOH_UDC_RXTX_BYTES) | ++ req->req.length; ++ } ++ /* set HOST BUSY */ ++ req->td_data->status = (req->td_data->status & ++ ~IOH_UDC_BUFF_STS) | ++ IOH_UDC_BS_HST_BSY; ++ } ++ return retval; ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void process_zlp(struct ioh_udc_ep *ep, ++ * struct ioh_udc_request *req) ++ *@brief This function process zero length packets from the gadget driver ++ *@remarks The following actions are performed: ++ *- Invoke the requests completion routine ++ *- If there is a set config or set interface request that is not ++ * acknowledged, set CSR_DONE using ioh_udc_set_csr_done API. ++ * Reset dev->set_cfg_not_acked to 0. ++ *- If there is a setup request waiting for acknowledgement, ++ *clear the NAK on EP0 IN using ioh_udc_ep_clear_nak API and set the ++ *naking status as 0 in dev->ep[UDC_EP0IN_IDX].naking. Reset dev-> ++ * waiting_zlp_ack to 0 ++ *@param ep Reference to the endpoint structure ++ *@param req Reference to the request ++ *@return none ++ *@see ++ * - complete_req ++ * - ioh_udc_set_csr_done ++ * - ioh_udc_ep_clear_nak ++ */ ++static void process_zlp(struct ioh_udc_ep *ep, struct ioh_udc_request *req) ++{ ++ struct ioh_udc_dev *dev = ep->dev; ++ ++ IOH_DEBUG("process_zlp: enter ep%d%s", ++ ep->num, (ep->in ? "in" : "out")); ++ /* IN zlp's are handled by hardware */ ++ complete_req(ep, req, 0); ++ ++ /* if set_config or set_intf is waiting for ack by zlp ++ *then set CSR_DONE ++ */ ++ if (dev->set_cfg_not_acked) { ++ IOH_DEBUG("process_zlp: csr done"); ++ ioh_udc_set_csr_done(dev->regs); ++ dev->set_cfg_not_acked = 0; ++ } ++ /* setup command is ACK'ed now by zlp */ ++ if (!dev->stall) { ++ if (dev->waiting_zlp_ack) { ++ /* clear NAK by writing CNAK in EP0_IN */ ++ ioh_udc_ep_clear_nak(dev->ep[UDC_EP0IN_IDX].regs); ++ dev->waiting_zlp_ack = 0; ++ } ++ } ++ IOH_DEBUG("process_zlp: exit"); ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_queue(struct usb_ep *usbep, ++ * struct usb_request *usbreq, gfp_t gfp) ++ *@brief This function queues a request packet. It is called by gadget driver ++ *@remarks The following actions are performed: ++ * - If any of the argument is NULL or the request has NULL buffer ++ * or NULL completion handler, return -EINVAL ++ * - Verify if the endpoint is enabled before trying to queue. if not, ++ * return -EINVAL ++ * - Verify if the request queue is non empty. If so, return -EINVAL ++ * - If the gadget is not bound or invalid, return -ESHUTDOWN ++ * - Setup a DMA mapping for the request buffer and ++ * allocate the DMA descriptors ++ * - If usbeps request queue is empty ++ * - If length of data equals 0, call process_zlp API ++ * and return IOH_UDC_SUCCESS ++ * - if there are no IN endpoints, ++ * - Start the receive request by invoking ++ * ioh_udc_start_rxrequest ++ * - Oterwise ++ * - Wait till STALL bit in endpoint control register ++ * is cleared ++ * - Clear NAK by invoking ioh_udc_ep_clear_nak. ++ * - Enable endpoint interrupts for out endpoint ++ * - Enable TX DMA by invoking ioh_udc_set_dma ++ * - If request queue not empty, ++ * - Add the request to end of usbeps queue ++ * - Return with IOH_UDC_SUCCESS ++ *@param usbep Reference to the USB endpoint structure ++ *@param usbreq Reference to the USB request ++ *@param gfp Flag to be used while mapping the data buffer ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - prepare_dma ++ * - process_zlp ++ * - ioh_udc_start_rxrequest ++ * - ioh_udc_read_ep_control ++ * - ioh_udc_ep_clear_nak ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_set_dma ++ */ ++static int ioh_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, ++ gfp_t gfp) ++{ ++ int retval = 0; ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_dev *dev; ++ struct ioh_udc_request *req; ++ unsigned long iflags; ++ ++ IOH_DEBUG("ioh_udc_pcd_queue: enter"); ++ if ((usbep == NULL) || (usbreq == NULL) || (usbreq->complete == NULL) || ++ (usbreq->buf == NULL)) { ++ IOH_DEBUG("ioh_udc_pcd_queue: Invalid end point OR request"); ++ return -EINVAL; ++ } ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ if ((ep->desc == NULL) && (ep->num != 0)) { ++ IOH_DEBUG("ioh_udc_pcd_queue: Trying to queue before before\ ++ enabling the end point %d", ep->num); ++ /* Don't let non-control ep queue before enable */ ++ return -EINVAL; ++ } ++ req = container_of(usbreq, struct ioh_udc_request, req); ++ IOH_DEBUG("ioh_udc_pcd_queue: ep%d%s req = 0x%08x", ep->num, ++ (ep->in ? "in" : "out"), (u32)req); ++ if (!list_empty(&req->queue)) { ++ IOH_DEBUG("list_empty error: req->queue = 0x%08x\ ++ ioh-req = 0x%08x", (u32)(&(req->queue)), (u32)req); ++ return -EINVAL; ++ } ++ dev = ep->dev; ++ if ((dev->driver == NULL) || (dev->gadget.speed == USB_SPEED_UNKNOWN)) { ++ IOH_DEBUG("ioh_udc_pcd_queue: Gadget not bound/invalid"); ++ IOH_DEBUG("dev->driver = 0x%p speed = 0x%x", dev->driver, ++ dev->gadget.speed); ++ return -ESHUTDOWN; ++ } ++ spin_lock_irqsave(&ep->dev->lock, iflags); ++ /* map the buffer for dma */ ++ if ((usbreq->length != 0) && ++ ((usbreq->dma == DMA_ADDR_INVALID) || (usbreq->dma == 0))) { ++ if (ep->in) { ++ usbreq->dma = pci_map_single(dev->pdev, usbreq->buf, ++ usbreq->length, PCI_DMA_TODEVICE); ++ } else { ++ usbreq->dma = pci_map_single(dev->pdev, usbreq->buf, ++ usbreq->length, PCI_DMA_FROMDEVICE); ++ } ++ req->dma_mapped = 1; ++ } ++ ++ if (usbreq->length > 0) { /* setup the descriptors */ ++ retval = prepare_dma(ep, req, gfp); ++ if (retval != 0) { ++ /* Need to unmap before returning? ... ++ req->dma_mapped = 1; */ ++ spin_unlock_irqrestore(&dev->lock, iflags); ++ return retval; ++ } ++ } ++ ++ usbreq->actual = 0; ++ usbreq->status = -EINPROGRESS; ++ req->dma_done = 0; ++ ++ if (list_empty(&ep->queue) && !ep->halted) { ++ /* no pending transfer, so start this req */ ++ if ((usbreq->length == 0)) { ++ process_zlp(ep, req); ++ spin_unlock_irqrestore(&dev->lock, iflags); ++ return 0; ++ } ++ if (!ep->in) { ++ ioh_udc_start_rxrequest(ep, req); ++ } else { ++ /* ++ * For IN trfr the descriptors will be programmed and ++ * P bit will be set when ++ * we get an IN token ++ */ ++ ++ while (ioh_udc_read_ep_control(ep->regs) & ++ (1 << UDC_EPCTL_S)) ++ udelay(100); ++ ++ ioh_udc_ep_clear_nak(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ (1 << ep->num)); ++ /* enable DMA */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_TX); ++ } ++ } ++ IOH_DEBUG("ioh_udc_pcd_queue: desc[stat:0x%08x dptr:0x%08x\ ++ next:0x%08x]", ++ req->td_data->status, req->td_data->dataptr, ++ req->td_data->next); ++ /* Now add this request to the ep's pending requests */ ++ if (req != NULL) ++ list_add_tail(&req->queue, &ep->queue); ++ ++#ifdef IOH_PRINT_REG ++ ioh_udc_print_regs((u32)dev->virt_addr); ++#endif ++ spin_unlock_irqrestore(&dev->lock, iflags); ++ return retval; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_dequeue(struct usb_ep *usbep, ++ * struct usb_request *usbreq) ++ *@brief This function de-queues a request packet. It is called ++ * by gadget driver ++ *@remarks The following actions are performed: ++ * - If any of the argument is NULL, return -EINVAL ++ * - If the request is not in usbeps queue, return -EINVAL ++ * - Set the NAK bit ++ * - If the request is not in processing , call its\ ++ * completion handler ++ *@param usbep Reference to the USB endpoint structure ++ *@param usbreq Reference to the USB request ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_ep_set_nak ++ * - complete_req ++ */ ++static int ioh_udc_pcd_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) ++{ ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_request *req; ++ unsigned long flags; ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ if ((usbep == NULL) || (usbreq == NULL) || ++ ((ep->desc == NULL) && (ep->num != 0))) { ++ return -EINVAL; ++ } ++ IOH_DEBUG("ioh_udc_pcd_dequeue: enter ep%d%s", ep->num, ++ (ep->in ? "in" : "out")); ++ req = container_of(usbreq, struct ioh_udc_request, req); ++ spin_lock_irqsave(&ep->dev->lock, flags); ++ /* make sure it's still queued on this endpoint */ ++ list_for_each_entry(req, &ep->queue, queue) { ++ if (&req->req == usbreq) ++ break; ++ ++ } ++ ++ if (&req->req != usbreq) { ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return -EINVAL; ++ } ++ ioh_udc_ep_set_nak(ep->regs); ++ if (!list_empty(&req->queue)) ++ complete_req(ep, req, -ECONNRESET); ++ ++ spin_unlock_irqrestore(&ep->dev->lock, flags); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_set_halt(struct usb_ep *usbep, int halt) ++ *@brief This function Sets or clear the endpoint halt feature ++ *@remarks The following actions are performed: ++ * - If the ep->desc is NULL and ep->num is 0, ++ * return -EINVAL. ++ * - If ep->dev->driver is NULL and speed is unknown, ++ * return -ESHUTDOWN ++ * - If there are pending transfers, return -EAGAIN ++ * - If halt is 0, Clear the STALL for the endpoint ++ * - Otherwise, ++ * - Set the STALL for the endpoint ++ * - Enable endpoint interrupts for out endpoint ++ *@param usbep Reference to the USB endpoint structure ++ *@param halt Specifies whether to set or clear the feature ++ *@return int [ 0 on success and linux error number on failure ] ++ *@see ++ * - ioh_udc_ep_clear_stall ++ * - ioh_udc_ep_set_stall ++ * - ioh_udc_enable_ep_interrupts ++ */ ++static int ioh_udc_pcd_set_halt(struct usb_ep *usbep, int halt) ++{ ++ struct ioh_udc_ep *ep; ++ unsigned long iflags; ++ ++ if (usbep == NULL) ++ return -EINVAL; ++ ++ ++ IOH_DEBUG("ioh_udc_pcd_set_halt: %s: halt=%d", usbep->name, halt); ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ ++ if ((ep->desc == NULL) && (ep->num == 0)) { ++ IOH_DEBUG("ioh_udc_pcd_set_halt: ep->desc = 0x%x:\ ++ ep->num = 0x%x", (u32)(ep->desc), ep->num); ++ return -EINVAL; ++ } ++ if ((ep->dev->driver == NULL) || (ep->dev->gadget.speed\ ++ == USB_SPEED_UNKNOWN)) { ++ IOH_DEBUG("ioh_udc_pcd_set_halt: ep->dev->driver = 0x%x:\ ++ ep->dev->gadget.speed = 0x%x", (u32)(ep->dev->driver), ++ ep->dev->gadget.speed); ++ return -ESHUTDOWN; ++ } ++ ++ spin_lock_irqsave(&udc_stall_spinlock, iflags); ++ ++ if (!list_empty(&ep->queue)) { ++ IOH_DEBUG("ioh_udc_pcd_set_halt: list not empty"); ++ spin_unlock_irqrestore(&udc_stall_spinlock, iflags); ++ return -EAGAIN; ++ } ++ /* halt or clear halt */ ++ if (halt == 0) { ++ ioh_udc_ep_clear_stall(ep->regs); ++ } else { ++ if (ep->num == IOH_UDC_EP0) ++ ep->dev->stall = 1; ++ ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ } ++ spin_unlock_irqrestore(&udc_stall_spinlock, iflags); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static int ioh_udc_pcd_set_wedge(struct usb_ep *usbep) ++ *@brief This function Sets or clear the endpoint halt feature ++ *@param usbep Reference to the USB endpoint structure ++ *@param halt Specifies whether to set or clear the feature ++ *@return int [ 0 on success and linux error number on failure ] ++ */ ++static int ioh_udc_pcd_set_wedge(struct usb_ep *usbep) ++{ ++ struct ioh_udc_ep *ep; ++ unsigned long iflags; ++ ++ if (usbep == NULL) ++ return -EINVAL; ++ ++ ++ IOH_DEBUG("ioh_udc_pcd_set_wedge: %s:", usbep->name); ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ ++ if ((ep->desc == NULL) && (ep->num == 0)) { ++ IOH_DEBUG("ioh_udc_pcd_set_wedge: ep->desc = 0x%x:\ ++ ep->num = 0x%x", (u32)(ep->desc), ep->num); ++ return -EINVAL; ++ } ++ if ((ep->dev->driver == NULL) || (ep->dev->gadget.speed ==\ ++ USB_SPEED_UNKNOWN)) { ++ IOH_DEBUG("ioh_udc_pcd_set_wedge: ep->dev->driver = 0x%x:\ ++ ep->dev->gadget.speed = 0x%x", (u32)(ep->dev->driver), ++ ep->dev->gadget.speed); ++ return -ESHUTDOWN; ++ } ++ ++ spin_lock_irqsave(&udc_stall_spinlock, iflags); ++ ++ if (!list_empty(&ep->queue)) { ++ IOH_DEBUG("ioh_udc_pcd_set_wedge: list not empty"); ++ spin_unlock_irqrestore(&udc_stall_spinlock, iflags); ++ return -EAGAIN; ++ } ++ /* halt */ ++ if (ep->num == IOH_UDC_EP0) ++ ep->dev->stall = 1; ++ ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ ++ ep->dev->prot_stall = 1; ++ spin_unlock_irqrestore(&udc_stall_spinlock, iflags); ++ return 0; ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_pcd_fifo_flush(struct usb_ep *usbep) ++ *@brief This function Flush the FIFO of specified endpoint ++ *@remarks The following actions are performed: ++ * - Depending on the endpoint direction, flush the TX or RX FIFO ++ *@param usbep Reference to the USB endpoint structure ++ *@return none ++ *@see ++ * - ioh_udc_ep_fifo_flush ++ */ ++static void ioh_udc_pcd_fifo_flush(struct usb_ep *usbep) ++{ ++ struct ioh_udc_ep *ep; ++ ++ if (usbep == NULL) ++ return; ++ ++ ++ IOH_DEBUG("ioh_udc_pcd_fifo_flush: %s", usbep->name); ++ ++ ep = container_of(usbep, struct ioh_udc_ep, ep); ++ if ((ep->desc == NULL) && (ep->num != 0)) ++ return; ++ ++ ++ ioh_udc_ep_fifo_flush(ep->regs, ep->in); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_svc_data_out(struct ioh_udc_dev *dev, ++ * int ep_num) ++ *@brief Handles interrupts from OUT endpoint ++ *@remarks The following actions are performed: ++ *- Depending on the endpoint direction, flush the TX or RX FIFO ++ *- If the interrupt is BNA and request queue is not empty, get next request ++ * - If DMA state is DONE and dma_going flag is not set, start receive ++ * request. ++ *- If the interrupt is HE, log the error message ++ *- If the interrupt is RSS, ++ * - Set STALL useig ioh_udc_ep_set_stall API. ++ * - Enable endpoint interrupts for out endpoint ++ *- If the interrupt is RCS, ++ * - If the protocol stall flag not set, ++ * - Clear stall useing ioh_udc_ep_clear_stall API. ++ * - Otherwise ++ * - Set STALL using ioh_udc_ep_set_stall API. ++ * - Enable endpoint interrupts for out endpoint ++ *- If the interrupt is OUT_DATA, ++ * - If the protocol stall flag is set, ++ * - Set STALL using ioh_udc_ep_set_stall API. ++ * - Enable endpoint interrupts for out endpoint ++ * - Otherwise ++ * - invoke the completion routine using ioh_udc_complete_receiver ++ *- If request queue is empty, ++ * - Enable DMA using ioh_udc_set_dma API ++ *@param dev Reference to the device structure ++ *@param ep_num Endpoint that generated the interrupt ++ *@return none ++ *@see ++ * - ioh_udc_start_rxrequest ++ * - ioh_udc_ep_set_stall ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_ep_clear_stall ++ * - ioh_udc_complete_receiver ++ * - ioh_udc_set_dma ++ */ ++static void ioh_udc_svc_data_out(struct ioh_udc_dev *dev, int ep_num) ++{ ++ u32 epsts; ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_request *req = NULL; ++ ++ ep = &dev->ep[2*ep_num + 1]; ++ epsts = ep->epsts; ++ ep->epsts = 0; ++ ++ IOH_DEBUG("ioh_udc_svc_data_out: ep%d%s status = 0x%08x", ep->num, ++ (ep->in ? "in" : "out"), epsts); ++ if (epsts & (1 << UDC_EPSTS_BNA)) { /* Just log it; only in DMA mode */ ++ if (!list_empty(&ep->queue)) { ++ /* next request */ ++ req = list_entry(ep->queue.next, struct ioh_udc_request, ++ queue); ++ IOH_DEBUG("BNA on ep%dout occured", ep->num); ++ if ((req->td_data_last->status & IOH_UDC_BUFF_STS) != ++ IOH_UDC_BS_DMA_DONE) { ++ if (req->dma_going == 0) ++ ioh_udc_start_rxrequest(ep, req); ++ ++ return; ++ } ++ } ++ } ++ if (epsts & (1 << UDC_EPSTS_HE)) { /* Host error - Just log it */ ++ IOH_DEBUG("Host Error on ep%dout occured", ep->num); ++ return; ++ } ++ if (epsts & (1 << UDC_EPSTS_RSS)) { ++ IOH_DEBUG("ioh_udc_svc_data_out: RSS"); ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ } ++ if (epsts & (1 << UDC_EPSTS_RCS)) { ++ IOH_DEBUG("ioh_udc_svc_data_out: RCS prot_stall = %d", ++ dev->prot_stall); ++ if (dev->prot_stall == 0) { ++ ioh_udc_ep_clear_stall(ep->regs); ++ } else { ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ } ++ } ++ if (((epsts & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) == ++ UDC_EPSTS_OUT_DATA) { ++ if (ep->dev->prot_stall == 1) { ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ } else { ++ ioh_udc_complete_receiver(ep); ++ } ++ } ++ ++ if (list_empty(&ep->queue)) { ++ /* enable DMA */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ } ++} ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_svc_control_in(struct ioh_udc_dev *dev) ++ *@brief Handle Control IN endpoint interrupts ++ *@remarks The following actions are performed: ++ * - if the interrupt is TDC [DMA completed] or XFERDONE or TXEMPTY ++ * or ISOINDONE or HE or BNA, log the status. ++ * - If there is an TDC token ++ * - Invoke the requests completion routine. ++ * - If there is an IN token ++ * - Invoke the next request start routine. ++ *@param dev Reference to the device structure ++ *@return none ++ *@see ++ * - ioh_udc_complete_transfer ++ * - ioh_udc_start_next_txrequest ++ */ ++static void ioh_udc_svc_control_in(struct ioh_udc_dev *dev) ++{ ++ u32 epsts; ++ struct ioh_udc_ep *ep; ++ ++ ep = &dev->ep[UDC_EP0IN_IDX]; ++ epsts = ep->epsts; ++ ep->epsts = 0; ++ ++ IOH_DEBUG("ioh_udc_ep0_in intr status 0x%x", epsts); ++ ++ if ((epsts & ((1 << UDC_EPSTS_IN) | (1 << UDC_EPSTS_BNA) | ++ (1 << UDC_EPSTS_HE) | ++ (1 << UDC_EPSTS_TDC) | (1 << UDC_EPSTS_RCS) | ++ (1 << UDC_EPSTS_TXEMPTY) | ++ (1 << UDC_EPSTS_XFERDONE))) == 0) { ++ IOH_DEBUG("Non interrupt request ep%din status %x", ++ ep->num, epsts); ++ return; ++ } ++ if ((epsts & (1 << UDC_EPSTS_BNA))) { /* Just log it */ ++ IOH_DEBUG("BNA on ep%din occured", ep->num); ++ return; ++ } ++ if (epsts & (1 << UDC_EPSTS_HE)) { ++ IOH_DEBUG("Host Error on ep%din occured", ep->num); ++ return; ++ } ++ if (epsts & (1 << UDC_EPSTS_TXEMPTY)) { /* Tx empty */ ++ IOH_DEBUG("ioh_udc_ep0_in intr: TXEMPTY"); ++ } ++ if ((epsts & (1 << UDC_EPSTS_TDC)) && (!dev->stall)) { ++ /* DMA completed */ ++ IOH_DEBUG("TDC on ep%din", ep->num); ++ ioh_udc_complete_transfer(ep); ++ } ++ /* On IN interrupt, provide data if we have any */ ++ if ((epsts & (1 << UDC_EPSTS_IN)) && ++ ((epsts & (1 << UDC_EPSTS_TDC)) == 0) && ++ ((epsts & (1 << UDC_EPSTS_TXEMPTY)) == 0)) { ++ ioh_udc_start_next_txrequest(ep); ++ } ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_svc_control_out(struct ioh_udc_dev *dev) ++ *@brief Routine that handle Control OUT endpoint interrupts ++ *@param dev Reference to the device structure ++ *@return none ++ *@remarks The following actions are performed: ++ * - If Buffer NOT Available, log a debug message ++ * - If setup data present ++ *- Set device stall status to False ++ *- Invoke ioh_udc_ep_set_nak API to set SNAK field of IN endpoint register ++ *- Get the data from setup data descriptor ++ * Initialize setup data descriptor using ioh_udc_fifo_read API ++ *- Disable the TX DMA using ioh_udc_clear_dma API ++ *- Make the gadget's ep0 point to appropriate endpoint ++ * structure (ep0 IN or OUT) ++ * based on the request type ++ *- If the receive data is "Mass storage Reset", clear the protocol stall flag. ++ *- Invoke the gadget driver's setup routine with data received ++ *- if the setup routine returns a value between 0 and maximum packet size ++ * (ep0 in returns data on IN phase), ++ * - Invoke ioh_udc_ep_clear_nak API to clear NAK for In endpoint 0. ++ * - Enable DMA for RX using ioh_udc_set_dma API. ++ * - Invoke ioh_udc_ep_clear_nak API to clear NAK for In endpoint 0. ++ *- If the setup routine fails (returns < 0), ++ * - Stall the device using ioh_udc_ep_set_stall API ++ * - Enable the interrupt endpoint ++ * - Enable DMA for RX using ioh_udc_set_dma API. ++ *- Otherwise ++ * - Set 'waiting for zlp ACK' status as TRUE ++ *- If data is present ++ *- If request queue is empty, ++ * - Set the descriptor status as HOST_BUSY ++ * - Enable DMA for RX using ioh_udc_set_dma API. ++ *- Otherwise ++ * - Invoke ioh_udc_svc_data_out to handle the request. ++ * - Re-program the data descriptor using ioh_udc_ep_set_ddptr API ++ * - Enable Rx DMA using ioh_udc_set_dma API ++ *@see ++ * - ioh_udc_ep_set_nak ++ * - ioh_udc_init_setup_buff ++ * - ioh_udc_clear_dma ++ * - ioh_udc_ep_fifo_flush ++ * - ioh_udc_ep_clear_nak ++ * - ioh_udc_set_dma ++ * - ioh_udc_ep_set_stall ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_svc_data_out ++ * - ioh_udc_ep_set_ddptr ++ * - ioh_udc_ep_set_rrdy ++ */ ++static void ioh_udc_svc_control_out(struct ioh_udc_dev *dev) ++{ ++ u32 stat; ++ int setup_supported; ++ struct ioh_udc_ep *ep; ++ ++ IOH_DEBUG("ioh_udc_ep0_out"); ++ ep = &dev->ep[UDC_EP0OUT_IDX]; ++ stat = ep->epsts; ++ ep->epsts = 0; ++ ++ if (stat & (1 << UDC_EPSTS_BNA)) { ++ IOH_DEBUG("EP0: BNA"); ++ /* When we get a request, we will populate the descriptors. */ ++ /* Anything else to do? */ ++ } ++ /* If setup data */ ++ if (((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) == ++ UDC_EPSTS_OUT_SETUP) { ++ dev->stall = 0; ++ dev->ep[UDC_EP0IN_IDX].halted = 0; ++ dev->ep[UDC_EP0OUT_IDX].halted = 0; ++ /* In data not ready */ ++ ioh_udc_ep_set_nak(dev->ep[UDC_EP0IN_IDX].regs); ++ setup_data.data[0] = ep->td_stp->data12; ++ setup_data.data[1] = ep->td_stp->data34; ++ IOH_DEBUG("EP0 setup data12: 0x%x data34:0x%x", ++ ep->td_stp->data12, ep->td_stp->data34); ++ ioh_udc_init_setup_buff(ep->td_stp); ++ ioh_udc_clear_dma(dev->regs, DMA_DIR_TX); ++ ioh_udc_ep_fifo_flush(dev->ep[UDC_EP0IN_IDX].regs, ++ dev->ep[UDC_EP0IN_IDX].in); ++ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) { ++ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; ++ } else { /* OUT */ ++ dev->gadget.ep0 = &ep->ep; ++ } ++ IOH_DEBUG("EP0 setup data: 0x%x 0x%x", setup_data.data[0], ++ setup_data.data[1]); ++ spin_unlock(&dev->lock); ++ /* Mass storage Reset */ ++ if ((setup_data.data[0] == 0x0000ff21) && (setup_data.data[1] == ++ 0x00000000)) { ++ dev->prot_stall = 0; ++ IOH_DEBUG("Mass storage reset prot_stall = %d", ++ dev->prot_stall); ++ } ++ /* call gadget with setup data received */ ++ setup_supported = dev->driver->setup(&dev->gadget, ++ &setup_data.request); ++ spin_lock(&dev->lock); ++ ++ /* ep0 in returns data on IN phase */ ++ if (setup_supported >= 0 && setup_supported < ++ UDC_EP0IN_MAX_PKT_SIZE) { ++ ioh_udc_ep_clear_nak(dev->ep[UDC_EP0IN_IDX].regs); ++ /* Gadget would have queued a request when ++ we called the setup */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ ioh_udc_ep_clear_nak(ep->regs); ++ } else if (setup_supported < 0) { ++ /* if unsupported request, then stall */ ++ IOH_DEBUG("EP0 setup unsupported: ep0_set_stall"); ++ ioh_udc_ep_set_stall(dev->ep[UDC_EP0IN_IDX].regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ dev->stall = 0; ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ } else { ++ dev->waiting_zlp_ack = 1; ++ } ++ } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_OFS) == ++ UDC_EPSTS_OUT_DATA) && (dev->stall == 0)) { ++ if (list_empty(&ep->queue)) { ++ IOH_LOG(KERN_ERR, "control_out: ZLP"); ++ /* If no requests, reactivate */ ++ ep->td_data->status = ++ (ep->td_data->status & ++ ~IOH_UDC_BUFF_STS) | ++ IOH_UDC_BS_HST_RDY; ++ /* Enable RDE */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ } else { ++ /* control write */ ++ ioh_udc_svc_data_out(dev, UDC_EP0OUT_IDX); ++ /* re-program desc. pointer for possible ZLPs */ ++ ioh_udc_ep_set_ddptr(ep->regs, ++ ep->td_data_phys); ++ /* Enable RDE */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ } ++ } ++ ioh_udc_ep_set_rrdy(ep->regs); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_svc_data_in(struct ioh_udc_dev *dev, int ep_num) ++ *@brief This function process endpoint interrupts for IN endpoints ++ *@param dev Reference to the device structure ++ *@param ep_num Endpoint that generated the interrupt ++ *@return none ++ *@remarks The interrupts are processed as follows: ++ *- If the interrupt is HE, log the error message ++ *- If the interrupt is RSS, ++ * - Set STALL useig ioh_udc_ep_set_stall API ++ * - Enable endpoint interrupts for out endpoint ++ *- If the interrupt is RCS, ++ * - If the protocol stall flag not set, ++ * - Clear stall useing ioh_udc_ep_clear_stall API ++ * - Otherwise ++ * - Set STALL using ioh_udc_ep_set_stall API. ++ * - Enable endpoint interrupts for out endpoint ++ *- If the interrupt is TDC, ++ * - Invoke the completion routine using ioh_udc_complete_receiver API ++ *- If the interrupt is IN, and is not RSS/TDC/TXEMPTY ++ * - Start the next transmit request using ioh_udc_start_next_txrequest API ++ *@see ++ * - ioh_udc_ep_set_stall ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_ep_clear_stall ++ * - ioh_udc_complete_transfer ++ * - ioh_udc_start_next_txrequest ++ */ ++static void ioh_udc_svc_data_in(struct ioh_udc_dev *dev, int ep_num) ++{ ++ u32 epsts; ++ struct ioh_udc_ep *ep; ++ ep = &dev->ep[2*ep_num]; ++ epsts = ep->epsts; ++ ep->epsts = 0; ++ ++ IOH_DEBUG("ioh_udc_svc_data_in: ep%d%s status = 0x%08x", ep->num, ++ (ep->in ? "in" : "out"), epsts); ++ ++ if ((epsts & ((1 << UDC_EPSTS_IN) | (1 << UDC_EPSTS_BNA) | ++ (1 << UDC_EPSTS_HE) | ++ (1 << UDC_EPSTS_TDC) | (1 << UDC_EPSTS_RCS) | ++ (1 << UDC_EPSTS_TXEMPTY) | ++ (1 << UDC_EPSTS_RSS) | ++ (1 << UDC_EPSTS_XFERDONE))) == 0) { ++ IOH_DEBUG("Non interrupt request ep%din status %x", ++ ep->num, epsts); ++ return; ++ } ++ if ((epsts & (1 << UDC_EPSTS_BNA))) { /* Just log it */ ++ IOH_DEBUG("BNA on ep%din occured", ep->num); ++ return; ++ } ++ if (epsts & (1 << UDC_EPSTS_HE)) { ++ IOH_DEBUG("Host Error on ep%din occured", ep->num); ++ return; ++ } ++ if (epsts & (1 << UDC_EPSTS_RSS)) { ++ IOH_DEBUG("ioh_udc_svc_data_in: RSS"); ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ } ++ if (epsts & (1 << UDC_EPSTS_RCS)) { ++ IOH_DEBUG("ioh_udc_svc_data_in: RCS prot_stall = %d", ++ dev->prot_stall); ++ if (dev->prot_stall == 0) { ++ ioh_udc_ep_clear_stall(ep->regs); ++ } else { ++ ioh_udc_ep_set_stall(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ } ++ } ++ if (epsts & (1 << UDC_EPSTS_TDC)) { /* DMA completed */ ++ ioh_udc_complete_transfer(ep); ++ } ++ /* On IN interrupt, provide data if we have any */ ++ if ((epsts & (1 << UDC_EPSTS_IN)) && ++ ((epsts & (1 << UDC_EPSTS_RSS)) == 0) && ++ ((epsts & (1 << UDC_EPSTS_TDC)) == 0) && ++ ((epsts & (1 << UDC_EPSTS_TXEMPTY)) == 0)) { ++ ioh_udc_start_next_txrequest(ep); ++ } ++ IOH_DEBUG("ioh_udc_ep_in intr ep ctrl = 0x%x", ++ IOH_READ32((u32)&ep->regs->epctl)); ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_complete_transfer(struct ioh_udc_ep *ep) ++ *@brief This function completes a transfer ++ *@param ep Reference to the endpoint structure ++ *@remarks The following actions are performed: ++ * - Get the request from the queue ++ * - If the request is valid, do the following ++ *- Get the last dma descriptor. if the DMA transfer is completed, ++ * - update the request length as actual ++ *- If the actual length has been updated, ++ * - update the status field of the last request ++ * - complete the request using complete_req function ++ * - set dma in progress status as false ++ * - if there are pending requests, clear NAK using ioh_udc_ep_clear_nak ++ * and enable ++ * endpoint interrupts ++ * - if there are no pending requests, set DMA in progress status ++ * as false and disable ++ * endpoint interrupts ++ *@return none ++ *@see ++ * - complete_req ++ * - ioh_udc_read_ep_control ++ * - ioh_udc_ep_clear_nak ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_disable_ep_interrupts ++ */ ++static void ioh_udc_complete_transfer(struct ioh_udc_ep *ep) ++{ ++ struct ioh_udc_request *req; ++ ++ IOH_DEBUG("ioh_udc_complete_transfer"); ++ ++ if (!list_empty(&ep->queue)) { ++ IOH_DEBUG("list_entry"); ++ req = list_entry(ep->queue.next, struct ioh_udc_request, queue); ++ if (req && ((req->td_data_last->status & IOH_UDC_BUFF_STS) == ++ IOH_UDC_BS_DMA_DONE)) { ++#ifdef DMA_PPB_WITH_DESC_UPDATE ++ struct ioh_udc_data_dma_desc *td_data = req->td_data; ++ for (i = 0; i < req->chain_len; i++) { ++ if ((td_data->status & IOH_UDC_RXTX_STS) != ++ IOH_UDC_RTS_SUCC) { ++ IOH_LOG(KERN_ERR, "Invalid RXTX status\ ++ (0x%08x) epstatus=0x%08x\n", ++ (td_data->status & ++ IOH_UDC_RXTX_STS), ++ (int)(ep->epsts)); ++ return; ++ } ++ td_data = (struct ioh_udc_data_dma_desc *) ++ phys_to_virt(td_data->next); ++ } ++#else ++ if ((req->td_data_last->status & IOH_UDC_RXTX_STS) != ++ IOH_UDC_RTS_SUCC) { ++ IOH_LOG(KERN_ERR, "Invalid RXTX status (0x%08x)\ ++ epstatus=0x%08x\n", ++ (req->td_data_last->status & ++ IOH_UDC_RXTX_STS), ++ (int)(ep->epsts)); ++ return; ++ } ++#endif ++ req->req.actual = req->req.length; ++ req->td_data_last->status = IOH_UDC_BS_HST_BSY | ++ IOH_UDC_DMA_LAST; ++ req->td_data->status = IOH_UDC_BS_HST_BSY | ++ IOH_UDC_DMA_LAST; ++ /* complete req */ ++ complete_req(ep, req, 0); ++ req->dma_going = 0; ++ if (!list_empty(&ep->queue)) { ++ while (ioh_udc_read_ep_control(ep->regs) & ++ (1 << UDC_EPCTL_S)) ++ udelay(100); ++ ++ ioh_udc_ep_clear_nak(ep->regs); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ } else { ++ ioh_udc_disable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + ++ UDC_EPINT_OUT_EP0)); ++ } ++ } ++ } ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_complete_receiver(struct ioh_udc_ep *ep) ++ *@brief This function completes a receiver ++ *@param ep Reference to the endpoint structure ++ *@remarks The following actions are performed: ++ * - If request queue is not empty, get next request ++ * - If buffer status is DMA Done ++ * - Disable DMA using ioh_udc_clear_dma API ++ * - Get size of Rx bytes ++ * - Set the descriptor status ++ * - Complete the request using complete_req API ++ * - If there is a new/failed requests try that ++ * now using ioh_udc_start_rxrequest API ++ * - Otherwise ++ * - Set receive ready using ioh_udc_ep_set_rrdy ++ *@return none ++ *@see ++ * - ioh_udc_clear_dma ++ * - complete_req ++ * - ioh_udc_start_rxrequest ++ * - ioh_udc_ep_set_rrdy ++ */ ++static void ioh_udc_complete_receiver(struct ioh_udc_ep *ep) ++{ ++ struct ioh_udc_request *req; ++ unsigned int count; ++ ++ IOH_DEBUG("ioh_udc_complete_receiver"); ++ ++ if (!list_empty(&ep->queue)) { ++ /* next request */ ++ req = list_entry(ep->queue.next, struct ioh_udc_request, queue); ++ if (req && (req->td_data_last->status & IOH_UDC_BUFF_STS) == ++ IOH_UDC_BS_DMA_DONE) { ++ IOH_DEBUG("ioh_udc_complete_receiver: ep%d%s DMA Done", ++ ep->num, (ep->in ? "in" : "out")); ++ /* Disable DMA */ ++ ioh_udc_clear_dma(ep->dev->regs, DMA_DIR_RX); ++#ifdef DMA_PPB_WITH_DESC_UPDATE ++{ ++ /* Get Rx bytes */ ++ struct ioh_udc_data_dma_desc *td_data = req->td_data; ++ for (i = 0, count = 0; i < req->chain_len; i++) { ++ if ((td_data->status & IOH_UDC_RXTX_STS) != ++ IOH_UDC_RTS_SUCC) { ++ IOH_LOG(KERN_ERR, "Invalid RXTX status\ ++ (0x%08x) epstatus=0x%08x\n", ++ (td_data->status & ++ IOH_UDC_RXTX_STS), ++ (int)(ep->epsts)); ++ return; ++ } ++ count += td_data->status & IOH_UDC_RXTX_BYTES; ++ td_data = (struct ioh_udc_data_dma_desc *)\ ++ phys_to_virt(td_data->next); ++ } ++} ++#else ++ if ((req->td_data_last->status & IOH_UDC_RXTX_STS) != ++ IOH_UDC_RTS_SUCC) { ++ IOH_LOG(KERN_ERR, "Invalid RXTX status (0x%08x)\ ++ epstatus=0x%08x\n", ++ (req->td_data_last->status & ++ IOH_UDC_RXTX_STS), ++ (int)(ep->epsts)); ++ return; ++ } ++ count = req->td_data_last->status & IOH_UDC_RXTX_BYTES; ++#endif ++ if ((count == 0) && (req->req.length == ++ UDC_DMA_MAXPACKET)) { ++ /* on 64k packets the RXBYTES field is zero */ ++ count = UDC_DMA_MAXPACKET; ++ } ++ ++ /* Set the descriptor status */ ++ req->td_data->status |= IOH_UDC_DMA_LAST; ++ req->td_data_last->status |= IOH_UDC_BS_HST_BSY; ++ ++ req->dma_going = 0; ++ /* complete request */ ++ req->req.actual = count; ++ complete_req(ep, req, 0); ++ ++ /* If there is a new/failed requests try that now */ ++ if (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, ++ struct ioh_udc_request, queue); ++ ioh_udc_start_rxrequest(ep, req); ++ } ++ } ++#ifdef DMA_PPB_WITH_DESC_UPDATE ++ else { ++ IOH_DEBUG("ioh_udc_complete_receiver: ep%d%s \ ++ DMA not Done", ep->num, (ep->in ? "in" : "out")); ++ ioh_udc_ep_set_rrdy(ep->regs); ++ } ++#endif ++ } ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_start_next_txrequest(struct ioh_udc_ep *ep) ++ *@brief This function starts the next transmission requirement ++ *@param ep Reference to the endpoint structure ++ *@remarks The following actions are performed: ++ *- If poll demand bit is set, return ++ *- If request queue is not empty, get next request from the queue ++ *- If the DMA going flag of next request queue is 1, invoke the following ++ * actions. ++ * - Clear the descriptor pointer ++ * - Set the all descriptor status to "Host ready" ++ * - Write the descriptor pointer ++ * - Enable the Tx DMA ++ * - Set the poll demand bit ++ * - Enable the interrupts of endpoint ++ * - Clear the status of NAK ++ *@see ++ * - ioh_udc_read_ep_control ++ * - ioh_udc_ep_set_ddptr ++ * - ioh_udc_set_dma ++ * - ioh_udc_ep_set_pd ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_ep_clear_nak ++ */ ++static void ioh_udc_start_next_txrequest(struct ioh_udc_ep *ep) ++{ ++ struct ioh_udc_request *req; ++ IOH_DEBUG("ioh_udc_start_next_txrequest: enter"); ++ if (ioh_udc_read_ep_control(ep->regs) & (1 << UDC_EPCTL_P)) ++ return; ++ ++ if (!list_empty(&ep->queue)) { ++ /* next request */ ++ req = list_entry(ep->queue.next, struct ioh_udc_request, queue); ++ if (req && !req->dma_going) { ++ IOH_DEBUG("Set request: req=%p req->td_data=%p", req, ++ req->td_data); ++ if (req->td_data) { ++ struct ioh_udc_data_dma_desc *td_data; ++ ++ while (ioh_udc_read_ep_control(ep->regs) & ++ (1 << UDC_EPCTL_S)) ++ udelay(100); ++ ++ req->dma_going = 1; ++ /* Clear the descriptor pointer */ ++ ioh_udc_ep_set_ddptr(ep->regs, 0); ++ ++ td_data = req->td_data; ++ while (1) { ++ td_data->status = (td_data->status & ++ ~IOH_UDC_BUFF_STS) | ++ IOH_UDC_BS_HST_RDY; ++ if ((td_data->status & ++ IOH_UDC_DMA_LAST) == ++ IOH_UDC_DMA_LAST) ++ break; ++ ++ td_data = ++ (struct ioh_udc_data_dma_desc *)\ ++ phys_to_virt(td_data->next); ++ } ++ /* Write the descriptor pointer */ ++ ioh_udc_ep_set_ddptr(ep->regs, ++ req->td_data_phys); ++ /* Enable the Tx DMA */ ++ ioh_udc_set_dma(ep->dev->regs, DMA_DIR_TX); ++ /* Set the poll demand bit */ ++ ioh_udc_ep_set_pd(ep->regs); ++ /* Enable the interrupts of endpoint */ ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num :\ ++ ep->num + UDC_EPINT_OUT_EP0)); ++ /* Clear NAK */ ++ ioh_udc_ep_clear_nak(ep->regs); ++ } ++ } ++ } ++} ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_start_rxrequest(struct ioh_udc_ep *ep, ++ * struct ioh_udc_request *req) ++ *@brief This function starts the receive requirement. ++ *@param ep Reference to the endpoint structure ++ *@param req Reference to the request structure ++ *@remarks The following actions are performed: ++ * - Disable the Rx DMA ++ * - Set the status bits for all descriptors ++ * - Write the descriptor pointer ++ * - Enable the interrupts of endpoint ++ * - Enable the Rx DMA ++ * - Clear NAK ++ * - Set the receive ready ++ *@see ++ * - ioh_udc_clear_dma ++ * - ioh_udc_ep_set_ddptr ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_set_dma ++ * - ioh_udc_ep_clear_nak ++ * - ioh_udc_ep_set_rrdy ++ */ ++static void ioh_udc_start_rxrequest(struct ioh_udc_ep *ep, ++ struct ioh_udc_request *req) ++{ ++ struct ioh_udc_data_dma_desc *td_data; ++ ++ IOH_DEBUG("ioh_udc_start_request: enter"); ++ /* Disable Rx DMA */ ++ ioh_udc_clear_dma(ep->dev->regs, DMA_DIR_RX); ++ td_data = req->td_data; ++ ep->td_data = req->td_data; ++ /* Set the status bits for all descriptors */ ++ while (1) { ++ td_data->status = (td_data->status & ~IOH_UDC_BUFF_STS) | ++ IOH_UDC_BS_HST_RDY; ++ if ((td_data->status & IOH_UDC_DMA_LAST) == IOH_UDC_DMA_LAST) ++ break; ++ ++ td_data = (struct ioh_udc_data_dma_desc *) \ ++ phys_to_virt(td_data->next); ++ } ++ /* Write the descriptor pointer */ ++ ioh_udc_ep_set_ddptr(ep->regs, req->td_data_phys); ++ req->dma_going = 1; ++ /* Enable endpoint interrupts */ ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, 1 << ++ (ep->num + UDC_EPINT_OUT_EP0)); ++ /* Enable Rx DMA */ ++ ioh_udc_set_dma(ep->dev->regs, DMA_DIR_RX); ++ /* Clear NAK */ ++ ioh_udc_ep_clear_nak(ep->regs); ++ /* Set receive ready */ ++ ioh_udc_ep_set_rrdy(ep->regs); ++} ++ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn static void ioh_udc_postsvc_epinters(struct ioh_udc_dev *dev, ++ * int ep_num) ++ *@brief This function enables end point interrupts and clears NAK status ++ *@param dev Reference to the device structure ++ *@param ep_num End point number ++ *@return none ++ *@remarks The following actions are performed: ++ * - If the end point request queue is not empty, ++ * - Enable the endpoint interrupts using ++ * ioh_udc_enable_ep_interrupts ++ * - Clear Endpoint NAK status using ioh_udc_ep_clear_nak ++ *@see ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_ep_clear_nak ++ */ ++static void ioh_udc_postsvc_epinters(struct ioh_udc_dev *dev, int ep_num) ++{ ++ struct ioh_udc_ep *ep; ++ struct ioh_udc_request *req; ++ ep = &dev->ep[2*ep_num]; ++ ++ if (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, struct ioh_udc_request, queue); ++ ioh_udc_enable_ep_interrupts(ep->dev->regs, ++ 1 << (ep->in ? ep->num : ep->num + UDC_EPINT_OUT_EP0)); ++ ioh_udc_ep_clear_nak(ep->regs); ++ } ++} ++ ++/* Interrupt Service Routine */ ++/*!@ingroup UDC_InterfaceLayerAPI ++ *@fn irqreturn_t ioh_udc_isr(int irq, void *pdev) ++ *@brief This function handles interrupts from the IOH USB Device ++ *@param irq Interrupt request number ++ *@param dev Reference to the device structure ++ *@return none ++ *@remarks The following actions are performed: ++ *- Read the device and endpoint interrupt registers ++ *- Clear the device and endpoint interrupts using ++ * ioh_udc_write_device_interrupts ++ * and ioh_udc_write_ep_interrupts APIs respectively ++ *- If there are no interrupts, return IRQ_NONE ++ *- If there are any device interrupt(s), invoke ioh_udc_dev_isr ++ * to process those ++ *- Invoke ioh_udc_read_all_epstatus to read endpoint interrupts status ++ *- If there is interrupt asserted on EP0 IN, ++ * invoke ioh_udc_svc_control_in and ioh_udc_postsvc_epinters. ++ *- If there is interrupt asserted on EP0 OUT, invoke ioh_udc_svc_control_out ++ *- For all other IN end points for which the interrupt bit is set, ++ * invoke ioh_udc_svc_data_in and ioh_udc_postsvc_epinters. ++ *- For all other OUT end points for which the interrupt bit is set, ++ * invoke ioh_udc_svc_data_out ++ *- Return IRQ_HANDLED ++ *@see ++ * - ioh_udc_read_device_interrupts ++ * - ioh_udc_read_ep_interrupts ++ * - ioh_udc_write_device_interrupts ++ * - ioh_udc_write_ep_interrupts ++ * - ioh_udc_dev_isr ++ * - ioh_udc_svc_control_out ++ * - ioh_udc_svc_control_in ++ * - ioh_udc_svc_data_out ++ * - ioh_udc_svc_data_in ++ * - ioh_udc_read_all_epstatus ++ * - ioh_udc_postsvc_epinters ++ */ ++irqreturn_t ioh_udc_isr(int irq, void *pdev) ++{ ++ struct ioh_udc_dev *dev; ++ u32 dev_intr, ep_intr; ++ int i; ++ ++ IOH_DEBUG("ioh_udc_isr: enter"); ++ dev = (struct ioh_udc_dev *) pdev; ++ dev_intr = ioh_udc_read_device_interrupts(dev->regs); ++ ep_intr = ioh_udc_read_ep_interrupts(dev->regs); ++ ++ if (dev_intr != 0) { ++ /* Clear device interrupts */ ++ ioh_udc_write_device_interrupts(dev->regs, dev_intr); ++ } ++ if (ep_intr != 0) { ++ /* Clear ep interrupts */ ++ ioh_udc_write_ep_interrupts(dev->regs, ep_intr); ++ } ++ if ((dev_intr == 0) && (ep_intr == 0)) { ++ IOH_DEBUG("ioh_udc_isr: exit IRQ_NONE"); ++ return IRQ_NONE; ++ } ++ spin_lock(&dev->lock); ++ ++ if (dev_intr != 0) { ++ IOH_DEBUG("ioh_udc_isr: device intr 0x%x", dev_intr); ++ ioh_udc_dev_isr(dev, dev_intr); ++ } ++ ++ if (ep_intr != 0) { ++ IOH_DEBUG("ioh_udc_isr: ep intr 0x%x", ep_intr); ++ ioh_udc_read_all_epstatus(dev, ep_intr); ++ ++ /* Process Control In interrupts, if present */ ++ if (ep_intr & (1 << UDC_EPINT_IN_EP0)) { ++ ioh_udc_svc_control_in(dev); ++ ioh_udc_postsvc_epinters(dev, 0); ++ } ++ /* Process Control Out interrupts, if present */ ++ if (ep_intr & (1 << UDC_EPINT_OUT_EP0)) ++ ioh_udc_svc_control_out(dev); ++ ++ /* Process data in end point interrupts */ ++ for (i = 1; i < IOH_UDC_USED_EP_NUM; i++) { ++ if (ep_intr & (1 << i)) { ++ ioh_udc_svc_data_in(dev, i); ++ ioh_udc_postsvc_epinters(dev, i); ++ } ++ } ++ /* Process data out end point interrupts */ ++ for (i = UDC_EPINT_OUT_EP1; i < (UDC_EPINT_OUT_EP0 + ++ IOH_UDC_USED_EP_NUM); i++) { ++ if (ep_intr & (1 << i)) ++ ioh_udc_svc_data_out(dev, i - ++ UDC_EPINT_OUT_EP0); ++ } ++ } ++ spin_unlock(&dev->lock); ++ IOH_DEBUG("ioh_udc_isr: exit IRQ_HANDLED"); ++ ++ return IRQ_HANDLED; ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn void ioh_udc_activate_control_ep(struct ioh_udc_dev *dev) ++ *@brief This function enables the control endpoints for traffic after a reset ++ *@param dev Reference to the device structure ++ *@return none ++ *@remarks The following actions are performed: ++ *- Setup IN endpoint, ++ * - Flush the TX FIFO using ioh_udc_ep_fifo_flush API ++ * - Set the buffer size for TXFIFO entries of EP0_IN using ++ * ioh_udc_ep_set_bufsz API ++ * - Set max packet size of EP0 IN using ioh_udc_ep_set_maxpkt API ++ * - Initialize the IN EP Descriptor ++ *- Setup OUT endpoint, ++ * - Flush the RX FIFO using ioh_udc_ep_fifo_flush API ++ * - Set max packet size of EP0 OUT using ioh_udc_ep_set_maxpkt. ++ * - Set max packet size of EP0 OUT UDC CSR ++ * - Initialize the SETUP buffer ++ * - Write the DMA Descriptor address ++ * - Write the Setup Descriptor address ++ * - Initialize the DMA descriptor ++ * - Clear NAK ++ *@see ++ * - ioh_udc_clear_ep_control ++ * - ioh_udc_ep_fifo_flush ++ * - ioh_udc_ep_set_bufsz ++ * - ioh_udc_ep_set_maxpkt ++ * - ioh_udc_write_csr ++ * - ioh_udc_init_setup_buff ++ * - ioh_udc_ep_set_subptr ++ * - ioh_udc_ep_set_ddptr ++ * - ioh_udc_ep_clear_nak ++ */ ++void ioh_udc_activate_control_ep(struct ioh_udc_dev *dev) ++{ ++ struct ioh_udc_ep *ep; ++ u32 val; ++ /* Setup IN endpoint ----------------------------- */ ++ ep = &dev->ep[UDC_EP0IN_IDX]; ++ ++ /* Flush TX fifo */ ++ ioh_udc_clear_ep_control(ep->regs); ++ ioh_udc_ep_fifo_flush(ep->regs, ep->in); ++ ++ /* Set buffer size (tx fifo entries) of EP0_IN */ ++ ioh_udc_ep_set_bufsz(ep->regs, UDC_EP0IN_BUFF_SIZE, ep->in); ++ ++ /* Set max packet size of EP0_IN */ ++ ioh_udc_ep_set_maxpkt(ep->regs, UDC_EP0IN_MAX_PKT_SIZE); ++ ++ /* Initialize the IN EP Descriptor */ ++ ep->td_data = NULL; ++ ep->td_stp = NULL; ++ ep->td_data_phys = 0; ++ ep->td_stp_phys = 0; ++ ++ /* Setup OUT endpoint ----------------------------- */ ++ ep = &dev->ep[UDC_EP0OUT_IDX]; ++ ++ /* Flush RX fifo */ ++ ioh_udc_clear_ep_control(ep->regs); ++ ioh_udc_ep_fifo_flush(ep->regs, ep->in); ++ ++ /* Set buffer size (rx fifo entries) of EP0_OUT */ ++ ioh_udc_ep_set_bufsz(ep->regs, UDC_EP0OUT_BUFF_SIZE, ep->in); ++ ++ /* Set max packet size of EP0_OUT */ ++ ioh_udc_ep_set_maxpkt(ep->regs, UDC_EP0OUT_MAX_PKT_SIZE); ++ ++ /* Set max packet size of EP0 OUT UDC CSR */ ++ val = UDC_EP0OUT_MAX_PKT_SIZE << UDC_CSR_NE_MAX_PKT_OFS; ++ ioh_udc_write_csr(val, (u32) (&dev->csr->ne[UDC_EP0OUT_IDX])); ++ ++ /* Initialize the SETUP buffer */ ++ ioh_udc_init_setup_buff(ep->td_stp); ++ ++ /* Write dma desc address */ ++ ioh_udc_ep_set_subptr(ep->regs, ep->td_stp_phys); ++ ++ /* Write Setup desc address */ ++ ioh_udc_ep_set_ddptr(ep->regs, ep->td_data_phys); ++ ++ /* Initialize dma descriptor */ ++ ep->td_data->status = IOH_UDC_DMA_LAST; ++ ep->td_data->dataptr = dma_addr; ++ ep->td_data->next = ep->td_data_phys; ++ ++ /* Clear NAK */ ++ ioh_udc_ep_clear_nak(ep->regs); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn ioh_udc_read_all_epstatus(struct ioh_udc_dev *dev, u32 ep_intr) ++ *@brief This function read all endpoint status ++ *@param dev Reference to the device structure ++ *@param ep_intr Status of endpoint interrupt ++ *@return none ++ *@remarks The following actions are performed: ++ * - For each of the used endpoints, ++ * - Read the endpoint status using ++ * ioh_udc_read_ep_status ++ * - Invoke ioh_udc_clear_ep_status to clear ++ * the status ++ *@see ++ * - ioh_udc_read_ep_status ++ * - ioh_udc_clear_ep_status ++ */ ++static void ioh_udc_read_all_epstatus(struct ioh_udc_dev *dev, u32 ep_intr) ++{ ++ int i; ++ struct ioh_udc_ep *ep; ++ ++ for (i = 0; i < IOH_UDC_USED_EP_NUM; i++) { ++ /* IN */ ++ if (ep_intr & (0x1 << i)) { ++ ep = &dev->ep[2*i]; ++ ep->epsts = ioh_udc_read_ep_status(ep->regs); ++ ioh_udc_clear_ep_status(ep->regs, ep->epsts); ++ } ++ /* OUT */ ++ if (ep_intr & (0x10000 << i)) { ++ ep = &dev->ep[2*i+1]; ++ ep->epsts = ioh_udc_read_ep_status(ep->regs); ++ ioh_udc_clear_ep_status(ep->regs, ep->epsts); ++ } ++ } ++ return; ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn static void ioh_udc_setup_ep0(struct ioh_udc_dev *dev) ++ *@brief This function enables control endpoint for traffic ++ *@remarks The following actions are performed: ++ * - Enable ep0 interrupts using ++ * ioh_udc_enable_ep_interrupts API. ++ * - Enable device interrupts (Set configuration command ++ * interrupt, ++ * Set interface command interrupt, ENUM interrupt, ++ * USB Reset interrupt) ++ * using ioh_udc_enable_interrupts API ++ *@param dev Reference to the device structure ++ *@return none ++ *@see ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_enable_interrupts ++ */ ++static void ioh_udc_setup_ep0(struct ioh_udc_dev *dev) ++{ ++ /* enable ep0 interrupts */ ++ ioh_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 | ++ 1 << UDC_EPINT_OUT_EP0); ++ ++ /* enable device interrupts */ ++ ioh_udc_enable_interrupts(dev->regs, (1 << UDC_DEVINT_UR) | ++ (1 << UDC_DEVINT_US) | (1 << UDC_DEVINT_ES) | ++ (1 << UDC_DEVINT_ENUM) | (1 << UDC_DEVINT_SI) | ++ (1 << UDC_DEVINT_SC)); ++ IOH_DEBUG("Dev intr mask set to %x", ++ IOH_READ32((u32 *)&(dev->regs->devirqmsk))); ++ IOH_DEBUG("Ep intr mask set to %x", ++ IOH_READ32((u32 *)&(dev->regs->epirqmsk))); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ *@fn ioh_udc_init_setup_buff(struct ioh_udc_stp_dma_desc *td_stp) ++ *@brief This function initializes the SETUP buffer ++ *@param td_stp Reference to the SETP buffer structure ++ *@return none ++ */ ++static void ioh_udc_init_setup_buff(struct ioh_udc_stp_dma_desc *td_stp) ++{ ++ static u32 pky_marker; ++ IOH_DEBUG("ioh_udc_init_setup_buff"); ++ ++ if (td_stp == NULL) { ++ IOH_DEBUG("SETUP BUFF == NULL"); ++ return; ++ } ++ td_stp->reserved = ++pky_marker; ++ td_stp->data12 = 0xFFFFFFFF; ++ td_stp->data34 = 0xFFFFFFFF; ++ td_stp->status = IOH_UDC_BS_HST_RDY; ++} ++ +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc.h +@@ -0,0 +1,172 @@ ++ /*! ++ * @file ioh_udc.h ++ * @brief ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or ++ * interrupt type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++#ifndef _IOH_UDC_H_ ++#include ++#include ++ ++extern const struct usb_gadget_ops ioh_udc_ops; ++extern struct ioh_udc_dev *ioh_udc; ++ ++extern irqreturn_t ioh_udc_isr(int irq, void *pdev); ++extern int ioh_udc_pcd_init(struct ioh_udc_dev *dev); ++extern void ioh_udc_dev_isr(struct ioh_udc_dev *dev, u32 dev_intr); ++ ++/*!@ingroup UDC_Global ++ * @struct ioh_udc_request ++ * @brief Structure holding a IOH USB device request ++ */ ++struct ioh_udc_request /* request packet */ ++{ ++ struct usb_request req; /**< embedded ep request */ ++ dma_addr_t td_data_phys; /**< phys. address */ ++ struct ioh_udc_data_dma_desc *td_data;/*< first dma desc. of chain */ ++ struct ioh_udc_data_dma_desc *td_data_last;/**< last dma desc. ++ of chain */ ++ struct list_head queue; /**< associated queue */ ++ ++ /* flags */ ++ unsigned dma_going:1,/**< DMA in progress for request */ ++ dma_mapped:1,/**< DMA memory mapped ++ for request */ ++ dma_done:1; /**< DMA completed ++ for request */ ++ unsigned chain_len; /**< chain length */ ++}; ++ ++/*!@ingroup UDC_Global ++ * @struct ioh_udc_ep ++ * @brief Structure holding a IOH USB device Endpoint information ++ */ ++struct ioh_udc_ep { ++ struct usb_ep ep; /**< embedded ep request */ ++ dma_addr_t td_stp_phys;/**< for setup request */ ++ dma_addr_t td_data_phys;/**< for data request */ ++ struct ioh_udc_stp_dma_desc *td_stp; /**< for setup request */ ++ struct ioh_udc_data_dma_desc *td_data; /**< for data request */ ++ ++ struct ioh_udc_dev *dev; /**< reference to device struct */ ++ struct ioh_udc_ep_regs __iomem *regs; ++ u32 __iomem *dma; /**< dma enabled or not */ ++ const struct usb_endpoint_descriptor *desc; /**< for this ep */ ++ ++ /* queue for requests */ ++ struct list_head queue; ++ ++ unsigned num:5; /**< endpoint number */ ++ unsigned in:1; /**< endpoint is IN */ ++ unsigned halted; /**< endpoint halted? */ ++ unsigned long epsts; /**< Endpoint status */ ++}; ++ ++ ++/*!@ingroup UDC_Global ++ * @struct ioh_udc_dev ++ * @brief Structure holding complete information of the ++ IOH USB device ++ */ ++struct ioh_udc_dev { ++ struct usb_gadget gadget; /**< gadget driver data */ ++ struct usb_gadget_driver *driver;/**< reference to gadget ++ driver bound */ ++ struct pci_dev *pdev; /**< reference to the ++ PCI device */ ++ ++ /* all endpoints */ ++ struct ioh_udc_ep ep[IOH_UDC_EP_NUM]; /**< array of ++ endpoints */ ++ spinlock_t lock; /* protects all state */ ++ /* operational flags */ ++ unsigned active:1, /**< enabled the PCI device */ ++ stall:1, /**< stall requested */ ++ prot_stall:1, /**< protcol stall requested */ ++ irq_registered:1, /**< irq registered with system */ ++ mem_region:1, /**< device memory mapped */ ++ registered:1, /**< driver regsitered with system */ ++ suspended:1, /**< driver in suspended state */ ++ connected:1, /**< gadget driver associated */ ++ set_cfg_not_acked:1,/**< pending acknowledgement ++ 4 setup */ ++ waiting_zlp_ack:1;/**< pending acknowledgement 4 ZLP */ ++ ++ /* registers */ ++ struct ioh_udc_csrs __iomem *csr; /**< address of config & status ++ registers */ ++ struct ioh_udc_regs __iomem *regs; /**< address of device ++ registers */ ++ struct ioh_udc_ep_regs __iomem *ep_regs; /**< address of endpoint ++ registers */ ++ ++ /* DMA desc pools */ ++ struct pci_pool *data_requests; /**< DMA pool for ++ data requests */ ++ struct pci_pool *stp_requests; /**< DMA pool for ++ setup requests */ ++ ++ /* device data */ ++ unsigned long phys_addr; /**< of device memory */ ++ void __iomem *virt_addr;/**< for mapped device ++ memory */ ++ unsigned irq; /**< IRQ line for the device */ ++ ++ struct ioh_udc_cfg_data cfg_data;/**< current cfg, intf, ++ and alt in use */ ++}; ++ ++/*!@ingroup UDC_Global ++ * @struct ioh_udc_ep ++ * @brief Structure holding setup request data ++ */ ++union ioh_udc_setup_data { ++ u32 data[2]; /**< 8 bytes of setup data */ ++ struct usb_ctrlrequest request; /**< setup request for gadget driver */ ++}; ++ ++/*!@ingroup UDC_UtilitiesAPI ++ * @fn ioh_udc_activate_control_ep(struct ioh_udc_dev *dev) ++ * @brief Performs necessary operations to enable endpoint 0 ++ */ ++extern void ioh_udc_activate_control_ep(struct ioh_udc_dev *dev); ++ ++/*!@ingroup UDC_UtilitiesAPI ++ * @fn empty_req_queue(struct ioh_udc_ep *ep) ++ * @brief Removes all requests queued on the endpoint ++ */ ++extern void empty_req_queue(struct ioh_udc_ep *ep); ++ ++#endif /* _IOH_UDC_H_ */ +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc_hal.c +@@ -0,0 +1,1110 @@ ++ /*! ++ * @file ioh_udc_hal.c ++ * @brief ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or ++ * interrupt type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++/*#include */ ++#include ++#include "pch_common.h" ++#include "pch_debug.h" ++ ++#include ++#include "pch_udc_hal.h" ++ ++#define INLINE inline ++static u32 ioh_udc_base; ++ ++#define MAX_LOOP 200 ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn inline void ioh_udc_write_csr(unsigned long val, unsigned long ++ * addr) ++ * @remarks The following actions are performed: ++ * - Wait for any ongoing access to config registers to ++ * complete, by polling the CSR busy flag. ++ * - Write the value to the CSR register. ++ * - Wait till the write gets completed by polling the ++ * CSR busy flag. ++ * @param val [IN] value to be written to CSR register ++ * @param addr [IN] address of CSR register ++ * @retval none ++ */ ++INLINE void ioh_udc_write_csr(unsigned long val, unsigned long addr) ++{ ++ int count = MAX_LOOP; ++ ++ /* Wait till idle */ ++ while ((count > 0) &&\ ++ (IOH_READ32((unsigned long *)(IOH_UDC_CSR_BUSY_ADDR + ioh_udc_base)) & ++ IOH_UDC_CSR_BUSY)) ++ count--; ++ ++ if (count < 0) ++ IOH_DEBUG("ioh_udc_write_csr: wait error; count = %x", count); ++ ++ iowrite32(val, (unsigned long *)addr); ++ /* Wait till idle */ ++ count = MAX_LOOP; ++ while ((count > 0) && ++ (IOH_READ32((unsigned long *)(IOH_UDC_CSR_BUSY_ADDR + ioh_udc_base)) & ++ IOH_UDC_CSR_BUSY)) ++ count--; ++ ++ if (count < 0) ++ IOH_DEBUG("ioh_udc_write_csr: wait error; count = %x", count); ++ ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_csr(unsigned long addr) ++ * @remarks The main tasks performed by this method are: ++ * - This function waits for any access to internal ++ * USB_DEVICE registers to ++ * complete and then reads the config register ++ * @param addr [IN] address of CSR register ++ * @retval u32 - content of CSR register ++ */ ++INLINE u32 ioh_udc_read_csr(unsigned long addr) ++{ ++ int count = MAX_LOOP; ++ ++ /* Wait till idle */ ++ while ((count > 0) && ++ (IOH_READ32((unsigned long *)(IOH_UDC_CSR_BUSY_ADDR + ioh_udc_base)) & ++ IOH_UDC_CSR_BUSY)) ++ count--; ++ ++ if (count < 0) ++ IOH_DEBUG("ioh_udc_read_csr: wait error; count = %x", count); ++ /* Dummy read */ ++ IOH_READ32((unsigned long *)addr); ++ count = MAX_LOOP; ++ /* Wait till idle */ ++ while ((count > 0) && ++ (IOH_READ32((unsigned long *)(IOH_UDC_CSR_BUSY_ADDR + ioh_udc_base)) & ++ IOH_UDC_CSR_BUSY)) ++ count--; ++ /* actual read */ ++ if (count < 0) ++ IOH_DEBUG("ioh_udc_read_csr: wait error; count = %x", count); ++ ++ return IOH_READ32((unsigned long *)addr); ++} ++ ++/* Prints UDC device registers and endpoint irq registers */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_print_regs(u32 base) ++ * @remarks The main tasks performed by this method are: ++ * - Read UDC device registers and endpoint registers and print them ++ * @param base [IN] the remapped base address ++ */ ++void ioh_udc_print_regs(u32 base) ++{ ++ struct ioh_udc_data_dma_desc *data_desc; ++ struct ioh_udc_stp_dma_desc *stp_desc; ++ u32 *regs = (u32 *) (base + UDC_DEVCFG_ADDR); ++ u32 ddp, stp; ++ int i; ++ ++ IOH_DEBUG("print_regs: base %x", base); ++ IOH_DEBUG("------- Device registers ---------"); ++ IOH_DEBUG("dev config = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->devcfg)); ++ IOH_DEBUG("dev control = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->devctl)); ++ IOH_DEBUG("dev status = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->devsts)); ++ IOH_DEBUG("dev int's = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->devirqsts)); ++ IOH_DEBUG("dev intmask = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->devirqmsk)); ++ IOH_DEBUG("dev ep int's = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->epirqsts)); ++ IOH_DEBUG("dev ep intmask = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_regs *) ++ regs)->epirqmsk)); ++ ++ regs = (u32 *) (base + UDC_EPIN_REGS_ADDR); ++ IOH_DEBUG("------- Endpoint registers -------"); ++ for (i = 0; i < IOH_UDC_USED_EP_NUM; i++) { ++ IOH_DEBUG("Endpoint IN %1d ----------", i); ++ IOH_DEBUG("Ep control = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->epctl)); ++ IOH_DEBUG("Ep status = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->epsts)); ++ IOH_DEBUG("Buffer size = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->bufin_framenum)); ++ IOH_DEBUG("Max packet = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->bufout_maxpkt)); ++ ddp = IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->desptr); ++ IOH_DEBUG("Data Desc Ptr = %08x", ddp); ++ ++ if ((ddp != 0) && (ddp != 0xFFFFFFFF)) { ++ data_desc = phys_to_virt(ddp); ++ IOH_DEBUG(" |- status = %08x", data_desc->status); ++ IOH_DEBUG(" |- reserved = %08x", data_desc->reserved); ++ IOH_DEBUG(" |- dataptr = %08x", data_desc->dataptr); ++ IOH_DEBUG(" +- next = %08x", data_desc->next); ++ } ++ regs += UDC_EP_REG_OFS / sizeof regs; ++ } ++ regs = (u32 *) (base + UDC_EPOUT_REGS_ADDR); ++ for (i = 0; i < IOH_UDC_USED_EP_NUM; i++) { ++ IOH_DEBUG("Endpoint OUT %1d ---------", i); ++ IOH_DEBUG("Ep control = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->epctl)); ++ IOH_DEBUG("Ep status = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->epsts)); ++ IOH_DEBUG("Frame Number = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->bufin_framenum)); ++ IOH_DEBUG("Buf / Max pkt = %08x", ++ IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->bufout_maxpkt)); ++ stp = IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->subptr); ++ IOH_DEBUG("Setup buf ptr = %08x", stp); ++ ++ if ((stp != 0) && (stp != 0xFFFFFFFF)) { ++ stp_desc = phys_to_virt(stp); ++ IOH_DEBUG(" |- status = %08x", stp_desc->status); ++ IOH_DEBUG(" |- reserved = %08x", stp_desc->reserved); ++ IOH_DEBUG(" |- data12 = %08x", stp_desc->data12); ++ IOH_DEBUG(" +- data34 = %08x", stp_desc->data34); ++ } ++ ++ ddp = IOH_READ32((u32)&((struct ioh_udc_ep_regs *) ++ regs)->desptr); ++ IOH_DEBUG("Data Desc Ptr = %08x", ddp); ++ if ((ddp != 0) && (ddp != 0xFFFFFFFF)) { ++ data_desc = phys_to_virt(ddp); ++ IOH_DEBUG(" |- status = %08x", data_desc->status); ++ IOH_DEBUG(" |- reserved = %08x", data_desc->reserved); ++ IOH_DEBUG(" |- dataptr = %08x", data_desc->dataptr); ++ IOH_DEBUG(" +- next = %08x", data_desc->next); ++ } ++ regs += UDC_EP_REG_OFS / sizeof regs; ++ } ++ regs = (u32 *) (base + UDC_CSR_ADDR); ++ IOH_DEBUG("------- Endpoint Configuration ---"); ++ for (i = 0; i < IOH_UDC_USED_EP_NUM * 2; i++) { ++ IOH_DEBUG("EP config%d = %08x", i, ++ ioh_udc_read_csr((u32)&((struct ioh_udc_csrs *) ++ regs)->ne[i])); ++ } ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_init(struct ioh_udc_regs *dev) ++ * @remarks The main tasks performed by this method are: ++ * - If argument passed is NULL, return. ++ * - Set the base address for USB device registers ++ * - Invoke soft reset and PHY reset ++ * - Disable and clear the Device and endpoint interrupts ++ * - Enable dynamic CSR programming, set self powered and configure device ++ * speed in the Device Config register ++ * - Enable TX DMA, BURST and THRESHOLD modes ++ * and set BURST and THRESHOLD length. ++ * - Put the device in soft disconnect mode ++ * @param dev [IN] reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_init(struct ioh_udc_regs *dev) ++{ ++ u32 reset_reg; ++ ++ IOH_DEBUG("ioh_udc_init: enter"); ++ if (NULL == dev) { ++ IOH_LOG(KERN_ERR, "ioh_udc_init: Invalid address"); ++ return; ++ } ++ /* Set the UDC_Global variable */ ++ ioh_udc_base = (u32) dev - UDC_DEVCFG_ADDR; ++ /* Soft Reset and Reset PHY */ ++ reset_reg = (ioh_udc_base + IOH_UDC_SRST_ADDR); ++ IOH_WRITE32((1 << IOH_UDC_SRST), (u32 *)(reset_reg)); ++ IOH_WRITE32((1 << IOH_UDC_SRST) | (1 << IOH_UDC_PSRST), ++ (u32 *)(reset_reg)); ++ mdelay(1); ++ IOH_WRITE32((1 << IOH_UDC_SRST), (u32 *)(reset_reg)); ++ IOH_WRITE32(0x00, (u32 *)(reset_reg)); ++ mdelay(1); ++ ++ /* mask and clear all device interrupts */ ++ IOH_SET_ADDR_BIT((u32)&dev->devirqmsk, UDC_DEVINT_MSK); ++ IOH_SET_ADDR_BIT((u32)&dev->devirqsts, UDC_DEVINT_MSK); ++ ++ /* mask and clear all ep interrupts */ ++ IOH_SET_ADDR_BIT((u32)&dev->epirqmsk, UDC_EPINT_MSK_DISABLE_ALL); ++ IOH_SET_ADDR_BIT((u32)&dev->epirqsts, UDC_EPINT_MSK_DISABLE_ALL); ++ ++ /* enable dynamic CSR programmingi, self powered and device speed */ ++ if (speed_fs) { ++ IOH_SET_ADDR_BIT((u32)&dev->devcfg, (1 << UDC_DEVCFG_CSR_PRG) | ++ (1 << UDC_DEVCFG_SP) | /* set self powered */ ++ UDC_DEVCFG_SPD_FS); /* program speed - full speed */ ++ } else { /* defaul high speed */ ++ IOH_SET_ADDR_BIT((u32)&dev->devcfg, (1 << UDC_DEVCFG_CSR_PRG) | ++ (1 << UDC_DEVCFG_SP) | /* set self powered */ ++ UDC_DEVCFG_SPD_HS); /* program speed - high speed */ ++ } ++#ifdef DMA_PPB_WITH_DESC_UPDATE ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, ++ (IOH_UDC_THLEN << UDC_DEVCTL_THLEN_OFS) | ++ (IOH_UDC_BRLEN << UDC_DEVCTL_BRLEN_OFS) | ++ (1 << UDC_DEVCTL_MODE) | (1 << UDC_DEVCTL_BREN) | ++ (1 << UDC_DEVCTL_DU) | ++ (1 << UDC_DEVCTL_THE)); ++#else ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, ++ (IOH_UDC_THLEN << UDC_DEVCTL_THLEN_OFS) | ++ (IOH_UDC_BRLEN << UDC_DEVCTL_BRLEN_OFS) | ++ (1 << UDC_DEVCTL_MODE) | (1 << UDC_DEVCTL_BREN) | ++ (1 << UDC_DEVCTL_THE)); ++#endif ++ IOH_DEBUG("ioh_udc_init: exit"); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_exit(struct ioh_udc_regs *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Put the device in soft disconnect mode ++ * - Clear the device and endpoint interrupts ++ * and disable them ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_exit(struct ioh_udc_regs *dev) ++{ ++ IOH_DEBUG("ioh_udc_exit: enter"); ++ /* mask all device interrupts */ ++ IOH_SET_ADDR_BIT((u32)&dev->devirqmsk, UDC_DEVINT_MSK); ++ ++ /* mask all ep interrupts */ ++ IOH_SET_ADDR_BIT((u32)&dev->epirqmsk, UDC_EPINT_MSK_DISABLE_ALL); ++ ++ /* put device in disconnected state */ ++ ioh_udc_set_disconnect(dev); ++ IOH_DEBUG("ioh_udc_exit: exit"); ++} ++ ++/* Initiates a remote wakeup */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_rmt_wakeup(struct ioh_udc_regs *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Set the RES (bit 1) of the device control register ++ * - Wait for 1 msec ++ * - Clear the RES bit ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_rmt_wakeup(struct ioh_udc_regs *dev) ++{ ++ IOH_DEBUG("ioh_udc_rmt_wakeup: enter"); ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RES); ++ mdelay(1); ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RES); ++ IOH_DEBUG("ioh_udc_rmt_wakeup: exit"); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_get_frame(struct ioh_udc_regs *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Retrieve the current frame from device status register ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval int ++ * - current frame ++ */ ++int ioh_udc_get_frame(struct ioh_udc_regs *dev) ++{ ++ u32 frame; ++ ++ IOH_DEBUG("ioh_udc_get_frame: enter"); ++ frame = IOH_READ32((u32)&dev->devsts); ++ IOH_DEBUG("ioh_udc_get_frame: exit"); ++ return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_OFS; ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_clear_selfpowered (struct ioh_udc_regs __iomem *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Clear the 'SP' bit (bit 3) of the device config register ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_clear_selfpowered(struct ioh_udc_regs __iomem *dev) ++{ ++ IOH_CLR_ADDR_BIT((u32)&dev->devcfg, 1 << UDC_DEVCFG_SP); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_selfpowered (struct ioh_udc_regs __iomem *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Set the 'SP' bit (bit 3) of the device config register ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_set_selfpowered(struct ioh_udc_regs __iomem *dev) ++{ ++ IOH_SET_ADDR_BIT((u32)&dev->devcfg, 1 << UDC_DEVCFG_SP); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_disconnect (struct ioh_udc_regs __iomem *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Set the SD bit (bit 10) of device control register ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_set_disconnect(struct ioh_udc_regs __iomem *dev) ++{ ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_SD); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_get_speed (struct ioh_udc_regs __iomem *dev) ++ * @remarks The main tasks performed by this method are: ++ * - Return the speed from Device status register ENUMSPD (bit 13, 14) ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval int ++ * - The speed(LOW=1, FULL=2, HIGH=3) ++ */ ++int ioh_udc_get_speed(struct ioh_udc_regs __iomem *dev) ++{ ++ u32 val; ++ ++ val = IOH_READ32((u32)&dev->devsts); ++ return (val & UDC_DEVSTS_ENUM_SPEED_MASK) >> UDC_DEVSTS_ENUM_SPEED_OFS; ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_clear_disconnect (struct ioh_udc_regs __iomem *dev) ++ * @remarks The main tasks performed by this method are ++ * - Clear the SD bit (bit 10) and set the RES bit (bit 1) ++ * of the device control register ++ * - After 1msec, clear the RES bit (bit 1) of the device ++ * control register ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @retval none ++ */ ++void ioh_udc_clear_disconnect(struct ioh_udc_regs __iomem *dev) ++{ ++ /* Clear the disconnect */ ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RES); ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_SD); ++ mdelay(1); ++ /* Resume USB signalling */ ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RES); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_vbus_session (struct ioh_udc_regs __iomem *dev, int is_active) ++ * @remarks The main tasks performed by this method are: ++ * - If 'is_active' invoke ioh_udc_clear_disconnect to make ++ * this device available to host ++ * - Otherwise invoke ioh_udc_set_disconnect to make the ++ * device unavailable ++ * @param dev [IN] Reference to ioh_udc_regs structure ++ * @param is_active [IN] Parameter specifying the action ++ * - is_active = 0 indicating VBUS power is ending ++ * - is_active != 0 indicating VBUS power is starting ++ * @retval none ++ */ ++void ioh_udc_vbus_session(struct ioh_udc_regs __iomem *dev, int is_active) ++{ ++ if (is_active == 0) ++ ioh_udc_set_disconnect(dev); ++ else ++ ioh_udc_clear_disconnect(dev); ++ ++} ++ ++/* Stall or clear stall of endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_stall(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks The main tasks performed by this method are: ++ * - If this is a IN endpoint, flush the TX FIFO ( F bit) ++ * of the endpoint control register ++ * - Set the bit 0 (S bit) of the endpoint control register ++ * @param ep [IN] reference to structure of type ++ * ioh_udc_ep_regs ++ * @retval none ++ */ ++void ioh_udc_ep_set_stall(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ if (EP_IS_IN(ep)) { /* flush fifo */ ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_F); ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_S); ++ } else { ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_S); ++ } ++} ++ ++/* Halt or clear halt of endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_clear_stall(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks The main tasks performed by this method are: ++ * - Clear the bit 0 (S bit) of the endpoint control register ++ * - Set the bit 8 (CNAK bit) of the endpoint control register ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++void ioh_udc_ep_clear_stall(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ /* Clear the stall */ ++ IOH_CLR_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_S); ++ ++ /* clear NAK by writing CNAK */ ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_CNAK); ++} ++ ++ ++/* Set the transfer type of endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_trfr_type(struct ioh_udc_ep_regs __iomem *ep, u8 type) ++ * @remarks The main tasks performed by this method are: ++ * - Set the transfer type of endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param type [IN] type of endpoint ++ * @retval none ++ */ ++void ioh_udc_ep_set_trfr_type(struct ioh_udc_ep_regs __iomem *ep, u8 type) ++{ ++ IOH_WRITE32(((type << UDC_EPCTL_ET_OFS) & UDC_EPCTL_ET_MASK) , ++ (u32)&ep->epctl); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_bufsz(struct ioh_udc_ep_regs __iomem *ep, ++ * u32 buf_size) ++ * @remarks The main task performed by this method is: ++ * - Set the maximum packet size for the endpoint ++ * @param ep [IN] reference to structure of ++ * type ioh_udc_ep_regs ++ * @param buf_size [IN] the buffer size ++ * @retval none ++ */ ++void ioh_udc_ep_set_bufsz(struct ioh_udc_ep_regs __iomem *ep, ++ u32 buf_size, u32 ep_in) ++{ ++ u32 data; ++ if (ep_in) { ++ data = IOH_READ32((u32)&ep->bufin_framenum); ++ data = (data & 0xffff0000) | (buf_size & 0xffff); ++ IOH_WRITE32(data, (u32)&ep->bufin_framenum); ++ } else { ++ data = IOH_READ32((u32)&ep->bufout_maxpkt); ++ data = (buf_size << 16) | (data & 0xffff); ++ IOH_WRITE32(data, (u32)&ep->bufout_maxpkt); ++ } ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_maxpkt(struct ioh_udc_ep_regs __iomem *ep, ++ * u32 pkt_size) ++ * @remarks Set the Max packet size for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param pkt_size [IN] the packet size ++ * @retval none ++ */ ++/* Set the Max packet size for the endpoint */ ++void ioh_udc_ep_set_maxpkt(struct ioh_udc_ep_regs __iomem *ep, u32 pkt_size) ++{ ++ u32 data; ++ data = IOH_READ32((u32)&ep->bufout_maxpkt); ++ data = (data & 0xffff0000) | (pkt_size & 0xffff); ++ IOH_WRITE32(data, (u32)&ep->bufout_maxpkt); ++} ++ ++/* Set the Setup buffer pointer for the endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_subptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr) ++ * @remarks Set the Setup buffer pointer for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param addr [IN] address of the register ++ * @retval none ++ */ ++INLINE void ioh_udc_ep_set_subptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr) ++{ ++ IOH_WRITE32(addr, (u32)&ep->subptr); ++} ++ ++/* Set the Data descriptor pointer for the endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_ddptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr) ++ * @remarks Set the Data descriptor pointer for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param addr [IN] address of the register ++ * @retval none ++ */ ++INLINE void ioh_udc_ep_set_ddptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr) ++{ ++ IOH_WRITE32(addr, (u32)&ep->desptr); ++} ++ ++/* Set the poll demand bit for the endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_pd(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Set the poll demand bit for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++INLINE void ioh_udc_ep_set_pd(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_P); ++} ++ ++/* Set the receive ready bit for the endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Set the receive ready bit for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++INLINE void ioh_udc_ep_set_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ IOH_DEBUG("ioh_udc_ep_set_rrdy: ep%d%s", EP_NUM(ep), ++ (EP_IS_IN(ep) ? "in" : "out")); ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_RRDY); ++} ++ ++/* Clear the receive ready bit for the endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_clear_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Clear the receive ready bit for the endpoint ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++INLINE void ioh_udc_ep_clear_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ IOH_CLR_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_RRDY); ++} ++ ++/* Enabling RX/TX DMA */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_dma(struct ioh_udc_regs __iomem *dev, int dir) ++ * @remarks Set the 'TDE' or RDE bit of device control register depending ++ * on the direction specified ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param dir [IN] whether Tx or Rx ++ * - dir = DMA_DIR_RX Receive ++ * - dir = DMA_DIR_TX Transmit ++ * @retval none ++ */ ++INLINE void ioh_udc_set_dma(struct ioh_udc_regs __iomem *dev, int dir) ++{ ++ if (dir == DMA_DIR_RX) ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RDE); ++ else if (dir == DMA_DIR_TX) ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, (1 << UDC_DEVCTL_TDE)); ++ ++} ++ ++/* Disable RX/TX DMA */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_clear_dma(struct ioh_udc_regs __iomem *dev, int dir) ++ * @remarks Clear the 'TDE' or RDE bit of device control ++ * register depending on the direction specified ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param dir [IN] whether Tx or Rx ++ * - dir = DMA_DIR_RX Receive ++ * - dir = DMA_DIR_TX Transmit ++ * @retval none ++ */ ++void ioh_udc_clear_dma(struct ioh_udc_regs __iomem *dev, int dir) ++{ ++ if (dir == DMA_DIR_RX) ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_RDE); /* ++ clear RDE */ ++ else if (dir == DMA_DIR_TX) ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_TDE); ++ ++} ++ ++/* Set CSR done */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_csr_done(struct ioh_udc_regs __iomem *dev) ++ * @remarks Set the device control register CSR done field (bit 13) ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @retval none ++ */ ++void ioh_udc_set_csr_done(struct ioh_udc_regs __iomem *dev) ++{ ++ /* set CSR Done */ ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, 1 << UDC_DEVCTL_CSR_DONE); ++} ++ ++/* Set Burst length */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_burst_length(struct ioh_udc_regs __iomem *dev, u8 len) ++ * @remarks The main tasks done by this method are: ++ * - Set the device control register burst length field ++ * - Enable the bust mode ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param len [IN] burst length ++ * @retval none ++ */ ++void ioh_udc_set_burst_length(struct ioh_udc_regs __iomem *dev, u8 len) ++{ ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, (0xff << UDC_DEVCTL_BRLEN_OFS)); ++ /* set Burst length and enable burst mode*/ ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, (len << UDC_DEVCTL_BRLEN_OFS) | ++ (1 << UDC_DEVCTL_BREN)); ++} ++ ++/* Set Threshold length */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_set_threshold_length(struct ioh_udc_regs __iomem *dev, u8 len) ++ * @remarks - Set the device control register threshold ++ * length field ++ * - Enable the threshold mode ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param len [IN] burst length ++ * @retval none ++ */ ++void ioh_udc_set_threshold_length(struct ioh_udc_regs __iomem *dev, u8 len) ++{ ++ IOH_CLR_ADDR_BIT((u32)&dev->devctl, (0xff << UDC_DEVCTL_THLEN_OFS)); ++ /* set Burst Threshold length and enable threshold mode*/ ++ IOH_SET_ADDR_BIT((u32)&dev->devctl, (len << UDC_DEVCTL_THLEN_OFS) | ++ (1 << UDC_DEVCTL_THE)); ++} ++ ++/* Disable device interrupts */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_disable_interrupts(struct ioh_udc_regs __iomem *dev, u32 mask) ++ * @remarks Disables the specified interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param mask [IN] mask to disable interrupts ++ * @retval none ++ */ ++void ioh_udc_disable_interrupts(struct ioh_udc_regs __iomem *dev, u32 mask) ++{ ++ /* set the mask */ ++ IOH_SET_ADDR_BIT((u32)&dev->devirqmsk, mask); ++ IOH_DEBUG("Interrupt mask reg = %08x", ++ IOH_READ32((u32)&dev->devirqmsk)); ++} ++ ++/* Enable device interrupts */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_enable_interrupts(struct ioh_udc_regs __iomem *dev, ++ * u32 mask) ++ * @remarks Enable the specified interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param mask [IN] mask to enable interrupts ++ * @retval none ++ */ ++void ioh_udc_enable_interrupts(struct ioh_udc_regs __iomem *dev, u32 mask) ++{ ++ /* set the mask */ ++ IOH_CLR_ADDR_BIT((u32)&dev->devirqmsk, mask); ++ IOH_DEBUG("Interrupt mask reg = %08x", ++ IOH_READ32((u32)&dev->devirqmsk)); ++} ++ ++/* Disable Ep interrupts */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_disable_ep_interrupts(struct ioh_udc_regs __iomem *dev, ++ * u32 mask) ++ * @remarks Disable endpoint interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param mask [IN] mask to disable interrupts ++ * @retval none ++ */ ++void ioh_udc_disable_ep_interrupts(struct ioh_udc_regs __iomem *dev, u32 mask) ++{ ++ /* set the mask */ ++ IOH_SET_ADDR_BIT((u32)&dev->epirqmsk, mask); ++ IOH_DEBUG("Interrupt ep mask reg = %08x", ++ IOH_READ32((u32)&dev->epirqmsk)); ++} ++ ++/* Enable Ep interrupts */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_enable_ep_interrupts(struct ioh_udc_regs __iomem *dev, ++ * u32 mask) ++ * @remarks Enable endpoint interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param mask [IN] mask to enable interrupts ++ * @retval none ++ */ ++void ioh_udc_enable_ep_interrupts(struct ioh_udc_regs __iomem *dev, u32 mask) ++{ ++ /* set the mask */ ++ IOH_CLR_ADDR_BIT((u32)&dev->epirqmsk, mask); ++ IOH_DEBUG("Interrupt ep mask reg = %08x", ++ IOH_READ32((u32)&dev->epirqmsk)); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_device_interrupts(struct ioh_udc_regs __iomem *dev) ++ * @remarks Read the device interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @retval u32 ++ * - The device interrupts ++ */ ++INLINE u32 ioh_udc_read_device_interrupts(struct ioh_udc_regs __iomem *dev) ++{ ++ return IOH_READ32((u32)&dev->devirqsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_write_device_interrupts ++ * (struct ioh_udc_regs __iomem *dev, u32 val) ++ * @remarks Write device interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param val [IN] the value to be written to interrupt register ++ * @retval none ++ */ ++INLINE void ioh_udc_write_device_interrupts(struct ioh_udc_regs __iomem *dev, ++ u32 val) ++{ ++ IOH_WRITE32(val, (u32)&dev->devirqsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_ep_interrupts(struct ioh_udc_regs __iomem *dev) ++ * @remarks Read the endpoint interrupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @retval u32 ++ * - the endpoint interrupt ++ */ ++INLINE u32 ioh_udc_read_ep_interrupts(struct ioh_udc_regs __iomem *dev) ++{ ++ return IOH_READ32((u32)&dev->epirqsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_write_ep_interrupts ++ * @remarks Clear endpoint interupts ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @param val [IN] the value to be written to interrupt register ++ * @retval none ++ */ ++INLINE void ioh_udc_write_ep_interrupts(struct ioh_udc_regs __iomem *dev, ++ u32 val) ++{ ++ IOH_WRITE32(val, (u32)&dev->epirqsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_device_status ++ * @remarks Read the device status ++ * @param dev [IN] reference to structure of type ioh_udc_regs ++ * @retval u32 ++ * - the device status ++ */ ++INLINE u32 ioh_udc_read_device_status(struct ioh_udc_regs __iomem *dev) ++{ ++ return IOH_READ32((u32)&dev->devsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_ep_control(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Read the endpoint control ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval u32 ++ * - the endpoint control register value ++ */ ++INLINE u32 ioh_udc_read_ep_control(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ return IOH_READ32((u32)&ep->epctl); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_clear_ep_control(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Clear the endpoint control register ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval u32 ++ * - the endpoint control register value ++ */ ++INLINE void ioh_udc_clear_ep_control(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ return IOH_WRITE32(0, (u32)&ep->epctl); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_read_ep_status(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Read the endpoint status ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval u32 ++ * - the endpoint status ++ */ ++INLINE u32 ioh_udc_read_ep_status(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ return IOH_READ32((u32)&ep->epsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_clear_ep_status(struct ioh_udc_ep_regs __iomem *ep, ++ * u32 stat) ++ * @remarks Clear the endpoint status ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param stat [IN] endpoint status ++ * @retval none ++ */ ++INLINE void ioh_udc_clear_ep_status(struct ioh_udc_ep_regs __iomem *ep, ++ u32 stat) ++{ ++ return IOH_WRITE32(stat, (u32)&ep->epsts); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_set_nak(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Set the bit 7 (SNAK field) of the endpoint control register ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++void ioh_udc_ep_set_nak(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_SNAK); ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_clear_nak(struct ioh_udc_ep_regs __iomem *ep) ++ * @remarks Set the bit 8 (CNAK field) of the endpoint control register ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @retval none ++ */ ++void ioh_udc_ep_clear_nak(struct ioh_udc_ep_regs __iomem *ep) ++{ ++ unsigned int loopcnt = 0; ++ ++ if (IOH_READ32((u32)&ep->epctl) & (1 << UDC_EPCTL_NAK)) { ++ if (!(EP_IS_IN(ep))) { ++ while ((ioh_udc_read_ep_status(ep) & ++ (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) { ++ if (loopcnt++ > 100000) { ++ IOH_DEBUG("RxFIFO not Empty loop \ ++ count = %d", loopcnt); ++ break; ++ } ++ udelay(100); ++ } ++ } ++ while (IOH_READ32((u32)&ep->epctl) & (1 << UDC_EPCTL_NAK)) { ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_CNAK); ++ udelay(5); ++ if (loopcnt++ >= 25) { ++ IOH_DEBUG("Clear NAK not set for ep%d%s:\ ++ counter=%d", ++ EP_NUM(ep), (EP_IS_IN(ep) ? \ ++ "in" : "out"), loopcnt); ++ break; ++ } ++ } ++ } ++} ++ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_fifo_flush(struct ioh_udc_ep_regs __iomem *ep, int dir) ++ * @remarks The main tasks performed by this method are: ++ *- If the endpoint is IN, ++ * - set the bit 1 (F) of endpoint control register ++ *- Otherwise ++ * - If the Rx FIFO is not empty, ++ * - Set bit 12 (MRX FLUSH) of EP control register ++ * - Wait till MRXFIFO EMPTY (bit 8) is set in EP status register ++ * - Clear bit 12 (MRX FLUSH) of EP control register ++ * @param ep [IN] reference to structure of type ioh_udc_ep_regs ++ * @param dir [IN] direction of endpoint ++ * - dir = 0 endpoint is OUT ++ * - dir != 0 endpoint is IN ++ * @retval none ++ */ ++void ioh_udc_ep_fifo_flush(struct ioh_udc_ep_regs __iomem *ep, int dir) ++{ ++ unsigned int loopcnt = 0; ++ ++ IOH_DEBUG("ioh_udc_ep_fifo_flush: ep%d%s", EP_NUM(ep), ++ (EP_IS_IN(ep) ? "in" : "out")); ++ if (dir) { /* IN ep */ ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << UDC_EPCTL_F); ++ } else { ++ if ((ioh_udc_read_ep_status(ep) & ++ (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) { ++ IOH_SET_ADDR_BIT((u32)&ep->epctl, 1 << ++ UDC_EPCTL_MRXFLUSH); ++ /* Wait for RxFIFO Empty */ ++ while ((ioh_udc_read_ep_status(ep) & ++ (1 << UDC_EPSTS_MRXFIFO_EMP)) == 0) { ++ if (loopcnt++ > 1000000) { ++ IOH_DEBUG("RxFIFO not Empty loop\ ++ count = %d", loopcnt); ++ break; ++ } ++ udelay(100); ++ } ++ IOH_CLR_ADDR_BIT((u32)&ep->epctl, 1 << ++ UDC_EPCTL_MRXFLUSH); ++ } ++ } ++} ++ ++/* Enables endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_enable(struct ioh_udc_ep_regs __iomem *regs, ++ * struct ioh_udc_cfg_data *cfg, ++ * const struct usb_endpoint_descriptor *desc) ++ * @remarks The following actions are performed: ++ *- Set transfer type of the endpoint using ioh_udc_ep_set_trfr_type ++ * API passing desc->bmAttributes ++ *- Set Buffer size for the endpoint by ioh_udc_ep_set_bufsz ++ *- Set Maximum packet size for the endpoint using ioh_udc_ep_set_maxpkt ++ * API, passing desc->wMaxPacketSize ++ *- Flush FIFO of the endpoint by ioh_udc_ep_fifo_flush ++ *- Set NAK of the endpoint by ioh_udc_ep_set_nak ++ *- Calculate the endpoint configuration value from the following parameters ++ * and update the same in corresponding register [based on endpoint ++ * direction]using ioh_udc_write_csr API: ++ * - endpoint (ep) number ++ * - ep direction ++ * - ep transfer type mask ++ * - cfg->cur_cfg ++ * - cfg->cur_intf ++ * - cfg->cur_intf ++ * - desc->wMaxPacketSize ++ * @param regs [IN] Reference to structure ioh_udc_ep_regs ++ * @param desc [IN] endpoint descriptor ++ * @retval none ++ * @see ++ * - ioh_udc_ep_set_trfr_type ++ * - ioh_udc_ep_set_bufsz ++ * - ioh_udc_ep_set_maxpkt ++ * - ioh_udc_ep_set_nak ++ * - ioh_udc_ep_fifo_flush ++ * - ioh_udc_write_csr ++ */ ++void ioh_udc_ep_enable(struct ioh_udc_ep_regs __iomem *regs, ++ struct ioh_udc_cfg_data *cfg, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ u32 ep_num = EP_NUM(regs); ++ u32 ep_in = EP_IS_IN(regs); ++ u32 val = 0; ++ u32 buff_size = 0; ++ ++ IOH_DEBUG("ioh_udc_ep_enable: ep%x%s bmAttributes = %d\ ++ wMaxPacketSize = %d", ++ ep_num, (ep_in ? "in" : "out"), desc->bmAttributes, ++ desc->wMaxPacketSize); ++ /* set traffic type */ ++ ioh_udc_ep_set_trfr_type(regs, desc->bmAttributes); ++ /* Set buff size */ ++ if (ep_in) ++ buff_size = UDC_EPIN_BUFF_SIZE; ++ else ++ buff_size = UDC_EPOUT_BUFF_SIZE; ++ ++ ioh_udc_ep_set_bufsz(regs, buff_size, ep_in); ++ /* Set max packet size */ ++ ioh_udc_ep_set_maxpkt(regs, le16_to_cpu(desc->wMaxPacketSize)); ++ /* Set NAK */ ++ ioh_udc_ep_set_nak(regs); ++ /* Flush fifo */ ++ ioh_udc_ep_fifo_flush(regs, ep_in); ++ /* Configure the endpoint */ ++ val = ep_num << UDC_CSR_NE_NUM_OFS | ep_in << UDC_CSR_NE_DIR_OFS | ++ ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) << ++ UDC_CSR_NE_TYPE_OFS) | ++ (cfg->cur_cfg << UDC_CSR_NE_CFG_OFS) | ++ (cfg->cur_intf << UDC_CSR_NE_INTF_OFS) | ++ (cfg->cur_alt << UDC_CSR_NE_ALT_OFS) | ++ le16_to_cpu(desc->wMaxPacketSize) << ++ UDC_CSR_NE_MAX_PKT_OFS; ++ ++ if (ep_in) ++ ioh_udc_write_csr(val, (u32) (ioh_udc_base + UDC_CSR_ADDR + ++ (ep_num * 2) * 4)); ++ else ++ ioh_udc_write_csr(val, (u32) (ioh_udc_base + UDC_CSR_ADDR + ++ (ep_num * 2 + 1) * 4)); ++ ++ IOH_DEBUG("ioh_udc_ep_enable: Endpoint register = 0x%08x", val); ++} ++ ++/* Resets endpoint */ ++/*!@ingroup UDC_HALLayerAPI ++ * @fn ioh_udc_ep_disable(struct ioh_udc_ep_regs __iomem *regs) ++ * @remarks The following actions are performed: ++ *- If the endpoint is IN, ++ * - Set the bit 1 (Flush field) and clear other bit of endpoint control ++ * register ++ * - Set the bit 7 (SNAK field) and clear other bit of the endpoint control ++ * register ++ * - Set the bit 6 (IN field) of the endpoint status register ++ *- Otherwise ++ * - Set the bit 7 (SNAK field) and clear other bit of the endpoint control ++ * register ++ *- Initialize the data descriptor pointer to 0 using ++ * ioh_udc_ep_set_ddptr API ++ * @param regs [IN] Reference to structure ioh_udc_ep_regs ++ * @retval none ++ */ ++void ioh_udc_ep_disable(struct ioh_udc_ep_regs __iomem *regs) ++{ ++ if (EP_IS_IN(regs)) { ++ /* flush the fifo */ ++ IOH_WRITE32(1 << UDC_EPCTL_F , (u32)®s->epctl); ++ /* set NAK */ ++ IOH_WRITE32(1 << UDC_EPCTL_SNAK , (u32)®s->epctl); ++ ++ IOH_SET_ADDR_BIT((u32)®s->epsts, 1 << UDC_EPSTS_IN); ++ } else { ++ /* set NAK */ ++ IOH_WRITE32(1 << UDC_EPCTL_SNAK , (u32)®s->epctl); ++ } ++ /* reset desc pointer */ ++ IOH_WRITE32(0, (u32)®s->desptr); ++} +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc_hal.h +@@ -0,0 +1,1829 @@ ++ /*! ++ * @file ioh_udc_hal.h ++ * @brief This file contains the declarations for all HAL layer APIs. ++ * It also ++ * lists the various macros used by HAL layer. ++ * ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or ++ * interrupt type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++#ifndef _IOH_UDC_HAL_H_ ++#define _IOH_UDC_HAL_H_ ++ ++#include ++ ++/*! @defgroup UDC */ ++ ++/*! @defgroup UDC_Global ++@ingroup UDC ++@brief This group describes the global entities within ++ the module. ++@remarks This group includes all the global data structures ++ used within the modules. These are mainly used to ++ store the device related information, so that it can ++ be used by other functions of the modules. ++
++*/ ++ ++/*! @defgroup UDC_PCILayer ++@ingroup UDC ++@brief This group describes the PCI layer interface ++ functionalities. ++@remarks This group contains the functions and data structures ++ that are used to interface the module with PCI Layer ++ subsystem of the Kernel. ++
++*/ ++ ++/*! @defgroup UDC_InterfaceLayer ++@ingroup UDC ++@brief This group describes the Driver interface functionalities. ++@remarks This group contains the data structures and functions used ++ to interface the module driver with the kernel subsystem. ++
++*/ ++ ++/*! @defgroup UDC_HALLayer ++@ingroup UDC ++@brief This group describes the hardware specific functionalities. ++@remarks This group contains the functions and data structures used ++ by the module to communicate with the hardware. These ++ functions are device specific and designed according to the ++ device specifications. ++
++*/ ++ ++/*! @defgroup UDC_Utilities ++@ingroup UDC ++@brief This group describes the utility functionalities. ++@remarks This group contains the functions and data structures used ++ to assist the other functionalities in their operations. ++
++*/ ++ ++/*! @defgroup UDC_PCILayerAPI ++@ingroup UDC_PCILayer ++@brief This group contains the API(functions) used as the PCI ++ interface between the Kernel subsystem and the module. ++
++*/ ++ ++/*! @defgroup UDC_PCILayerFacilitators ++@ingroup UDC_PCILayer ++@brief This group contains the data structures used by the PCI ++ Layer APIs for their functionalities. ++
++*/ ++ ++/*! @defgroup UDC_InterfaceLayerAPI ++@ingroup UDC_InterfaceLayer ++@brief This group contains the API(functions) used as the Driver ++ ++
++*/ ++ ++/*! @defgroup UDC_InterfaceLayerFacilitators ++@ingroup UDC_InterfaceLayer ++@brief This group contains the data structures used by the Driver ++ interface APIs for their functionalities. ++
++*/ ++ ++/*! @defgroup UDC_HALLayerAPI ++@ingroup UDC_HALLayer ++@brief This group contains the APIs(functions) used to interact with ++ the hardware. These APIs act as an interface between the ++ hardware and the other driver functions. ++
++*/ ++ ++/*! @defgroup UDC_UtilitiesAPI ++@ingroup UDC_Utilities ++@brief This group contains the APIs(functions) used by other functions ++ in their operations. ++
++*/ ++ ++ ++/* Device Config Register */ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_ADDR ++@brief Address offset of Device Configuration Register ++*/ ++#define UDC_DEVCFG_ADDR 0x400 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SET_DESC ++@brief Bit position of SET_DESC field in ++ Device configuration register ++*/ ++#define UDC_DEVCFG_SET_DESC 18 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_CSR_PRG ++@brief Bit position of CSR_PRG field in ++ Device configuration register ++*/ ++ ++#define UDC_DEVCFG_CSR_PRG 17 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_HALT_STATUS ++@brief Bit position of HALT_STATUS field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_HALT_STATUS 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_STATUS1 ++@brief Bit position of STATUS1 field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_STATUS1 8 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_STATUS ++@brief Bit position of STATUS field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_STATUS 7 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_DIR ++@brief Bit position of DIR field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_DIR 6 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_PI ++@brief Bit position of PI field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_PI 5 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SS ++@brief Bit position of SS field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_SS 4 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SP ++@brief Bit position of SP field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_SP 3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_RWKP ++@brief Bit position of RWKP field in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_RWKP 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SPD_MASK ++@brief Mask for SPD bits in ++ Device configuration register. ++*/ ++#define UDC_DEVCFG_SPD_MASK 0x3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SPD_OFS ++*/ ++#define UDC_DEVCFG_SPD_OFS 0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SPD_HS ++*/ ++#define UDC_DEVCFG_SPD_HS 0x0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SPD_FS ++*/ ++#define UDC_DEVCFG_SPD_FS 0x1 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCFG_SPD_LS ++*/ ++#define UDC_DEVCFG_SPD_LS 0x2 ++/*#define UDC_DEVCFG_SPD_FS 0x3*/ ++ ++/* Device Control Register */ ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_ADDR ++@brief Address offset for Device control register ++*/ ++#define UDC_DEVCTL_ADDR 0x404 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_THLEN_MASK ++@brief Mask for Threshold length field of ++ Device control register. ++*/ ++#define UDC_DEVCTL_THLEN_MASK 0xff000000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_THLEN_OFS ++*/ ++#define UDC_DEVCTL_THLEN_OFS 24 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_BRLEN_MASK ++@brief Mask for Burst length field of ++ Device control register. ++*/ ++#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_BRLEN_OFS ++@brief Starting bit position of ++ Burst length field in Device ++ control register. ++*/ ++#define UDC_DEVCTL_BRLEN_OFS 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_CSR_DONE ++@brief The bit position of CSR_DONE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_CSR_DONE 13 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_DEVNAK ++@brief The bit position of DEVNAK ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_DEVNAK 12 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_SD ++@brief The bit position of SD field in ++ Device control register. ++*/ ++#define UDC_DEVCTL_SD 10 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_MODE ++@brief The bit position of MODE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_MODE 9 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_BREN ++@brief The bit position of BREN ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_BREN 8 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_THE ++@brief The bit position of THE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_THE 7 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_BF ++@brief The bit position of BF ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_BF 6 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_BE ++@brief The bit position of BE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_BE 5 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_DU ++@brief The bit position of DU ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_DU 4 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_TDE ++@brief The bit position of TDE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_TDE 3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_RDE ++@brief The bit position of RDE ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_RDE 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVCTL_RES ++@brief The bit position of RES ++ field in Device control register. ++*/ ++#define UDC_DEVCTL_RES 0 ++ ++/*! @ingroup UDC_HALLayer ++@def IOH_UDC_BRLEN ++@brief Specifies the Burst Length ++*/ ++#define IOH_UDC_BRLEN 0xF /* Burst length */ ++ ++/*! @ingroup UDC_HALLayer ++@def IOH_UDC_THLEN ++@brief Specifies the Threshold Length ++*/ ++#define IOH_UDC_THLEN 0x1F /* Threshold length */ ++ ++/*! @ingroup UDC_HALLayer ++@def DMA_DIR_RX ++@brief Specifies DMA for data receive ++*/ ++#define DMA_DIR_RX 1 ++ ++/*! @ingroup UDC_HALLayer ++@def DMA_DIR_TX ++@brief Specifies DMA for data transmit ++*/ ++#define DMA_DIR_TX 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DMA_MAXPACKET ++@brief Specifies maximum packet size for DMA ++*/ ++#define UDC_DMA_MAXPACKET 65536 ++ ++/* Device Status Register */ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ADDR ++@brief The address offset for Device Status register. ++*/ ++#define UDC_DEVSTS_ADDR 0x408 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_TS_MASK ++@brief Mask for TS field of ++ Device status register ++*/ ++#define UDC_DEVSTS_TS_MASK 0xfffc0000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_TS_OFS ++@brief Starting bit position of TS field of ++ Device status register ++*/ ++#define UDC_DEVSTS_TS_OFS 18 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_RWKPST ++@brief Bit position of RWKPST field of ++ Device status register ++*/ ++#define UDC_DEVSTS_RWKPST 17 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_PHY_ERROR ++@brief Bit position of PHY_ERROR field of ++ Device status register ++*/ ++#define UDC_DEVSTS_PHY_ERROR 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_RXFIFO_EMPTY ++@brief Bit position of RXFIFO_EMPTY field of ++ Device status register ++*/ ++#define UDC_DEVSTS_RXFIFO_EMPTY 15 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_MASK ++@brief Mask for SPEED field of ++ Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_OFS ++@brief Starting bit position of SPEED field ++ of Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_OFS 13 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_FULL ++@brief Specifies value for maximum speed for ++ SPEED field of Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_FULL 1 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_HIGH ++@brief Specifies value for high speed for ++ SPEED field of Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_HIGH 0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_LOW ++@brief Specifies value for low speed for ++ SPEED field of Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_LOW 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ENUM_SPEED_FULLX ++@brief Specifies value for full speed for ++ SPEED field of Device status register ++*/ ++#define UDC_DEVSTS_ENUM_SPEED_FULLX 3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_SUSP ++@brief Bit position of SUSP field of ++ Device status register. ++*/ ++#define UDC_DEVSTS_SUSP 12 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ALT_MASK ++@brief Mask for ALT field of ++ Device status register. ++*/ ++#define UDC_DEVSTS_ALT_MASK 0x00000f00 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_ALT_OFS ++@brief Starting bit position of ++ ALT field of Device status register. ++*/ ++#define UDC_DEVSTS_ALT_OFS 8 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_INTF_MASK ++@brief Mask for INTF field of ++ Device status register. ++*/ ++#define UDC_DEVSTS_INTF_MASK 0x000000f0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_INTF_OFS ++@brief The starting bit position for INTF field ++ in Device status register. ++*/ ++#define UDC_DEVSTS_INTF_OFS 4 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_CFG_MASK ++@brief Mask for CFG field in ++ Device status register. ++*/ ++#define UDC_DEVSTS_CFG_MASK 0x0000000f ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVSTS_CFG_OFS ++@brief Starting bit position for CFG field ++ in Device status register. ++*/ ++#define UDC_DEVSTS_CFG_OFS 0 ++ ++ ++/* Device Interrupt Register */ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_ADDR ++@brief The address offset for ++ Device interrupt register ++*/ ++#define UDC_DEVINT_ADDR 0x40c ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_RWKP ++@brief The bit position for ++ RWKP field in Device interrupt register ++*/ ++#define UDC_DEVINT_RWKP 7 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_ENUM ++@brief Bit position for ENUM field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_ENUM 6 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_SOF ++@brief Bit position for SOF field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_SOF 5 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_US ++@brief Bit position for US field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_US 4 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_UR ++@brief Bit position for UR field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_UR 3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_ES ++@brief Bit position for ES field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_ES 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_SI ++@brief Bit position for SI field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_SI 1 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_SC ++@brief Bit position for SC field in ++ Device interrupt register ++*/ ++#define UDC_DEVINT_SC 0 ++ ++/* Device Interrupt Mask Register */ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_MASK_ADDR ++@brief The address offset for ++ Device interrupt mask register ++*/ ++#define UDC_DEVINT_MSK_ADDR 0x410 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEVINT_MSK ++@brief Interrupt Mask ++*/ ++#define UDC_DEVINT_MSK 0x7f ++ ++/* Endpoint Interrupt Register */ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_ADDR ++@brief The address offset for ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_ADDR 0x414 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_MASK ++@brief Mask for OUT field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_MASK 0xffff0000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_OFS ++@brief Starting bit position for OUT field of ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_OFS 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_MASK ++@brief Mask for IN field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_MASK 0x0000ffff ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_OFS ++@brief Starting bit position for IN field of ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_OFS 0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_EP0 ++@brief Bit position for IN_EP0 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_EP0 0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_EP1 ++@brief Bit position for IN_EP1 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_EP1 1 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_EP2 ++@brief Bit position for IN_EP2 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_EP2 2 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_EP3 ++@brief Bit position for IN_EP3 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_IN_EP3 3 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_EP0 ++@brief Bit position for OUT_EP0 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_EP0 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_EP1 ++@brief Bit position for OUT_EP1 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_EP1 17 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_EP2 ++@brief Bit position for OUT_EP2 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_EP2 18 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_EP3 ++@brief Bit position for OUT_EP3 field in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_OUT_EP3 19 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_EP0_ENABLE_MSK ++@brief Mask to enable EP0 interrupt in ++ Endpoint interrupt register ++*/ ++#define UDC_EPINT_EP0_ENABLE_MSK 0x000e000e ++ ++/* Endpoint Interrupt Mask Register -----------------------------------------*/ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_MSK_ADDR ++@brief Address offset for Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_MSK_ADDR 0x418 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_MSK_MASK ++@brief Mask for OUT_MSK field of ++ Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_OUT_MSK_MASK 0xffff0000 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_OUT_MSK_OFS ++@brief Starting bit position for OUT_MSK field of ++ Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_OUT_MSK_OFS 16 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_MSK_MASK ++@brief Mask for IN_MSK field of ++ Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_IN_MSK_MASK 0x0000ffff ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_MSK_MASK ++@brief Starting bit position for IN_MSK field of ++ Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_IN_MSK_OFS 0 ++ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPINT_IN_MSK_MASK ++@brief Mask to disable all interrupts in ++ Endpoint Interrupt Mask Register ++*/ ++#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff ++ ++/* mask non-EP0 endpoints */ ++/*! @ingroup UDC_HALLayer ++@def UDC_EPDATAINT_MSK_DISABLE ++@brief mask non-EP0 endpoints ++*/ ++#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe ++ ++/* mask all dev interrupts */ ++/*! @ingroup UDC_HALLayer ++@def UDC_DEV_MSK_DISABLE ++@brief mask all dev interrupts ++*/ ++#define UDC_DEV_MSK_DISABLE 0x7f ++ ++/* UDC CSR Busy status Register -----------------------------------------*/ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_CSR_BUSY_ADDR ++@brief Address offset for UDC CSR Busy status Register ++*/ ++#define IOH_UDC_CSR_BUSY_ADDR 0x4f0 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_CSR_BUSY ++@brief Bit position of CSR field in ++ UDC CSR Busy status Register ++*/ ++#define IOH_UDC_CSR_BUSY 1 ++ ++/* SOFT RESET Register ------------------------------------------------------*/ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_SRST_ADDR ++@brief Address offset for UDC Soft reset Register ++*/ ++#define IOH_UDC_SRST_ADDR 0x4fc ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_PHY_RESET ++@brief Bit position of PSRST field in ++ UDC Soft Reset Register ++*/ ++#define IOH_UDC_PSRST 1 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_SOFT_RESET ++@brief Bit position of SRST field in ++ UDC Soft Reset Register ++*/ ++#define IOH_UDC_SRST 0 ++ ++/* Endpoint-specific CSR's --------------------------------------------------*/ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPREGS_ADDR ++@brief address offset for Endpoint-specific CSR ++*/ ++#define UDC_EPREGS_ADDR 0x0 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_REGS_ADDR ++@brief address offset for EPIN register ++*/ ++#define UDC_EPIN_REGS_ADDR 0x0 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_REGS_ADDR ++@brief address offset for EPOUT register ++*/ ++#define UDC_EPOUT_REGS_ADDR 0x200 ++ ++/*!@ingroup UDC_HALLayer ++@def EP_IS_IN(ep) ++*/ ++#define EP_IS_IN(ep) (((u32)(ep)) < (ioh_udc_base + UDC_EPOUT_REGS_ADDR)) ++ ++/*!@ingroup UDC_HALLayer ++@def EP_NUM(ep) ++*/ ++#define EP_NUM(ep) ((((u32)(ep) - (ioh_udc_base +\ ++ UDC_EPREGS_ADDR)) / 0x20) & 0xf) ++ ++/* Endpoint Control Registers */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ADDR ++@brief Address offset for Endpoint Control Register ++*/ ++#define UDC_EPCTL_ADDR 0x0 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_RRDY ++@brief Bit position of RRDY field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_RRDY 9 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_CNAK ++@brief Bit position of CNAK field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_CNAK 8 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_SNAK ++@brief Bit position of SNAK field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_SNAK 7 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_NAK ++@brief Bit position of NAK field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_NAK 6 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_MASK ++@brief Mask for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_MASK 0x00000030 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_OFS ++@brief Starting bit position for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_OFS 4 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_CONTROL ++@brief Value for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_CONTROL 0 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_ISO ++@brief Value for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_ISO 1 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_BULK ++@brief Value for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_BULK 2 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_ET_INTERRUPT ++@brief Value for ET field in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_ET_INTERRUPT 3 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_MRXFLUSH ++@brief Bit position for MRXFLUSH in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_MRXFLUSH 12 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_P ++@brief Bit position for P in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_P 3 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_SN ++@brief Bit position for SN in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_SN 2 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_F ++@brief Bit position for F in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_F 1 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPCTL_S ++@brief Bit position for S in ++ Endpoint Control Register ++*/ ++#define UDC_EPCTL_S 0 ++ ++/* Endpoint Status Registers */ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_ADDR ++@brief Address offset for Endpoint Status Register ++*/ ++#define UDC_EPSTS_ADDR 0x4 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_XFERDONE ++@brief Bit position for XFERDONE in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_XFERDONE 27 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_RSS ++@brief Bit position for RSS in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_RSS 26 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_RCS ++@brief Bit position for RCS in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_RCS 25 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_TXEMPTY ++@brief Bit position for TXEMPTY in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_TXEMPTY 24 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_ISOINDONE ++@brief Bit position for ISOINDONE in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_ISOINDONE 23 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_RX_PKT_SIZE_MASK ++@brief Mask for RX_PKT_SIZE field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_RX_PKT_SIZE_OFS ++@brief Starting offset for RX_PKT_SIZE field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_RX_PKT_SIZE_OFS 11 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_TDC ++@brief Bit position for TDC field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_TDC 10 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_HE ++@brief Bit position for HE field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_HE 9 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_MRXFIFO_EMP ++@brief Bit position for MRXFIFO EMPTY field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_MRXFIFO_EMP 8 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_BNA ++@brief Bit position for BNA field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_BNA 7 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_IN ++@brief Bit position for IN field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_IN 6 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_MASK ++@brief Mask for OUT field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_OUT_MASK 0x00000030 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_OFS ++@brief Starting bit position for OUT field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_OUT_OFS 4 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_DATA ++@brief Value for OUT field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_OUT_DATA 1 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_DATA_CLEAR ++@brief Clear OUT field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_OUT_DATA_CLEAR 0x10 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_DATA_CLEAR ++@brief Clear OUT field in ++ Endpoint Status Register ++*/ ++#define UDC_EPSTS_OUT_SETUP 2 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_DATA_SETUP_CLEAR ++*/ ++#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPSTS_OUT_CLEAR ++*/ ++#define UDC_EPSTS_OUT_CLEAR 0x30 ++ ++/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_BUFF_SIZE_ADDR ++@brief Address offset for Endpoint Buffer Size IN register ++*/ ++#define UDC_EPIN_BUFF_SIZE_ADDR 0x8 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_FRAME_NUMBER_ADDR ++@brief Address offset for Receive Packet Frame Number OUT Register ++*/ ++#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_BUFF_SIZE_MASK ++@brief Mask for EPIN buffer size field in ++ Endpoint Buffer Size IN register ++*/ ++#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_BUFF_SIZE_OFS ++@brief Starting bit position for EPIN buffer size field in ++ Endpoint Buffer Size IN register ++*/ ++#define UDC_EPIN_BUFF_SIZE_OFS 0 ++/* EP0in txfifo = 256 bytes*/ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0IN_BUFF_SIZE ++@brief EPIN0 Buffer Size ++*/ ++#define UDC_EP0IN_BUFF_SIZE 64 ++ ++/* EP0in fullspeed txfifo = 128 bytes*/ ++/*!@ingroup UDC_HALLayer ++@def UDC_FS_EPIN0_BUFF_SIZE ++@brief EPIN0 Buffer Size ++*/ ++#define UDC_FS_EPIN0_BUFF_SIZE 32 ++ ++/* fifo size mult = fifo size / max packet */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN0_BUFF_SIZE_MULT ++*/ ++#define UDC_EPIN_BUFF_SIZE_MULT 2 ++ ++/* EPin data fifo size = 2048 bytes DOUBLE BUFFERING */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_BUFF_SIZE ++@brief Buffer size ++*/ ++#define UDC_EPIN_BUFF_SIZE 512 ++/* EPin small INT data fifo size = 128 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPIN_SMALLINT_BUFF_SIZE ++@brief Buffer size ++*/ ++#define UDC_EPIN_SMALLINT_BUFF_SIZE 32 ++ ++/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */ ++/*!@ingroup UDC_HALLayer ++@def UDC_FS_EPIN_BUFF_SIZE ++@brief Buffer size ++*/ ++#define UDC_FS_EPIN_BUFF_SIZE 32 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_FRAME_NUMBER_MASK ++@brief Mask for frame number ++*/ ++#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_FRAME_NUMBER_OFS ++@brief Starting bit position for frame number ++*/ ++#define UDC_EPOUT_FRAME_NUMBER_OFS 0 ++ ++/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_BUFF_SIZE_ADDR ++@brief Address offset for Endpoint Buffer Size OUT Register ++*/ ++#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP_MAX_PKT_SIZE_ADDR ++@brief Address offset for Max Packet Size Register ++*/ ++#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_BUFF_SIZE_MASK ++@brief Mask for EPOUT buffer size field ++*/ ++#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_BUFF_SIZE_OFS ++@brief Starting bit position for EPOUT buffer size field ++*/ ++#define UDC_EPOUT_BUFF_SIZE_OFS 16 ++ ++/* EP0out rxfifo = 256 bytes*/ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0OUT_BUFF_SIZE ++@brief EP0 OUT Buffer Size ++*/ ++#define UDC_EP0OUT_BUFF_SIZE 64 ++ ++/* EPout data fifo size = 2048 bytes DOUBLE BUFFERING */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EPOUT_BUFF_SIZE ++@brief Buffer size ++*/ ++#define UDC_EPOUT_BUFF_SIZE 512 ++ ++/* EPout fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */ ++/*!@ingroup UDC_HALLayer ++@def UDC_FS_EPOUT_BUFF_SIZE ++@brief Buffer size ++*/ ++#define UDC_FS_EPOUT_BUFF_SIZE 32 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP_MAX_PKT_SIZE_MASK ++@brief Mask for EP maximum packet size ++*/ ++#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP_MAX_PKT_SIZE_OFS ++@brief Starting bit position for EP maximum packet size ++*/ ++#define UDC_EP_MAX_PKT_SIZE_OFS 0 ++/* EP0in max packet size = 64 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0IN_MAX_PKT_SIZE ++@brief EP0 IN maximum packet size ++*/ ++#define UDC_EP0IN_MAX_PKT_SIZE 64 ++/* EP0out max packet size = 64 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0OUT_MAX_PKT_SIZE ++@brief EP0 OUT maximum packet size ++*/ ++#define UDC_EP0OUT_MAX_PKT_SIZE 64 ++ ++/* Bulk max packet size = 512 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_BULK_MAX_PKT_SIZE ++@brief BULK maximum packet size ++*/ ++#define UDC_BULK_MAX_PKT_SIZE 512 ++ ++/* EP0in fullspeed max packet size = 64 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_FS_EP0IN_MAX_PKT_SIZE ++@brief Full speed EP0 IN maximum packet size ++*/ ++#define UDC_FS_EP0IN_MAX_PKT_SIZE 64 ++/* EP0out fullspeed max packet size = 64 bytes */ ++/*!@ingroup UDC_HALLayer ++@def UDC_FS_EP0OUT_MAX_PKT_SIZE ++@brief Full speed EP0 OUT maximum packet size ++*/ ++#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64 ++ ++/* Offset to next EP registers */ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP_REG_OFS ++@brief Offset to next EP registers ++*/ ++#define UDC_EP_REG_OFS 0x20 ++ ++/* UDC_Global CSR's */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_ADD ++@brief Offset of CSR register ++*/ ++#define UDC_CSR_ADDR 0x500 ++ ++/* EP NE bits */ ++/* EP number */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_NUM_MASK ++*/ ++#define UDC_CSR_NE_NUM_MASK 0x0000000f ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_NUM_OFS ++*/ ++#define UDC_CSR_NE_NUM_OFS 0 ++ ++/* EP direction */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_DIR_MASK ++@brief EP direction mask ++*/ ++#define UDC_CSR_NE_DIR_MASK 0x00000010 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_DIR_OFS ++@brief Offset for EP direction bits ++*/ ++#define UDC_CSR_NE_DIR_OFS 4 ++ ++/* EP type */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_TYPE_MASK ++@brief Mask for EP type ++*/ ++#define UDC_CSR_NE_TYPE_MASK 0x00000060 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_TYPE_OFS ++@brief Offset for EP type bits ++*/ ++#define UDC_CSR_NE_TYPE_OFS 5 ++ ++/* EP config number */ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_CFG_MASK ++@brief Mask for EP config number ++*/ ++#define UDC_CSR_NE_CFG_MASK 0x00000780 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_CFG_OFS ++@brief Offset for EP config number bits ++*/ ++#define UDC_CSR_NE_CFG_OFS 7 ++ ++/* EP interface number */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_INTF_MASK ++@brief Mask for EP interface number bits ++*/ ++#define UDC_CSR_NE_INTF_MASK 0x00007800 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_INTF_OFS ++@brief Offset for EP interface number bits ++*/ ++#define UDC_CSR_NE_INTF_OFS 11 ++ ++/* EP alt setting */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_ALT_MASK ++@brief Mask for EP alt setting ++*/ ++#define UDC_CSR_NE_ALT_MASK 0x00078000 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_ALT_OFS ++@brief Offset for EP alt bits ++*/ ++#define UDC_CSR_NE_ALT_OFS 15 ++ ++/* max pkt */ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_MAX_PKT_MASK ++@brief Mask for max packet bits ++*/ ++#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_CSR_NE_MAX_PKT_OFS ++@brief Offset for max packet bits ++*/ ++#define UDC_CSR_NE_MAX_PKT_OFS 19 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_EP_NUM ++@brief Total number of EPs ++*/ ++#define IOH_UDC_EP_NUM 32 /* 16 IN and 16 OUT */ ++/* EP number of EP's really used */ ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_USED_EP_NUM ++@brief number of EPs used ++*/ ++#define IOH_UDC_USED_EP_NUM 4 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0IN_IDX ++@brief Control IN ep index ++*/ ++#define UDC_EP0IN_IDX 0 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_EP0UT_IDX ++@brief Control OUT ep index ++*/ ++#define UDC_EP0OUT_IDX 1 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_EP0 ++@brief number of EP0 ++*/ ++#define IOH_UDC_EP0 0 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_EP1 ++@brief number of EP1 ++*/ ++#define IOH_UDC_EP1 1 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_EP2 ++@brief number of EP2 ++*/ ++#define IOH_UDC_EP2 2 ++ ++/*!@ingroup UDC_HALLayer ++@def IOH_UDC_EP3 ++@brief number of EP3 ++*/ ++#define IOH_UDC_EP3 3 ++ ++/* Rx fifo address and size = 2k -------------------------------------------*/ ++/*!@ingroup UDC_HALLayer ++@def UDC_RXFIFO_ADDR ++@brief Address offset of Rx FIFO ++*/ ++#define UDC_RXFIFO_ADDR 0x800 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_RXFIFO_SIZE ++@brief Rx FIFO size ++*/ ++#define UDC_RXFIFO_SIZE 0x800 ++ ++/* Tx fifo address and size = 4k -----------------------------------------*/ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_TXFIFO_ADDR ++@brief Address offset of Tx FIFO ++*/ ++#define UDC_TXFIFO_ADDR 0x1000 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_TXFIFO_SIZE ++@brief Tx FIFO size ++*/ ++#define UDC_TXFIFO_SIZE 0x1000 ++ ++/* general constants */ ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_DWORD_BYTES ++@brief Bytes in DWORD ++*/ ++#define UDC_DWORD_BYTES 4 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_BITS_PER_BYTE ++@brief Bits in a byte ++*/ ++#define UDC_BITS_PER_BYTE 8 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_BITS_PER_BYTE_SHIFT ++*/ ++#define UDC_BITS_PER_BYTE_SHIFT 3 ++ ++/*!@ingroup UDC_HALLayer ++@def UDC_BYTE_MASK ++@brief Mask to get lower byte ++*/ ++#define UDC_BYTE_MASK 0xff ++ ++/* Endpoint configuration regsisters */ ++/*!@ingroup UDC_HALLayer ++@struct ioh_udc_csrs_ ++@brief Structure to Endpoint configuration registers ++*/ ++struct ioh_udc_csrs { ++ u32 ne[IOH_UDC_USED_EP_NUM * 2]; ++}; ++ ++/* UDC_Global registers */ ++/*!@ingroup UDC_Global ++@struct ioh_udc_regs_ ++@brief Structure holding values of configuration registers ++*/ ++struct ioh_udc_regs { ++ u32 devcfg; /**< Device configuration register */ ++ u32 devctl; /**< Device control register */ ++ u32 devsts; /**< Device status register */ ++ u32 devirqsts; /**< Device irq status register */ ++ u32 devirqmsk; /**< Device irq mask register */ ++ u32 epirqsts; /**< Endpoint irq status register */ ++ u32 epirqmsk; /**< Endpoint irq mask register */ ++ u32 devlpm; /**< LPM control/status register */ ++}; ++ ++/*!@ingroup UDC_Global ++@struct ioh_udc_ep_regs__ ++@brief Structure holding values of ep configuration registers ++*/ ++struct ioh_udc_ep_regs { ++ u32 epctl; /**< Endpoint control register */ ++ u32 epsts; /**< Endpoint status register */ ++ u32 bufin_framenum; /**< buffer size in / frame number out */ ++ u32 bufout_maxpkt; /**< buffer size out / maxpkt in */ ++ u32 subptr; /**< setup buffer pointer */ ++ u32 desptr; /**< Data descriptor pointer */ ++ u32 confirm; /**< Write/Read confirmation for slave mode only */ ++}; ++ ++#define DMA_ADDR_INVALID (~(dma_addr_t)0) ++ ++/*!@ingroup UDC_Global ++@struct ioh_udc_data_dma_desc_ ++@brief Structure to hold DMA descriptor information for data ++*/ ++struct ioh_udc_data_dma_desc { ++ u32 status; /**< status quadlet */ ++ u32 reserved; ++ u32 dataptr; /**< buffer descriptor */ ++ u32 next; /**< next descriptor */ ++}; ++ ++/*!@ingroup UDC_Global ++@struct struct ioh_udc_stp_dma_desc_ ++@brief Structure to hold DMA descriptor information for control data ++*/ ++struct ioh_udc_stp_dma_desc { ++ u32 status; ++ u32 reserved; ++ u32 data12; /**< first setup word */ ++ u32 data34; /**< second setup word */ ++}; ++ ++/*!@ingroup UDC_Global ++@struct ioh_udc_cfg_data ++@brief Structure to hold current configuration and interface information ++*/ ++struct ioh_udc_cfg_data { ++ u16 cur_cfg; /**< current configuration in use */ ++ u16 cur_intf; /**< current interface in use */ ++ u16 cur_alt; /**< current alt interface in use */ ++}; ++ ++/* DMA status definitions */ ++#define IOH_UDC_BUFF_STS 0xC0000000 /**< Buffer status mask */ ++#define IOH_UDC_BS_HST_RDY 0x00000000 /**< 2'b00 : Host Ready */ ++#define IOH_UDC_BS_DMA_BSY 0x40000000 /**< 2'b01 : DMA Busy */ ++#define IOH_UDC_BS_DMA_DONE 0x80000000 /**< 2'b10 : DMA Done */ ++#define IOH_UDC_BS_HST_BSY 0xC0000000 /**< 2'b11 : HOST busy */ ++ ++#define IOH_UDC_RXTX_STS 0x30000000 /**< Rx/Tx Status Mask */ ++#define IOH_UDC_RTS_SUCC 0x00000000 /**< Success */ ++#define IOH_UDC_RTS_DESERR 0x10000000 /**< Descriptor Error */ ++#define IOH_UDC_RTS_BUFERR 0x30000000 /**< Buffer Error */ ++ ++#define IOH_UDC_DMA_LAST 0x08000000 /**< Last Descriptor Indication */ ++#define IOH_UDC_RXTX_BYTES 0x0000ffff /**< Number of Rx/Tx Bytes Mask */ ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_print_regs(u32 base) ++@brief Prints UDC device registers and endpoint irq registers ++*/ ++extern void ioh_udc_print_regs(u32 base); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_init(struct ioh_udc_regs *dev) ++@brief Initializes the UDC hardware ++*/ ++extern void ioh_udc_init(struct ioh_udc_regs *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_exit(struct ioh_udc_regs *dev) ++@brief This API will do any cleanup required for the USB device hardware. ++*/ ++extern void ioh_udc_exit(struct ioh_udc_regs *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_write_csr(unsigned long val, unsigned long addr) ++@brief Write to CSR register ++*/ ++extern void ioh_udc_write_csr(unsigned long val, unsigned long addr); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_csr(unsigned long addr) ++@brief Read the content of CSR ++*/ ++extern u32 ioh_udc_read_csr(unsigned long addr); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_enable(struct ioh_udc_ep_regs __iomem *regs, ++ struct ioh_udc_cfg_data *cfg, struct usb_endpoint_descriptor *desc); ++@brief Enables endpoint ++*/ ++extern void ioh_udc_ep_enable(struct ioh_udc_ep_regs __iomem *regs, ++ struct ioh_udc_cfg_data *cfg, ++ const struct usb_endpoint_descriptor *desc); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_disable(struct ioh_udc_ep_regs __iomem *regs) ++@brief Disables endpoint ++*/ ++extern void ioh_udc_ep_disable(struct ioh_udc_ep_regs __iomem *regs); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_get_frame(struct ioh_udc_regs __iomem *dev) ++@brief This API will return the current frame number ++*/ ++extern int ioh_udc_get_frame(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_dma(struct ioh_udc_regs *dev, int dir) ++@brief Enables Tx/Rx DMA ++*/ ++extern void ioh_udc_set_dma(struct ioh_udc_regs *dev, int dir); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_clear_dma(struct ioh_udc_regs *dev, int dir) ++@brief Disable Tx/Rx DMA ++*/ ++extern void ioh_udc_clear_dma(struct ioh_udc_regs *dev, int dir); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_rmt_wakeup(struct ioh_udc_regs __iomem *dev) ++@brief Initiates a remote wakeup ++*/ ++extern void ioh_udc_rmt_wakeup(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_clear_selfpowered (struct ioh_udc_regs __iomem *dev) ++@brief This API will clear the self powered feature of the device ++*/ ++extern void ioh_udc_clear_selfpowered(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_selfpowered (struct ioh_udc_regs __iomem *dev) ++@brief This API will set the self powered feature of the device ++*/ ++extern void ioh_udc_set_selfpowered(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_disconnect (struct ioh_udc_regs __iomem *dev) ++@brief This API will cause the device to enter soft disconnect state ++*/ ++extern void ioh_udc_set_disconnect(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_clear_disconnect (struct ioh_udc_regs __iomem *dev) ++@brief This API will get the device out of soft disconnect state. ++*/ ++extern void ioh_udc_clear_disconnect(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_vbus_session (struct ioh_udc_regs __iomem *dev, int is_active) ++@brief This API will be called when VBUS power is made active for the device. ++*/ ++extern void ioh_udc_vbus_session(struct ioh_udc_regs __iomem *dev, ++ int is_active); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_clear_stall(struct ioh_udc_ep_regs __iomem *ep) ++@brief This API will clear the STALL handshake feature of the specified endpoint ++*/ ++extern void ioh_udc_ep_clear_stall(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_stall(struct ioh_udc_ep_regs __iomem *ep) ++@brief This API will set the STALL handshake feature of the specified endpoint. ++*/ ++extern void ioh_udc_ep_set_stall(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_clear_nak(struct ioh_udc_ep_regs __iomem *ep) ++@brief This API will stop the endpoint from issuing NAK packets. ++*/ ++extern void ioh_udc_ep_clear_nak(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_nak(struct ioh_udc_ep_regs __iomem *ep) ++@brief This API will cause the endpoint to issue NAK packets. ++*/ ++extern void ioh_udc_ep_set_nak(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_fifo_flush(struct ioh_udc_ep_regs __iomem *ep, int dir) ++@brief This API will flush the FIFO of the specified endpoint. ++*/ ++extern void ioh_udc_ep_fifo_flush(struct ioh_udc_ep_regs __iomem *ep, int dir); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_disable_interrupts(struct ioh_udc_regs *dev, u32 mask) ++@brief This API will disable the specified device interrupts ++*/ ++extern void ioh_udc_disable_interrupts(struct ioh_udc_regs *dev, u32 mask); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_enable_interrupts(struct ioh_udc_regs *dev, u32 mask) ++@brief This API will enable specified device interrupts ++*/ ++extern void ioh_udc_enable_interrupts(struct ioh_udc_regs *dev, u32 mask); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_disable_ep_interrupts(struct ioh_udc_regs *dev, u32 mask) ++@brief This API will disable the interrupts from specific endpoint. ++*/ ++extern void ioh_udc_disable_ep_interrupts(struct ioh_udc_regs *dev, u32 mask); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_enable_ep_interrupts(struct ioh_udc_regs *dev, u32 mask) ++@brief This API will enable the interrupts from specific endpoint. ++*/ ++extern void ioh_udc_enable_ep_interrupts(struct ioh_udc_regs *dev, u32 mask); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_csr_done(struct ioh_udc_regs *dev) ++@brief This API will inform the device the completion of ++ USB device programming. ++*/ ++extern void ioh_udc_set_csr_done(struct ioh_udc_regs *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_burst_length(struct ioh_udc_regs *dev, u8 len) ++@brief This API will set the length of 32bit words on a ++ single burst of DMA . ++*/ ++extern void ioh_udc_set_burst_length(struct ioh_udc_regs *dev, u8 len); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_set_threshold_length(struct ioh_udc_regs *dev, u8 len) ++@brief This API will set the length of 32bit words after ++ which DMA can start ++*/ ++extern void ioh_udc_set_threshold_length(struct ioh_udc_regs *dev, u8 len); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_get_speed (struct ioh_udc_regs __iomem *dev ++@brief This API will return the current speed ++*/ ++extern int ioh_udc_get_speed(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_trfr_type(struct ioh_udc_ep_regs __iomem *ep, u8 type) ++@brief This API will set the endpoint type in the endpoint control register. ++*/ ++extern void ioh_udc_ep_set_trfr_type(struct ioh_udc_ep_regs __iomem *ep, ++ u8 type); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_maxpkt(struct ioh_udc_ep_regs __iomem *ep, u32 pkt_size) ++@brief This API will set the maximum packet size for the endpoint. ++*/ ++extern void ioh_udc_ep_set_maxpkt(struct ioh_udc_ep_regs __iomem *ep, ++ u32 pkt_size); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_bufsz(struct ioh_udc_ep_regs __iomem *ep, ++ u32 buf_size, u32 ep_in) ++@brief Sets buffer size for the endpoint ++*/ ++extern void ioh_udc_ep_set_bufsz(struct ioh_udc_ep_regs __iomem *ep, ++ u32 buf_size, u32 ep_in); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_ddptr(struct ioh_udc_ep_regs __iomem *ep, ++ u32 addr) ++@brief This API will set the data descriptor pointer for the endpoint. ++*/ ++extern void ioh_udc_ep_set_ddptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_subptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr) ++@brief Set the Setup buffer pointer for the endpoint ++*/ ++extern void ioh_udc_ep_set_subptr(struct ioh_udc_ep_regs __iomem *ep, u32 addr); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_device_interrupts(struct ioh_udc_regs __iomem *dev) ++@brief Returns the interrupt status ++*/ ++extern u32 ioh_udc_read_device_interrupts(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_write_device_interrupts(struct ioh_udc_regs __iomem *dev, u32 val); ++@brief Writes Interrupts ++*/ ++extern void ioh_udc_write_device_interrupts(struct ioh_udc_regs __iomem *dev, ++ u32 val); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_ep_interrupts(struct ioh_udc_regs __iomem *ep) ++@brief Reads endpoint interrupts ++*/ ++extern u32 ioh_udc_read_ep_interrupts(struct ioh_udc_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_write_ep_interrupts(struct ioh_udc_regs __iomem *ep, u32 val) ++@brief Writes endpoint interrupts ++*/ ++extern void ioh_udc_write_ep_interrupts(struct ioh_udc_regs __iomem *ep, ++ u32 val); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_device_status(struct ioh_udc_regs __iomem *dev) ++@brief Reads device status register ++*/ ++extern u32 ioh_udc_read_device_status(struct ioh_udc_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_ep_control(struct ioh_udc_ep_regs __iomem *dev) ++@brief Reads the endpoint status registers. ++*/ ++extern u32 ioh_udc_read_ep_control(struct ioh_udc_ep_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_clear_ep_control(struct ioh_udc_ep_regs __iomem *dev) ++@brief Clear the endpoint status registers. ++*/ ++extern void ioh_udc_clear_ep_control(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_read_ep_status(struct ioh_udc_ep_regs __iomem *dev) ++@brief Reads the endpoint status registers. ++*/ ++extern u32 ioh_udc_read_ep_status(struct ioh_udc_ep_regs __iomem *dev); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_pd(struct ioh_udc_ep_regs __iomem *ep) ++@brief Set the poll demand bit for the endpoint ++*/ ++extern void ioh_udc_ep_set_pd(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_set_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++@brief Set the receive ready bit for the endpoint ++*/ ++extern void ioh_udc_ep_set_rrdy(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_ep_clear_rrdy(struct ioh_udc_ep_regs __iomem *ep) ++@brief Clear the receive ready bit for the endpoint ++*/ ++extern void ioh_udc_ep_clear_rrdy(struct ioh_udc_ep_regs __iomem *ep); ++ ++/*!@ingroup UDC_HALLayerAPI ++@fn ioh_udc_clear_ep_status(struct ioh_udc_ep_regs __iomem *ep, u32 stat) ++@brief Clears endpoint status register ++*/ ++extern void ioh_udc_clear_ep_status(struct ioh_udc_ep_regs __iomem *ep, ++ u32 stat); ++extern int speed_fs; ++#endif /* IOH_UDC_HAL_H_ */ +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc_intr.c +@@ -0,0 +1,396 @@ ++ /*! ++ * @file ioh_udc_intr.c ++ * @brief ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or ++ * interrupt type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++/*#include */ ++#include ++#include "pch_common.h" ++#include "pch_debug.h" ++ ++#include "pch_udc_hal.h" ++#include "pch_udc.h" ++ ++/* received setup data */ ++static union ioh_udc_setup_data setup_data; ++ ++/*! @ingroup UDC_UtilitiesAPI ++ * @fn void ioh_udc_svc_ur_interrupt(struct ioh_udc_dev *dev) ++ * @brief This function handles a USB reset interrupt ++ * @param dev [@ref IN] reference to driver structure ++ * @return none ++ * @remarks The following actions are performed: ++ *- Disable Rx/TX DMA using ioh_udc_clear_dma API ++ *- Mask all endpoint interrupts by invoking ioh_udc_disable_ep_interrupts API ++ *- Clear all endpoint interrupts by invoking ioh_udc_write_ep_interrupts API ++ *- Clear all endpoint status register invoking ioh_udc_clear_ep_status API ++ *- Clear all endpoint control register by invoking ioh_udc_clear_ep_control API ++ *- Clear all endpoint Data descriptor pointer register by invoking ++ * ioh_udc_ep_set_ddptr API ++ *- Clear all endpoint UDC Endpoint register by invoking ioh_udc_write_csr API ++ *- Clear status flags ++ *- Set the all endpoint's NAK by invoking ioh_udc_ep_set_nak API ++ *- Flush the all endpoint's Tx/RxFIFO by invoking ioh_udc_ep_fifo_flush API ++ *- Disable ep0 to empty request queue by invoking empty_req_queue API ++ *- Invoke the gadget driver's fs disconnect method ++- Empty EP0 IN request queue using empty_req_queue API ++ * @see ++ * - ioh_udc_clear_dma ++ * - ioh_udc_disable_ep_interrupts ++ * - ioh_udc_write_ep_interrupts ++ * - ioh_udc_clear_ep_status ++ * - ioh_udc_clear_ep_control ++ * - ioh_udc_ep_set_ddptr ++ * - ioh_udc_write_csr ++ * - ioh_udc_ep_set_nak ++ * - ioh_udc_ep_fifo_flush ++ * - empty_req_queue ++ */ ++void ioh_udc_svc_ur_interrupt(struct ioh_udc_dev *dev) ++{ ++ struct ioh_udc_ep *ep; ++ int i; ++ ++ IOH_DEBUG("USB_RESET Enter"); ++ ++#ifdef IOH_PRINT_REG ++ ioh_udc_print_regs((u32)dev->virt_addr); ++#endif ++ ++ /* Disable DMA */ ++ ioh_udc_clear_dma(dev->regs, DMA_DIR_TX); ++ ioh_udc_clear_dma(dev->regs, DMA_DIR_RX); ++ /* Mask all endpoint interrupts */ ++ ioh_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL); ++ /* clear all endpoint interrupts */ ++ ioh_udc_write_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL); ++ ++ for (i = 0; i < IOH_UDC_EP_NUM; i++) { ++ ep = &dev->ep[i]; ++ ioh_udc_clear_ep_status(ep->regs, 0x1F0006F0); ++ ioh_udc_clear_ep_control(ep->regs); ++ ioh_udc_ep_set_ddptr(ep->regs, 0); ++ ioh_udc_write_csr(0x00, (u32) (&dev->csr->ne[i])); ++ } ++ ++ dev->stall = 0; ++ dev->prot_stall = 0; ++ dev->waiting_zlp_ack = 0; ++ dev->set_cfg_not_acked = 0; ++ ++ /* disable ep to empty req queue. Skip the control EP's */ ++ for (i = 0; i < (IOH_UDC_USED_EP_NUM*2); i++) { ++ ep = &dev->ep[i]; ++ /* Set NAK */ ++ ioh_udc_ep_set_nak(ep->regs); ++ /* Flush fifo */ ++ ioh_udc_ep_fifo_flush(ep->regs , ep->in); ++ /* Complete request queue */ ++ empty_req_queue(ep); ++ } ++ if (dev->driver && dev->driver->disconnect) ++ dev->driver->disconnect(&dev->gadget); ++ ++ IOH_DEBUG("USB_RESET Exit"); ++} ++ ++/*! @ingroup UDC_UtilitiesAPI ++ * @fn ioh_udc_svc_enum_interrupt(struct ioh_udc_dev *dev) ++ * @brief This function handles a USB speed enumeration done interrupt ++ * @param dev [@ref IN] reference to driver structure ++ * @return none ++ * @remarks The following actions are performed: ++ * - Read the device status using ioh_udc_read_device_status API ++ * - Set the speed element in device structure. ++ * - Activate control endpoint using ioh_udc_activate_control_ep API ++ * - Enable EP0 interrupts using ioh_udc_enable_ep_interrupts API ++ * - Enable Rx/TX DMA using ioh_udc_set_dma API ++ * - Set receive ready using ioh_udc_ep_set_rrdy API ++ * @see ++ * - ioh_udc_read_device_status ++ * - ioh_udc_activate_control_ep ++ * - ioh_udc_enable_ep_interrupts ++ * - ioh_udc_set_dma ++ * - ioh_udc_ep_set_rrdy ++ */ ++void ++ioh_udc_svc_enum_interrupt(struct ioh_udc_dev *dev) ++{ ++ u32 dev_stat, dev_speed; ++ u32 speed = USB_SPEED_FULL; ++ ++ dev_stat = ioh_udc_read_device_status(dev->regs); ++ dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >> ++ UDC_DEVSTS_ENUM_SPEED_OFS; ++ ++ IOH_DEBUG("ioh_udc_svc_enum_interrupt: dev_speed = 0x%08x", dev_speed); ++ ++ if (dev_speed == UDC_DEVSTS_ENUM_SPEED_HIGH) { ++ IOH_DEBUG("HighSpeed"); ++ speed = USB_SPEED_HIGH; ++ } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_FULL) { ++ IOH_DEBUG("FullSpeed"); ++ speed = USB_SPEED_FULL; ++ } else if (dev_speed == UDC_DEVSTS_ENUM_SPEED_LOW) { ++ IOH_DEBUG("LowSpeed?"); ++ speed = USB_SPEED_LOW; ++ } else { ++ IOH_DEBUG("FullSpeed?"); ++ } ++ dev->gadget.speed = speed; ++ ++ ioh_udc_activate_control_ep(dev); ++ ++ /* enable ep0 interrupts */ ++ ioh_udc_enable_ep_interrupts(dev->regs, 1 << UDC_EPINT_IN_EP0 | ++ 1 << UDC_EPINT_OUT_EP0); ++ ++ /* enable DMA */ ++ ioh_udc_set_dma(dev->regs, DMA_DIR_TX); ++ ioh_udc_set_dma(dev->regs, DMA_DIR_RX); ++ ioh_udc_ep_set_rrdy(dev->ep[UDC_EP0OUT_IDX].regs); ++ ++#ifdef IOH_PRINT_REG ++ ioh_udc_print_regs((u32)dev->virt_addr); ++#endif ++ ++ IOH_DEBUG("EP mask set to %x", ++ IOH_READ32((u32 *)&(dev->regs->epirqmsk))); ++ IOH_DEBUG("USB_SPEED_ENUM Exit"); ++} ++ ++/*! @ingroup UDC_UtilitiesAPI ++ * @fn ioh_udc_svc_intf_interrupt(struct ioh_udc_dev *dev) ++ * @brief This function handles a set interface interrupt ++ * @param dev [@ref IN] reference to driver structure ++ * @return none ++ * @remarks The following actions are performed: ++ * - Read the device status using ioh_udc_read_device_status API ++ * - Update current interface in use and current alternate interface ++ * in use status from the device status information ++ * - Set device "Set Config Not ACKed" status as TRUE ++ * - Construct the usb request for gadget driver and inform it ++ * - Program the Endpoint configuration registers using ioh_udc_read_csr ++ * and ioh_udc_write_csr APIs ++ * - Clear stall bit status using ioh_udc_ep_clear_stall ++ * - Call gadget with setup data received ++ * @see ++ * - ioh_udc_read_device_status ++ * - ioh_udc_read_csr ++ * - ioh_udc_write_csr ++ * - ioh_udc_ep_clear_stall ++ */ ++void ++ioh_udc_svc_intf_interrupt(struct ioh_udc_dev *dev) ++{ ++ u32 reg, dev_stat = 0; ++ int i, ret; ++ ++ IOH_DEBUG("SI"); ++ dev_stat = ioh_udc_read_device_status(dev->regs); ++ dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> ++ UDC_DEVSTS_INTF_OFS; ++ dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >> ++ UDC_DEVSTS_ALT_OFS; ++ IOH_DEBUG("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat, ++ (dev_stat & UDC_CSR_NE_CFG_MASK) >> UDC_CSR_NE_CFG_OFS, ++ dev->cfg_data.cur_intf, dev->cfg_data.cur_alt); ++ ++ dev->set_cfg_not_acked = 1; ++ ++ /* Construct the usb request for gadget driver and inform it */ ++ memset(&setup_data, 0 , sizeof setup_data); ++ setup_data.request.bRequest = USB_REQ_SET_INTERFACE; ++ setup_data.request.bRequestType = USB_RECIP_INTERFACE; ++ setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_alt); ++ setup_data.request.wIndex = cpu_to_le16(dev->cfg_data.cur_intf); ++ ++ /* programm the Endpoint Cfg registers */ ++ for (i = 0; i < IOH_UDC_USED_EP_NUM * 2; i++) { ++ if (i == 1) { /* Only one end point cfg register */ ++ reg = ioh_udc_read_csr((u32) (&dev->csr->ne[i])); ++ reg = (reg & ~UDC_CSR_NE_INTF_MASK) | ++ (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_OFS); ++ reg = (reg & ~UDC_CSR_NE_ALT_MASK) | ++ (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_OFS); ++ ioh_udc_write_csr(reg, (u32) (&dev->csr->ne[i])); ++ } ++ /* clear stall bits */ ++ ioh_udc_ep_clear_stall(dev->ep[i].regs); ++ dev->ep[i].halted = 0; ++ } ++ dev->stall = 0; ++ spin_unlock(&dev->lock); ++ ret = dev->driver->setup(&dev->gadget, &setup_data.request); ++ spin_lock(&dev->lock); ++ ++ IOH_DEBUG("EXIT -- SI"); ++} ++ ++/*! @ingroup UDC_UtilitiesAPI ++ * @fn ioh_udc_svc_cfg_interrupt(struct ioh_udc_dev *dev) ++ * @brief This function handles a set configuration interrupt ++ * @param dev [@ref IN] reference to driver structure ++ * @return none ++ * @remarks The following actions are performed: ++ * - Read the device status using ioh_udc_read_device_status API ++ * - Set the set_cfg_not_acked element in device structure to 1. ++ * - Update "current configuration in use" status based on the ++ * device status ++ * - Construct a usb request for gadget driver ++ * - Program the Endpoint configuration registers using ++ * ioh_udc_read_csr and ioh_udc_write_csr APIs ++ * - Clear stall bit status using ioh_udc_ep_clear_stall ++ * - Call gadget with setup data received ++ * @see ++ * - ioh_udc_read_device_status ++ * - ioh_udc_read_csr ++ * - ioh_udc_write_csr ++ * - ioh_udc_ep_clear_stall ++ */ ++void ++ioh_udc_svc_cfg_interrupt(struct ioh_udc_dev *dev) ++{ ++ int i, ret; ++ u32 reg, dev_stat = 0; ++ ++ IOH_DEBUG("SC"); ++ dev_stat = ioh_udc_read_device_status(dev->regs); ++ IOH_DEBUG("DVSTATUS=%08x, cfg=%d, intf=%d, alt=%d", dev_stat, ++ (dev_stat & UDC_DEVSTS_CFG_MASK) >> UDC_DEVSTS_CFG_OFS, ++ (dev_stat & UDC_DEVSTS_INTF_MASK) >> UDC_DEVSTS_INTF_OFS, ++ (dev_stat & UDC_DEVSTS_ALT_MASK) >> UDC_DEVSTS_ALT_OFS); ++ ++ dev->set_cfg_not_acked = 1; ++ ++ dev->cfg_data.cur_cfg = (dev_stat & UDC_DEVSTS_CFG_MASK) >> ++ UDC_DEVSTS_CFG_OFS; ++ /* make usb request for gadget driver */ ++ memset(&setup_data, 0 , sizeof setup_data); ++ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; ++ setup_data.request.wValue = cpu_to_le16(dev->cfg_data.cur_cfg); ++ ++ /* program the NE registers */ ++ for (i = 0; i < IOH_UDC_USED_EP_NUM * 2; i++) { ++ if (i == 1) { ++ reg = ioh_udc_read_csr((u32) (&dev->csr->ne[i])); ++ reg = (reg & ~UDC_CSR_NE_CFG_MASK) | ++ (dev->cfg_data.cur_cfg << UDC_CSR_NE_CFG_OFS); ++ ioh_udc_write_csr(reg, (u32) (&dev->csr->ne[i])); ++ } ++ /* clear stall bits */ ++ ioh_udc_ep_clear_stall(dev->ep[i].regs); ++ dev->ep[i].halted = 0; ++ } ++ dev->stall = 0; ++ ++ /* call gadget zero with setup data received */ ++ spin_unlock(&dev->lock); ++ ret = dev->driver->setup(&dev->gadget, &setup_data.request); ++ spin_lock(&dev->lock); ++ ++ IOH_DEBUG("SC Exit...ret %d", ret); ++} ++ ++/*! @ingroup UDC_UtilitiesAPI ++ * @fn void ioh_udc_dev_isr(struct ioh_udc_dev *dev, u32 dev_intr) ++ * @brief This function services device interrupts by invoking appropriate ++ * routines. ++ * @remarks The following actions are performed: ++ *- If USB reset interrupt status is received, invoke ioh_udc_svc_ur_interrupt ++ * function ++ *- If Enumeration done interrupt is received, invoke ioh_udc_svc_enum_interrupt ++ * function ++ *- If Set Interface interrupt is received, invoke ioh_udc_svc_intf_interrupt ++ * function ++ *- If Set Config interrupt is received, invoke ioh_udc_svc_cfg_interrupt ++ * function ++ *- If USB suspend interrupt or ES interrupt is received, invoke the ++ * API ioh_udc_rmt_wakeup ++ *- For the following interrupts, log a message in the system log: ++ * - USB Suspend interrupt ++ * - SOF token detection interrupt ++ * - ES interrupt, (IDLE > 3ms on the USB) ++ * - RWKP interrupt (Remote Wakeup) ++ * @param dev Reference to the device structure ++ * @param dev_intr The Device interrupt status. ++ * @see ++ * - ioh_udc_svc_ur_interrupt ++ * - ioh_udc_svc_enum_interrupt ++ * - ioh_udc_svc_intf_interrupt ++ * - ioh_udc_svc_cfg_interrupt ++ * @return none ++ */ ++void ioh_udc_dev_isr(struct ioh_udc_dev *dev, u32 dev_intr) ++{ ++ /* USB Reset Interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_UR)) ++ ioh_udc_svc_ur_interrupt(dev); ++ ++ /* Enumeration Done Interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_ENUM)) ++ ioh_udc_svc_enum_interrupt(dev); ++ ++ /* Set Interface Interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_SI)) ++ ioh_udc_svc_intf_interrupt(dev); ++ ++ /* Set Config Interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_SC)) ++ ioh_udc_svc_cfg_interrupt(dev); ++ ++ /* USB Suspend interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_US)) ++ IOH_DEBUG("USB_SUSPEND"); ++ ++ /* Clear the SOF interrupt, if enabled */ ++ if (dev_intr & (1 << UDC_DEVINT_SOF)) ++ IOH_DEBUG("SOF"); ++ ++ /* ES interrupt, IDLE > 3ms on the USB */ ++ if (dev_intr & (1 << UDC_DEVINT_ES)) ++ IOH_DEBUG("ES"); ++ ++ /* RWKP interrupt */ ++ if (dev_intr & (1 << UDC_DEVINT_RWKP)) ++ IOH_DEBUG("RWKP"); ++ ++} +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc_pci.c +@@ -0,0 +1,549 @@ ++/*! ++ * @file ioh_udc_pci.c ++ * @brief ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or ++ * interrupt type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++/* ++ * ioh_udc_pci.c -- IOH UDC high/full speed USB device controller ++ * ++ */ ++ ++ ++/*!@ingroup UDC_PCILayer ++ * @def UDC_MOD_DESCRIPTION ++ * @brief USB device controller driver description. ++ */ ++#define UDC_MOD_DESCRIPTION "OKISEMI IOH UDC - USB Device Controller" ++ ++/*!@ingroup UDC_PCILayer ++ * @def IOH_UDC_PCI_BAR ++ * @brief Number of PCI BAR. ++ */ ++#define IOH_UDC_PCI_BAR 1 ++ ++/* udc specific */ ++#include "pch_common.h" ++#include "pch_debug.h" ++#include "pch_udc_pci.h" ++#include "pch_udc.h" ++ ++static int ioh_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id); ++static void ioh_udc_remove(struct pci_dev *pdev); ++static void ioh_udc_shutdown(struct pci_dev *pdev); ++static int ioh_udc_suspend(struct pci_dev *pdev, pm_message_t state); ++static int ioh_udc_resume(struct pci_dev *pdev); ++ ++/* description */ ++static const char mod_desc[] = UDC_MOD_DESCRIPTION; ++static const char name[] = "ioh_udc"; ++ ++/* pointer to device object */ ++/*!@ingroup UDC_Global ++ * @brief pointer to device object ++ */ ++struct ioh_udc_dev *ioh_udc; ++ ++/* Speed selection flag */ ++/*!@ingroup UDC_Global ++ * @brief Specifies operation speed (High or FULL) - passed as module parameter ++ */ ++int speed_fs; ++ ++/* module parameters */ ++module_param_named(speed_fs, speed_fs, bool, S_IRUGO); ++MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); ++ ++/* Tears down device */ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static void gadget_release(struct device *pdev) ++ * @brief Free the gadget driver private data ++ * @remarks The main tasks performed by this method are: ++ * - Retrieve the pointer to the private data using dev_get_drvdata API. ++ * - Free the memory allocated for the device structure using kfree API. ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @return none ++ */ ++static void gadget_release(struct device *pdev) ++{ ++ struct ioh_udc_dev *dev = dev_get_drvdata(pdev); ++ kfree(dev); ++} ++ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static void ioh_udc_remove(struct pci_dev *pdev) ++ * @brief Implements the remove routine for IOH USB device controller driver ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @remarks The main tasks performed by this method are: ++ * - Deallocate any PCI memory pool created ++ * - Release IRQ ++ * - Unmap device memory ++ * - Disable the PCI device ++ * - Unregister the device from system ++ * @return none ++ */ ++static void ioh_udc_remove(struct pci_dev *pdev) ++{ ++ struct ioh_udc_dev *dev = pci_get_drvdata(pdev); ++ ++ IOH_DEBUG("ioh_udc_remove enter"); ++ /* gadget driver must not be registered */ ++ if (dev->driver != NULL) ++ IOH_LOG(KERN_ERR, "udc_pci_remove: gadget driver\ ++ still bound!!!"); ++ ++ /* dma pool cleanup */ ++ if (dev->data_requests != NULL) ++ pci_pool_destroy(dev->data_requests); ++ ++ ++ if (dev->stp_requests != NULL) { ++ /* cleanup DMA desc's for ep0in */ ++ if (dev->ep[UDC_EP0OUT_IDX].td_stp != NULL) { ++ pci_pool_free(dev->stp_requests, ++ dev->ep[UDC_EP0OUT_IDX].td_stp, ++ dev->ep[UDC_EP0OUT_IDX].td_stp_phys); ++ } ++ if (dev->ep[UDC_EP0OUT_IDX].td_data != NULL) { ++ pci_pool_free(dev->stp_requests, ++ dev->ep[UDC_EP0OUT_IDX].td_data, ++ dev->ep[UDC_EP0OUT_IDX].td_data_phys); ++ } ++ pci_pool_destroy(dev->stp_requests); ++ } ++ ++ ioh_udc_exit(dev->regs); ++ ++ if (dev->irq_registered) ++ free_irq(pdev->irq, dev); ++ ++ if (dev->virt_addr != NULL) ++ iounmap(dev->virt_addr); ++ ++ if (dev->mem_region) ++ release_mem_region(dev->phys_addr, pci_resource_len(pdev, ++ IOH_UDC_PCI_BAR)); ++ ++ if (dev->active) ++ pci_disable_device(pdev); ++ ++ if (dev->registered) ++ device_unregister(&dev->gadget.dev); ++ else ++ kfree(dev); ++ ++ pci_set_drvdata(pdev, NULL); ++} ++ ++/*!@ingroup UDC_UtilitiesAPI ++ * @fn static int init_dma_pools(struct ioh_udc_dev *dev) ++ * @brief create dma pools during initialization ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @remarks The following actions are performed: ++ *- Create a PCI memory pool of DMA descriptors for handling data requests ++ * using pci_pool_create API ++ *- If failed to create the pool, return -ENOMEM ++ *- Create a PCI memory pool of DMA descriptors for handling setup requests ++ * using pci_pool_create API ++ *- If failed to create the pool, return -ENOMEM ++ *- Allocate one entry from setup pool to be used for setup requests using ++ * pci_pool_alloc API ++ *- If failed to allocate, return -ENOMEM ++ *- Allocate one entry from setup pool to be used for control IN requests ++ * using pci_pool_alloc API ++ *- If failed to allocate, return -ENOMEM ++ * @return none ++ */ ++static int init_dma_pools(struct ioh_udc_dev *dev) ++{ ++ struct ioh_udc_stp_dma_desc *td_stp; ++ struct ioh_udc_data_dma_desc *td_data; ++ ++ /* DMA setup */ ++ dev->data_requests = pci_pool_create("data_requests", dev->pdev, ++ sizeof(struct ioh_udc_data_dma_desc), 0, 0); ++ if (dev->data_requests == NULL) { ++ IOH_LOG(KERN_ERR, "init_dma_pools: can't get request\ ++ data pool"); ++ return -ENOMEM; ++ } ++ ++ /* dma desc for setup data */ ++ dev->stp_requests = pci_pool_create("setup requests", dev->pdev, ++ sizeof(struct ioh_udc_stp_dma_desc), 0, 0); ++ if (dev->stp_requests == NULL) { ++ IOH_LOG(KERN_ERR, "init_dma_pools: can't get setup\ ++ request pool"); ++ return -ENOMEM; ++ } ++ /* setup */ ++ td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL, ++ &dev->ep[UDC_EP0OUT_IDX].td_stp_phys); ++ if (td_stp == NULL) { ++ IOH_LOG(KERN_ERR, "init_dma_pools: can't allocate setup\ ++ dma descriptor"); ++ return -ENOMEM; ++ } ++ dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp; ++ ++ /* data: 0 packets !? */ ++ td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL, ++ &dev->ep[UDC_EP0OUT_IDX].td_data_phys); ++ if (td_data == NULL) { ++ IOH_LOG(KERN_ERR, "init_dma_pools: can't allocate data dma\ ++ descriptor"); ++ return -ENOMEM; ++ } ++ dev->ep[UDC_EP0OUT_IDX].td_data = td_data; ++ dev->ep[UDC_EP0IN_IDX].td_stp = NULL; ++ dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0; ++ dev->ep[UDC_EP0IN_IDX].td_data = NULL; ++ dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; ++ return 0; ++} ++ ++ ++ ++/* Called by pci bus driver to init pci context */ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static int ioh_udc_probe(struct pci_dev *pdev, ++ * const struct pci_device_id *id) ++ * @brief Implements the Probe routine for IOH USB device controller driver ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @param id [@ref IN] reference to struct pci_device_id table ++ * @return int [ 0 on Success and linux error number on failure ] ++ * @remarks The following actions are performed: ++ *- Allocate and initialize the device driver data structures ++ *- Enable the PCI device and set driver private data ++ *- Do PCI resource allocation for the device ++ *- Request memory region for the device ++ *- Map PCI device memory to kernel virtual space ++ *- Initialize the HAL layer by invoking ioh_udc_pcd_init API ++ *- Register the interrupt handler ioh_udc_isr ++ *- Enable Bus mastering for the device using pci_set_master API. ++ *- Enable memory write invalidate PCI transaction using pci_try_set_mwi API. ++ *- Set up device structure and ops structure and initialize the gadget driver ++ * data structure ++ *- If using DMA (specified during module loading), initialize DMA pools using ++ * init_dma_pools API ++ *- Register the device with the system using device_register API ++ *- Put the device in disconnected state till a driver is bound, using ++ * ioh_udc_set_disconnect API ++ *- Invoke ioh_udc_remove to perform clean-up on any error. ++ */ ++static int ioh_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) ++{ ++ unsigned long resource; ++ unsigned long len; ++ int retval = 0; ++ struct ioh_udc_dev *dev; ++ ++ IOH_DEBUG("ioh_udc_probe: enter"); ++ /* one udc only */ ++ if (ioh_udc != NULL) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: already probed"); ++ return -EBUSY; ++ } ++ ++ /* init */ ++ dev = kzalloc(sizeof(struct ioh_udc_dev), GFP_KERNEL); ++ if (dev == NULL) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: no memory for device\ ++ structure"); ++ return -ENOMEM; ++ } ++ memset(dev, 0, sizeof(struct ioh_udc_dev)); ++ /* pci setup */ ++ if (pci_enable_device(pdev) < 0) { ++ kfree(dev); ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: pci_enable_device failed"); ++ return -ENODEV; ++ } ++ dev->active = 1; ++ pci_set_drvdata(pdev, dev); ++ ++ /* PCI resource allocation */ ++ resource = pci_resource_start(pdev, 1); ++ len = pci_resource_len(pdev, 1); ++ IOH_DEBUG("ioh_udc_probe: resource %lx, len %ld", resource, len); ++ ++ if (request_mem_region(resource, len, name) == NULL) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: pci device used already"); ++ retval = -EBUSY; ++ goto finished; ++ } ++ dev->phys_addr = resource; ++ dev->mem_region = 1; ++ ++ dev->virt_addr = ioremap_nocache(resource, len); ++ if (dev->virt_addr == NULL) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: device memory cannot be\ ++ mapped"); ++ retval = -ENOMEM; ++ goto finished; ++ } ++ IOH_DEBUG("ioh_udc_probe: device memory mapped at %x", ++ (int)dev->virt_addr); ++ ++ if (pdev->irq == 0) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: irq not set"); ++ retval = -ENODEV; ++ goto finished; ++ } ++ ++ ioh_udc = dev; ++ ++ /* initialize the hardware */ ++ if (ioh_udc_pcd_init(dev) != 0) ++ goto finished; ++ ++ ++ if (request_irq(pdev->irq, ioh_udc_isr, IRQF_SHARED, name, dev) != 0) { ++ IOH_LOG(KERN_ERR, "ioh_udc_probe: request_irq(%d) fail", ++ pdev->irq); ++ retval = -ENODEV; ++ goto finished; ++ } ++ dev->irq = pdev->irq; ++ dev->irq_registered = 1; ++ ++ pci_set_master(pdev); ++ pci_try_set_mwi(pdev); ++ ++ /* device struct setup */ ++ spin_lock_init(&dev->lock); ++ dev->pdev = pdev; ++ dev->gadget.ops = &ioh_udc_ops; ++ ++ /* init dma pools */ ++ retval = init_dma_pools(dev); ++ if (retval != 0) ++ goto finished; ++ ++/* strcpy(dev->gadget.dev.bus_id, "gadget");*/ ++ dev_set_name(&dev->gadget.dev, "gadget"); ++ dev->gadget.dev.parent = &pdev->dev; ++ dev->gadget.dev.dma_mask = pdev->dev.dma_mask; ++ dev->gadget.dev.release = gadget_release; ++ dev->gadget.name = name; ++ dev->gadget.is_dualspeed = 1; ++ ++ retval = device_register(&dev->gadget.dev); ++ if (retval != 0) ++ goto finished; ++ ++ dev->registered = 1; ++ ++ /* Put the device in disconnected state till a driver is bound */ ++ ioh_udc_set_disconnect(dev->regs); ++ ++#ifdef IOH_PRINT_REG ++ /* print dev register info */ ++ ioh_udc_print_regs((u32)dev->virt_addr); ++#endif ++ return 0; ++ ++finished: ++ ioh_udc_remove(pdev); ++ return retval; ++} ++ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static void ioh_udc_shutdown(struct pci_dev *pdev) ++ * @brief This routine makes sure that the device is quiescent. ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @return none ++ * @remarks The main tasks performed by this method are: ++ * - Disable interrupts from the device ++ * - Put the PCI device in soft disconnect mode ++ */ ++static void ioh_udc_shutdown(struct pci_dev *pdev) ++{ ++ struct ioh_udc_dev *dev = pci_get_drvdata(pdev); ++ ++ IOH_DEBUG("ioh_udc_shutdown enter"); ++ ++ ioh_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK); ++ ioh_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL); ++ ++ /* disable the pullup so the host will think we're gone */ ++ ioh_udc_set_disconnect(dev->regs); ++} ++ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static int ioh_udc_suspend(struct pci_dev *pdev, pm_message_t state) ++ * @brief Implements the Suspend functionality for IOH USB device controller ++ * driver ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @param state [@ref IN] specifies new PM state to which to transition to ++ * @return int [ 0 on Success and linux error number on failure ] ++ * @remarks The main tasks performed by this method are: ++ * - Disable interrupts from the device ++ * - Disable the PCI device ++ * - Save the PCI state ++ * - Transition to new power state ++ */ ++static int ioh_udc_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct ioh_udc_dev *dev = pci_get_drvdata(pdev); ++ ++ IOH_DEBUG("ioh_udc_suspend enter"); ++ ++ ioh_udc_disable_interrupts(dev->regs, UDC_DEVINT_MSK); ++ ioh_udc_disable_ep_interrupts(dev->regs, UDC_EPINT_MSK_DISABLE_ALL); ++ ++ pci_disable_device(pdev); ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ ++ if (pci_save_state(pdev) != 0) { ++ IOH_LOG(KERN_ERR, "ioh_udc_suspend: could not save PCI config\ ++ state"); ++ return -ENOMEM; ++ } ++ ++ if (pci_set_power_state(pdev, pci_choose_state(pdev, state)) == -EIO) ++ IOH_DEBUG("ioh_udc_suspend: does not support PM cpabilities"); ++ ++ ++ return 0; ++} ++ ++/*!@ingroup UDC_PCILayerAPI ++ * @fn static int ioh_udc_resume(struct pci_dev *pdev) ++ * @brief Implements the Resume functionality for IOH USB device ++ * controller driver ++ * @param pdev [@ref IN] reference to struct pci_dev ++ * @return int [ 0 on Success and linux error number on failure ] ++ * @remarks The main tasks performed by this method are: ++ * - Set power state to PCI_D0 using pci_set_power_state ++ * - Restore the device state using pci_restore_state ++ * - Enable the device using pci_enable_device ++ * - Enable the bus mastering using pci_set_master ++ * - Disable the PM notifications using pci_enable_wake ++ */ ++static int ioh_udc_resume(struct pci_dev *pdev) ++{ ++ int ret; ++ ++ ret = pci_set_power_state(pdev, PCI_D0); ++ if (ret != 0) ++ IOH_DEBUG("ioh_udc_resume: does not support PM cpabilities"); ++ ++ ++ ret = pci_restore_state(pdev); ++ if (ret != 0) { ++ IOH_LOG(KERN_ERR, "ioh_udc_resume: pci_restore_state failed"); ++ return ret; ++ } ++ ++ ret = pci_enable_device(pdev); ++ ++ if (ret != 0) { ++ IOH_LOG(KERN_ERR, "ioh_udc_resume: pci_enable_device failed"); ++ return ret; ++ } ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ ++ return 0; ++} ++ ++/* PCI device parameters */ ++/*!@ingroup UDC_InterfaceLayer ++ * @struct ioh_udc_pcidev_id ++ * @brief This is an instance of pci_device_id structure which holds ++ * information ++ * about the PCI USB device that are supported by this ++ * driver. ++ */ ++static const struct pci_device_id ioh_udc_pcidev_id[] = { ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOH1_UDC), ++ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, ++ .class_mask = 0xffffffff, ++ }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ROHM_IOH2_UDC), ++ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, ++ .class_mask = 0xffffffff, ++ }, ++ { 0 }, ++}; ++ ++MODULE_DEVICE_TABLE(pci, ioh_udc_pcidev_id); ++ ++/* PCI functions */ ++/*!@ingroup UDC_InterfaceLayer ++ * @struct ioh_udc_driver ++ * @brief Linux pci_driver structure which provides the reference to ++ * PCI methods of this driver ++ */ ++static struct pci_driver ioh_udc_driver = { ++ .name = (char *) name, ++ .id_table = ioh_udc_pcidev_id, ++ .probe = ioh_udc_probe, ++ .remove = ioh_udc_remove, ++ .suspend = ioh_udc_suspend, ++ .resume = ioh_udc_resume, ++ .shutdown = ioh_udc_shutdown, ++}; ++ ++/* Initialize the driver */ ++/*!@ingroup UDC_InterfaceLayerAPI ++ * @fn static int __init ioh_udc_pci_init(void) ++ * @brief This function is the entry point for the driver ++ * @param none ++ * @return int [ 0 on success and <0 on failure ] ++ */ ++static int __init ioh_udc_pci_init(void) ++{ ++ return pci_register_driver(&ioh_udc_driver); ++} ++module_init(ioh_udc_pci_init); ++ ++/* Cleans driver */ ++/*!@ingroup UDC_InterfaceLayerAPI ++ * @fn static void __exit ioh_udc_pci_exit(void) ++ * @brief This function is the exit point for the driver ++ * @param none ++ * @return none ++ */ ++static void __exit ioh_udc_pci_exit(void) ++{ ++ pci_unregister_driver(&ioh_udc_driver); ++} ++module_exit(ioh_udc_pci_exit); ++ ++MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/usb/gadget/pch_udc_pci.h +@@ -0,0 +1,97 @@ ++ /*! ++ * @file ioh_udc_pci.h ++ * @brief ++ * The IOH UDC is a USB High speed DMA capable USB device controller. ++ * It provides 4 IN and 4 OUT endpoints (control, bulk isochronous or interrupt ++ * type). ++ * ++ * The IOH USB device controller driver provides required interface ++ * to the USB gadget framework for accessing the IOH USB device hardware. ++ * ++ * @version 0.96 ++ * ++ * @section ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++ /* ++ * History: ++ * Copyright (C) 2009 OKI SEMICONDUCTOR Co., LTD. ++ * All rights reserved. ++ * ++ * created: ++ * OKI SEMICONDUCTOR 2/26/2010 ++ * modified: ++ * ++ */ ++ ++#ifndef IOH_UDC_PCI_H ++#define IOH_UDC_PCI_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* gadget stack */ ++#include ++#include ++#include "pch_udc_hal.h" ++ ++/*!@ingroup UDC_InterfaceLayer ++ * @def PCI_VENDOR_ID_INTEL ++ * @brief PCI Vendor ID for Intel. ++ */ ++#define PCI_VENDOR_ID_INTEL 0x8086 ++/*!@ingroup UDC_InterfaceLayer ++ * @def PCI_VENDOR_ID_ROHM ++ * @brief PCI Vendor ID for ROHM. ++ */ ++#define PCI_VENDOR_ID_ROHM 0x10db ++ ++/*!@ingroup UDC_InterfaceLayer ++ * @def PCI_DEVICE_ID_INTEL_IOH1_UDC ++ * @brief Outlines the PCI Device ID for Intel IOH GE UDC device. ++ */ ++#define PCI_DEVICE_ID_INTEL_IOH1_UDC 0x8808 /*Device Id for GE device*/ ++ ++/*!@ingroup UDC_InterfaceLayer ++ * @def PCI_DEVICE_ID_INTEL_IOH1_UDC ++ * @brief Outlines the PCI Device ID for ROHM IOH IVI UDC device. ++ */ ++#define PCI_DEVICE_ID_ROHM_IOH2_UDC 0x801D /* Device ID for IVI*/ ++ ++extern u32 ioh_udc_base; ++#endif /* #ifdef IOH_UDC_PCI_H */ -- cgit v1.2.3