/*
 * Arizona haptics driver
 *
 * Copyright 2012 Wolfson Microelectronics plc
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 * 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/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>

#include <sound/soc.h>
#include <sound/soc-dapm.h>

#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>

struct arizona_haptics {
	struct arizona *arizona;
	struct input_dev *input_dev;
	struct work_struct work;

	struct mutex mutex;
	u8 intensity;
};

static void arizona_haptics_work(struct work_struct *work)
{
	struct arizona_haptics *haptics = container_of(work,
						       struct arizona_haptics,
						       work);
	struct arizona *arizona = haptics->arizona;
	struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
	int ret;

	if (!haptics->arizona->dapm) {
		dev_err(arizona->dev, "No DAPM context\n");
		return;
	}

	if (haptics->intensity) {
		ret = regmap_update_bits(arizona->regmap,
					 ARIZONA_HAPTICS_PHASE_2_INTENSITY,
					 ARIZONA_PHASE2_INTENSITY_MASK,
					 haptics->intensity);
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to set intensity: %d\n",
				ret);
			return;
		}

		/* This enable sequence will be a noop if already enabled */
		ret = regmap_update_bits(arizona->regmap,
					 ARIZONA_HAPTICS_CONTROL_1,
					 ARIZONA_HAP_CTRL_MASK,
					 1 << ARIZONA_HAP_CTRL_SHIFT);
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to start haptics: %d\n",
				ret);
			return;
		}

		mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);

		ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
				ret);
			mutex_unlock(dapm_mutex);
			return;
		}

		ret = snd_soc_dapm_sync(arizona->dapm);
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
				ret);
			mutex_unlock(dapm_mutex);
			return;
		}

		mutex_unlock(dapm_mutex);

	} else {
		/* This disable sequence will be a noop if already enabled */
		mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);

		ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
				ret);
			mutex_unlock(dapm_mutex);
			return;
		}

		ret = snd_soc_dapm_sync(arizona->dapm);
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
				ret);
			mutex_unlock(dapm_mutex);
			return;
		}

		mutex_unlock(dapm_mutex);

		ret = regmap_update_bits(arizona->regmap,
					 ARIZONA_HAPTICS_CONTROL_1,
					 ARIZONA_HAP_CTRL_MASK,
					 1 << ARIZONA_HAP_CTRL_SHIFT);
		if (ret != 0) {
			dev_err(arizona->dev, "Failed to stop haptics: %d\n",
				ret);
			return;
		}
	}
}

static int arizona_haptics_play(struct input_dev *input, void *data,
				struct ff_effect *effect)
{
	struct arizona_haptics *haptics = input_get_drvdata(input);
	struct arizona *arizona = haptics->arizona;

	if (!arizona->dapm) {
		dev_err(arizona->dev, "No DAPM context\n");
		return -EBUSY;
	}

	if (effect->u.rumble.strong_magnitude) {
		/* Scale the magnitude into the range the device supports */
		if (arizona->pdata.hap_act) {
			haptics->intensity =
				effect->u.rumble.strong_magnitude >> 9;
			if (effect->direction < 0x8000)
				haptics->intensity += 0x7f;
		} else {
			haptics->intensity =
				effect->u.rumble.strong_magnitude >> 8;
		}
	} else {
		haptics->intensity = 0;
	}

	schedule_work(&haptics->work);

	return 0;
}

static void arizona_haptics_close(struct input_dev *input)
{
	struct arizona_haptics *haptics = input_get_drvdata(input);
	struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;

	cancel_work_sync(&haptics->work);

	mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);

	if (haptics->arizona->dapm)
		snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");

	mutex_unlock(dapm_mutex);
}

static int arizona_haptics_probe(struct platform_device *pdev)
{
	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
	struct arizona_haptics *haptics;
	int ret;

	haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
	if (!haptics)
		return -ENOMEM;

	haptics->arizona = arizona;

	ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
				 ARIZONA_HAP_ACT, arizona->pdata.hap_act);
	if (ret != 0) {
		dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
			ret);
		return ret;
	}

	INIT_WORK(&haptics->work, arizona_haptics_work);

	haptics->input_dev = input_allocate_device();
	if (haptics->input_dev == NULL) {
		dev_err(arizona->dev, "Failed to allocate input device\n");
		return -ENOMEM;
	}

	input_set_drvdata(haptics->input_dev, haptics);

	haptics->input_dev->name = "arizona:haptics";
	haptics->input_dev->dev.parent = pdev->dev.parent;
	haptics->input_dev->close = arizona_haptics_close;
	__set_bit(FF_RUMBLE, haptics->input_dev->ffbit);

	ret = input_ff_create_memless(haptics->input_dev, NULL,
				      arizona_haptics_play);
	if (ret < 0) {
		dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
			ret);
		goto err_ialloc;
	}

	ret = input_register_device(haptics->input_dev);
	if (ret < 0) {
		dev_err(arizona->dev, "couldn't register input device: %d\n",
			ret);
		goto err_iff;
	}

	platform_set_drvdata(pdev, haptics);

	return 0;

err_iff:
	if (haptics->input_dev)
		input_ff_destroy(haptics->input_dev);
err_ialloc:
	input_free_device(haptics->input_dev);

	return ret;
}

static int arizona_haptics_remove(struct platform_device *pdev)
{
	struct arizona_haptics *haptics = platform_get_drvdata(pdev);

	input_unregister_device(haptics->input_dev);

	return 0;
}

static struct platform_driver arizona_haptics_driver = {
	.probe		= arizona_haptics_probe,
	.remove		= arizona_haptics_remove,
	.driver		= {
		.name	= "arizona-haptics",
		.owner	= THIS_MODULE,
	},
};
module_platform_driver(arizona_haptics_driver);

MODULE_ALIAS("platform:arizona-haptics");
MODULE_DESCRIPTION("Arizona haptics driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
