* [PATCH] spi: Add SuperH HSPI prototype driver
@ 2011-12-27 8:35 Kuninori Morimoto
[not found] ` <87vcp2tnst.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
0 siblings, 1 reply; 8+ messages in thread
From: Kuninori Morimoto @ 2011-12-27 8:35 UTC (permalink / raw)
To: Grant Likely
Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus,
Kuninori Morimoto
This patch adds SuperH HSPI driver.
It is still prototype driver, but has enough function at this point.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
---
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-sh-hspi.c | 375 +++++++++++++++++++++++++++++++++++++++++++
include/linux/spi/sh_hspi.h | 34 ++++
4 files changed, 416 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/spi-sh-hspi.c
create mode 100644 include/linux/spi/sh_hspi.h
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 52e2900..c5e5fe6 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -325,6 +325,12 @@ config SPI_SH_SCI
help
SPI driver for SuperH SCI blocks.
+config SPI_SH_HSPI
+ tristate "SuperH HSPI controller"
+ depends on ARCH_SHMOBILE
+ help
+ SPI driver for SuperH HSPI blocks.
+
config SPI_STMP3XXX
tristate "Freescale STMP37xx/378x SPI/SSP controller"
depends on ARCH_STMP3XXX && SPI_MASTER
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 61c3261..d65e059 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
obj-$(CONFIG_SPI_SH) += spi-sh.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
+obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o
obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
new file mode 100644
index 0000000..ee4c8e6
--- /dev/null
+++ b/drivers/spi/spi-sh-hspi.c
@@ -0,0 +1,375 @@
+/*
+ * SuperH HSPI bus driver
+ *
+ * Copyright (C) 2011 Kuninori Morimoto
+ *
+ * Based on spi-sh.c:
+ * Based on pxa2xx_spi.c:
+ * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/sh_hspi.h>
+
+#define SPCR 0x00
+#define SPSR 0x04
+#define SPSCR 0x08
+#define SPTBR 0x0C
+#define SPRBR 0x10
+#define SPCR2 0x14
+
+/* SPSR */
+#define RXFL (1 << 2)
+
+#define hspi2info(h) (h->dev->platform_data)
+
+struct hspi_priv {
+ void __iomem *addr;
+ struct spi_master *master;
+ struct list_head queue;
+ struct workqueue_struct *workqueue;
+ struct work_struct ws;
+ struct device *dev;
+ spinlock_t lock;
+};
+
+/*
+ * basic function
+ */
+static void hspi_write(struct hspi_priv *hspi, int reg, u32 val)
+{
+ iowrite32(val, hspi->addr + reg);
+}
+
+static u8 hspi_read(struct hspi_priv *hspi, int reg)
+{
+ return (u8)ioread32(hspi->addr + reg);
+}
+
+/*
+static void hspi_bset(struct hspi_priv *hspi, int reg, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = (u32)hspi_read(hspi, reg);
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ hspi_write(hspi, tmp, reg);
+}
+*/
+/*
+ * transfer function
+ */
+static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
+{
+ int t = 256;
+
+ while (t--) {
+ if ((mask & hspi_read(hspi, SPSR)) == val)
+ return 0;
+
+ mdelay(10);
+ }
+
+ dev_err(hspi->dev, "timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int hspi_push(struct hspi_priv *hspi, struct spi_message *msg,
+ struct spi_transfer *t)
+{
+ int i, ret;
+ u8 *data = (u8 *)t->tx_buf;
+
+ /*
+ * FIXME
+ * very simple, but polling transfer
+ */
+ for (i = 0; i < t->len; i++) {
+ /* wait remains */
+ ret = hspi_status_check_timeout(hspi, 0x1, 0x0);
+ if (ret < 0)
+ return ret;
+
+ hspi_write(hspi, SPTBR, (u32)data[i]);
+
+ /* wait recive */
+ ret = hspi_status_check_timeout(hspi, 0x4, 0x4);
+ if (ret < 0)
+ return ret;
+
+ /* dummy read */
+ hspi_read(hspi, SPRBR);
+ }
+
+ return 0;
+}
+
+static int hspi_pop(struct hspi_priv *hspi, struct spi_message *msg,
+ struct spi_transfer *t)
+{
+ int i;
+ u8 *data = (u8 *)t->rx_buf;
+
+ /*
+ * FIXME
+ * very simple, but polling receive
+ */
+ for (i = 0; i < t->len; i++) {
+ /* wait remains */
+ while ((0x1 & hspi_read(hspi, SPSR)))
+ mdelay(10);
+
+ /* dummy write */
+ hspi_write(hspi, SPTBR, 0x0);
+
+ /* wait recive */
+ while (!(0x4 & hspi_read(hspi, SPSR)))
+ mdelay(10);
+
+ data[i] = (u8)hspi_read(hspi, SPRBR);
+ }
+
+ return 0;
+}
+
+static void hspi_work(struct work_struct *work)
+{
+ struct hspi_priv *hspi = container_of(work, struct hspi_priv, ws);
+ struct sh_hspi_info *info = hspi2info(hspi);
+ struct spi_message *msg;
+ struct spi_transfer *t;
+ unsigned long flags;
+ u32 data;
+ int ret;
+
+ dev_dbg(hspi->dev, "%s\n", __func__);
+
+ /************************ pm enable ************************/
+ pm_runtime_get_sync(hspi->dev);
+
+ /* setup first of all in under pm_runtime */
+ data = SH_HSPI_CLK_DIVC(info->flags);
+
+ if (info->flags & SH_HSPI_FBS)
+ data |= 1 << 7;
+ if (info->flags & SH_HSPI_CLKP_HIGH)
+ data |= 1 << 6;
+ if (info->flags & SH_HSPI_IDIV_DIV128)
+ data |= 1 << 5;
+
+ hspi_write(hspi, SPCR, data);
+ hspi_write(hspi, SPSR, 0x0);
+ hspi_write(hspi, SPSCR, 0x1); /* master mode */
+
+ while (1) {
+ msg = NULL;
+
+ /************************ spin lock ************************/
+ spin_lock_irqsave(&hspi->lock, flags);
+ if (!list_empty(&hspi->queue)) {
+ msg = list_entry(hspi->queue.next,
+ struct spi_message, queue);
+ list_del_init(&msg->queue);
+ }
+ spin_unlock_irqrestore(&hspi->lock, flags);
+ /************************ spin unlock ************************/
+ if (!msg)
+ break;
+
+ ret = 0;
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ if (t->tx_buf) {
+ ret = hspi_push(hspi, msg, t);
+ if (ret < 0)
+ goto error;
+ }
+ if (t->rx_buf) {
+ ret = hspi_pop(hspi, msg, t);
+ if (ret < 0)
+ goto error;
+ }
+ msg->actual_length += t->len;
+ }
+error:
+ msg->status = ret;
+ msg->complete(msg->context);
+ }
+
+ pm_runtime_put_sync(hspi->dev);
+ /************************ pm disable ************************/
+
+ return;
+}
+
+/*
+ * spi master function
+ */
+static int hspi_setup(struct spi_device *spi)
+{
+ struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
+ struct device *dev = hspi->dev;
+
+ if (8 != spi->bits_per_word) {
+ dev_err(dev, "bits_per_word shluld be 8\n");
+ return -EIO;
+ }
+
+ dev_dbg(dev, "%s setup\n", spi->modalias);
+
+ return 0;
+}
+
+static void hspi_cleanup(struct spi_device *spi)
+{
+ struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
+ struct device *dev = hspi->dev;
+
+ dev_dbg(dev, "%s cleanup\n", spi->modalias);
+}
+
+static int hspi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ /************************ spin lock ************************/
+ spin_lock_irqsave(&hspi->lock, flags);
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ list_add_tail(&msg->queue, &hspi->queue);
+
+ spin_unlock_irqrestore(&hspi->lock, flags);
+ /************************ spin unlock ************************/
+
+ queue_work(hspi->workqueue, &hspi->ws);
+
+ return 0;
+}
+
+static int __devinit hspi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct spi_master *master;
+ struct hspi_priv *hspi;
+ const char *devname;
+ int ret;
+
+ /* get base addr */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "invalid resource\n");
+ return -EINVAL;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct hspi_priv));
+ if (!master) {
+ dev_err(&pdev->dev, "spi_alloc_master error.\n");
+ return -ENOMEM;
+ }
+
+ hspi = spi_master_get_devdata(master);
+ dev_set_drvdata(&pdev->dev, hspi);
+
+ devname = dev_name(&pdev->dev);
+
+ /* init hspi */
+ hspi->master = master;
+ hspi->dev = &pdev->dev;
+ hspi->addr = ioremap(res->start, resource_size(res));
+ if (!hspi->addr) {
+ dev_err(&pdev->dev, "ioremap error.\n");
+ ret = -ENOMEM;
+ goto error1;
+ }
+ hspi->workqueue = create_singlethread_workqueue(devname);
+ if (!hspi->workqueue) {
+ dev_err(&pdev->dev, "create workqueue error\n");
+ ret = -EBUSY;
+ goto error2;
+ }
+
+ spin_lock_init(&hspi->lock);
+ INIT_LIST_HEAD(&hspi->queue);
+ INIT_WORK(&hspi->ws, hspi_work);
+
+ master->num_chipselect = 1;
+ master->bus_num = pdev->id;
+ master->setup = hspi_setup;
+ master->transfer = hspi_transfer;
+ master->cleanup = hspi_cleanup;
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+ ret = spi_register_master(master);
+ if (ret < 0) {
+ printk(KERN_ERR "spi_register_master error.\n");
+ goto error3;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ dev_info(&pdev->dev, "%s probed\n", devname);
+
+ return 0;
+
+ error3:
+ destroy_workqueue(hspi->workqueue);
+ error2:
+ iounmap(hspi->addr);
+ error1:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int __devexit hspi_remove(struct platform_device *pdev)
+{
+ struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ destroy_workqueue(hspi->workqueue);
+ iounmap(hspi->addr);
+ spi_unregister_master(hspi->master);
+
+ return 0;
+}
+
+static struct platform_driver hspi_driver = {
+ .probe = hspi_probe,
+ .remove = __devexit_p(hspi_remove),
+ .driver = {
+ .name = "sh-hspi",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(hspi_driver);
+
+MODULE_DESCRIPTION("SuperH HSPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>");
+MODULE_ALIAS("platform:sh_spi");
diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h
new file mode 100644
index 0000000..956d112
--- /dev/null
+++ b/include/linux/spi/sh_hspi.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Kuninori Morimoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef SH_HSPI_H
+#define SH_HSPI_H
+
+/*
+ * flags
+ *
+ *
+ */
+#define SH_HSPI_CLK_DIVC(d) (d & 0xFF)
+
+#define SH_HSPI_FBS (1 << 8)
+#define SH_HSPI_CLKP_HIGH (1 << 9) /* default LOW */
+#define SH_HSPI_IDIV_DIV128 (1 << 10) /* default div16 */
+struct sh_hspi_info {
+ u32 flags;
+};
+
+#endif
--
1.7.5.4
------------------------------------------------------------------------------
Write once. Port to many.
Get the SDK and tools to simplify cross-platform app development. Create
new or port existing apps to sell to consumers worldwide. Explore the
Intel AppUpSM program developer opportunity. appdeveloper.intel.com/join
http://p.sf.net/sfu/intel-appdev
^ permalink raw reply related [flat|nested] 8+ messages in thread[parent not found: <87vcp2tnst.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>]
* Re: [PATCH] spi: Add SuperH HSPI prototype driver [not found] ` <87vcp2tnst.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> @ 2012-01-04 20:05 ` Grant Likely [not found] ` <20120104200548.GH15503-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Grant Likely @ 2012-01-04 20:05 UTC (permalink / raw) To: Kuninori Morimoto Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus, Kuninori Morimoto On Tue, Dec 27, 2011 at 12:35:18AM -0800, Kuninori Morimoto wrote: > This patch adds SuperH HSPI driver. > It is still prototype driver, but has enough function at this point. > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> Some brief comments below... > --- > +static int hspi_pop(struct hspi_priv *hspi, struct spi_message *msg, > + struct spi_transfer *t) > +{ > + int i; > + u8 *data = (u8 *)t->rx_buf; > + > + /* > + * FIXME > + * very simple, but polling receive > + */ > + for (i = 0; i < t->len; i++) { > + /* wait remains */ > + while ((0x1 & hspi_read(hspi, SPSR))) > + mdelay(10); > + > + /* dummy write */ > + hspi_write(hspi, SPTBR, 0x0); > + > + /* wait recive */ > + while (!(0x4 & hspi_read(hspi, SPSR))) > + mdelay(10); Those mdelays are really expensive. Can the driver sleep instead? > + > + data[i] = (u8)hspi_read(hspi, SPRBR); > + } > + > + return 0; > +} > + > +static void hspi_work(struct work_struct *work) > +{ > + struct hspi_priv *hspi = container_of(work, struct hspi_priv, ws); > + struct sh_hspi_info *info = hspi2info(hspi); > + struct spi_message *msg; > + struct spi_transfer *t; > + unsigned long flags; > + u32 data; > + int ret; > + > + dev_dbg(hspi->dev, "%s\n", __func__); > + > + /************************ pm enable ************************/ > + pm_runtime_get_sync(hspi->dev); > + > + /* setup first of all in under pm_runtime */ > + data = SH_HSPI_CLK_DIVC(info->flags); > + > + if (info->flags & SH_HSPI_FBS) > + data |= 1 << 7; > + if (info->flags & SH_HSPI_CLKP_HIGH) > + data |= 1 << 6; > + if (info->flags & SH_HSPI_IDIV_DIV128) > + data |= 1 << 5; > + > + hspi_write(hspi, SPCR, data); > + hspi_write(hspi, SPSR, 0x0); > + hspi_write(hspi, SPSCR, 0x1); /* master mode */ > + > + while (1) { > + msg = NULL; > + > + /************************ spin lock ************************/ > + spin_lock_irqsave(&hspi->lock, flags); > + if (!list_empty(&hspi->queue)) { > + msg = list_entry(hspi->queue.next, > + struct spi_message, queue); > + list_del_init(&msg->queue); > + } > + spin_unlock_irqrestore(&hspi->lock, flags); > + /************************ spin unlock ************************/ > + if (!msg) > + break; > + > + ret = 0; > + list_for_each_entry(t, &msg->transfers, transfer_list) { > + if (t->tx_buf) { > + ret = hspi_push(hspi, msg, t); > + if (ret < 0) > + goto error; > + } > + if (t->rx_buf) { > + ret = hspi_pop(hspi, msg, t); > + if (ret < 0) > + goto error; > + } > + msg->actual_length += t->len; > + } > +error: > + msg->status = ret; > + msg->complete(msg->context); > + } > + > + pm_runtime_put_sync(hspi->dev); > + /************************ pm disable ************************/ > + > + return; > +} > + > +/* > + * spi master function > + */ > +static int hspi_setup(struct spi_device *spi) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + struct device *dev = hspi->dev; > + > + if (8 != spi->bits_per_word) { > + dev_err(dev, "bits_per_word shluld be 8\n"); typo > + return -EIO; > + } > + > + dev_dbg(dev, "%s setup\n", spi->modalias); > + > + return 0; > +} > + > +static void hspi_cleanup(struct spi_device *spi) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + struct device *dev = hspi->dev; > + > + dev_dbg(dev, "%s cleanup\n", spi->modalias); > +} > + > +static int hspi_transfer(struct spi_device *spi, struct spi_message *msg) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + unsigned long flags; > + > + /************************ spin lock ************************/ > + spin_lock_irqsave(&hspi->lock, flags); > + > + msg->actual_length = 0; > + msg->status = -EINPROGRESS; > + list_add_tail(&msg->queue, &hspi->queue); > + > + spin_unlock_irqrestore(&hspi->lock, flags); > + /************************ spin unlock ************************/ > + > + queue_work(hspi->workqueue, &hspi->ws); > + > + return 0; > +} > + > +static int __devinit hspi_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + struct spi_master *master; > + struct hspi_priv *hspi; > + const char *devname; > + int ret; > + > + /* get base addr */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(&pdev->dev, "invalid resource\n"); > + return -EINVAL; > + } > + > + master = spi_alloc_master(&pdev->dev, sizeof(struct hspi_priv)); sizeof(*hspi) > + if (!master) { > + dev_err(&pdev->dev, "spi_alloc_master error.\n"); > + return -ENOMEM; > + } > + > + hspi = spi_master_get_devdata(master); > + dev_set_drvdata(&pdev->dev, hspi); > + > + devname = dev_name(&pdev->dev); > + > + /* init hspi */ > + hspi->master = master; > + hspi->dev = &pdev->dev; > + hspi->addr = ioremap(res->start, resource_size(res)); > + if (!hspi->addr) { > + dev_err(&pdev->dev, "ioremap error.\n"); > + ret = -ENOMEM; > + goto error1; > + } > + hspi->workqueue = create_singlethread_workqueue(devname); nit: After addressing my comment below, devname is referenced exactly once after being set. create_singlethread_workqueue(dev_name(&pdev->dev)) is sufficient here. > + if (!hspi->workqueue) { > + dev_err(&pdev->dev, "create workqueue error\n"); > + ret = -EBUSY; > + goto error2; > + } > + > + spin_lock_init(&hspi->lock); > + INIT_LIST_HEAD(&hspi->queue); > + INIT_WORK(&hspi->ws, hspi_work); > + > + master->num_chipselect = 1; > + master->bus_num = pdev->id; > + master->setup = hspi_setup; > + master->transfer = hspi_transfer; > + master->cleanup = hspi_cleanup; > + master->mode_bits = SPI_CPOL | SPI_CPHA; > + ret = spi_register_master(master); > + if (ret < 0) { > + printk(KERN_ERR "spi_register_master error.\n"); dev_err() > + goto error3; > + } > + > + pm_runtime_enable(&pdev->dev); > + > + dev_info(&pdev->dev, "%s probed\n", devname); dev_info() prints the devname already. This line prints it twice. > + > + return 0; > + > + error3: > + destroy_workqueue(hspi->workqueue); > + error2: > + iounmap(hspi->addr); > + error1: > + spi_master_put(master); > + > + return ret; > +} > + > +static int __devexit hspi_remove(struct platform_device *pdev) > +{ > + struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev); > + > + pm_runtime_disable(&pdev->dev); > + > + destroy_workqueue(hspi->workqueue); > + iounmap(hspi->addr); > + spi_unregister_master(hspi->master); Must unregister the master *before* unmapping it and destroying the workqueue. > + > + return 0; > +} ------------------------------------------------------------------------------ Ridiculously easy VDI. With Citrix VDI-in-a-Box, you don't need a complex infrastructure or vast IT resources to deliver seamless, secure access to virtual desktops. With this all-in-one solution, easily deploy virtual desktops for less than the cost of PCs and save 60% on VDI infrastructure costs. Try it free! http://p.sf.net/sfu/Citrix-VDIinabox ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <20120104200548.GH15503-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org>]
* [PATCH v2] spi: Add SuperH HSPI prototype driver [not found] ` <20120104200548.GH15503-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org> @ 2012-01-06 6:00 ` Kuninori Morimoto [not found] ` <871urd9xq0.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Kuninori Morimoto @ 2012-01-06 6:00 UTC (permalink / raw) To: Grant Likely Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus, Kuninori Morimoto This patch adds SuperH HSPI driver. It is still prototype driver, but has enough function at this point. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> --- v1 -> v2 - mdelay() -> msleep() - typo fix - sizeof(struct hspi_priv) -> sizeof(*hspi) - remove "devname" - use dev_err() instead of printk(KERN_ERR, ) - modiry spi_unregister_master() timing drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-sh-hspi.c | 363 +++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/sh_hspi.h | 34 ++++ 4 files changed, 404 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi-sh-hspi.c create mode 100644 include/linux/spi/sh_hspi.h diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a1fd73d..33bb33e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -325,6 +325,12 @@ config SPI_SH_SCI help SPI driver for SuperH SCI blocks. +config SPI_SH_HSPI + tristate "SuperH HSPI controller" + depends on ARCH_SHMOBILE + help + SPI driver for SuperH HSPI blocks. + config SPI_STMP3XXX tristate "Freescale STMP37xx/378x SPI/SSP controller" depends on ARCH_STMP3XXX && SPI_MASTER diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 61c3261..d65e059 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_SH) += spi-sh.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o +obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c new file mode 100644 index 0000000..f527d24 --- /dev/null +++ b/drivers/spi/spi-sh-hspi.c @@ -0,0 +1,363 @@ +/* + * SuperH HSPI bus driver + * + * Copyright (C) 2011 Kuninori Morimoto + * + * Based on spi-sh.c: + * Based on pxa2xx_spi.c: + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/spi/sh_hspi.h> + +#define SPCR 0x00 +#define SPSR 0x04 +#define SPSCR 0x08 +#define SPTBR 0x0C +#define SPRBR 0x10 +#define SPCR2 0x14 + +/* SPSR */ +#define RXFL (1 << 2) + +#define hspi2info(h) (h->dev->platform_data) + +struct hspi_priv { + void __iomem *addr; + struct spi_master *master; + struct list_head queue; + struct workqueue_struct *workqueue; + struct work_struct ws; + struct device *dev; + spinlock_t lock; +}; + +/* + * basic function + */ +static void hspi_write(struct hspi_priv *hspi, int reg, u32 val) +{ + iowrite32(val, hspi->addr + reg); +} + +static u8 hspi_read(struct hspi_priv *hspi, int reg) +{ + return (u8)ioread32(hspi->addr + reg); +} + +/* + * transfer function + */ +static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) +{ + int t = 256; + + while (t--) { + if ((mask & hspi_read(hspi, SPSR)) == val) + return 0; + + msleep(10); + } + + dev_err(hspi->dev, "timeout\n"); + return -ETIMEDOUT; +} + +static int hspi_push(struct hspi_priv *hspi, struct spi_message *msg, + struct spi_transfer *t) +{ + int i, ret; + u8 *data = (u8 *)t->tx_buf; + + /* + * FIXME + * very simple, but polling transfer + */ + for (i = 0; i < t->len; i++) { + /* wait remains */ + ret = hspi_status_check_timeout(hspi, 0x1, 0x0); + if (ret < 0) + return ret; + + hspi_write(hspi, SPTBR, (u32)data[i]); + + /* wait recive */ + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); + if (ret < 0) + return ret; + + /* dummy read */ + hspi_read(hspi, SPRBR); + } + + return 0; +} + +static int hspi_pop(struct hspi_priv *hspi, struct spi_message *msg, + struct spi_transfer *t) +{ + int i, ret; + u8 *data = (u8 *)t->rx_buf; + + /* + * FIXME + * very simple, but polling receive + */ + for (i = 0; i < t->len; i++) { + /* wait remains */ + ret = hspi_status_check_timeout(hspi, 0x1, 0); + if (ret < 0) + return ret; + + /* dummy write */ + hspi_write(hspi, SPTBR, 0x0); + + /* wait recive */ + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); + if (ret < 0) + return ret; + + data[i] = (u8)hspi_read(hspi, SPRBR); + } + + return 0; +} + +static void hspi_work(struct work_struct *work) +{ + struct hspi_priv *hspi = container_of(work, struct hspi_priv, ws); + struct sh_hspi_info *info = hspi2info(hspi); + struct spi_message *msg; + struct spi_transfer *t; + unsigned long flags; + u32 data; + int ret; + + dev_dbg(hspi->dev, "%s\n", __func__); + + /************************ pm enable ************************/ + pm_runtime_get_sync(hspi->dev); + + /* setup first of all in under pm_runtime */ + data = SH_HSPI_CLK_DIVC(info->flags); + + if (info->flags & SH_HSPI_FBS) + data |= 1 << 7; + if (info->flags & SH_HSPI_CLKP_HIGH) + data |= 1 << 6; + if (info->flags & SH_HSPI_IDIV_DIV128) + data |= 1 << 5; + + hspi_write(hspi, SPCR, data); + hspi_write(hspi, SPSR, 0x0); + hspi_write(hspi, SPSCR, 0x1); /* master mode */ + + while (1) { + msg = NULL; + + /************************ spin lock ************************/ + spin_lock_irqsave(&hspi->lock, flags); + if (!list_empty(&hspi->queue)) { + msg = list_entry(hspi->queue.next, + struct spi_message, queue); + list_del_init(&msg->queue); + } + spin_unlock_irqrestore(&hspi->lock, flags); + /************************ spin unlock ************************/ + if (!msg) + break; + + ret = 0; + list_for_each_entry(t, &msg->transfers, transfer_list) { + if (t->tx_buf) { + ret = hspi_push(hspi, msg, t); + if (ret < 0) + goto error; + } + if (t->rx_buf) { + ret = hspi_pop(hspi, msg, t); + if (ret < 0) + goto error; + } + msg->actual_length += t->len; + } +error: + msg->status = ret; + msg->complete(msg->context); + } + + pm_runtime_put_sync(hspi->dev); + /************************ pm disable ************************/ + + return; +} + +/* + * spi master function + */ +static int hspi_setup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + if (8 != spi->bits_per_word) { + dev_err(dev, "bits_per_word should be 8\n"); + return -EIO; + } + + dev_dbg(dev, "%s setup\n", spi->modalias); + + return 0; +} + +static void hspi_cleanup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + dev_dbg(dev, "%s cleanup\n", spi->modalias); +} + +static int hspi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + unsigned long flags; + + /************************ spin lock ************************/ + spin_lock_irqsave(&hspi->lock, flags); + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + list_add_tail(&msg->queue, &hspi->queue); + + spin_unlock_irqrestore(&hspi->lock, flags); + /************************ spin unlock ************************/ + + queue_work(hspi->workqueue, &hspi->ws); + + return 0; +} + +static int __devinit hspi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct spi_master *master; + struct hspi_priv *hspi; + int ret; + + /* get base addr */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid resource\n"); + return -EINVAL; + } + + master = spi_alloc_master(&pdev->dev, sizeof(*hspi)); + if (!master) { + dev_err(&pdev->dev, "spi_alloc_master error.\n"); + return -ENOMEM; + } + + hspi = spi_master_get_devdata(master); + dev_set_drvdata(&pdev->dev, hspi); + + /* init hspi */ + hspi->master = master; + hspi->dev = &pdev->dev; + hspi->addr = ioremap(res->start, resource_size(res)); + if (!hspi->addr) { + dev_err(&pdev->dev, "ioremap error.\n"); + ret = -ENOMEM; + goto error1; + } + hspi->workqueue = create_singlethread_workqueue(dev_name(&pdev->dev)); + if (!hspi->workqueue) { + dev_err(&pdev->dev, "create workqueue error\n"); + ret = -EBUSY; + goto error2; + } + + spin_lock_init(&hspi->lock); + INIT_LIST_HEAD(&hspi->queue); + INIT_WORK(&hspi->ws, hspi_work); + + master->num_chipselect = 1; + master->bus_num = pdev->id; + master->setup = hspi_setup; + master->transfer = hspi_transfer; + master->cleanup = hspi_cleanup; + master->mode_bits = SPI_CPOL | SPI_CPHA; + ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto error3; + } + + pm_runtime_enable(&pdev->dev); + + dev_info(&pdev->dev, "probed\n"); + + return 0; + + error3: + destroy_workqueue(hspi->workqueue); + error2: + iounmap(hspi->addr); + error1: + spi_master_put(master); + + return ret; +} + +static int __devexit hspi_remove(struct platform_device *pdev) +{ + struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + spi_unregister_master(hspi->master); + destroy_workqueue(hspi->workqueue); + iounmap(hspi->addr); + + return 0; +} + +static struct platform_driver hspi_driver = { + .probe = hspi_probe, + .remove = __devexit_p(hspi_remove), + .driver = { + .name = "sh-hspi", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(hspi_driver); + +MODULE_DESCRIPTION("SuperH HSPI bus driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>"); +MODULE_ALIAS("platform:sh_spi"); diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h new file mode 100644 index 0000000..956d112 --- /dev/null +++ b/include/linux/spi/sh_hspi.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef SH_HSPI_H +#define SH_HSPI_H + +/* + * flags + * + * + */ +#define SH_HSPI_CLK_DIVC(d) (d & 0xFF) + +#define SH_HSPI_FBS (1 << 8) +#define SH_HSPI_CLKP_HIGH (1 << 9) /* default LOW */ +#define SH_HSPI_IDIV_DIV128 (1 << 10) /* default div16 */ +struct sh_hspi_info { + u32 flags; +}; + +#endif -- 1.7.5.4 ------------------------------------------------------------------------------ Ridiculously easy VDI. With Citrix VDI-in-a-Box, you don't need a complex infrastructure or vast IT resources to deliver seamless, secure access to virtual desktops. With this all-in-one solution, easily deploy virtual desktops for less than the cost of PCs and save 60% on VDI infrastructure costs. Try it free! http://p.sf.net/sfu/Citrix-VDIinabox ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <871urd9xq0.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>]
* Re: [PATCH v2] spi: Add SuperH HSPI prototype driver [not found] ` <871urd9xq0.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> @ 2012-02-29 8:03 ` Kuninori Morimoto 2012-03-01 9:26 ` Shubhrajyoti Datta 1 sibling, 0 replies; 8+ messages in thread From: Kuninori Morimoto @ 2012-02-29 8:03 UTC (permalink / raw) To: Grant Likely Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus, Kuninori Morimoto Hi Grant > This patch adds SuperH HSPI driver. > It is still prototype driver, but has enough function at this point. > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> > --- > v1 -> v2 > > - mdelay() -> msleep() > - typo fix > - sizeof(struct hspi_priv) -> sizeof(*hspi) > - remove "devname" > - use dev_err() instead of printk(KERN_ERR, ) > - modiry spi_unregister_master() timing Which branch can I find this patch on your git-tree ? or was it rejected ? Best regards --- Kuninori Morimoto ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2] spi: Add SuperH HSPI prototype driver [not found] ` <871urd9xq0.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> 2012-02-29 8:03 ` Kuninori Morimoto @ 2012-03-01 9:26 ` Shubhrajyoti Datta [not found] ` <CAM=Q2cv3QBLEWp+rQ9f5onBS1j=wZOes5m-r9fs6Uvfu6bnTkg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 8+ messages in thread From: Shubhrajyoti Datta @ 2012-03-01 9:26 UTC (permalink / raw) To: Kuninori Morimoto Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus, Kuninori Morimoto Hi Kuninori, On Fri, Jan 6, 2012 at 11:30 AM, Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> wrote: > This patch adds SuperH HSPI driver. > It is still prototype driver, but has enough function at this point. > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> > --- > v1 -> v2 > > - mdelay() -> msleep() > - typo fix > - sizeof(struct hspi_priv) -> sizeof(*hspi) > - remove "devname" > - use dev_err() instead of printk(KERN_ERR, ) > - modiry spi_unregister_master() timing > > drivers/spi/Kconfig | 6 + > drivers/spi/Makefile | 1 + > drivers/spi/spi-sh-hspi.c | 363 +++++++++++++++++++++++++++++++++++++++++++ > include/linux/spi/sh_hspi.h | 34 ++++ > 4 files changed, 404 insertions(+), 0 deletions(-) > create mode 100644 drivers/spi/spi-sh-hspi.c > create mode 100644 include/linux/spi/sh_hspi.h > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index a1fd73d..33bb33e 100644 > --- a/drivers/spi/Kconfig > +++ b/drivers/spi/Kconfig > @@ -325,6 +325,12 @@ config SPI_SH_SCI > help > SPI driver for SuperH SCI blocks. > > +config SPI_SH_HSPI > + tristate "SuperH HSPI controller" > + depends on ARCH_SHMOBILE > + help > + SPI driver for SuperH HSPI blocks. > + > config SPI_STMP3XXX > tristate "Freescale STMP37xx/378x SPI/SSP controller" > depends on ARCH_STMP3XXX && SPI_MASTER > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index 61c3261..d65e059 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o > obj-$(CONFIG_SPI_SH) += spi-sh.o > obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o > obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o > +obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o > obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o > obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o > obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o > diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c > new file mode 100644 > index 0000000..f527d24 > --- /dev/null > +++ b/drivers/spi/spi-sh-hspi.c > @@ -0,0 +1,363 @@ > +/* > + * SuperH HSPI bus driver > + * > + * Copyright (C) 2011 Kuninori Morimoto > + * > + * Based on spi-sh.c: > + * Based on pxa2xx_spi.c: > + * Copyright (C) 2011 Renesas Solutions Corp. > + * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + * > + */ > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/timer.h> > +#include <linux/delay.h> > +#include <linux/list.h> > +#include <linux/workqueue.h> > +#include <linux/interrupt.h> > +#include <linux/platform_device.h> > +#include <linux/pm_runtime.h> > +#include <linux/io.h> > +#include <linux/spi/spi.h> > +#include <linux/spi/sh_hspi.h> > + > +#define SPCR 0x00 > +#define SPSR 0x04 > +#define SPSCR 0x08 > +#define SPTBR 0x0C > +#define SPRBR 0x10 > +#define SPCR2 0x14 > + > +/* SPSR */ > +#define RXFL (1 << 2) > + > +#define hspi2info(h) (h->dev->platform_data) > + > +struct hspi_priv { > + void __iomem *addr; > + struct spi_master *master; > + struct list_head queue; > + struct workqueue_struct *workqueue; > + struct work_struct ws; > + struct device *dev; > + spinlock_t lock; > +}; > + > +/* > + * basic function > + */ > +static void hspi_write(struct hspi_priv *hspi, int reg, u32 val) > +{ > + iowrite32(val, hspi->addr + reg); > +} > + > +static u8 hspi_read(struct hspi_priv *hspi, int reg) > +{ > + return (u8)ioread32(hspi->addr + reg); You do a ioread32 and then typecast to u8 Didnt undwerstand? > +} > + > +/* > + * transfer function > + */ > +static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) > +{ > + int t = 256; > + > + while (t--) { > + if ((mask & hspi_read(hspi, SPSR)) == val) > + return 0; > + > + msleep(10); > + } > + > + dev_err(hspi->dev, "timeout\n"); > + return -ETIMEDOUT; > +} > + > +static int hspi_push(struct hspi_priv *hspi, struct spi_message *msg, > + struct spi_transfer *t) > +{ > + int i, ret; > + u8 *data = (u8 *)t->tx_buf; > + > + /* > + * FIXME > + * very simple, but polling transfer > + */ > + for (i = 0; i < t->len; i++) { > + /* wait remains */ > + ret = hspi_status_check_timeout(hspi, 0x1, 0x0); > + if (ret < 0) > + return ret; > + > + hspi_write(hspi, SPTBR, (u32)data[i]); > + > + /* wait recive */ > + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); > + if (ret < 0) > + return ret; > + > + /* dummy read */ > + hspi_read(hspi, SPRBR); > + } > + > + return 0; > +} > + > +static int hspi_pop(struct hspi_priv *hspi, struct spi_message *msg, > + struct spi_transfer *t) > +{ > + int i, ret; > + u8 *data = (u8 *)t->rx_buf; > + > + /* > + * FIXME > + * very simple, but polling receive > + */ > + for (i = 0; i < t->len; i++) { > + /* wait remains */ > + ret = hspi_status_check_timeout(hspi, 0x1, 0); > + if (ret < 0) > + return ret; > + > + /* dummy write */ > + hspi_write(hspi, SPTBR, 0x0); > + > + /* wait recive */ > + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); > + if (ret < 0) > + return ret; > + > + data[i] = (u8)hspi_read(hspi, SPRBR); > + } > + > + return 0; > +} > + > +static void hspi_work(struct work_struct *work) > +{ > + struct hspi_priv *hspi = container_of(work, struct hspi_priv, ws); > + struct sh_hspi_info *info = hspi2info(hspi); > + struct spi_message *msg; > + struct spi_transfer *t; > + unsigned long flags; > + u32 data; > + int ret; > + > + dev_dbg(hspi->dev, "%s\n", __func__); > + > + /************************ pm enable ************************/ > + pm_runtime_get_sync(hspi->dev); > + > + /* setup first of all in under pm_runtime */ > + data = SH_HSPI_CLK_DIVC(info->flags); > + > + if (info->flags & SH_HSPI_FBS) > + data |= 1 << 7; > + if (info->flags & SH_HSPI_CLKP_HIGH) > + data |= 1 << 6; > + if (info->flags & SH_HSPI_IDIV_DIV128) > + data |= 1 << 5; > + > + hspi_write(hspi, SPCR, data); > + hspi_write(hspi, SPSR, 0x0); > + hspi_write(hspi, SPSCR, 0x1); /* master mode */ > + > + while (1) { > + msg = NULL; > + > + /************************ spin lock ************************/ > + spin_lock_irqsave(&hspi->lock, flags); > + if (!list_empty(&hspi->queue)) { > + msg = list_entry(hspi->queue.next, > + struct spi_message, queue); > + list_del_init(&msg->queue); > + } > + spin_unlock_irqrestore(&hspi->lock, flags); > + /************************ spin unlock ************************/ > + if (!msg) > + break; > + > + ret = 0; > + list_for_each_entry(t, &msg->transfers, transfer_list) { > + if (t->tx_buf) { > + ret = hspi_push(hspi, msg, t); > + if (ret < 0) > + goto error; > + } > + if (t->rx_buf) { > + ret = hspi_pop(hspi, msg, t); > + if (ret < 0) > + goto error; > + } > + msg->actual_length += t->len; > + } > +error: > + msg->status = ret; > + msg->complete(msg->context); > + } > + > + pm_runtime_put_sync(hspi->dev); > + /************************ pm disable ************************/ > + > + return; > +} > + > +/* > + * spi master function > + */ > +static int hspi_setup(struct spi_device *spi) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + struct device *dev = hspi->dev; > + > + if (8 != spi->bits_per_word) { > + dev_err(dev, "bits_per_word should be 8\n"); > + return -EIO; > + } > + > + dev_dbg(dev, "%s setup\n", spi->modalias); > + > + return 0; > +} > + > +static void hspi_cleanup(struct spi_device *spi) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + struct device *dev = hspi->dev; > + > + dev_dbg(dev, "%s cleanup\n", spi->modalias); > +} > + > +static int hspi_transfer(struct spi_device *spi, struct spi_message *msg) > +{ > + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); > + unsigned long flags; > + > + /************************ spin lock ************************/ > + spin_lock_irqsave(&hspi->lock, flags); > + > + msg->actual_length = 0; > + msg->status = -EINPROGRESS; > + list_add_tail(&msg->queue, &hspi->queue); > + > + spin_unlock_irqrestore(&hspi->lock, flags); > + /************************ spin unlock ************************/ > + > + queue_work(hspi->workqueue, &hspi->ws); > + > + return 0; > +} > + > +static int __devinit hspi_probe(struct platform_device *pdev) > +{ > + struct resource *res; > + struct spi_master *master; > + struct hspi_priv *hspi; > + int ret; > + > + /* get base addr */ > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(&pdev->dev, "invalid resource\n"); > + return -EINVAL; > + } > + > + master = spi_alloc_master(&pdev->dev, sizeof(*hspi)); > + if (!master) { > + dev_err(&pdev->dev, "spi_alloc_master error.\n"); > + return -ENOMEM; > + } > + > + hspi = spi_master_get_devdata(master); > + dev_set_drvdata(&pdev->dev, hspi); > + > + /* init hspi */ > + hspi->master = master; > + hspi->dev = &pdev->dev; > + hspi->addr = ioremap(res->start, resource_size(res)); Could we use devm_* functions here > + if (!hspi->addr) { <snip> ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <CAM=Q2cv3QBLEWp+rQ9f5onBS1j=wZOes5m-r9fs6Uvfu6bnTkg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* [PATCH v3] spi: Add SuperH HSPI prototype driver [not found] ` <CAM=Q2cv3QBLEWp+rQ9f5onBS1j=wZOes5m-r9fs6Uvfu6bnTkg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2012-03-02 1:10 ` Kuninori Morimoto [not found] ` <878vjjbyfk.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Kuninori Morimoto @ 2012-03-02 1:10 UTC (permalink / raw) To: Shubhrajyoti Datta, Grant Likely Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Magnus, Kuninori Morimoto This patch adds SuperH HSPI driver. It is still prototype driver, but has enough function at this point. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> --- v2 -> v3 - modify wrong hspi_read() return cast - use devm_xx() drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-sh-hspi.c | 364 +++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/sh_hspi.h | 34 ++++ 4 files changed, 405 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/spi-sh-hspi.c create mode 100644 include/linux/spi/sh_hspi.h diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8293658..6f544e6 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -324,6 +324,12 @@ config SPI_SH_SCI help SPI driver for SuperH SCI blocks. +config SPI_SH_HSPI + tristate "SuperH HSPI controller" + depends on ARCH_SHMOBILE + help + SPI driver for SuperH HSPI blocks. + config SPI_STMP3XXX tristate "Freescale STMP37xx/378x SPI/SSP controller" depends on ARCH_STMP3XXX && SPI_MASTER diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 61c3261..d65e059 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_SH) += spi-sh.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o +obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c new file mode 100644 index 0000000..8356ec8 --- /dev/null +++ b/drivers/spi/spi-sh-hspi.c @@ -0,0 +1,364 @@ +/* + * SuperH HSPI bus driver + * + * Copyright (C) 2011 Kuninori Morimoto + * + * Based on spi-sh.c: + * Based on pxa2xx_spi.c: + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/spi/sh_hspi.h> + +#define SPCR 0x00 +#define SPSR 0x04 +#define SPSCR 0x08 +#define SPTBR 0x0C +#define SPRBR 0x10 +#define SPCR2 0x14 + +/* SPSR */ +#define RXFL (1 << 2) + +#define hspi2info(h) (h->dev->platform_data) + +struct hspi_priv { + void __iomem *addr; + struct spi_master *master; + struct list_head queue; + struct workqueue_struct *workqueue; + struct work_struct ws; + struct device *dev; + spinlock_t lock; +}; + +/* + * basic function + */ +static void hspi_write(struct hspi_priv *hspi, int reg, u32 val) +{ + iowrite32(val, hspi->addr + reg); +} + +static u32 hspi_read(struct hspi_priv *hspi, int reg) +{ + return ioread32(hspi->addr + reg); +} + +/* + * transfer function + */ +static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) +{ + int t = 256; + + while (t--) { + if ((mask & hspi_read(hspi, SPSR)) == val) + return 0; + + msleep(20); + } + + dev_err(hspi->dev, "timeout\n"); + return -ETIMEDOUT; +} + +static int hspi_push(struct hspi_priv *hspi, struct spi_message *msg, + struct spi_transfer *t) +{ + int i, ret; + u8 *data = (u8 *)t->tx_buf; + + /* + * FIXME + * very simple, but polling transfer + */ + for (i = 0; i < t->len; i++) { + /* wait remains */ + ret = hspi_status_check_timeout(hspi, 0x1, 0x0); + if (ret < 0) + return ret; + + hspi_write(hspi, SPTBR, (u32)data[i]); + + /* wait recive */ + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); + if (ret < 0) + return ret; + + /* dummy read */ + hspi_read(hspi, SPRBR); + } + + return 0; +} + +static int hspi_pop(struct hspi_priv *hspi, struct spi_message *msg, + struct spi_transfer *t) +{ + int i, ret; + u8 *data = (u8 *)t->rx_buf; + + /* + * FIXME + * very simple, but polling receive + */ + for (i = 0; i < t->len; i++) { + /* wait remains */ + ret = hspi_status_check_timeout(hspi, 0x1, 0); + if (ret < 0) + return ret; + + /* dummy write */ + hspi_write(hspi, SPTBR, 0x0); + + /* wait recive */ + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); + if (ret < 0) + return ret; + + data[i] = (u8)hspi_read(hspi, SPRBR); + } + + return 0; +} + +static void hspi_work(struct work_struct *work) +{ + struct hspi_priv *hspi = container_of(work, struct hspi_priv, ws); + struct sh_hspi_info *info = hspi2info(hspi); + struct spi_message *msg; + struct spi_transfer *t; + unsigned long flags; + u32 data; + int ret; + + dev_dbg(hspi->dev, "%s\n", __func__); + + /************************ pm enable ************************/ + pm_runtime_get_sync(hspi->dev); + + /* setup first of all in under pm_runtime */ + data = SH_HSPI_CLK_DIVC(info->flags); + + if (info->flags & SH_HSPI_FBS) + data |= 1 << 7; + if (info->flags & SH_HSPI_CLKP_HIGH) + data |= 1 << 6; + if (info->flags & SH_HSPI_IDIV_DIV128) + data |= 1 << 5; + + hspi_write(hspi, SPCR, data); + hspi_write(hspi, SPSR, 0x0); + hspi_write(hspi, SPSCR, 0x1); /* master mode */ + + while (1) { + msg = NULL; + + /************************ spin lock ************************/ + spin_lock_irqsave(&hspi->lock, flags); + if (!list_empty(&hspi->queue)) { + msg = list_entry(hspi->queue.next, + struct spi_message, queue); + list_del_init(&msg->queue); + } + spin_unlock_irqrestore(&hspi->lock, flags); + /************************ spin unlock ************************/ + if (!msg) + break; + + ret = 0; + list_for_each_entry(t, &msg->transfers, transfer_list) { + if (t->tx_buf) { + ret = hspi_push(hspi, msg, t); + if (ret < 0) + goto error; + } + if (t->rx_buf) { + ret = hspi_pop(hspi, msg, t); + if (ret < 0) + goto error; + } + msg->actual_length += t->len; + } +error: + msg->status = ret; + msg->complete(msg->context); + } + + pm_runtime_put_sync(hspi->dev); + /************************ pm disable ************************/ + + return; +} + +/* + * spi master function + */ +static int hspi_setup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + if (8 != spi->bits_per_word) { + dev_err(dev, "bits_per_word should be 8\n"); + return -EIO; + } + + dev_dbg(dev, "%s setup\n", spi->modalias); + + return 0; +} + +static void hspi_cleanup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + dev_dbg(dev, "%s cleanup\n", spi->modalias); +} + +static int hspi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + unsigned long flags; + + /************************ spin lock ************************/ + spin_lock_irqsave(&hspi->lock, flags); + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + list_add_tail(&msg->queue, &hspi->queue); + + spin_unlock_irqrestore(&hspi->lock, flags); + /************************ spin unlock ************************/ + + queue_work(hspi->workqueue, &hspi->ws); + + return 0; +} + +static int __devinit hspi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct spi_master *master; + struct hspi_priv *hspi; + int ret; + + /* get base addr */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid resource\n"); + return -EINVAL; + } + + master = spi_alloc_master(&pdev->dev, sizeof(*hspi)); + if (!master) { + dev_err(&pdev->dev, "spi_alloc_master error.\n"); + return -ENOMEM; + } + + hspi = spi_master_get_devdata(master); + dev_set_drvdata(&pdev->dev, hspi); + + /* init hspi */ + hspi->master = master; + hspi->dev = &pdev->dev; + hspi->addr = devm_ioremap(hspi->dev, + res->start, resource_size(res)); + if (!hspi->addr) { + dev_err(&pdev->dev, "ioremap error.\n"); + ret = -ENOMEM; + goto error1; + } + hspi->workqueue = create_singlethread_workqueue(dev_name(&pdev->dev)); + if (!hspi->workqueue) { + dev_err(&pdev->dev, "create workqueue error\n"); + ret = -EBUSY; + goto error2; + } + + spin_lock_init(&hspi->lock); + INIT_LIST_HEAD(&hspi->queue); + INIT_WORK(&hspi->ws, hspi_work); + + master->num_chipselect = 1; + master->bus_num = pdev->id; + master->setup = hspi_setup; + master->transfer = hspi_transfer; + master->cleanup = hspi_cleanup; + master->mode_bits = SPI_CPOL | SPI_CPHA; + ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto error3; + } + + pm_runtime_enable(&pdev->dev); + + dev_info(&pdev->dev, "probed\n"); + + return 0; + + error3: + destroy_workqueue(hspi->workqueue); + error2: + devm_iounmap(hspi->dev, hspi->addr); + error1: + spi_master_put(master); + + return ret; +} + +static int __devexit hspi_remove(struct platform_device *pdev) +{ + struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + spi_unregister_master(hspi->master); + destroy_workqueue(hspi->workqueue); + devm_iounmap(hspi->dev, hspi->addr); + + return 0; +} + +static struct platform_driver hspi_driver = { + .probe = hspi_probe, + .remove = __devexit_p(hspi_remove), + .driver = { + .name = "sh-hspi", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(hspi_driver); + +MODULE_DESCRIPTION("SuperH HSPI bus driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>"); +MODULE_ALIAS("platform:sh_spi"); diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h new file mode 100644 index 0000000..956d112 --- /dev/null +++ b/include/linux/spi/sh_hspi.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef SH_HSPI_H +#define SH_HSPI_H + +/* + * flags + * + * + */ +#define SH_HSPI_CLK_DIVC(d) (d & 0xFF) + +#define SH_HSPI_FBS (1 << 8) +#define SH_HSPI_CLKP_HIGH (1 << 9) /* default LOW */ +#define SH_HSPI_IDIV_DIV128 (1 << 10) /* default div16 */ +struct sh_hspi_info { + u32 flags; +}; + +#endif -- 1.7.5.4 ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <878vjjbyfk.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>]
* Re: [PATCH v3] spi: Add SuperH HSPI prototype driver [not found] ` <878vjjbyfk.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> @ 2012-03-09 17:54 ` Grant Likely [not found] ` <CACxGe6scA9M4byU1vGSBaZaMjuB8z8q7t2m+qdDkGoYK4=+1mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Grant Likely @ 2012-03-09 17:54 UTC (permalink / raw) To: Kuninori Morimoto Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shubhrajyoti Datta, Magnus, Kuninori Morimoto On Thu, Mar 1, 2012 at 6:10 PM, Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> wrote: > This patch adds SuperH HSPI driver. > It is still prototype driver, but has enough function at this point. > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> Applied, thanks. However, the spi subsystem is getting new support for core-queuing in v3.4. You should craft a patch before v3.5 to use the new infrastructure. g. ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <CACxGe6scA9M4byU1vGSBaZaMjuB8z8q7t2m+qdDkGoYK4=+1mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v3] spi: Add SuperH HSPI prototype driver [not found] ` <CACxGe6scA9M4byU1vGSBaZaMjuB8z8q7t2m+qdDkGoYK4=+1mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2012-03-13 0:23 ` Kuninori Morimoto 0 siblings, 0 replies; 8+ messages in thread From: Kuninori Morimoto @ 2012-03-13 0:23 UTC (permalink / raw) To: Grant Likely Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Shubhrajyoti Datta, Magnus, Kuninori Morimoto Hi Grant > On Thu, Mar 1, 2012 at 6:10 PM, Kuninori Morimoto > <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> wrote: > > This patch adds SuperH HSPI driver. > > It is still prototype driver, but has enough function at this point. > > > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org> > > Applied, thanks. > > However, the spi subsystem is getting new support for core-queuing in > v3.4. You should craft a patch before v3.5 to use the new > infrastructure. I understand, Thank you. I keep updating this driver Best regards --- Kuninori Morimoto ------------------------------------------------------------------------------ Keep Your Developer Skills Current with LearnDevNow! The most comprehensive online learning library for Microsoft developers is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3, Metro Style Apps, more. Free future releases when you subscribe now! http://p.sf.net/sfu/learndevnow-d2d ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2012-03-13 0:23 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-27 8:35 [PATCH] spi: Add SuperH HSPI prototype driver Kuninori Morimoto
[not found] ` <87vcp2tnst.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2012-01-04 20:05 ` Grant Likely
[not found] ` <20120104200548.GH15503-e0URQFbLeQY2iJbIjFUEsiwD8/FfD2ys@public.gmane.org>
2012-01-06 6:00 ` [PATCH v2] " Kuninori Morimoto
[not found] ` <871urd9xq0.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2012-02-29 8:03 ` Kuninori Morimoto
2012-03-01 9:26 ` Shubhrajyoti Datta
[not found] ` <CAM=Q2cv3QBLEWp+rQ9f5onBS1j=wZOes5m-r9fs6Uvfu6bnTkg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-02 1:10 ` [PATCH v3] " Kuninori Morimoto
[not found] ` <878vjjbyfk.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2012-03-09 17:54 ` Grant Likely
[not found] ` <CACxGe6scA9M4byU1vGSBaZaMjuB8z8q7t2m+qdDkGoYK4=+1mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-13 0:23 ` Kuninori Morimoto
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).