blob: f075ef33834f8708b799bdeb93e43586c75139f5 [file] [log] [blame]
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +05301/*
2 * ci13xxx_pci.c - MIPS USB IP core family device controller
3 *
4 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
5 *
6 * Author: David Lopo
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030013#include <linux/platform_device.h>
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053014#include <linux/module.h>
15#include <linux/pci.h>
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030016#include <linux/interrupt.h>
17#include <linux/usb/gadget.h>
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053018
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030019#include "ci13xxx_udc.h"
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053020
21/* driver name */
22#define UDC_DRIVER_NAME "ci13xxx_pci"
23
24/******************************************************************************
25 * PCI block
26 *****************************************************************************/
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030027struct ci13xxx_udc_driver pci_driver = {
Pavankumar Kondetif01ef572010-12-07 17:54:02 +053028 .name = UDC_DRIVER_NAME,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030029 .capoffset = DEF_CAPOFFSET,
30};
31
32struct ci13xxx_udc_driver langwell_pci_driver = {
33 .name = UDC_DRIVER_NAME,
34 .capoffset = 0,
Pavankumar Kondetif01ef572010-12-07 17:54:02 +053035};
36
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053037/**
38 * ci13xxx_pci_probe: PCI probe
39 * @pdev: USB device controller being probed
40 * @id: PCI hotplug ID connecting controller to UDC framework
41 *
42 * This function returns an error code
43 * Allocates basic PCI resources for this USB device controller, and then
44 * invokes the udc_probe() method to start the UDC associated with it
45 */
46static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
47 const struct pci_device_id *id)
48{
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030049 struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
50 struct platform_device *plat_ci;
51 struct resource res[3];
52 int retval = 0, nres = 2;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053053
Alexander Shishkin1989b5c2012-05-11 17:25:40 +030054 if (!driver) {
55 dev_err(&pdev->dev, "device doesn't provide driver data\n");
56 return -ENODEV;
57 }
58
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053059 retval = pci_enable_device(pdev);
60 if (retval)
61 goto done;
62
63 if (!pdev->irq) {
64 dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
65 retval = -ENODEV;
66 goto disable_device;
67 }
68
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030069 pci_set_power_state(pdev, PCI_D0);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053070 pci_set_master(pdev);
71 pci_try_set_mwi(pdev);
72
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030073 plat_ci = platform_device_alloc("ci_udc", -1);
74 if (!plat_ci) {
75 dev_err(&pdev->dev, "can't allocate ci_udc platform device\n");
76 retval = -ENOMEM;
77 goto disable_device;
78 }
Alexander Shishkinf9df8392012-05-04 16:47:16 +030079
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030080 memset(res, 0, sizeof(res));
81 res[0].start = pci_resource_start(pdev, 0);
82 res[0].end = pci_resource_end(pdev, 0);
83 res[0].flags = IORESOURCE_MEM;
84 res[1].start = pdev->irq;
85 res[1].flags = IORESOURCE_IRQ;
86
87 retval = platform_device_add_resources(plat_ci, res, nres);
88 if (retval) {
89 dev_err(&pdev->dev, "can't add resources to platform device\n");
90 goto put_platform;
91 }
92
93 retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053094 if (retval)
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030095 goto put_platform;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053096
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030097 dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
98 plat_ci->dev.dma_mask = pdev->dev.dma_mask;
99 plat_ci->dev.dma_parms = pdev->dev.dma_parms;
100 plat_ci->dev.parent = &pdev->dev;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530101
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300102 pci_set_drvdata(pdev, plat_ci);
103
104 retval = platform_device_add(plat_ci);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530105 if (retval)
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300106 goto put_platform;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530107
108 return 0;
109
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300110 put_platform:
111 pci_set_drvdata(pdev, NULL);
112 platform_device_put(plat_ci);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530113 disable_device:
114 pci_disable_device(pdev);
115 done:
116 return retval;
117}
118
119/**
120 * ci13xxx_pci_remove: PCI remove
121 * @pdev: USB Device Controller being removed
122 *
123 * Reverses the effect of ci13xxx_pci_probe(),
124 * first invoking the udc_remove() and then releases
125 * all PCI resources allocated for this USB device controller
126 */
127static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
128{
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300129 struct platform_device *plat_ci = pci_get_drvdata(pdev);
130
131 platform_device_unregister(plat_ci);
132 pci_set_drvdata(pdev, NULL);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530133 pci_disable_device(pdev);
134}
135
136/**
137 * PCI device table
138 * PCI device structure
139 *
140 * Check "pci.h" for details
141 */
142static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300143 {
144 PCI_DEVICE(0x153F, 0x1004),
145 .driver_data = (kernel_ulong_t)&pci_driver,
146 },
147 {
148 PCI_DEVICE(0x153F, 0x1006),
149 .driver_data = (kernel_ulong_t)&pci_driver,
150 },
151 {
152 PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
153 .driver_data = (kernel_ulong_t)&langwell_pci_driver,
154 },
155 {
156 PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
157 .driver_data = (kernel_ulong_t)&langwell_pci_driver,
158 },
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530159 { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
160};
161MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
162
163static struct pci_driver ci13xxx_pci_driver = {
164 .name = UDC_DRIVER_NAME,
165 .id_table = ci13xxx_pci_id_table,
166 .probe = ci13xxx_pci_probe,
167 .remove = __devexit_p(ci13xxx_pci_remove),
168};
169
Axel Lin3cdb7722012-04-04 22:14:58 +0800170module_pci_driver(ci13xxx_pci_driver);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530171
172MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
173MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
174MODULE_LICENSE("GPL");
175MODULE_VERSION("June 2008");