linux/drivers/spi/spi-dw-mmio.c
<<
>>
Prefs
   1/*
   2 * Memory-mapped interface driver for DW SPI Core
   3 *
   4 * Copyright (c) 2010, Octasic semiconductor.
   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
  11#include <linux/clk.h>
  12#include <linux/err.h>
  13#include <linux/interrupt.h>
  14#include <linux/platform_device.h>
  15#include <linux/slab.h>
  16#include <linux/spi/spi.h>
  17#include <linux/scatterlist.h>
  18#include <linux/module.h>
  19
  20#include "spi-dw.h"
  21
  22#define DRIVER_NAME "dw_spi_mmio"
  23
  24struct dw_spi_mmio {
  25        struct dw_spi  dws;
  26        struct clk     *clk;
  27};
  28
  29static int dw_spi_mmio_probe(struct platform_device *pdev)
  30{
  31        struct dw_spi_mmio *dwsmmio;
  32        struct dw_spi *dws;
  33        struct resource *mem, *ioarea;
  34        int ret;
  35
  36        dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL);
  37        if (!dwsmmio) {
  38                ret = -ENOMEM;
  39                goto err_end;
  40        }
  41
  42        dws = &dwsmmio->dws;
  43
  44        /* Get basic io resource and map it */
  45        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  46        if (!mem) {
  47                dev_err(&pdev->dev, "no mem resource?\n");
  48                ret = -EINVAL;
  49                goto err_kfree;
  50        }
  51
  52        ioarea = request_mem_region(mem->start, resource_size(mem),
  53                        pdev->name);
  54        if (!ioarea) {
  55                dev_err(&pdev->dev, "SPI region already claimed\n");
  56                ret = -EBUSY;
  57                goto err_kfree;
  58        }
  59
  60        dws->regs = ioremap_nocache(mem->start, resource_size(mem));
  61        if (!dws->regs) {
  62                dev_err(&pdev->dev, "SPI region already mapped\n");
  63                ret = -ENOMEM;
  64                goto err_release_reg;
  65        }
  66
  67        dws->irq = platform_get_irq(pdev, 0);
  68        if (dws->irq < 0) {
  69                dev_err(&pdev->dev, "no irq resource?\n");
  70                ret = dws->irq; /* -ENXIO */
  71                goto err_unmap;
  72        }
  73
  74        dwsmmio->clk = clk_get(&pdev->dev, NULL);
  75        if (IS_ERR(dwsmmio->clk)) {
  76                ret = PTR_ERR(dwsmmio->clk);
  77                goto err_irq;
  78        }
  79        clk_enable(dwsmmio->clk);
  80
  81        dws->parent_dev = &pdev->dev;
  82        dws->bus_num = 0;
  83        dws->num_cs = 4;
  84        dws->max_freq = clk_get_rate(dwsmmio->clk);
  85
  86        ret = dw_spi_add_host(dws);
  87        if (ret)
  88                goto err_clk;
  89
  90        platform_set_drvdata(pdev, dwsmmio);
  91        return 0;
  92
  93err_clk:
  94        clk_disable(dwsmmio->clk);
  95        clk_put(dwsmmio->clk);
  96        dwsmmio->clk = NULL;
  97err_irq:
  98        free_irq(dws->irq, dws);
  99err_unmap:
 100        iounmap(dws->regs);
 101err_release_reg:
 102        release_mem_region(mem->start, resource_size(mem));
 103err_kfree:
 104        kfree(dwsmmio);
 105err_end:
 106        return ret;
 107}
 108
 109static int dw_spi_mmio_remove(struct platform_device *pdev)
 110{
 111        struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
 112        struct resource *mem;
 113
 114        clk_disable(dwsmmio->clk);
 115        clk_put(dwsmmio->clk);
 116        dwsmmio->clk = NULL;
 117
 118        free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
 119        dw_spi_remove_host(&dwsmmio->dws);
 120        iounmap(dwsmmio->dws.regs);
 121        kfree(dwsmmio);
 122
 123        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 124        release_mem_region(mem->start, resource_size(mem));
 125        return 0;
 126}
 127
 128static struct platform_driver dw_spi_mmio_driver = {
 129        .probe          = dw_spi_mmio_probe,
 130        .remove         = dw_spi_mmio_remove,
 131        .driver         = {
 132                .name   = DRIVER_NAME,
 133                .owner  = THIS_MODULE,
 134        },
 135};
 136module_platform_driver(dw_spi_mmio_driver);
 137
 138MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
 139MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
 140MODULE_LICENSE("GPL v2");
 141