Commit e443b333 authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Greg Kroah-Hartman

usb: chipidea: split the driver code into units

Split the driver into the following parts:
  * core  -- resources, register access, capabilities, etc;
  * udc   -- device controller functionality;
  * debug -- logging events.
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent bc25a80d
config USB_CHIPIDEA config USB_CHIPIDEA
tristate "ChipIdea Highspeed Dual Role Controller" tristate "ChipIdea Highspeed Dual Role Controller"
depends on USB && USB_GADGET depends on USB
select USB_GADGET_DUALSPEED
help help
Say Y here if your system has a dual role high speed USB Say Y here if your system has a dual role high speed USB
controller based on ChipIdea silicon IP. Currently, only the controller based on ChipIdea silicon IP. Currently, only the
peripheral mode is supported. peripheral mode is supported.
When compiled dynamically, the module will be called ci-hdrc.ko. When compiled dynamically, the module will be called ci-hdrc.ko.
if USB_CHIPIDEA
config USB_CHIPIDEA_UDC
bool "ChipIdea device controller"
depends on USB_GADGET
select USB_GADGET_DUALSPEED
help
Say Y here to enable device controller functionality of the
ChipIdea driver.
config USB_CHIPIDEA_DEBUG
bool "ChipIdea driver debug"
help
Say Y here to enable debugging output of the ChipIdea driver.
endif
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
ci_hdrc-y := ci13xxx_udc.o ci_hdrc-y := core.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
ifneq ($(CONFIG_PCI),) ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
......
/*
* bits.h - register bits of the ChipIdea USB IP core
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
* Author: David Lopo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DRIVERS_USB_CHIPIDEA_BITS_H
#define __DRIVERS_USB_CHIPIDEA_BITS_H
/* HCCPARAMS */
#define HCCPARAMS_LEN BIT(17)
/* DCCPARAMS */
#define DCCPARAMS_DEN (0x1F << 0)
#define DCCPARAMS_DC BIT(7)
/* TESTMODE */
#define TESTMODE_FORCE BIT(0)
/* USBCMD */
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
#define USBCMD_SUTW BIT(13)
#define USBCMD_ATDTW BIT(14)
/* USBSTS & USBINTR */
#define USBi_UI BIT(0)
#define USBi_UEI BIT(1)
#define USBi_PCI BIT(2)
#define USBi_URI BIT(6)
#define USBi_SLI BIT(8)
/* DEVICEADDR */
#define DEVICEADDR_USBADRA BIT(24)
#define DEVICEADDR_USBADR (0x7FUL << 25)
/* PORTSC */
#define PORTSC_FPR BIT(6)
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
#define DEVLC_PSPD_HS (0x02UL << 25)
/* USBMODE */
#define USBMODE_CM (0x03UL << 0)
#define USBMODE_CM_IDLE (0x00UL << 0)
#define USBMODE_CM_DEVICE (0x02UL << 0)
#define USBMODE_CM_HOST (0x03UL << 0)
#define USBMODE_SLOM BIT(3)
#define USBMODE_SDIS BIT(4)
/* ENDPTCTRL */
#define ENDPTCTRL_RXS BIT(0)
#define ENDPTCTRL_RXT (0x03UL << 2)
#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
#define ENDPTCTRL_RXE BIT(7)
#define ENDPTCTRL_TXS BIT(16)
#define ENDPTCTRL_TXT (0x03UL << 18)
#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
#define ENDPTCTRL_TXE BIT(23)
#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */
/* /*
* ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core * ci.h - common structures, functions, and macros of the ChipIdea driver
* *
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
* *
...@@ -8,77 +8,24 @@ ...@@ -8,77 +8,24 @@
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* Description: MIPS USB IP core family device controller
* Structures, registers and logging macros
*/ */
#ifndef _CI13XXX_h_ #ifndef __DRIVERS_USB_CHIPIDEA_CI_H
#define _CI13XXX_h_ #define __DRIVERS_USB_CHIPIDEA_CI_H
#include <linux/list.h>
#include <linux/usb/gadget.h>
/****************************************************************************** /******************************************************************************
* DEFINE * DEFINE
*****************************************************************************/ *****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ #define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32 #define ENDPT_MAX 32
#define CTRL_PAYLOAD_MAX 64
#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */
#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
/****************************************************************************** /******************************************************************************
* STRUCTURES * STRUCTURES
*****************************************************************************/ *****************************************************************************/
/* DMA layout of transfer descriptors */
struct ci13xxx_td {
/* 0 */
u32 next;
#define TD_TERMINATE BIT(0)
#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
/* 1 */
u32 token;
#define TD_STATUS (0x00FFUL << 0)
#define TD_STATUS_TR_ERR BIT(3)
#define TD_STATUS_DT_ERR BIT(5)
#define TD_STATUS_HALTED BIT(6)
#define TD_STATUS_ACTIVE BIT(7)
#define TD_MULTO (0x0003UL << 10)
#define TD_IOC BIT(15)
#define TD_TOTAL_BYTES (0x7FFFUL << 16)
/* 2 */
u32 page[5];
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
} __attribute__ ((packed));
/* DMA layout of queue heads */
struct ci13xxx_qh {
/* 0 */
u32 cap;
#define QH_IOS BIT(15)
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
/* 1 */
u32 curr;
/* 2 - 8 */
struct ci13xxx_td td;
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
} __attribute__ ((packed));
/* Extension of usb_request */
struct ci13xxx_req {
struct usb_request req;
unsigned map;
struct list_head queue;
struct ci13xxx_td *ptr;
dma_addr_t dma;
struct ci13xxx_td *zptr;
dma_addr_t zdma;
};
/* Extension of usb_ep */ /* Extension of usb_ep */
struct ci13xxx_ep { struct ci13xxx_ep {
struct usb_ep ep; struct usb_ep ep;
...@@ -100,22 +47,6 @@ struct ci13xxx_ep { ...@@ -100,22 +47,6 @@ struct ci13xxx_ep {
struct dma_pool *td_pool; struct dma_pool *td_pool;
}; };
struct ci13xxx;
struct ci13xxx_udc_driver {
const char *name;
/* offset of the capability registers */
uintptr_t capoffset;
unsigned long flags;
#define CI13XXX_REGS_SHARED BIT(0)
#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
#define CI13XXX_PULLUP_ON_VBUS BIT(2)
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
struct hw_bank { struct hw_bank {
unsigned lpm; /* is LPM? */ unsigned lpm; /* is LPM? */
void __iomem *abs; /* bus map offset */ void __iomem *abs; /* bus map offset */
...@@ -159,9 +90,6 @@ struct ci13xxx { ...@@ -159,9 +90,6 @@ struct ci13xxx {
/****************************************************************************** /******************************************************************************
* REGISTERS * REGISTERS
*****************************************************************************/ *****************************************************************************/
/* Default offset of capability registers */
#define DEF_CAPOFFSET 0x100
/* register size */ /* register size */
#define REG_BITS (32) #define REG_BITS (32)
...@@ -190,59 +118,87 @@ enum ci13xxx_regs { ...@@ -190,59 +118,87 @@ enum ci13xxx_regs {
OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2, OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
}; };
/* HCCPARAMS */
#define HCCPARAMS_LEN BIT(17) /**
* ffs_nr: find first (least significant) bit set
/* DCCPARAMS */ * @x: the word to search
#define DCCPARAMS_DEN (0x1F << 0) *
#define DCCPARAMS_DC BIT(7) * This function returns bit number (instead of position)
*/
/* TESTMODE */ static inline int ffs_nr(u32 x)
#define TESTMODE_FORCE BIT(0) {
int n = ffs(x);
/* USBCMD */
#define USBCMD_RS BIT(0) return n ? n-1 : 32;
#define USBCMD_RST BIT(1) }
#define USBCMD_SUTW BIT(13)
#define USBCMD_ATDTW BIT(14) /**
* hw_read: reads from a hw register
/* USBSTS & USBINTR */ * @reg: register index
#define USBi_UI BIT(0) * @mask: bitfield mask
#define USBi_UEI BIT(1) *
#define USBi_PCI BIT(2) * This function returns register contents
#define USBi_URI BIT(6) */
#define USBi_SLI BIT(8) static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
{
/* DEVICEADDR */ return ioread32(udc->hw_bank.regmap[reg]) & mask;
#define DEVICEADDR_USBADRA BIT(24) }
#define DEVICEADDR_USBADR (0x7FUL << 25)
/**
/* PORTSC */ * hw_write: writes to a hw register
#define PORTSC_FPR BIT(6) * @reg: register index
#define PORTSC_SUSP BIT(7) * @mask: bitfield mask
#define PORTSC_HSP BIT(9) * @data: new value
#define PORTSC_PTC (0x0FUL << 16) */
static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
/* DEVLC */ u32 mask, u32 data)
#define DEVLC_PSPD (0x03UL << 25) {
#define DEVLC_PSPD_HS (0x02UL << 25) if (~mask)
data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
/* USBMODE */ | (data & mask);
#define USBMODE_CM (0x03UL << 0)
#define USBMODE_CM_IDLE (0x00UL << 0) iowrite32(data, udc->hw_bank.regmap[reg]);
#define USBMODE_CM_DEVICE (0x02UL << 0) }
#define USBMODE_CM_HOST (0x03UL << 0)
#define USBMODE_SLOM BIT(3) /**
#define USBMODE_SDIS BIT(4) * hw_test_and_clear: tests & clears a hw register
* @reg: register index
/* ENDPTCTRL */ * @mask: bitfield mask
#define ENDPTCTRL_RXS BIT(0) *
#define ENDPTCTRL_RXT (0x03UL << 2) * This function returns register contents
#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ */
#define ENDPTCTRL_RXE BIT(7) static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
#define ENDPTCTRL_TXS BIT(16) u32 mask)
#define ENDPTCTRL_TXT (0x03UL << 18) {
#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
#define ENDPTCTRL_TXE BIT(23)
iowrite32(val, udc->hw_bank.regmap[reg]);
#endif /* _CI13XXX_h_ */ return val;
}
/**
* hw_test_and_write: tests & writes a hw register
* @reg: register index
* @mask: bitfield mask
* @data: new value
*
* This function returns register contents
*/
static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
u32 mask, u32 data)
{
u32 val = hw_read(udc, reg, ~0);
hw_write(udc, reg, mask, data);
return (val & mask) >> ffs_nr(mask);
}
int hw_device_init(struct ci13xxx *udc, void __iomem *base,
uintptr_t cap_offset);
int hw_device_reset(struct ci13xxx *ci);
int hw_port_test_set(struct ci13xxx *ci, u8 mode);
u8 hw_port_test_get(struct ci13xxx *ci);
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
#include <linux/usb/msm_hsusb_hw.h> #include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h> #include <linux/usb/ulpi.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/chipidea.h>
#include "ci13xxx_udc.h" #include "ci.h"
#define MSM_USB_BASE (udc->regs) #define MSM_USB_BASE (udc->regs)
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/chipidea.h>
#include "ci13xxx_udc.h"
/* driver name */ /* driver name */
#define UDC_DRIVER_NAME "ci13xxx_pci" #define UDC_DRIVER_NAME "ci13xxx_pci"
......
/*
* core.c - ChipIdea USB IP core family device controller
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
* Author: David Lopo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Description: ChipIdea USB IP core family device controller
*
* This driver is composed of several blocks:
* - HW: hardware interface
* - DBG: debug facilities (optional)
* - UTIL: utilities
* - ISR: interrupts handling
* - ENDPT: endpoint operations (Gadget API)
* - GADGET: gadget operations (Gadget API)
* - BUS: bus glue code, bus abstraction layer
*
* Compile Options
* - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
* - STALL_IN: non-empty bulk-in pipes cannot be halted
* if defined mass storage compliance succeeds but with warnings
* => case 4: Hi > Dn
* => case 5: Hi > Di
* => case 8: Hi <> Do
* if undefined usbtest 13 fails
* - TRACE: enable function tracing (depends on DEBUG)
*
* Main Features
* - Chapter 9 & Mass Storage Compliance with Gadget File Storage
* - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
* - Normal & LPM support
*
* USBTEST Report
* - OK: 0-12, 13 (STALL_IN defined) & 14
* - Not Supported: 15 & 16 (ISO)
*
* TODO List
* - OTG
* - Isochronous & Interrupt Traffic
* - Handle requests which spawns into several TDs
* - GET_STATUS(device) - always reports 0
* - Gadget API (majority of optional features)
* - Suspend & Remote Wakeup
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "debug.h"
/* MSM specific */
#define ABS_AHBBURST (0x0090UL)
#define ABS_AHBMODE (0x0098UL)
/* UDC register map */
static uintptr_t ci_regs_nolpm[] = {
[CAP_CAPLENGTH] = 0x000UL,
[CAP_HCCPARAMS] = 0x008UL,
[CAP_DCCPARAMS] = 0x024UL,
[CAP_TESTMODE] = 0x038UL,
[OP_USBCMD] = 0x000UL,
[OP_USBSTS] = 0x004UL,
[OP_USBINTR] = 0x008UL,
[OP_DEVICEADDR] = 0x014UL,
[OP_ENDPTLISTADDR] = 0x018UL,
[OP_PORTSC] = 0x044UL,
[OP_DEVLC] = 0x084UL,
[OP_USBMODE] = 0x068UL,
[OP_ENDPTSETUPSTAT] = 0x06CUL,
[OP_ENDPTPRIME] = 0x070UL,
[OP_ENDPTFLUSH] = 0x074UL,
[OP_ENDPTSTAT] = 0x078UL,
[OP_ENDPTCOMPLETE] = 0x07CUL,
[OP_ENDPTCTRL] = 0x080UL,
};
static uintptr_t ci_regs_lpm[] = {
[CAP_CAPLENGTH] = 0x000UL,
[CAP_HCCPARAMS] = 0x008UL,
[CAP_DCCPARAMS] = 0x024UL,
[CAP_TESTMODE] = 0x0FCUL,
[OP_USBCMD] = 0x000UL,
[OP_USBSTS] = 0x004UL,
[OP_USBINTR] = 0x008UL,
[OP_DEVICEADDR] = 0x014UL,
[OP_ENDPTLISTADDR] = 0x018UL,
[OP_PORTSC] = 0x044UL,
[OP_DEVLC] = 0x084UL,
[OP_USBMODE] = 0x0C8UL,
[OP_ENDPTSETUPSTAT] = 0x0D8UL,
[OP_ENDPTPRIME] = 0x0DCUL,
[OP_ENDPTFLUSH] = 0x0E0UL,
[OP_ENDPTSTAT] = 0x0E4UL,
[OP_ENDPTCOMPLETE] = 0x0E8UL,
[OP_ENDPTCTRL] = 0x0ECUL,
};
static int hw_alloc_regmap(struct ci13xxx *udc, bool is_lpm)
{
int i;
kfree(udc->hw_bank.regmap);
udc->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *),
GFP_KERNEL);
if (!udc->hw_bank.regmap)
return -ENOMEM;
for (i = 0; i < OP_ENDPTCTRL; i++)
udc->hw_bank.regmap[i] =
(i <= CAP_LAST ? udc->hw_bank.cap : udc->hw_bank.op) +
(is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]);
for (; i <= OP_LAST; i++)
udc->hw_bank.regmap[i] = udc->hw_bank.op +
4 * (i - OP_ENDPTCTRL) +
(is_lpm
? ci_regs_lpm[OP_ENDPTCTRL]
: ci_regs_nolpm[OP_ENDPTCTRL]);
return 0;
}
/**
* hw_port_test_set: writes port test mode (execute without interruption)
* @mode: new value
*
* This function returns an error code
*/
int hw_port_test_set(struct ci13xxx *ci, u8 mode)
{
const u8 TEST_MODE_MAX = 7;
if (mode > TEST_MODE_MAX)
return -EINVAL;
hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
return 0;
}
/**
* hw_port_test_get: reads port test mode value
*
* This function returns port test mode value
*/
u8 hw_port_test_get(struct ci13xxx *ci)
{
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
}
int hw_device_init(struct ci13xxx *udc, void __iomem *base,
uintptr_t cap_offset)
{
u32 reg;
/* bank is a module variable */
udc->hw_bank.abs = base;
udc->hw_bank.cap = udc->hw_bank.abs;
udc->hw_bank.cap += cap_offset;
udc->hw_bank.op = udc->hw_bank.cap + ioread8(udc->hw_bank.cap);
hw_alloc_regmap(udc, false);
reg = hw_read(udc, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
ffs_nr(HCCPARAMS_LEN);
udc->hw_bank.lpm = reg;
hw_alloc_regmap(udc, !!reg);
udc->hw_bank.size = udc->hw_bank.op - udc->hw_bank.abs;
udc->hw_bank.size += OP_LAST;
udc->hw_bank.size /= sizeof(u32);
reg = hw_read(udc, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
ffs_nr(DCCPARAMS_DEN);
udc->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
if (udc->hw_ep_max == 0 || udc->hw_ep_max > ENDPT_MAX)
return -ENODEV;
dev_dbg(udc->dev, "ChipIdea UDC found, lpm: %d; cap: %p op: %p\n",
udc->hw_bank.lpm, udc->hw_bank.cap, udc->hw_bank.op);
/* setup lock mode ? */
/* ENDPTSETUPSTAT is '0' by default */
/* HCSPARAMS.bf.ppc SHOULD BE zero for device */
return 0;
}
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
*
* This function returns an error code
*/
int hw_device_reset(struct ci13xxx *ci)
{
/* should flush & stop before reset */
hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
if (ci->udc_driver->notify_event)
ci->udc_driver->notify_event(ci,
CI13XXX_CONTROLLER_RESET_EVENT);
if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
/* HW >= 2.3 */
hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
pr_err("cannot enter in device mode");
pr_err("lpm = %i", ci->hw_bank.lpm);
return -ENODEV;
}
return 0;
}
static int __devinit ci_udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ci13xxx_udc_driver *driver = dev->platform_data;
struct ci13xxx *udc;
struct resource *res;
void __iomem *base;
int ret;
if (!driver) {
dev_err(dev, "platform data missing\n");
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing resource\n");
return -ENODEV;
}
base = devm_request_and_ioremap(dev, res);
if (!res) {
dev_err(dev, "can't request and ioremap resource\n");
return -ENOMEM;
}
ret = udc_probe(driver, dev, base, &udc);
if (ret)
return ret;
udc->irq = platform_get_irq(pdev, 0);
if (udc->irq < 0) {
dev_err(dev, "missing IRQ\n");
ret = -ENODEV;
goto out;
}
platform_set_drvdata(pdev, udc);
ret = request_irq(udc->irq, udc_irq, IRQF_SHARED, driver->name, udc);
out:
if (ret)
udc_remove(udc);
return ret;
}
static int __devexit ci_udc_remove(struct platform_device *pdev)
{
struct ci13xxx *udc = platform_get_drvdata(pdev);
free_irq(udc->irq, udc);
udc_remove(udc);
return 0;
}
static struct platform_driver ci_udc_driver = {
.probe = ci_udc_probe,
.remove = __devexit_p(ci_udc_remove),
.driver = {
.name = "ci_udc",
},
};
module_platform_driver(ci_udc_driver);
MODULE_ALIAS("platform:ci_udc");
MODULE_ALIAS("platform:ci13xxx");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("ChipIdea UDC Driver");
This diff is collapsed.
/*
* debug.h - ChipIdea USB driver debug interfaces
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
* Author: David Lopo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DRIVERS_USB_CHIPIDEA_DEBUG_H
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
void dbg_interrupt(u32 intmask);
void dbg_done(u8 addr, const u32 token, int status);
void dbg_event(u8 addr, const char *name, int status);
void dbg_queue(u8 addr, const struct usb_request *req, int status);
void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
int dbg_create_files(struct device *dev);
int dbg_remove_files(struct device *dev);
#else
static inline void dbg_interrupt(u32 intmask)
{
}
static inline void dbg_done(u8 addr, const u32 token, int status)
{
}
static inline void dbg_event(u8 addr, const char *name, int status)
{
}
static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
{
}
static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
{
}
static inline int dbg_create_files(struct device *dev)
{
return 0;
}
static inline int dbg_remove_files(struct device *dev)
{
return 0;
}
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */
/*
* udc.h - ChipIdea UDC structures
*
* Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
*
* Author: David Lopo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __DRIVERS_USB_CHIPIDEA_UDC_H
#define __DRIVERS_USB_CHIPIDEA_UDC_H
#include <linux/list.h>
#define CTRL_PAYLOAD_MAX 64
#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */
#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
/* DMA layout of transfer descriptors */
struct ci13xxx_td {
/* 0 */
u32 next;
#define TD_TERMINATE BIT(0)
#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
/* 1 */
u32 token;
#define TD_STATUS (0x00FFUL << 0)
#define TD_STATUS_TR_ERR BIT(3)
#define TD_STATUS_DT_ERR BIT(5)
#define TD_STATUS_HALTED BIT(6)
#define TD_STATUS_ACTIVE BIT(7)
#define TD_MULTO (0x0003UL << 10)
#define TD_IOC BIT(15)
#define TD_TOTAL_BYTES (0x7FFFUL << 16)
/* 2 */
u32 page[5];
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
} __attribute__ ((packed));
/* DMA layout of queue heads */
struct ci13xxx_qh {
/* 0 */
u32 cap;
#define QH_IOS BIT(15)
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
/* 1 */
u32 curr;
/* 2 - 8 */
struct ci13xxx_td td;
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
} __attribute__ ((packed));
/* Extension of usb_request */
struct ci13xxx_req {
struct usb_request req;
unsigned map;
struct list_head queue;
struct ci13xxx_td *ptr;
dma_addr_t dma;
struct ci13xxx_td *zptr;
dma_addr_t zdma;
};
#ifdef CONFIG_USB_CHIPIDEA_UDC
irqreturn_t udc_irq(int irq, void *data);
int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
void __iomem *regs, struct ci13xxx **_udc);
void udc_remove(struct ci13xxx *udc);
#else
static inline irqreturn_t udc_irq(int irq, void *data)
{
return IRQ_NONE;
}
static inline
int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
void __iomem *regs, struct ci13xxx **_udc)
{
return -ENODEV;
}
static inline void udc_remove(struct ci13xxx *udc)
{
}
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
/*
* Platform data for the chipidea USB dual role controller
*/
#ifndef __LINUX_USB_CHIPIDEA_H
#define __LINUX_USB_CHIPIDEA_H
struct ci13xxx;
struct ci13xxx_udc_driver {
const char *name;
/* offset of the capability registers */
uintptr_t capoffset;
unsigned long flags;
#define CI13XXX_REGS_SHARED BIT(0)
#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
#define CI13XXX_PULLUP_ON_VBUS BIT(2)
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
/* Default offset of capability registers */
#define DEF_CAPOFFSET 0x100
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment