Hi Kuninori, On Fri, Jan 6, 2012 at 11:30 AM, Kuninori Morimoto <kuninori.morimoto...@renesas.com> 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...@renesas.com> > --- > 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/ _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general