Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
# SPDX-License-Identifier: GPL-2.0
config USB_ISP1760
tristate "NXP ISP 1760/1761/1763 support"
depends on USB || USB_GADGET
select REGMAP_MMIO
help
Say Y or M here if your system as an ISP1760/1763 USB host controller
or an ISP1761 USB dual-role controller.
This driver does not support isochronous transfers or OTG.
This USB controller is usually attached to a non-DMA-Master
capable bus. NXP's eval kit brings this chip on PCI card
where the chip itself is behind a PLB to simulate such
a bus.
To compile this driver as a module, choose M here: the
module will be called isp1760.
config USB_ISP1760_HCD
bool
config USB_ISP1761_UDC
bool
if USB_ISP1760
choice
prompt "ISP1760 Mode Selection"
default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
config USB_ISP1760_HOST_ROLE
bool "Host only mode"
depends on USB=y || USB=USB_ISP1760
select USB_ISP1760_HCD
help
Select this if you want to use the ISP1760 in host mode only. The
gadget function will be disabled.
config USB_ISP1760_GADGET_ROLE
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in peripheral mode only.
The host function will be disabled.
config USB_ISP1760_DUAL_ROLE
bool "Dual Role mode"
depends on USB=y || USB=USB_ISP1760
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1760_HCD
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in both host and
peripheral modes.
endchoice
endif
+6
View File
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
isp1760-y := isp1760-core.o isp1760-if.o
isp1760-$(CONFIG_USB_ISP1760_HCD) += isp1760-hcd.o
isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
obj-$(CONFIG_USB_ISP1760) += isp1760.o
@@ -0,0 +1,607 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Rui Miguel Silva <rui.silva@linaro.org>
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
#include "isp1760-udc.h"
static int isp1760_init_core(struct isp1760_device *isp)
{
struct isp1760_hcd *hcd = &isp->hcd;
struct isp1760_udc *udc = &isp->udc;
u32 otg_ctrl;
/* Low-level chip reset */
if (isp->rst_gpio) {
gpiod_set_value_cansleep(isp->rst_gpio, 1);
msleep(50);
gpiod_set_value_cansleep(isp->rst_gpio, 0);
}
/*
* Reset the host controller, including the CPU interface
* configuration.
*/
isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) {
dev_err(isp->dev, "isp1763 analog overcurrent not available\n");
return -EINVAL;
}
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8)
isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH);
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT);
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
isp1760_field_set(hcd->fields, 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_reg_write(udc->regs, ISP176x_DC_MODE, 0);
isp1760_field_set(hcd->fields, HW_COMN_IRQ);
}
/*
* 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
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
if (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN) {
otg_ctrl = (ISP176x_HW_DM_PULLDOWN_CLEAR |
ISP176x_HW_DP_PULLDOWN_CLEAR |
ISP176x_HW_OTG_DISABLE);
} else {
otg_ctrl = (ISP176x_HW_SW_SEL_HC_DC_CLEAR |
ISP176x_HW_VBUS_DRV |
ISP176x_HW_SEL_CP_EXT);
}
isp1760_reg_write(hcd->regs, ISP176x_HC_OTG_CTRL, otg_ctrl);
}
dev_info(isp->dev, "%s bus width: %u, oc: %s\n",
hcd->is_isp1763 ? "isp1763" : "isp1760",
isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 :
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
hcd->is_isp1763 ? "not available" :
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
return 0;
}
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
{
struct isp1760_udc *udc = &isp->udc;
if (enable)
isp1760_field_set(udc->fields, HW_DP_PULLUP);
else
isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR);
}
/*
* ISP1760/61:
*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
static const struct isp1760_memory_layout isp176x_memory_conf = {
.blocks[0] = 32,
.blocks_size[0] = 256,
.blocks[1] = 20,
.blocks_size[1] = 1024,
.blocks[2] = 4,
.blocks_size[2] = 8192,
.slot_num = 32,
.payload_blocks = 32 + 20 + 4,
.payload_area_size = 0xf000,
};
/*
* ISP1763:
*
* 20kb divided in:
* - 8 blocks @ 256 bytes
* - 2 blocks @ 1024 bytes
* - 4 blocks @ 4096 bytes
*/
static const struct isp1760_memory_layout isp1763_memory_conf = {
.blocks[0] = 8,
.blocks_size[0] = 256,
.blocks[1] = 2,
.blocks_size[1] = 1024,
.blocks[2] = 4,
.blocks_size[2] = 4096,
.slot_num = 16,
.payload_blocks = 8 + 2 + 4,
.payload_area_size = 0x5000,
};
static const struct regmap_range isp176x_hc_volatile_ranges[] = {
regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD),
regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY),
regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR),
};
static const struct regmap_access_table isp176x_hc_volatile_table = {
.yes_ranges = isp176x_hc_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges),
};
static const struct regmap_config isp1760_hc_regmap_conf = {
.name = "isp1760-hc",
.reg_bits = 16,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.max_register = ISP176x_HC_OTG_CTRL_CLEAR,
.volatile_table = &isp176x_hc_volatile_table,
};
static const struct reg_field isp1760_hc_reg_fields[] = {
[HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4),
[HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3),
[HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7),
[HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6),
[CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7),
[CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1),
[CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0),
[STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2),
[HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13),
[FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0),
[HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31),
[HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31),
[HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31),
[HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31),
[HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31),
[HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31),
[HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31),
[HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31),
[HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31),
[PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13),
[PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12),
[PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11),
[PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8),
[PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7),
[PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6),
[PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2),
[PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1),
[PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0),
[ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31),
[HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15),
[HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10),
[HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8),
[HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6),
[HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5),
[HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2),
[HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1),
[HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0),
[HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31),
[HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15),
[HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7),
[HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31),
[SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
[ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2),
[INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1),
[ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0),
[MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17),
[MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15),
[HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9),
[HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8),
[HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7),
[HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31),
[HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31),
[HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31),
[HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31),
[HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31),
[HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31),
[HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 26, 26),
[HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 23, 23),
[HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 20, 20),
[HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 19, 19),
[HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 18, 18),
[HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 17, 17),
[HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL, 16, 16),
[HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL, 10, 10),
[HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL, 7, 7),
[HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL, 4, 4),
[HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL, 3, 3),
[HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL, 2, 2),
[HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL, 1, 1),
[HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL, 0, 0),
/* Make sure the array is sized properly during compilation */
[HC_FIELD_MAX] = {},
};
static const struct reg_field isp1763_hc_reg_fields[] = {
[CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7),
[CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1),
[CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0),
[STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2),
[HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13),
[FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0),
[HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15),
[HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15),
[HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15),
[HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15),
[HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15),
[HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15),
[HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15),
[HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15),
[HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15),
[PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13),
[PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12),
[PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11),
[PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8),
[PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7),
[PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6),
[PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2),
[PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1),
[PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0),
[HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4),
[HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6),
[HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5),
[HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3),
[HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2),
[HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1),
[HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0),
[SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3),
[SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0),
[HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15),
[HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15),
[HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7),
[HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15),
[ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2),
[INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1),
[ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0),
[MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15),
[HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15),
[HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10),
[HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8),
[HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7),
[HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15),
[HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15),
[HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15),
[HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15),
[HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15),
[HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15),
[HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15),
[HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10),
[HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7),
[HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4),
[HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3),
[HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2),
[HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1),
[HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0),
[HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15),
[HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10),
[HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7),
[HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4),
[HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3),
[HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2),
[HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1),
[HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0),
/* Make sure the array is sized properly during compilation */
[HC_FIELD_MAX] = {},
};
static const struct regmap_range isp1763_hc_volatile_ranges[] = {
regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD),
regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA),
regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR),
};
static const struct regmap_access_table isp1763_hc_volatile_table = {
.yes_ranges = isp1763_hc_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges),
};
static const struct regmap_config isp1763_hc_regmap_conf = {
.name = "isp1763-hc",
.reg_bits = 8,
.reg_stride = 2,
.val_bits = 16,
.fast_io = true,
.max_register = ISP1763_HC_OTG_CTRL_CLEAR,
.volatile_table = &isp1763_hc_volatile_table,
};
static const struct regmap_range isp176x_dc_volatile_ranges[] = {
regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE),
regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX),
};
static const struct regmap_access_table isp176x_dc_volatile_table = {
.yes_ranges = isp176x_dc_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges),
};
static const struct regmap_config isp1761_dc_regmap_conf = {
.name = "isp1761-dc",
.reg_bits = 16,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.max_register = ISP176x_DC_TESTMODE,
.volatile_table = &isp176x_dc_volatile_table,
};
static const struct reg_field isp1761_dc_reg_fields[] = {
[DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7),
[DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6),
[DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8),
[DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4),
[DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3),
[DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6),
[DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4),
[DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2),
[DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0),
[DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25),
[DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23),
[DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21),
[DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19),
[DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17),
[DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15),
[DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13),
[DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11),
[DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8),
[DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7),
[DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5),
[DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4),
[DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3),
[DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0),
[DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5),
[DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4),
[DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0),
[DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4),
[DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3),
[DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2),
[DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1),
[DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0),
[DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15),
[DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10),
[DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3),
[DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1),
[DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13),
[DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10),
[DC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_DC_CHIPID, 16, 31),
[DC_CHIP_ID_LOW] = REG_FIELD(ISP176x_DC_CHIPID, 0, 15),
[DC_SCRATCH] = REG_FIELD(ISP176x_DC_SCRATCH, 0, 15),
/* Make sure the array is sized properly during compilation */
[DC_FIELD_MAX] = {},
};
static const struct regmap_range isp1763_dc_volatile_ranges[] = {
regmap_reg_range(ISP1763_DC_EPMAXPKTSZ, ISP1763_DC_EPTYPE),
regmap_reg_range(ISP1763_DC_BUFLEN, ISP1763_DC_EPINDEX),
};
static const struct regmap_access_table isp1763_dc_volatile_table = {
.yes_ranges = isp1763_dc_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(isp1763_dc_volatile_ranges),
};
static const struct reg_field isp1763_dc_reg_fields[] = {
[DC_DEVEN] = REG_FIELD(ISP1763_DC_ADDRESS, 7, 7),
[DC_DEVADDR] = REG_FIELD(ISP1763_DC_ADDRESS, 0, 6),
[DC_VBUSSTAT] = REG_FIELD(ISP1763_DC_MODE, 8, 8),
[DC_SFRESET] = REG_FIELD(ISP1763_DC_MODE, 4, 4),
[DC_GLINTENA] = REG_FIELD(ISP1763_DC_MODE, 3, 3),
[DC_CDBGMOD_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 6, 6),
[DC_DDBGMODIN_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 4, 4),
[DC_DDBGMODOUT_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 2, 2),
[DC_INTPOL] = REG_FIELD(ISP1763_DC_INTCONF, 0, 0),
[DC_IEPRXTX_7] = REG_FIELD(ISP1763_DC_INTENABLE, 25, 25),
[DC_IEPRXTX_6] = REG_FIELD(ISP1763_DC_INTENABLE, 23, 23),
[DC_IEPRXTX_5] = REG_FIELD(ISP1763_DC_INTENABLE, 21, 21),
[DC_IEPRXTX_4] = REG_FIELD(ISP1763_DC_INTENABLE, 19, 19),
[DC_IEPRXTX_3] = REG_FIELD(ISP1763_DC_INTENABLE, 17, 17),
[DC_IEPRXTX_2] = REG_FIELD(ISP1763_DC_INTENABLE, 15, 15),
[DC_IEPRXTX_1] = REG_FIELD(ISP1763_DC_INTENABLE, 13, 13),
[DC_IEPRXTX_0] = REG_FIELD(ISP1763_DC_INTENABLE, 11, 11),
[DC_IEP0SETUP] = REG_FIELD(ISP1763_DC_INTENABLE, 8, 8),
[DC_IEVBUS] = REG_FIELD(ISP1763_DC_INTENABLE, 7, 7),
[DC_IEHS_STA] = REG_FIELD(ISP1763_DC_INTENABLE, 5, 5),
[DC_IERESM] = REG_FIELD(ISP1763_DC_INTENABLE, 4, 4),
[DC_IESUSP] = REG_FIELD(ISP1763_DC_INTENABLE, 3, 3),
[DC_IEBRST] = REG_FIELD(ISP1763_DC_INTENABLE, 0, 0),
[DC_EP0SETUP] = REG_FIELD(ISP1763_DC_EPINDEX, 5, 5),
[DC_ENDPIDX] = REG_FIELD(ISP1763_DC_EPINDEX, 1, 4),
[DC_EPDIR] = REG_FIELD(ISP1763_DC_EPINDEX, 0, 0),
[DC_CLBUF] = REG_FIELD(ISP1763_DC_CTRLFUNC, 4, 4),
[DC_VENDP] = REG_FIELD(ISP1763_DC_CTRLFUNC, 3, 3),
[DC_DSEN] = REG_FIELD(ISP1763_DC_CTRLFUNC, 2, 2),
[DC_STATUS] = REG_FIELD(ISP1763_DC_CTRLFUNC, 1, 1),
[DC_STALL] = REG_FIELD(ISP1763_DC_CTRLFUNC, 0, 0),
[DC_BUFLEN] = REG_FIELD(ISP1763_DC_BUFLEN, 0, 15),
[DC_FFOSZ] = REG_FIELD(ISP1763_DC_EPMAXPKTSZ, 0, 10),
[DC_EPENABLE] = REG_FIELD(ISP1763_DC_EPTYPE, 3, 3),
[DC_ENDPTYP] = REG_FIELD(ISP1763_DC_EPTYPE, 0, 1),
[DC_UFRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 11, 13),
[DC_FRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 0, 10),
[DC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_DC_CHIPID_HIGH, 0, 15),
[DC_CHIP_ID_LOW] = REG_FIELD(ISP1763_DC_CHIPID_LOW, 0, 15),
[DC_SCRATCH] = REG_FIELD(ISP1763_DC_SCRATCH, 0, 15),
/* Make sure the array is sized properly during compilation */
[DC_FIELD_MAX] = {},
};
static const struct regmap_config isp1763_dc_regmap_conf = {
.name = "isp1763-dc",
.reg_bits = 8,
.reg_stride = 2,
.val_bits = 16,
.fast_io = true,
.max_register = ISP1763_DC_TESTMODE,
.volatile_table = &isp1763_dc_volatile_table,
};
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
const struct regmap_config *hc_regmap;
const struct reg_field *hc_reg_fields;
const struct regmap_config *dc_regmap;
const struct reg_field *dc_reg_fields;
struct isp1760_device *isp;
struct isp1760_hcd *hcd;
struct isp1760_udc *udc;
struct regmap_field *f;
bool udc_enabled;
int ret;
int i;
/*
* If neither the HCD not the UDC is enabled return an error, as no
* device would be registered.
*/
udc_enabled = ((devflags & ISP1760_FLAG_ISP1763) ||
(devflags & ISP1760_FLAG_ISP1761));
if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
(!udc_enabled || !IS_ENABLED(CONFIG_USB_ISP1761_UDC)))
return -ENODEV;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
if (!isp)
return -ENOMEM;
isp->dev = dev;
isp->devflags = devflags;
hcd = &isp->hcd;
udc = &isp->udc;
hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
udc->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) {
dev_err(dev, "isp1760/61 do not support data width 8\n");
return -EINVAL;
}
if (hcd->is_isp1763) {
hc_regmap = &isp1763_hc_regmap_conf;
hc_reg_fields = &isp1763_hc_reg_fields[0];
dc_regmap = &isp1763_dc_regmap_conf;
dc_reg_fields = &isp1763_dc_reg_fields[0];
} else {
hc_regmap = &isp1760_hc_regmap_conf;
hc_reg_fields = &isp1760_hc_reg_fields[0];
dc_regmap = &isp1761_dc_regmap_conf;
dc_reg_fields = &isp1761_dc_reg_fields[0];
}
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
hcd->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(hcd->base))
return PTR_ERR(hcd->base);
hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap);
if (IS_ERR(hcd->regs))
return PTR_ERR(hcd->regs);
for (i = 0; i < HC_FIELD_MAX; i++) {
f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]);
if (IS_ERR(f))
return PTR_ERR(f);
hcd->fields[i] = f;
}
udc->regs = devm_regmap_init_mmio(dev, hcd->base, dc_regmap);
if (IS_ERR(udc->regs))
return PTR_ERR(udc->regs);
for (i = 0; i < DC_FIELD_MAX; i++) {
f = devm_regmap_field_alloc(dev, udc->regs, dc_reg_fields[i]);
if (IS_ERR(f))
return PTR_ERR(f);
udc->fields[i] = f;
}
if (hcd->is_isp1763)
hcd->memory_layout = &isp1763_memory_conf;
else
hcd->memory_layout = &isp176x_memory_conf;
ret = isp1760_init_core(isp);
if (ret < 0)
return ret;
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
ret = isp1760_hcd_register(hcd, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
}
if (udc_enabled && IS_ENABLED(CONFIG_USB_ISP1761_UDC)) {
ret = isp1760_udc_register(isp, irq, irqflags);
if (ret < 0) {
isp1760_hcd_unregister(hcd);
return ret;
}
}
dev_set_drvdata(dev, isp);
return 0;
}
void isp1760_unregister(struct device *dev)
{
struct isp1760_device *isp = dev_get_drvdata(dev);
isp1760_udc_unregister(isp);
isp1760_hcd_unregister(&isp->hcd);
}
MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,97 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP1760_CORE_H_
#define _ISP1760_CORE_H_
#include <linux/ioport.h>
#include <linux/regmap.h>
#include "isp1760-hcd.h"
#include "isp1760-udc.h"
struct device;
struct gpio_desc;
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_PERIPHERAL_EN 0x00000004 /* Port 1 supports Peripheral mode*/
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
#define ISP1760_FLAG_ISP1763 0x00000200 /* Chip is ISP1763 */
#define ISP1760_FLAG_BUS_WIDTH_8 0x00000400 /* 8-bit data bus width */
struct isp1760_device {
struct device *dev;
unsigned int devflags;
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_field_read(struct regmap_field **fields, u32 field)
{
unsigned int val;
regmap_field_read(fields[field], &val);
return val;
}
static inline void isp1760_field_write(struct regmap_field **fields, u32 field,
u32 val)
{
regmap_field_write(fields[field], val);
}
static inline void isp1760_field_set(struct regmap_field **fields, u32 field)
{
isp1760_field_write(fields, field, 0xFFFFFFFF);
}
static inline void isp1760_field_clear(struct regmap_field **fields, u32 field)
{
isp1760_field_write(fields, field, 0);
}
static inline u32 isp1760_reg_read(struct regmap *regs, u32 reg)
{
unsigned int val;
regmap_read(regs, reg, &val);
return val;
}
static inline void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val)
{
regmap_write(regs, reg, val);
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
#include <linux/spinlock.h>
#include <linux/regmap.h>
#include "isp1760-regs.h"
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
struct usb_hcd;
struct isp1760_slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
unsigned long timestamp;
};
/* chip memory management */
#define ISP176x_BLOCK_MAX (32 + 20 + 4)
#define ISP176x_BLOCK_NUM 3
struct isp1760_memory_layout {
unsigned int blocks[ISP176x_BLOCK_NUM];
unsigned int blocks_size[ISP176x_BLOCK_NUM];
unsigned int slot_num;
unsigned int payload_blocks;
unsigned int payload_area_size;
};
struct isp1760_memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
enum isp1760_queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
struct usb_hcd *hcd;
void __iomem *base;
struct regmap *regs;
struct regmap_field *fields[HC_FIELD_MAX];
bool is_isp1763;
const struct isp1760_memory_layout *memory_layout;
spinlock_t lock;
struct isp1760_slotinfo *atl_slots;
int atl_done_map;
struct isp1760_slotinfo *int_slots;
int int_done_map;
struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX];
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
unsigned periodic_size;
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
};
#ifdef CONFIG_USB_ISP1760_HCD
int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
int irq, unsigned long irqflags, struct device *dev);
void isp1760_hcd_unregister(struct isp1760_hcd *priv);
int isp1760_init_kmem_once(void);
void isp1760_deinit_kmem_cache(void);
#else
static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
struct resource *mem,
int irq, unsigned long irqflags,
struct device *dev)
{
return 0;
}
static inline void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{
}
static inline int isp1760_init_kmem_once(void)
{
return 0;
}
static inline void isp1760_deinit_kmem_cache(void)
{
}
#endif
#endif /* _ISP1760_HCD_H_ */
@@ -0,0 +1,302 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Glue code for the ISP1760 driver and bus
* Currently there is support for
* - OpenFirmware
* - PCI
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
* Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
*
*/
#include <linux/usb.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
#ifdef CONFIG_USB_PCI
#include <linux/pci.h>
#endif
#ifdef CONFIG_USB_PCI
static int isp1761_pci_init(struct pci_dev *dev)
{
resource_size_t mem_start;
resource_size_t mem_length;
u8 __iomem *iobase;
u8 latency, limit;
int retry_count;
u32 reg_data;
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
mem_start = pci_resource_start(dev, 3);
mem_length = pci_resource_len(dev, 3);
if (mem_length < 0xffff) {
printk(KERN_ERR "memory length for this resource is wrong\n");
return -ENOMEM;
}
if (!request_mem_region(mem_start, mem_length, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
return -EBUSY;
}
/* map available memory */
iobase = ioremap(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "Error ioremap failed\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* bad pci latencies can contribute to overruns */
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
}
/* Try to check whether we can access Scratch Register of
* Host Controller or not. The initial PCI access is retried until
* local init for the PCI bridge is completed
*/
retry_count = 20;
reg_data = 0;
while ((reg_data != 0xFACE) && retry_count) {
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
writel(0xface, iobase + ISP176x_HC_SCRATCH);
udelay(100);
reg_data = readl(iobase + ISP176x_HC_SCRATCH) & 0x0000ffff;
retry_count--;
}
iounmap(iobase);
release_mem_region(mem_start, mem_length);
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
return -ENOMEM;
}
/* Grab the PLX PCI mem maped port start address we need */
mem_start = pci_resource_start(dev, 0);
mem_length = pci_resource_len(dev, 0);
if (!request_mem_region(mem_start, mem_length, "ISP1761 IO MEM")) {
printk(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* configure PLX PCI chip to pass interrupts */
#define PLX_INT_CSR_REG 0x68
reg_data = readl(iobase + PLX_INT_CSR_REG);
reg_data |= 0x900;
writel(reg_data, iobase + PLX_INT_CSR_REG);
/* done with PLX IO access */
iounmap(iobase);
release_mem_region(mem_start, mem_length);
return 0;
}
static int isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
unsigned int devflags = 0;
int ret;
if (!dev->irq)
return -ENODEV;
if (pci_enable_device(dev) < 0)
return -ENODEV;
ret = isp1761_pci_init(dev);
if (ret < 0)
goto error;
pci_set_master(dev);
ret = isp1760_register(&dev->resource[3], dev->irq, 0, &dev->dev,
devflags);
if (ret < 0)
goto error;
return 0;
error:
pci_disable_device(dev);
return ret;
}
static void isp1761_pci_remove(struct pci_dev *dev)
{
isp1760_unregister(&dev->dev);
pci_disable_device(dev);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
{
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx[] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x5406,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = 0x9054,
},
{ }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
static struct pci_driver isp1761_pci_driver = {
.name = "isp1760",
.id_table = isp1760_plx,
.probe = isp1761_pci_probe,
.remove = isp1761_pci_remove,
.shutdown = isp1761_pci_shutdown,
};
#endif
static int isp1760_plat_probe(struct platform_device *pdev)
{
unsigned long irqflags;
unsigned int devflags = 0;
struct resource *mem_res;
int irq;
int ret;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
irqflags = irq_get_trigger_type(irq);
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
struct device_node *dp = pdev->dev.of_node;
u32 bus_width = 0;
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
if (of_device_is_compatible(dp, "nxp,usb-isp1763"))
devflags |= ISP1760_FLAG_ISP1763;
/*
* Some systems wire up only 8 of 16 data lines or
* 16 of the 32 data lines
*/
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
else if (bus_width == 8)
devflags |= ISP1760_FLAG_BUS_WIDTH_8;
if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL)
devflags |= ISP1760_FLAG_PERIPHERAL_EN;
if (of_property_read_bool(dp, "analog-oc"))
devflags |= ISP1760_FLAG_ANALOG_OC;
if (of_property_read_bool(dp, "dack-polarity"))
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (of_property_read_bool(dp, "dreq-polarity"))
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
} else {
pr_err("isp1760: no platform data\n");
return -ENXIO;
}
ret = isp1760_register(mem_res, irq, irqflags, &pdev->dev, devflags);
if (ret < 0)
return ret;
pr_info("ISP1760 USB device initialised\n");
return 0;
}
static void isp1760_plat_remove(struct platform_device *pdev)
{
isp1760_unregister(&pdev->dev);
}
#ifdef CONFIG_OF
static const struct of_device_id isp1760_of_match[] = {
{ .compatible = "nxp,usb-isp1760", },
{ .compatible = "nxp,usb-isp1761", },
{ .compatible = "nxp,usb-isp1763", },
{ },
};
MODULE_DEVICE_TABLE(of, isp1760_of_match);
#endif
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
.remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
.of_match_table = of_match_ptr(isp1760_of_match),
},
};
static int __init isp1760_init(void)
{
int ret, any_ret = -ENODEV;
isp1760_init_kmem_once();
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
#ifdef CONFIG_USB_PCI
ret = pci_register_driver(&isp1761_pci_driver);
if (!ret)
any_ret = 0;
#endif
if (any_ret)
isp1760_deinit_kmem_cache();
return any_ret;
}
module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
#ifdef CONFIG_USB_PCI
pci_unregister_driver(&isp1761_pci_driver);
#endif
isp1760_deinit_kmem_cache();
}
module_exit(isp1760_exit);
@@ -0,0 +1,308 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP176x_REGS_H_
#define _ISP176x_REGS_H_
/* -----------------------------------------------------------------------------
* Host Controller
*/
/* ISP1760/31 */
/* EHCI capability registers */
#define ISP176x_HC_VERSION 0x002
#define ISP176x_HC_HCSPARAMS 0x004
#define ISP176x_HC_HCCPARAMS 0x008
/* EHCI operational registers */
#define ISP176x_HC_USBCMD 0x020
#define ISP176x_HC_USBSTS 0x024
#define ISP176x_HC_FRINDEX 0x02c
#define ISP176x_HC_CONFIGFLAG 0x060
#define ISP176x_HC_PORTSC1 0x064
#define ISP176x_HC_ISO_PTD_DONEMAP 0x130
#define ISP176x_HC_ISO_PTD_SKIPMAP 0x134
#define ISP176x_HC_ISO_PTD_LASTPTD 0x138
#define ISP176x_HC_INT_PTD_DONEMAP 0x140
#define ISP176x_HC_INT_PTD_SKIPMAP 0x144
#define ISP176x_HC_INT_PTD_LASTPTD 0x148
#define ISP176x_HC_ATL_PTD_DONEMAP 0x150
#define ISP176x_HC_ATL_PTD_SKIPMAP 0x154
#define ISP176x_HC_ATL_PTD_LASTPTD 0x158
/* Configuration Register */
#define ISP176x_HC_HW_MODE_CTRL 0x300
#define ISP176x_HC_CHIP_ID 0x304
#define ISP176x_HC_SCRATCH 0x308
#define ISP176x_HC_RESET 0x30c
#define ISP176x_HC_BUFFER_STATUS 0x334
#define ISP176x_HC_MEMORY 0x33c
/* Interrupt Register */
#define ISP176x_HC_INTERRUPT 0x310
#define ISP176x_HC_INTERRUPT_ENABLE 0x314
#define ISP176x_HC_ISO_IRQ_MASK_OR 0x318
#define ISP176x_HC_INT_IRQ_MASK_OR 0x31c
#define ISP176x_HC_ATL_IRQ_MASK_OR 0x320
#define ISP176x_HC_ISO_IRQ_MASK_AND 0x324
#define ISP176x_HC_INT_IRQ_MASK_AND 0x328
#define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c
#define ISP176x_HC_OTG_CTRL 0x374
#define ISP176x_HC_OTG_CTRL_SET 0x374
#define ISP176x_HC_OTG_CTRL_CLEAR 0x376
enum isp176x_host_controller_fields {
/* HC_PORTSC1 */
PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
/* HC_HCSPARAMS */
HCS_PPC, HCS_N_PORTS,
/* HC_HCCPARAMS */
HCC_ISOC_CACHE, HCC_ISOC_THRES,
/* HC_USBCMD */
CMD_LRESET, CMD_RESET, CMD_RUN,
/* HC_USBSTS */
STS_PCD,
/* HC_FRINDEX */
HC_FRINDEX,
/* HC_CONFIGFLAG */
FLAG_CF,
/* ISO/INT/ATL PTD */
HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD,
HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD,
HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD,
/* HC_HW_MODE_CTRL */
ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA,
HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT,
HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
/* HC_CHIP_ID */
HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV,
/* HC_SCRATCH */
HC_SCRATCH,
/* HC_RESET */
SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
/* HC_BUFFER_STATUS */
ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL,
/* HC_MEMORY */
MEM_BANK_SEL, MEM_START_ADDR,
/* HC_DATA */
HC_DATA,
/* HC_INTERRUPT */
HC_INTERRUPT,
/* HC_INTERRUPT_ENABLE */
HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE,
/* INTERRUPT MASKS */
HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR,
HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND,
/* HW_OTG_CTRL_SET */
HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS,
/* HW_OTG_CTRL_CLR */
HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR,
/* Last element */
HC_FIELD_MAX,
};
/* ISP1763 */
/* EHCI operational registers */
#define ISP1763_HC_USBCMD 0x8c
#define ISP1763_HC_USBSTS 0x90
#define ISP1763_HC_FRINDEX 0x98
#define ISP1763_HC_CONFIGFLAG 0x9c
#define ISP1763_HC_PORTSC1 0xa0
#define ISP1763_HC_ISO_PTD_DONEMAP 0xa4
#define ISP1763_HC_ISO_PTD_SKIPMAP 0xa6
#define ISP1763_HC_ISO_PTD_LASTPTD 0xa8
#define ISP1763_HC_INT_PTD_DONEMAP 0xaa
#define ISP1763_HC_INT_PTD_SKIPMAP 0xac
#define ISP1763_HC_INT_PTD_LASTPTD 0xae
#define ISP1763_HC_ATL_PTD_DONEMAP 0xb0
#define ISP1763_HC_ATL_PTD_SKIPMAP 0xb2
#define ISP1763_HC_ATL_PTD_LASTPTD 0xb4
/* Configuration Register */
#define ISP1763_HC_HW_MODE_CTRL 0xb6
#define ISP1763_HC_CHIP_REV 0x70
#define ISP1763_HC_CHIP_ID 0x72
#define ISP1763_HC_SCRATCH 0x78
#define ISP1763_HC_RESET 0xb8
#define ISP1763_HC_BUFFER_STATUS 0xba
#define ISP1763_HC_MEMORY 0xc4
#define ISP1763_HC_DATA 0xc6
/* Interrupt Register */
#define ISP1763_HC_INTERRUPT 0xd4
#define ISP1763_HC_INTERRUPT_ENABLE 0xd6
#define ISP1763_HC_ISO_IRQ_MASK_OR 0xd8
#define ISP1763_HC_INT_IRQ_MASK_OR 0xda
#define ISP1763_HC_ATL_IRQ_MASK_OR 0xdc
#define ISP1763_HC_ISO_IRQ_MASK_AND 0xde
#define ISP1763_HC_INT_IRQ_MASK_AND 0xe0
#define ISP1763_HC_ATL_IRQ_MASK_AND 0xe2
#define ISP1763_HC_OTG_CTRL_SET 0xe4
#define ISP1763_HC_OTG_CTRL_CLEAR 0xe6
/* -----------------------------------------------------------------------------
* Peripheral Controller
*/
#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 ISP176x_DC_CDBGMOD_ACK BIT(6)
#define ISP176x_DC_DDBGMODIN_ACK BIT(4)
#define ISP176x_DC_DDBGMODOUT_ACK BIT(2)
#define ISP176x_DC_IEP0SETUP BIT(8)
#define ISP176x_DC_IEVBUS BIT(7)
#define ISP176x_DC_IEHS_STA BIT(5)
#define ISP176x_DC_IERESM BIT(4)
#define ISP176x_DC_IESUSP BIT(3)
#define ISP176x_DC_IEBRST BIT(0)
#define ISP176x_HW_OTG_DISABLE_CLEAR BIT(26)
#define ISP176x_HW_SW_SEL_HC_DC_CLEAR BIT(23)
#define ISP176x_HW_VBUS_DRV_CLEAR BIT(20)
#define ISP176x_HW_SEL_CP_EXT_CLEAR BIT(19)
#define ISP176x_HW_DM_PULLDOWN_CLEAR BIT(18)
#define ISP176x_HW_DP_PULLDOWN_CLEAR BIT(17)
#define ISP176x_HW_DP_PULLUP_CLEAR BIT(16)
#define ISP176x_HW_OTG_DISABLE BIT(10)
#define ISP176x_HW_SW_SEL_HC_DC BIT(7)
#define ISP176x_HW_VBUS_DRV BIT(4)
#define ISP176x_HW_SEL_CP_EXT BIT(3)
#define ISP176x_HW_DM_PULLDOWN BIT(2)
#define ISP176x_HW_DP_PULLDOWN BIT(1)
#define ISP176x_HW_DP_PULLUP BIT(0)
#define ISP176x_DC_ENDPTYP_ISOC 0x01
#define ISP176x_DC_ENDPTYP_BULK 0x02
#define ISP176x_DC_ENDPTYP_INTERRUPT 0x03
/* Initialization Registers */
#define ISP176x_DC_ADDRESS 0x0200
#define ISP176x_DC_MODE 0x020c
#define ISP176x_DC_INTCONF 0x0210
#define ISP176x_DC_DEBUG 0x0212
#define ISP176x_DC_INTENABLE 0x0214
/* Data Flow Registers */
#define ISP176x_DC_EPMAXPKTSZ 0x0204
#define ISP176x_DC_EPTYPE 0x0208
#define ISP176x_DC_BUFLEN 0x021c
#define ISP176x_DC_BUFSTAT 0x021e
#define ISP176x_DC_DATAPORT 0x0220
#define ISP176x_DC_CTRLFUNC 0x0228
#define ISP176x_DC_EPINDEX 0x022c
/* DMA Registers */
#define ISP176x_DC_DMACMD 0x0230
#define ISP176x_DC_DMATXCOUNT 0x0234
#define ISP176x_DC_DMACONF 0x0238
#define ISP176x_DC_DMAHW 0x023c
#define ISP176x_DC_DMAINTREASON 0x0250
#define ISP176x_DC_DMAINTEN 0x0254
#define ISP176x_DC_DMAEP 0x0258
#define ISP176x_DC_DMABURSTCOUNT 0x0264
/* General Registers */
#define ISP176x_DC_INTERRUPT 0x0218
#define ISP176x_DC_CHIPID 0x0270
#define ISP176x_DC_FRAMENUM 0x0274
#define ISP176x_DC_SCRATCH 0x0278
#define ISP176x_DC_UNLOCKDEV 0x027c
#define ISP176x_DC_INTPULSEWIDTH 0x0280
#define ISP176x_DC_TESTMODE 0x0284
enum isp176x_device_controller_fields {
/* DC_ADDRESS */
DC_DEVEN, DC_DEVADDR,
/* DC_MODE */
DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA,
/* DC_INTCONF */
DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL,
/* DC_INTENABLE */
DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3,
DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0,
DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST,
/* DC_EPINDEX */
DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR,
/* DC_CTRLFUNC */
DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL,
/* DC_BUFLEN */
DC_BUFLEN,
/* DC_EPMAXPKTSZ */
DC_FFOSZ,
/* DC_EPTYPE */
DC_EPENABLE, DC_ENDPTYP,
/* DC_FRAMENUM */
DC_FRAMENUM, DC_UFRAMENUM,
/* DC_CHIP_ID */
DC_CHIP_ID_HIGH, DC_CHIP_ID_LOW,
/* DC_SCRATCH */
DC_SCRATCH,
/* Last element */
DC_FIELD_MAX,
};
/* ISP1763 */
/* Initialization Registers */
#define ISP1763_DC_ADDRESS 0x00
#define ISP1763_DC_MODE 0x0c
#define ISP1763_DC_INTCONF 0x10
#define ISP1763_DC_INTENABLE 0x14
/* Data Flow Registers */
#define ISP1763_DC_EPMAXPKTSZ 0x04
#define ISP1763_DC_EPTYPE 0x08
#define ISP1763_DC_BUFLEN 0x1c
#define ISP1763_DC_BUFSTAT 0x1e
#define ISP1763_DC_DATAPORT 0x20
#define ISP1763_DC_CTRLFUNC 0x28
#define ISP1763_DC_EPINDEX 0x2c
/* DMA Registers */
#define ISP1763_DC_DMACMD 0x30
#define ISP1763_DC_DMATXCOUNT 0x34
#define ISP1763_DC_DMACONF 0x38
#define ISP1763_DC_DMAHW 0x3c
#define ISP1763_DC_DMAINTREASON 0x50
#define ISP1763_DC_DMAINTEN 0x54
#define ISP1763_DC_DMAEP 0x58
#define ISP1763_DC_DMABURSTCOUNT 0x64
/* General Registers */
#define ISP1763_DC_INTERRUPT 0x18
#define ISP1763_DC_CHIPID_LOW 0x70
#define ISP1763_DC_CHIPID_HIGH 0x72
#define ISP1763_DC_FRAMENUM 0x74
#define ISP1763_DC_SCRATCH 0x78
#define ISP1763_DC_UNLOCKDEV 0x7c
#define ISP1763_DC_INTPULSEWIDTH 0x80
#define ISP1763_DC_TESTMODE 0x84
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,108 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the NXP ISP1761 device controller
*
* Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Rui Miguel Silva <rui.silva@linaro.org>
*/
#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>
#include "isp1760-regs.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: regmap for 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 {
struct isp1760_device *isp;
int irq;
char *irqname;
struct regmap *regs;
struct regmap_field *fields[DC_FIELD_MAX];
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;
bool is_isp1763;
unsigned int devstatus;
};
#ifdef 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