[PATCH] input: spi: Driver for SPI data stream driven vibrator

2010-10-25 Thread Ilkka Koskinen
This driver provides access to drive a vibrator connected
to SPI data line via Input layer's Force Feedback interface.

Client application provides samples (data streams) to be
played as CUSTOM_DATA. The samples are stored in driver's
internal buffers.

The driver is not able to mix the given samples. Instead, it
remembers the currently played sample and next one to be played.

Signed-off-by: Ilkka Koskinen 
---
 drivers/input/misc/Kconfig |5 +
 drivers/input/misc/Makefile|2 +-
 drivers/input/misc/vibra_spi.c |  429 
 include/linux/spi/vibra.h  |   34 
 4 files changed, 469 insertions(+), 1 deletions(-)
 create mode 100644 drivers/input/misc/vibra_spi.c
 create mode 100644 include/linux/spi/vibra.h

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b49e233..3441832 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -438,4 +438,9 @@ config INPUT_ADXL34X_SPI
  To compile this driver as a module, choose M here: the
  module will be called adxl34x-spi.
 
+config INPUT_SPI_VIBRA
+   tristate "Support for SPI driven Vibra module"
+   help
+ Support for Vibra module that is connected to OMAP SPI bus.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 19ccca7..cde272f 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -41,4 +41,4 @@ obj-$(CONFIG_INPUT_WINBOND_CIR)   += winbond-cir.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)   += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)  += wm831x-on.o
 obj-$(CONFIG_INPUT_YEALINK)+= yealink.o
-
+obj-$(CONFIG_INPUT_SPI_VIBRA)  += vibra_spi.o
diff --git a/drivers/input/misc/vibra_spi.c b/drivers/input/misc/vibra_spi.c
new file mode 100644
index 000..551a3b8
--- /dev/null
+++ b/drivers/input/misc/vibra_spi.c
@@ -0,0 +1,429 @@
+/*
+ * This file implements a driver for SPI data driven vibrator.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Ilkka Koskinen 
+ *
+ * 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.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Number of effects handled with memoryless devices */
+#define VIBRA_EFFECTS  36
+#define MAX_EFFECT_SIZE1024 /* In bytes */
+
+#define FF_EFFECT_QUEUED   0
+#define FF_EFFECT_PLAYING  1
+#define FF_EFFECT_ABORTING 2
+#define FF_EFFECT_UPLOADING3
+
+enum vibra_status {
+   IDLE = 0,
+   STARTED,
+   PLAYING,
+   CLOSING,
+};
+
+struct effect_info {
+   char*buf;
+   int buflen;
+   unsigned long   flags;  /* effect state (STARTED, PLAYING, etc) */
+   unsigned long   stop_at;
+};
+
+struct vibra_data {
+   struct device   *dev;
+   struct input_dev*input_dev;
+
+   struct workqueue_struct *workqueue;
+   struct work_struct  play_work;
+
+   struct spi_device   *spi_dev;
+   struct spi_transfer t;
+   struct spi_message  msg;
+   u32 spi_max_speed_hz;
+
+   void (*set_power)(bool enable);
+
+   enum vibra_status   status;
+
+   struct effect_info  effects[VIBRA_EFFECTS];
+   int next_effect;
+   int current_effect;
+   unsigned long   stop_at;
+};
+
+static int vibra_spi_raw_write_effect(struct vibra_data *vibra)
+{
+   spi_message_init(&vibra->msg);
+   memset(&vibra->t, 0, sizeof(vibra->t));
+
+   vibra->t.tx_buf = vibra->effects[vibra->current_effect].buf;
+   vibra->t.len= vibra->effects[vibra->current_effect].buflen;
+   spi_message_add_tail(&vibra->t, &vibra->msg);
+
+   return spi_sync(vibra->spi_dev, &vibra->msg);
+}
+
+static void vibra_play_work(struct work_struct *work)
+{
+   struct vibra_data *vibra = container_of(work,
+   struct vibra_data, play_work);
+   struct effect_info *curr, *next;
+   unsigned long flags;
+
+   while (1) {
+   spin_lock_irqsave(&vibra->input_dev->event_lock, flags);
+   curr = &vib

[PATCH] spi/omap2_mcspi: Verify TX reg is empty after TX only xfer with DMA

2010-10-19 Thread Ilkka Koskinen
In case of TX only with DMA, the driver assumes that the data
has been transferred once DMA callback in invoked. However,
SPI's shift register may still contain data. Thus, the driver
is supposed to verify that the register is empty and the end of
the SPI transfer has been reached.

Signed-off-by: Ilkka Koskinen 
Tested-by: Tuomas Katila 
---
 drivers/spi/omap2_mcspi.c |   39 ++-
 1 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index b3a94ca..a2e053c 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi 
*mcspi)
return 0;
 }
 
+static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
+{
+   unsigned long timeout;
+
+   timeout = jiffies + msecs_to_jiffies(1000);
+   while (!(__raw_readl(reg) & bit)) {
+   if (time_after(jiffies, timeout))
+   return -1;
+   cpu_relax();
+   }
+   return 0;
+}
+
 static unsigned
 omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 {
@@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct 
spi_transfer *xfer)
u32 l;
u8  * rx;
const u8* tx;
+   void __iomem*chstat_reg;
 
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
l = mcspi_cached_chconf0(spi);
 
+   chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+
count = xfer->len;
c = count;
word_len = cs->word_len;
@@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct 
spi_transfer *xfer)
if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion);
dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+
+   /* for TX_ONLY mode, be sure all words have shifted out */
+   if (rx == NULL) {
+   if (mcspi_wait_for_reg_bit(chstat_reg,
+   OMAP2_MCSPI_CHSTAT_TXS) < 0)
+   dev_err(&spi->dev, "TXS timed out\n");
+   else if (mcspi_wait_for_reg_bit(chstat_reg,
+   OMAP2_MCSPI_CHSTAT_EOT) < 0)
+   dev_err(&spi->dev, "EOT timed out\n");
+   }
}
 
if (rx != NULL) {
@@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct 
spi_transfer *xfer)
return count;
 }
 
-static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
-{
-   unsigned long timeout;
-
-   timeout = jiffies + msecs_to_jiffies(1000);
-   while (!(__raw_readl(reg) & bit)) {
-   if (time_after(jiffies, timeout))
-   return -1;
-   cpu_relax();
-   }
-   return 0;
-}
-
 static unsigned
 omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 {
-- 
1.6.0.4


--
Download new Adobe(R) Flash(R) Builder(TM) 4
The new Adobe(R) Flex(R) 4 and Flash(R) Builder(TM) 4 (formerly 
Flex(R) Builder(TM)) enable the development of rich applications that run
across multiple browsers and platforms. Download your free trials today!
http://p.sf.net/sfu/adobe-dev2dev
___
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general