usb: isp1760: Add device controller support
The ISP1761 is a dual-mode host and device controller backward compatible on the host side with the ISP1760. Add support for the device controller. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
9a66e13290
commit
0316ca6319
|
@ -109,6 +109,13 @@ config USB_GR_UDC
|
|||
Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB
|
||||
VHDL IP core library.
|
||||
|
||||
config USB_ISP1761_UDC
|
||||
boolean "NXP ISP1761 USB Device Controller"
|
||||
depends on USB_ISP1760_HCD
|
||||
help
|
||||
The NXP ISP1761 is a dual-role high-speed USB host and device
|
||||
controller.
|
||||
|
||||
config USB_OMAP
|
||||
tristate "OMAP USB Device Controller"
|
||||
depends on ARCH_OMAP1
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
CFLAGS_xhci-trace.o := -I$(src)
|
||||
|
||||
isp1760-y := isp1760-core.o isp1760-hcd.o isp1760-if.o
|
||||
isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
|
||||
|
||||
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
|
||||
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
#include "isp1760-core.h"
|
||||
#include "isp1760-hcd.h"
|
||||
#include "isp1760-regs.h"
|
||||
#include "isp1760-udc.h"
|
||||
|
||||
static void isp1760_init_core(struct isp1760_device *isp)
|
||||
{
|
||||
u32 otgctrl;
|
||||
u32 hwmode;
|
||||
|
||||
/* Low-level chip reset */
|
||||
|
@ -59,6 +61,17 @@ static void isp1760_init_core(struct isp1760_device *isp)
|
|||
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
|
||||
hwmode |= HW_INTR_EDGE_TRIG;
|
||||
|
||||
/*
|
||||
* The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
|
||||
* IRQ line for both the host and device controllers. Hardcode IRQ
|
||||
* sharing for now and disable the DC interrupts globally to avoid
|
||||
* spurious interrupts during HCD registration.
|
||||
*/
|
||||
if (isp->devflags & ISP1760_FLAG_ISP1761) {
|
||||
isp1760_write32(isp->regs, DC_MODE, 0);
|
||||
hwmode |= HW_COMN_IRQ;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to set this first in case we're in 16-bit mode.
|
||||
* Write it twice to ensure correct upper bits if switching
|
||||
|
@ -68,18 +81,33 @@ static void isp1760_init_core(struct isp1760_device *isp)
|
|||
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
|
||||
|
||||
/*
|
||||
* PORT 1 Control register of the ISP1760 is the OTG control register on
|
||||
* ISP1761. Since there is no OTG or device controller support in this
|
||||
* driver, we use port 1 as a "normal" USB host port on both chips.
|
||||
* PORT 1 Control register of the ISP1760 is the OTG control register
|
||||
* on ISP1761.
|
||||
*
|
||||
* TODO: Really support OTG. For now we configure port 1 in device mode
|
||||
* when OTG is requested.
|
||||
*/
|
||||
isp1760_write32(isp->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
|
||||
usleep_range(10000, 11000);
|
||||
if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
|
||||
(isp->devflags & ISP1760_FLAG_OTG_EN))
|
||||
otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
|
||||
| HW_OTG_DISABLE;
|
||||
else
|
||||
otgctrl = (HW_SW_SEL_HC_DC << 16)
|
||||
| (HW_VBUS_DRV | HW_SEL_CP_EXT);
|
||||
|
||||
isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
|
||||
|
||||
dev_info(isp->dev, "bus width: %u, oc: %s\n",
|
||||
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
|
||||
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
|
||||
}
|
||||
|
||||
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
|
||||
{
|
||||
isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
|
||||
enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
|
||||
}
|
||||
|
||||
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
||||
struct device *dev, unsigned int devflags)
|
||||
{
|
||||
|
@ -114,6 +142,15 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (devflags & ISP1760_FLAG_ISP1761) {
|
||||
ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
|
||||
IRQF_DISABLED);
|
||||
if (ret < 0) {
|
||||
isp1760_hcd_unregister(&isp->hcd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, isp);
|
||||
|
||||
return 0;
|
||||
|
@ -123,6 +160,9 @@ void isp1760_unregister(struct device *dev)
|
|||
{
|
||||
struct isp1760_device *isp = dev_get_drvdata(dev);
|
||||
|
||||
if (isp->devflags & ISP1760_FLAG_ISP1761)
|
||||
isp1760_udc_unregister(isp);
|
||||
|
||||
isp1760_hcd_unregister(&isp->hcd);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/ioport.h>
|
||||
|
||||
#include "isp1760-hcd.h"
|
||||
#include "isp1760-udc.h"
|
||||
|
||||
struct device;
|
||||
struct gpio_desc;
|
||||
|
@ -45,12 +46,15 @@ struct isp1760_device {
|
|||
struct gpio_desc *rst_gpio;
|
||||
|
||||
struct isp1760_hcd hcd;
|
||||
struct isp1760_udc udc;
|
||||
};
|
||||
|
||||
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
||||
struct device *dev, unsigned int devflags);
|
||||
void isp1760_unregister(struct device *dev);
|
||||
|
||||
void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
|
||||
|
||||
static inline u32 isp1760_read32(void __iomem *base, u32 reg)
|
||||
{
|
||||
return readl(base + reg);
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#ifndef _ISP1760_REGS_H_
|
||||
#define _ISP1760_REGS_H_
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Host Controller
|
||||
*/
|
||||
|
||||
/* EHCI capability registers */
|
||||
#define HC_CAPLENGTH 0x000
|
||||
#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
|
||||
|
@ -70,6 +74,9 @@
|
|||
#define HC_HW_MODE_CTRL 0x300
|
||||
#define ALL_ATX_RESET (1 << 31)
|
||||
#define HW_ANA_DIGI_OC (1 << 15)
|
||||
#define HW_DEV_DMA (1 << 11)
|
||||
#define HW_COMN_IRQ (1 << 10)
|
||||
#define HW_COMN_DMA (1 << 9)
|
||||
#define HW_DATA_BUS_32BIT (1 << 8)
|
||||
#define HW_DACK_POL_HIGH (1 << 6)
|
||||
#define HW_DREQ_POL_HIGH (1 << 5)
|
||||
|
@ -98,6 +105,17 @@
|
|||
#define PORT1_INIT2 (1 << 23)
|
||||
#define HW_OTG_CTRL_SET 0x374
|
||||
#define HW_OTG_CTRL_CLR 0x376
|
||||
#define HW_OTG_DISABLE (1 << 10)
|
||||
#define HW_OTG_SE0_EN (1 << 9)
|
||||
#define HW_BDIS_ACON_EN (1 << 8)
|
||||
#define HW_SW_SEL_HC_DC (1 << 7)
|
||||
#define HW_VBUS_CHRG (1 << 6)
|
||||
#define HW_VBUS_DISCHRG (1 << 5)
|
||||
#define HW_VBUS_DRV (1 << 4)
|
||||
#define HW_SEL_CP_EXT (1 << 3)
|
||||
#define HW_DM_PULLDOWN (1 << 2)
|
||||
#define HW_DP_PULLDOWN (1 << 1)
|
||||
#define HW_DP_PULLUP (1 << 0)
|
||||
|
||||
/* Interrupt Register */
|
||||
#define HC_INTERRUPT_REG 0x310
|
||||
|
@ -117,4 +135,96 @@
|
|||
#define HC_INT_IRQ_MASK_AND_REG 0x328
|
||||
#define HC_ATL_IRQ_MASK_AND_REG 0x32c
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Peripheral Controller
|
||||
*/
|
||||
|
||||
/* Initialization Registers */
|
||||
#define DC_ADDRESS 0x0200
|
||||
#define DC_DEVEN (1 << 7)
|
||||
|
||||
#define DC_MODE 0x020c
|
||||
#define DC_DMACLKON (1 << 9)
|
||||
#define DC_VBUSSTAT (1 << 8)
|
||||
#define DC_CLKAON (1 << 7)
|
||||
#define DC_SNDRSU (1 << 6)
|
||||
#define DC_GOSUSP (1 << 5)
|
||||
#define DC_SFRESET (1 << 4)
|
||||
#define DC_GLINTENA (1 << 3)
|
||||
#define DC_WKUPCS (1 << 2)
|
||||
|
||||
#define DC_INTCONF 0x0210
|
||||
#define DC_CDBGMOD_ACK_NAK (0 << 6)
|
||||
#define DC_CDBGMOD_ACK (1 << 6)
|
||||
#define DC_CDBGMOD_ACK_1NAK (2 << 6)
|
||||
#define DC_DDBGMODIN_ACK_NAK (0 << 4)
|
||||
#define DC_DDBGMODIN_ACK (1 << 4)
|
||||
#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
|
||||
#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
|
||||
#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
|
||||
#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
|
||||
#define DC_INTLVL (1 << 1)
|
||||
#define DC_INTPOL (1 << 0)
|
||||
|
||||
#define DC_DEBUG 0x0212
|
||||
#define DC_INTENABLE 0x0214
|
||||
#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
|
||||
#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
|
||||
#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
|
||||
#define DC_IEP0SETUP (1 << 8)
|
||||
#define DC_IEVBUS (1 << 7)
|
||||
#define DC_IEDMA (1 << 6)
|
||||
#define DC_IEHS_STA (1 << 5)
|
||||
#define DC_IERESM (1 << 4)
|
||||
#define DC_IESUSP (1 << 3)
|
||||
#define DC_IEPSOF (1 << 2)
|
||||
#define DC_IESOF (1 << 1)
|
||||
#define DC_IEBRST (1 << 0)
|
||||
|
||||
/* Data Flow Registers */
|
||||
#define DC_EPINDEX 0x022c
|
||||
#define DC_EP0SETUP (1 << 5)
|
||||
#define DC_ENDPIDX(n) ((n) << 1)
|
||||
#define DC_EPDIR (1 << 0)
|
||||
|
||||
#define DC_CTRLFUNC 0x0228
|
||||
#define DC_CLBUF (1 << 4)
|
||||
#define DC_VENDP (1 << 3)
|
||||
#define DC_DSEN (1 << 2)
|
||||
#define DC_STATUS (1 << 1)
|
||||
#define DC_STALL (1 << 0)
|
||||
|
||||
#define DC_DATAPORT 0x0220
|
||||
#define DC_BUFLEN 0x021c
|
||||
#define DC_DATACOUNT_MASK 0xffff
|
||||
#define DC_BUFSTAT 0x021e
|
||||
#define DC_EPMAXPKTSZ 0x0204
|
||||
|
||||
#define DC_EPTYPE 0x0208
|
||||
#define DC_NOEMPKT (1 << 4)
|
||||
#define DC_EPENABLE (1 << 3)
|
||||
#define DC_DBLBUF (1 << 2)
|
||||
#define DC_ENDPTYP_ISOC (1 << 0)
|
||||
#define DC_ENDPTYP_BULK (2 << 0)
|
||||
#define DC_ENDPTYP_INTERRUPT (3 << 0)
|
||||
|
||||
/* DMA Registers */
|
||||
#define DC_DMACMD 0x0230
|
||||
#define DC_DMATXCOUNT 0x0234
|
||||
#define DC_DMACONF 0x0238
|
||||
#define DC_DMAHW 0x023c
|
||||
#define DC_DMAINTREASON 0x0250
|
||||
#define DC_DMAINTEN 0x0254
|
||||
#define DC_DMAEP 0x0258
|
||||
#define DC_DMABURSTCOUNT 0x0264
|
||||
|
||||
/* General Registers */
|
||||
#define DC_INTERRUPT 0x0218
|
||||
#define DC_CHIPID 0x0270
|
||||
#define DC_FRAMENUM 0x0274
|
||||
#define DC_SCRATCH 0x0278
|
||||
#define DC_UNLOCKDEV 0x027c
|
||||
#define DC_INTPULSEWIDTH 0x0280
|
||||
#define DC_TESTMODE 0x0284
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Driver for the NXP ISP1761 device controller
|
||||
*
|
||||
* Copyright 2014 Ideas on Board Oy
|
||||
*
|
||||
* Contacts:
|
||||
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
*
|
||||
* 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 _ISP1760_UDC_H_
|
||||
#define _ISP1760_UDC_H_
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
struct isp1760_device;
|
||||
struct isp1760_udc;
|
||||
|
||||
enum isp1760_ctrl_state {
|
||||
ISP1760_CTRL_SETUP, /* Waiting for a SETUP transaction */
|
||||
ISP1760_CTRL_DATA_IN, /* Setup received, data IN stage */
|
||||
ISP1760_CTRL_DATA_OUT, /* Setup received, data OUT stage */
|
||||
ISP1760_CTRL_STATUS, /* 0-length request in status stage */
|
||||
};
|
||||
|
||||
struct isp1760_ep {
|
||||
struct isp1760_udc *udc;
|
||||
struct usb_ep ep;
|
||||
|
||||
struct list_head queue;
|
||||
|
||||
unsigned int addr;
|
||||
unsigned int maxpacket;
|
||||
char name[7];
|
||||
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
|
||||
bool rx_pending;
|
||||
bool halted;
|
||||
bool wedged;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct isp1760_udc - UDC state information
|
||||
* irq: IRQ number
|
||||
* irqname: IRQ name (as passed to request_irq)
|
||||
* regs: Base address of the UDC registers
|
||||
* driver: Gadget driver
|
||||
* gadget: Gadget device
|
||||
* lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
|
||||
* ep: Array of endpoints
|
||||
* ep0_state: Control request state for endpoint 0
|
||||
* ep0_dir: Direction of the current control request
|
||||
* ep0_length: Length of the current control request
|
||||
* connected: Tracks gadget driver bus connection state
|
||||
*/
|
||||
struct isp1760_udc {
|
||||
#if CONFIG_USB_ISP1761_UDC
|
||||
struct isp1760_device *isp;
|
||||
|
||||
int irq;
|
||||
char *irqname;
|
||||
void __iomem *regs;
|
||||
|
||||
struct usb_gadget_driver *driver;
|
||||
struct usb_gadget gadget;
|
||||
|
||||
spinlock_t lock;
|
||||
struct timer_list vbus_timer;
|
||||
|
||||
struct isp1760_ep ep[15];
|
||||
|
||||
enum isp1760_ctrl_state ep0_state;
|
||||
u8 ep0_dir;
|
||||
u16 ep0_length;
|
||||
|
||||
bool connected;
|
||||
|
||||
unsigned int devstatus;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if CONFIG_USB_ISP1761_UDC
|
||||
int isp1760_udc_register(struct isp1760_device *isp, int irq,
|
||||
unsigned long irqflags);
|
||||
void isp1760_udc_unregister(struct isp1760_device *isp);
|
||||
#else
|
||||
static inline int isp1760_udc_register(struct isp1760_device *isp, int irq,
|
||||
unsigned long irqflags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void isp1760_udc_unregister(struct isp1760_device *isp)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue