summaryrefslogtreecommitdiff
path: root/drivers/usb/isp1760/isp1760-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/isp1760/isp1760-core.c')
-rw-r--r--drivers/usb/isp1760/isp1760-core.c239
1 files changed, 203 insertions, 36 deletions
diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
index fdeb4cf97cc5..c79ba98df9f9 100644
--- a/drivers/usb/isp1760/isp1760-core.c
+++ b/drivers/usb/isp1760/isp1760-core.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/usb.h>
@@ -25,8 +26,8 @@
static void isp1760_init_core(struct isp1760_device *isp)
{
- u32 otgctrl;
- u32 hwmode;
+ struct isp1760_hcd *hcd = &isp->hcd;
+ struct isp1760_udc *udc = &isp->udc;
/* Low-level chip reset */
if (isp->rst_gpio) {
@@ -39,24 +40,22 @@ static void isp1760_init_core(struct isp1760_device *isp)
* Reset the host controller, including the CPU interface
* configuration.
*/
- isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
+ isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
- hwmode = HW_DATA_BUS_32BIT;
-
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
- hwmode &= ~HW_DATA_BUS_32BIT;
+ isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
- hwmode |= HW_ANA_DIGI_OC;
+ isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
- hwmode |= HW_DACK_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
- hwmode |= HW_DREQ_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
- hwmode |= HW_INTR_HIGH_ACT;
+ isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT);
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
- hwmode |= HW_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
@@ -65,19 +64,11 @@ static void isp1760_init_core(struct isp1760_device *isp)
* spurious interrupts during HCD registration.
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
- isp1760_write32(isp->regs, DC_MODE, 0);
- hwmode |= HW_COMN_IRQ;
+ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
+ isp1760_field_set(hcd->fields, 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
- * to 16-bit mode.
- */
- 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 ISP1761.
*
@@ -85,14 +76,15 @@ static void isp1760_init_core(struct isp1760_device *isp)
* when OTG is requested.
*/
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);
+ (isp->devflags & ISP1760_FLAG_OTG_EN)) {
+ isp1760_field_set(hcd->fields, HW_DM_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_DP_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_OTG_DISABLE);
+ } else {
+ isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC);
+ isp1760_field_set(hcd->fields, HW_VBUS_DRV);
+ isp1760_field_set(hcd->fields, HW_SEL_CP_EXT);
+ }
dev_info(isp->dev, "bus width: %u, oc: %s\n",
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
@@ -101,16 +93,158 @@ static void isp1760_init_core(struct isp1760_device *isp)
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);
+ 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);
}
+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_ATL_IRQ_MASK_AND),
+};
+
+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 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_MEMORY,
+ .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),
+ [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),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
+ [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_INT_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 8),
+};
+
+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),
+ regmap_reg_range(ISP1761_DC_OTG_CTRL_SET, ISP1761_DC_OTG_CTRL_CLEAR),
+};
+
+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 struct regmap_config isp1761_dc_regmap_conf = {
+ .name = "isp1761-dc",
+ .reg_bits = 16,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .max_register = ISP1761_DC_OTG_CTRL_CLEAR,
+ .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),
+ [HW_OTG_DISABLE] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 10, 10),
+ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 7, 7),
+ [HW_VBUS_DRV] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 4, 4),
+ [HW_SEL_CP_EXT] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 3, 3),
+ [HW_DM_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 2, 2),
+ [HW_DP_PULLDOWN] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 1, 1),
+ [HW_DP_PULLUP] = REG_FIELD(ISP1761_DC_OTG_CTRL_SET, 0, 0),
+ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 10, 10),
+ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 7, 7),
+ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 4, 4),
+ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 3, 3),
+ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 2, 2),
+ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 1, 1),
+ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1761_DC_OTG_CTRL_CLEAR, 0, 0),
+};
+
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
struct isp1760_device *isp;
+ struct isp1760_hcd *hcd;
+ struct isp1760_udc *udc;
bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+ struct regmap_field *f;
+ void __iomem *base;
int ret;
+ int i;
/*
* If neither the HCD not the UDC is enabled return an error, as no
@@ -126,19 +260,52 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
isp->dev = dev;
isp->devflags = devflags;
+ hcd = &isp->hcd;
+ udc = &isp->udc;
+
+ if (devflags & ISP1760_FLAG_BUS_WIDTH_16) {
+ isp1760_hc_regmap_conf.val_bits = 16;
+ isp1761_dc_regmap_conf.val_bits = 16;
+ }
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
- isp->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(isp->regs))
- return PTR_ERR(isp->regs);
+ hcd->base = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hcd->base))
+ return PTR_ERR(hcd->base);
+
+ hcd->regs = devm_regmap_init_mmio(dev, base, &isp1760_hc_regmap_conf);
+ 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,
+ isp1760_hc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ hcd->fields[i] = f;
+ }
+
+ udc->regs = devm_regmap_init_mmio(dev, base, &isp1761_dc_regmap_conf);
+ 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,
+ isp1761_dc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ udc->fields[i] = f;
+ }
isp1760_init_core(isp);
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
- ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
+ ret = isp1760_hcd_register(hcd, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
@@ -147,7 +314,7 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
ret = isp1760_udc_register(isp, irq, irqflags);
if (ret < 0) {
- isp1760_hcd_unregister(&isp->hcd);
+ isp1760_hcd_unregister(hcd);
return ret;
}
}