summaryrefslogtreecommitdiff
path: root/drivers/misc/vib-gpio.c
diff options
context:
space:
mode:
authorDoug Zobel <dzobel1@motorola.com>2013-11-15 14:29:07 -0600
committerJames Wylder <jwylder@motorola.com>2014-03-05 17:46:52 -0600
commitd2a782003a6047da120a33e6f8ee6fd33bb825d6 (patch)
tree8d20bd4ecda62a06e98993c4108456bc1acb0d0b /drivers/misc/vib-gpio.c
parent32fd2d36d2464056d4522a9c02797b7c2b2e884f (diff)
downloadolio-linux-3.10-d2a782003a6047da120a33e6f8ee6fd33bb825d6.tar.xz
olio-linux-3.10-d2a782003a6047da120a33e6f8ee6fd33bb825d6.zip
CW integration and minnow bringup
* create minnow machine type * create Android makefile * add pre-commit syntax check * enable -Werror * Add drivers: CPCAP, TPS65xxx, m4sensorhub, atmxt, lm3535, usb gadget, minnow display, TI 12xx wireless Change-Id: I7962f5e1256715f2452aed5a62a4f2f2383d5046
Diffstat (limited to 'drivers/misc/vib-gpio.c')
-rw-r--r--drivers/misc/vib-gpio.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/drivers/misc/vib-gpio.c b/drivers/misc/vib-gpio.c
new file mode 100644
index 00000000000..d80d34db9f3
--- /dev/null
+++ b/drivers/misc/vib-gpio.c
@@ -0,0 +1,224 @@
+/* drivers/misc/vib-gpio.c
+ *
+ * Copyright (C) 2009 Motorola, Inc.
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/vib-gpio.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+/* TODO: replace with correct header */
+#include "../staging/android/timed_output.h"
+
+struct vib_gpio_data {
+ struct timed_output_dev dev;
+ struct work_struct vib_work;
+ struct hrtimer timer;
+ spinlock_t lock;
+
+ struct vib_gpio_platform_data *pdata;
+
+ int vib_power_state;
+ int vib_state;
+};
+
+struct vib_gpio_data *misc_data;
+
+static void vib_gpio_set(int on)
+{
+ if (on) {
+ if (misc_data->pdata->power_on && !misc_data->vib_power_state) {
+ misc_data->pdata->power_on();
+ misc_data->vib_power_state = 1;
+ }
+ if (misc_data->pdata->gpio >= 0)
+ gpio_direction_output(misc_data->pdata->gpio,
+ misc_data->pdata->active_low ?
+ 0 : 1);
+ } else {
+ if (misc_data->pdata->gpio >= 0)
+ gpio_direction_output(misc_data->pdata->gpio,
+ misc_data->pdata->active_low ?
+ 1 : 0);
+
+ if (misc_data->pdata->power_off && misc_data->vib_power_state) {
+ misc_data->pdata->power_off();
+ misc_data->vib_power_state = 0;
+ }
+ }
+}
+
+static void vib_gpio_update(struct work_struct *work)
+{
+ vib_gpio_set(misc_data->vib_state);
+}
+
+static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
+{
+ struct vib_gpio_data *data =
+ container_of(timer, struct vib_gpio_data, timer);
+ data->vib_state = 0;
+ schedule_work(&data->vib_work);
+ return HRTIMER_NORESTART;
+}
+
+static int vib_gpio_get_time(struct timed_output_dev *dev)
+{
+ struct vib_gpio_data *data =
+ container_of(dev, struct vib_gpio_data, dev);
+
+ if (hrtimer_active(&data->timer)) {
+ ktime_t r = hrtimer_get_remaining(&data->timer);
+ struct timeval t = ktime_to_timeval(r);
+ return t.tv_sec * 1000 + t.tv_usec / 1000;
+ } else
+ return 0;
+}
+
+static void vib_gpio_enable(struct timed_output_dev *dev, int value)
+{
+ struct vib_gpio_data *data =
+ container_of(dev, struct vib_gpio_data, dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&data->lock, flags);
+ hrtimer_cancel(&data->timer);
+
+ if (value == 0)
+ data->vib_state = 0;
+ else {
+ value = (value > data->pdata->max_timeout ?
+ data->pdata->max_timeout : value);
+ data->vib_state = 1;
+ hrtimer_start(&data->timer,
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ schedule_work(&data->vib_work);
+}
+
+/* This is a temporary solution until a more global haptics soltion is
+ * available for haptics that need to occur in any application */
+void vibrator_haptic_fire(int value)
+{
+ vib_gpio_enable(&misc_data->dev, value);
+}
+
+static int vib_gpio_probe(struct platform_device *pdev)
+{
+ struct vib_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct vib_gpio_data *gpio_data;
+ int ret = 0;
+
+ if (!pdata) {
+ ret = -EBUSY;
+ goto err0;
+ }
+ gpio_data = kzalloc(sizeof(struct vib_gpio_data), GFP_KERNEL);
+ if (!gpio_data) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ gpio_data->pdata = pdata;
+
+ INIT_WORK(&gpio_data->vib_work, vib_gpio_update);
+
+ hrtimer_init(&gpio_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ gpio_data->timer.function = gpio_timer_func;
+ spin_lock_init(&gpio_data->lock);
+
+ gpio_data->dev.name = "vibrator";
+ gpio_data->dev.get_time = vib_gpio_get_time;
+ gpio_data->dev.enable = vib_gpio_enable;
+ ret = timed_output_dev_register(&gpio_data->dev);
+ if (ret < 0)
+ goto err1;
+
+ if (gpio_data->pdata->init)
+ ret = gpio_data->pdata->init();
+ if (ret < 0)
+ goto err2;
+
+ misc_data = gpio_data;
+ if (misc_data->pdata->gpio >= 0)
+ gpio_direction_output(gpio_data->pdata->gpio,
+ gpio_data->pdata->active_low);
+
+ platform_set_drvdata(pdev, gpio_data);
+
+ vib_gpio_enable(&gpio_data->dev, gpio_data->pdata->initial_vibrate);
+
+ pr_info("vib gpio probe done");
+ return 0;
+
+err2:
+ timed_output_dev_unregister(&gpio_data->dev);
+err1:
+ kfree(gpio_data->pdata);
+ kfree(gpio_data);
+err0:
+ return ret;
+}
+
+static int vib_gpio_remove(struct platform_device *pdev)
+{
+ struct vib_gpio_data *gpio_data = platform_get_drvdata(pdev);
+
+ if (gpio_data->pdata->exit)
+ gpio_data->pdata->exit();
+
+ timed_output_dev_unregister(&gpio_data->dev);
+
+ kfree(gpio_data->pdata);
+ kfree(gpio_data);
+
+ return 0;
+}
+
+static struct platform_driver vib_gpio_driver = {
+ .probe = vib_gpio_probe,
+ .remove = vib_gpio_remove,
+ .driver = {
+ .name = VIB_GPIO_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init vib_gpio_init(void)
+{
+ return platform_driver_register(&vib_gpio_driver);
+}
+
+static void __exit vib_gpio_exit(void)
+{
+ platform_driver_unregister(&vib_gpio_driver);
+}
+
+late_initcall(vib_gpio_init);
+module_exit(vib_gpio_exit);
+
+MODULE_AUTHOR("Motorola");
+MODULE_DESCRIPTION("vib gpio driver");
+MODULE_LICENSE("GPL");