linux/drivers/usb/chipidea/ci_hdrc_pci.c
<<
>>
Prefs
   1/*
   2 * ci_hdrc_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
  13#include <linux/platform_device.h>
  14#include <linux/module.h>
  15#include <linux/pci.h>
  16#include <linux/interrupt.h>
  17#include <linux/usb/gadget.h>
  18#include <linux/usb/chipidea.h>
  19#include <linux/usb/usb_phy_generic.h>
  20
  21/* driver name */
  22#define UDC_DRIVER_NAME   "ci_hdrc_pci"
  23
  24struct ci_hdrc_pci {
  25        struct platform_device  *ci;
  26        struct platform_device  *phy;
  27};
  28
  29/******************************************************************************
  30 * PCI block
  31 *****************************************************************************/
  32static struct ci_hdrc_platform_data pci_platdata = {
  33        .name           = UDC_DRIVER_NAME,
  34        .capoffset      = DEF_CAPOFFSET,
  35};
  36
  37static struct ci_hdrc_platform_data langwell_pci_platdata = {
  38        .name           = UDC_DRIVER_NAME,
  39        .capoffset      = 0,
  40};
  41
  42static struct ci_hdrc_platform_data penwell_pci_platdata = {
  43        .name           = UDC_DRIVER_NAME,
  44        .capoffset      = 0,
  45        .power_budget   = 200,
  46};
  47
  48/**
  49 * ci_hdrc_pci_probe: PCI probe
  50 * @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 */
  57static int ci_hdrc_pci_probe(struct pci_dev *pdev,
  58                                       const struct pci_device_id *id)
  59{
  60        struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
  61        struct ci_hdrc_pci *ci;
  62        struct resource res[3];
  63        int retval = 0, nres = 2;
  64
  65        if (!platdata) {
  66                dev_err(&pdev->dev, "device doesn't provide driver data\n");
  67                return -ENODEV;
  68        }
  69
  70        ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
  71        if (!ci)
  72                return -ENOMEM;
  73
  74        retval = pcim_enable_device(pdev);
  75        if (retval)
  76                return retval;
  77
  78        if (!pdev->irq) {
  79                dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
  80                return -ENODEV;
  81        }
  82
  83        pci_set_master(pdev);
  84        pci_try_set_mwi(pdev);
  85
  86        /* register a nop PHY */
  87        ci->phy = usb_phy_generic_register();
  88        if (IS_ERR(ci->phy))
  89                return PTR_ERR(ci->phy);
  90
  91        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
  98        ci->ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
  99        if (IS_ERR(ci->ci)) {
 100                dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
 101                usb_phy_generic_unregister(ci->phy);
 102                return PTR_ERR(ci->ci);
 103        }
 104
 105        pci_set_drvdata(pdev, ci);
 106
 107        return 0;
 108}
 109
 110/**
 111 * ci_hdrc_pci_remove: PCI remove
 112 * @pdev: USB Device Controller being removed
 113 *
 114 * Reverses the effect of ci_hdrc_pci_probe(),
 115 * first invoking the udc_remove() and then releases
 116 * all PCI resources allocated for this USB device controller
 117 */
 118static void ci_hdrc_pci_remove(struct pci_dev *pdev)
 119{
 120        struct ci_hdrc_pci *ci = pci_get_drvdata(pdev);
 121
 122        ci_hdrc_remove_device(ci->ci);
 123        usb_phy_generic_unregister(ci->phy);
 124}
 125
 126/**
 127 * PCI device table
 128 * PCI device structure
 129 *
 130 * Check "pci.h" for details
 131 *
 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.
 134 */
 135static const struct pci_device_id ci_hdrc_pci_id_table[] = {
 136        {
 137                PCI_DEVICE(0x153F, 0x1004),
 138                .driver_data = (kernel_ulong_t)&pci_platdata,
 139        },
 140        {
 141                PCI_DEVICE(0x153F, 0x1006),
 142                .driver_data = (kernel_ulong_t)&pci_platdata,
 143        },
 144        {
 145                PCI_VDEVICE(INTEL, 0x0811),
 146                .driver_data = (kernel_ulong_t)&langwell_pci_platdata,
 147        },
 148        {
 149                PCI_VDEVICE(INTEL, 0x0829),
 150                .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
 151        },
 152        {
 153                /* Intel Clovertrail */
 154                PCI_VDEVICE(INTEL, 0xe006),
 155                .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
 156        },
 157        { 0 } /* end: all zeroes */
 158};
 159MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
 160
 161static struct pci_driver ci_hdrc_pci_driver = {
 162        .name         = UDC_DRIVER_NAME,
 163        .id_table     = ci_hdrc_pci_id_table,
 164        .probe        = ci_hdrc_pci_probe,
 165        .remove       = ci_hdrc_pci_remove,
 166};
 167
 168module_pci_driver(ci_hdrc_pci_driver);
 169
 170MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
 171MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
 172MODULE_LICENSE("GPL");
 173MODULE_VERSION("June 2008");
 174MODULE_ALIAS("platform:ci13xxx_pci");
 175