blob: 0e3146ede80e3592bc38bcc9f200784931afd603 [file] [log] [blame]
/*
* DRV2603 haptic driver for LRA and ERM vibrator motor
*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/pwm.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/input/drv2603-vibrator.h>
#include <linux/edp.h>
#define DEFAULT_DUTY_CYCLE 80
enum drv2603_state {
VIBRATOR_OFF,
VIBRATOR_ON,
};
struct drv2603_chip {
int pwm_id;
struct pwm_device *pwm_device;
struct device *dev;
struct input_dev *input_dev;
struct regulator *regulator;
struct work_struct work;
int gpio;
int duty_cycle;
enum drv2603_mode vibrator_mode;
enum drv2603_state state;
struct edp_client *haptic_edp_client;
};
static int drv2603_set_duty_cycle(struct drv2603_chip *chip, int val)
{
return pwm_config(chip->pwm_device, val * 100, 10000);
}
static int drv2603_vibrator_initialize(struct drv2603_chip *chip)
{
int ret;
chip->duty_cycle = DEFAULT_DUTY_CYCLE;
ret = drv2603_set_duty_cycle(chip, chip->duty_cycle);
if (ret) {
dev_err(chip->dev, "Failed to initialize pwm config\n");
return ret;
}
ret = gpio_request_one(chip->gpio, GPIOF_OUT_INIT_LOW, NULL);
if (ret) {
dev_err(chip->dev, "Failed to request gpio\n");
return ret;
}
return 0;
}
static int drv2603_vibrate(struct drv2603_chip *chip)
{
int ret;
unsigned int approved;
switch (chip->state) {
case VIBRATOR_OFF:
if (chip->haptic_edp_client) {
ret = edp_update_client_request(chip->haptic_edp_client,
DRV2603_HAPTIC_EDP_LOW, &approved);
if (ret) {
dev_err(chip->dev,
"E state transition failed\n");
return ret;
}
}
gpio_set_value_cansleep(chip->gpio, 0);
drv2603_set_duty_cycle(chip, 0);
pwm_disable(chip->pwm_device);
regulator_disable(chip->regulator);
break;
case VIBRATOR_ON:
if (chip->haptic_edp_client) {
ret = edp_update_client_request(chip->haptic_edp_client,
DRV2603_HAPTIC_EDP_HIGH, &approved);
if (ret || approved != DRV2603_HAPTIC_EDP_HIGH) {
dev_err(chip->dev,
"E state transition failed\n");
return ret;
}
}
regulator_enable(chip->regulator);
drv2603_set_duty_cycle(chip, chip->duty_cycle);
gpio_set_value_cansleep(chip->gpio, 1);
pwm_enable(chip->pwm_device);
break;
}
return 0;
}
static void drv2603_haptic_play_effect_work(struct work_struct *work)
{
struct drv2603_chip *chip =
container_of(work, struct drv2603_chip, work);
drv2603_vibrate(chip);
}
static int drv2603_haptic_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct drv2603_chip *chip = input_get_drvdata(dev);
int magnitude = effect->u.rumble.strong_magnitude;
if (!magnitude)
magnitude = effect->u.rumble.weak_magnitude;
if (magnitude && chip->state == VIBRATOR_OFF) {
chip->state = VIBRATOR_ON;
schedule_work(&chip->work);
} else if (!magnitude && chip->state == VIBRATOR_ON) {
chip->state = VIBRATOR_OFF;
schedule_work(&chip->work);
}
return 0;
}
static ssize_t drv2603_vibrator_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct drv2603_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", chip->state);
}
static ssize_t drv2603_vibrator_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct drv2603_chip *chip = dev_get_drvdata(dev);
int var;
sscanf(buf, "%d", &var);
if (var == 0 && chip->state == VIBRATOR_ON) {
cancel_work_sync(&chip->work);
chip->state = VIBRATOR_OFF;
schedule_work(&chip->work);
} else if (var == 1 && chip->state == VIBRATOR_OFF) {
cancel_work_sync(&chip->work);
chip->state = VIBRATOR_ON;
schedule_work(&chip->work);
}
return count;
}
static ssize_t drv2603_vibrator_duty_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct drv2603_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", chip->duty_cycle);
}
static ssize_t drv2603_vibrator_duty_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct drv2603_chip *chip = dev_get_drvdata(dev);
int duty_cycle;
sscanf(buf, "%d", &duty_cycle);
if (duty_cycle >= 0 && duty_cycle <= 100)
chip->duty_cycle = duty_cycle;
else
dev_err(dev, "Duty cycle should be in range 0-100\n");
return count;
}
static void drv2603_vibrator_throttle(unsigned int new_state, void *priv_data)
{
struct drv2603_chip *chip = priv_data;
if (!chip)
return;
if (chip->state == VIBRATOR_ON) {
chip->state = VIBRATOR_OFF;
drv2603_vibrate(chip);
}
}
static DEVICE_ATTR(vibrator_enable, 0640, drv2603_vibrator_enable_show,
drv2603_vibrator_enable_store);
static DEVICE_ATTR(duty_cycle, 0640, drv2603_vibrator_duty_cycle_show,
drv2603_vibrator_duty_cycle_store);
static struct attribute *drv2603_vibrator_attr[] = {
&dev_attr_vibrator_enable.attr,
&dev_attr_duty_cycle.attr,
NULL,
};
static const struct attribute_group drv2603_vibrator_attr_group = {
.attrs = drv2603_vibrator_attr,
};
static int drv2603_probe(struct platform_device *pdev)
{
int ret;
struct drv2603_chip *chip;
struct input_dev *input_dev;
struct edp_manager *battery_manager = NULL;
struct drv2603_platform_data *drv2603_pdata =
dev_get_platdata(&pdev->dev);
chip = devm_kzalloc(&pdev->dev, sizeof(*chip),
GFP_KERNEL);
if (!chip) {
dev_err(&pdev->dev, "Memory allocation failed for chip\n");
return -ENOMEM;
}
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&pdev->dev,
"unable to allocate memory for input dev\n");
return PTR_ERR(input_dev);
}
chip->pwm_id = drv2603_pdata->pwm_id;
chip->gpio = drv2603_pdata->gpio;
chip->duty_cycle = drv2603_pdata->duty_cycle;
chip->vibrator_mode = drv2603_pdata->vibrator_mode;
chip->dev = &pdev->dev;
chip->input_dev = input_dev;
dev_set_drvdata(&pdev->dev, chip);
chip->regulator = regulator_get(&pdev->dev, "vdd_vbrtr");
if (IS_ERR_OR_NULL(chip->regulator)) {
dev_err(&pdev->dev, "Failed to get regulator\n");
ret = PTR_ERR(chip->regulator);
goto err_regulator;
}
chip->pwm_device = pwm_request(chip->pwm_id, "drv2603-vibrator");
if (IS_ERR_OR_NULL(chip->pwm_device)) {
dev_err(&pdev->dev, "Failed to get pwm device\n");
ret = PTR_ERR(chip->pwm_device);
goto err_pwm;
}
if (drv2603_pdata->edp_states[0] == 0) {
dev_err(&pdev->dev, "EDP states invalid or not present");
goto register_input;
}
chip->haptic_edp_client = devm_kzalloc(&pdev->dev,
sizeof(struct edp_client), GFP_KERNEL);
if (IS_ERR_OR_NULL(chip->haptic_edp_client)) {
dev_err(&pdev->dev, "Could not allocate edp client\n");
goto register_input;
}
strncpy(chip->haptic_edp_client->name, "drv2603-haptic",
EDP_NAME_LEN - 1);
chip->haptic_edp_client->name[EDP_NAME_LEN - 1] = '\0';
chip->haptic_edp_client->states = drv2603_pdata->edp_states;
chip->haptic_edp_client->num_states = DRV2603_HAPTIC_EDP_NUM_STATES;
chip->haptic_edp_client->e0_index = DRV2603_HAPTIC_EDP_LOW;
chip->haptic_edp_client->priority = EDP_MAX_PRIO + 2;
chip->haptic_edp_client->throttle = drv2603_vibrator_throttle;
chip->haptic_edp_client->private_data = chip;
battery_manager = edp_get_manager("battery");
if (IS_ERR_OR_NULL(battery_manager)) {
dev_err(&pdev->dev, "Unable to get edp manager\n");
} else {
ret = edp_register_client(battery_manager,
chip->haptic_edp_client);
if (ret) {
dev_err(&pdev->dev, "Unable to register edp client\n");
} else {
ret = edp_update_client_request(chip->haptic_edp_client,
DRV2603_HAPTIC_EDP_LOW, NULL);
if (ret) {
dev_err(&pdev->dev,
"Unable to set E0 EDP state\n");
edp_unregister_client(chip->haptic_edp_client);
} else {
goto register_input;
}
}
}
devm_kfree(&pdev->dev, chip->haptic_edp_client);
chip->haptic_edp_client = NULL;
register_input:
input_dev->name = "drv2603-haptic";
input_dev->id.version = 1;
input_dev->dev.parent = &pdev->dev;
input_set_drvdata(input_dev, chip);
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
ret = input_ff_create_memless(input_dev, NULL,
drv2603_haptic_play_effect);
if (ret) {
dev_err(&pdev->dev,
"unable to create FF device(ret : %d)\n", ret);
goto err_input_create;
}
INIT_WORK(&chip->work, drv2603_haptic_play_effect_work);
ret = input_register_device(input_dev);
if (ret) {
dev_err(&pdev->dev,
"unable to register input device(ret : %d)\n", ret);
goto err_input_register;
}
ret = drv2603_vibrator_initialize(chip);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize resources\n");
goto err_vibrator_init;
}
ret = sysfs_create_group(&pdev->dev.kobj,
&drv2603_vibrator_attr_group);
if (ret) {
dev_err(&pdev->dev, "Failed to create sysfs group\n");
goto err_sysfs_create;
}
chip->state = VIBRATOR_OFF;
return 0;
err_sysfs_create:
gpio_free(chip->gpio);
err_vibrator_init:
input_unregister_device(input_dev);
err_input_register:
destroy_work_on_stack(&chip->work);
err_input_create:
edp_unregister_client(chip->haptic_edp_client);
pwm_free(chip->pwm_device);
err_pwm:
regulator_put(chip->regulator);
err_regulator:
input_free_device(input_dev);
return ret;
}
static int drv2603_remove(struct platform_device *pdev)
{
struct drv2603_chip *chip = dev_get_drvdata(&pdev->dev);
pwm_free(chip->pwm_device);
gpio_free(chip->gpio);
destroy_work_on_stack(&chip->work);
edp_unregister_client(chip->haptic_edp_client);
input_unregister_device(chip->input_dev);
input_free_device(chip->input_dev);
regulator_put(chip->regulator);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int drv2603_suspend(struct device *dev)
{
struct drv2603_chip *chip = dev_get_drvdata(dev);
if (chip->state == VIBRATOR_ON) {
chip->state = VIBRATOR_OFF;
drv2603_vibrate(chip);
}
return 0;
}
static int drv2603_resume(struct device *dev)
{
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(drv2603_pm_ops, drv2603_suspend, drv2603_resume);
static struct platform_driver drv2603_driver = {
.probe = drv2603_probe,
.remove = drv2603_remove,
.driver = {
.name = "drv2603-vibrator",
.owner = THIS_MODULE,
.pm = &drv2603_pm_ops,
},
};
static int __init drv2603_vibrator_init(void)
{
return platform_driver_register(&drv2603_driver);
}
module_init(drv2603_vibrator_init);
static void __exit drv2603_vibrator_exit(void)
{
platform_driver_unregister(&drv2603_driver);
}
module_exit(drv2603_vibrator_exit);
MODULE_DESCRIPTION("Drv2603 vibrator driver");
MODULE_AUTHOR("Sumit Sharma <sumsharma@nvidia.com>");
MODULE_LICENSE("GPL v2");