@@ -73,6 +73,16 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_DA9058_ONKEY
+ tristate "DA9058 ONKEY support"
+ depends on MFD_DA9058
+ help
+ Support the ONKEY of DA9058 PMICs as an input device
+ reporting power button status.
+
+ To compile this driver as a module, choose M here: the module
+ will be called da9058_onkey.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -41,6 +41,7 @@ obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
+obj-$(CONFIG_INPUT_DA9058_ONKEY) += da9058_onkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
new file mode 100644
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 Dialog Semiconductor Ltd.
+ *
+ * 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/module.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/da9058/version.h>
+#include <linux/mfd/da9058/registers.h>
+#include <linux/mfd/da9058/core.h>
+#include <linux/mfd/da9058/irq.h>
+#include <linux/mfd/da9058/onkey.h>
+
+struct da9058_onkey {
+ struct da9058 *da9058;
+ struct platform_device *pdev;
+ struct input_dev *input;
+ struct delayed_work work;
+ int irq;
+};
+
+static void da9058_onkey_poll(struct work_struct *work)
+{
+ struct da9058_onkey *onkey = container_of(work, struct da9058_onkey,
+ work.work);
+ struct da9058 *da9058 = onkey->da9058;
+ int poll, ret;
+ unsigned int sa;
+
+ ret = da9058_reg_read(da9058, DA9058_STATUSA_REG, &sa);
+ if (ret) {
+ dev_dbg(&onkey->pdev->dev, "Failed to read ONKEY: %d\n", ret);
+ poll = 1;
+ } else if (sa & DA9058_STATUSA_NONKEY) {
+ poll = 0;
+ } else {
+ poll = 1;
+ }
+
+ input_report_key(onkey->input, KEY_POWER, poll);
+ input_sync(onkey->input);
+
+ if (poll)
+ schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static irqreturn_t da9058_onkey_event_handler(int irq, void *data)
+{
+ struct da9058_onkey *onkey = data;
+
+ schedule_delayed_work(&onkey->work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit da9058_onkey_probe(struct platform_device *pdev)
+{
+ struct da9058 *da9058 = dev_get_drvdata(pdev->dev.parent);
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct da9058_onkey_pdata *onkey_pdata;
+ struct da9058_onkey *onkey;
+ int ret;
+
+ if (cell == NULL) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ onkey_pdata = cell->platform_data;
+
+ if (onkey_pdata == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ dev_info(&pdev->dev, "Starting ONKEY\n");
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9058_onkey),
+ GFP_KERNEL);
+ if (!onkey) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ platform_set_drvdata(pdev, onkey);
+
+ onkey->da9058 = da9058;
+ onkey->pdev = pdev;
+
+ INIT_DELAYED_WORK(&onkey->work, da9058_onkey_poll);
+
+ onkey->input = input_allocate_device();
+ if (!onkey->input) {
+ dev_err(&pdev->dev, "failed to allocate data device\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ onkey->input->evbit[0] = BIT_MASK(EV_KEY);
+ onkey->input->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+ onkey->input->name = "da9058-onkey";
+ onkey->input->phys = "da9058-onkey/input0";
+ onkey->input->dev.parent = &pdev->dev;
+
+ ret = input_register_device(onkey->input);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Unable to register input ONKEY device: %d\n", ret);
+ goto err2;
+ }
+ onkey->irq = DA9058_IRQ_ENONKEY;
+
+ ret = request_threaded_irq(da9058_to_virt_irq_num(da9058, onkey->irq),
+ NULL, da9058_onkey_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "DA9058 keydown", onkey);
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get ONKEY keydown IRQ %d: %d\n",
+ onkey->irq, ret);
+ goto err3;
+ }
+ goto exit;
+
+err3:
+err2:
+ input_free_device(onkey->input);
+err1:
+ platform_set_drvdata(pdev, NULL);
+exit:
+ return ret;
+}
+
+static int __devexit da9058_onkey_remove(struct platform_device *pdev)
+{
+ struct da9058_onkey *onkey = platform_get_drvdata(pdev);
+ struct da9058 *da9058 = onkey->da9058;
+
+ free_irq(da9058_to_virt_irq_num(da9058, onkey->irq), onkey);
+ cancel_delayed_work_sync(&onkey->work);
+ input_unregister_device(onkey->input);
+
+ return 0;
+}
+
+static struct platform_driver da9058_onkey_driver = {
+ .probe = da9058_onkey_probe,
+ .remove = __devexit_p(da9058_onkey_remove),
+ .driver = {
+ .name = "da9058-onkey",
+ .owner = THIS_MODULE,
+ }
+};
+
+module_platform_driver(da9058_onkey_driver);
+
+MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
+MODULE_DESCRIPTION("Dialog DA9058 PMIC Onkey Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:da9058-onkey");