[patch v4 0/4] Cypress c67x00 (EZ-Host/EZ-OTG) support
Peter Korsgaard
jacmet at sunsite.dk
Tue Jan 22 08:16:35 EST 2008
>>>>> "Grant" == Grant Likely <grant.likely at secretlab.ca> writes:
Grant> Personally, I'd prefer to see the v3 series picked up now (as I
Grant> believe all outstanding comments from the list have been addressed)
Grant> and have new patches build on top of that, but that's just my
Grant> preference.
Here's the v3->v4 without gadget diff:
diff --git a/MAINTAINERS b/MAINTAINERS
index 2340cfb..e3b7866 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3832,6 +3832,12 @@ L: linux-usb at vger.kernel.org
S: Maintained
W: http://www.kroah.com/linux-usb/
+USB CYPRESS C67X00 DRIVER
+P: Peter Korsgaard
+M: jacmet at sunsite.dk
+L: linux-usb at vger.kernel.org
+S: Maintained
+
USB DAVICOM DM9601 DRIVER
P: Peter Korsgaard
M: jacmet at sunsite.dk
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index 0f0720a..c2ea3b6 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -1,7 +1,7 @@
/*
* c67x00-drv.c: Cypress C67X00 USB Common infrastructure
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -30,8 +30,8 @@
* The c67x00 has 2 SIE's (serial interface engine) wich can be configured
* to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
*
- * Depending on the platform configuration, the SIE's are created (setup_sie)
- * and the corresponding subdriver is initialized (c67x00_probe_sie).
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
*/
#include <linux/device.h>
@@ -41,36 +41,17 @@
#include <asm/io.h>
#include "c67x00.h"
+#include "c67x00-hcd.h"
-static struct platform_driver c67x00_driver;
-
-static void
-c67x00_setup_sie(struct c67x00_sie *sie, struct c67x00_device *dev, int sie_num)
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+ struct c67x00_device *dev, int sie_num)
{
- static unsigned int id = 0;
-
- /* Fill in needed attributes */
- sie->pdev = platform_device_register_simple("c67x00_sie",
- id++, NULL, 0);
- /* driver used in hub.c: hub_port_init */
- sie->pdev->dev.driver = &c67x00_driver.driver;
spin_lock_init(&sie->lock);
sie->dev = dev;
sie->sie_num = sie_num;
sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
-}
-static void c67x00_teardown_sie(struct c67x00_sie *sie)
-{
- sie->pdev->dev.driver = NULL;
- platform_device_unregister(sie->pdev);
-}
-
-/* ------------------------------------------------------------------ */
-
-static void c67x00_probe_sie(struct c67x00_sie *sie)
-{
- switch (c67x00_sie_config(sie->dev->pdata->sie_config, sie->sie_num)) {
+ switch (sie->mode) {
case C67X00_SIE_HOST:
c67x00_hcd_probe(sie);
break;
@@ -83,15 +64,14 @@ static void c67x00_probe_sie(struct c67x00_sie *sie)
default:
dev_err(sie_dev(sie),
"Unsupported configuration: 0x%x for SIE %d\n",
- c67x00_sie_config(sie->dev->pdata->sie_config,
- sie->sie_num), sie->sie_num);
+ sie->mode, sie->sie_num);
break;
}
}
static void c67x00_remove_sie(struct c67x00_sie *sie)
{
- switch (c67x00_sie_config(sie->dev->pdata->sie_config, sie->sie_num)) {
+ switch (sie->mode) {
case C67X00_SIE_HOST:
c67x00_hcd_remove(sie);
break;
@@ -101,44 +81,42 @@ static void c67x00_remove_sie(struct c67x00_sie *sie)
}
}
-/* ------------------------------------------------------------------ */
static irqreturn_t c67x00_irq(int irq, void *__dev)
{
struct c67x00_device *c67x00 = __dev;
struct c67x00_sie *sie;
- u16 msg;
+ u16 msg, int_status;
int i, count = 8;
- c67x00->int_status = c67x00_ll_hpi_status(c67x00);
- if (!c67x00->int_status)
+ int_status = c67x00_ll_hpi_status(c67x00);
+ if (!int_status)
return IRQ_NONE;
- while (c67x00->int_status != 0 && (count-- >= 0)) {
- c67x00_ll_irq(c67x00);
+ while (int_status != 0 && (count-- >= 0)) {
+ c67x00_ll_irq(c67x00, int_status);
for (i = 0; i < C67X00_SIES; i++) {
sie = &c67x00->sie[i];
msg = 0;
- spin_lock(&sie->lock);
- if (c67x00->int_status & SIEMSG_FLAG(sie->sie_num))
- msg = c67x00_ll_get_siemsg(c67x00,sie->sie_num);
+ if (int_status & SIEMSG_FLG(i)) {
+ msg = c67x00_ll_get_siemsg(sie);
+ /* clear register to allow next message */
+ c67x00_ll_set_siemsg(sie, 0);
+ }
if (sie->irq)
- sie->irq(sie, msg);
- spin_unlock(&sie->lock);
+ sie->irq(sie, int_status, msg);
}
- c67x00->int_status = c67x00_ll_hpi_status(c67x00);
+ int_status = c67x00_ll_hpi_status(c67x00);
}
- if (c67x00->int_status)
+ if (int_status)
dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
- "status = 0x%04x\n", c67x00->int_status);
+ "status = 0x%04x\n", int_status);
return IRQ_HANDLED;
}
-/* ---------------------------------------------------------------------
- * Platform bus binding
- */
+/* ------------------------------------------------------------------------- */
static int __devinit c67x00_drv_probe(struct platform_device *pdev)
{
@@ -176,20 +154,14 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
goto map_failed;
}
- spin_lock_init(&c67x00->hw_lock);
+ spin_lock_init(&c67x00->hpi.lock);
c67x00->hpi.regstep = pdata->hpi_regstep;
c67x00->pdata = pdev->dev.platform_data;
c67x00->pdev = pdev;
- for (i = 0; i < C67X00_SIES; i++)
- c67x00_setup_sie(&c67x00->sie[i], c67x00, i);
-
c67x00_ll_init(c67x00);
c67x00_ll_hpi_reg_init(c67x00);
- dev_info(&pdev->dev, "USB OTG controller, p:0x%x, v:0x%p, irq:%i\n",
- res->start, c67x00->hpi.base, res2->start);
-
ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
if (ret) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
@@ -203,19 +175,19 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
}
for (i = 0; i < C67X00_SIES; i++)
- c67x00_probe_sie(&c67x00->sie[i]);
+ c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
platform_set_drvdata(pdev, c67x00);
return 0;
- reset_failed:
+reset_failed:
free_irq(res2->start, c67x00);
- request_irq_failed:
+request_irq_failed:
iounmap(c67x00->hpi.base);
- map_failed:
+map_failed:
release_mem_region(res->start, res->end - res->start + 1);
- request_mem_failed:
+request_mem_failed:
kfree(c67x00);
return ret;
@@ -227,10 +199,8 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
struct resource *res;
int i;
- for (i = 0; i < C67X00_SIES; i++) {
+ for (i = 0; i < C67X00_SIES; i++)
c67x00_remove_sie(&c67x00->sie[i]);
- c67x00_teardown_sie(&c67x00->sie[i]);
- }
c67x00_ll_release(c67x00);
@@ -250,9 +220,9 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
}
static struct platform_driver c67x00_driver = {
- .probe = c67x00_drv_probe,
- .remove = __devexit_p(c67x00_drv_remove),
- .driver = {
+ .probe = c67x00_drv_probe,
+ .remove = __devexit_p(c67x00_drv_remove),
+ .driver = {
.owner = THIS_MODULE,
.name = "c67x00",
},
@@ -265,12 +235,13 @@ static int __init c67x00_init(void)
return platform_driver_register(&c67x00_driver);
}
-module_init(c67x00_init);
static void __exit c67x00_exit(void)
{
platform_driver_unregister(&c67x00_driver);
}
+
+module_init(c67x00_init);
module_exit(c67x00_exit);
MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
index 3d0b77e..4afb291 100644
--- a/drivers/usb/c67x00/c67x00-hcd.c
+++ b/drivers/usb/c67x00/c67x00-hcd.c
@@ -1,7 +1,7 @@
/*
* c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -66,7 +66,7 @@ static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
int i;
*buf = 0;
- status = c67x00_ll_husb_get_status(sie);
+ status = c67x00_ll_usb_get_status(sie);
for (i = 0; i < C67X00_PORTS; i++)
if (status & PORT_CONNECT_CHANGE(i))
*buf |= (1 << i);
@@ -91,13 +91,14 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetHubStatus:
*(__le32 *) buf = cpu_to_le32(0);
- len = 4; /* hub power */
+ len = 4; /* hub power */
break;
+
case GetPortStatus:
if (wIndex > C67X00_PORTS)
return -EPIPE;
- status = c67x00_ll_husb_get_status(sie);
+ status = c67x00_ll_usb_get_status(sie);
usb_status = c67x00_ll_get_usb_ctl(sie);
wPortChange = 0;
@@ -120,6 +121,7 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
len = 4;
break;
+
case SetHubFeature: /* We don't implement these */
case ClearHubFeature:
switch (wValue) {
@@ -127,35 +129,41 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case C_HUB_LOCAL_POWER:
len = 0;
break;
+
default:
return -EPIPE;
}
break;
+
case SetPortFeature:
if (wIndex > C67X00_PORTS)
return -EPIPE;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"SetPortFeature %d (SUSPEND)\n", port);
len = 0;
break;
+
case USB_PORT_FEAT_RESET:
c67x00_hub_reset_host_port(sie, port);
len = 0;
break;
+
case USB_PORT_FEAT_POWER:
/* Power always enabled */
len = 0;
break;
+
default:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"%s: SetPortFeature %d (0x%04x) Error!\n",
__FUNCTION__, port, wValue);
return -EPIPE;
}
break;
+
case ClearPortFeature:
if (wIndex > C67X00_PORTS)
return -EPIPE;
@@ -167,53 +175,64 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
c67x00_hub_reset_host_port(sie, port);
len = 0;
break;
+
case USB_PORT_FEAT_C_ENABLE:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): C_ENABLE\n", port);
len = 0;
break;
+
case USB_PORT_FEAT_SUSPEND:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): SUSPEND\n", port);
len = 0;
break;
+
case USB_PORT_FEAT_C_SUSPEND:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): C_SUSPEND\n", port);
len = 0;
break;
+
case USB_PORT_FEAT_POWER:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): POWER\n", port);
return -EPIPE;
+
case USB_PORT_FEAT_C_CONNECTION:
- c67x00_ll_husb_clear_status(sie,
- PORT_CONNECT_CHANGE(port));
+ c67x00_ll_usb_clear_status(sie,
+ PORT_CONNECT_CHANGE(port));
len = 0;
break;
+
case USB_PORT_FEAT_C_OVER_CURRENT:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): OVER_CURRENT\n", port);
len = 0;
break;
+
case USB_PORT_FEAT_C_RESET:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"ClearPortFeature (%d): C_RESET\n", port);
len = 0;
break;
+
default:
- dev_dbg(c67x00_hcd_dev(c67x00),
+ dev_dbg(c67x00_dev(c67x00),
"%s: ClearPortFeature %d (0x%04x) Error!\n",
__FUNCTION__, port, wValue);
return -EPIPE;
}
break;
+
case GetHubDescriptor:
len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
memcpy(buf, c67x00_hub_des, len);
break;
+
default:
- dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __FUNCTION__);
+ dev_dbg(c67x00_dev(c67x00), "%s: unknown\n", __FUNCTION__);
+ return -EPIPE;
}
return 0;
@@ -228,18 +247,17 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*
* This function is called from the interrupt handler in c67x00-drv.c
*/
-static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 msg)
+static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
{
- struct c67x00_device *c67x00 = sie->dev;
- struct c67x00_hcd *c67x00_hcd = sie->private_data;
- struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00_hcd);
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
/* Handle sie message flags */
if (msg) {
if (msg & HUSB_TDListDone)
- c67x00_sched_kick(c67x00_hcd);
+ c67x00_sched_kick(c67x00);
else
- dev_warn(c67x00_hcd_dev(c67x00_hcd),
+ dev_warn(c67x00_dev(c67x00),
"Unknown SIE msg flag(s): 0x%04x\n", msg);
}
@@ -250,30 +268,31 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 msg)
return;
/* Handle Start of frame events */
- if (sie->dev->int_status & SOFEOP_FLG(sie->sie_num)) {
- c67x00_ll_husb_clear_status(sie, SOF_EOP_IRQ_FLG);
- c67x00_sched_kick(c67x00_hcd);
+ if (int_status & SOFEOP_FLG(sie->sie_num)) {
+ c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+ c67x00_sched_kick(c67x00);
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
}
/**
- * c67x00_hcd_start: Host Controller start hook
+ * c67x00_hcd_start: Host controller start hook
*/
static int c67x00_hcd_start(struct usb_hcd *hcd)
{
hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING;
hcd->poll_rh = 1;
+
return 0;
}
/**
- * c67x00_hcd_start: Host Controller stop hook
+ * c67x00_hcd_stop: Host controller stop hook
*/
static void c67x00_hcd_stop(struct usb_hcd *hcd)
{
- /* Nothing todo */
+ /* Nothing to do */
}
static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
@@ -281,29 +300,29 @@ static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
u16 temp_val;
- dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __FUNCTION__);
+ dev_dbg(c67x00_dev(c67x00), "%s\n", __FUNCTION__);
temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
temp_val &= HOST_FRAME_MASK;
return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
}
static struct hc_driver c67x00_hc_driver = {
- .description = "c67x00-hcd",
- .product_desc = "Cypress C67X00 Host Controller",
- .hcd_priv_size = sizeof(struct c67x00_hcd),
- .flags = HCD_USB11 | HCD_MEMORY,
+ .description = "c67x00-hcd",
+ .product_desc = "Cypress C67X00 Host Controller",
+ .hcd_priv_size = sizeof(struct c67x00_hcd),
+ .flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
- .start = c67x00_hcd_start,
- .stop = c67x00_hcd_stop,
+ .start = c67x00_hcd_start,
+ .stop = c67x00_hcd_stop,
/*
* managing i/o requests and associated device resources
*/
- .urb_enqueue = c67x00_urb_enqueue,
- .urb_dequeue = c67x00_urb_dequeue,
+ .urb_enqueue = c67x00_urb_enqueue,
+ .urb_dequeue = c67x00_urb_dequeue,
.endpoint_disable = c67x00_endpoint_disable,
/*
@@ -315,7 +334,7 @@ static struct hc_driver c67x00_hc_driver = {
* root hub support
*/
.hub_status_data = c67x00_hub_status_data,
- .hub_control = c67x00_hub_control,
+ .hub_control = c67x00_hub_control,
};
/* ---------------------------------------------------------------------
@@ -324,9 +343,10 @@ static struct hc_driver c67x00_hc_driver = {
int c67x00_hcd_probe(struct c67x00_sie *sie)
{
- int retval;
- struct usb_hcd *hcd = NULL;
struct c67x00_hcd *c67x00;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+ int retval;
hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
if (!hcd) {
@@ -349,11 +369,6 @@ int c67x00_hcd_probe(struct c67x00_sie *sie)
c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
c67x00->max_frame_bw = MAX_FRAME_BW_STD;
- spin_lock(&sie->lock);
- sie->private_data = c67x00;
- sie->irq = c67x00_hcd_irq;
- spin_unlock(&sie->lock);
-
c67x00_ll_husb_init_host_port(sie);
init_completion(&c67x00->endpoint_disable);
@@ -368,23 +383,26 @@ int c67x00_hcd_probe(struct c67x00_sie *sie)
goto err2;
}
+ spin_lock_irqsave(&sie->lock, flags);
+ sie->private_data = c67x00;
+ sie->irq = c67x00_hcd_irq;
+ spin_unlock_irqrestore(&sie->lock, flags);
+
return retval;
- err2:
+err2:
c67x00_sched_stop_scheduler(c67x00);
- err1:
+err1:
usb_put_hcd(hcd);
- err0:
+err0:
return retval;
}
/* may be called with controller, bus, and devices active */
void c67x00_hcd_remove(struct c67x00_sie *sie)
{
- struct usb_hcd *hcd;
- struct c67x00_hcd *c67x00;
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
- c67x00 = sie->private_data;
- hcd = c67x00_hcd_to_hcd(c67x00);
c67x00_sched_stop_scheduler(c67x00);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
index 5b35f01..daee4cd 100644
--- a/drivers/usb/c67x00/c67x00-hcd.h
+++ b/drivers/usb/c67x00/c67x00-hcd.h
@@ -1,7 +1,7 @@
/*
* c67x00-hcd.h: Cypress C67X00 USB HCD
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -69,15 +69,6 @@
struct c67x00_hcd {
spinlock_t lock;
struct c67x00_sie *sie;
- /* Requirement:
- * All enabled bits in ports must have a position <= MAX_NB_HCD_PORTS
- * (position starts counting from 1!)
- * ( ports & ~((1<<MAX_NB_HCD_PORTS)-1) ) == 0
- *
- * This might be relaxed if needed by using an other indexing scheme
- * for port[] (e.g. use wIndex instead of real port number)
- * */
-#define MAX_NB_HCD_PORTS 2
unsigned int low_speed_ports; /* bitmask of low speed ports */
unsigned int urb_count;
unsigned int urb_iso_count;
@@ -119,6 +110,30 @@ static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
}
+/* -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_USB_C67X00_HCD
+/* Functions used by drv */
+int c67x00_hcd_probe(struct c67x00_sie *sie);
+void c67x00_hcd_remove(struct c67x00_sie *sie);
+#else
+static inline int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+ printk(KERN_ERR "hcd requested but CONFIG_USB_C67X00_HCD "
+ "not enabled!\n");
+ return -ENODEV;
+}
+
+static inline void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+}
+
+static int usb_disabled(void)
+{
+ return 0;
+}
+#endif /* CONFIG_USB_C67X00_HCD */
+
/* ---------------------------------------------------------------------
* Transfer Descriptor scheduling functions
*/
@@ -132,6 +147,6 @@ void c67x00_sched_kick(struct c67x00_hcd *c67x00);
int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
-#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
+#define c67x00_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
#endif /* _USB_C67X00_HCD_H */
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
index d6a95d6..ebf58e3 100644
--- a/drivers/usb/c67x00/c67x00-ll-hpi.c
+++ b/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -1,7 +1,7 @@
/*
* c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -23,37 +23,41 @@
#include <asm/io.h>
#include <asm/byteorder.h>
+#include <linux/usb/c67x00.h>
#include "c67x00.h"
+#define COMM_REGS 14
+
+struct lcp_int_data {
+ u16 regs[COMM_REGS];
+};
+
/* -------------------------------------------------------------------------- */
/* Interface definitions */
#define COMM_ACK 0x0FED
#define COMM_NAK 0xDEAD
-#define COMM_CTRL_REG_ADDR 0x01BC
-#define COMM_CTRL_REG_DATA 0x01BE
-#define COMM_CTRL_REG_LOGIC 0x01C0
-#define COMM_WRITE_CTRL_REG 0xCE03
-#define COMM_READ_CTRL_REG 0xCE02
-
#define COMM_RESET 0xFA50
#define COMM_EXEC_INT 0xCE01
#define COMM_INT_NUM 0x01C2
+
/* Registers 0 to COMM_REGS-1 */
#define COMM_R(x) (0x01C4 + 2 * (x))
-#define HUSB_SIE_pCurrentTDPtr(x) ( (x) ? 0x01B2 : 0x01B0 )
-#define HUSB_SIE_pTDListDone_Sem(x) ( (x) ? 0x01B8 : 0x01B6 )
+#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6)
#define HUSB_pEOT 0x01B4
/* Software interrupts */
/* 114, 115: */
-#define HUSB_SIE_INIT_INT(x) ( (x) ? 0x0073 : 0x0072 )
-#define HUSB_RESET_INT 0x0074 /* 116 */
+#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT 0x0074
#define SUSB_INIT_INT 0x0071
-/* ---------------------------------------------------------------------
+#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
* HPI implementation
*
* The c67x00 chip also support control via SPI or HSS serial
@@ -89,9 +93,9 @@ static inline u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
u16 value;
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
@@ -107,43 +111,43 @@ static inline void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
{
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_word_nolock(dev, reg, value);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
/*
* Only data is little endian, addr has cpu endianess
*/
static inline void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
- u16 * data, u16 count)
+ u16 *data, u16 count)
{
unsigned long flags;
int i;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
/*
* Only data is little endian, addr has cpu endianess
*/
static inline void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
- u16 * data, u16 count)
+ u16 *data, u16 count)
{
unsigned long flags;
int i;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
*data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static inline void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
@@ -151,10 +155,10 @@ static inline void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
u16 value;
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
hpi_write_word_nolock(dev, reg, value | mask);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static inline void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
@@ -162,10 +166,10 @@ static inline void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
u16 value;
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_word_nolock(dev, reg);
hpi_write_word_nolock(dev, reg, value & ~mask);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
static inline u16 hpi_recv_mbox(struct c67x00_device *dev)
@@ -173,9 +177,9 @@ static inline u16 hpi_recv_mbox(struct c67x00_device *dev)
u16 value;
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_reg(dev, HPI_MAILBOX);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
@@ -184,21 +188,21 @@ static inline u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
{
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_MAILBOX, value);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
-u16 c67x00_ll_hpi_status(struct c67x00_device * dev)
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
{
u16 value;
unsigned long flags;
- spin_lock_irqsave(&dev->hw_lock, flags);
+ spin_lock_irqsave(&dev->hpi.lock, flags);
value = hpi_read_reg(dev, HPI_STATUS);
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
return value;
}
@@ -211,7 +215,7 @@ void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
c67x00_ll_hpi_status(dev);
hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
- for (i=0; i<C67X00_SIES; i++) {
+ for (i = 0; i < C67X00_SIES; i++) {
hpi_write_word(dev, SIEMSG_REG(i), 0);
hpi_read_word(dev, SIEMSG_REG(i));
}
@@ -236,69 +240,81 @@ static inline u16 ll_recv_msg(struct c67x00_device *dev)
{
u16 res;
- res = wait_for_completion_timeout(&dev->lcp.msg_received, 5 * HZ);
+ res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
WARN_ON(!res);
return (res == 0) ? -EIO : 0;
}
/* -------------------------------------------------------------------------- */
+/* General functions */
-u16 c67x00_comm_read_ctrl_reg(struct c67x00_device * dev, u16 addr)
+u16 c67x00_ll_get_siemsg(struct c67x00_sie *sie)
{
- unsigned long msg, res;
- int rc;
+ return hpi_read_word(sie->dev, SIEMSG_REG(sie->sie_num));
+}
- mutex_lock(&dev->lcp.mutex);
- hpi_write_word(dev, COMM_CTRL_REG_ADDR, addr);
- hpi_send_mbox(dev, COMM_READ_CTRL_REG);
- rc = ll_recv_msg(dev);
+void c67x00_ll_set_siemsg(struct c67x00_sie *sie, u16 val)
+{
+ hpi_write_word(sie->dev, SIEMSG_REG(sie->sie_num), val);
+}
- BUG_ON(rc); /* No return path for error code; crash spectacularly */
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
- msg = dev->lcp.last_msg;
- if (msg != COMM_ACK) {
- dev_warn(&dev->pdev->dev, "COMM_READ_CTRL_REG didn't ACK!\n");
- res = 0;
- } else {
- res = hpi_read_word(dev, COMM_CTRL_REG_DATA);
- }
- mutex_unlock(&dev->lcp.mutex);
- return res;
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val)
+{
+ hpi_write_word(sie->dev,
+ DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num), val);
+}
+
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+ u16 val)
+{
+ /* This undocumented register needs to be set to the packet size
+ Normally the BIOS sets this correctly when it is able to parse
+ the configuration descriptor correctly */
+ hpi_write_word(sie->dev,
+ (DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num)
+ + 0x0A), val);
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+ hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
}
-int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
- struct c67x00_lcp_int_data *data)
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+ struct lcp_int_data *data)
{
int i, rc;
- mutex_lock(&dev->lcp.mutex);
+ mutex_lock(&dev->hpi.lcp.mutex);
hpi_write_word(dev, COMM_INT_NUM, nr);
for (i = 0; i < COMM_REGS; i++)
hpi_write_word(dev, COMM_R(i), data->regs[i]);
hpi_send_mbox(dev, COMM_EXEC_INT);
rc = ll_recv_msg(dev);
- mutex_unlock(&dev->lcp.mutex);
+ mutex_unlock(&dev->hpi.lcp.mutex);
return rc;
}
-/* -------------------------------------------------------------------------- */
-/* General functions */
-
-u16 c67x00_ll_get_siemsg(struct c67x00_device *dev, int sie)
+static u16 c67x00_get_comm_reg(struct c67x00_device *dev, u16 nr)
{
- return hpi_read_word(dev, SIEMSG_REG(sie));
-}
-
-void c67x00_ll_set_siemsg(struct c67x00_device *dev, int sie, u16 val)
-{
- hpi_write_word(dev, SIEMSG_REG(sie), val);
-}
-
-u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
-{
- return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+ return hpi_read_word(dev, COMM_R(nr));
}
/* -------------------------------------------------------------------------- */
@@ -306,15 +322,15 @@ u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
{
- mutex_lock(&dev->lcp.mutex);
+ mutex_lock(&dev->hpi.lcp.mutex);
hpi_write_word(dev, HUSB_pEOT, value);
- mutex_unlock(&dev->lcp.mutex);
+ mutex_unlock(&dev->hpi.lcp.mutex);
}
static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
{
struct c67x00_device *dev = sie->dev;
- struct c67x00_lcp_int_data data;
+ struct lcp_int_data data;
int rc;
rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
@@ -324,7 +340,7 @@ static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
{
struct c67x00_device *dev = sie->dev;
- struct c67x00_lcp_int_data data;
+ struct lcp_int_data data;
int rc;
data.regs[0] = 50; /* Reset USB port for 50ms */
@@ -343,20 +359,7 @@ u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
}
-/**
- * c67x00_ll_husb_clear_status - clear the host status bits
- */
-void c67x00_ll_husb_clear_status(struct c67x00_sie *sie, u16 bits)
-{
- hpi_write_word(sie->dev, HOST_STAT_REG(sie->sie_num), bits);
-}
-
-u16 c67x00_ll_husb_get_status(struct c67x00_sie *sie)
-{
- return hpi_read_word(sie->dev, HOST_STAT_REG(sie->sie_num));
-}
-
-u16 c67x00_ll_husb_get_frame(struct c67x00_sie * sie)
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
{
return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
}
@@ -367,7 +370,7 @@ void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
c67x00_ll_husb_sie_init(sie);
/* Clear interrupts */
- c67x00_ll_husb_clear_status(sie, HOST_STAT_MASK);
+ c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
/* Check */
if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
dev_warn(sie_dev(sie),
@@ -377,7 +380,7 @@ void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
{
/* Clear connect change */
- c67x00_ll_husb_clear_status(sie, PORT_CONNECT_CHANGE(port));
+ c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
/* Enable interrupts */
hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
@@ -390,31 +393,14 @@ void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
}
/* -------------------------------------------------------------------------- */
-void c67x00_ll_susb_init(struct c67x00_sie *sie)
-{
- struct c67x00_device *dev = sie->dev;
- struct c67x00_lcp_int_data data;
- int rc;
-
- data.regs[1] = 1; /* full speed */
- data.regs[2] = sie->sie_num + 1;
- rc = c67x00_comm_exec_int(dev, SUSB_INIT_INT, &data);
- BUG_ON(rc); /* No return path for error code; crash spectacularly */
-
- hpi_clear_bits(dev, HPI_IRQ_ROUTING_REG,
- SOFEOP_TO_HPI_EN(sie->sie_num));
- hpi_set_bits(dev, HPI_IRQ_ROUTING_REG, SOFEOP_TO_CPU_EN(sie->sie_num));
-}
-
-/* -------------------------------------------------------------------------- */
-void c67x00_ll_irq(struct c67x00_device *dev)
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
{
- if ((dev->int_status & MBX_OUT_FLG) == 0)
+ if ((int_status & MBX_OUT_FLG) == 0)
return;
- dev->lcp.last_msg = hpi_recv_mbox(dev);
- complete(&dev->lcp.msg_received);
+ dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+ complete(&dev->hpi.lcp.msg_received);
}
/* -------------------------------------------------------------------------- */
@@ -423,10 +409,10 @@ int c67x00_ll_reset(struct c67x00_device *dev)
{
int rc;
- mutex_lock(&dev->lcp.mutex);
+ mutex_lock(&dev->hpi.lcp.mutex);
hpi_send_mbox(dev, COMM_RESET);
rc = ll_recv_msg(dev);
- mutex_unlock(&dev->lcp.mutex);
+ mutex_unlock(&dev->hpi.lcp.mutex);
return rc;
}
@@ -434,12 +420,14 @@ int c67x00_ll_reset(struct c67x00_device *dev)
/* -------------------------------------------------------------------------- */
/**
- * c67x00_write_mem_le16 - write into c67x00 memory
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
* Only data is little endian, addr has cpu endianess.
*/
-void c67x00_ll_hpi_write_mem_le16(struct c67x00_device *dev, u16 addr, int len,
- char *data)
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
{
+ u8 *buf = data;
+
/* Sanity check */
if (addr + len > 0xffff) {
dev_err(&dev->pdev->dev,
@@ -451,55 +439,52 @@ void c67x00_ll_hpi_write_mem_le16(struct c67x00_device *dev, u16 addr, int len,
/* unaligned access */
u16 tmp;
tmp = hpi_read_word(dev, addr - 1);
- tmp = (tmp & 0x00ff) | (*data++ << 8);
+ tmp = (tmp & 0x00ff) | (*buf++ << 8);
hpi_write_word(dev, addr - 1, tmp);
addr++;
len--;
}
- hpi_write_words_le16(dev, addr, (u16 *) data, len / 2);
- data += len & ~0x01;
+ hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
if (len) {
u16 tmp;
tmp = hpi_read_word(dev, addr);
- tmp = (tmp & 0xff00) | (*data++);
+ tmp = (tmp & 0xff00) | *buf;
hpi_write_word(dev, addr, tmp);
- addr++;
- len--;
}
-
}
/**
- * c67x00_ll_hpi_read_mem_le16 - read from c67x00 memory
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
* Only data is little endian, addr has cpu endianess.
*/
-void c67x00_ll_hpi_read_mem_le16(struct c67x00_device *dev, u16 addr, int len,
- char *data)
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
{
+ u8 *buf = data;
+
if (addr & 0x01) {
/* unaligned access */
u16 tmp;
tmp = hpi_read_word(dev, addr - 1);
- *data++ = (tmp >> 8) & 0x00ff;
+ *buf++ = (tmp >> 8) & 0x00ff;
addr++;
len--;
}
- hpi_read_words_le16(dev, addr, (u16 *) data, len / 2);
- data += len & ~0x01;
+ hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
if (len) {
u16 tmp;
tmp = hpi_read_word(dev, addr);
- *data++ = tmp & 0x00ff;
- addr++;
- len--;
+ *buf = tmp & 0x00ff;
}
}
@@ -507,8 +492,8 @@ void c67x00_ll_hpi_read_mem_le16(struct c67x00_device *dev, u16 addr, int len,
void c67x00_ll_init(struct c67x00_device *dev)
{
- mutex_init(&dev->lcp.mutex);
- init_completion(&dev->lcp.msg_received);
+ mutex_init(&dev->hpi.lcp.mutex);
+ init_completion(&dev->hpi.lcp.msg_received);
}
void c67x00_ll_release(struct c67x00_device *dev)
diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c
index 35d7318..3140d89 100644
--- a/drivers/usb/c67x00/c67x00-sched.c
+++ b/drivers/usb/c67x00/c67x00-sched.c
@@ -1,7 +1,7 @@
/*
* c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -71,7 +71,7 @@ struct c67x00_td {
/* SW part */
struct list_head td_list;
u16 td_addr;
- char *data;
+ void *data;
struct urb *urb;
unsigned long privdata;
@@ -113,7 +113,7 @@ struct c67x00_urb_priv {
#define TD_STATUSMASK_STALL 0x80
#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
- TD_STATUSMASK_STALL )
+ TD_STATUSMASK_STALL)
#define TD_RETRYCNT_OFFSET 0x08
#define TD_RETRYCNTMASK_ACT_FLG 0x10
@@ -134,8 +134,8 @@ struct c67x00_urb_priv {
#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL)
#define td_sequence_ok(td) (!td->status || \
- ( !(td->status & TD_STATUSMASK_SEQ) == \
- !(td->ctrl_reg & SEQ_SEL) ))
+ (!(td->status & TD_STATUSMASK_SEQ) == \
+ !(td->ctrl_reg & SEQ_SEL)))
#define td_acked(td) (!td->status || \
(td->status & TD_STATUSMASK_ACK))
@@ -144,21 +144,14 @@ struct c67x00_urb_priv {
/* -------------------------------------------------------------------------- */
#ifdef DEBUG
-/*
- * These patterns are written into the c67x00 internal memory and the
- * urb->transfer_buffer respectively in order to simplify debugging.
- */
-#define NON_RECEIVED_PATTERN 0xac
-#define UNREAD_PATTERN 0x0c
-/* #define DEBUG_PATTERN */
/**
* dbg_td - Dump the contents of the TD
*/
static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
{
- struct device *dev = c67x00_hcd_dev(c67x00);
- int i, len = td_length(td);
+ struct device *dev = c67x00_dev(c67x00);
+
dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
dev_dbg(dev, "urb: 0x%p\n", td->urb);
dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe));
@@ -173,12 +166,8 @@ static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
dev_dbg(dev, "residue: 0x%02x\n", td->residue);
dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
dev_dbg(dev, "data:");
- for (i = 0; i < len; i++) {
- if (!(i % 8))
- printk("\n ");
- printk(" 0x%02x", td->data[i]);
- }
- printk("\n");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
+ td->data, td_length(td), 1);
}
#else /* DEBUG */
@@ -190,8 +179,6 @@ dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { }
/* -------------------------------------------------------------------------- */
/* Helper functions */
-/* -------------------------------------------------------------------------- */
-
static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
{
u16 temp_val;
@@ -254,12 +241,10 @@ static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
* * only clear when needed
* * keep a list of tds with earch urbp
*/
- list_for_each_entry(td, &c67x00->td_list, td_list) {
+ list_for_each_entry(td, &c67x00->td_list, td_list)
if (urb == td->urb)
td->urb = NULL;
- }
- /* Discard the urb private data */
urbp = urb->hcpriv;
urb->hcpriv = NULL;
list_del(&urbp->hep_node);
@@ -271,10 +256,8 @@ static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
static struct c67x00_ep_data *
c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
{
- //struct usb_device *udev = urb->dev;
struct usb_host_endpoint *hep = urb->ep;
struct c67x00_ep_data *ep_data;
- struct c67x00_ep_data *prev;
int type;
c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
@@ -306,11 +289,13 @@ c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
ep_data->next_frame = frame_add(c67x00->current_frame, 1);
/* Add the endpoint data to one of the pipe lists; must be added
- * in order of endpoint address */
+ in order of endpoint address */
type = usb_pipetype(urb->pipe);
if (list_empty(&ep_data->node)) {
list_add(&ep_data->node, &c67x00->list[type]);
} else {
+ struct c67x00_ep_data *prev;
+
list_for_each_entry(prev, &c67x00->list[type], node) {
if (prev->hep->desc.bEndpointAddress >
hep->desc.bEndpointAddress) {
@@ -326,6 +311,7 @@ c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
static int c67x00_ep_data_free(struct usb_host_endpoint *hep)
{
struct c67x00_ep_data *ep_data = hep->hcpriv;
+
if (!ep_data)
return 0;
@@ -348,11 +334,11 @@ void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
unsigned long flags;
if (!list_empty(&ep->urb_list))
- dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
+ dev_warn(c67x00_dev(c67x00), "error: urb list not empty\n");
spin_lock_irqsave(&c67x00->lock, flags);
- /* Loop waiting for all transfers in the endpoint queue to complete */
+ /* loop waiting for all transfers in the endpoint queue to complete */
while (c67x00_ep_data_free(ep)) {
/* Drop the lock so we can sleep waiting for the hardware */
spin_unlock_irqrestore(&c67x00->lock, flags);
@@ -384,7 +370,7 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,
{
int ret;
unsigned long flags;
- struct c67x00_urb_priv *urbp = NULL;
+ struct c67x00_urb_priv *urbp;
struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
int port = get_root_port(urb->dev)-1;
@@ -406,11 +392,13 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,
ret = -ENOMEM;
goto err_urbp;
}
+
INIT_LIST_HEAD(&urbp->hep_node);
urbp->urb = urb;
urbp->port = port;
urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
+
if (!urbp->ep_data) {
ret = -ENOMEM;
goto err_epdata;
@@ -443,7 +431,8 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,
struct urb *last_urb;
last_urb = list_entry(urbp->ep_data->queue.prev,
- struct c67x00_urb_priv, hep_node)->urb;
+ struct c67x00_urb_priv,
+ hep_node)->urb;
urb->start_frame =
frame_add(last_urb->start_frame,
last_urb->number_of_packets *
@@ -456,22 +445,22 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,
/* Add the URB to the endpoint queue */
list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
- /* If this is the only urb, kick start the controller */
+ /* If this is the only URB, kick start the controller */
if (!c67x00->urb_count++)
c67x00_ll_hpi_enable_sofeop(c67x00->sie);
c67x00_sched_kick(c67x00);
-
spin_unlock_irqrestore(&c67x00->lock, flags);
+
return 0;
- /* Something went wrong; unwind the allocations */
- err_epdata:
+err_epdata:
kfree(urbp);
- err_urbp:
+err_urbp:
usb_hcd_unlink_urb_from_ep(hcd, urb);
- err_not_linked:
+err_not_linked:
spin_unlock_irqrestore(&c67x00->lock, flags);
+
return ret;
}
@@ -487,6 +476,12 @@ int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ usb_hcd_giveback_urb(hcd, urb, status);
+
+ return 0;
done:
spin_unlock_irqrestore(&c67x00->lock, flags);
@@ -502,6 +497,7 @@ static inline void
c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
{
struct c67x00_urb_priv *urbp;
+
if (!urb)
return;
@@ -515,8 +511,8 @@ c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
/* -------------------------------------------------------------------------- */
-static int claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
- int len, int periodic)
+static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
+ int len, int periodic)
{
struct c67x00_urb_priv *urbp = urb->hcpriv;
int bit_time;
@@ -583,10 +579,9 @@ static int claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
/**
* td_addr and buf_addr must be word aligned
*/
-static int create_td(struct c67x00_hcd *c67x00,
- struct urb *urb,
- char *data,
- int len, int pid, int toggle, unsigned long privdata)
+static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
+ void *data, int len, int pid, int toggle,
+ unsigned long privdata)
{
struct c67x00_td *td;
struct c67x00_urb_priv *urbp = urb->hcpriv;
@@ -594,8 +589,8 @@ static int create_td(struct c67x00_hcd *c67x00,
__u8 cmd = 0;
int tt = 0;
- if (claim_frame_bw(c67x00, urb, len,
- usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)))
+ if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
+ || usb_pipeint(urb->pipe)))
return -EMSGSIZE; /* Not really an error, but expected */
td = kzalloc(sizeof(*td), GFP_ATOMIC);
@@ -658,7 +653,7 @@ static int create_td(struct c67x00_hcd *c67x00,
return 0;
}
-static inline void release_td(struct c67x00_td *td)
+static inline void c67x00_release_td(struct c67x00_td *td)
{
list_del_init(&td->td_list);
kfree(td);
@@ -666,7 +661,7 @@ static inline void release_td(struct c67x00_td *td)
/* -------------------------------------------------------------------------- */
-static int add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
{
int remaining;
int toggle;
@@ -695,8 +690,8 @@ static int add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
remaining;
- ret = create_td(c67x00, urb, td_buf, len, pid, toggle,
- DATA_STAGE);
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
+ DATA_STAGE);
if (ret)
goto out; /* td wasn't created */
toggle ^= 1;
@@ -704,15 +699,14 @@ static int add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
if (usb_pipecontrol(urb->pipe))
break;
}
- out:
+out:
return ret;
}
/**
- *
* return 0 in case more bandwidth is available, else errorcode
*/
-static int add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
{
int ret;
int pid;
@@ -720,9 +714,8 @@ static int add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
switch (urb->interval) {
default:
case SETUP_STAGE:
- ret = create_td(c67x00, urb,
- urb->setup_packet,
- 8, USB_PID_SETUP, 0, SETUP_STAGE);
+ ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
+ 8, USB_PID_SETUP, 0, SETUP_STAGE);
if (ret)
return ret;
urb->interval = SETUP_STAGE;
@@ -731,14 +724,15 @@ static int add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
break;
case DATA_STAGE:
if (urb->transfer_buffer_length) {
- ret = add_data_urb(c67x00, urb);
+ ret = c67x00_add_data_urb(c67x00, urb);
if (ret)
return ret;
break;
} /* else fallthrough */
case STATUS_STAGE:
pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
- ret = create_td(c67x00, urb, NULL, 0, pid, 1, STATUS_STAGE);
+ ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
+ STATUS_STAGE);
if (ret)
return ret;
break;
@@ -750,19 +744,19 @@ static int add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
/*
* return 0 in case more bandwidth is available, else errorcode
*/
-static int add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
{
struct c67x00_urb_priv *urbp = urb->hcpriv;
if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
urbp->ep_data->next_frame =
frame_add(urbp->ep_data->next_frame, urb->interval);
- return add_data_urb(c67x00, urb);
+ return c67x00_add_data_urb(c67x00, urb);
}
return 0;
}
-static int add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
{
struct c67x00_urb_priv *urbp = urb->hcpriv;
@@ -777,7 +771,8 @@ static int add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
len = urb->iso_frame_desc[urbp->cnt].length;
pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
- ret = create_td(c67x00, urb, td_buf, len, pid, 0, urbp->cnt);
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
+ urbp->cnt);
if (ret) {
printk(KERN_DEBUG "create failed: %d\n", ret);
urb->iso_frame_desc[urbp->cnt].actual_length = 0;
@@ -806,7 +801,8 @@ static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
if (!list_empty(&ep_data->queue)) {
/* and add the first urb */
/* isochronous transfer rely on this */
- urb = list_entry(ep_data->queue.next, struct c67x00_urb_priv,
+ urb = list_entry(ep_data->queue.next,
+ struct c67x00_urb_priv,
hep_node)->urb;
add(c67x00, urb);
}
@@ -819,11 +815,11 @@ static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
/* Check if we can proceed */
if (!list_empty(&c67x00->td_list)) {
- dev_warn(c67x00_hcd_dev(c67x00),
+ dev_warn(c67x00_dev(c67x00),
"TD list not empty! This should not happen!\n");
list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
dbg_td(c67x00, td, "Unprocessed td");
- release_td(td);
+ c67x00_release_td(td);
}
}
@@ -835,10 +831,10 @@ static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
c67x00->next_buf_addr = c67x00->buf_base_addr;
/* Fill the list */
- c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, add_iso_urb);
- c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, add_int_urb);
- c67x00_fill_from_list(c67x00, PIPE_CONTROL, add_ctrl_urb);
- c67x00_fill_from_list(c67x00, PIPE_BULK, add_data_urb);
+ c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
+ c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
+ c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
+ c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
}
/* -------------------------------------------------------------------------- */
@@ -849,19 +845,15 @@ static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
static inline void
c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
{
- c67x00_ll_hpi_read_mem_le16(c67x00->sie->dev, td->td_addr, CY_TD_SIZE,
- (char *)td);
+ c67x00_ll_read_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
if (usb_pipein(td->pipe) && td_actual_bytes(td))
- c67x00_ll_hpi_read_mem_le16(c67x00->sie->dev,
- td_ly_base_addr(td),
- td_actual_bytes(td), td->data);
+ c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, td_actual_bytes(td));
}
-/* -------------------------------------------------------------------------- */
-
-static int
-c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
{
if (td->status & TD_STATUSMASK_ERR) {
dbg_td(c67x00, td, "ERROR_FLAG");
@@ -910,8 +902,8 @@ static inline int c67x00_end_of_data(struct c67x00_td *td)
/* Remove all td's from the list which come
* after last_td and are meant for the same pipe.
* This is used when a short packet has occured */
-static inline void
-c67x00_clear_pipe(struct c67x00_hcd *c67x00, struct c67x00_td *last_td)
+static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
+ struct c67x00_td *last_td)
{
struct c67x00_td *td, *tmp;
td = last_td;
@@ -919,7 +911,7 @@ c67x00_clear_pipe(struct c67x00_hcd *c67x00, struct c67x00_td *last_td)
while (td->td_list.next != &c67x00->td_list) {
td = list_entry(td->td_list.next, struct c67x00_td, td_list);
if (td->pipe == last_td->pipe) {
- release_td(td);
+ c67x00_release_td(td);
td = tmp;
}
tmp = td;
@@ -929,7 +921,7 @@ c67x00_clear_pipe(struct c67x00_hcd *c67x00, struct c67x00_td *last_td)
/* -------------------------------------------------------------------------- */
static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
- struct c67x00_td *td)
+ struct c67x00_td *td)
{
struct urb *urb = td->urb;
@@ -949,18 +941,21 @@ static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
/* Don't count setup_packet with normal data: */
urb->actual_length = 0;
break;
+
case DATA_STAGE:
if (c67x00_end_of_data(td)) {
urb->interval = STATUS_STAGE;
c67x00_clear_pipe(c67x00, td);
}
break;
+
case STATUS_STAGE:
urb->interval = 0;
c67x00_giveback_urb(c67x00, urb, 0);
break;
}
break;
+
case PIPE_INTERRUPT:
case PIPE_BULK:
if (unlikely(c67x00_end_of_data(td))) {
@@ -1023,7 +1018,8 @@ static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
* inactive state. This state matches successful transfers so
* we must make sure not to service them. */
if (td->status & TD_ERROR_MASK) {
- c67x00_giveback_urb(c67x00, urb, c67x00_td_to_error(c67x00, td));
+ c67x00_giveback_urb(c67x00, urb,
+ c67x00_td_to_error(c67x00, td));
goto cont;
}
@@ -1045,7 +1041,7 @@ static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
clear_endpoint = 0;
c67x00_handle_successful_td(c67x00, td);
- cont:
+ cont:
if (clear_endpoint)
c67x00_clear_pipe(c67x00, td);
if (ack_ok)
@@ -1054,7 +1050,7 @@ static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
!(td->ctrl_reg & SEQ_SEL));
/* next in list could have been removed, due to clear_pipe! */
tmp = list_entry(td->td_list.next, typeof(*td), td_list);
- release_td(td);
+ c67x00_release_td(td);
}
}
@@ -1076,12 +1072,11 @@ static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
int len = td_length(td);
if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
- c67x00_ll_hpi_write_mem_le16(c67x00->sie->dev,
- td_ly_base_addr(td),
- len, td->data);
+ c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, len);
- c67x00_ll_hpi_write_mem_le16(c67x00->sie->dev, td->td_addr,
- CY_TD_SIZE, (char *)td);
+ c67x00_ll_write_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
}
static void c67x00_send_frame(struct c67x00_hcd *c67x00)
@@ -1089,7 +1084,7 @@ static void c67x00_send_frame(struct c67x00_hcd *c67x00)
struct c67x00_td *td;
if (list_empty(&c67x00->td_list))
- dev_warn(c67x00_hcd_dev(c67x00),
+ dev_warn(c67x00_dev(c67x00),
"%s: td list should not be empty here!\n",
__FUNCTION__);
@@ -1136,15 +1131,11 @@ static void c67x00_do_work(struct c67x00_hcd *c67x00)
}
c67x00_fill_frame(c67x00);
- if (list_empty(&c67x00->td_list))
- /* URBs aren't for this frame */
- goto out;
- else {
+ if (!list_empty(&c67x00->td_list))
/* TD's have been added to the frame */
c67x00_send_frame(c67x00);
- goto out;
- }
- out:
+
+out:
spin_unlock(&c67x00->lock);
}
@@ -1160,24 +1151,23 @@ static void c67x00_sched_done(unsigned long __c67x00)
{
struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
struct c67x00_urb_priv *urbp, *tmp;
- struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
struct urb *urb;
- int status;
spin_lock(&c67x00->lock);
/* Loop over the done list and give back all the urbs */
list_for_each_entry_safe(urbp, tmp, &c67x00->done_list, hep_node) {
urb = urbp->urb;
- status = urbp->status;
-
c67x00_release_urb(c67x00, urb);
-
- usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- spin_unlock(&c67x00->lock);
- usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&c67x00->lock);
+ if (!usb_hcd_check_unlink_urb(c67x00_hcd_to_hcd(c67x00),
+ urb, urbp->status)) {
+ usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00),
+ urb);
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb,
+ urbp->status);
+ spin_lock(&c67x00->lock);
+ }
}
spin_unlock(&c67x00->lock);
}
diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h
index 00a38df..35f81d7 100644
--- a/drivers/usb/c67x00/c67x00.h
+++ b/drivers/usb/c67x00/c67x00.h
@@ -1,7 +1,7 @@
/*
* c67x00.h: Cypress C67X00 USB register and field definitions
*
- * Copyright (C) 2006-2007 Barco N.V.
+ * Copyright (C) 2006-2008 Barco N.V.
* Derived from the Cypress cy7c67200/300 ezusb linux driver and
* based on multiple host controller drivers inside the linux kernel.
*
@@ -24,8 +24,7 @@
#ifndef _USB_C67X00_H
#define _USB_C67X00_H
-#include <linux/interrupt.h>
-#include <linux/list.h>
+#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/mutex.h>
@@ -34,9 +33,6 @@
* Cypress C67x00 register definitions
*/
-/* Processor control registers */
-/* =========================== */
-
/* Hardware Revision Register */
#define HW_REV_REG 0xC004
@@ -44,12 +40,28 @@
/* ===================== */
/* USB Control Register */
-#define USB_CTL_REG(x) ( (x) ? 0xC0AA : 0xC08A )
+#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A)
-#define LOW_SPEED_PORT(x) ( (x) ? 0x0800 : 0x0400 )
+#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400)
#define HOST_MODE 0x0200
-#define PORT_RES_EN(x) ( (x) ? 0x0100 : 0x0080 )
-#define SOF_EOP_EN(x) ( (x) ? 0x0002 : 0x0001 )
+#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG 0x0001
+#define EP1_IRQ_FLG 0x0002
+#define EP2_IRQ_FLG 0x0004
+#define EP3_IRQ_FLG 0x0008
+#define EP4_IRQ_FLG 0x0010
+#define EP5_IRQ_FLG 0x0020
+#define EP6_IRQ_FLG 0x0040
+#define EP7_IRQ_FLG 0x0080
+#define RESET_IRQ_FLG 0x0100
+#define SOF_EOP_IRQ_FLG 0x0200
+#define ID_IRQ_FLG 0x4000
+#define VBUS_IRQ_FLG 0x8000
/* USB Host only registers */
/* ======================= */
@@ -63,50 +75,119 @@
#define ARM_EN 0x0001 /* Arm operation */
/* Host n Interrupt Enable Register */
-#define HOST_IRQ_EN_REG(x) ( (x) ? 0xC0AC : 0xC08C)
+#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */
+#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */
+#define ID_IRQ_EN 0x4000 /* ID interrupt enable */
+#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */
#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */
-/* Host n status register */
-#define HOST_STAT_REG(x) ( (x) ? 0xC0B0 : 0xC090 )
-
+/* USB status register */
#define HOST_STAT_MASK 0x02FD
-#define SOF_EOP_IRQ_FLG 0x0200
-#define PORT_CONNECT_CHANGE(x) ( (x) ? 0x0020 : 0x0010 )
-#define PORT_SE0_STATUS(x) ( (x) ? 0x0008 : 0x0004 )
+#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004)
/* Host Frame Register */
-#define HOST_FRAME_REG(x) ( (x) ? 0xC0B6 : 0xC096 )
+#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096)
#define HOST_FRAME_MASK 0x07FF
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \
+ ? (0x0280 + (ep << 4)) \
+ : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \
+ ? (0x0286 + (ep << 4)) \
+ : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E))
+
/* HPI registers */
/* ============= */
/* HPI Status register */
-#define SOFEOP_FLG(x) (1 << ( (x) ? 12 : 10 ))
-#define SIEMSG_FLAG(x) (1 << (4 + (x)))
+#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x) (1 << (4 + (x)))
+#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x) (1 << (2 + (x)))
+#define RESUME_FLG(x) (1 << (6 + (x)))
#define MBX_OUT_FLG 0x0001 /* Message out available */
+#define MBX_IN_FLG 0x0100
+#define ID_FLG 0x4000
+#define VBUS_FLG 0x8000
/* Interrupt routing register */
#define HPI_IRQ_ROUTING_REG 0x0142
-#define SOFEOP_TO_HPI_EN(x) ( (x) ? 0x2000 : 0x0800 )
-#define SOFEOP_TO_CPU_EN(x) ( (x) ? 0x1000 : 0x0400 )
+#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE 0x4000
+#define VBUS_TO_HPI_ENABLE 0x8000
/* SIE msg registers */
-#define SIEMSG_REG(x) ( (x) ? 0x0148 : 0x0144 )
+#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144)
#define HUSB_TDListDone 0x1000
+#define SUSB_EP0_MSG 0x0001
+#define SUSB_EP1_MSG 0x0002
+#define SUSB_EP2_MSG 0x0004
+#define SUSB_EP3_MSG 0x0008
+#define SUSB_EP4_MSG 0x0010
+#define SUSB_EP5_MSG 0x0020
+#define SUSB_EP6_MSG 0x0040
+#define SUSB_EP7_MSG 0x0080
+#define SUSB_RST_MSG 0x0100
+#define SUSB_SOF_MSG 0x0200
+#define SUSB_CFG_MSG 0x0400
+#define SUSB_SUS_MSG 0x0800
+#define SUSB_ID_MSG 0x4000
+#define SUSB_VBUS_MSG 0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x) ((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */
#define SIE_TD_SIZE 0x200 /* size of the td list */
#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */
-#define SIE_TD_OFFSET(host) ( (host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0 )
+#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE 0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE 8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
+ ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE 0x1800
+#define CY_UDC_REQ_BUFFER_BASE 0x2000
+#define CY_UDC_REQ_BUFFER_SIZE 0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
+ ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
/* ---------------------------------------------------------------------
* Driver data structures
*/
@@ -114,44 +195,19 @@
struct c67x00_device;
/**
- * struct c67x00_lcp
- */
-struct c67x00_lcp {
- /* Internal use only */
- struct mutex mutex;
- struct completion msg_received;
- u16 last_msg;
-};
-
-/**
- * struct c67x00_lcp_data
- */
-#define COMM_REGS 14
-struct c67x00_lcp_int_data {
- u16 regs[COMM_REGS];
-};
-
-/**
- * struct c67x00_sie - Common data associated with an SIE
+ * struct c67x00_sie - Common data associated with a SIE
* @lock: lock to protect this struct
* @private_data: subdriver dependent data
- * @pdev: platform device associated with this SIE, created in c67x00-drv.c
- * @irq: subdriver depenent irq handler, set NULL when not used
- * @msg_received: called when an SIEmsg has been received
+ * @irq: subdriver dependent irq handler, set NULL when not used
* @dev: link to common driver structure
* @sie_num: SIE number on chip, starting from 0
* @mode: SIE mode (host/peripheral/otg/not used)
- *
- * Each SIE has a separate platform_device associated with it, because the
- * hcd needs such a device for itself (TODO: use a struct device instead
- * of a new platform device).
*/
struct c67x00_sie {
/* Entries to be used by the subdrivers */
spinlock_t lock; /* protect this structure */
void *private_data;
- struct platform_device *pdev;
- void (*irq) (struct c67x00_sie * sie, u16 msg);
+ void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
/* Read only: */
struct c67x00_device *dev;
@@ -159,80 +215,80 @@ struct c67x00_sie {
int mode;
};
-#define sie_dev(s) (&(s)->pdev->dev)
+#define sie_dev(s) (&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+ /* Internal use only */
+ struct mutex mutex;
+ struct completion msg_received;
+ u16 last_msg;
+};
+/*
+ * struct c67x00_hpi
+ */
struct c67x00_hpi {
void __iomem *base;
int regstep;
+ spinlock_t lock;
+ struct c67x00_lcp lcp;
};
#define C67X00_SIES 2
#define C67X00_PORTS 2
/**
- * struct c67x00_device - Common data structure for a c67x00 instance
+ * struct c67x00_device - Common data associated with a c67x00 instance
* @hpi: hpi addresses
* @sie: array of sie's on this chip
+ * @pdev: platform device of instance
* @pdata: configuration provided by the platform
- * @hw_lock: hardware lock
- * @int_status: interrupt status register, only valid in_interrupt()
- * @lcp: link control protocol dependent data
*/
struct c67x00_device {
struct c67x00_hpi hpi;
struct c67x00_sie sie[C67X00_SIES];
struct platform_device *pdev;
struct c67x00_platform_data *pdata;
- spinlock_t hw_lock;
-
- u16 int_status;
- struct c67x00_lcp lcp;
};
/* ---------------------------------------------------------------------
- * HCD setup and teardown hooks; defined here because these are the
- * only routines which are called directly by the core driver.
- */
-extern int c67x00_hcd_probe(struct c67x00_sie *sie);
-extern void c67x00_hcd_remove(struct c67x00_sie *sie);
-
-/* ---------------------------------------------------------------------
* Low level interface functions
*/
-/* Host Port Interface (hpi) functions */
+/* Host Port Interface (HPI) functions */
u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
/* General functions */
-u16 c67x00_ll_get_siemsg(struct c67x00_device *dev, int sie);
-void c67x00_ll_set_siemsg(struct c67x00_device *dev, int sie, u16 val);
+u16 c67x00_ll_get_siemsg(struct c67x00_sie *sie);
+void c67x00_ll_set_siemsg(struct c67x00_sie *sie, u16 val);
u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val);
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+ u16 val);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
/* Host specific functions */
void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
-void c67x00_ll_husb_clear_status(struct c67x00_sie *sie, u16 bits);
-u16 c67x00_ll_husb_get_status(struct c67x00_sie *sie);
u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
-/* Slave specific functions */
-void c67x00_ll_susb_init(struct c67x00_sie *sie);
-
-/* Read and write to memory */
-void c67x00_ll_hpi_write_mem_le16(struct c67x00_device *dev, u16 addr,
- int len, char *data);
-void c67x00_ll_hpi_read_mem_le16(struct c67x00_device *dev, u16 addr,
- int len, char *data);
-
/* Called by c67x00_irq to handle lcp interrupts */
-void c67x00_ll_irq(struct c67x00_device *dev);
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
/* Setup and teardown */
void c67x00_ll_init(struct c67x00_device *dev);
diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h
index 80b1a87..3a4b9ce 100644
--- a/include/linux/usb/c67x00.h
+++ b/include/linux/usb/c67x00.h
@@ -25,17 +25,20 @@
/* SIE configuration */
#define C67X00_SIE_UNUSED 0
#define C67X00_SIE_HOST 1
-#define C67X00_SIE_PERIPHERAL 2
+#define C67X00_SIE_PERIPHERAL_A 2 /* peripheral on A port */
+#define C67X00_SIE_PERIPHERAL_B 3 /* peripheral on B port */
#define c67x00_sie_config(config, n) (((config)>>(4*(n)))&0x3)
-#define C67X00_SIE1_UNUSED (C67X00_SIE_UNUSED << 0)
-#define C67X00_SIE1_HOST (C67X00_SIE_HOST << 0)
-#define C67X00_SIE1_PERIPHERAL (C67X00_SIE_PERIPHERAL << 0)
+#define C67X00_SIE1_UNUSED (C67X00_SIE_UNUSED << 0)
+#define C67X00_SIE1_HOST (C67X00_SIE_HOST << 0)
+#define C67X00_SIE1_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 0)
+#define C67X00_SIE1_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 0)
-#define C67X00_SIE2_UNUSED (C67X00_SIE_UNUSED << 4)
-#define C67X00_SIE2_HOST (C67X00_SIE_HOST << 4)
-#define C67X00_SIE2_PERIPHERAL (C67X00_SIE_PERIPHERAL << 4)
+#define C67X00_SIE2_UNUSED (C67X00_SIE_UNUSED << 4)
+#define C67X00_SIE2_HOST (C67X00_SIE_HOST << 4)
+#define C67X00_SIE2_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 4)
+#define C67X00_SIE2_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 4)
struct c67x00_platform_data {
int sie_config; /* SIEs config (C67X00_SIEx_*) */
--
Bye, Peter Korsgaard
More information about the Linuxppc-dev
mailing list