0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/input.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/device.h>
0012 #include <linux/mfd/intel_soc_pmic.h>
0013 #include <linux/mfd/intel_soc_pmic_mrfld.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/pm_wakeirq.h>
0017 #include <linux/slab.h>
0018
0019 #define BCOVE_PBSTATUS 0x27
0020 #define BCOVE_PBSTATUS_PBLVL BIT(4)
0021
0022 static irqreturn_t mrfld_pwrbtn_interrupt(int irq, void *dev_id)
0023 {
0024 struct input_dev *input = dev_id;
0025 struct device *dev = input->dev.parent;
0026 struct regmap *regmap = dev_get_drvdata(dev);
0027 unsigned int state;
0028 int ret;
0029
0030 ret = regmap_read(regmap, BCOVE_PBSTATUS, &state);
0031 if (ret)
0032 return IRQ_NONE;
0033
0034 dev_dbg(dev, "PBSTATUS=0x%x\n", state);
0035 input_report_key(input, KEY_POWER, !(state & BCOVE_PBSTATUS_PBLVL));
0036 input_sync(input);
0037
0038 regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
0039 return IRQ_HANDLED;
0040 }
0041
0042 static int mrfld_pwrbtn_probe(struct platform_device *pdev)
0043 {
0044 struct device *dev = &pdev->dev;
0045 struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
0046 struct input_dev *input;
0047 int irq, ret;
0048
0049 irq = platform_get_irq(pdev, 0);
0050 if (irq < 0)
0051 return irq;
0052
0053 input = devm_input_allocate_device(dev);
0054 if (!input)
0055 return -ENOMEM;
0056 input->name = pdev->name;
0057 input->phys = "power-button/input0";
0058 input->id.bustype = BUS_HOST;
0059 input->dev.parent = dev;
0060 input_set_capability(input, EV_KEY, KEY_POWER);
0061 ret = input_register_device(input);
0062 if (ret)
0063 return ret;
0064
0065 dev_set_drvdata(dev, pmic->regmap);
0066
0067 ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_pwrbtn_interrupt,
0068 IRQF_ONESHOT | IRQF_SHARED, pdev->name,
0069 input);
0070 if (ret)
0071 return ret;
0072
0073 regmap_update_bits(pmic->regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_PWRBTN, 0);
0074 regmap_update_bits(pmic->regmap, BCOVE_MPBIRQ, BCOVE_PBIRQ_PBTN, 0);
0075
0076 device_init_wakeup(dev, true);
0077 dev_pm_set_wake_irq(dev, irq);
0078 return 0;
0079 }
0080
0081 static int mrfld_pwrbtn_remove(struct platform_device *pdev)
0082 {
0083 struct device *dev = &pdev->dev;
0084
0085 dev_pm_clear_wake_irq(dev);
0086 device_init_wakeup(dev, false);
0087 return 0;
0088 }
0089
0090 static const struct platform_device_id mrfld_pwrbtn_id_table[] = {
0091 { .name = "mrfld_bcove_pwrbtn" },
0092 {}
0093 };
0094 MODULE_DEVICE_TABLE(platform, mrfld_pwrbtn_id_table);
0095
0096 static struct platform_driver mrfld_pwrbtn_driver = {
0097 .driver = {
0098 .name = "mrfld_bcove_pwrbtn",
0099 },
0100 .probe = mrfld_pwrbtn_probe,
0101 .remove = mrfld_pwrbtn_remove,
0102 .id_table = mrfld_pwrbtn_id_table,
0103 };
0104 module_platform_driver(mrfld_pwrbtn_driver);
0105
0106 MODULE_DESCRIPTION("Power-button driver for Basin Cove PMIC");
0107 MODULE_LICENSE("GPL v2");