blob: b635ab67490de3a93a9c0df0f17848376ae1d947 [file] [log] [blame]
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +05301/*
Alexander Shishkin8e229782013-06-24 14:46:36 +03002 * ci_hdrc_pci.c - MIPS USB IP core family device controller
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +05303 *
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>
Alexander Shishkine443b332012-05-11 17:25:46 +030018#include <linux/usb/chipidea.h>
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080019#include <linux/usb/usb_phy_generic.h>
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053020
21/* driver name */
Alexander Shishkin8e229782013-06-24 14:46:36 +030022#define UDC_DRIVER_NAME "ci_hdrc_pci"
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053023
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080024struct ci_hdrc_pci {
25 struct platform_device *ci;
26 struct platform_device *phy;
27};
28
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053029/******************************************************************************
30 * PCI block
31 *****************************************************************************/
Alexander Shishkin8e229782013-06-24 14:46:36 +030032static struct ci_hdrc_platform_data pci_platdata = {
Pavankumar Kondetif01ef572010-12-07 17:54:02 +053033 .name = UDC_DRIVER_NAME,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030034 .capoffset = DEF_CAPOFFSET,
35};
36
Alexander Shishkin8e229782013-06-24 14:46:36 +030037static struct ci_hdrc_platform_data langwell_pci_platdata = {
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030038 .name = UDC_DRIVER_NAME,
39 .capoffset = 0,
Pavankumar Kondetif01ef572010-12-07 17:54:02 +053040};
41
Alexander Shishkin8e229782013-06-24 14:46:36 +030042static struct ci_hdrc_platform_data penwell_pci_platdata = {
Alexander Shishkinbd841982012-05-11 17:25:55 +030043 .name = UDC_DRIVER_NAME,
44 .capoffset = 0,
45 .power_budget = 200,
46};
47
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053048/**
Alexander Shishkin8e229782013-06-24 14:46:36 +030049 * ci_hdrc_pci_probe: PCI probe
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053050 * @pdev: USB device controller being probed
51 * @id: PCI hotplug ID connecting controller to UDC framework
52 *
53 * This function returns an error code
54 * Allocates basic PCI resources for this USB device controller, and then
55 * invokes the udc_probe() method to start the UDC associated with it
56 */
Alexander Shishkin8e229782013-06-24 14:46:36 +030057static int ci_hdrc_pci_probe(struct pci_dev *pdev,
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053058 const struct pci_device_id *id)
59{
Alexander Shishkin8e229782013-06-24 14:46:36 +030060 struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080061 struct ci_hdrc_pci *ci;
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030062 struct resource res[3];
63 int retval = 0, nres = 2;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053064
Richard Zhao77c44002012-06-29 17:48:53 +080065 if (!platdata) {
Alexander Shishkin1989b5c2012-05-11 17:25:40 +030066 dev_err(&pdev->dev, "device doesn't provide driver data\n");
67 return -ENODEV;
68 }
69
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080070 ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
71 if (!ci)
72 return -ENOMEM;
73
Andy Shevchenko8b2379b2013-06-13 18:00:02 +030074 retval = pcim_enable_device(pdev);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053075 if (retval)
Andy Shevchenko8b2379b2013-06-13 18:00:02 +030076 return retval;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053077
78 if (!pdev->irq) {
79 dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
Andy Shevchenko8b2379b2013-06-13 18:00:02 +030080 return -ENODEV;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053081 }
82
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +053083 pci_set_master(pdev);
84 pci_try_set_mwi(pdev);
85
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080086 /* register a nop PHY */
87 ci->phy = usb_phy_generic_register();
Wei Yongjun8c0614c2016-02-06 22:57:06 +080088 if (IS_ERR(ci->phy))
89 return PTR_ERR(ci->phy);
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080090
Alexander Shishkin62bb84e2012-05-08 23:29:01 +030091 memset(res, 0, sizeof(res));
92 res[0].start = pci_resource_start(pdev, 0);
93 res[0].end = pci_resource_end(pdev, 0);
94 res[0].flags = IORESOURCE_MEM;
95 res[1].start = pdev->irq;
96 res[1].flags = IORESOURCE_IRQ;
97
Andy Shevchenkoba1aff62015-02-11 12:45:00 +080098 ci->ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
99 if (IS_ERR(ci->ci)) {
Alexander Shishkin8e229782013-06-24 14:46:36 +0300100 dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
Andy Shevchenkoba1aff62015-02-11 12:45:00 +0800101 usb_phy_generic_unregister(ci->phy);
102 return PTR_ERR(ci->ci);
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300103 }
104
Andy Shevchenkoba1aff62015-02-11 12:45:00 +0800105 pci_set_drvdata(pdev, ci);
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300106
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530107 return 0;
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530108}
109
110/**
Alexander Shishkin8e229782013-06-24 14:46:36 +0300111 * ci_hdrc_pci_remove: PCI remove
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530112 * @pdev: USB Device Controller being removed
113 *
Alexander Shishkin8e229782013-06-24 14:46:36 +0300114 * Reverses the effect of ci_hdrc_pci_probe(),
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530115 * first invoking the udc_remove() and then releases
116 * all PCI resources allocated for this USB device controller
117 */
Alexander Shishkin8e229782013-06-24 14:46:36 +0300118static void ci_hdrc_pci_remove(struct pci_dev *pdev)
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530119{
Andy Shevchenkoba1aff62015-02-11 12:45:00 +0800120 struct ci_hdrc_pci *ci = pci_get_drvdata(pdev);
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300121
Andy Shevchenkoba1aff62015-02-11 12:45:00 +0800122 ci_hdrc_remove_device(ci->ci);
123 usb_phy_generic_unregister(ci->phy);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530124}
125
126/**
127 * PCI device table
128 * PCI device structure
129 *
130 * Check "pci.h" for details
Andy Shevchenko518ca8d2015-02-03 18:08:39 +0200131 *
132 * Note: ehci-pci driver may try to probe the device first. You have to add an
133 * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530134 */
Jingoo Han4e065b82013-11-28 14:15:26 +0900135static const struct pci_device_id ci_hdrc_pci_id_table[] = {
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300136 {
137 PCI_DEVICE(0x153F, 0x1004),
Richard Zhao77c44002012-06-29 17:48:53 +0800138 .driver_data = (kernel_ulong_t)&pci_platdata,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300139 },
140 {
141 PCI_DEVICE(0x153F, 0x1006),
Richard Zhao77c44002012-06-29 17:48:53 +0800142 .driver_data = (kernel_ulong_t)&pci_platdata,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300143 },
144 {
Sergei Shtylyov46b95a1d2015-10-04 23:55:35 +0300145 PCI_VDEVICE(INTEL, 0x0811),
Richard Zhao77c44002012-06-29 17:48:53 +0800146 .driver_data = (kernel_ulong_t)&langwell_pci_platdata,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300147 },
148 {
Sergei Shtylyov46b95a1d2015-10-04 23:55:35 +0300149 PCI_VDEVICE(INTEL, 0x0829),
Richard Zhao77c44002012-06-29 17:48:53 +0800150 .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
Alexander Shishkin62bb84e2012-05-08 23:29:01 +0300151 },
David Cohena2143392013-10-01 14:32:58 -0700152 {
153 /* Intel Clovertrail */
Sergei Shtylyov46b95a1d2015-10-04 23:55:35 +0300154 PCI_VDEVICE(INTEL, 0xe006),
David Cohena2143392013-10-01 14:32:58 -0700155 .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
156 },
157 { 0 } /* end: all zeroes */
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530158};
Alexander Shishkin8e229782013-06-24 14:46:36 +0300159MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530160
Alexander Shishkin8e229782013-06-24 14:46:36 +0300161static struct pci_driver ci_hdrc_pci_driver = {
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530162 .name = UDC_DRIVER_NAME,
Alexander Shishkin8e229782013-06-24 14:46:36 +0300163 .id_table = ci_hdrc_pci_id_table,
164 .probe = ci_hdrc_pci_probe,
165 .remove = ci_hdrc_pci_remove,
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530166};
167
Alexander Shishkin8e229782013-06-24 14:46:36 +0300168module_pci_driver(ci_hdrc_pci_driver);
Pavankumar Kondeti409a15d2010-12-07 17:53:59 +0530169
170MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
171MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
172MODULE_LICENSE("GPL");
173MODULE_VERSION("June 2008");
Alexander Shishkin8e229782013-06-24 14:46:36 +0300174MODULE_ALIAS("platform:ci13xxx_pci");