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
|
Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB
|
||||||
VHDL IP core library.
|
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
|
config USB_OMAP
|
||||||
tristate "OMAP USB Device Controller"
|
tristate "OMAP USB Device Controller"
|
||||||
depends on ARCH_OMAP1
|
depends on ARCH_OMAP1
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
CFLAGS_xhci-trace.o := -I$(src)
|
CFLAGS_xhci-trace.o := -I$(src)
|
||||||
|
|
||||||
isp1760-y := isp1760-core.o isp1760-hcd.o isp1760-if.o
|
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-hcd.o fhci-hub.o fhci-q.o
|
||||||
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
||||||
|
|
|
@ -24,9 +24,11 @@
|
||||||
#include "isp1760-core.h"
|
#include "isp1760-core.h"
|
||||||
#include "isp1760-hcd.h"
|
#include "isp1760-hcd.h"
|
||||||
#include "isp1760-regs.h"
|
#include "isp1760-regs.h"
|
||||||
|
#include "isp1760-udc.h"
|
||||||
|
|
||||||
static void isp1760_init_core(struct isp1760_device *isp)
|
static void isp1760_init_core(struct isp1760_device *isp)
|
||||||
{
|
{
|
||||||
|
u32 otgctrl;
|
||||||
u32 hwmode;
|
u32 hwmode;
|
||||||
|
|
||||||
/* Low-level chip reset */
|
/* 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)
|
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
|
||||||
hwmode |= HW_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.
|
* We have to set this first in case we're in 16-bit mode.
|
||||||
* Write it twice to ensure correct upper bits if switching
|
* 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);
|
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PORT 1 Control register of the ISP1760 is the OTG control register on
|
* PORT 1 Control register of the ISP1760 is the OTG control register
|
||||||
* ISP1761. Since there is no OTG or device controller support in this
|
* on ISP1761.
|
||||||
* driver, we use port 1 as a "normal" USB host port on both chips.
|
*
|
||||||
|
* 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);
|
if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
|
||||||
usleep_range(10000, 11000);
|
(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",
|
dev_info(isp->dev, "bus width: %u, oc: %s\n",
|
||||||
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
|
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
|
||||||
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
|
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,
|
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
||||||
struct device *dev, unsigned int devflags)
|
struct device *dev, unsigned int devflags)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +142,15 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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);
|
dev_set_drvdata(dev, isp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -123,6 +160,9 @@ void isp1760_unregister(struct device *dev)
|
||||||
{
|
{
|
||||||
struct isp1760_device *isp = dev_get_drvdata(dev);
|
struct isp1760_device *isp = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (isp->devflags & ISP1760_FLAG_ISP1761)
|
||||||
|
isp1760_udc_unregister(isp);
|
||||||
|
|
||||||
isp1760_hcd_unregister(&isp->hcd);
|
isp1760_hcd_unregister(&isp->hcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
||||||
#include "isp1760-hcd.h"
|
#include "isp1760-hcd.h"
|
||||||
|
#include "isp1760-udc.h"
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
struct gpio_desc;
|
struct gpio_desc;
|
||||||
|
@ -45,12 +46,15 @@ struct isp1760_device {
|
||||||
struct gpio_desc *rst_gpio;
|
struct gpio_desc *rst_gpio;
|
||||||
|
|
||||||
struct isp1760_hcd hcd;
|
struct isp1760_hcd hcd;
|
||||||
|
struct isp1760_udc udc;
|
||||||
};
|
};
|
||||||
|
|
||||||
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
|
||||||
struct device *dev, unsigned int devflags);
|
struct device *dev, unsigned int devflags);
|
||||||
void isp1760_unregister(struct device *dev);
|
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)
|
static inline u32 isp1760_read32(void __iomem *base, u32 reg)
|
||||||
{
|
{
|
||||||
return readl(base + reg);
|
return readl(base + reg);
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
#ifndef _ISP1760_REGS_H_
|
#ifndef _ISP1760_REGS_H_
|
||||||
#define _ISP1760_REGS_H_
|
#define _ISP1760_REGS_H_
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* Host Controller
|
||||||
|
*/
|
||||||
|
|
||||||
/* EHCI capability registers */
|
/* EHCI capability registers */
|
||||||
#define HC_CAPLENGTH 0x000
|
#define HC_CAPLENGTH 0x000
|
||||||
#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
|
#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
|
||||||
|
@ -70,6 +74,9 @@
|
||||||
#define HC_HW_MODE_CTRL 0x300
|
#define HC_HW_MODE_CTRL 0x300
|
||||||
#define ALL_ATX_RESET (1 << 31)
|
#define ALL_ATX_RESET (1 << 31)
|
||||||
#define HW_ANA_DIGI_OC (1 << 15)
|
#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_DATA_BUS_32BIT (1 << 8)
|
||||||
#define HW_DACK_POL_HIGH (1 << 6)
|
#define HW_DACK_POL_HIGH (1 << 6)
|
||||||
#define HW_DREQ_POL_HIGH (1 << 5)
|
#define HW_DREQ_POL_HIGH (1 << 5)
|
||||||
|
@ -98,6 +105,17 @@
|
||||||
#define PORT1_INIT2 (1 << 23)
|
#define PORT1_INIT2 (1 << 23)
|
||||||
#define HW_OTG_CTRL_SET 0x374
|
#define HW_OTG_CTRL_SET 0x374
|
||||||
#define HW_OTG_CTRL_CLR 0x376
|
#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 */
|
/* Interrupt Register */
|
||||||
#define HC_INTERRUPT_REG 0x310
|
#define HC_INTERRUPT_REG 0x310
|
||||||
|
@ -117,4 +135,96 @@
|
||||||
#define HC_INT_IRQ_MASK_AND_REG 0x328
|
#define HC_INT_IRQ_MASK_AND_REG 0x328
|
||||||
#define HC_ATL_IRQ_MASK_AND_REG 0x32c
|
#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
|
#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