linux/drivers/spi/spi-dw-pci.c
<<
>>
Prefs
   1/*
   2 * PCI interface driver for DW SPI Core
   3 *
   4 * Copyright (c) 2009, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along
  16 * with this program; if not, write to the Free Software Foundation,
  17 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  18 */
  19
  20#include <linux/interrupt.h>
  21#include <linux/pci.h>
  22#include <linux/slab.h>
  23#include <linux/spi/spi.h>
  24#include <linux/module.h>
  25
  26#include "spi-dw.h"
  27
  28#define DRIVER_NAME "dw_spi_pci"
  29
  30struct dw_spi_pci {
  31        struct pci_dev  *pdev;
  32        struct dw_spi   dws;
  33};
  34
  35static int spi_pci_probe(struct pci_dev *pdev,
  36        const struct pci_device_id *ent)
  37{
  38        struct dw_spi_pci *dwpci;
  39        struct dw_spi *dws;
  40        int pci_bar = 0;
  41        int ret;
  42
  43        printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n",
  44                pdev->vendor, pdev->device);
  45
  46        ret = pci_enable_device(pdev);
  47        if (ret)
  48                return ret;
  49
  50        dwpci = kzalloc(sizeof(struct dw_spi_pci), GFP_KERNEL);
  51        if (!dwpci) {
  52                ret = -ENOMEM;
  53                goto err_disable;
  54        }
  55
  56        dwpci->pdev = pdev;
  57        dws = &dwpci->dws;
  58
  59        /* Get basic io resource and map it */
  60        dws->paddr = pci_resource_start(pdev, pci_bar);
  61        dws->iolen = pci_resource_len(pdev, pci_bar);
  62
  63        ret = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
  64        if (ret)
  65                goto err_kfree;
  66
  67        dws->regs = ioremap_nocache((unsigned long)dws->paddr,
  68                                pci_resource_len(pdev, pci_bar));
  69        if (!dws->regs) {
  70                ret = -ENOMEM;
  71                goto err_release_reg;
  72        }
  73
  74        dws->parent_dev = &pdev->dev;
  75        dws->bus_num = 0;
  76        dws->num_cs = 4;
  77        dws->irq = pdev->irq;
  78
  79        /*
  80         * Specific handling for Intel MID paltforms, like dma setup,
  81         * clock rate, FIFO depth.
  82         */
  83        if (pdev->device == 0x0800) {
  84                ret = dw_spi_mid_init(dws);
  85                if (ret)
  86                        goto err_unmap;
  87        }
  88
  89        ret = dw_spi_add_host(dws);
  90        if (ret)
  91                goto err_unmap;
  92
  93        /* PCI hook and SPI hook use the same drv data */
  94        pci_set_drvdata(pdev, dwpci);
  95        return 0;
  96
  97err_unmap:
  98        iounmap(dws->regs);
  99err_release_reg:
 100        pci_release_region(pdev, pci_bar);
 101err_kfree:
 102        kfree(dwpci);
 103err_disable:
 104        pci_disable_device(pdev);
 105        return ret;
 106}
 107
 108static void spi_pci_remove(struct pci_dev *pdev)
 109{
 110        struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
 111
 112        pci_set_drvdata(pdev, NULL);
 113        dw_spi_remove_host(&dwpci->dws);
 114        iounmap(dwpci->dws.regs);
 115        pci_release_region(pdev, 0);
 116        kfree(dwpci);
 117        pci_disable_device(pdev);
 118}
 119
 120#ifdef CONFIG_PM
 121static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
 122{
 123        struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
 124        int ret;
 125
 126        ret = dw_spi_suspend_host(&dwpci->dws);
 127        if (ret)
 128                return ret;
 129        pci_save_state(pdev);
 130        pci_disable_device(pdev);
 131        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 132        return ret;
 133}
 134
 135static int spi_resume(struct pci_dev *pdev)
 136{
 137        struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
 138        int ret;
 139
 140        pci_set_power_state(pdev, PCI_D0);
 141        pci_restore_state(pdev);
 142        ret = pci_enable_device(pdev);
 143        if (ret)
 144                return ret;
 145        return dw_spi_resume_host(&dwpci->dws);
 146}
 147#else
 148#define spi_suspend     NULL
 149#define spi_resume      NULL
 150#endif
 151
 152static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
 153        /* Intel MID platform SPI controller 0 */
 154        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
 155        {},
 156};
 157
 158static struct pci_driver dw_spi_driver = {
 159        .name =         DRIVER_NAME,
 160        .id_table =     pci_ids,
 161        .probe =        spi_pci_probe,
 162        .remove =       spi_pci_remove,
 163        .suspend =      spi_suspend,
 164        .resume =       spi_resume,
 165};
 166
 167module_pci_driver(dw_spi_driver);
 168
 169MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
 170MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
 171MODULE_LICENSE("GPL v2");
 172