Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Input: twl4030 - add TWL603x power button

Like the TWL4030, these PMICs also have a power button feature, so extend
the TWL4030 power button driver. As the irqchip of the TWL6030 mfd driver
does not provide mask, unmask finctions, do it manually.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
Link: https://patch.msgid.link/20251106-twl6030-button-v4-2-fdf1aa6e1e9a@kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Andreas Kemnade and committed by
Dmitry Torokhov
ec8fce2a b72fbdc0

+55 -5
+55 -5
drivers/input/misc/twl4030-pwrbutton.c
··· 20 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 21 */ 22 22 23 + #include <linux/bits.h> 23 24 #include <linux/module.h> 24 25 #include <linux/init.h> 25 26 #include <linux/kernel.h> ··· 31 30 #include <linux/platform_device.h> 32 31 #include <linux/mfd/twl.h> 33 32 34 - #define PWR_PWRON_IRQ (1 << 0) 33 + #define PWR_PWRON_IRQ BIT(0) 35 34 36 - #define STS_HW_CONDITIONS 0xf 35 + struct twl_pwrbutton_chipdata { 36 + u8 status_reg; 37 + bool need_manual_irq; 38 + }; 39 + 40 + static const struct twl_pwrbutton_chipdata twl4030_chipdata = { 41 + .status_reg = 0xf, 42 + .need_manual_irq = false, 43 + }; 44 + 45 + static const struct twl_pwrbutton_chipdata twl6030_chipdata = { 46 + .status_reg = 0x2, 47 + .need_manual_irq = true, 48 + }; 37 49 38 50 static irqreturn_t powerbutton_irq(int irq, void *_pwr) 39 51 { 40 52 struct input_dev *pwr = _pwr; 53 + const struct twl_pwrbutton_chipdata *pdata = dev_get_drvdata(pwr->dev.parent); 41 54 int err; 42 55 u8 value; 43 56 44 - err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); 57 + err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, pdata->status_reg); 45 58 if (!err) { 46 59 pm_wakeup_event(pwr->dev.parent, 0); 47 60 input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); ··· 70 55 71 56 static int twl4030_pwrbutton_probe(struct platform_device *pdev) 72 57 { 58 + const struct twl_pwrbutton_chipdata *pdata; 73 59 struct input_dev *pwr; 74 60 int irq = platform_get_irq(pdev, 0); 75 61 int err; 62 + 63 + pdata = device_get_match_data(&pdev->dev); 64 + if (!pdata) 65 + return -EINVAL; 66 + 67 + platform_set_drvdata(pdev, (void *)pdata); 76 68 77 69 pwr = devm_input_allocate_device(&pdev->dev); 78 70 if (!pwr) { ··· 107 85 return err; 108 86 } 109 87 88 + if (pdata->need_manual_irq) { 89 + err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A); 90 + if (err) 91 + return err; 92 + 93 + err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A); 94 + if (err) 95 + return err; 96 + } 97 + 110 98 device_init_wakeup(&pdev->dev, true); 111 99 112 100 return 0; 113 101 } 114 102 103 + static void twl4030_pwrbutton_remove(struct platform_device *pdev) 104 + { 105 + const struct twl_pwrbutton_chipdata *pdata = platform_get_drvdata(pdev); 106 + 107 + if (pdata->need_manual_irq) { 108 + twl6030_interrupt_mask(0x01, REG_INT_MSK_LINE_A); 109 + twl6030_interrupt_mask(0x01, REG_INT_MSK_STS_A); 110 + } 111 + } 112 + 115 113 #ifdef CONFIG_OF 116 114 static const struct of_device_id twl4030_pwrbutton_dt_match_table[] = { 117 - { .compatible = "ti,twl4030-pwrbutton" }, 118 - {}, 115 + { 116 + .compatible = "ti,twl4030-pwrbutton", 117 + .data = &twl4030_chipdata, 118 + }, 119 + { 120 + .compatible = "ti,twl6030-pwrbutton", 121 + .data = &twl6030_chipdata, 122 + }, 123 + { } 119 124 }; 120 125 MODULE_DEVICE_TABLE(of, twl4030_pwrbutton_dt_match_table); 121 126 #endif 122 127 123 128 static struct platform_driver twl4030_pwrbutton_driver = { 124 129 .probe = twl4030_pwrbutton_probe, 130 + .remove = twl4030_pwrbutton_remove, 125 131 .driver = { 126 132 .name = "twl4030_pwrbutton", 127 133 .of_match_table = of_match_ptr(twl4030_pwrbutton_dt_match_table),