ehci-w90x900.c 4.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*
 * linux/driver/usb/host/ehci-w90x900.c
 *
 * Copyright (c) 2008 Nuvoton technology corporation.
 *
 * Wan ZongShun <mcuos.com@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation;version 2 of the License.
 *
 */

#include <linux/platform_device.h>

/*ebable phy0 and phy1 for w90p910*/
#define	ENPHY		(0x01<<8)
#define PHY0_CTR	(0xA4)
#define PHY1_CTR	(0xA8)

static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
		      struct platform_device *pdev)
{
	struct usb_hcd *hcd;
	struct ehci_hcd *ehci;
	struct resource *res;
	int retval = 0, irq;
	unsigned long val;


	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		retval = -ENXIO;
		goto err1;
	}

	hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");
	if (!hcd) {
		retval = -ENOMEM;
		goto err1;
	}

	hcd->rsrc_start = res->start;
44
	hcd->rsrc_len = resource_size(res);
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
		retval = -EBUSY;
		goto err2;
	}

	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
	if (hcd->regs == NULL) {
		retval = -EFAULT;
		goto err3;
	}

	ehci = hcd_to_ehci(hcd);
	ehci->caps = hcd->regs;
	ehci->regs = hcd->regs +
60
		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

	/* enable PHY 0,1,the regs only apply to w90p910
	*  0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
	*  w90p910 IC relative to ehci->regs.
	*/
	val = __raw_readl(ehci->regs+PHY0_CTR);
	val |= ENPHY;
	__raw_writel(val, ehci->regs+PHY0_CTR);

	val = __raw_readl(ehci->regs+PHY1_CTR);
	val |= ENPHY;
	__raw_writel(val, ehci->regs+PHY1_CTR);

	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
	ehci->sbrn = 0x20;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		goto err4;

81 82
	ehci_reset(ehci);

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
	if (retval != 0)
		goto err4;

	ehci_writel(ehci, 1, &ehci->regs->configured_flag);

	return retval;
err4:
	iounmap(hcd->regs);
err3:
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
	usb_put_hcd(hcd);
err1:
	return retval;
}

static
void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev)
{
	usb_remove_hcd(hcd);
	iounmap(hcd->regs);
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
	usb_put_hcd(hcd);
}

static const struct hc_driver ehci_w90x900_hc_driver = {
	.description = hcd_name,
	.product_desc = "Nuvoton w90x900 EHCI Host Controller",
	.hcd_priv_size = sizeof(struct ehci_hcd),

	/*
	 * generic hardware linkage
	 */
	.irq = ehci_irq,
	.flags = HCD_USB2|HCD_MEMORY,

	/*
	 * basic lifecycle operations
	 */
	.reset = ehci_init,
	.start = ehci_run,

	.stop = ehci_stop,
	.shutdown = ehci_shutdown,

	/*
	 * managing i/o requests and associated device resources
	 */
	.urb_enqueue = ehci_urb_enqueue,
	.urb_dequeue = ehci_urb_dequeue,
	.endpoint_disable = ehci_endpoint_disable,
P
Paul Mundt 已提交
135
	.endpoint_reset = ehci_endpoint_reset,
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

	/*
	 * scheduling support
	 */
	.get_frame_number = ehci_get_frame,

	/*
	 * root hub support
	 */
	.hub_status_data = ehci_hub_status_data,
	.hub_control = ehci_hub_control,
#ifdef	CONFIG_PM
	.bus_suspend = ehci_bus_suspend,
	.bus_resume = ehci_bus_resume,
#endif
	.relinquish_port	= ehci_relinquish_port,
	.port_handed_over	= ehci_port_handed_over,
P
Paul Mundt 已提交
153 154

	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
};

static int __devinit ehci_w90x900_probe(struct platform_device *pdev)
{
	if (usb_disabled())
		return -ENODEV;

	return usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev);
}

static int __devexit ehci_w90x900_remove(struct platform_device *pdev)
{
	struct usb_hcd *hcd = platform_get_drvdata(pdev);

	usb_w90x900_remove(hcd, pdev);

	return 0;
}

static struct platform_driver ehci_hcd_w90x900_driver = {
	.probe  = ehci_w90x900_probe,
	.remove = __devexit_p(ehci_w90x900_remove),
	.driver = {
		.name = "w90x900-ehci",
		.owner = THIS_MODULE,
	},
};

MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910 usb ehci driver!");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:w90p910-ehci");