// SPDX-License-Identifier: GPL-2.0 /* * Driver for the PF1550 ONKEY * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. * * Portions Copyright (c) 2025 Savoir-faire Linux Inc. * Samuel Kayode */ #include #include #include #include #include #include #include #define PF1550_ONKEY_IRQ_NR 6 struct onkey_drv_data { struct device *dev; const struct pf1550_ddata *pf1550; bool wakeup; struct input_dev *input; }; static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data) { struct onkey_drv_data *onkey = data; struct platform_device *pdev = to_platform_device(onkey->dev); int i, state, irq_type = -1; for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) if (irq == platform_get_irq(pdev, i)) irq_type = i; switch (irq_type) { case PF1550_ONKEY_IRQ_PUSHI: state = 0; break; case PF1550_ONKEY_IRQ_1SI: case PF1550_ONKEY_IRQ_2SI: case PF1550_ONKEY_IRQ_3SI: case PF1550_ONKEY_IRQ_4SI: case PF1550_ONKEY_IRQ_8SI: state = 1; break; default: dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n", irq_type); return IRQ_HANDLED; } input_event(onkey->input, EV_KEY, KEY_POWER, state); input_sync(onkey->input); return IRQ_HANDLED; } static int pf1550_onkey_probe(struct platform_device *pdev) { struct onkey_drv_data *onkey; struct input_dev *input; bool key_power = false; int i, irq, error; onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); if (!onkey) return -ENOMEM; onkey->dev = &pdev->dev; onkey->pf1550 = dev_get_drvdata(pdev->dev.parent); if (!onkey->pf1550->regmap) return dev_err_probe(&pdev->dev, -ENODEV, "failed to get regmap\n"); onkey->wakeup = device_property_read_bool(pdev->dev.parent, "wakeup-source"); if (device_property_read_bool(pdev->dev.parent, "nxp,disable-key-power")) { error = regmap_clear_bits(onkey->pf1550->regmap, PF1550_PMIC_REG_PWRCTRL1, PF1550_ONKEY_RST_EN); if (error) return dev_err_probe(&pdev->dev, error, "failed: disable turn system off"); } else { key_power = true; } input = devm_input_allocate_device(&pdev->dev); if (!input) return dev_err_probe(&pdev->dev, -ENOMEM, "failed to allocate the input device\n"); input->name = pdev->name; input->phys = "pf1550-onkey/input0"; input->id.bustype = BUS_HOST; if (key_power) input_set_capability(input, EV_KEY, KEY_POWER); onkey->input = input; platform_set_drvdata(pdev, onkey); for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { irq = platform_get_irq(pdev, i); if (irq < 0) return irq; error = devm_request_threaded_irq(&pdev->dev, irq, NULL, pf1550_onkey_irq_handler, IRQF_NO_SUSPEND, "pf1550-onkey", onkey); if (error) return dev_err_probe(&pdev->dev, error, "failed: irq request (IRQ: %d)\n", i); } error = input_register_device(input); if (error) return dev_err_probe(&pdev->dev, error, "failed to register input device\n"); device_init_wakeup(&pdev->dev, onkey->wakeup); return 0; } static int pf1550_onkey_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct onkey_drv_data *onkey = platform_get_drvdata(pdev); int i, irq; if (!device_may_wakeup(&pdev->dev)) regmap_write(onkey->pf1550->regmap, PF1550_PMIC_REG_ONKEY_INT_MASK0, ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI); else for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { irq = platform_get_irq(pdev, i); if (irq > 0) enable_irq_wake(irq); } return 0; } static int pf1550_onkey_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct onkey_drv_data *onkey = platform_get_drvdata(pdev); int i, irq; if (!device_may_wakeup(&pdev->dev)) regmap_write(onkey->pf1550->regmap, PF1550_PMIC_REG_ONKEY_INT_MASK0, ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI))); else for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { irq = platform_get_irq(pdev, i); if (irq > 0) disable_irq_wake(irq); } return 0; } static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend, pf1550_onkey_resume); static const struct platform_device_id pf1550_onkey_id[] = { { "pf1550-onkey", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, pf1550_onkey_id); static struct platform_driver pf1550_onkey_driver = { .driver = { .name = "pf1550-onkey", .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops), }, .probe = pf1550_onkey_probe, .id_table = pf1550_onkey_id, }; module_platform_driver(pf1550_onkey_driver); MODULE_AUTHOR("Freescale Semiconductor"); MODULE_DESCRIPTION("PF1550 onkey Driver"); MODULE_LICENSE("GPL");