Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Binghua Duan and committed by
Dmitry Torokhov
9b5f953d f6e63f80

+176
+10
drivers/input/misc/Kconfig
··· 637 637 To compile this driver as a module, choose M here: the 638 638 module will be called xen-kbdfront. 639 639 640 + config INPUT_SIRFSOC_ONKEY 641 + bool "CSR SiRFSoC power on/off/suspend key support" 642 + depends on ARCH_SIRF && OF 643 + default y 644 + help 645 + Say Y here if you want to support for the SiRFSoC power on/off/suspend key 646 + in Linux, after you press the onkey, system will suspend. 647 + 648 + If unsure, say N. 649 + 640 650 endif
+1
drivers/input/misc/Makefile
··· 51 51 obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o 52 52 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o 53 53 obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o 54 + obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o 54 55 obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o 55 56 obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o 56 57 obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
+165
drivers/input/misc/sirfsoc-onkey.c
··· 1 + /* 2 + * Power key driver for SiRF PrimaII 3 + * 4 + * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. 5 + * 6 + * Licensed under GPLv2 or later. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/init.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/delay.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/input.h> 15 + #include <linux/rtc/sirfsoc_rtciobrg.h> 16 + #include <linux/of.h> 17 + 18 + struct sirfsoc_pwrc_drvdata { 19 + u32 pwrc_base; 20 + struct input_dev *input; 21 + }; 22 + 23 + #define PWRC_ON_KEY_BIT (1 << 0) 24 + 25 + #define PWRC_INT_STATUS 0xc 26 + #define PWRC_INT_MASK 0x10 27 + 28 + static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id) 29 + { 30 + struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id; 31 + u32 int_status; 32 + 33 + int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + 34 + PWRC_INT_STATUS); 35 + sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT, 36 + pwrcdrv->pwrc_base + PWRC_INT_STATUS); 37 + 38 + /* 39 + * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c 40 + * to queue a SUSPEND APM event 41 + */ 42 + input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1); 43 + input_sync(pwrcdrv->input); 44 + 45 + /* 46 + * Todo: report KEY_POWER event for Android platforms, Android PowerManager 47 + * will handle the suspend and powerdown/hibernation 48 + */ 49 + 50 + return IRQ_HANDLED; 51 + } 52 + 53 + static const struct of_device_id sirfsoc_pwrc_of_match[] = { 54 + { .compatible = "sirf,prima2-pwrc" }, 55 + {}, 56 + } 57 + MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match); 58 + 59 + static int sirfsoc_pwrc_probe(struct platform_device *pdev) 60 + { 61 + struct device_node *np = pdev->dev.of_node; 62 + struct sirfsoc_pwrc_drvdata *pwrcdrv; 63 + int irq; 64 + int error; 65 + 66 + pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata), 67 + GFP_KERNEL); 68 + if (!pwrcdrv) { 69 + dev_info(&pdev->dev, "Not enough memory for the device data\n"); 70 + return -ENOMEM; 71 + } 72 + 73 + /* 74 + * we can't use of_iomap because pwrc is not mapped in memory, 75 + * the so-called base address is only offset in rtciobrg 76 + */ 77 + error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base); 78 + if (error) { 79 + dev_err(&pdev->dev, 80 + "unable to find base address of pwrc node in dtb\n"); 81 + return error; 82 + } 83 + 84 + pwrcdrv->input = devm_input_allocate_device(&pdev->dev); 85 + if (!pwrcdrv->input) 86 + return -ENOMEM; 87 + 88 + pwrcdrv->input->name = "sirfsoc pwrckey"; 89 + pwrcdrv->input->phys = "pwrc/input0"; 90 + pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR); 91 + 92 + irq = platform_get_irq(pdev, 0); 93 + error = devm_request_irq(&pdev->dev, irq, 94 + sirfsoc_pwrc_isr, IRQF_SHARED, 95 + "sirfsoc_pwrc_int", pwrcdrv); 96 + if (error) { 97 + dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n", 98 + irq, error); 99 + return error; 100 + } 101 + 102 + sirfsoc_rtc_iobrg_writel( 103 + sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) | 104 + PWRC_ON_KEY_BIT, 105 + pwrcdrv->pwrc_base + PWRC_INT_MASK); 106 + 107 + error = input_register_device(pwrcdrv->input); 108 + if (error) { 109 + dev_err(&pdev->dev, 110 + "unable to register input device, error: %d\n", 111 + error); 112 + return error; 113 + } 114 + 115 + platform_set_drvdata(pdev, pwrcdrv); 116 + device_init_wakeup(&pdev->dev, 1); 117 + 118 + return 0; 119 + } 120 + 121 + static int sirfsoc_pwrc_remove(struct platform_device *pdev) 122 + { 123 + device_init_wakeup(&pdev->dev, 0); 124 + 125 + return 0; 126 + } 127 + 128 + #ifdef CONFIG_PM_SLEEP 129 + static int pwrc_resume(struct device *dev) 130 + { 131 + struct platform_device *pdev = to_platform_device(dev); 132 + struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev); 133 + 134 + /* 135 + * Do not mask pwrc interrupt as we want pwrc work as a wakeup source 136 + * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c 137 + */ 138 + sirfsoc_rtc_iobrg_writel( 139 + sirfsoc_rtc_iobrg_readl( 140 + pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT, 141 + pwrcdrv->pwrc_base + PWRC_INT_MASK); 142 + 143 + return 0; 144 + } 145 + #endif 146 + 147 + static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume); 148 + 149 + static struct platform_driver sirfsoc_pwrc_driver = { 150 + .probe = sirfsoc_pwrc_probe, 151 + .remove = sirfsoc_pwrc_remove, 152 + .driver = { 153 + .name = "sirfsoc-pwrc", 154 + .owner = THIS_MODULE, 155 + .pm = &sirfsoc_pwrc_pm_ops, 156 + .of_match_table = of_match_ptr(sirfsoc_pwrc_of_match), 157 + } 158 + }; 159 + 160 + module_platform_driver(sirfsoc_pwrc_driver); 161 + 162 + MODULE_LICENSE("GPLv2"); 163 + MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>"); 164 + MODULE_DESCRIPTION("CSR Prima2 PWRC Driver"); 165 + MODULE_ALIAS("platform:sirfsoc-pwrc");