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#include <linux/of.h>
  20#include <linux/of_gpio.h>
  21#include <linux/of_platform.h>
  22
  23#include "spi-dw.h"
  24
  25#define DRIVER_NAME "dw_spi_mmio"
  26
  27struct dw_spi_mmio {
  28        struct dw_spi  dws;
  29        struct clk     *clk;
  30};
  31
  32static int dw_spi_mmio_probe(struct platform_device *pdev)
  33{
  34        struct dw_spi_mmio *dwsmmio;
  35        struct dw_spi *dws;
  36        struct resource *mem;
  37        int ret;
  38        int num_cs;
  39
  40        dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
  41                        GFP_KERNEL);
  42        if (!dwsmmio)
  43                return -ENOMEM;
  44
  45        dws = &dwsmmio->dws;
  46
  47        /* Get basic io resource and map it */
  48        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  49        if (!mem) {
  50                dev_err(&pdev->dev, "no mem resource?\n");
  51                return -EINVAL;
  52        }
  53
  54        dws->regs = devm_ioremap_resource(&pdev->dev, mem);
  55        if (IS_ERR(dws->regs)) {
  56                dev_err(&pdev->dev, "SPI region map failed\n");
  57                return PTR_ERR(dws->regs);
  58        }
  59
  60        dws->irq = platform_get_irq(pdev, 0);
  61        if (dws->irq < 0) {
  62                dev_err(&pdev->dev, "no irq resource?\n");
  63                return dws->irq; /* -ENXIO */
  64        }
  65
  66        dwsmmio->clk = devm_clk_get(&pdev->dev, NULL);
  67        if (IS_ERR(dwsmmio->clk))
  68                return PTR_ERR(dwsmmio->clk);
  69        ret = clk_prepare_enable(dwsmmio->clk);
  70        if (ret)
  71                return ret;
  72
  73        dws->bus_num = pdev->id;
  74
  75        dws->max_freq = clk_get_rate(dwsmmio->clk);
  76
  77        of_property_read_u32(pdev->dev.of_node, "reg-io-width",
  78                             &dws->reg_io_width);
  79
  80        num_cs = 4;
  81
  82        if (pdev->dev.of_node)
  83                of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
  84
  85        dws->num_cs = num_cs;
  86
  87        if (pdev->dev.of_node) {
  88                int i;
  89
  90                for (i = 0; i < dws->num_cs; i++) {
  91                        int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
  92                                        "cs-gpios", i);
  93
  94                        if (cs_gpio == -EPROBE_DEFER) {
  95                                ret = cs_gpio;
  96                                goto out;
  97                        }
  98
  99                        if (gpio_is_valid(cs_gpio)) {
 100                                ret = devm_gpio_request(&pdev->dev, cs_gpio,
 101                                                dev_name(&pdev->dev));
 102                                if (ret)
 103                                        goto out;
 104                        }
 105                }
 106        }
 107
 108        ret = dw_spi_add_host(&pdev->dev, dws);
 109        if (ret)
 110                goto out;
 111
 112        platform_set_drvdata(pdev, dwsmmio);
 113        return 0;
 114
 115out:
 116        clk_disable_unprepare(dwsmmio->clk);
 117        return ret;
 118}
 119
 120static int dw_spi_mmio_remove(struct platform_device *pdev)
 121{
 122        struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
 123
 124        clk_disable_unprepare(dwsmmio->clk);
 125        dw_spi_remove_host(&dwsmmio->dws);
 126
 127        return 0;
 128}
 129
 130static const struct of_device_id dw_spi_mmio_of_match[] = {
 131        { .compatible = "snps,dw-apb-ssi", },
 132        { /* end of table */}
 133};
 134MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
 135
 136static struct platform_driver dw_spi_mmio_driver = {
 137        .probe          = dw_spi_mmio_probe,
 138        .remove         = dw_spi_mmio_remove,
 139        .driver         = {
 140                .name   = DRIVER_NAME,
 141                .of_match_table = dw_spi_mmio_of_match,
 142        },
 143};
 144module_platform_driver(dw_spi_mmio_driver);
 145
 146MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
 147MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
 148MODULE_LICENSE("GPL v2");
 149