ohci-nxp.c 9.7 KB
Newer Older
1
/*
2
 * driver for NXP USB Host devices
3
 *
4
 * Currently supported OHCI host devices:
5
 * - NXP LPC32xx
6 7
 *
 * Authors: Dmitry Chigirev <source@mvista.com>
8
 *	    Vitaly Wool <vitalywool@gmail.com>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * register initialization is based on code examples provided by Philips
 * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
 *
 * NOTE: This driver does not have suspend/resume functionality
 * This driver is intended for engineering development purposes only
 *
 * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
 * the terms of the GNU General Public License version 2. This program
 * is licensed "as is" without any warranty of any kind, whether express
 * or implied.
 */
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
R
Roland Stigge 已提交
24
#include <linux/of.h>
25
#include <linux/usb/isp1301.h>
26

27
#include <mach/hardware.h>
28
#include <asm/mach-types.h>
29 30
#include <asm/io.h>

31 32
#include <mach/platform.h>
#include <mach/irqs.h>
33

34 35 36 37
#define USB_CONFIG_BASE		0x31020000
#define PWRMAN_BASE		0x40004000

#define USB_CTRL		IO_ADDRESS(PWRMAN_BASE + 0x64)
38 39 40

/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN	(1 << 24)
R
Roland Stigge 已提交
41
#define USB_DEV_NEED_CLK_EN	(1 << 22)
42
#define USB_HOST_NEED_CLK_EN	(1 << 21)
R
Roland Stigge 已提交
43
#define PAD_CONTROL_LAST_DRIVEN	(1 << 19)
44

45
#define USB_OTG_STAT_CONTROL	IO_ADDRESS(USB_CONFIG_BASE + 0x110)
46 47 48 49 50

/* USB_OTG_STAT_CONTROL bit defines */
#define TRANSPARENT_I2C_EN	(1 << 7)
#define HOST_EN			(1 << 0)

51 52 53 54 55 56 57 58 59
/* On LPC32xx, those are undefined */
#ifndef start_int_set_falling_edge
#define start_int_set_falling_edge(irq)
#define start_int_set_rising_edge(irq)
#define start_int_ack(irq)
#define start_int_mask(irq)
#define start_int_umask(irq)
#endif

60
static struct i2c_client *isp1301_i2c_client;
61 62 63

extern int usb_disabled(void);

64 65 66
static struct clk *usb_pll_clk;
static struct clk *usb_dev_clk;
static struct clk *usb_otg_clk;
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
static void isp1301_configure_lpc32xx(void)
{
	/* LPC32XX only supports DAT_SE0 USB mode */
	/* This sequence is important */

	/* Disable transparent UART mode first */
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
		MC1_UART_EN);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		(ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
		~MC1_SPEED_REG);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
				  ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		  (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR),
		  ~0);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_MODE_CONTROL_2,
		(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_OTG_CONTROL_1,
		(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		(ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
		(OTG1_DM_PULLUP | OTG1_DP_PULLUP));
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
		~0);
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);

	/* Enable usb_need_clk clock after transceiver is initialized */
R
Roland Stigge 已提交
107
	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
108 109 110 111 112 113 114 115 116 117 118

	printk(KERN_INFO "ISP1301 Vendor ID  : 0x%04x\n",
	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
	printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n",
	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x02));
	printk(KERN_INFO "ISP1301 Version ID : 0x%04x\n",
	      i2c_smbus_read_word_data(isp1301_i2c_client, 0x14));
}

static void isp1301_configure(void)
{
119
	isp1301_configure_lpc32xx();
120 121 122 123
}

static inline void isp1301_vbus_on(void)
{
124 125
	i2c_smbus_write_byte_data(isp1301_i2c_client, ISP1301_I2C_OTG_CONTROL_1,
				  OTG1_VBUS_DRV);
126 127 128 129
}

static inline void isp1301_vbus_off(void)
{
130 131 132
	i2c_smbus_write_byte_data(isp1301_i2c_client,
		ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
		OTG1_VBUS_DRV);
133 134
}

135
static void nxp_start_hc(void)
136 137 138 139 140 141
{
	unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
	isp1301_vbus_on();
}

142
static void nxp_stop_hc(void)
143 144 145 146 147 148 149
{
	unsigned long tmp;
	isp1301_vbus_off();
	tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
	__raw_writel(tmp, USB_OTG_STAT_CONTROL);
}

B
Bill Pemberton 已提交
150
static int ohci_nxp_start(struct usb_hcd *hcd)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
{
	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
	int ret;

	if ((ret = ohci_init(ohci)) < 0)
		return ret;

	if ((ret = ohci_run(ohci)) < 0) {
		dev_err(hcd->self.controller, "can't start\n");
		ohci_stop(hcd);
		return ret;
	}
	return 0;
}

166
static const struct hc_driver ohci_nxp_hc_driver = {
167
	.description = hcd_name,
168
	.product_desc =		"nxp OHCI",
169 170 171 172 173 174 175 176 177 178 179

	/*
	 * generic hardware linkage
	 */
	.irq = ohci_irq,
	.flags = HCD_USB11 | HCD_MEMORY,

	.hcd_priv_size =	sizeof(struct ohci_hcd),
	/*
	 * basic lifecycle operations
	 */
180
	.start = ohci_nxp_start,
181
	.stop = ohci_stop,
D
David Brownell 已提交
182
	.shutdown = ohci_shutdown,
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

	/*
	 * managing i/o requests and associated device resources
	 */
	.urb_enqueue = ohci_urb_enqueue,
	.urb_dequeue = ohci_urb_dequeue,
	.endpoint_disable = ohci_endpoint_disable,

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

	/*
	 * root hub support
	 */
	.hub_status_data = ohci_hub_status_data,
	.hub_control = ohci_hub_control,
D
David Brownell 已提交
201 202 203 204
#ifdef	CONFIG_PM
	.bus_suspend = ohci_bus_suspend,
	.bus_resume = ohci_bus_resume,
#endif
205 206 207
	.start_port_reset = ohci_start_port_reset,
};

B
Bill Pemberton 已提交
208
static int usb_hcd_nxp_probe(struct platform_device *pdev)
209 210 211
{
	struct usb_hcd *hcd = 0;
	struct ohci_hcd *ohci;
212
	const struct hc_driver *driver = &ohci_nxp_hc_driver;
R
Roland Stigge 已提交
213
	struct resource *res;
214
	int ret = 0, irq;
215 216 217 218 219 220 221 222 223 224 225 226 227 228
	struct device_node *isp1301_node;

	if (pdev->dev.of_node) {
		isp1301_node = of_parse_phandle(pdev->dev.of_node,
						"transceiver", 0);
	} else {
		isp1301_node = NULL;
	}

	isp1301_i2c_client = isp1301_get_client(isp1301_node);
	if (!isp1301_i2c_client) {
		ret = -EPROBE_DEFER;
		goto out;
	}
229

R
Roland Stigge 已提交
230 231 232
	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;

233
	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
234
	if (usb_disabled()) {
235
		dev_err(&pdev->dev, "USB is disabled\n");
236 237 238 239 240
		ret = -ENODEV;
		goto out;
	}

	/* Enable AHB slave USB clock, needed for further USB clock control */
R
Roland Stigge 已提交
241
	__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
242 243

	/* Enable USB PLL */
244 245
	usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
	if (IS_ERR(usb_pll_clk)) {
246
		dev_err(&pdev->dev, "failed to acquire USB PLL\n");
247
		ret = PTR_ERR(usb_pll_clk);
248 249 250
		goto out1;
	}

251
	ret = clk_enable(usb_pll_clk);
252
	if (ret < 0) {
253
		dev_err(&pdev->dev, "failed to start USB PLL\n");
254 255 256
		goto out2;
	}

257
	ret = clk_set_rate(usb_pll_clk, 48000);
258
	if (ret < 0) {
259
		dev_err(&pdev->dev, "failed to set USB clock rate\n");
260 261 262
		goto out3;
	}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	/* Enable USB device clock */
	usb_dev_clk = clk_get(&pdev->dev, "ck_usbd");
	if (IS_ERR(usb_dev_clk)) {
		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
		ret = PTR_ERR(usb_dev_clk);
		goto out4;
	}

	ret = clk_enable(usb_dev_clk);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
		goto out5;
	}

	/* Enable USB otg clocks */
	usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
	if (IS_ERR(usb_otg_clk)) {
		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
281
		ret = PTR_ERR(usb_otg_clk);
282 283 284
		goto out6;
	}

285 286
	__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);

287 288 289 290 291
	ret = clk_enable(usb_otg_clk);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
		goto out7;
	}
292

293
	isp1301_configure();
294

R
Roland Stigge 已提交
295
	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
296
	if (!hcd) {
297
		dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
298
		ret = -ENOMEM;
299
		goto out8;
300 301
	}

R
Roland Stigge 已提交
302 303 304 305
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "Failed to get MEM resource\n");
		ret =  -ENOMEM;
306
		goto out8;
R
Roland Stigge 已提交
307 308
	}

309 310 311
	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(hcd->regs)) {
		ret = PTR_ERR(hcd->regs);
312
		goto out8;
313
	}
R
Roland Stigge 已提交
314 315
	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);
316 317 318 319

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		ret = -ENXIO;
320
		goto out8;
321 322
	}

323
	nxp_start_hc();
324 325 326 327 328
	platform_set_drvdata(pdev, hcd);
	ohci = hcd_to_ohci(hcd);
	ohci_hcd_init(ohci);

	dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
Y
Yong Zhang 已提交
329
	ret = usb_add_hcd(hcd, irq, 0);
330 331 332
	if (ret == 0)
		return ret;

333
	nxp_stop_hc();
334
out8:
335
	usb_put_hcd(hcd);
336 337 338 339 340 341 342 343
out7:
	clk_disable(usb_otg_clk);
out6:
	clk_put(usb_otg_clk);
out5:
	clk_disable(usb_dev_clk);
out4:
	clk_put(usb_dev_clk);
344
out3:
345
	clk_disable(usb_pll_clk);
346
out2:
347
	clk_put(usb_pll_clk);
348
out1:
349
	isp1301_i2c_client = NULL;
350 351 352 353
out:
	return ret;
}

354
static int usb_hcd_nxp_remove(struct platform_device *pdev)
355 356 357 358
{
	struct usb_hcd *hcd = platform_get_drvdata(pdev);

	usb_remove_hcd(hcd);
359
	nxp_stop_hc();
360 361
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
	usb_put_hcd(hcd);
362 363 364 365
	clk_disable(usb_pll_clk);
	clk_put(usb_pll_clk);
	clk_disable(usb_dev_clk);
	clk_put(usb_dev_clk);
366
	i2c_unregister_device(isp1301_i2c_client);
367
	isp1301_i2c_client = NULL;
368 369 370 371 372 373

	platform_set_drvdata(pdev, NULL);

	return 0;
}

374 375 376
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:usb-ohci");

R
Roland Stigge 已提交
377 378 379 380 381 382 383 384
#ifdef CONFIG_OF
static const struct of_device_id usb_hcd_nxp_match[] = {
	{ .compatible = "nxp,ohci-nxp" },
	{},
};
MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match);
#endif

385
static struct platform_driver usb_hcd_nxp_driver = {
386 387
	.driver = {
		.name = "usb-ohci",
388
		.owner	= THIS_MODULE,
R
Roland Stigge 已提交
389
		.of_match_table = of_match_ptr(usb_hcd_nxp_match),
390
	},
391 392
	.probe = usb_hcd_nxp_probe,
	.remove = usb_hcd_nxp_remove,
393 394
};