Skip to content

Commit

Permalink
max8997_vibrator: user configurable vibrator intensity
Browse files Browse the repository at this point in the history
Based on codeworkx's GT-I9300 implementation

Conflicts:

	drivers/motor/max8997_vibrator.c
  • Loading branch information
Entropy512 authored and Gokhan Moral committed Sep 4, 2012
1 parent 9bc092b commit e39f3af
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 54 deletions.
86 changes: 79 additions & 7 deletions drivers/motor/max8997_vibrator.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/*
* haptic motor driver for max8997 - max8997_vibrator.c
*
* Copyright (C) 2011 Unknown Samsung Employees (Original file was missing copyright header)
* Copyright (C) 2012 The CyanogenMod Project
* Daniel Hillenbrand <codeworkx@cyanogenmod.com>
* Andrew Dodd <atd7@cornell.edu>
*
* 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.
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timed_output.h>
Expand All @@ -14,6 +27,9 @@
#include "mach/gpio.h"
#endif

static unsigned long pwm_val = 50; /* duty in percent */
static int pwm_duty = 28230; /* duty value, 37640=100% 28230=50%, 18820=0% */

struct vibrator_drvdata {
struct max8997_motor_data *pdata;
struct pwm_device *pwm;
Expand All @@ -31,9 +47,6 @@ struct vibrator_drvdata {
struct vibrator_drvdata *g_data;
#endif

#define VIBRATOR_PERIOD 38022
extern int vibrator_duty;

static int vibetonz_clk_on(struct device *dev, bool en)
{
struct clk *vibetonz_clk = NULL;
Expand Down Expand Up @@ -92,7 +105,7 @@ static void vibrator_work(struct work_struct *_work)
struct vibrator_drvdata *data =
container_of(_work, struct vibrator_drvdata, work);

printk(KERN_DEBUG "[VIB] time = %dms\n", data->timeout);
pr_debug("[VIB] time = %dms\n", data->timeout);

if (0 == data->timeout) {
if (!data->running)
Expand All @@ -113,8 +126,8 @@ static void vibrator_work(struct work_struct *_work)
else
regulator_enable(data->regulator);
i2c_max8997_hapticmotor(data, true);
pwm_config(data->pwm,
vibrator_duty, VIBRATOR_PERIOD);
pwm_config(data->pwm, pwm_duty, data->pdata->period);
pr_info("[VIB] %s: pwm_config duty=%d\n", __func__, pwm_duty);
pwm_enable(data->pwm);

data->running = true;
Expand Down Expand Up @@ -192,7 +205,6 @@ void vibtonz_pwm(int nForce)
/* add to avoid the glitch issue */
static int prev_duty;
int pwm_period = data->pdata->period;
int pwm_duty = pwm_period/2 + ((pwm_period/2 - 2) * nForce)/127;

#if defined(CONFIG_MACH_P4)
if (pwm_duty > data->pdata->duty)
Expand All @@ -204,12 +216,70 @@ void vibtonz_pwm(int nForce)
/* add to avoid the glitch issue */
if (prev_duty != pwm_duty) {
prev_duty = pwm_duty;
pr_debug("[VIB] %s: setting pwm_duty=%d", __func__, pwm_duty);
pwm_config(data->pwm, pwm_duty, pwm_period);
}
}
EXPORT_SYMBOL(vibtonz_pwm);
#endif

static ssize_t pwm_val_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int count;

pwm_val = ((pwm_duty - 18820) * 100) / 18820;

count = sprintf(buf, "%lu\n", pwm_val);
pr_debug("[VIB] pwm_val: %lu\n", pwm_val);

return count;
}

ssize_t pwm_val_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
if (kstrtoul(buf, 0, &pwm_val))
pr_err("[VIB] %s: error on storing pwm_val\n", __func__);

pr_info("[VIB] %s: pwm_val=%lu\n", __func__, pwm_val);

pwm_duty = (pwm_val * 18820) / 100 + 18820;

/* make sure new pwm duty is in range */
if(pwm_duty > 37640) {
pwm_duty = 37640;
}
else if (pwm_duty < 18820) {
pwm_duty = 18820;
}

pr_info("[VIB] %s: pwm_duty=%d\n", __func__, pwm_duty);

return size;
}
static DEVICE_ATTR(pwm_val, S_IRUGO | S_IWUSR,
pwm_val_show, pwm_val_store);

static int create_vibrator_sysfs(void)
{
int ret;
struct kobject *vibrator_kobj;
vibrator_kobj = kobject_create_and_add("vibrator", NULL);
if (unlikely(!vibrator_kobj))
return -ENOMEM;

ret = sysfs_create_file(vibrator_kobj,
&dev_attr_pwm_val.attr);
if (unlikely(ret < 0)) {
pr_err("[VIB] sysfs_create_file failed: %d\n", ret);
return ret;
}

return 0;
}

static int __devinit vibrator_probe(struct platform_device *pdev)
{
struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
Expand Down Expand Up @@ -250,6 +320,8 @@ static int __devinit vibrator_probe(struct platform_device *pdev)
INIT_WORK(&ddata->work, vibrator_work);
spin_lock_init(&ddata->lock);

create_vibrator_sysfs();

ddata->pwm = pwm_request(pdata->pwm_id, "vibrator");
if (IS_ERR(ddata->pwm)) {
pr_err("[VIB] Failed to request pwm.\n");
Expand Down
47 changes: 0 additions & 47 deletions drivers/motor/tspdrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,6 @@ static int g_nMajor;
#include "VibeOSKernelLinuxTime.c"
#endif

#define VIBRATOR_LEVEL_DEFAULT 6
#define VIBRATOR_DUTY_DEFAULT 38000
static const int vibrator_duty_levels[] = { 26000, 28000, 30000, 32000, 34000, 36000, VIBRATOR_DUTY_DEFAULT };
static int vibrator_level = VIBRATOR_LEVEL_DEFAULT;
int vibrator_duty = VIBRATOR_DUTY_DEFAULT;

/* File IO */
static int open(struct inode *inode, struct file *file);
static int release(struct inode *inode, struct file *file);
Expand All @@ -134,39 +128,6 @@ static const struct file_operations fops = {
.llseek = default_llseek
};

static ssize_t show_vibrator_level_max(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%d\n", (ARRAY_SIZE(vibrator_duty_levels) - 1));
}

static ssize_t show_vibrator_level(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf,"%d\n", vibrator_level);
}

static ssize_t store_vibrator_level(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
int data = 0;
if (sscanf(buf, "%u\n", &data) == 1) {
if (data >= ARRAY_SIZE(vibrator_duty_levels))
data = ARRAY_SIZE(vibrator_duty_levels) - 1;
else if (data < 0)
data = 0;
vibrator_level = data;
vibrator_duty = vibrator_duty_levels[vibrator_level];
} else {
printk(KERN_ERR "tspdrv: invalid vibrator level\n");
}
return len;
}

static DEVICE_ATTR(vibrator_level_max, S_IRUGO | S_IWUGO, show_vibrator_level_max, NULL);
static DEVICE_ATTR(vibrator_level, S_IRUGO | S_IWUGO, show_vibrator_level, store_vibrator_level);

#ifndef IMPLEMENT_AS_CHAR_DRIVER
static struct miscdevice miscdev = {
.minor = MISC_DYNAMIC_MINOR,
Expand Down Expand Up @@ -310,14 +271,6 @@ int init_module(void)
}

wake_lock_init(&vib_wake_lock, WAKE_LOCK_SUSPEND, "vib_present");

if (device_create_file(&platdev.dev, &dev_attr_vibrator_level_max) < 0) {
printk(KERN_ERR "Failed to create device file(%s)!\n", dev_attr_vibrator_level_max.attr.name);
}
if (device_create_file(&platdev.dev, &dev_attr_vibrator_level) < 0) {
printk(KERN_ERR "Failed to create device file(%s)!\n", dev_attr_vibrator_level.attr.name);
}

return 0;

err_platform_drv_reg:
Expand Down

0 comments on commit e39f3af

Please sign in to comment.