Skip to content

Commit

Permalink
usb: isp1760: move to regmap for register access
Browse files Browse the repository at this point in the history
Rework access to registers and memory to use regmap framework.
No change in current feature or way of work is intended with this
change.

This will allow to reuse this driver with other IP of this family,
for example isp1763, with little changes and effort.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Link: https://lore.kernel.org/r/20210513084717.2487366-3-rui.silva@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Rui Miguel Silva authored and Greg Kroah-Hartman committed May 21, 2021
1 parent abfabc8 commit 1da9e1c
Show file tree
Hide file tree
Showing 9 changed files with 789 additions and 531 deletions.
1 change: 1 addition & 0 deletions drivers/usb/isp1760/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
config USB_ISP1760
tristate "NXP ISP 1760/1761 support"
depends on USB || USB_GADGET
select REGMAP_MMIO
help
Say Y or M here if your system as an ISP1760 USB host controller
or an ISP1761 USB dual-role controller.
Expand Down
239 changes: 203 additions & 36 deletions drivers/usb/isp1760/isp1760-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -65,18 +64,10 @@ 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.
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand Down
38 changes: 33 additions & 5 deletions drivers/usb/isp1760/isp1760-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define _ISP1760_CORE_H_

#include <linux/ioport.h>
#include <linux/regmap.h>

#include "isp1760-hcd.h"
#include "isp1760-udc.h"
Expand All @@ -38,7 +39,6 @@ struct gpio_desc;
struct isp1760_device {
struct device *dev;

void __iomem *regs;
unsigned int devflags;
struct gpio_desc *rst_gpio;

Expand All @@ -52,14 +52,42 @@ 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_field_read(struct regmap_field **fields, u32 field)
{
return readl(base + reg);
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_write32(void __iomem *base, u32 reg, u32 val)
static inline void isp1760_field_clear(struct regmap_field **fields, u32 field)
{
writel(val, base + reg);
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
Loading

0 comments on commit 1da9e1c

Please sign in to comment.