1*9acb215cSSamuel Kayode // SPDX-License-Identifier: GPL-2.0 2*9acb215cSSamuel Kayode /* 3*9acb215cSSamuel Kayode * Driver for the PF1550 ONKEY 4*9acb215cSSamuel Kayode * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. 5*9acb215cSSamuel Kayode * 6*9acb215cSSamuel Kayode * Portions Copyright (c) 2025 Savoir-faire Linux Inc. 7*9acb215cSSamuel Kayode * Samuel Kayode <samuel.kayode@savoirfairelinux.com> 8*9acb215cSSamuel Kayode */ 9*9acb215cSSamuel Kayode 10*9acb215cSSamuel Kayode #include <linux/err.h> 11*9acb215cSSamuel Kayode #include <linux/input.h> 12*9acb215cSSamuel Kayode #include <linux/interrupt.h> 13*9acb215cSSamuel Kayode #include <linux/kernel.h> 14*9acb215cSSamuel Kayode #include <linux/module.h> 15*9acb215cSSamuel Kayode #include <linux/mfd/pf1550.h> 16*9acb215cSSamuel Kayode #include <linux/platform_device.h> 17*9acb215cSSamuel Kayode 18*9acb215cSSamuel Kayode #define PF1550_ONKEY_IRQ_NR 6 19*9acb215cSSamuel Kayode 20*9acb215cSSamuel Kayode struct onkey_drv_data { 21*9acb215cSSamuel Kayode struct device *dev; 22*9acb215cSSamuel Kayode const struct pf1550_ddata *pf1550; 23*9acb215cSSamuel Kayode bool wakeup; 24*9acb215cSSamuel Kayode struct input_dev *input; 25*9acb215cSSamuel Kayode }; 26*9acb215cSSamuel Kayode 27*9acb215cSSamuel Kayode static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data) 28*9acb215cSSamuel Kayode { 29*9acb215cSSamuel Kayode struct onkey_drv_data *onkey = data; 30*9acb215cSSamuel Kayode struct platform_device *pdev = to_platform_device(onkey->dev); 31*9acb215cSSamuel Kayode int i, state, irq_type = -1; 32*9acb215cSSamuel Kayode 33*9acb215cSSamuel Kayode for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) 34*9acb215cSSamuel Kayode if (irq == platform_get_irq(pdev, i)) 35*9acb215cSSamuel Kayode irq_type = i; 36*9acb215cSSamuel Kayode 37*9acb215cSSamuel Kayode switch (irq_type) { 38*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_PUSHI: 39*9acb215cSSamuel Kayode state = 0; 40*9acb215cSSamuel Kayode break; 41*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_1SI: 42*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_2SI: 43*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_3SI: 44*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_4SI: 45*9acb215cSSamuel Kayode case PF1550_ONKEY_IRQ_8SI: 46*9acb215cSSamuel Kayode state = 1; 47*9acb215cSSamuel Kayode break; 48*9acb215cSSamuel Kayode default: 49*9acb215cSSamuel Kayode dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n", 50*9acb215cSSamuel Kayode irq_type); 51*9acb215cSSamuel Kayode return IRQ_HANDLED; 52*9acb215cSSamuel Kayode } 53*9acb215cSSamuel Kayode 54*9acb215cSSamuel Kayode input_event(onkey->input, EV_KEY, KEY_POWER, state); 55*9acb215cSSamuel Kayode input_sync(onkey->input); 56*9acb215cSSamuel Kayode 57*9acb215cSSamuel Kayode return IRQ_HANDLED; 58*9acb215cSSamuel Kayode } 59*9acb215cSSamuel Kayode 60*9acb215cSSamuel Kayode static int pf1550_onkey_probe(struct platform_device *pdev) 61*9acb215cSSamuel Kayode { 62*9acb215cSSamuel Kayode struct onkey_drv_data *onkey; 63*9acb215cSSamuel Kayode struct input_dev *input; 64*9acb215cSSamuel Kayode bool key_power = false; 65*9acb215cSSamuel Kayode int i, irq, error; 66*9acb215cSSamuel Kayode 67*9acb215cSSamuel Kayode onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); 68*9acb215cSSamuel Kayode if (!onkey) 69*9acb215cSSamuel Kayode return -ENOMEM; 70*9acb215cSSamuel Kayode 71*9acb215cSSamuel Kayode onkey->dev = &pdev->dev; 72*9acb215cSSamuel Kayode 73*9acb215cSSamuel Kayode onkey->pf1550 = dev_get_drvdata(pdev->dev.parent); 74*9acb215cSSamuel Kayode if (!onkey->pf1550->regmap) 75*9acb215cSSamuel Kayode return dev_err_probe(&pdev->dev, -ENODEV, 76*9acb215cSSamuel Kayode "failed to get regmap\n"); 77*9acb215cSSamuel Kayode 78*9acb215cSSamuel Kayode onkey->wakeup = device_property_read_bool(pdev->dev.parent, 79*9acb215cSSamuel Kayode "wakeup-source"); 80*9acb215cSSamuel Kayode 81*9acb215cSSamuel Kayode if (device_property_read_bool(pdev->dev.parent, 82*9acb215cSSamuel Kayode "nxp,disable-key-power")) { 83*9acb215cSSamuel Kayode error = regmap_clear_bits(onkey->pf1550->regmap, 84*9acb215cSSamuel Kayode PF1550_PMIC_REG_PWRCTRL1, 85*9acb215cSSamuel Kayode PF1550_ONKEY_RST_EN); 86*9acb215cSSamuel Kayode if (error) 87*9acb215cSSamuel Kayode return dev_err_probe(&pdev->dev, error, 88*9acb215cSSamuel Kayode "failed: disable turn system off"); 89*9acb215cSSamuel Kayode } else { 90*9acb215cSSamuel Kayode key_power = true; 91*9acb215cSSamuel Kayode } 92*9acb215cSSamuel Kayode 93*9acb215cSSamuel Kayode input = devm_input_allocate_device(&pdev->dev); 94*9acb215cSSamuel Kayode if (!input) 95*9acb215cSSamuel Kayode return dev_err_probe(&pdev->dev, -ENOMEM, 96*9acb215cSSamuel Kayode "failed to allocate the input device\n"); 97*9acb215cSSamuel Kayode 98*9acb215cSSamuel Kayode input->name = pdev->name; 99*9acb215cSSamuel Kayode input->phys = "pf1550-onkey/input0"; 100*9acb215cSSamuel Kayode input->id.bustype = BUS_HOST; 101*9acb215cSSamuel Kayode 102*9acb215cSSamuel Kayode if (key_power) 103*9acb215cSSamuel Kayode input_set_capability(input, EV_KEY, KEY_POWER); 104*9acb215cSSamuel Kayode 105*9acb215cSSamuel Kayode onkey->input = input; 106*9acb215cSSamuel Kayode platform_set_drvdata(pdev, onkey); 107*9acb215cSSamuel Kayode 108*9acb215cSSamuel Kayode for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { 109*9acb215cSSamuel Kayode irq = platform_get_irq(pdev, i); 110*9acb215cSSamuel Kayode if (irq < 0) 111*9acb215cSSamuel Kayode return irq; 112*9acb215cSSamuel Kayode 113*9acb215cSSamuel Kayode error = devm_request_threaded_irq(&pdev->dev, irq, NULL, 114*9acb215cSSamuel Kayode pf1550_onkey_irq_handler, 115*9acb215cSSamuel Kayode IRQF_NO_SUSPEND, 116*9acb215cSSamuel Kayode "pf1550-onkey", onkey); 117*9acb215cSSamuel Kayode if (error) 118*9acb215cSSamuel Kayode return dev_err_probe(&pdev->dev, error, 119*9acb215cSSamuel Kayode "failed: irq request (IRQ: %d)\n", 120*9acb215cSSamuel Kayode i); 121*9acb215cSSamuel Kayode } 122*9acb215cSSamuel Kayode 123*9acb215cSSamuel Kayode error = input_register_device(input); 124*9acb215cSSamuel Kayode if (error) 125*9acb215cSSamuel Kayode return dev_err_probe(&pdev->dev, error, 126*9acb215cSSamuel Kayode "failed to register input device\n"); 127*9acb215cSSamuel Kayode 128*9acb215cSSamuel Kayode device_init_wakeup(&pdev->dev, onkey->wakeup); 129*9acb215cSSamuel Kayode 130*9acb215cSSamuel Kayode return 0; 131*9acb215cSSamuel Kayode } 132*9acb215cSSamuel Kayode 133*9acb215cSSamuel Kayode static int pf1550_onkey_suspend(struct device *dev) 134*9acb215cSSamuel Kayode { 135*9acb215cSSamuel Kayode struct platform_device *pdev = to_platform_device(dev); 136*9acb215cSSamuel Kayode struct onkey_drv_data *onkey = platform_get_drvdata(pdev); 137*9acb215cSSamuel Kayode int i, irq; 138*9acb215cSSamuel Kayode 139*9acb215cSSamuel Kayode if (!device_may_wakeup(&pdev->dev)) 140*9acb215cSSamuel Kayode regmap_write(onkey->pf1550->regmap, 141*9acb215cSSamuel Kayode PF1550_PMIC_REG_ONKEY_INT_MASK0, 142*9acb215cSSamuel Kayode ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | 143*9acb215cSSamuel Kayode ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI); 144*9acb215cSSamuel Kayode else 145*9acb215cSSamuel Kayode for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { 146*9acb215cSSamuel Kayode irq = platform_get_irq(pdev, i); 147*9acb215cSSamuel Kayode if (irq > 0) 148*9acb215cSSamuel Kayode enable_irq_wake(irq); 149*9acb215cSSamuel Kayode } 150*9acb215cSSamuel Kayode 151*9acb215cSSamuel Kayode return 0; 152*9acb215cSSamuel Kayode } 153*9acb215cSSamuel Kayode 154*9acb215cSSamuel Kayode static int pf1550_onkey_resume(struct device *dev) 155*9acb215cSSamuel Kayode { 156*9acb215cSSamuel Kayode struct platform_device *pdev = to_platform_device(dev); 157*9acb215cSSamuel Kayode struct onkey_drv_data *onkey = platform_get_drvdata(pdev); 158*9acb215cSSamuel Kayode int i, irq; 159*9acb215cSSamuel Kayode 160*9acb215cSSamuel Kayode if (!device_may_wakeup(&pdev->dev)) 161*9acb215cSSamuel Kayode regmap_write(onkey->pf1550->regmap, 162*9acb215cSSamuel Kayode PF1550_PMIC_REG_ONKEY_INT_MASK0, 163*9acb215cSSamuel Kayode ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | 164*9acb215cSSamuel Kayode ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | 165*9acb215cSSamuel Kayode ONKEY_IRQ_8SI))); 166*9acb215cSSamuel Kayode else 167*9acb215cSSamuel Kayode for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { 168*9acb215cSSamuel Kayode irq = platform_get_irq(pdev, i); 169*9acb215cSSamuel Kayode if (irq > 0) 170*9acb215cSSamuel Kayode disable_irq_wake(irq); 171*9acb215cSSamuel Kayode } 172*9acb215cSSamuel Kayode 173*9acb215cSSamuel Kayode return 0; 174*9acb215cSSamuel Kayode } 175*9acb215cSSamuel Kayode 176*9acb215cSSamuel Kayode static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend, 177*9acb215cSSamuel Kayode pf1550_onkey_resume); 178*9acb215cSSamuel Kayode 179*9acb215cSSamuel Kayode static const struct platform_device_id pf1550_onkey_id[] = { 180*9acb215cSSamuel Kayode { "pf1550-onkey", }, 181*9acb215cSSamuel Kayode { /* sentinel */ } 182*9acb215cSSamuel Kayode }; 183*9acb215cSSamuel Kayode MODULE_DEVICE_TABLE(platform, pf1550_onkey_id); 184*9acb215cSSamuel Kayode 185*9acb215cSSamuel Kayode static struct platform_driver pf1550_onkey_driver = { 186*9acb215cSSamuel Kayode .driver = { 187*9acb215cSSamuel Kayode .name = "pf1550-onkey", 188*9acb215cSSamuel Kayode .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops), 189*9acb215cSSamuel Kayode }, 190*9acb215cSSamuel Kayode .probe = pf1550_onkey_probe, 191*9acb215cSSamuel Kayode .id_table = pf1550_onkey_id, 192*9acb215cSSamuel Kayode }; 193*9acb215cSSamuel Kayode module_platform_driver(pf1550_onkey_driver); 194*9acb215cSSamuel Kayode 195*9acb215cSSamuel Kayode MODULE_AUTHOR("Freescale Semiconductor"); 196*9acb215cSSamuel Kayode MODULE_DESCRIPTION("PF1550 onkey Driver"); 197*9acb215cSSamuel Kayode MODULE_LICENSE("GPL"); 198