linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Trilok Soni <tsoni@codeaurora.org>
Cc: linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	rtc-linux@googlegroups.com, linux-arm-msm@vger.kernel.org
Subject: Re: [RFC v1 PATCH 4/6] input: pmic8058_pwrkey: Add support for power key
Date: Wed, 10 Nov 2010 23:21:07 -0800	[thread overview]
Message-ID: <20101111072107.GA24415@core.coreip.homeip.net> (raw)
In-Reply-To: <1289393281-4459-5-git-send-email-tsoni@codeaurora.org>

Hi Trilkok,

On Wed, Nov 10, 2010 at 06:17:59PM +0530, Trilok Soni wrote:
> Add support for PMIC8058 power key driven over dedicated
> KYPD_PWR_N pin. It allows the user to specify the amount
> of time by which the power key reporting can be delayed.
> 

Why do we need to delay KEY_POWER reporting? Do we need to use high
resolution timers or regular timers would do as well? KEY_END appears to
be abused (you don't want to move your cursor to the end of line, do
you?). Also I wonder if header file should reside in linux/mfd with the
rest of pmic8058 components.

Thanks. 

> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Trilok Soni <tsoni@codeaurora.org>
> ---
>  drivers/input/misc/Kconfig            |   11 +
>  drivers/input/misc/Makefile           |    1 +
>  drivers/input/misc/pmic8058-pwrkey.c  |  322 +++++++++++++++++++++++++++++++++
>  include/linux/input/pmic8058-pwrkey.h |   37 ++++
>  4 files changed, 371 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/misc/pmic8058-pwrkey.c
>  create mode 100644 include/linux/input/pmic8058-pwrkey.h
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index b99b8cb..aeb9165 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -348,6 +348,17 @@ config INPUT_PWM_BEEPER
>  	  To compile this driver as a module, choose M here: the module will be
>  	  called pwm-beeper.
>  
> +config INPUT_PMIC8058_PWRKEY
> +	tristate "PMIC8058 power key support"
> +	depends on PMIC8058
> +	help
> +	  Say Y here if you want support for the PMIC8058 power key.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called pmic8058-pwrkey.
> +
>  config INPUT_GPIO_ROTARY_ENCODER
>  	tristate "Rotary encoders connected to GPIO pins"
>  	depends on GPIOLIB && GENERIC_GPIO
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 1fe1f6c..c4357a0 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -31,6 +31,7 @@ obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o
>  obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
>  obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
>  obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
> +obj-$(CONFIG_INPUT_PMIC8058_PWRKEY)	+= pmic8058-pwrkey.o
>  obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
>  obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
>  obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
> diff --git a/drivers/input/misc/pmic8058-pwrkey.c b/drivers/input/misc/pmic8058-pwrkey.c
> new file mode 100644
> index 0000000..3714b24
> --- /dev/null
> +++ b/drivers/input/misc/pmic8058-pwrkey.c
> @@ -0,0 +1,322 @@
> +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/mfd/pmic8058.h>
> +#include <linux/log2.h>
> +#include <linux/spinlock.h>
> +#include <linux/hrtimer.h>
> +
> +#include <linux/input/pmic8058-pwrkey.h>
> +
> +#define PON_CNTL_1	0x1C
> +#define PON_CNTL_PULL_UP BIT(7)
> +#define PON_CNTL_TRIG_DELAY_MASK (0x7)
> +
> +/**
> + * struct pmic8058_pwrkey - pmic8058 pwrkey information
> + * @key_press_irq: key press irq number
> + * @pm_chip: pmic8058 parent
> + * @timer: timer for end key simulation
> + * @key_pressed: flag to keep track for power key reporting
> + * @pdata: platform data
> + * @lock:  protect key press update and end key simulation
> + */
> +struct pmic8058_pwrkey {
> +	struct input_dev *pwr;
> +	int key_press_irq;
> +	struct pm8058_chip	*pm_chip;
> +	struct hrtimer timer;
> +	bool key_pressed;
> +	struct pmic8058_pwrkey_pdata *pdata;
> +	spinlock_t lock;
> +};
> +
> +static enum hrtimer_restart pmic8058_pwrkey_timer(struct hrtimer *timer)
> +{
> +	unsigned long flags;
> +	struct pmic8058_pwrkey *pwrkey = container_of(timer,
> +						struct pmic8058_pwrkey,	timer);
> +
> +	spin_lock_irqsave(&pwrkey->lock, flags);
> +	pwrkey->key_pressed = true;
> +
> +	input_report_key(pwrkey->pwr, KEY_POWER, 1);
> +	input_sync(pwrkey->pwr);
> +	spin_unlock_irqrestore(&pwrkey->lock, flags);
> +
> +	return HRTIMER_NORESTART;
> +}
> +
> +static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
> +{
> +	struct pmic8058_pwrkey *pwrkey = _pwrkey;
> +	struct pmic8058_pwrkey_pdata *pdata = pwrkey->pdata;
> +	unsigned long flags;
> +
> +	/* no pwrkey time duration, means no end key simulation */
> +	if (!pwrkey->pdata->pwrkey_time_ms) {
> +		input_report_key(pwrkey->pwr, KEY_POWER, 1);
> +		input_sync(pwrkey->pwr);
> +		return IRQ_HANDLED;
> +	}
> +
> +	spin_lock_irqsave(&pwrkey->lock, flags);
> +
> +	input_report_key(pwrkey->pwr, KEY_END, 1);
> +	input_sync(pwrkey->pwr);
> +
> +	hrtimer_start(&pwrkey->timer,
> +			ktime_set(pdata->pwrkey_time_ms / 1000,
> +				(pdata->pwrkey_time_ms % 1000) * 1000000),
> +			HRTIMER_MODE_REL);
> +	spin_unlock_irqrestore(&pwrkey->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
> +{
> +	struct pmic8058_pwrkey *pwrkey = _pwrkey;
> +	unsigned long flags;
> +
> +	/* no pwrkey time, means no delay in pwr key reporting */
> +	if (!pwrkey->pdata->pwrkey_time_ms) {
> +		input_report_key(pwrkey->pwr, KEY_POWER, 0);
> +		input_sync(pwrkey->pwr);
> +		return IRQ_HANDLED;
> +	}
> +
> +	spin_lock_irqsave(&pwrkey->lock, flags);
> +	hrtimer_cancel(&pwrkey->timer);
> +
> +	if (pwrkey->key_pressed) {
> +		pwrkey->key_pressed = false;
> +		input_report_key(pwrkey->pwr, KEY_POWER, 0);
> +		input_sync(pwrkey->pwr);
> +	}
> +
> +	input_report_key(pwrkey->pwr, KEY_END, 0);
> +	input_sync(pwrkey->pwr);
> +
> +	spin_unlock_irqrestore(&pwrkey->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +#ifdef CONFIG_PM
> +static int pmic8058_pwrkey_suspend(struct device *dev)
> +{
> +	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		enable_irq_wake(pwrkey->key_press_irq);
> +
> +	return 0;
> +}
> +
> +static int pmic8058_pwrkey_resume(struct device *dev)
> +{
> +	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		disable_irq_wake(pwrkey->key_press_irq);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops pm8058_pwr_key_pm_ops = {
> +	.suspend	= pmic8058_pwrkey_suspend,
> +	.resume		= pmic8058_pwrkey_resume,
> +};
> +#endif
> +
> +static int __devinit pmic8058_pwrkey_probe(struct platform_device *pdev)
> +{
> +	struct input_dev *pwr;
> +	int key_release_irq = platform_get_irq(pdev, 0);
> +	int key_press_irq = platform_get_irq(pdev, 1);
> +	int err;
> +	unsigned int delay;
> +	u8 pon_cntl;
> +	struct pmic8058_pwrkey *pwrkey;
> +	struct pmic8058_pwrkey_pdata *pdata = pdev->dev.platform_data;
> +	struct pm8058_chip	*pm_chip;
> +
> +	pm_chip = platform_get_drvdata(pdev);
> +	if (pm_chip == NULL) {
> +		dev_err(&pdev->dev, "no parent data passed in\n");
> +		return -EFAULT;
> +	}
> +
> +	if (!pdata) {
> +		dev_err(&pdev->dev, "power key platform data not supplied\n");
> +		return -EINVAL;
> +	}
> +
> +	if (pdata->kpd_trigger_delay_us > 62500) {
> +		dev_err(&pdev->dev, "invalid pwr key trigger delay\n");
> +		return -EINVAL;
> +	}
> +
> +	if (pdata->pwrkey_time_ms &&
> +	     (pdata->pwrkey_time_ms < 500 || pdata->pwrkey_time_ms > 1000)) {
> +		dev_err(&pdev->dev, "invalid pwr key time supplied\n");
> +		return -EINVAL;
> +	}
> +
> +	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
> +	if (!pwrkey)
> +		return -ENOMEM;
> +
> +	pwrkey->pm_chip = pm_chip;
> +	pwrkey->pdata   = pdata;
> +
> +	pwr = input_allocate_device();
> +	if (!pwr) {
> +		dev_dbg(&pdev->dev, "Can't allocate power button\n");
> +		err = -ENOMEM;
> +		goto free_pwrkey;
> +	}
> +
> +	input_set_capability(pwr, EV_KEY, KEY_POWER);
> +	input_set_capability(pwr, EV_KEY, KEY_END);
> +
> +	pwr->name = "pmic8058_pwrkey";
> +	pwr->phys = "pmic8058_pwrkey/input0";
> +	pwr->dev.parent = &pdev->dev;
> +
> +	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
> +	delay = 1 + ilog2(delay);
> +
> +	err = pm8058_read(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
> +	if (err < 0) {
> +		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
> +		goto free_input_dev;
> +	}
> +
> +
> +	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
> +	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
> +	pon_cntl |= (pdata->pull_up ? PON_CNTL_PULL_UP : ~PON_CNTL_PULL_UP);
> +	err = pm8058_write(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
> +	if (err < 0) {
> +		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
> +		goto free_input_dev;
> +	}
> +
> +	hrtimer_init(&pwrkey->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> +	pwrkey->timer.function = pmic8058_pwrkey_timer;
> +
> +	spin_lock_init(&pwrkey->lock);
> +
> +	err = input_register_device(pwr);
> +	if (err) {
> +		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
> +		goto free_input_dev;
> +	}
> +
> +	pwrkey->key_press_irq = key_press_irq;
> +	pwrkey->pwr = pwr;
> +
> +	platform_set_drvdata(pdev, pwrkey);
> +
> +	err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
> +			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_press", pwrkey);
> +	if (err < 0) {
> +		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
> +				 key_press_irq, err);
> +		goto unreg_input_dev;
> +	}
> +
> +	err = request_any_context_irq(key_release_irq, pwrkey_release_irq,
> +			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_release",
> +				 pwrkey);
> +	if (err < 0) {
> +		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
> +				 key_release_irq, err);
> +
> +		goto free_press_irq;
> +	}
> +
> +	device_init_wakeup(&pdev->dev, pdata->wakeup);
> +
> +	return 0;
> +
> +free_press_irq:
> +	free_irq(key_press_irq, NULL);
> +unreg_input_dev:
> +	input_unregister_device(pwr);
> +	pwr = NULL;
> +free_input_dev:
> +	input_free_device(pwr);
> +free_pwrkey:
> +	kfree(pwrkey);
> +	return err;
> +}
> +
> +static int __devexit pmic8058_pwrkey_remove(struct platform_device *pdev)
> +{
> +	struct pmic8058_pwrkey *pwrkey = platform_get_drvdata(pdev);
> +	int key_release_irq = platform_get_irq(pdev, 0);
> +	int key_press_irq = platform_get_irq(pdev, 1);
> +
> +	device_init_wakeup(&pdev->dev, 0);
> +
> +	free_irq(key_press_irq, pwrkey);
> +	free_irq(key_release_irq, pwrkey);
> +	input_unregister_device(pwrkey->pwr);
> +	kfree(pwrkey);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver pmic8058_pwrkey_driver = {
> +	.probe		= pmic8058_pwrkey_probe,
> +	.remove		= __devexit_p(pmic8058_pwrkey_remove),
> +	.driver		= {
> +		.name	= "pm8058-pwrkey",
> +		.owner	= THIS_MODULE,
> +#ifdef CONFIG_PM
> +		.pm	= &pm8058_pwr_key_pm_ops,
> +#endif
> +	},
> +};
> +
> +static int __init pmic8058_pwrkey_init(void)
> +{
> +	return platform_driver_register(&pmic8058_pwrkey_driver);
> +}
> +module_init(pmic8058_pwrkey_init);
> +
> +static void __exit pmic8058_pwrkey_exit(void)
> +{
> +	platform_driver_unregister(&pmic8058_pwrkey_driver);
> +}
> +module_exit(pmic8058_pwrkey_exit);
> +
> +MODULE_ALIAS("platform:pmic8058_pwrkey");
> +MODULE_DESCRIPTION("PMIC8058 Power Key driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
> diff --git a/include/linux/input/pmic8058-pwrkey.h b/include/linux/input/pmic8058-pwrkey.h
> new file mode 100644
> index 0000000..dd849fe
> --- /dev/null
> +++ b/include/linux/input/pmic8058-pwrkey.h
> @@ -0,0 +1,37 @@
> +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + */
> +
> +#ifndef __PMIC8058_PWRKEY_H__
> +#define __PMIC8058_PWRKEY_H__
> +/**
> + * struct pmic8058_pwrkey_pdata - platform data for pwrkey driver
> + * @pull up:  power on register control for pull up/down configuration
> + * @pwrkey_time_ms: time after which power key event should be generated, if
> + *                  key is released before then end key is reported.
> + *                  Supply zero for only power key reporting.
> + * @kpd_trigger_delay_us: time delay for power key state change interrupt
> + *                  trigger.
> + * @wakeup: configure power key as wakeup source
> + */
> +struct pmic8058_pwrkey_pdata {
> +	bool pull_up;
> +	u16  pwrkey_time_ms;
> +	u32  kpd_trigger_delay_us;
> +	u32  wakeup;
> +};
> +
> +#endif /* __PMIC8058_PWRKEY_H__ */
> -- 
> 1.7.0.2
> 

-- 
Dmitry

  reply	other threads:[~2010-11-11  7:21 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-10 12:47 [RFC v1 PATCH 0/6] Qualcomm PMIC8058 sub-device drivers Trilok Soni
2010-11-10 12:47 ` [RFC v1 PATCH 1/6] matrix_keypad: Increase the max limit of rows and columns Trilok Soni
2010-11-10 18:33   ` Eric Miao
2010-11-10 23:30     ` Dmitry Torokhov
2010-11-17 17:54       ` Dmitry Torokhov
2010-11-10 12:47 ` [RFC v1 PATCH 2/6] input: pm8058_keypad: Qualcomm PMIC8058 keypad controller driver Trilok Soni
2010-11-16  3:49   ` Trilok Soni
2010-11-17 18:02   ` Dmitry Torokhov
2010-12-06 18:14   ` Dmitry Torokhov
2010-12-07  9:22     ` Trilok Soni
2010-12-07  9:30       ` Dmitry Torokhov
2010-12-07  9:32         ` Trilok Soni
2011-01-06 11:56     ` [rtc-linux] " Anirudh Ghayal
2010-11-10 12:47 ` [RFC v1 PATCH 3/6] led: pmic8058: Add PMIC8058 leds driver Trilok Soni
2010-11-10 20:45   ` Lars-Peter Clausen
2010-11-10 23:28     ` Dmitry Torokhov
2010-11-10 23:50       ` Lars-Peter Clausen
2010-11-11 12:15     ` Trilok Soni
2010-12-06 13:44       ` Trilok Soni
2010-12-07 15:11         ` Lars-Peter Clausen
2010-12-07 15:47           ` Trilok Soni
2010-11-10 12:47 ` [RFC v1 PATCH 4/6] input: pmic8058_pwrkey: Add support for power key Trilok Soni
2010-11-11  7:21   ` Dmitry Torokhov [this message]
2010-11-11 12:00     ` Trilok Soni
2010-11-12  0:57       ` Dmitry Torokhov
2010-11-12  8:56         ` Trilok Soni
2010-11-12 19:58           ` Dmitry Torokhov
2010-11-10 12:48 ` [RFC v1 PATCH 5/6] input: pmic8058-othc: Add support for PM8058 based OTHC Trilok Soni
2010-11-16  3:08   ` Trilok Soni
2010-11-16  5:36   ` Datta, Shubhrajyoti
2010-11-16  6:36     ` Trilok Soni
2010-12-01  5:34       ` Anirudh Ghayal
2010-12-07 10:04   ` Dmitry Torokhov
2010-12-07 12:10     ` Anirudh Ghayal
2010-11-10 12:48 ` [RFC v1 PATCH 6/6] drivers: rtc: Add support for Qualcomm PMIC8058 RTC Trilok Soni
2010-11-12  8:53   ` Trilok Soni
2010-11-12 12:53   ` Lars-Peter Clausen
2010-11-12 15:17     ` [rtc-linux] " Anirudh Ghayal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101111072107.GA24415@core.coreip.homeip.net \
    --to=dmitry.torokhov@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rtc-linux@googlegroups.com \
    --cc=tsoni@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).