* 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>
#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)
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;
#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;
};
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
#include <asm/unaligned.h>
#include <asm/cacheflush.h>
+#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
*/
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);
}
/*
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);
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);
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;
*(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);
#include <linux/spinlock.h>
-struct gpio_desc;
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
#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;
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);