diff options
-rw-r--r-- | drivers/usb/host/isp1760-core.c | 62 | ||||
-rw-r--r-- | drivers/usb/host/isp1760-core.h | 31 | ||||
-rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 67 | ||||
-rw-r--r-- | drivers/usb/host/isp1760-hcd.h | 20 |
4 files changed, 105 insertions, 75 deletions
diff --git a/drivers/usb/host/isp1760-core.c b/drivers/usb/host/isp1760-core.c index 35278a8356b..e840a1d3676 100644 --- a/drivers/usb/host/isp1760-core.c +++ b/drivers/usb/host/isp1760-core.c @@ -13,7 +13,8 @@ * version 2 as published by the Free Software Foundation. */ -#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> @@ -22,6 +23,54 @@ #include "isp1760-core.h" #include "isp1760-hcd.h" +#include "isp1760-regs.h" + +static void isp1760_init_core(struct isp1760_device *isp) +{ + u32 hwmode; + + /* Low-level chip reset */ + if (isp->rst_gpio) { + gpiod_set_value_cansleep(isp->rst_gpio, 1); + mdelay(50); + gpiod_set_value_cansleep(isp->rst_gpio, 0); + } + + /* + * Reset the host controller, including the CPU interface + * configuration. + */ + isp1760_write32(isp->regs, HC_RESET_REG, 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; + if (isp->devflags & ISP1760_FLAG_ANALOG_OC) + hwmode |= HW_ANA_DIGI_OC; + if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH) + hwmode |= HW_DACK_POL_HIGH; + if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH) + hwmode |= HW_DREQ_POL_HIGH; + if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH) + hwmode |= HW_INTR_HIGH_ACT; + if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) + hwmode |= HW_INTR_EDGE_TRIG; + + /* + * 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); + + dev_info(isp->dev, "bus width: %u, oc: %s\n", + isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32, + isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital"); +} int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, struct device *dev, unsigned int devflags) @@ -39,12 +88,21 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, if (!isp) return -ENOMEM; + isp->dev = dev; + isp->devflags = devflags; + + 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); + isp1760_init_core(isp); + ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq, - irqflags | IRQF_SHARED, dev, devflags); + irqflags | IRQF_SHARED, dev); if (ret < 0) return ret; diff --git a/drivers/usb/host/isp1760-core.h b/drivers/usb/host/isp1760-core.h index 0caeb113527..cd4a0f3981d 100644 --- a/drivers/usb/host/isp1760-core.h +++ b/drivers/usb/host/isp1760-core.h @@ -20,8 +20,29 @@ #include "isp1760-hcd.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_OTG_EN 0x00000004 /* Port 1 supports OTG */ +#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 */ + struct isp1760_device { + struct device *dev; + void __iomem *regs; + unsigned int devflags; + struct gpio_desc *rst_gpio; struct isp1760_hcd hcd; }; @@ -30,4 +51,14 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags, struct device *dev, unsigned int devflags); void isp1760_unregister(struct device *dev); +static inline u32 isp1760_read32(void __iomem *base, u32 reg) +{ + return readl(base + reg); +} + +static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val) +{ + writel(val, base + reg); +} + #endif diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 0cf620b1f6a..5309d732448 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -26,6 +26,7 @@ #include <asm/unaligned.h> #include <asm/cacheflush.h> +#include "isp1760-core.h" #include "isp1760-hcd.h" #include "isp1760-regs.h" @@ -160,12 +161,12 @@ struct urb_listitem { */ static u32 reg_read32(void __iomem *base, u32 reg) { - return readl(base + reg); + return isp1760_read32(base, reg); } static void reg_write32(void __iomem *base, u32 reg, u32 val) { - writel(val, base + reg); + isp1760_write32(base, reg, val); } /* @@ -466,37 +467,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) int result; u32 scratch, hwmode; - /* low-level chip reset */ - if (priv->rst_gpio) { - gpiod_set_value_cansleep(priv->rst_gpio, 1); - mdelay(50); - gpiod_set_value_cansleep(priv->rst_gpio, 0); - } - - /* Setup HW Mode Control: This assumes a level active-low interrupt */ - hwmode = HW_DATA_BUS_32BIT; - - if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) - hwmode &= ~HW_DATA_BUS_32BIT; - if (priv->devflags & ISP1760_FLAG_ANALOG_OC) - hwmode |= HW_ANA_DIGI_OC; - if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH) - hwmode |= HW_DACK_POL_HIGH; - if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH) - hwmode |= HW_DREQ_POL_HIGH; - if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH) - hwmode |= HW_INTR_HIGH_ACT; - if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) - hwmode |= HW_INTR_EDGE_TRIG; - - /* - * 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. - */ - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe); /* Change bus pattern */ scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG); @@ -506,31 +476,27 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) return -ENODEV; } - /* pre reset */ + /* + * The RESET_HC bit in the SW_RESET register is supposed to reset the + * host controller without touching the CPU interface registers, but at + * least on the ISP1761 it seems to behave as the RESET_ALL bit and + * reset the whole device. We thus can't use it here, so let's reset + * the host controller through the EHCI USB Command register. The device + * has been reset in core code anyway, so this shouldn't matter. + */ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - /* reset */ - reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL); - mdelay(100); - - reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC); - mdelay(100); - result = ehci_reset(hcd); if (result) return result; /* Step 11 passed */ - dev_info(hcd->self.controller, "bus width: %d, oc: %s\n", - (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ? - 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ? - "analog" : "digital"); - /* ATL reset */ + hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET; reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); mdelay(10); reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); @@ -2234,7 +2200,7 @@ void isp1760_deinit_kmem_cache(void) int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, struct resource *mem, int irq, unsigned long irqflags, - struct device *dev, unsigned int devflags) + struct device *dev) { struct usb_hcd *hcd; int ret; @@ -2246,13 +2212,6 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, *(struct isp1760_hcd **)hcd->hcd_priv = priv; priv->hcd = hcd; - priv->devflags = devflags; - - priv->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); - if (IS_ERR(priv->rst_gpio)) { - ret = PTR_ERR(priv->rst_gpio); - goto error; - } init_memory(priv); diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h index dcd2232848c..df7ea3684b7 100644 --- a/drivers/usb/host/isp1760-hcd.h +++ b/drivers/usb/host/isp1760-hcd.h @@ -3,7 +3,6 @@ #include <linux/spinlock.h> -struct gpio_desc; struct isp1760_qh; struct isp1760_qtd; struct resource; @@ -27,20 +26,6 @@ struct usb_hcd; #define MAX_PAYLOAD_SIZE BLOCK_3_SIZE #define PAYLOAD_AREA_SIZE 0xf000 -/* - * 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_OTG_EN 0x00000004 /* Port 1 supports OTG */ -#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 */ - struct isp1760_slotinfo { struct isp1760_qh *qh; struct isp1760_qtd *qtd; @@ -79,14 +64,11 @@ struct isp1760_hcd { unsigned i_thresh; unsigned long reset_done; unsigned long next_statechange; - unsigned int devflags; - - struct gpio_desc *rst_gpio; }; int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs, struct resource *mem, int irq, unsigned long irqflags, - struct device *dev, unsigned int devflags); + struct device *dev); void isp1760_hcd_unregister(struct isp1760_hcd *priv); int isp1760_init_kmem_once(void); |