| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (C) 2022 Richtek Technology Corp. |
| * Author: ChiYuan Huang <cy_huang@richtek.com> |
| */ |
| |
| #include <linux/bits.h> |
| #include <linux/input.h> |
| #include <linux/interrupt.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/mod_devicetable.h> |
| #include <linux/platform_device.h> |
| #include <linux/regmap.h> |
| |
| #define RT5120_REG_INTSTAT 0x1E |
| #define RT5120_PWRKEYSTAT_MASK BIT(7) |
| |
| struct rt5120_priv { |
| struct regmap *regmap; |
| struct input_dev *input; |
| }; |
| |
| static irqreturn_t rt5120_pwrkey_handler(int irq, void *devid) |
| { |
| struct rt5120_priv *priv = devid; |
| unsigned int stat; |
| int error; |
| |
| error = regmap_read(priv->regmap, RT5120_REG_INTSTAT, &stat); |
| if (error) |
| return IRQ_NONE; |
| |
| input_report_key(priv->input, KEY_POWER, |
| !(stat & RT5120_PWRKEYSTAT_MASK)); |
| input_sync(priv->input); |
| |
| return IRQ_HANDLED; |
| } |
| |
| static int rt5120_pwrkey_probe(struct platform_device *pdev) |
| { |
| struct rt5120_priv *priv; |
| struct device *dev = &pdev->dev; |
| int press_irq, release_irq; |
| int error; |
| |
| priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| if (!priv) |
| return -ENOMEM; |
| |
| priv->regmap = dev_get_regmap(dev->parent, NULL); |
| if (!priv->regmap) { |
| dev_err(dev, "Failed to init regmap\n"); |
| return -ENODEV; |
| } |
| |
| press_irq = platform_get_irq_byname(pdev, "pwrkey-press"); |
| if (press_irq < 0) |
| return press_irq; |
| |
| release_irq = platform_get_irq_byname(pdev, "pwrkey-release"); |
| if (release_irq < 0) |
| return release_irq; |
| |
| /* Make input device be device resource managed */ |
| priv->input = devm_input_allocate_device(dev); |
| if (!priv->input) |
| return -ENOMEM; |
| |
| priv->input->name = "rt5120_pwrkey"; |
| priv->input->phys = "rt5120_pwrkey/input0"; |
| priv->input->id.bustype = BUS_I2C; |
| input_set_capability(priv->input, EV_KEY, KEY_POWER); |
| |
| error = input_register_device(priv->input); |
| if (error) { |
| dev_err(dev, "Failed to register input device: %d\n", error); |
| return error; |
| } |
| |
| error = devm_request_threaded_irq(dev, press_irq, |
| NULL, rt5120_pwrkey_handler, |
| 0, "pwrkey-press", priv); |
| if (error) { |
| dev_err(dev, |
| "Failed to register pwrkey press irq: %d\n", error); |
| return error; |
| } |
| |
| error = devm_request_threaded_irq(dev, release_irq, |
| NULL, rt5120_pwrkey_handler, |
| 0, "pwrkey-release", priv); |
| if (error) { |
| dev_err(dev, |
| "Failed to register pwrkey release irq: %d\n", error); |
| return error; |
| } |
| |
| return 0; |
| } |
| |
| static const struct of_device_id r5120_pwrkey_match_table[] = { |
| { .compatible = "richtek,rt5120-pwrkey" }, |
| {} |
| }; |
| MODULE_DEVICE_TABLE(of, r5120_pwrkey_match_table); |
| |
| static struct platform_driver rt5120_pwrkey_driver = { |
| .driver = { |
| .name = "rt5120-pwrkey", |
| .of_match_table = r5120_pwrkey_match_table, |
| }, |
| .probe = rt5120_pwrkey_probe, |
| }; |
| module_platform_driver(rt5120_pwrkey_driver); |
| |
| MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); |
| MODULE_DESCRIPTION("Richtek RT5120 power key driver"); |
| MODULE_LICENSE("GPL"); |