summaryrefslogtreecommitdiff
path: root/drivers/platform/sprd/sprd_vibrator_2723.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/sprd/sprd_vibrator_2723.c')
-rw-r--r--drivers/platform/sprd/sprd_vibrator_2723.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/drivers/platform/sprd/sprd_vibrator_2723.c b/drivers/platform/sprd/sprd_vibrator_2723.c
new file mode 100644
index 00000000..e44db15c
--- /dev/null
+++ b/drivers/platform/sprd/sprd_vibrator_2723.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <../../../drivers/staging/android/timed_output.h>
+#include <linux/sched.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/adi.h>
+#include <soc/sprd/adc.h>
+
+#ifdef CONFIG_SC_VIBRATOR_GPIO
+#include <linux/gpio.h>
+#include <soc/sprd/board.h>
+#elif defined(CONFIG_SC_VIBRATOR_POWER)
+#include <linux/regulator/consumer.h>
+#endif
+
+#include <soc/sprd/sci_glb_regs.h>
+#define ANA_VIBRATOR_CTRL0 (ANA_REGS_GLB_BASE + 0xf8)
+
+#define CUR_DRV_CAL_SEL (0x0 << 12)
+#define SLP_LDOVIBR_PD_EN (0x1 << 9)
+#define LDO_VIBR_PD (0x1 << 8)
+#define LDO_VIBR_V (0xB4)
+
+static struct work_struct vibrator_work;
+static struct hrtimer vibe_timer;
+static int vibe_state = 0;
+
+static inline uint32_t vibrator_read(unsigned long reg)
+{
+ return sci_adi_read(reg);
+}
+
+static void set_vibrator(int on)
+{
+ if (on){
+ sci_adi_clr(ANA_VIBRATOR_CTRL0, LDO_VIBR_PD);
+ sci_adi_clr(ANA_VIBRATOR_CTRL0, SLP_LDOVIBR_PD_EN);
+ printk("v_reg:0x%08x\n",ANA_VIBRATOR_CTRL0);
+ printk("v_reg_value:0x%08x\n",vibrator_read(ANA_VIBRATOR_CTRL0));
+
+ }
+ else{
+ sci_adi_write(ANA_VIBRATOR_CTRL0, LDO_VIBR_PD, LDO_VIBR_PD);
+ sci_adi_write(ANA_VIBRATOR_CTRL0, SLP_LDOVIBR_PD_EN, SLP_LDOVIBR_PD_EN);
+ }
+}
+
+static void vibrator_hw_init(void)
+{
+ sci_adi_write(ANA_REG_GLB_RTC_CLK_EN, BIT_RTC_VIBR_EN, BIT_RTC_VIBR_EN);
+ sci_adi_write(ANA_VIBRATOR_CTRL0,CUR_DRV_CAL_SEL,CUR_DRV_CAL_SEL);
+ sci_adi_clr(ANA_VIBRATOR_CTRL0, 0xFF);
+ sci_adi_write(ANA_VIBRATOR_CTRL0,LDO_VIBR_V,LDO_VIBR_V);
+}
+
+static void update_vibrator(struct work_struct *work)
+{
+ set_vibrator(vibe_state);
+}
+
+static void vibrator_enable(struct timed_output_dev *dev, int value)
+{
+
+ hrtimer_cancel(&vibe_timer);
+
+ if (value == 0)
+ vibe_state = 0;
+ else {
+ value = (value > 15000) ? 15000 : value;
+ vibe_state = 1;
+ hrtimer_start(&vibe_timer,
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ printk("vibrator_enable:value = %d\n",value);
+ printk("vibrator_enable:vibe_state = %d\n",vibe_state);
+
+ }
+
+ schedule_work(&vibrator_work);
+}
+
+static int vibrator_get_time(struct timed_output_dev *dev)
+{
+ ktime_t re;
+
+ if (hrtimer_active(&vibe_timer)) {
+ re = hrtimer_get_remaining(&vibe_timer);
+ return ktime_to_ns(re);
+ } else
+ return 0;
+}
+
+static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
+{
+ vibe_state = 0;
+ schedule_work(&vibrator_work);
+
+ return HRTIMER_NORESTART;
+}
+
+static struct timed_output_dev sprd_vibrator = {
+ .name = "vibrator",
+ .get_time = vibrator_get_time,
+ .enable = vibrator_enable,
+};
+
+static int __init sprd_init_vibrator(void)
+{
+ vibrator_hw_init();
+
+ printk("locate in sprd_init_vibrator!\n");
+ INIT_WORK(&vibrator_work, update_vibrator);
+ vibe_state = 0;
+ hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ vibe_timer.function = vibrator_timer_func;
+
+ timed_output_dev_register(&sprd_vibrator);
+
+ return 0;
+}
+
+module_init(sprd_init_vibrator);
+MODULE_DESCRIPTION("vibrator driver for spreadtrum Processors");
+MODULE_LICENSE("GPL");
+