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