summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c179
1 files changed, 137 insertions, 42 deletions
diff --git a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
index c8be7393f7..bd6f7a0aa1 100644
--- a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
+++ b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
@@ -63,8 +63,17 @@ MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
#define ADMHCD_STATE_SUS 0x00000003 /* bus state suspended */
#define ADMHCD_DMA_EN 0x00000004 /* enable dma engine */
-#define ADMHCD_NPS 0x00000020 /* No Power Switch */
+#define ADMHCD_RST_ST 0x00 /* USB reset state */
+#define ADMHCD_RSM_ST 0x01 /* USB resume state */
+#define ADMHCD_OPR_ST 0x10 /* USB operational state */
+#define ADMHCD_SUS_ST 0x11 /* USB suspend state */
+
+#define ADMHCD_NPS 0x00000200 /* No Power Switch */
+#define ADMHCD_PSM 0x00000100 /* Power switch mode */
+#define ADMHCD_OPCM 0x00000400 /* Over current protect mode */
+#define ADMHCD_NOCP 0x00000800 /* No over current protect mode */
#define ADMHCD_LPSC 0x04000000 /* Local power switch change */
+#define ADMHCD_LPS 0x01000000 /* Local power switch/global power switch */
#define ADMHCD_CCS 0x00000001 /* current connect status */
#define ADMHCD_PES 0x00000002 /* port enable status */
@@ -150,7 +159,6 @@ static int admhcd_td_err[16] = {
struct admhcd {
spinlock_t lock;
- void __iomem *addr_reg;
void __iomem *data_reg;
/* Root hub registers */
u32 rhdesca;
@@ -687,18 +695,135 @@ err:
return retval;
}
+static int admhcd_start(struct usb_hcd *hcd)
+{
+ struct admhcd *ahcd = hcd_to_admhcd(hcd);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ahcd->lock, flags);
+
+ /* Initialise the HCD registers */
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
+ mdelay(10);
+
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
+
+ while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET)
+ mdelay(1);
+
+ /* Enable USB host mode */
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
+
+ /* Set host specific settings */
+ admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
+ admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
+ admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
+
+ /* Set interrupts */
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE,
+ ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS,
+ ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
+
+ admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
+ admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
+
+
+ hcd->state = HC_STATE_RUNNING;
+
+ spin_unlock_irqrestore(&ahcd->lock, flags);
+ return 0;
+}
+
+static int admhcd_sw_reset(struct admhcd *ahcd)
+{
+ int retries = 15;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ahcd->lock, flags);
+
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
+ mdelay(10);
+
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
+
+ while (--retries) {
+ mdelay(1);
+ if (!(admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET))
+ break;
+ }
+ if (!retries) {
+ printk(KERN_WARNING "%s Software reset timeout\n", hcd_name);
+ ret = -ETIME;
+ }
+ spin_unlock_irqrestore(&ahcd->lock, flags);
+ return ret;
+}
+
+static int admhcd_reset(struct usb_hcd *hcd)
+{
+ struct admhcd *ahcd = hcd_to_admhcd(hcd);
+ u32 val = 0;
+ int ret, timeout = 15; /* ms */
+ unsigned long t;
+
+ ret = admhcd_sw_reset(ahcd);
+ if (ret)
+ return ret;
+
+ t = jiffies + msecs_to_jiffies(timeout);
+ while (time_before_eq(jiffies, t)) {
+ msleep(4);
+ spin_lock_irq(&ahcd->lock);
+ val = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL) & ADMHCD_OPR_ST;
+ spin_unlock_irq(&ahcd->lock);
+ if (val)
+ break;
+ }
+ if (!val) {
+ printk(KERN_WARNING "Device not ready after %dms\n", timeout);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static void admhcd_stop(struct usb_hcd *hcd)
+{
+ struct admhcd *ahcd = hcd_to_admhcd(hcd);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&ahcd->lock, flags);
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
+
+ /* Set global control of power for ports */
+ val = admhcd_reg_get(ahcd, ADMHCD_REG_RHDESCR);
+ val &= (~ADMHCD_PSM | ADMHCD_LPS);
+ admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, val);
+
+ spin_unlock_irqrestore(&ahcd->lock, flags);
+
+ /* Ask for software reset */
+ admhcd_sw_reset(ahcd);
+}
+
+
static struct hc_driver adm5120_hc_driver = {
.description = hcd_name,
.product_desc = "ADM5120 HCD",
.hcd_priv_size = sizeof(struct admhcd),
.irq = adm5120hcd_irq,
- .flags = HCD_USB11,
+ .flags = HCD_MEMORY|HCD_USB11,
.urb_enqueue = admhcd_urb_enqueue,
.urb_dequeue = admhcd_urb_dequeue,
.endpoint_disable = admhcd_endpoint_disable,
.get_frame_number = admhcd_get_frame_number,
.hub_status_data = admhcd_hub_status_data,
.hub_control = admhcd_hub_control,
+ .start = admhcd_start,
+ .stop = admhcd_stop,
+ .reset = admhcd_reset,
};
#define resource_len(r) (((r)->end - (r)->start) + 1)
@@ -707,13 +832,12 @@ static int __init adm5120hcd_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct admhcd *ahcd;
- struct resource *addr, *data;
- void __iomem *addr_reg;
+ struct resource *data;
void __iomem *data_reg;
int err = 0, irq;
- if (pdev->num_resources < 3) {
+ if (pdev->num_resources < 2) {
err = -ENODEV;
goto out;
}
@@ -725,23 +849,12 @@ static int __init adm5120hcd_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!addr || !data || irq < 0) {
+ if (!data || irq < 0) {
err = -ENODEV;
goto out;
}
- if (!request_mem_region(addr->start, 2, hcd_name)) {
- err = -EBUSY;
- goto out;
- }
-
- addr_reg = ioremap(addr->start, resource_len(addr));
- if (addr_reg == NULL) {
- err = -ENOMEM;
- goto out_mem;
- }
if (!request_mem_region(data->start, 2, hcd_name)) {
err = -EBUSY;
goto out_unmap;
@@ -757,37 +870,19 @@ static int __init adm5120hcd_probe(struct platform_device *pdev)
if (!hcd)
goto out_mem;
- hcd->rsrc_start = addr->start;
+ hcd->rsrc_start = data->start;
+ hcd->rsrc_len = resource_len(data);
+ hcd->regs = (u32)data_reg;
ahcd = hcd_to_admhcd(hcd);
spin_lock_init(&ahcd->lock);
INIT_LIST_HEAD(&ahcd->async);
ahcd->data_reg = data_reg;
- ahcd->addr_reg = addr_reg;
+ ahcd->base = (u32)data_reg;
hcd->product_desc = "ADM5120 HCD";
- /* Initialise the HCD registers */
- admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
- mdelay(10);
-
- admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
-
- while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET)
- mdelay(1);
-
- admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
- admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
- admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
- admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
- admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE,
- ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
- admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS,
- ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
- admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
- admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
-
err = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (err)
goto out_dev;
@@ -797,9 +892,9 @@ static int __init adm5120hcd_probe(struct platform_device *pdev)
out_dev:
usb_put_hcd(hcd);
out_unmap:
- iounmap(addr_reg);
+ iounmap(data_reg);
out_mem:
- release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start);
+ release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start +1);
out:
return err;
}