linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Add max77693 haptic driver
@ 2014-09-05 11:48 Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 1/4] mfd: max77693: Initialize haptic register map Jaewon Kim
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Jaewon Kim @ 2014-09-05 11:48 UTC (permalink / raw)
  To: Dmitry Torokhov, Samuel Ortiz, Lee Jones
  Cc: linux-kernel, linux-input, Chanwoo Choi, Jaewon Kim

This series adds max77693 haptic driver.
The max77693 is a Multifunction device with PMIC, CHARGER, LED,
MUIC, HAPTIC and this series is haptic device driver in MAX77693.
The haptic driver use regmap method for i2c communication and
support force feedback framework in input device.

Changes in v3:
 - driver : remove mutex in workqueue
 - driver : mv max77693_haptic_set_duty_cyle() to workqueue.
 - driver : remove max77693_haptic_remove[]
 - driver : add suspend() function to turn-off entering suspend.

Changes in v2:
 - split to documentation and mfd patchs.
 - Documentation : change explanation of haptic 
 - Documentation : remove pwm-names propertie in example

Jaewon Kim (4):
  mfd: max77693: Initialize haptic register map
  Input: misc: Add haptic driver on max77693
  mfd: max77693: add haptic of_compatible in mfd_cell
  mfd: max77693: Update DT binding to support haptic

 Documentation/devicetree/bindings/mfd/max77693.txt |   18 ++
 drivers/input/misc/Kconfig                         |   12 +
 drivers/input/misc/Makefile                        |    1 +
 drivers/input/misc/max77693-haptic.c               |  321 ++++++++++++++++++++
 drivers/mfd/max77693.c                             |   26 +-
 include/linux/mfd/max77693-private.h               |    9 +
 6 files changed, 383 insertions(+), 4 deletions(-)
 create mode 100644 drivers/input/misc/max77693-haptic.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/4] mfd: max77693: Initialize haptic register map
  2014-09-05 11:48 [PATCH v3 0/4] Add max77693 haptic driver Jaewon Kim
@ 2014-09-05 11:48 ` Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Jaewon Kim @ 2014-09-05 11:48 UTC (permalink / raw)
  To: Dmitry Torokhov, Samuel Ortiz, Lee Jones
  Cc: linux-kernel, linux-input, Chanwoo Choi, Jaewon Kim

This patch add regmap_haptic initialization to use haptic register map
in haptic device driver.

Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/max77693.c |   21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index 249c139..fbfed56 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -144,6 +144,12 @@ static const struct regmap_irq_chip max77693_muic_irq_chip = {
 	.num_irqs		= ARRAY_SIZE(max77693_muic_irqs),
 };
 
+static const struct regmap_config max77693_regmap_haptic_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = MAX77693_HAPTIC_REG_END,
+};
+
 static int max77693_i2c_probe(struct i2c_client *i2c,
 			      const struct i2c_device_id *id)
 {
@@ -193,6 +199,15 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 	}
 	i2c_set_clientdata(max77693->haptic, max77693);
 
+	max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic,
+					&max77693_regmap_haptic_config);
+	if (IS_ERR(max77693->regmap_haptic)) {
+		ret = PTR_ERR(max77693->regmap_haptic);
+		dev_err(max77693->dev,
+			"failed to initialize haptic register map: %d\n", ret);
+		goto err_regmap;
+	}
+
 	/*
 	 * Initialize register map for MUIC device because use regmap-muic
 	 * instance of MUIC device when irq of max77693 is initialized
@@ -204,7 +219,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 		ret = PTR_ERR(max77693->regmap_muic);
 		dev_err(max77693->dev,
 			"failed to allocate register map: %d\n", ret);
-		goto err_regmap_muic;
+		goto err_regmap;
 	}
 
 	ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@@ -214,7 +229,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 				&max77693->irq_data_led);
 	if (ret) {
 		dev_err(max77693->dev, "failed to add irq chip: %d\n", ret);
-		goto err_regmap_muic;
+		goto err_regmap;
 	}
 
 	ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@@ -265,7 +280,7 @@ err_irq_charger:
 	regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys);
 err_irq_topsys:
 	regmap_del_irq_chip(max77693->irq, max77693->irq_data_led);
-err_regmap_muic:
+err_regmap:
 	i2c_unregister_device(max77693->haptic);
 err_i2c_haptic:
 	i2c_unregister_device(max77693->muic);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/4] Input: misc: Add haptic driver on max77693
  2014-09-05 11:48 [PATCH v3 0/4] Add max77693 haptic driver Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 1/4] mfd: max77693: Initialize haptic register map Jaewon Kim
@ 2014-09-05 11:48 ` Jaewon Kim
  2014-09-08 13:05   ` Lee Jones
                     ` (2 more replies)
  2014-09-05 11:48 ` [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 4/4] mfd: max77693: Update DT binding to support haptic Jaewon Kim
  3 siblings, 3 replies; 9+ messages in thread
From: Jaewon Kim @ 2014-09-05 11:48 UTC (permalink / raw)
  To: Dmitry Torokhov, Samuel Ortiz, Lee Jones
  Cc: linux-kernel, linux-input, Chanwoo Choi, Jaewon Kim

This patch add max77693-haptic device driver to support the haptic controller
on MAX77693. The MAX77693 is a Multifunction device with PMIC, CHARGER, LED,
MUIC, HAPTIC and the patch is haptic device driver in the MAX77693. This driver
support external pwm and LRA(Linear Resonant Actuator) motor. User can control
the haptic driver by using force feedback framework.

Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/input/misc/Kconfig           |   12 ++
 drivers/input/misc/Makefile          |    1 +
 drivers/input/misc/max77693-haptic.c |  321 ++++++++++++++++++++++++++++++++++
 include/linux/mfd/max77693-private.h |    9 +
 4 files changed, 343 insertions(+)
 create mode 100644 drivers/input/misc/max77693-haptic.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 2ff4425..c597c52 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -144,6 +144,18 @@ config INPUT_M68K_BEEP
 	tristate "M68k Beeper support"
 	depends on M68K
 
+config INPUT_MAX77693_HAPTIC
+	tristate "MAXIM MAX77693 haptic controller support"
+	depends on MFD_MAX77693 && PWM
+	select INPUT_FF_MEMLESS
+	help
+	  This option enables device driver support for the haptic controller
+	  on MAXIM MAX77693 chip. This driver supports ff-memless interface
+	  from input framework.
+
+	  To compile this driver as module, choose M here: the
+	  module will be called max77693-haptic.
+
 config INPUT_MAX8925_ONKEY
 	tristate "MAX8925 ONKEY support"
 	depends on MFD_MAX8925
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 4955ad3..b28570c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
+obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
 obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
 obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
 obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
new file mode 100644
index 0000000..d06026b
--- /dev/null
+++ b/drivers/input/misc/max77693-haptic.c
@@ -0,0 +1,321 @@
+/*
+ * max77693-haptic.c - MAXIM MAX77693 Haptic device driver
+ *
+ * Copyright (C) 2014 Samsung Electronics
+ * Jaewon Kim <jaewon02.kim@samsung.com>
+ *
+ * This program is not provided / owned by Maxim Integrated Products.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/max77693.h>
+#include <linux/mfd/max77693-private.h>
+
+#define MAX_MAGNITUDE_SHIFT	16
+
+enum max77693_haptic_motor_type {
+	MAX77693_HAPTIC_ERM = 0,
+	MAX77693_HAPTIC_LRA,
+};
+
+enum max77693_haptic_pulse_mode {
+	MAX77693_HAPTIC_EXTERNAL_MODE = 0,
+	MAX77693_HAPTIC_INTERNAL_MODE,
+};
+
+enum max77693_haptic_pwm_divisor {
+	MAX77693_HAPTIC_PWM_DIVISOR_32 = 0,
+	MAX77693_HAPTIC_PWM_DIVISOR_64,
+	MAX77693_HAPTIC_PWM_DIVISOR_128,
+	MAX77693_HAPTIC_PWM_DIVISOR_256,
+};
+
+struct max77693_haptic {
+	struct regmap *regmap_pmic;
+	struct regmap *regmap_haptic;
+	struct device *dev;
+	struct input_dev *input_dev;
+	struct pwm_device *pwm_dev;
+	struct regulator *motor_reg;
+
+	bool enabled;
+	unsigned int magnitude;
+	unsigned int pwm_duty;
+	enum max77693_haptic_motor_type type;
+	enum max77693_haptic_pulse_mode mode;
+	enum max77693_haptic_pwm_divisor pwm_divisor;
+
+	struct work_struct work;
+};
+
+static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
+{
+	int ret;
+	int delta = (haptic->pwm_dev->period + haptic->pwm_duty)/2;
+
+	ret = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
+	if (ret) {
+		dev_err(haptic->dev, "cannot configuration pwm\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77693_haptic_configure(struct max77693_haptic *haptic,
+						unsigned int enable)
+{
+	int ret;
+	unsigned int value = 0;
+
+	value = ((haptic->type << MAX77693_CONFIG2_MODE) |
+		(enable << MAX77693_CONFIG2_MEN) |
+		(haptic->mode << MAX77693_CONFIG2_HTYP) |
+		(haptic->pwm_divisor));
+
+	ret = regmap_write(haptic->regmap_haptic,
+				MAX77693_HAPTIC_REG_CONFIG2, value);
+	if (ret) {
+		dev_err(haptic->dev, "cannot write haptic regmap\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77693_haptic_lowsys(struct max77693_haptic *haptic,
+						unsigned int enable)
+{
+	int ret;
+
+	ret = regmap_update_bits(haptic->regmap_pmic,
+			MAX77693_PMIC_REG_LSCNFG,
+			MAX77693_PMIC_LOW_SYS_MASK,
+			enable << MAX77693_PMIC_LOW_SYS_SHIFT);
+	if (ret) {
+		dev_err(haptic->dev, "cannot update pmic regmap\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void max77693_haptic_enable(struct max77693_haptic *haptic)
+{
+	int ret;
+
+	if (haptic->enabled)
+		return;
+
+	ret = pwm_enable(haptic->pwm_dev);
+	if (ret) {
+		dev_err(haptic->dev, "cannot enable haptic pwm device");
+		return;
+	}
+
+	ret = max77693_haptic_lowsys(haptic, 1);
+	if (ret)
+		goto err_enable_lowsys;
+
+	ret = max77693_haptic_configure(haptic, 1);
+	if (ret)
+		goto err_enable_config;
+
+	haptic->enabled = true;
+
+	return;
+
+err_enable_config:
+	max77693_haptic_lowsys(haptic, 0);
+err_enable_lowsys:
+	pwm_disable(haptic->pwm_dev);
+}
+
+static void max77693_haptic_disable(struct max77693_haptic *haptic)
+{
+	int ret;
+
+	if (!haptic->enabled)
+		return;
+
+	ret = max77693_haptic_configure(haptic, 0);
+	if (ret)
+		return;
+
+	ret = max77693_haptic_lowsys(haptic, 0);
+	if (ret)
+		goto err_disable_lowsys;
+
+	pwm_disable(haptic->pwm_dev);
+	haptic->enabled = false;
+
+	return;
+
+err_disable_lowsys:
+	max77693_haptic_configure(haptic, 1);
+}
+
+static void max77693_haptic_play_work(struct work_struct *work)
+{
+	struct max77693_haptic *haptic =
+			container_of(work, struct max77693_haptic, work);
+	int ret;
+
+	ret = max77693_haptic_set_duty_cycle(haptic);
+	if (ret) {
+		dev_err(haptic->dev, "cannot set duty cycle\n");
+		return;
+	}
+
+	if (haptic->magnitude)
+		max77693_haptic_enable(haptic);
+	else
+		max77693_haptic_disable(haptic);
+}
+
+static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
+				struct ff_effect *effect)
+{
+	struct max77693_haptic *haptic = input_get_drvdata(dev);
+	uint64_t period_mag_multi;
+
+	haptic->magnitude = effect->u.rumble.strong_magnitude;
+	if (!haptic->magnitude)
+		haptic->magnitude = effect->u.rumble.weak_magnitude;
+
+	/*
+	 * The magnitude comes from force-feedback interface.
+	 * The formula convert magnitude to pwm_duty as following:
+	 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
+	 */
+	period_mag_multi = (int64_t)(haptic->pwm_dev->period *
+						haptic->magnitude);
+	haptic->pwm_duty = (unsigned int)(period_mag_multi >>
+						MAX_MAGNITUDE_SHIFT);
+
+	schedule_work(&haptic->work);
+
+	return 0;
+}
+
+static void max77693_haptic_close(struct input_dev *dev)
+{
+	struct max77693_haptic *haptic = input_get_drvdata(dev);
+
+	cancel_work_sync(&haptic->work);
+	max77693_haptic_disable(haptic);
+}
+
+static int max77693_haptic_probe(struct platform_device *pdev)
+{
+	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
+	struct max77693_haptic *haptic;
+	int ret = 0;
+
+	haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
+	if (!haptic)
+		return -ENOMEM;
+
+	haptic->regmap_pmic = max77693->regmap;
+	haptic->regmap_haptic = max77693->regmap_haptic;
+	haptic->dev = &pdev->dev;
+	haptic->type = MAX77693_HAPTIC_LRA;
+	haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
+	haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
+
+	/* Get pwm and regulatot for haptic device */
+	haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
+	if (IS_ERR(haptic->pwm_dev)) {
+		dev_err(&pdev->dev, "failed to get pwm device\n");
+		return PTR_ERR(haptic->pwm_dev);
+	}
+
+	haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
+	if (IS_ERR(haptic->motor_reg)) {
+		dev_err(&pdev->dev, "failed to get regulator\n");
+		return PTR_ERR(haptic->motor_reg);
+	}
+
+	ret = regulator_enable(haptic->motor_reg);
+	if (ret) {
+		dev_err(haptic->dev, "failed to enable regulator\n");
+		return ret;
+	}
+
+	/* Initialize input device for haptic device */
+	haptic->input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!haptic->input_dev) {
+		dev_err(&pdev->dev, "failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	haptic->input_dev->name = "max77693-haptic";
+	haptic->input_dev->id.version = 1;
+	haptic->input_dev->dev.parent = &pdev->dev;
+	haptic->input_dev->close = max77693_haptic_close;
+	input_set_drvdata(haptic->input_dev, haptic);
+	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
+
+	ret = input_ff_create_memless(haptic->input_dev, NULL,
+				max77693_haptic_play_effect);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to create force-feedback\n");
+		return ret;
+	}
+
+	ret = input_register_device(haptic->input_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register input device\n");
+		return ret;
+	}
+
+	INIT_WORK(&haptic->work, max77693_haptic_play_work);
+
+	platform_set_drvdata(pdev, haptic);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77693_haptic_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct max77693_haptic *haptic = platform_get_drvdata(pdev);
+
+	max77693_haptic_disable(haptic);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, NULL);
+
+static struct platform_driver max77693_haptic_driver = {
+	.driver		= {
+		.name	= "max77693-haptic",
+		.owner	= THIS_MODULE,
+		.pm	= &max77693_haptic_pm_ops,
+	},
+	.probe		= max77693_haptic_probe,
+};
+module_platform_driver(max77693_haptic_driver);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
+MODULE_ALIAS("platform:max77693-haptic");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index c466ff3..d0e578f 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -251,6 +251,15 @@ enum max77693_haptic_reg {
 	MAX77693_HAPTIC_REG_END,
 };
 
+/* max77693-pmic LSCNFG configuraton register */
+#define MAX77693_PMIC_LOW_SYS_MASK      0x80
+#define MAX77693_PMIC_LOW_SYS_SHIFT     7
+
+/* max77693-haptic configuration register */
+#define MAX77693_CONFIG2_MODE           7
+#define MAX77693_CONFIG2_MEN            6
+#define MAX77693_CONFIG2_HTYP           5
+
 enum max77693_irq_source {
 	LED_INT = 0,
 	TOPSYS_INT,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell
  2014-09-05 11:48 [PATCH v3 0/4] Add max77693 haptic driver Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 1/4] mfd: max77693: Initialize haptic register map Jaewon Kim
  2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
@ 2014-09-05 11:48 ` Jaewon Kim
  2014-09-09  8:15   ` Lee Jones
  2014-09-05 11:48 ` [PATCH v3 4/4] mfd: max77693: Update DT binding to support haptic Jaewon Kim
  3 siblings, 1 reply; 9+ messages in thread
From: Jaewon Kim @ 2014-09-05 11:48 UTC (permalink / raw)
  To: Dmitry Torokhov, Samuel Ortiz, Lee Jones
  Cc: linux-kernel, linux-input, Chanwoo Choi, Jaewon Kim

This patch add haptic of_compatible in order to use the haptic
device driver using Devicetree.

Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/mfd/max77693.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index fbfed56..03fd431 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -46,7 +46,10 @@ static const struct mfd_cell max77693_devs[] = {
 	{ .name = "max77693-charger", },
 	{ .name = "max77693-flash", },
 	{ .name = "max77693-muic", },
-	{ .name = "max77693-haptic", },
+	{
+	  .name = "max77693-haptic",
+	  .of_compatible = "maxim,max77693-haptic",
+	},
 };
 
 static const struct regmap_config max77693_regmap_config = {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/4] mfd: max77693: Update DT binding to support haptic
  2014-09-05 11:48 [PATCH v3 0/4] Add max77693 haptic driver Jaewon Kim
                   ` (2 preceding siblings ...)
  2014-09-05 11:48 ` [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell Jaewon Kim
@ 2014-09-05 11:48 ` Jaewon Kim
  3 siblings, 0 replies; 9+ messages in thread
From: Jaewon Kim @ 2014-09-05 11:48 UTC (permalink / raw)
  To: Dmitry Torokhov, Samuel Ortiz, Lee Jones
  Cc: linux-kernel, linux-input, Chanwoo Choi, Jaewon Kim

This patch add haptic DT binding documentation and example
to support haptic driver in max77693 Multifunction device.

Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 Documentation/devicetree/bindings/mfd/max77693.txt |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
index 11921cc..d178b9e 100644
--- a/Documentation/devicetree/bindings/mfd/max77693.txt
+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
@@ -27,6 +27,17 @@ Optional properties:
 
 	[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
 
+- haptic : The haptic of max77693 have to be instantiated under subnod
+  named "haptic" using the following haptic format in example.
+  Haptic sensation from motor can be changed by changing a period cycle in pwms.
+
+ Required properties:
+	- compatible : Must be "maxim,max77693-hpatic"
+	- haptic-supply : power supply for haptic motor
+		[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+	- pwms : phandle to the physical PWM device,
+		[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
+
 Example:
 	max77693@66 {
 		compatible = "maxim,max77693";
@@ -52,4 +63,11 @@ Example:
 					regulator-boot-on;
 			};
 		};
+
+		haptic {
+			compatible = "maxim,max77693-haptic";
+			haptic-supply = <&haptic_supply>;
+			pwms = <&pwm 0 40000 0>;
+			pwm-names = "haptic";
+		};
 	};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/4] Input: misc: Add haptic driver on max77693
  2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
@ 2014-09-08 13:05   ` Lee Jones
  2014-09-08 21:37   ` Dmitry Torokhov
  2014-09-15 23:29   ` Lee Jones
  2 siblings, 0 replies; 9+ messages in thread
From: Lee Jones @ 2014-09-08 13:05 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: Dmitry Torokhov, Samuel Ortiz, linux-kernel, linux-input, Chanwoo Choi

On Fri, 05 Sep 2014, Jaewon Kim wrote:

> This patch add max77693-haptic device driver to support the haptic controller
> on MAX77693. The MAX77693 is a Multifunction device with PMIC, CHARGER, LED,
> MUIC, HAPTIC and the patch is haptic device driver in the MAX77693. This driver
> support external pwm and LRA(Linear Resonant Actuator) motor. User can control
> the haptic driver by using force feedback framework.
> 
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

So I guess we just need a Maintainer Ack for this, then we can take in
the set?

Can the other patches in the set be applied without this one?

> ---
>  drivers/input/misc/Kconfig           |   12 ++
>  drivers/input/misc/Makefile          |    1 +
>  drivers/input/misc/max77693-haptic.c |  321 ++++++++++++++++++++++++++++++++++
>  include/linux/mfd/max77693-private.h |    9 +
>  4 files changed, 343 insertions(+)
>  create mode 100644 drivers/input/misc/max77693-haptic.c
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 2ff4425..c597c52 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -144,6 +144,18 @@ config INPUT_M68K_BEEP
>  	tristate "M68k Beeper support"
>  	depends on M68K
>  
> +config INPUT_MAX77693_HAPTIC
> +	tristate "MAXIM MAX77693 haptic controller support"
> +	depends on MFD_MAX77693 && PWM
> +	select INPUT_FF_MEMLESS
> +	help
> +	  This option enables device driver support for the haptic controller
> +	  on MAXIM MAX77693 chip. This driver supports ff-memless interface
> +	  from input framework.
> +
> +	  To compile this driver as module, choose M here: the
> +	  module will be called max77693-haptic.
> +
>  config INPUT_MAX8925_ONKEY
>  	tristate "MAX8925 ONKEY support"
>  	depends on MFD_MAX8925
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 4955ad3..b28570c 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
>  obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
>  obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
>  obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
> +obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
>  obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
>  obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
>  obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
> diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
> new file mode 100644
> index 0000000..d06026b
> --- /dev/null
> +++ b/drivers/input/misc/max77693-haptic.c
> @@ -0,0 +1,321 @@
> +/*
> + * max77693-haptic.c - MAXIM MAX77693 Haptic device driver
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is not provided / owned by Maxim Integrated Products.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/input.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +
> +#define MAX_MAGNITUDE_SHIFT	16
> +
> +enum max77693_haptic_motor_type {
> +	MAX77693_HAPTIC_ERM = 0,
> +	MAX77693_HAPTIC_LRA,
> +};
> +
> +enum max77693_haptic_pulse_mode {
> +	MAX77693_HAPTIC_EXTERNAL_MODE = 0,
> +	MAX77693_HAPTIC_INTERNAL_MODE,
> +};
> +
> +enum max77693_haptic_pwm_divisor {
> +	MAX77693_HAPTIC_PWM_DIVISOR_32 = 0,
> +	MAX77693_HAPTIC_PWM_DIVISOR_64,
> +	MAX77693_HAPTIC_PWM_DIVISOR_128,
> +	MAX77693_HAPTIC_PWM_DIVISOR_256,
> +};
> +
> +struct max77693_haptic {
> +	struct regmap *regmap_pmic;
> +	struct regmap *regmap_haptic;
> +	struct device *dev;
> +	struct input_dev *input_dev;
> +	struct pwm_device *pwm_dev;
> +	struct regulator *motor_reg;
> +
> +	bool enabled;
> +	unsigned int magnitude;
> +	unsigned int pwm_duty;
> +	enum max77693_haptic_motor_type type;
> +	enum max77693_haptic_pulse_mode mode;
> +	enum max77693_haptic_pwm_divisor pwm_divisor;
> +
> +	struct work_struct work;
> +};
> +
> +static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +	int delta = (haptic->pwm_dev->period + haptic->pwm_duty)/2;
> +
> +	ret = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot configuration pwm\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_configure(struct max77693_haptic *haptic,
> +						unsigned int enable)
> +{
> +	int ret;
> +	unsigned int value = 0;
> +
> +	value = ((haptic->type << MAX77693_CONFIG2_MODE) |
> +		(enable << MAX77693_CONFIG2_MEN) |
> +		(haptic->mode << MAX77693_CONFIG2_HTYP) |
> +		(haptic->pwm_divisor));
> +
> +	ret = regmap_write(haptic->regmap_haptic,
> +				MAX77693_HAPTIC_REG_CONFIG2, value);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot write haptic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_lowsys(struct max77693_haptic *haptic,
> +						unsigned int enable)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(haptic->regmap_pmic,
> +			MAX77693_PMIC_REG_LSCNFG,
> +			MAX77693_PMIC_LOW_SYS_MASK,
> +			enable << MAX77693_PMIC_LOW_SYS_SHIFT);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot update pmic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_enable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (haptic->enabled)
> +		return;
> +
> +	ret = pwm_enable(haptic->pwm_dev);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot enable haptic pwm device");
> +		return;
> +	}
> +
> +	ret = max77693_haptic_lowsys(haptic, 1);
> +	if (ret)
> +		goto err_enable_lowsys;
> +
> +	ret = max77693_haptic_configure(haptic, 1);
> +	if (ret)
> +		goto err_enable_config;
> +
> +	haptic->enabled = true;
> +
> +	return;
> +
> +err_enable_config:
> +	max77693_haptic_lowsys(haptic, 0);
> +err_enable_lowsys:
> +	pwm_disable(haptic->pwm_dev);
> +}
> +
> +static void max77693_haptic_disable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (!haptic->enabled)
> +		return;
> +
> +	ret = max77693_haptic_configure(haptic, 0);
> +	if (ret)
> +		return;
> +
> +	ret = max77693_haptic_lowsys(haptic, 0);
> +	if (ret)
> +		goto err_disable_lowsys;
> +
> +	pwm_disable(haptic->pwm_dev);
> +	haptic->enabled = false;
> +
> +	return;
> +
> +err_disable_lowsys:
> +	max77693_haptic_configure(haptic, 1);
> +}
> +
> +static void max77693_haptic_play_work(struct work_struct *work)
> +{
> +	struct max77693_haptic *haptic =
> +			container_of(work, struct max77693_haptic, work);
> +	int ret;
> +
> +	ret = max77693_haptic_set_duty_cycle(haptic);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot set duty cycle\n");
> +		return;
> +	}
> +
> +	if (haptic->magnitude)
> +		max77693_haptic_enable(haptic);
> +	else
> +		max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
> +				struct ff_effect *effect)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +	uint64_t period_mag_multi;
> +
> +	haptic->magnitude = effect->u.rumble.strong_magnitude;
> +	if (!haptic->magnitude)
> +		haptic->magnitude = effect->u.rumble.weak_magnitude;
> +
> +	/*
> +	 * The magnitude comes from force-feedback interface.
> +	 * The formula convert magnitude to pwm_duty as following:
> +	 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
> +	 */
> +	period_mag_multi = (int64_t)(haptic->pwm_dev->period *
> +						haptic->magnitude);
> +	haptic->pwm_duty = (unsigned int)(period_mag_multi >>
> +						MAX_MAGNITUDE_SHIFT);
> +
> +	schedule_work(&haptic->work);
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_close(struct input_dev *dev)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +
> +	cancel_work_sync(&haptic->work);
> +	max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_probe(struct platform_device *pdev)
> +{
> +	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77693_haptic *haptic;
> +	int ret = 0;
> +
> +	haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
> +	if (!haptic)
> +		return -ENOMEM;
> +
> +	haptic->regmap_pmic = max77693->regmap;
> +	haptic->regmap_haptic = max77693->regmap_haptic;
> +	haptic->dev = &pdev->dev;
> +	haptic->type = MAX77693_HAPTIC_LRA;
> +	haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
> +	haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
> +
> +	/* Get pwm and regulatot for haptic device */
> +	haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
> +	if (IS_ERR(haptic->pwm_dev)) {
> +		dev_err(&pdev->dev, "failed to get pwm device\n");
> +		return PTR_ERR(haptic->pwm_dev);
> +	}
> +
> +	haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
> +	if (IS_ERR(haptic->motor_reg)) {
> +		dev_err(&pdev->dev, "failed to get regulator\n");
> +		return PTR_ERR(haptic->motor_reg);
> +	}
> +
> +	ret = regulator_enable(haptic->motor_reg);
> +	if (ret) {
> +		dev_err(haptic->dev, "failed to enable regulator\n");
> +		return ret;
> +	}
> +
> +	/* Initialize input device for haptic device */
> +	haptic->input_dev = devm_input_allocate_device(&pdev->dev);
> +	if (!haptic->input_dev) {
> +		dev_err(&pdev->dev, "failed to allocate input device\n");
> +		return -ENOMEM;
> +	}
> +
> +	haptic->input_dev->name = "max77693-haptic";
> +	haptic->input_dev->id.version = 1;
> +	haptic->input_dev->dev.parent = &pdev->dev;
> +	haptic->input_dev->close = max77693_haptic_close;
> +	input_set_drvdata(haptic->input_dev, haptic);
> +	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
> +
> +	ret = input_ff_create_memless(haptic->input_dev, NULL,
> +				max77693_haptic_play_effect);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to create force-feedback\n");
> +		return ret;
> +	}
> +
> +	ret = input_register_device(haptic->input_dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to register input device\n");
> +		return ret;
> +	}
> +
> +	INIT_WORK(&haptic->work, max77693_haptic_play_work);
> +
> +	platform_set_drvdata(pdev, haptic);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int max77693_haptic_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct max77693_haptic *haptic = platform_get_drvdata(pdev);
> +
> +	max77693_haptic_disable(haptic);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, NULL);
> +
> +static struct platform_driver max77693_haptic_driver = {
> +	.driver		= {
> +		.name	= "max77693-haptic",
> +		.owner	= THIS_MODULE,
> +		.pm	= &max77693_haptic_pm_ops,
> +	},
> +	.probe		= max77693_haptic_probe,
> +};
> +module_platform_driver(max77693_haptic_driver);
> +
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
> +MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
> +MODULE_ALIAS("platform:max77693-haptic");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
> index c466ff3..d0e578f 100644
> --- a/include/linux/mfd/max77693-private.h
> +++ b/include/linux/mfd/max77693-private.h
> @@ -251,6 +251,15 @@ enum max77693_haptic_reg {
>  	MAX77693_HAPTIC_REG_END,
>  };
>  
> +/* max77693-pmic LSCNFG configuraton register */
> +#define MAX77693_PMIC_LOW_SYS_MASK      0x80
> +#define MAX77693_PMIC_LOW_SYS_SHIFT     7
> +
> +/* max77693-haptic configuration register */
> +#define MAX77693_CONFIG2_MODE           7
> +#define MAX77693_CONFIG2_MEN            6
> +#define MAX77693_CONFIG2_HTYP           5
> +
>  enum max77693_irq_source {
>  	LED_INT = 0,
>  	TOPSYS_INT,

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/4] Input: misc: Add haptic driver on max77693
  2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
  2014-09-08 13:05   ` Lee Jones
@ 2014-09-08 21:37   ` Dmitry Torokhov
  2014-09-15 23:29   ` Lee Jones
  2 siblings, 0 replies; 9+ messages in thread
From: Dmitry Torokhov @ 2014-09-08 21:37 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: Samuel Ortiz, Lee Jones, linux-kernel, linux-input, Chanwoo Choi

On Fri, Sep 05, 2014 at 08:48:20PM +0900, Jaewon Kim wrote:
> This patch add max77693-haptic device driver to support the haptic controller
> on MAX77693. The MAX77693 is a Multifunction device with PMIC, CHARGER, LED,
> MUIC, HAPTIC and the patch is haptic device driver in the MAX77693. This driver
> support external pwm and LRA(Linear Resonant Actuator) motor. User can control
> the haptic driver by using force feedback framework.
> 
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/input/misc/Kconfig           |   12 ++
>  drivers/input/misc/Makefile          |    1 +
>  drivers/input/misc/max77693-haptic.c |  321 ++++++++++++++++++++++++++++++++++
>  include/linux/mfd/max77693-private.h |    9 +
>  4 files changed, 343 insertions(+)
>  create mode 100644 drivers/input/misc/max77693-haptic.c
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 2ff4425..c597c52 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -144,6 +144,18 @@ config INPUT_M68K_BEEP
>  	tristate "M68k Beeper support"
>  	depends on M68K
>  
> +config INPUT_MAX77693_HAPTIC
> +	tristate "MAXIM MAX77693 haptic controller support"
> +	depends on MFD_MAX77693 && PWM
> +	select INPUT_FF_MEMLESS
> +	help
> +	  This option enables device driver support for the haptic controller
> +	  on MAXIM MAX77693 chip. This driver supports ff-memless interface
> +	  from input framework.
> +
> +	  To compile this driver as module, choose M here: the
> +	  module will be called max77693-haptic.
> +
>  config INPUT_MAX8925_ONKEY
>  	tristate "MAX8925 ONKEY support"
>  	depends on MFD_MAX8925
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 4955ad3..b28570c 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
>  obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
>  obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
>  obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
> +obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
>  obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
>  obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
>  obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
> diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
> new file mode 100644
> index 0000000..d06026b
> --- /dev/null
> +++ b/drivers/input/misc/max77693-haptic.c
> @@ -0,0 +1,321 @@
> +/*
> + * max77693-haptic.c - MAXIM MAX77693 Haptic device driver
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is not provided / owned by Maxim Integrated Products.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/input.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +
> +#define MAX_MAGNITUDE_SHIFT	16
> +
> +enum max77693_haptic_motor_type {
> +	MAX77693_HAPTIC_ERM = 0,
> +	MAX77693_HAPTIC_LRA,
> +};
> +
> +enum max77693_haptic_pulse_mode {
> +	MAX77693_HAPTIC_EXTERNAL_MODE = 0,
> +	MAX77693_HAPTIC_INTERNAL_MODE,
> +};
> +
> +enum max77693_haptic_pwm_divisor {
> +	MAX77693_HAPTIC_PWM_DIVISOR_32 = 0,
> +	MAX77693_HAPTIC_PWM_DIVISOR_64,
> +	MAX77693_HAPTIC_PWM_DIVISOR_128,
> +	MAX77693_HAPTIC_PWM_DIVISOR_256,
> +};
> +
> +struct max77693_haptic {
> +	struct regmap *regmap_pmic;
> +	struct regmap *regmap_haptic;
> +	struct device *dev;
> +	struct input_dev *input_dev;
> +	struct pwm_device *pwm_dev;
> +	struct regulator *motor_reg;
> +
> +	bool enabled;
> +	unsigned int magnitude;
> +	unsigned int pwm_duty;
> +	enum max77693_haptic_motor_type type;
> +	enum max77693_haptic_pulse_mode mode;
> +	enum max77693_haptic_pwm_divisor pwm_divisor;
> +
> +	struct work_struct work;
> +};
> +
> +static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +	int delta = (haptic->pwm_dev->period + haptic->pwm_duty)/2;

Spaces around '/'.

> +
> +	ret = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot configuration pwm\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_configure(struct max77693_haptic *haptic,
> +						unsigned int enable)

bool?

> +{
> +	int ret;
> +	unsigned int value = 0;
> +

You do not need to initialize value and assign a brand new value to it
immediately after.

> +	value = ((haptic->type << MAX77693_CONFIG2_MODE) |
> +		(enable << MAX77693_CONFIG2_MEN) |
> +		(haptic->mode << MAX77693_CONFIG2_HTYP) |
> +		(haptic->pwm_divisor));
> +
> +	ret = regmap_write(haptic->regmap_haptic,
> +				MAX77693_HAPTIC_REG_CONFIG2, value);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot write haptic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_lowsys(struct max77693_haptic *haptic,
> +						unsigned int enable)

bool

> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(haptic->regmap_pmic,
> +			MAX77693_PMIC_REG_LSCNFG,
> +			MAX77693_PMIC_LOW_SYS_MASK,
> +			enable << MAX77693_PMIC_LOW_SYS_SHIFT);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot update pmic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_enable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (haptic->enabled)
> +		return;
> +
> +	ret = pwm_enable(haptic->pwm_dev);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot enable haptic pwm device");
> +		return;
> +	}
> +
> +	ret = max77693_haptic_lowsys(haptic, 1);
> +	if (ret)
> +		goto err_enable_lowsys;
> +
> +	ret = max77693_haptic_configure(haptic, 1);
> +	if (ret)
> +		goto err_enable_config;
> +
> +	haptic->enabled = true;
> +
> +	return;
> +
> +err_enable_config:
> +	max77693_haptic_lowsys(haptic, 0);
> +err_enable_lowsys:
> +	pwm_disable(haptic->pwm_dev);
> +}
> +
> +static void max77693_haptic_disable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (!haptic->enabled)
> +		return;
> +
> +	ret = max77693_haptic_configure(haptic, 0);
> +	if (ret)
> +		return;
> +
> +	ret = max77693_haptic_lowsys(haptic, 0);
> +	if (ret)
> +		goto err_disable_lowsys;
> +
> +	pwm_disable(haptic->pwm_dev);
> +	haptic->enabled = false;
> +
> +	return;
> +
> +err_disable_lowsys:
> +	max77693_haptic_configure(haptic, 1);
> +}
> +
> +static void max77693_haptic_play_work(struct work_struct *work)
> +{
> +	struct max77693_haptic *haptic =
> +			container_of(work, struct max77693_haptic, work);
> +	int ret;
> +
> +	ret = max77693_haptic_set_duty_cycle(haptic);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot set duty cycle\n");
> +		return;
> +	}
> +
> +	if (haptic->magnitude)
> +		max77693_haptic_enable(haptic);
> +	else
> +		max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
> +				struct ff_effect *effect)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +	uint64_t period_mag_multi;
> +
> +	haptic->magnitude = effect->u.rumble.strong_magnitude;
> +	if (!haptic->magnitude)
> +		haptic->magnitude = effect->u.rumble.weak_magnitude;
> +
> +	/*
> +	 * The magnitude comes from force-feedback interface.
> +	 * The formula convert magnitude to pwm_duty as following:
> +	 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
> +	 */
> +	period_mag_multi = (int64_t)(haptic->pwm_dev->period *
> +						haptic->magnitude);
> +	haptic->pwm_duty = (unsigned int)(period_mag_multi >>
> +						MAX_MAGNITUDE_SHIFT);
> +
> +	schedule_work(&haptic->work);
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_close(struct input_dev *dev)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +
> +	cancel_work_sync(&haptic->work);
> +	max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_probe(struct platform_device *pdev)
> +{
> +	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77693_haptic *haptic;
> +	int ret = 0;
> +
> +	haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
> +	if (!haptic)
> +		return -ENOMEM;
> +
> +	haptic->regmap_pmic = max77693->regmap;
> +	haptic->regmap_haptic = max77693->regmap_haptic;
> +	haptic->dev = &pdev->dev;
> +	haptic->type = MAX77693_HAPTIC_LRA;
> +	haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
> +	haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
> +
> +	/* Get pwm and regulatot for haptic device */
> +	haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
> +	if (IS_ERR(haptic->pwm_dev)) {
> +		dev_err(&pdev->dev, "failed to get pwm device\n");
> +		return PTR_ERR(haptic->pwm_dev);
> +	}
> +
> +	haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
> +	if (IS_ERR(haptic->motor_reg)) {
> +		dev_err(&pdev->dev, "failed to get regulator\n");
> +		return PTR_ERR(haptic->motor_reg);
> +	}
> +
> +	ret = regulator_enable(haptic->motor_reg);
> +	if (ret) {
> +		dev_err(haptic->dev, "failed to enable regulator\n");
> +		return ret;
> +	}
> +
> +	/* Initialize input device for haptic device */
> +	haptic->input_dev = devm_input_allocate_device(&pdev->dev);
> +	if (!haptic->input_dev) {
> +		dev_err(&pdev->dev, "failed to allocate input device\n");

Hmm.. is it OK for the regulator to stay enabled? Actually, why don't
you put regulator enable/disable in open/close?

> +		return -ENOMEM;
> +	}
> +
> +	haptic->input_dev->name = "max77693-haptic";
> +	haptic->input_dev->id.version = 1;
> +	haptic->input_dev->dev.parent = &pdev->dev;
> +	haptic->input_dev->close = max77693_haptic_close;
> +	input_set_drvdata(haptic->input_dev, haptic);
> +	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
> +
> +	ret = input_ff_create_memless(haptic->input_dev, NULL,
> +				max77693_haptic_play_effect);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to create force-feedback\n");
> +		return ret;
> +	}
> +
> +	ret = input_register_device(haptic->input_dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to register input device\n");
> +		return ret;
> +	}
> +
> +	INIT_WORK(&haptic->work, max77693_haptic_play_work);

You need to initialize work before creating input device, otherwise
there is a chance play request would come before work is initialized.

> +
> +	platform_set_drvdata(pdev, haptic);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int max77693_haptic_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct max77693_haptic *haptic = platform_get_drvdata(pdev);
> +
> +	max77693_haptic_disable(haptic);
> +
> +	return 0;
> +}

I still think you need resume as well. If for some reason you suspended
vibrating you need to resume and continue vibrating. Sleep should be
transparent to users.

> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, NULL);
> +
> +static struct platform_driver max77693_haptic_driver = {
> +	.driver		= {
> +		.name	= "max77693-haptic",
> +		.owner	= THIS_MODULE,
> +		.pm	= &max77693_haptic_pm_ops,
> +	},
> +	.probe		= max77693_haptic_probe,
> +};
> +module_platform_driver(max77693_haptic_driver);
> +
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
> +MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
> +MODULE_ALIAS("platform:max77693-haptic");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
> index c466ff3..d0e578f 100644
> --- a/include/linux/mfd/max77693-private.h
> +++ b/include/linux/mfd/max77693-private.h
> @@ -251,6 +251,15 @@ enum max77693_haptic_reg {
>  	MAX77693_HAPTIC_REG_END,
>  };
>  
> +/* max77693-pmic LSCNFG configuraton register */
> +#define MAX77693_PMIC_LOW_SYS_MASK      0x80
> +#define MAX77693_PMIC_LOW_SYS_SHIFT     7
> +
> +/* max77693-haptic configuration register */
> +#define MAX77693_CONFIG2_MODE           7
> +#define MAX77693_CONFIG2_MEN            6
> +#define MAX77693_CONFIG2_HTYP           5
> +
>  enum max77693_irq_source {
>  	LED_INT = 0,
>  	TOPSYS_INT,
> -- 
> 1.7.9.5
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell
  2014-09-05 11:48 ` [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell Jaewon Kim
@ 2014-09-09  8:15   ` Lee Jones
  0 siblings, 0 replies; 9+ messages in thread
From: Lee Jones @ 2014-09-09  8:15 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: Dmitry Torokhov, Samuel Ortiz, linux-kernel, linux-input, Chanwoo Choi

On Fri, 05 Sep 2014, Jaewon Kim wrote:

> This patch add haptic of_compatible in order to use the haptic
> device driver using Devicetree.
> 
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/mfd/max77693.c |    5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
> index fbfed56..03fd431 100644
> --- a/drivers/mfd/max77693.c
> +++ b/drivers/mfd/max77693.c
> @@ -46,7 +46,10 @@ static const struct mfd_cell max77693_devs[] = {
>  	{ .name = "max77693-charger", },
>  	{ .name = "max77693-flash", },
>  	{ .name = "max77693-muic", },
> -	{ .name = "max77693-haptic", },
> +	{
> +	  .name = "max77693-haptic",
> +	  .of_compatible = "maxim,max77693-haptic",
> +	},

Proper tabbing please.

>  };
>  
>  static const struct regmap_config max77693_regmap_config = {

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/4] Input: misc: Add haptic driver on max77693
  2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
  2014-09-08 13:05   ` Lee Jones
  2014-09-08 21:37   ` Dmitry Torokhov
@ 2014-09-15 23:29   ` Lee Jones
  2 siblings, 0 replies; 9+ messages in thread
From: Lee Jones @ 2014-09-15 23:29 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: Dmitry Torokhov, Samuel Ortiz, linux-kernel, linux-input, Chanwoo Choi

On Fri, 05 Sep 2014, Jaewon Kim wrote:

> This patch add max77693-haptic device driver to support the haptic controller
> on MAX77693. The MAX77693 is a Multifunction device with PMIC, CHARGER, LED,
> MUIC, HAPTIC and the patch is haptic device driver in the MAX77693. This driver
> support external pwm and LRA(Linear Resonant Actuator) motor. User can control
> the haptic driver by using force feedback framework.
> 
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/input/misc/Kconfig           |   12 ++
>  drivers/input/misc/Makefile          |    1 +
>  drivers/input/misc/max77693-haptic.c |  321 ++++++++++++++++++++++++++++++++++
>  include/linux/mfd/max77693-private.h |    9 +

For the MFD stuff:
  Acked-by: Lee Jones <lee.jones@linaro.org>

>  4 files changed, 343 insertions(+)
>  create mode 100644 drivers/input/misc/max77693-haptic.c
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index 2ff4425..c597c52 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -144,6 +144,18 @@ config INPUT_M68K_BEEP
>  	tristate "M68k Beeper support"
>  	depends on M68K
>  
> +config INPUT_MAX77693_HAPTIC
> +	tristate "MAXIM MAX77693 haptic controller support"
> +	depends on MFD_MAX77693 && PWM
> +	select INPUT_FF_MEMLESS
> +	help
> +	  This option enables device driver support for the haptic controller
> +	  on MAXIM MAX77693 chip. This driver supports ff-memless interface
> +	  from input framework.
> +
> +	  To compile this driver as module, choose M here: the
> +	  module will be called max77693-haptic.
> +
>  config INPUT_MAX8925_ONKEY
>  	tristate "MAX8925 ONKEY support"
>  	depends on MFD_MAX8925
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 4955ad3..b28570c 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
>  obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
>  obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
>  obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
> +obj-$(CONFIG_INPUT_MAX77693_HAPTIC)	+= max77693-haptic.o
>  obj-$(CONFIG_INPUT_MAX8925_ONKEY)	+= max8925_onkey.o
>  obj-$(CONFIG_INPUT_MAX8997_HAPTIC)	+= max8997_haptic.o
>  obj-$(CONFIG_INPUT_MC13783_PWRBUTTON)	+= mc13783-pwrbutton.o
> diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
> new file mode 100644
> index 0000000..d06026b
> --- /dev/null
> +++ b/drivers/input/misc/max77693-haptic.c
> @@ -0,0 +1,321 @@
> +/*
> + * max77693-haptic.c - MAXIM MAX77693 Haptic device driver
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is not provided / owned by Maxim Integrated Products.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/input.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +
> +#define MAX_MAGNITUDE_SHIFT	16
> +
> +enum max77693_haptic_motor_type {
> +	MAX77693_HAPTIC_ERM = 0,
> +	MAX77693_HAPTIC_LRA,
> +};
> +
> +enum max77693_haptic_pulse_mode {
> +	MAX77693_HAPTIC_EXTERNAL_MODE = 0,
> +	MAX77693_HAPTIC_INTERNAL_MODE,
> +};
> +
> +enum max77693_haptic_pwm_divisor {
> +	MAX77693_HAPTIC_PWM_DIVISOR_32 = 0,
> +	MAX77693_HAPTIC_PWM_DIVISOR_64,
> +	MAX77693_HAPTIC_PWM_DIVISOR_128,
> +	MAX77693_HAPTIC_PWM_DIVISOR_256,
> +};
> +
> +struct max77693_haptic {
> +	struct regmap *regmap_pmic;
> +	struct regmap *regmap_haptic;
> +	struct device *dev;
> +	struct input_dev *input_dev;
> +	struct pwm_device *pwm_dev;
> +	struct regulator *motor_reg;
> +
> +	bool enabled;
> +	unsigned int magnitude;
> +	unsigned int pwm_duty;
> +	enum max77693_haptic_motor_type type;
> +	enum max77693_haptic_pulse_mode mode;
> +	enum max77693_haptic_pwm_divisor pwm_divisor;
> +
> +	struct work_struct work;
> +};
> +
> +static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +	int delta = (haptic->pwm_dev->period + haptic->pwm_duty)/2;
> +
> +	ret = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot configuration pwm\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_configure(struct max77693_haptic *haptic,
> +						unsigned int enable)
> +{
> +	int ret;
> +	unsigned int value = 0;
> +
> +	value = ((haptic->type << MAX77693_CONFIG2_MODE) |
> +		(enable << MAX77693_CONFIG2_MEN) |
> +		(haptic->mode << MAX77693_CONFIG2_HTYP) |
> +		(haptic->pwm_divisor));
> +
> +	ret = regmap_write(haptic->regmap_haptic,
> +				MAX77693_HAPTIC_REG_CONFIG2, value);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot write haptic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77693_haptic_lowsys(struct max77693_haptic *haptic,
> +						unsigned int enable)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(haptic->regmap_pmic,
> +			MAX77693_PMIC_REG_LSCNFG,
> +			MAX77693_PMIC_LOW_SYS_MASK,
> +			enable << MAX77693_PMIC_LOW_SYS_SHIFT);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot update pmic regmap\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_enable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (haptic->enabled)
> +		return;
> +
> +	ret = pwm_enable(haptic->pwm_dev);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot enable haptic pwm device");
> +		return;
> +	}
> +
> +	ret = max77693_haptic_lowsys(haptic, 1);
> +	if (ret)
> +		goto err_enable_lowsys;
> +
> +	ret = max77693_haptic_configure(haptic, 1);
> +	if (ret)
> +		goto err_enable_config;
> +
> +	haptic->enabled = true;
> +
> +	return;
> +
> +err_enable_config:
> +	max77693_haptic_lowsys(haptic, 0);
> +err_enable_lowsys:
> +	pwm_disable(haptic->pwm_dev);
> +}
> +
> +static void max77693_haptic_disable(struct max77693_haptic *haptic)
> +{
> +	int ret;
> +
> +	if (!haptic->enabled)
> +		return;
> +
> +	ret = max77693_haptic_configure(haptic, 0);
> +	if (ret)
> +		return;
> +
> +	ret = max77693_haptic_lowsys(haptic, 0);
> +	if (ret)
> +		goto err_disable_lowsys;
> +
> +	pwm_disable(haptic->pwm_dev);
> +	haptic->enabled = false;
> +
> +	return;
> +
> +err_disable_lowsys:
> +	max77693_haptic_configure(haptic, 1);
> +}
> +
> +static void max77693_haptic_play_work(struct work_struct *work)
> +{
> +	struct max77693_haptic *haptic =
> +			container_of(work, struct max77693_haptic, work);
> +	int ret;
> +
> +	ret = max77693_haptic_set_duty_cycle(haptic);
> +	if (ret) {
> +		dev_err(haptic->dev, "cannot set duty cycle\n");
> +		return;
> +	}
> +
> +	if (haptic->magnitude)
> +		max77693_haptic_enable(haptic);
> +	else
> +		max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
> +				struct ff_effect *effect)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +	uint64_t period_mag_multi;
> +
> +	haptic->magnitude = effect->u.rumble.strong_magnitude;
> +	if (!haptic->magnitude)
> +		haptic->magnitude = effect->u.rumble.weak_magnitude;
> +
> +	/*
> +	 * The magnitude comes from force-feedback interface.
> +	 * The formula convert magnitude to pwm_duty as following:
> +	 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
> +	 */
> +	period_mag_multi = (int64_t)(haptic->pwm_dev->period *
> +						haptic->magnitude);
> +	haptic->pwm_duty = (unsigned int)(period_mag_multi >>
> +						MAX_MAGNITUDE_SHIFT);
> +
> +	schedule_work(&haptic->work);
> +
> +	return 0;
> +}
> +
> +static void max77693_haptic_close(struct input_dev *dev)
> +{
> +	struct max77693_haptic *haptic = input_get_drvdata(dev);
> +
> +	cancel_work_sync(&haptic->work);
> +	max77693_haptic_disable(haptic);
> +}
> +
> +static int max77693_haptic_probe(struct platform_device *pdev)
> +{
> +	struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77693_haptic *haptic;
> +	int ret = 0;
> +
> +	haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
> +	if (!haptic)
> +		return -ENOMEM;
> +
> +	haptic->regmap_pmic = max77693->regmap;
> +	haptic->regmap_haptic = max77693->regmap_haptic;
> +	haptic->dev = &pdev->dev;
> +	haptic->type = MAX77693_HAPTIC_LRA;
> +	haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
> +	haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
> +
> +	/* Get pwm and regulatot for haptic device */
> +	haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
> +	if (IS_ERR(haptic->pwm_dev)) {
> +		dev_err(&pdev->dev, "failed to get pwm device\n");
> +		return PTR_ERR(haptic->pwm_dev);
> +	}
> +
> +	haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
> +	if (IS_ERR(haptic->motor_reg)) {
> +		dev_err(&pdev->dev, "failed to get regulator\n");
> +		return PTR_ERR(haptic->motor_reg);
> +	}
> +
> +	ret = regulator_enable(haptic->motor_reg);
> +	if (ret) {
> +		dev_err(haptic->dev, "failed to enable regulator\n");
> +		return ret;
> +	}
> +
> +	/* Initialize input device for haptic device */
> +	haptic->input_dev = devm_input_allocate_device(&pdev->dev);
> +	if (!haptic->input_dev) {
> +		dev_err(&pdev->dev, "failed to allocate input device\n");
> +		return -ENOMEM;
> +	}
> +
> +	haptic->input_dev->name = "max77693-haptic";
> +	haptic->input_dev->id.version = 1;
> +	haptic->input_dev->dev.parent = &pdev->dev;
> +	haptic->input_dev->close = max77693_haptic_close;
> +	input_set_drvdata(haptic->input_dev, haptic);
> +	input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
> +
> +	ret = input_ff_create_memless(haptic->input_dev, NULL,
> +				max77693_haptic_play_effect);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to create force-feedback\n");
> +		return ret;
> +	}
> +
> +	ret = input_register_device(haptic->input_dev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to register input device\n");
> +		return ret;
> +	}
> +
> +	INIT_WORK(&haptic->work, max77693_haptic_play_work);
> +
> +	platform_set_drvdata(pdev, haptic);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int max77693_haptic_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct max77693_haptic *haptic = platform_get_drvdata(pdev);
> +
> +	max77693_haptic_disable(haptic);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, NULL);
> +
> +static struct platform_driver max77693_haptic_driver = {
> +	.driver		= {
> +		.name	= "max77693-haptic",
> +		.owner	= THIS_MODULE,
> +		.pm	= &max77693_haptic_pm_ops,
> +	},
> +	.probe		= max77693_haptic_probe,
> +};
> +module_platform_driver(max77693_haptic_driver);
> +
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
> +MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
> +MODULE_ALIAS("platform:max77693-haptic");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
> index c466ff3..d0e578f 100644
> --- a/include/linux/mfd/max77693-private.h
> +++ b/include/linux/mfd/max77693-private.h
> @@ -251,6 +251,15 @@ enum max77693_haptic_reg {
>  	MAX77693_HAPTIC_REG_END,
>  };
>  
> +/* max77693-pmic LSCNFG configuraton register */
> +#define MAX77693_PMIC_LOW_SYS_MASK      0x80
> +#define MAX77693_PMIC_LOW_SYS_SHIFT     7
> +
> +/* max77693-haptic configuration register */
> +#define MAX77693_CONFIG2_MODE           7
> +#define MAX77693_CONFIG2_MEN            6
> +#define MAX77693_CONFIG2_HTYP           5
> +
>  enum max77693_irq_source {
>  	LED_INT = 0,
>  	TOPSYS_INT,

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-09-15 23:30 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-05 11:48 [PATCH v3 0/4] Add max77693 haptic driver Jaewon Kim
2014-09-05 11:48 ` [PATCH v3 1/4] mfd: max77693: Initialize haptic register map Jaewon Kim
2014-09-05 11:48 ` [PATCH v3 2/4] Input: misc: Add haptic driver on max77693 Jaewon Kim
2014-09-08 13:05   ` Lee Jones
2014-09-08 21:37   ` Dmitry Torokhov
2014-09-15 23:29   ` Lee Jones
2014-09-05 11:48 ` [PATCH v3 3/4] mfd: max77693: add haptic of_compatible in mfd_cell Jaewon Kim
2014-09-09  8:15   ` Lee Jones
2014-09-05 11:48 ` [PATCH v3 4/4] mfd: max77693: Update DT binding to support haptic Jaewon Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).