diff options
| author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-07-20 16:26:39 +0000 | 
|---|---|---|
| committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-07-20 16:26:39 +0000 | 
| commit | 921f798f6a97b60e1b3bf3b12d0075cc62f979a9 (patch) | |
| tree | 2e7f38b6e0beb5bdf8f6edc74b2595ed3fcb21a4 | |
| parent | 305cc5a4528347d1f325ebdec6aba0d1a7687503 (diff) | |
Fixup the hcd driver, add a start/stop/reset/sw_reset functions, should allow it to basically run
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@8078 3c298f89-4303-0410-b956-a3cf2f4a3e73
| -rw-r--r-- | target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c | 179 | 
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 c8be7393f..bd6f7a0aa 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;  }  | 
