Skip to content

Commit

Permalink
dwc2xx_hcd: register usb hcd with the usb subsystem
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Arlott <sa.me.uk>
  • Loading branch information
nomis committed Jun 3, 2012
1 parent 7b66993 commit 3dd975d
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 79 deletions.
228 changes: 177 additions & 51 deletions drivers/usb/host/dwc2xx-hcd.c
Expand Up @@ -27,119 +27,245 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

#include <linux/usb.h>
#include <linux/usb/hcd.h>

#include "dwc2xx-hcd.h"

#define MODULE_NAME "dwc2xx-hcd"

static irqreturn_t dwc2xx_hcd_irq_handler(int irq, void *dev_id)
static irqreturn_t dwc2xx_hcd_irq(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *hcd = dev_id;
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(hcd->dev, "irq\n");
dev_dbg(dwc->dev, "%s\n", __func__);
return IRQ_NONE;
}

static void dwc2xx_hcd_free(struct dwc2xx_hcd *hcd)
static int dwc2xx_hcd_reset(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return 0;
}

static int dwc2xx_hcd_start(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return 0;
}

static void dwc2xx_hcd_stop(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
}

static void dwc2xx_hcd_shutdown(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
}

static int dwc2xx_hcd_get_frame_number(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static int dwc2xx_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static int dwc2xx_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
kfree(hcd);
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static void dwc2xx_hcd_endpoint_disable(struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
}

static int dwc2xx_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static int dwc2xx_hcd_hub_control(struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static int dwc2xx_hcd_bus_suspend(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return 0;
}

static int dwc2xx_hcd_bus_resume(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return 0;
}

static int dwc2xx_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

dev_dbg(dwc->dev, "%s\n", __func__);
return -ENOSYS;
}

static const struct hc_driver dwc2xx_hcd_hc_driver = {
.description = MODULE_NAME,
.product_desc = "DWC 2.xx Host Controller",
.hcd_priv_size = sizeof(struct dwc2xx_hcd),

.irq = dwc2xx_hcd_irq,
.flags = HCD_MEMORY | HCD_USB2,

.reset = dwc2xx_hcd_reset,
.start = dwc2xx_hcd_start,
.stop = dwc2xx_hcd_stop,
.shutdown = dwc2xx_hcd_shutdown,

.urb_enqueue = dwc2xx_hcd_urb_enqueue,
.urb_dequeue = dwc2xx_hcd_urb_dequeue,
.endpoint_disable = dwc2xx_hcd_endpoint_disable,

.get_frame_number = dwc2xx_hcd_get_frame_number,

.hub_status_data = dwc2xx_hcd_hub_status_data,
.hub_control = dwc2xx_hcd_hub_control,

.bus_suspend = dwc2xx_hcd_bus_suspend,
.bus_resume = dwc2xx_hcd_bus_resume,

.start_port_reset = dwc2xx_hcd_start_port_reset
};

static int __devinit dwc2xx_hcd_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct dwc2xx_hcd *hcd = kzalloc(sizeof(*hcd), GFP_KERNEL);
struct usb_hcd *hcd;
struct dwc2xx_hcd *dwc;
int ret;

hcd = usb_create_hcd(&dwc2xx_hcd_hc_driver,
&pdev->dev, dev_name(&pdev->dev));
if (hcd == NULL)
return -ENOMEM;

hcd->dev = &pdev->dev;
if (of_address_to_resource(np, 0, &hcd->res)) {
dwc = hcd_to_dwc(hcd);
dwc->dev = &pdev->dev;
if (of_address_to_resource(np, 0, &dwc->res)) {
ret = -EINVAL;
goto err;
}

if (resource_size(&hcd->res) < SZ_128K) {
dev_err(hcd->dev, "resource too small (%#x)\n",
resource_size(&hcd->res));
if (resource_size(&dwc->res) < SZ_128K) {
dev_err(dwc->dev, "resource too small (%#x)\n",
resource_size(&dwc->res));
ret = -EINVAL;
goto err;
}

if (!request_region(hcd->res.start, resource_size(&hcd->res),
if (!request_region(dwc->res.start, resource_size(&dwc->res),
np->full_name)) {
dev_err(hcd->dev, "resource %#lx unavailable\n",
(unsigned long)hcd->res.start);
dev_err(dwc->dev, "resource %#lx unavailable\n",
(unsigned long)dwc->res.start);
ret = -EBUSY;
goto err;
}

hcd->base = ioremap(hcd->res.start, resource_size(&hcd->res));
if (!hcd->base) {
dev_err(hcd->dev, "error mapping io at %#lx\n",
(unsigned long)hcd->res.start);
hcd->regs = ioremap(dwc->res.start, resource_size(&dwc->res));
if (!hcd->regs) {
dev_err(dwc->dev, "error mapping io at %#lx\n",
(unsigned long)dwc->res.start);
ret = -EIO;
goto err_release;
}

hcd->id = readl(hcd->base + DWC_SNPS_ID_REG);
if ((hcd->id & DWC_SNPS_ID_MASK) != DWC_SNPS_ID_MATCH) {
dev_err(hcd->dev, "incompatible device %08x\n", hcd->id);
dwc->id = readl(hcd->regs + DWC_SNPS_ID_REG);
if ((dwc->id & DWC_SNPS_ID_MASK) != DWC_SNPS_ID_MATCH) {
dev_err(dwc->dev, "incompatible device %08x\n", dwc->id);
ret = -ENODEV;
goto err_unmap;
}

/* TODO: ensure the device won't trigger any interrupts */
hcd->irq = irq_of_parse_and_map(np, 0);
if (hcd->irq <= 0) {
dev_err(hcd->dev, "no IRQ\n");
dwc->irq = irq_of_parse_and_map(np, 0);
if (dwc->irq <= 0) {
dev_err(dwc->dev, "no IRQ\n");
ret = -ENXIO;
goto err_unmap;
}
hcd->irqaction.name = dev_name(hcd->dev);
hcd->irqaction.flags = IRQF_SHARED | IRQF_IRQPOLL;
hcd->irqaction.dev_id = hcd;
hcd->irqaction.handler = dwc2xx_hcd_irq_handler;

ret = setup_irq(hcd->irq, &hcd->irqaction);
dev_info(dwc->dev, "HCD v2.%03x at MMIO %#lx (irq = %d)\n",
dwc->id & ~DWC_SNPS_ID_MASK,
(unsigned long)dwc->res.start, dwc->irq);

dwc2xx_hcd_dump_regs(hcd);

/* TODO: ensure the device won't trigger any interrupts */
ret = usb_add_hcd(hcd, dwc->irq, 0);
if (ret) {
dev_err(hcd->dev, "unable to setup irq %d", hcd->irq);
spin_unlock_irq(&hcd->lock);
dev_err(dwc->dev, "failed to add HCD (%d)\n", ret);
goto err_unmap;
}

dev_info(hcd->dev, "HCD v2.%03x at MMIO %#lx (irq = %d)\n",
hcd->id & ~DWC_SNPS_ID_MASK, (unsigned long)hcd->res.start, hcd->irq);

dwc2xx_hcd_dump_regs(hcd);

platform_set_drvdata(pdev, hcd);
return 0;

/*
err_irq:
remove_irq(hcd->irq, &hcd->irqaction);
*/
err_unmap:
iounmap(hcd->base);
iounmap(hcd->regs);
err_release:
release_region(hcd->res.start, resource_size(&hcd->res));
release_region(dwc->res.start, resource_size(&dwc->res));
err:
dwc2xx_hcd_free(hcd);
usb_put_hcd(hcd);
return ret;
}

static int dwc2xx_hcd_remove(struct platform_device *pdev)
{
struct dwc2xx_hcd *hcd = platform_get_drvdata(pdev);
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);

remove_irq(hcd->irq, &hcd->irqaction);
iounmap(hcd->base);
release_region(hcd->res.start, resource_size(&hcd->res));
dwc2xx_hcd_free(hcd);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_region(dwc->res.start, resource_size(&dwc->res));
usb_put_hcd(hcd);
platform_set_drvdata(pdev, NULL);
return 0;
}
Expand Down
59 changes: 31 additions & 28 deletions drivers/usb/host/dwc2xx-hcd.h
Expand Up @@ -49,10 +49,7 @@
struct dwc2xx_hcd {
struct device *dev;
struct resource res;
void __iomem *base;
int irq;
struct irqaction irqaction;
struct spinlock lock;

u32 id; /* Synopsys ID */
};
Expand Down Expand Up @@ -122,36 +119,42 @@ enum dwc_hwcfg2_mode {
#define DWC_DV_TX_FIFO_SZ_REG(n) (DWC_DV_TX_FIFO_SZ_BASE + (n) * 4)
#define DWC_DV_TX_FIFO_SZ_COUNT 16

static void dwc2xx_hcd_dump_regs(struct dwc2xx_hcd *hcd)
static inline struct dwc2xx_hcd *hcd_to_dwc(struct usb_hcd *hcd)
{
return (struct dwc2xx_hcd *)hcd->hcd_priv;
}

static void dwc2xx_hcd_dump_regs(struct usb_hcd *hcd)
{
struct dwc2xx_hcd *dwc = hcd_to_dwc(hcd);
int i;

WARN_ON(1);
dev_dbg(hcd->dev, "%03x = %08x; DWC_OTG_CTL_REG\n", DWC_OTG_CTL_REG, readl(hcd->base + DWC_OTG_CTL_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_OTG_INT_REG\n", DWC_OTG_INT_REG, readl(hcd->base + DWC_OTG_INT_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_CORE_AHB_CFG_REG\n", DWC_CORE_AHB_CFG_REG, readl(hcd->base + DWC_CORE_AHB_CFG_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_CORE_USB_CFG_REG\n", DWC_CORE_USB_CFG_REG, readl(hcd->base + DWC_CORE_USB_CFG_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_CORE_RESET_REG\n", DWC_CORE_RESET_REG, readl(hcd->base + DWC_CORE_RESET_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_CORE_INT_REG\n", DWC_CORE_INT_REG, readl(hcd->base + DWC_CORE_INT_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_INT_MASK_REG\n", DWC_INT_MASK_REG, readl(hcd->base + DWC_INT_MASK_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_RX_STAT_PEEK_REG\n", DWC_RX_STAT_PEEK_REG, readl(hcd->base + DWC_RX_STAT_PEEK_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_RX_STAT_POP_REG\n", DWC_RX_STAT_POP_REG, readl(hcd->base + DWC_RX_STAT_POP_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_RX_FIFO_SZ_REG\n", DWC_RX_FIFO_SZ_REG, readl(hcd->base + DWC_RX_FIFO_SZ_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_NP_TX_FIFO_SZ_REG\n", DWC_NP_TX_FIFO_SZ_REG, readl(hcd->base + DWC_NP_TX_FIFO_SZ_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_NP_TX_STAT_READ_REG\n", DWC_NP_TX_STAT_READ_REG, readl(hcd->base + DWC_NP_TX_STAT_READ_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_I2C_CTL_REG\n", DWC_I2C_CTL_REG, readl(hcd->base + DWC_I2C_CTL_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_PHY_VENDOR_CTRL_REG\n", DWC_PHY_VENDOR_CTRL_REG, readl(hcd->base + DWC_PHY_VENDOR_CTRL_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_GPIO_REG\n", DWC_GPIO_REG, readl(hcd->base + DWC_GPIO_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_UID_REG\n", DWC_UID_REG, readl(hcd->base + DWC_UID_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_SNPS_ID_REG\n", DWC_SNPS_ID_REG, readl(hcd->base + DWC_SNPS_ID_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_USER_HW_CFG1_REG\n", DWC_USER_HW_CFG1_REG, readl(hcd->base + DWC_USER_HW_CFG1_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_USER_HW_CFG2_REG\n", DWC_USER_HW_CFG2_REG, readl(hcd->base + DWC_USER_HW_CFG2_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_USER_HW_CFG3_REG\n", DWC_USER_HW_CFG3_REG, readl(hcd->base + DWC_USER_HW_CFG3_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_USER_HW_CFG4_REG\n", DWC_USER_HW_CFG4_REG, readl(hcd->base + DWC_USER_HW_CFG4_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_CORE_LPM_CFG_REG\n", DWC_CORE_LPM_CFG_REG, readl(hcd->base + DWC_CORE_LPM_CFG_REG));
dev_dbg(hcd->dev, "%03x = %08x; DWC_HP_TX_FIFO_SZ_REG\n", DWC_HP_TX_FIFO_SZ_REG, readl(hcd->base + DWC_HP_TX_FIFO_SZ_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_OTG_CTL_REG\n", DWC_OTG_CTL_REG, readl(hcd->regs + DWC_OTG_CTL_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_OTG_INT_REG\n", DWC_OTG_INT_REG, readl(hcd->regs + DWC_OTG_INT_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_CORE_AHB_CFG_REG\n", DWC_CORE_AHB_CFG_REG, readl(hcd->regs + DWC_CORE_AHB_CFG_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_CORE_USB_CFG_REG\n", DWC_CORE_USB_CFG_REG, readl(hcd->regs + DWC_CORE_USB_CFG_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_CORE_RESET_REG\n", DWC_CORE_RESET_REG, readl(hcd->regs + DWC_CORE_RESET_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_CORE_INT_REG\n", DWC_CORE_INT_REG, readl(hcd->regs + DWC_CORE_INT_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_INT_MASK_REG\n", DWC_INT_MASK_REG, readl(hcd->regs + DWC_INT_MASK_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_RX_STAT_PEEK_REG\n", DWC_RX_STAT_PEEK_REG, readl(hcd->regs + DWC_RX_STAT_PEEK_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_RX_STAT_POP_REG\n", DWC_RX_STAT_POP_REG, readl(hcd->regs + DWC_RX_STAT_POP_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_RX_FIFO_SZ_REG\n", DWC_RX_FIFO_SZ_REG, readl(hcd->regs + DWC_RX_FIFO_SZ_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_NP_TX_FIFO_SZ_REG\n", DWC_NP_TX_FIFO_SZ_REG, readl(hcd->regs + DWC_NP_TX_FIFO_SZ_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_NP_TX_STAT_READ_REG\n", DWC_NP_TX_STAT_READ_REG, readl(hcd->regs + DWC_NP_TX_STAT_READ_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_I2C_CTL_REG\n", DWC_I2C_CTL_REG, readl(hcd->regs + DWC_I2C_CTL_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_PHY_VENDOR_CTRL_REG\n", DWC_PHY_VENDOR_CTRL_REG, readl(hcd->regs + DWC_PHY_VENDOR_CTRL_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_GPIO_REG\n", DWC_GPIO_REG, readl(hcd->regs + DWC_GPIO_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_UID_REG\n", DWC_UID_REG, readl(hcd->regs + DWC_UID_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_SNPS_ID_REG\n", DWC_SNPS_ID_REG, readl(hcd->regs + DWC_SNPS_ID_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_USER_HW_CFG1_REG\n", DWC_USER_HW_CFG1_REG, readl(hcd->regs + DWC_USER_HW_CFG1_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_USER_HW_CFG2_REG\n", DWC_USER_HW_CFG2_REG, readl(hcd->regs + DWC_USER_HW_CFG2_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_USER_HW_CFG3_REG\n", DWC_USER_HW_CFG3_REG, readl(hcd->regs + DWC_USER_HW_CFG3_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_USER_HW_CFG4_REG\n", DWC_USER_HW_CFG4_REG, readl(hcd->regs + DWC_USER_HW_CFG4_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_CORE_LPM_CFG_REG\n", DWC_CORE_LPM_CFG_REG, readl(hcd->regs + DWC_CORE_LPM_CFG_REG));
dev_dbg(dwc->dev, "%03x = %08x; DWC_HP_TX_FIFO_SZ_REG\n", DWC_HP_TX_FIFO_SZ_REG, readl(hcd->regs + DWC_HP_TX_FIFO_SZ_REG));
for (i = 0; i < DWC_DV_TX_FIFO_SZ_COUNT; i++)
dev_dbg(hcd->dev, "%03x = %08x; DWC_DV_TX_FIFO_SZ_REG(%d)\n", DWC_DV_TX_FIFO_SZ_REG(i), readl(hcd->base + DWC_DV_TX_FIFO_SZ_REG(i)), i);
dev_dbg(dwc->dev, "%03x = %08x; DWC_DV_TX_FIFO_SZ_REG(%d)\n", DWC_DV_TX_FIFO_SZ_REG(i), readl(hcd->regs + DWC_DV_TX_FIFO_SZ_REG(i)), i);
}

#endif

0 comments on commit 3dd975d

Please sign in to comment.