Input: sirfsoc_pwrc - add onkey input driver for CSR SiRFprimaII PWRC
There is an embedded PWRC(power controller) in SiRFprimaII and SiRFatlasVI, we have an ONKEY button which can generate interrupt to IRQ controller. In a typical user scenarios, at the runtime, if users touch the key, we put system to s2ram status. Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> Signed-off-by: Xianglong Du <Xianglong.Du@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
f6e63f8032
commit
9b5f953ddc
@ -637,4 +637,14 @@ config INPUT_XEN_KBDDEV_FRONTEND
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called xen-kbdfront.
|
||||
|
||||
config INPUT_SIRFSOC_ONKEY
|
||||
bool "CSR SiRFSoC power on/off/suspend key support"
|
||||
depends on ARCH_SIRF && OF
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to support for the SiRFSoC power on/off/suspend key
|
||||
in Linux, after you press the onkey, system will suspend.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif
|
||||
|
@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
|
||||
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
|
||||
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
|
||||
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
||||
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
|
||||
|
165
drivers/input/misc/sirfsoc-onkey.c
Normal file
165
drivers/input/misc/sirfsoc-onkey.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Power key driver for SiRF PrimaII
|
||||
*
|
||||
* Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
|
||||
*
|
||||
* Licensed under GPLv2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/rtc/sirfsoc_rtciobrg.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct sirfsoc_pwrc_drvdata {
|
||||
u32 pwrc_base;
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
#define PWRC_ON_KEY_BIT (1 << 0)
|
||||
|
||||
#define PWRC_INT_STATUS 0xc
|
||||
#define PWRC_INT_MASK 0x10
|
||||
|
||||
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
|
||||
u32 int_status;
|
||||
|
||||
int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
|
||||
PWRC_INT_STATUS);
|
||||
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
|
||||
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
|
||||
|
||||
/*
|
||||
* For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
|
||||
* to queue a SUSPEND APM event
|
||||
*/
|
||||
input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
|
||||
input_sync(pwrcdrv->input);
|
||||
|
||||
/*
|
||||
* Todo: report KEY_POWER event for Android platforms, Android PowerManager
|
||||
* will handle the suspend and powerdown/hibernation
|
||||
*/
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
|
||||
{ .compatible = "sirf,prima2-pwrc" },
|
||||
{},
|
||||
}
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
|
||||
|
||||
static int sirfsoc_pwrc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sirfsoc_pwrc_drvdata *pwrcdrv;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
|
||||
GFP_KERNEL);
|
||||
if (!pwrcdrv) {
|
||||
dev_info(&pdev->dev, "Not enough memory for the device data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* we can't use of_iomap because pwrc is not mapped in memory,
|
||||
* the so-called base address is only offset in rtciobrg
|
||||
*/
|
||||
error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to find base address of pwrc node in dtb\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!pwrcdrv->input)
|
||||
return -ENOMEM;
|
||||
|
||||
pwrcdrv->input->name = "sirfsoc pwrckey";
|
||||
pwrcdrv->input->phys = "pwrc/input0";
|
||||
pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
error = devm_request_irq(&pdev->dev, irq,
|
||||
sirfsoc_pwrc_isr, IRQF_SHARED,
|
||||
"sirfsoc_pwrc_int", pwrcdrv);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
|
||||
irq, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(
|
||||
sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
|
||||
PWRC_ON_KEY_BIT,
|
||||
pwrcdrv->pwrc_base + PWRC_INT_MASK);
|
||||
|
||||
error = input_register_device(pwrcdrv->input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to register input device, error: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pwrcdrv);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_pwrc_remove(struct platform_device *pdev)
|
||||
{
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pwrc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Do not mask pwrc interrupt as we want pwrc work as a wakeup source
|
||||
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
|
||||
*/
|
||||
sirfsoc_rtc_iobrg_writel(
|
||||
sirfsoc_rtc_iobrg_readl(
|
||||
pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
|
||||
pwrcdrv->pwrc_base + PWRC_INT_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
|
||||
|
||||
static struct platform_driver sirfsoc_pwrc_driver = {
|
||||
.probe = sirfsoc_pwrc_probe,
|
||||
.remove = sirfsoc_pwrc_remove,
|
||||
.driver = {
|
||||
.name = "sirfsoc-pwrc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &sirfsoc_pwrc_pm_ops,
|
||||
.of_match_table = of_match_ptr(sirfsoc_pwrc_of_match),
|
||||
}
|
||||
};
|
||||
|
||||
module_platform_driver(sirfsoc_pwrc_driver);
|
||||
|
||||
MODULE_LICENSE("GPLv2");
|
||||
MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
|
||||
MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
|
||||
MODULE_ALIAS("platform:sirfsoc-pwrc");
|
Loading…
Reference in New Issue
Block a user