Commit 8eec8a1167b5912c19fec2cdad5b968dd0f8690d

Authored by Hong Liu
Committed by Matthew Garrett
1 parent e2d3d44b9a

intel_mid_powerbtn: add power button driver for Medfield platform (#3)

The power button is connected to MSIC on Medfield, we will get two
interrupts from IOAPIC when pressing or releasing the power button.

Signed-off-by: Hong Liu <hong.liu@intel.com>
[Minor fixes as noted by Dmitry]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Matthew Garrett <mjg@redhat.com>

Showing 3 changed files with 157 additions and 0 deletions Side-by-side Diff

drivers/platform/x86/Kconfig
... ... @@ -616,6 +616,14 @@
616 616 Say Y here to support GPIO via the SCU IPC interface
617 617 on Intel MID platforms.
618 618  
  619 +config INTEL_MID_POWER_BUTTON
  620 + tristate "power button driver for Intel MID platforms"
  621 + depends on INTEL_SCU_IPC
  622 + help
  623 + This driver handles the power button on the Intel MID platforms.
  624 +
  625 + If unsure, say N.
  626 +
619 627 config RAR_REGISTER
620 628 bool "Restricted Access Region Register Driver"
621 629 depends on PCI && X86_MRST
drivers/platform/x86/Makefile
... ... @@ -36,4 +36,5 @@
36 36 obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
37 37 obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
38 38 obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
  39 +obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
drivers/platform/x86/intel_mid_powerbtn.c
  1 +/*
  2 + * Power button driver for Medfield.
  3 + *
  4 + * Copyright (C) 2010 Intel Corp
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; version 2 of the License.
  9 + *
  10 + * This program is distributed in the hope that it will be useful, but
  11 + * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 + * General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License along
  16 + * with this program; if not, write to the Free Software Foundation, Inc.,
  17 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  18 + */
  19 +
  20 +#include <linux/module.h>
  21 +#include <linux/init.h>
  22 +#include <linux/interrupt.h>
  23 +#include <linux/slab.h>
  24 +#include <linux/platform_device.h>
  25 +#include <linux/input.h>
  26 +#include <asm/intel_scu_ipc.h>
  27 +
  28 +#define DRIVER_NAME "msic_power_btn"
  29 +
  30 +#define MSIC_IRQ_STAT 0x02
  31 + #define MSIC_IRQ_PB (1 << 0)
  32 +#define MSIC_PB_CONFIG 0x3e
  33 +#define MSIC_PB_STATUS 0x3f
  34 + #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
  35 +
  36 +struct mfld_pb_priv {
  37 + struct input_dev *input;
  38 + unsigned int irq;
  39 +};
  40 +
  41 +static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
  42 +{
  43 + struct mfld_pb_priv *priv = dev_id;
  44 + int ret;
  45 + u8 pbstat;
  46 +
  47 + ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
  48 + if (ret < 0)
  49 + return IRQ_HANDLED;
  50 +
  51 + input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL));
  52 + input_sync(priv->input);
  53 +
  54 + return IRQ_HANDLED;
  55 +}
  56 +
  57 +static int __devinit mfld_pb_probe(struct platform_device *pdev)
  58 +{
  59 + struct mfld_pb_priv *priv;
  60 + struct input_dev *input;
  61 + int irq;
  62 + int error;
  63 +
  64 + irq = platform_get_irq(pdev, 0);
  65 + if (irq < 0)
  66 + return -EINVAL;
  67 +
  68 + priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL);
  69 + input = input_allocate_device();
  70 + if (!priv || !input) {
  71 + error = -ENOMEM;
  72 + goto err_free_mem;
  73 + }
  74 +
  75 + priv->input = input;
  76 + priv->irq = irq;
  77 +
  78 + input->name = pdev->name;
  79 + input->phys = "power-button/input0";
  80 + input->id.bustype = BUS_HOST;
  81 + input->dev.parent = &pdev->dev;
  82 +
  83 + input_set_capability(input, EV_KEY, KEY_POWER);
  84 +
  85 + error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr,
  86 + 0, DRIVER_NAME, priv);
  87 + if (error) {
  88 + dev_err(&pdev->dev,
  89 + "unable to request irq %d for mfld power button\n",
  90 + irq);
  91 + goto err_free_mem;
  92 + }
  93 +
  94 + error = input_register_device(input);
  95 + if (error) {
  96 + dev_err(&pdev->dev,
  97 + "unable to register input dev, error %d\n", error);
  98 + goto err_free_irq;
  99 + }
  100 +
  101 + platform_set_drvdata(pdev, priv);
  102 + return 0;
  103 +
  104 +err_free_irq:
  105 + free_irq(priv->irq, priv);
  106 +err_free_mem:
  107 + input_free_device(input);
  108 + kfree(priv);
  109 + return error;
  110 +}
  111 +
  112 +static int __devexit mfld_pb_remove(struct platform_device *pdev)
  113 +{
  114 + struct mfld_pb_priv *priv = platform_get_drvdata(pdev);
  115 +
  116 + free_irq(priv->irq, priv);
  117 + input_unregister_device(priv->input);
  118 + kfree(priv);
  119 +
  120 + platform_set_drvdata(pdev, NULL);
  121 + return 0;
  122 +}
  123 +
  124 +static struct platform_driver mfld_pb_driver = {
  125 + .driver = {
  126 + .name = DRIVER_NAME,
  127 + .owner = THIS_MODULE,
  128 + },
  129 + .probe = mfld_pb_probe,
  130 + .remove = __devexit_p(mfld_pb_remove),
  131 +};
  132 +
  133 +static int __init mfld_pb_init(void)
  134 +{
  135 + return platform_driver_register(&mfld_pb_driver);
  136 +}
  137 +module_init(mfld_pb_init);
  138 +
  139 +static void __exit mfld_pb_exit(void)
  140 +{
  141 + platform_driver_unregister(&mfld_pb_driver);
  142 +}
  143 +module_exit(mfld_pb_exit);
  144 +
  145 +MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
  146 +MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
  147 +MODULE_LICENSE("GPL v2");
  148 +MODULE_ALIAS("platform:" DRIVER_NAME);