summaryrefslogtreecommitdiffstats
path: root/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch')
-rw-r--r--configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch533
1 files changed, 0 insertions, 533 deletions
diff --git a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch
deleted file mode 100644
index 7f4c88c..0000000
--- a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0003-spi-new-controller-driver-for-efm32-SoCs.patch
+++ /dev/null
@@ -1,533 +0,0 @@
-From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
-Date: Thu, 23 Feb 2012 10:44:35 +0100
-Subject: [PATCH] spi: new controller driver for efm32 SoCs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-known issues:
- efm32-spi efm32-spi.1: master is unqueued, this is deprecated
-
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/spi/Kconfig | 5 +
- drivers/spi/Makefile | 1 +
- drivers/spi/spi-efm32.c | 481 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 487 insertions(+)
- create mode 100644 drivers/spi/spi-efm32.c
-
-diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
-index 89cbbab..6a273d3 100644
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -157,6 +157,11 @@ config SPI_DAVINCI
- help
- SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
-
-+config SPI_EFM32
-+ tristate "EFM32 SPI controller"
-+ depends on ARCH_EFM32
-+ select SPI_BITBANG
-+
- config SPI_EP93XX
- tristate "Cirrus Logic EP93xx SPI controller"
- depends on ARCH_EP93XX
-diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
-index 33f9c09..4a1cfb2 100644
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
- obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
- obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
- spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
-+obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
- obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
- obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
- obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
-diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
-new file mode 100644
-index 0000000..f20b36b
---- /dev/null
-+++ b/drivers/spi/spi-efm32.c
-@@ -0,0 +1,481 @@
-+/*
-+ * Copyright (C) 2012 Uwe Kleine-Koenig for Pengutronix
-+ *
-+ * This program is free software; you can redistribute it and/or modify it under
-+ * the terms of the GNU General Public License version 2 as published by the
-+ * Free Software Foundation.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/io.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spi_bitbang.h>
-+#include <linux/gpio.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/module.h>
-+#include <linux/of_gpio.h>
-+
-+#define DRIVER_NAME "efm32-spi"
-+
-+#define REG_CTRL 0x00
-+#define REG_CTRL_SYNC 0x0001
-+#define REG_CTRL_CLKPOL 0x0100
-+#define REG_CTRL_CLKPHA 0x0200
-+#define REG_CTRL_MSBF 0x0400
-+#define REG_CTRL_TXBIL 0x1000
-+
-+#define REG_FRAME 0x04
-+#define REG_FRAME_DATABITS__MASK 0x000f
-+#define REG_FRAME_DATABITS(n) ((n) - 3)
-+
-+#define REG_CMD 0x0c
-+#define REG_CMD_RXEN 0x0001
-+#define REG_CMD_RXDIS 0x0002
-+#define REG_CMD_TXEN 0x0004
-+#define REG_CMD_TXDIS 0x0008
-+#define REG_CMD_MASTEREN 0x0010
-+
-+#define REG_STATUS 0x10
-+#define REG_STATUS_TXENS 0x0002
-+#define REG_STATUS_TXC 0x0020
-+#define REG_STATUS_TXBL 0x0040
-+#define REG_STATUS_RXDATAV 0x0080
-+
-+#define REG_CLKDIV 0x14
-+
-+#define REG_RXDATAX 0x18
-+#define REG_RXDATAX_RXDATA__MASK 0x01ff
-+#define REG_RXDATAX_PERR 0x4000
-+#define REG_RXDATAX_FERR 0x8000
-+
-+#define REG_TXDATA 0x34
-+
-+#define REG_IF 0x40
-+#define REG_IF_TXBL 0x0002
-+#define REG_IF_RXDATAV 0x0004
-+
-+#define REG_IFS 0x44
-+#define REG_IFC 0x48
-+#define REG_IEN 0x4c
-+
-+#define REG_ROUTE 0x54
-+#define REG_ROUTE_RXPEN 0x0001
-+#define REG_ROUTE_TXPEN 0x0002
-+#define REG_ROUTE_CLKPEN 0x0008
-+#define REG_ROUTE_LOCATION__MASK 0x0700
-+#define REG_ROUTE_LOCATION(n) (((n) << 8) & REG_ROUTE_LOCATION__MASK)
-+
-+struct efm32_spi_ddata {
-+ /* bitbang must be the first member */
-+ struct spi_bitbang bitbang;
-+
-+ spinlock_t lock;
-+
-+ struct clk *clk;
-+ void __iomem *base;
-+ unsigned int rxirq, txirq;
-+
-+ /* irq data */
-+ struct completion done;
-+ const void *tx_buf;
-+ void *rx_buf;
-+ unsigned tx_len, rx_len;
-+ unsigned csgpio[];
-+};
-+
-+static void efm32_spi_write32(struct efm32_spi_ddata *ddata,
-+ u32 value, unsigned offset)
-+{
-+ writel_relaxed(value, ddata->base + offset);
-+}
-+
-+static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset)
-+{
-+ return readl_relaxed(ddata->base + offset);
-+}
-+
-+static int efm32_spi_setup(struct spi_device *spi)
-+{
-+ pr_debug("%s\n", __func__);
-+
-+ return 0;
-+
-+}
-+
-+static void efm32_spi_cleanup(struct spi_device *spi)
-+{
-+ pr_debug("%s\n", __func__);
-+}
-+
-+static void efm32_spi_chipselect(struct spi_device *spi, int is_on)
-+{
-+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
-+ int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE);
-+
-+ gpio_set_value(ddata->csgpio[spi->chip_select], value);
-+}
-+
-+static int efm32_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
-+{
-+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
-+
-+ unsigned bpw = t && t->bits_per_word ?
-+ t->bits_per_word : spi->bits_per_word;
-+ unsigned speed = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
-+ unsigned long clkfreq = clk_get_rate(ddata->clk);
-+ u32 clkdiv;
-+
-+ efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF |
-+ (spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) |
-+ (spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL);
-+
-+ efm32_spi_write32(ddata,
-+ REG_FRAME_DATABITS(bpw), REG_FRAME);
-+ /* XXX */
-+ if (2 * speed >= clkfreq)
-+ clkdiv = 0;
-+ else
-+ clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4);
-+
-+ if (clkdiv > (1U << 21))
-+ return -EINVAL;
-+
-+ efm32_spi_write32(ddata, clkdiv, REG_CLKDIV);
-+ efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD);
-+ efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD);
-+
-+ return 0;
-+}
-+
-+#define DEFINE_EFM32_SPI_XFER(type) \
-+static void efm32_spi_tx_ ## type(struct efm32_spi_ddata *ddata) \
-+{ \
-+ type val = 0; \
-+ \
-+ if (ddata->tx_len >= sizeof(type)) { \
-+ if (ddata->tx_buf) { \
-+ val = *(type *)ddata->tx_buf; \
-+ ddata->tx_buf += sizeof(type); \
-+ } \
-+ \
-+ ddata->tx_len -= sizeof(type); \
-+ efm32_spi_write32(ddata, val, REG_TXDATA); \
-+ pr_debug("%s: tx 0x%x\n", __func__, val); \
-+ } \
-+} \
-+ \
-+static void efm32_spi_rx_ ## type(struct efm32_spi_ddata *ddata) \
-+{ \
-+ if (ddata->rx_len >= sizeof(type)) { \
-+ u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX); \
-+ pr_debug("%s: rx 0x%x\n", __func__, rxdata); \
-+ \
-+ if (ddata->rx_buf) { \
-+ *(type *)ddata->rx_buf = rxdata; \
-+ ddata->rx_buf += sizeof(type); \
-+ } \
-+ \
-+ ddata->rx_len -= sizeof(type); \
-+ } \
-+}
-+
-+DEFINE_EFM32_SPI_XFER(u8)
-+
-+static void efm32_spi_filltx(struct efm32_spi_ddata *ddata)
-+{
-+ while (ddata->tx_len &&
-+ ddata->tx_len + 2 /* XXX * bpw */ > ddata->rx_len &&
-+ efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) {
-+ efm32_spi_tx_u8(ddata);
-+ }
-+}
-+
-+static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
-+{
-+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
-+ int ret = -EBUSY;
-+
-+ spin_lock_irq(&ddata->lock);
-+
-+ if (ddata->tx_buf || ddata->rx_buf)
-+ goto out_unlock;
-+
-+ ddata->tx_buf = t->tx_buf;
-+ ddata->rx_buf = t->rx_buf;
-+ ddata->tx_len = ddata->rx_len = t->len;
-+
-+ efm32_spi_filltx(ddata);
-+
-+ init_completion(&ddata->done);
-+
-+ efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
-+
-+ spin_unlock_irq(&ddata->lock);
-+
-+ wait_for_completion(&ddata->done);
-+
-+ spin_lock_irq(&ddata->lock);
-+
-+ ret = t->len - max(ddata->tx_len, ddata->rx_len);
-+
-+ efm32_spi_write32(ddata, 0, REG_IEN);
-+ ddata->tx_buf = ddata->rx_buf = NULL;
-+
-+out_unlock:
-+ spin_unlock_irq(&ddata->lock);
-+
-+ return ret;
-+}
-+
-+static irqreturn_t efm32_spi_rxirq(int irq, void *data)
-+{
-+ struct efm32_spi_ddata *ddata = data;
-+ irqreturn_t ret = IRQ_NONE;
-+
-+ spin_lock(&ddata->lock);
-+
-+ while (ddata->rx_len > 0 &&
-+ efm32_spi_read32(ddata, REG_STATUS) &
-+ REG_STATUS_RXDATAV) {
-+ efm32_spi_rx_u8(ddata);
-+
-+ ret = IRQ_HANDLED;
-+ }
-+
-+ if (!ddata->rx_len) {
-+ u32 ien = efm32_spi_read32(ddata, REG_IEN);
-+
-+ ien &= ~REG_IF_RXDATAV;
-+
-+ efm32_spi_write32(ddata, ien, REG_IEN);
-+
-+ complete(&ddata->done);
-+ }
-+
-+ spin_unlock(&ddata->lock);
-+
-+ return ret;
-+}
-+
-+static irqreturn_t efm32_spi_txirq(int irq, void *data)
-+{
-+ struct efm32_spi_ddata *ddata = data;
-+
-+ pr_debug("%s: txlen = %u, rxlen = %u, if=0x%08x, status=0x%08x\n",
-+ __func__, ddata->tx_len, ddata->rx_len,
-+ efm32_spi_read32(ddata, REG_IF),
-+ efm32_spi_read32(ddata, REG_STATUS));
-+
-+ spin_lock(&ddata->lock);
-+
-+ efm32_spi_filltx(ddata);
-+
-+ pr_debug("%s: txlen = %u, rxlen = %u\n", __func__,
-+ ddata->tx_len, ddata->rx_len);
-+
-+ if (!ddata->tx_len) {
-+ u32 ien = efm32_spi_read32(ddata, REG_IEN);
-+
-+ ien &= ~REG_IF_TXBL;
-+
-+ efm32_spi_write32(ddata, ien, REG_IEN);
-+ pr_debug("disable TXBL\n");
-+ }
-+
-+ spin_unlock(&ddata->lock);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int efm32_spi_probe(struct platform_device *pdev)
-+{
-+ struct efm32_spi_ddata *ddata;
-+ struct resource *res;
-+ int ret;
-+ struct spi_master *master;
-+ struct device_node *np = pdev->dev.of_node;
-+ unsigned int num_cs, i;
-+
-+ num_cs = of_gpio_named_count(np, "cs-gpios");
-+
-+ master = spi_alloc_master(&pdev->dev,
-+ sizeof(*ddata) + num_cs * sizeof(unsigned));
-+ if (!master) {
-+ dev_dbg(&pdev->dev,
-+ "failed to allocate spi master controller\n");
-+ return -ENOMEM;
-+ }
-+ platform_set_drvdata(pdev, master);
-+
-+ master->dev.of_node = pdev->dev.of_node;
-+
-+ master->bus_num = pdev->id;
-+ master->num_chipselect = num_cs;
-+ master->setup = efm32_spi_setup;
-+ master->cleanup = efm32_spi_cleanup;
-+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-+
-+ ddata = spi_master_get_devdata(master);
-+
-+ ddata->bitbang.master = spi_master_get(master);
-+ ddata->bitbang.chipselect = efm32_spi_chipselect;
-+ ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
-+ ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
-+
-+ spin_lock_init(&ddata->lock);
-+
-+ ddata->clk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(ddata->clk)) {
-+ ret = PTR_ERR(ddata->clk);
-+ dev_dbg(&pdev->dev, "failed to get clock: %d\n", ret);
-+ goto err_clk_get;
-+ }
-+
-+ for (i = 0; i < num_cs; ++i) {
-+ ret = of_get_named_gpio(np, "cs-gpios", i);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n",
-+ i, ret);
-+ //goto err_get_csgpio;
-+ }
-+ ddata->csgpio[i] = ret;
-+ dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]);
-+ ret = gpio_request_one(ddata->csgpio[i],
-+ GPIOF_OUT_INIT_LOW, DRIVER_NAME);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev,
-+ "failed to configure csgpio#%u (%d)\n",
-+ i, ret);
-+ //goto err_csgpio_request;
-+ }
-+ }
-+
-+ /* XXX: enable only on demand */
-+ ret = clk_prepare_enable(ddata->clk);
-+ if (ret < 0) {
-+ dev_dbg(&pdev->dev, "failed to enable clock: %d\n", ret);
-+ goto err_clk_enable;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ ret = -ENODEV;
-+ dev_dbg(&pdev->dev, "failed to determine base address\n");
-+ goto err_get_base;
-+ }
-+
-+ if (resource_size(res) < 60) {
-+ ret = -EINVAL;
-+ dev_dbg(&pdev->dev, "memory resource too small\n");
-+ goto err_too_small;
-+ }
-+
-+ /* XXX: request_mem_region? */
-+
-+ ddata->base = ioremap(res->start, resource_size(res));
-+ if (!ddata->base) {
-+ ret = -ENOMEM;
-+ dev_dbg(&pdev->dev, "failed to remap memory\n");
-+ goto err_ioremap;
-+ }
-+
-+ ret = platform_get_irq(pdev, 0);
-+ if (ret <= 0) {
-+ dev_dbg(&pdev->dev, "failed to get rx irq\n");
-+ goto err_get_rxirq;
-+ }
-+
-+ ddata->rxirq = ret;
-+
-+ ret = platform_get_irq(pdev, 1);
-+ if (ret <= 0)
-+ ret = ddata->rxirq + 1;
-+
-+ ddata->txirq = ret;
-+
-+ efm32_spi_write32(ddata, 0, REG_IEN);
-+ efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
-+ REG_ROUTE_CLKPEN | REG_ROUTE_LOCATION(1), REG_ROUTE);
-+
-+ ret = request_irq(ddata->rxirq, efm32_spi_rxirq, 0, DRIVER_NAME, ddata);
-+ if (ret) {
-+ dev_dbg(&pdev->dev, "failed to register rxirq (%d)\n", ret);
-+ goto err_request_rxirq;
-+ }
-+
-+ ret = request_irq(ddata->txirq, efm32_spi_txirq, 0, DRIVER_NAME, ddata);
-+ if (ret) {
-+ dev_dbg(&pdev->dev, "failed to register txirq (%d)\n", ret);
-+ goto err_request_txirq;
-+ }
-+
-+ ret = spi_bitbang_start(&ddata->bitbang);
-+ if (ret) {
-+ dev_dbg(&pdev->dev, "spi_bitbang_start failed: %d\n", ret);
-+
-+ free_irq(ddata->txirq, ddata);
-+err_request_txirq:
-+
-+ free_irq(ddata->rxirq, ddata);
-+err_request_rxirq:
-+err_get_rxirq:
-+ iounmap(ddata->base);
-+err_ioremap:
-+err_too_small:
-+err_get_base:
-+ clk_disable_unprepare(ddata->clk);
-+err_clk_enable:
-+ clk_put(ddata->clk);
-+err_clk_get:
-+ platform_set_drvdata(pdev, NULL);
-+ spi_master_put(master);
-+ kfree(master);
-+ }
-+
-+ pr_debug("%s returns %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+static int efm32_spi_remove(struct platform_device *pdev)
-+{
-+ struct spi_master *master = platform_get_drvdata(pdev);
-+ struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
-+
-+ free_irq(ddata->txirq, ddata);
-+ free_irq(ddata->rxirq, ddata);
-+ iounmap(ddata->base);
-+ clk_put(ddata->clk);
-+ platform_set_drvdata(pdev, NULL);
-+ spi_master_put(master);
-+ kfree(master);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id efm32_spi_dt_ids[] = {
-+ {
-+ .compatible = "efm32,spi",
-+ }, {
-+ /* sentinel */
-+ }
-+};
-+MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
-+
-+static struct platform_driver efm32_spi_driver = {
-+ .probe = efm32_spi_probe,
-+ .remove = efm32_spi_remove,
-+
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .of_match_table = efm32_spi_dt_ids,
-+ },
-+};
-+module_platform_driver(efm32_spi_driver);
-+
-+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
-+MODULE_DESCRIPTION("EFM32 SPI driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:" DRIVER_NAME);