pmaports/device/linux-samsung-i927/0006-leds-Add-led-class-support-isa1200-vibration-motor.patch
Sergey Larin 5ccbcf999d
samsung-i927: update kernel to 5.2.1, more updates (!452)
- OTG support
- Charger
- WiFi 5GHz
- RTC bug "fixed" (always-on interrupt - made device overheat!)
- Kernel version bumped to 5.2.1
- Memory timings
- New WM8994 codec board driver (fixes suspend/resume)
- Camera's regulator supported now (saves power at least!)
- Updated panel driver (still not in mainline, idk why)
- MHL support in kernel (fixes boot times and screen, currently disabled in X,
  not tested)
- Other minor kernel chagnes

[ci:skip-build]: already built successfully in CI
2019-07-17 00:15:26 +02:00

698 lines
18 KiB
Diff

From f14f1512693476e0a5256fef0bb4d0ad04e662da Mon Sep 17 00:00:00 2001
From: ryang <decatf@gmail.com>
Date: Tue, 31 Oct 2017 12:08:54 -0400
Subject: [PATCH] leds: Add led class support isa1200 vibration motor
(cherry picked from commit e510fd2c344d8f1967e186a3fa030ccee201a4d6)
Signed-off-by: Sergey Larin <cerg2010cerg2010@mail.ru>
---
drivers/leds/Kconfig | 8 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-isa1200.c | 565 ++++++++++++++++++++++++++++++++++++
drivers/leds/leds-isa1200.h | 71 +++++
4 files changed, 645 insertions(+)
create mode 100644 drivers/leds/leds-isa1200.c
create mode 100755 drivers/leds/leds-isa1200.h
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 760f73a49c9f..14552a9f2718 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -784,6 +784,14 @@ config LEDS_NIC78BX
To compile this driver as a module, choose M here: the module
will be called leds-nic78bx.
+config LEDS_ISA1200
+ tristate "LES support for the ISA1200 motor"
+ default n
+ depends on I2C
+ help
+ Say Y to enalbe the ISA1200 IC.
+
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 1e9702ebffee..8f2c88f41701 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
+obj-$(CONFIG_LEDS_ISA1200) += leds-isa1200.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
diff --git a/drivers/leds/leds-isa1200.c b/drivers/leds/leds-isa1200.c
new file mode 100644
index 000000000000..3f14a38a4cbd
--- /dev/null
+++ b/drivers/leds/leds-isa1200.c
@@ -0,0 +1,565 @@
+/*
+ * drivers/motor/isa1200_vibrator.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co. Ltd. All Rights Reserved.
+ *
+ * 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/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+
+
+#include <linux/hrtimer.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/pwm.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach-types.h>
+#include "leds-isa1200.h"
+
+#define AMPLITUDE_MIN 0
+#define AMPLITUDE_MAX 254
+
+
+struct isa1200_vibrator_drvdata {
+ struct i2c_client *client;
+ struct led_classdev cdev;
+
+ struct clk *vib_clk;
+ struct gpio_desc *enable_gpio;
+
+ struct pinctrl* pinctrl;
+ struct pinctrl_state *on_state;
+ struct pinctrl_state *off_state;
+
+ struct workqueue_struct *wq;
+ struct delayed_work work;
+
+ struct hrtimer timer;
+ spinlock_t lock;
+ int timeout;
+ int max_timeout;
+
+ bool running;
+
+ u8 amplitude;
+
+ u8 ctrl0;
+ u8 ctrl1;
+ u8 ctrl2;
+ u8 ctrl4;
+ u8 pll;
+ u8 duty;
+ u8 period;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+static int amplitude_to_duty(int period, int amplitude)
+{
+ int duty = (period * (amplitude + AMPLITUDE_MAX)) /
+ (2 *(AMPLITUDE_MAX - AMPLITUDE_MIN));
+ return duty;
+}
+
+static int isa1200_vibrator_i2c_write(struct i2c_client *client,
+ u8 addr, u8 val)
+{
+ int error = 0;
+ error = i2c_smbus_write_byte_data(client, addr, val);
+ if (error)
+ printk(KERN_ERR "[VIB] Failed to write addr=[0x%x], val=[0x%x]\n",
+ addr, val);
+
+ return error;
+}
+
+static void isa1200_vibrator_hw_init(struct isa1200_vibrator_drvdata *vib)
+{
+ msleep(20);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG0, vib->ctrl0);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG1, vib->ctrl1);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG2, vib->ctrl2);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_PLL_REG, vib->pll);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG4, vib->ctrl4);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_PWM_DUTY_REG, vib->period/2);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_PWM_PERIOD_REG, vib->period);
+
+#ifdef MOTOR_DEBUG
+ printk(KERN_DEBUG "[VIB] ctrl0 = 0x%x\n", vib->ctrl0);
+ printk(KERN_DEBUG "[VIB] ctrl1 = 0x%x\n", vib->ctrl1);
+ printk(KERN_DEBUG "[VIB] ctrl2 = 0x%x\n", vib->ctrl2);
+ printk(KERN_DEBUG "[VIB] pll = 0x%x\n", vib->pll);
+ printk(KERN_DEBUG "[VIB] ctrl4 = 0x%x\n", vib->ctrl4);
+ printk(KERN_DEBUG "[VIB] duty = 0x%x\n", vib->period/2);
+ printk(KERN_DEBUG "[VIB] period = 0x%x\n", vib->period);
+#endif
+
+}
+
+static void isa1200_vibrator_on(struct isa1200_vibrator_drvdata *vib)
+{
+ int duty = vib->duty;
+
+ pr_debug("%s\n", __func__);
+
+ if (vib->duty >= vib->period) {
+ duty -= 3;
+ }
+
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG0, vib->ctrl0 | CTL0_NORMAL_OP);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_PWM_DUTY_REG, vib->duty);
+#ifdef MOTOR_DEBUG
+ printk(KERN_DEBUG "[VIB] ctrl0 = 0x%x\n", vib->ctrl0 | CTL0_NORMAL_OP);
+ printk(KERN_DEBUG "[VIB] duty = 0x%x\n", duty);
+#endif
+}
+
+static void isa1200_vibrator_off(struct isa1200_vibrator_drvdata *vib)
+{
+ pr_debug("%s\n", __func__);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_PWM_DUTY_REG, vib->period/2);
+ isa1200_vibrator_i2c_write(vib->client,
+ HAPTIC_CONTROL_REG0, vib->ctrl0);
+}
+
+static void isa1200_vibrator_work(struct work_struct *work)
+{
+ struct isa1200_vibrator_drvdata *vib =
+ container_of(to_delayed_work(work), struct isa1200_vibrator_drvdata, work);
+ struct i2c_client* client = vib->client;
+ int err;
+
+ pr_debug("%s\n", __func__);
+
+ if (vib->timeout == 0) {
+ if (!vib->running)
+ return;
+
+ vib->running = false;
+ isa1200_vibrator_off(vib);
+ clk_disable_unprepare(vib->vib_clk);
+
+ if (vib->pinctrl && vib->off_state) {
+ err = pinctrl_select_state(vib->pinctrl, vib->off_state);
+ if (err != 0)
+ dev_err(&client->dev,
+ "%s: error setting pinctrl off state. err=%d\n", __func__, err);
+ }
+
+ } else {
+ if (vib->running)
+ return;
+
+ vib->running = true;
+
+ if (vib->pinctrl && vib->on_state) {
+ err = pinctrl_select_state(vib->pinctrl, vib->on_state);
+ if (err != 0) {
+ dev_err(&client->dev,
+ "%s: error setting pinctrl on state. err=%d\n", __func__, err);
+ return;
+ }
+ }
+
+ clk_prepare_enable(vib->vib_clk);
+ mdelay(1);
+ isa1200_vibrator_on(vib);
+ }
+}
+
+static enum hrtimer_restart isa1200_vibrator_timer_func(struct hrtimer *_timer)
+{
+ struct isa1200_vibrator_drvdata *vib =
+ container_of(_timer, struct isa1200_vibrator_drvdata, timer);
+
+ vib->timeout = 0;
+
+ queue_delayed_work(vib->wq, &vib->work, 0);
+ return HRTIMER_NORESTART;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+static void isa1200_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ pr_info("%s: value=%d\n", __func__, value);
+
+ led_cdev->brightness = value;
+}
+
+static int isa1200_blink_set(struct led_classdev *cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ pr_info("%s\n", __func__);
+ return 0;
+}
+
+static ssize_t enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct isa1200_vibrator_drvdata *vib =
+ container_of(led_cdev, struct isa1200_vibrator_drvdata, cdev);
+ unsigned long flags;
+ int value;
+
+ sscanf(buf, "%d", &value);
+ pr_debug("%s timeout=%d\n", __func__, value);
+
+#ifdef MOTOR_DEBUG
+ printk(KERN_DEBUG "[VIB] time = %dms\n", value);
+#endif
+ cancel_delayed_work(&vib->work);
+ hrtimer_cancel(&vib->timer);
+ vib->timeout = value;
+ queue_delayed_work(vib->wq, &vib->work, 0);
+ spin_lock_irqsave(&vib->lock, flags);
+ if (value > 0) {
+ if (value > vib->max_timeout)
+ value = vib->max_timeout;
+
+ hrtimer_start(&vib->timer,
+ ns_to_ktime((u64)value * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+ }
+ spin_unlock_irqrestore(&vib->lock, flags);
+
+ return size;
+}
+
+static ssize_t amplitude_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct isa1200_vibrator_drvdata *vib =
+ container_of(led_cdev, struct isa1200_vibrator_drvdata, cdev);
+
+ return sprintf(buf, "%d\n", vib->amplitude);
+}
+
+static ssize_t amplitude_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct isa1200_vibrator_drvdata *vib =
+ container_of(led_cdev, struct isa1200_vibrator_drvdata, cdev);
+ int amplitude;
+
+ sscanf(buf, "%d", &amplitude);
+
+ if (amplitude > AMPLITUDE_MAX)
+ amplitude = AMPLITUDE_MAX;
+ else if (amplitude < AMPLITUDE_MIN)
+ amplitude = AMPLITUDE_MIN;
+
+ vib->duty = amplitude_to_duty(vib->period, amplitude);
+ vib->amplitude = amplitude;
+
+ pr_debug("%s: amplitude=%d duty_cycle=%d\n", __func__, amplitude, vib->duty);
+
+ return size;
+}
+
+
+static struct device_attribute isa1200_device_attrs[] = {
+ __ATTR(enable, S_IWUSR,
+ NULL,
+ enable_store),
+ __ATTR(amplitude, S_IRUGO | S_IWUSR,
+ amplitude_show,
+ amplitude_store),
+};
+
+static int isa1200_init_pinctrl(struct isa1200_vibrator_drvdata *ddata)
+{
+ struct i2c_client *client = ddata->client;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *on_state, *off_state;
+ int err = 0;
+
+ pinctrl = devm_pinctrl_get(&client->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_info(&client->dev,
+ "%s: not using pinctrl.\n", __func__);
+ return 0;
+ }
+
+ off_state = pinctrl_lookup_state(pinctrl, "off");
+ if (IS_ERR(off_state)) {
+ dev_err(&client->dev,
+ "%s: error getting pinctrl off state\n", __func__);
+ err = -ENODEV;
+ goto err;
+ }
+
+ on_state = pinctrl_lookup_state(pinctrl, "on");
+ if (IS_ERR(on_state)) {
+ dev_err(&client->dev,
+ "%s: error getting pinctrl on state\n", __func__);
+ err = -ENODEV;
+ goto err;
+ }
+
+ err = pinctrl_select_state(pinctrl, off_state);
+ if (err) {
+ dev_err(&client->dev,
+ "%s: error setting pinctrl off state. err=%d\n", __func__, err);
+ err = -ENODEV;
+ goto err;
+ }
+
+ ddata->pinctrl = pinctrl;
+ ddata->off_state = off_state;
+ ddata->on_state = on_state;
+
+ return 0;
+
+err:
+ devm_pinctrl_put(pinctrl);
+ return err;
+}
+
+#ifdef CONFIG_OF
+static int isa1200_parse_dt(struct i2c_client *client,
+ struct isa1200_vibrator_drvdata *drvdata)
+{
+ struct device_node *np = client->dev.of_node;
+ struct clk *vib_clk;
+ int val, error;
+
+ drvdata->enable_gpio = devm_gpiod_get_optional(&client->dev,
+ "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(drvdata->enable_gpio)) {
+ error = PTR_ERR(drvdata->enable_gpio);
+ dev_err(&client->dev, "Failed to get enable gpio: %d\n", error);
+ return error;
+ }
+
+ if (!of_property_read_u32(np, "max-timeout", &val))
+ drvdata->max_timeout = val;
+ if (!of_property_read_u32(np, "ctrl0", &val))
+ drvdata->ctrl0 = val;
+ if (!of_property_read_u32(np, "ctrl1", &val))
+ drvdata->ctrl1 = val;
+ if (!of_property_read_u32(np, "ctrl2", &val))
+ drvdata->ctrl2 = val;
+ if (!of_property_read_u32(np, "ctrl4", &val))
+ drvdata->ctrl4 = val;
+ if (!of_property_read_u32(np, "pll", &val))
+ drvdata->pll = val;
+ if (!of_property_read_u32(np, "duty", &val))
+ drvdata->duty = val;
+ if (!of_property_read_u32(np, "period", &val))
+ drvdata->period = val;
+
+ vib_clk = of_clk_get_by_name(np, "vibrator-clk");
+ if (vib_clk == NULL) {
+ pr_err("%s: error getting clk.\n", __func__);
+ return -ENODEV;
+ }
+ drvdata->vib_clk = vib_clk;
+
+ return 0;
+}
+#else
+static int isa1200_parse_dt(struct i2c_client *client,
+ struct isa1200_vibrator_drvdata *drvdata)
+{
+ return -EINVAL;
+}
+#endif
+
+static int isa1200_vibrator_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct isa1200_vibrator_platform_data *pdata = NULL;
+ struct isa1200_vibrator_drvdata *ddata;
+ int i, ret = 0;
+
+ printk(KERN_DEBUG "[VIB] %s\n", __func__);
+
+ ddata = kzalloc(sizeof(struct isa1200_vibrator_drvdata), GFP_KERNEL);
+ if (NULL == ddata) {
+ printk(KERN_ERR "[VIB] Failed to alloc memory\n");
+ ret = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ if (client->dev.platform_data) {
+ pdata = client->dev.platform_data;
+
+ ddata->enable_gpio = pdata->enable_gpio;
+ ddata->vib_clk = pdata->get_clk();
+ ddata->ctrl0 = pdata->ctrl0;
+ ddata->ctrl1 = pdata->ctrl1;
+ ddata->ctrl2 = pdata->ctrl2;
+ ddata->ctrl4 = pdata->ctrl4;
+ ddata->pll = pdata->pll;
+ ddata->duty = pdata->duty;
+ ddata->period = pdata->period;
+ } else if (client->dev.of_node) {
+ ret = isa1200_parse_dt(client, ddata);
+ if (ret) {
+ pr_err("%s: error parsing device tree\n", __func__);
+ goto err_free_mem;
+ }
+ }
+
+ ddata->client = client;
+
+ ddata->cdev.name = "isa1200";
+ ddata->cdev.flags = LED_CORE_SUSPENDRESUME;
+ ddata->cdev.brightness_set = isa1200_brightness_set;
+ ddata->cdev.blink_set = isa1200_blink_set;
+ ddata->cdev.default_trigger = "none";
+ i2c_set_clientdata(client, ddata);
+
+ ret = isa1200_init_pinctrl(ddata);
+ if (ret)
+ goto err_free_mem;
+
+ isa1200_vibrator_hw_init(ddata);
+
+
+ hrtimer_init(&ddata->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ddata->timer.function = isa1200_vibrator_timer_func;
+
+ ddata->wq = create_singlethread_workqueue("isa1200");
+ INIT_DELAYED_WORK(&ddata->work, isa1200_vibrator_work);
+
+ ret = led_classdev_register(&client->dev, &ddata->cdev);
+ if (ret < 0)
+ goto err_free_mem;
+
+ for (i = 0; i < ARRAY_SIZE(isa1200_device_attrs); i++) {
+ ret = device_create_file(ddata->cdev.dev, &isa1200_device_attrs[i]);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s: failed to create sysfs attributes\n", __func__);
+ goto err_free_mem;
+ }
+ }
+
+ return 0;
+
+err_free_mem:
+ kfree(ddata);
+ return ret;
+
+}
+
+static int isa1200_vibrator_i2c_remove(struct i2c_client *client)
+{
+ struct isa1200_vibrator_drvdata *ddata = i2c_get_clientdata(client);
+ struct led_classdev *led_cdev = &ddata->cdev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(isa1200_device_attrs); i++) {
+ device_remove_file(led_cdev->dev, &isa1200_device_attrs[i]);
+ }
+
+ led_classdev_unregister(led_cdev);
+
+ flush_workqueue(ddata->wq);
+ destroy_workqueue(ddata->wq);
+ ddata->wq = NULL;
+
+ kfree(ddata);
+
+ return 0;
+}
+
+#if 0
+static int isa1200_vibrator_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isa1200_vibrator_drvdata *vib = i2c_get_clientdata(client);
+ gpio_direction_output(vib->gpio_en, 0);
+ return 0;
+}
+
+static int isa1200_vibrator_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isa1200_vibrator_drvdata *vib = i2c_get_clientdata(client);
+ // isa1200_vibrator_hw_init(ddata);
+ gpio_direction_output(vib->gpio_en, 1);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isa1200_pm,
+ isa1200_vibrator_suspend, isa1200_vibrator_resume);
+#define ISA1200_PM &isa1200_pm
+#else
+#define ISA1200_PM NULL
+#endif
+
+static const struct i2c_device_id isa1200_vibrator_device_id[] = {
+ {"isa1200_vibrator", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, isa1200_vibrator_device_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id isa1200_dt_match[] = {
+ { .compatible = "samsung_p3,isa1200_vibrator" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, isa1200_dt_match);
+#endif
+
+static struct i2c_driver isa1200_vibrator_i2c_driver = {
+ .driver = {
+ .name = "isa1200_vibrator",
+ .pm = ISA1200_PM,
+ .of_match_table = of_match_ptr(isa1200_dt_match),
+ .owner = THIS_MODULE,
+ },
+ .probe = isa1200_vibrator_i2c_probe,
+ .remove = isa1200_vibrator_i2c_remove,
+ .id_table = isa1200_vibrator_device_id,
+};
+
+module_i2c_driver(isa1200_vibrator_i2c_driver);
diff --git a/drivers/leds/leds-isa1200.h b/drivers/leds/leds-isa1200.h
new file mode 100755
index 000000000000..50713449003c
--- /dev/null
+++ b/drivers/leds/leds-isa1200.h
@@ -0,0 +1,71 @@
+/* arch/arm/mach-tegra/sec_vibrator.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co. Ltd. All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_SEC_VIBRATOR_H
+#define _LINUX_SEC_VIBRATOR_H
+
+#define HAPTIC_CONTROL_REG0 0x30
+#define HAPTIC_CONTROL_REG1 0x31
+#define HAPTIC_CONTROL_REG2 0x32
+#define HAPTIC_PLL_REG 0x33
+#define HAPTIC_CONTROL_REG4 0x34
+#define HAPTIC_PWM_DUTY_REG 0x35
+#define HAPTIC_PWM_PERIOD_REG 0x36
+#define HAPTIC_AMPLITUDE_REG 0x37
+
+/* HAPTIC_CONTROL_REG0 */
+#define CTL0_DIVIDER128 0
+#define CTL0_DIVIDER256 1
+#define CTL0_DIVIDER512 2
+#define CTL0_DIVIDER1024 3
+#define CTL0_13MHZ 1 << 2
+#define CTL0_PWM_INPUT 1 << 3
+#define CTL0_PWM_GEN 2 << 3
+#define CTL0_WAVE_GEN 3 << 3
+#define CTL0_HIGH_DRIVE 1 << 5
+#define CTL0_OVER_DR_EN 1 << 6
+#define CTL0_NORMAL_OP 1 << 7
+
+/* HAPTIC_CONTROL_REG1 */
+#define CTL1_HAPTICOFF_16U 0
+#define CTL1_HAPTICOFF_32U 1
+#define CTL1_HAPTICOFF_64U 2
+#define CTL1_HAPTICOFF_100U 3
+#define CTL1_HAPTICON_1U 1 << 2
+#define CTL1_SMART_EN 1 << 3
+#define CTL1_PLL_EN 1 << 4
+#define CTL1_ERM_TYPE 1 << 5
+#define CTL1_DEFAULT 1 << 6
+#define CTL1_EXT_CLOCK 1 << 7
+
+/* HAPTIC_CONTROL_REG2 */
+#define CTL2_EFFECT_EN 1
+#define CTL2_START_EFF_EN 1 << 2
+#define CTL2_SOFT_RESET_EN 1 << 7
+
+struct isa1200_vibrator_platform_data {
+ struct gpio_desc *enable_gpio;
+ int max_timeout;
+ u8 ctrl0;
+ u8 ctrl1;
+ u8 ctrl2;
+ u8 ctrl4;
+ u8 pll;
+ u8 duty;
+ u8 period;
+ struct clk *(*get_clk) (void);
+};
+
+#endif
--
2.22.0