diff options
Diffstat (limited to 'drivers/usb/isp1760/isp1760-core.c')
-rw-r--r-- | drivers/usb/isp1760/isp1760-core.c | 239 |
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; } } |