[Oppo Find 5] paperWastage:
here is a quick change, need su.

input range: 0 to 100 (percentage). there are only 20 discrete steps available (12 -> 31), so if you set it anywhere between 47-52 %, it'll get saved as 47%, and translated to the discrete step 21.

set to min:

echo 0 > /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-vib/amp

set to max:

echo 100 > /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-vib/amp

echo 50 > /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-vib/amp

cat /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-vib/amp

$ 47

From 8a08add29fbd277bbc09ae4c2b07b84676d81a28 Mon Sep 17 00:00:00 2001
From: Vince Ng <android@ngvincent.com>
Date: Sun, 7 Jul 2013 14:50:48 -0400
Subject: [PATCH] pm8xxx-vibrator: exposed sysfs to modify voltage level

should show up as /sys/devices/platform/msm_ssbi.0/pm8921-core/pm8xxx-vib/amp

there are only 20 discrete steps though (12 to 31)

Change-Id: I4a6306a0c086eaf0b6a212562b480ef0f35c03e3
---
drivers/misc/pm8xxx-vibrator.c | 51 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/pm8xxx-vibrator.c b/drivers/misc/pm8xxx-vibrator.c
index 62e7b45..00e1444 100644
--- a/drivers/misc/pm8xxx-vibrator.c
+++ b/drivers/misc/pm8xxx-vibrator.c
@@ -20,6 +20,8 @@
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/vibrator.h>

+#include "../staging/iio/sysfs.h"
+
#include "../staging/android/timed_output.h"

#define VIB_DRV	0x4A
@@ -32,6 +34,8 @@
#define VIB_MAX_LEVEL_mV	3100
#define VIB_MIN_LEVEL_mV	1200

+static unsigned int vib_level_range=(VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) / 100;
+
struct pm8xxx_vib {
struct hrtimer vib_timer;
struct timed_output_dev timed_dev;
@@ -198,6 +202,36 @@ static enum hrtimer_restart pm8xxx_vib_timer_func(struct hrtimer *timer)
return HRTIMER_NORESTART;
}

+static ssize_t pm8xxx_vib_voltage_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int level = vib_dev->level ;
+
+	// convert to percentage form
+	level = (level - VIB_MIN_LEVEL_mV/100) * 100 / vib_level_range ;
+
+	return sprintf(buf, "%d\n", level);
+}
+
+static ssize_t pm8xxx_vib_voltage_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t size)
+{
+ int level_multiply;
+	sscanf(buf, "%d", &level_multiply);
+	if (level_multiply > 100)
+	level_multiply = 100;
+	else if (level_multiply < 0)
+	level_multiply = 0;
+
+	vib_dev->level = VIB_MIN_LEVEL_mV/100 + vib_level_range * level_multiply / 100;
+
+	return size;
+}
+
+static struct device_attribute pm8xxx_vib_device_attrs[] = {
+ __ATTR(amp, S_IWUSR | S_IRUGO, pm8xxx_vib_voltage_show, pm8xxx_vib_voltage_store),
+};
+
#ifdef CONFIG_PM
static int pm8xxx_vib_suspend(struct device *dev)
{
@@ -224,7 +258,7 @@ static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
struct pm8xxx_vib *vib;
u8 val;
int rc;
-
+	int i;
if (!pdata)
return -EINVAL;

@@ -275,12 +309,27 @@ static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vib);

vib_dev = vib;
+	for (i = 0; i < ARRAY_SIZE(pm8xxx_vib_device_attrs); i++) {
+	rc = device_create_file(vib->dev,
+	&pm8xxx_vib_device_attrs[i]);
+	if (rc < 0) {
+	pr_err("%s: failed to create sysfs\n", __func__);
+	goto err_sysfs;
+	}
+	}

return 0;

err_read_vib:
kfree(vib);
return rc;
+
+err_sysfs:
+	for (; i >= 0; i--) {
+	device_remove_file(vib->dev,
+	&pm8xxx_vib_device_attrs[i]);
+	}
+	return rc;
}

static int __devexit pm8xxx_vib_remove(struct platform_device *pdev)
--
1.7.10.4