180708Sjake// SPDX-License-Identifier: GPL-2.0
280708Sjake/*
380708Sjake * ci_hdrc_pci.c - MIPS USB IP core family device controller
480708Sjake *
580708Sjake * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
680708Sjake *
780708Sjake * Author: David Lopo
880708Sjake */
980708Sjake
1080708Sjake#include <linux/platform_device.h>
1180708Sjake#include <linux/module.h>
1280708Sjake#include <linux/pci.h>
1380708Sjake#include <linux/interrupt.h>
1480708Sjake#include <linux/usb/gadget.h>
1580708Sjake#include <linux/usb/chipidea.h>
1680708Sjake#include <linux/usb/usb_phy_generic.h>
1780708Sjake
1880708Sjake/* driver name */
1980708Sjake#define UDC_DRIVER_NAME   "ci_hdrc_pci"
2080708Sjake
2180708Sjakestruct ci_hdrc_pci {
2280708Sjake	struct platform_device	*ci;
2380708Sjake	struct platform_device	*phy;
2480708Sjake};
2580708Sjake
2680708Sjake/******************************************************************************
2780708Sjake * PCI block
2880708Sjake *****************************************************************************/
2980708Sjakestatic struct ci_hdrc_platform_data pci_platdata = {
3080708Sjake	.name		= UDC_DRIVER_NAME,
3180708Sjake	.capoffset	= DEF_CAPOFFSET,
3280708Sjake};
3380708Sjake
3480708Sjakestatic struct ci_hdrc_platform_data langwell_pci_platdata = {
3580708Sjake	.name		= UDC_DRIVER_NAME,
3680708Sjake	.capoffset	= 0,
3780708Sjake};
3880708Sjake
3980708Sjakestatic struct ci_hdrc_platform_data penwell_pci_platdata = {
4080708Sjake	.name		= UDC_DRIVER_NAME,
4180708Sjake	.capoffset	= 0,
4280708Sjake	.power_budget	= 200,
4380708Sjake};
4480708Sjake
4580708Sjake/**
4680708Sjake * ci_hdrc_pci_probe: PCI probe
4780708Sjake * @pdev: USB device controller being probed
4880708Sjake * @id:   PCI hotplug ID connecting controller to UDC framework
4980708Sjake *
5080708Sjake * This function returns an error code
5180708Sjake * Allocates basic PCI resources for this USB device controller, and then
5280708Sjake * invokes the udc_probe() method to start the UDC associated with it
5380708Sjake */
5480708Sjakestatic int ci_hdrc_pci_probe(struct pci_dev *pdev,
5580708Sjake				       const struct pci_device_id *id)
5680708Sjake{
5780708Sjake	struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
5880708Sjake	struct ci_hdrc_pci *ci;
5980708Sjake	struct resource res[3];
6080708Sjake	int retval = 0, nres = 2;
6180708Sjake
6280708Sjake	if (!platdata) {
6380708Sjake		dev_err(&pdev->dev, "device doesn't provide driver data\n");
6480708Sjake		return -ENODEV;
6580708Sjake	}
6680708Sjake
6780708Sjake	ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
6891336Sjake	if (!ci)
6991336Sjake		return -ENOMEM;
7091336Sjake
7180708Sjake	retval = pcim_enable_device(pdev);
7280708Sjake	if (retval)
7380708Sjake		return retval;
7480709Sjake
75120710Salc	if (!pdev->irq) {
7680709Sjake		dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
7780708Sjake		return -ENODEV;
7880709Sjake	}
79120710Salc
8080709Sjake	pci_set_master(pdev);
8180708Sjake	pci_try_set_mwi(pdev);
8280709Sjake
83120710Salc	/* register a nop PHY */
8480709Sjake	ci->phy = usb_phy_generic_register();
8580709Sjake	if (IS_ERR(ci->phy))
8680709Sjake		return PTR_ERR(ci->phy);
87120710Salc
8880709Sjake	memset(res, 0, sizeof(res));
8980709Sjake	res[0].start	= pci_resource_start(pdev, 0);
90165324Skmacy	res[0].end	= pci_resource_end(pdev, 0);
91165324Skmacy	res[0].flags	= IORESOURCE_MEM;
92165324Skmacy	res[1].start	= pdev->irq;
93165324Skmacy	res[1].flags	= IORESOURCE_IRQ;
94165324Skmacy
95165324Skmacy	ci->ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
96165324Skmacy	if (IS_ERR(ci->ci)) {
97165324Skmacy		dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
9886226Stmm		usb_phy_generic_unregister(ci->phy);
9986226Stmm		return PTR_ERR(ci->ci);
10086226Stmm	}
10180709Sjake
10280709Sjake	pci_set_drvdata(pdev, ci);
10380709Sjake
10486226Stmm	return 0;
10586226Stmm}
10686226Stmm
10780709Sjake/**
108118239Speter * ci_hdrc_pci_remove: PCI remove
10988781Sjake * @pdev: USB Device Controller being removed
110118239Speter *
111116355Salc * Reverses the effect of ci_hdrc_pci_probe(),
11291360Sjake * first invoking the udc_remove() and then releases
11383366Sjulian * all PCI resources allocated for this USB device controller
114151344Skris */
115151344Skrisstatic void ci_hdrc_pci_remove(struct pci_dev *pdev)
116151344Skris{
117151344Skris	struct ci_hdrc_pci *ci = pci_get_drvdata(pdev);
118151344Skris
119151344Skris	ci_hdrc_remove_device(ci->ci);
120151344Skris	usb_phy_generic_unregister(ci->phy);
121151344Skris}
12283366Sjulian
12380708Sjake/*
12480708Sjake * PCI device table
12580708Sjake * PCI device structure
12680709Sjake *
12780708Sjake * Check "pci.h" for details
12880708Sjake *
12980708Sjake * Note: ehci-pci driver may try to probe the device first. You have to add an
13080708Sjake * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
13180708Sjake */
13280708Sjakestatic const struct pci_device_id ci_hdrc_pci_id_table[] = {
13380708Sjake	{
13480708Sjake		PCI_DEVICE(0x153F, 0x1004),
13580708Sjake		.driver_data = (kernel_ulong_t)&pci_platdata,
13680708Sjake	},
13780708Sjake	{
13880708Sjake		PCI_DEVICE(0x153F, 0x1006),
139		.driver_data = (kernel_ulong_t)&pci_platdata,
140	},
141	{
142		PCI_VDEVICE(INTEL, 0x0811),
143		.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
144	},
145	{
146		PCI_VDEVICE(INTEL, 0x0829),
147		.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
148	},
149	{
150		/* Intel Clovertrail */
151		PCI_VDEVICE(INTEL, 0xe006),
152		.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
153	},
154	{ 0 } /* end: all zeroes */
155};
156MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
157
158static struct pci_driver ci_hdrc_pci_driver = {
159	.name         =	UDC_DRIVER_NAME,
160	.id_table     =	ci_hdrc_pci_id_table,
161	.probe        =	ci_hdrc_pci_probe,
162	.remove       =	ci_hdrc_pci_remove,
163};
164
165module_pci_driver(ci_hdrc_pci_driver);
166
167MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
168MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
169MODULE_LICENSE("GPL");
170MODULE_ALIAS("platform:ci13xxx_pci");
171