44 * Copyright (C) 2026 Flipper FZCO
55 */
66
7- #include <linux/input.h>
7+ #include <linux/array_size.h>
8+ #include <linux/bitops.h>
9+ #include <linux/bits.h>
10+ #include <linux/device.h>
11+ #include <linux/errno.h>
812#include <linux/input-event-codes.h>
13+ #include <linux/input.h>
914#include <linux/interrupt.h>
10- #include <linux/irq .h>
11- #include <linux/limits .h>
15+ #include <linux/mod_devicetable .h>
16+ #include <linux/module .h>
1217#include <linux/platform_device.h>
18+ #include <linux/pm_wakeup.h>
1319#include <linux/regmap.h>
14- #include <linux/unaligned .h>
20+ #include <linux/types .h>
1521
1622#include <linux/mfd/flipper-one-mcu.h>
1723
3642#define FO_HS_BTN_C BIT(4)
3743#define FO_HS_BTN_D BIT(5)
3844
39- struct fo_input {
40- struct input_dev * idev_btn ;
41- struct input_dev * idev_touch ;
42- struct input_dev * idev_headset ;
43- struct fomcu_device * fomcu ;
44- };
45-
46- struct fo_irq {
47- const char * name ;
48- irqreturn_t (* handler )(int , void * );
49- };
45+ #define FO_SWBTN_POWER BIT(0)
5046
5147static irqreturn_t fo_input_btn_handler (int irq , void * data )
5248{
53- struct fo_input * input = data ;
54- struct regmap * regmap = input -> fomcu -> regmap ;
55- struct input_dev * idev = input -> idev_btn ;
49+ struct input_dev * idev = data ;
50+ struct regmap * regmap = input_get_drvdata (idev );
5651 struct device * parent = idev -> dev .parent ;
5752 unsigned int reg ;
5853 int err ;
@@ -81,13 +76,29 @@ static irqreturn_t fo_input_btn_handler(int irq, void *data)
8176 return IRQ_HANDLED ;
8277}
8378
79+ static void fo_input_setup_btn (struct input_dev * idev )
80+ {
81+ input_set_capability (idev , EV_KEY , KEY_ENTER ); /* D-pad center */
82+ input_set_capability (idev , EV_KEY , KEY_UP ); /* D-pad up */
83+ input_set_capability (idev , EV_KEY , KEY_DOWN ); /* D-pad down */
84+ input_set_capability (idev , EV_KEY , KEY_LEFT ); /* D-pad left */
85+ input_set_capability (idev , EV_KEY , KEY_RIGHT ); /* D-pad right */
86+ input_set_capability (idev , EV_KEY , KEY_TAB ); /* App switcher */
87+ input_set_capability (idev , EV_KEY , KEY_BACKSPACE ); /* Back */
88+ input_set_capability (idev , EV_KEY , KEY_A ); /* PTT */
89+ input_set_capability (idev , EV_KEY , KEY_Z ); /* Escape */
90+ input_set_capability (idev , EV_KEY , KEY_X ); /* View */
91+ input_set_capability (idev , EV_KEY , KEY_C ); /* Power */
92+ input_set_capability (idev , EV_KEY , KEY_V ); /* Edit */
93+ input_set_capability (idev , EV_KEY , KEY_B ); /* Run */
94+ }
95+
8496static irqreturn_t fo_input_touch_handler (int irq , void * data )
8597{
86- struct fo_input * input = data ;
87- struct regmap * regmap = input -> fomcu -> regmap ;
88- struct input_dev * idev = input -> idev_touch ;
98+ struct input_dev * idev = data ;
99+ struct regmap * regmap = input_get_drvdata (idev );
89100 struct device * parent = idev -> dev .parent ;
90- uint16_t buf [3 ];
101+ u16 buf [3 ];
91102 int err ;
92103
93104 err = regmap_bulk_read (regmap , FOMCU_REG_INPUT_TOUCH_X , & buf , ARRAY_SIZE (buf ));
@@ -106,11 +117,20 @@ static irqreturn_t fo_input_touch_handler(int irq, void *data)
106117 return IRQ_HANDLED ;
107118}
108119
120+ static void fo_input_setup_touch (struct input_dev * idev )
121+ {
122+ input_set_capability (idev , EV_KEY , BTN_TOUCH );
123+ input_set_capability (idev , EV_KEY , BTN_TOOL_FINGER );
124+ input_set_abs_params (idev , ABS_X , 0 , 1024 , 0 , 0 );
125+ input_set_abs_params (idev , ABS_Y , 0 , 800 , 0 , 0 );
126+ input_set_abs_params (idev , ABS_PRESSURE , 0 , 12288 , 0 , 0 );
127+ __set_bit (INPUT_PROP_POINTER , idev -> propbit );
128+ }
129+
109130static irqreturn_t fo_input_headset_handler (int irq , void * data )
110131{
111- struct fo_input * input = data ;
112- struct regmap * regmap = input -> fomcu -> regmap ;
113- struct input_dev * idev = input -> idev_headset ;
132+ struct input_dev * idev = data ;
133+ struct regmap * regmap = input_get_drvdata (idev );
114134 struct device * parent = idev -> dev .parent ;
115135 unsigned int reg ;
116136 int err ;
@@ -132,118 +152,124 @@ static irqreturn_t fo_input_headset_handler(int irq, void *data)
132152 return IRQ_HANDLED ;
133153}
134154
135- static const struct fo_irq fo_irqs [] = {
136- { .name = "flipper-one-input-btn" , .handler = fo_input_btn_handler },
137- { .name = "flipper-one-input-touch" , .handler = fo_input_touch_handler },
138- { .name = "flipper-one-input-headset" , .handler = fo_input_headset_handler },
155+ static void fo_input_setup_headset (struct input_dev * idev )
156+ {
157+ input_set_capability (idev , EV_SW , SW_HEADPHONE_INSERT );
158+ input_set_capability (idev , EV_SW , SW_MICROPHONE_INSERT );
159+ input_set_capability (idev , EV_KEY , KEY_PLAYPAUSE );
160+ input_set_capability (idev , EV_KEY , KEY_VOLUMEUP );
161+ input_set_capability (idev , EV_KEY , KEY_VOLUMEDOWN );
162+ input_set_capability (idev , EV_KEY , KEY_VOICECOMMAND );
163+ }
164+
165+ static irqreturn_t fo_input_swbtn_handler (int irq , void * data )
166+ {
167+ struct input_dev * idev = data ;
168+ struct regmap * regmap = input_get_drvdata (idev );
169+ struct device * parent = idev -> dev .parent ;
170+ unsigned int reg ;
171+ int err ;
172+
173+ err = regmap_read (regmap , FOMCU_REG_INPUT_SWBTNS , & reg );
174+ if (err ) {
175+ dev_err (parent , "Failed to read SW button states: %d\n" , err );
176+ return IRQ_NONE ;
177+ }
178+
179+ input_report_key (idev , KEY_POWER , FO_SWBTN_POWER & reg );
180+ input_sync (idev );
181+
182+ return IRQ_HANDLED ;
183+ }
184+
185+ static void fo_input_setup_swbtn (struct input_dev * idev )
186+ {
187+ input_set_capability (idev , EV_KEY , KEY_POWER );
188+ }
189+
190+ struct fo_input_config {
191+ const char * name ;
192+ const char * phys ;
193+ const char * irq_name ;
194+ irqreturn_t (* handler )(int irq , void * data );
195+ void (* setup )(struct input_dev * idev );
196+ };
197+
198+ static const struct fo_input_config fo_input_configs [] = {
199+ {
200+ .name = "Flipper One Buttons" ,
201+ .phys = "flipper-one-input/input0" ,
202+ .irq_name = "flipper-one-input-btn" ,
203+ .handler = fo_input_btn_handler ,
204+ .setup = fo_input_setup_btn ,
205+ },
206+ {
207+ .name = "Flipper One Touchpad" ,
208+ .phys = "flipper-one-input/input1" ,
209+ .irq_name = "flipper-one-input-touch" ,
210+ .handler = fo_input_touch_handler ,
211+ .setup = fo_input_setup_touch ,
212+ },
213+ {
214+ .name = "Flipper One Headset" ,
215+ .phys = "flipper-one-input/input2" ,
216+ .irq_name = "flipper-one-input-headset" ,
217+ .handler = fo_input_headset_handler ,
218+ .setup = fo_input_setup_headset ,
219+ },
220+ {
221+ .name = "Flipper One Software Buttons" ,
222+ .phys = "flipper-one-input/input3" ,
223+ .irq_name = "flipper-one-input-swbtn" ,
224+ .handler = fo_input_swbtn_handler ,
225+ .setup = fo_input_setup_swbtn ,
226+ },
139227};
140228
141229static int fo_input_probe (struct platform_device * pdev )
142230{
143231 struct fomcu_device * fomcu = dev_get_drvdata (pdev -> dev .parent );
144232 struct device * dev = & pdev -> dev ;
145- struct fo_input * input ;
146- struct input_dev * idev_btn , * idev_touch , * idev_headset ;
147233 int irq , err , i ;
148234
149- input = devm_kzalloc (dev , sizeof (* input ), GFP_KERNEL );
150- if (!input )
151- return - ENOMEM ;
152-
153- input -> fomcu = fomcu ;
154-
155- idev_btn = devm_input_allocate_device (dev );
156- if (!idev_btn ) {
157- dev_err (dev , "Failed to allocate buttons input device\n" );
158- return - ENOMEM ;
159- }
160- input -> idev_btn = idev_btn ;
235+ err = devm_device_init_wakeup (dev );
236+ if (err )
237+ return dev_err_probe (dev , err , "Failed to init wakeup\n" );
161238
162- idev_btn -> name = "Flipper One Buttons" ;
163- idev_btn -> phys = "flipper-one-input/input0" ;
164- idev_btn -> id . bustype = BUS_I2C ;
239+ for ( i = 0 ; i < ARRAY_SIZE ( fo_input_configs ); i ++ ) {
240+ const struct fo_input_config * cfg = & fo_input_configs [ i ] ;
241+ struct input_dev * idev ;
165242
166- idev_touch = devm_input_allocate_device (dev );
167- if (!idev_touch ) {
168- dev_err (dev , "Failed to allocate touch input device\n" );
169- return - ENOMEM ;
170- }
171- input -> idev_touch = idev_touch ;
243+ idev = devm_input_allocate_device (dev );
244+ if (!idev )
245+ return dev_err_probe (dev , - ENOMEM ,
246+ "Failed to allocate %s input device\n" ,
247+ cfg -> name );
172248
173- idev_touch -> name = "Flipper One Touchpad" ;
174- idev_touch -> phys = "flipper-one-input/input1" ;
175- idev_touch -> id .bustype = BUS_I2C ;
249+ idev -> name = cfg -> name ;
250+ idev -> phys = cfg -> phys ;
251+ idev -> id .bustype = BUS_I2C ;
252+ input_set_drvdata (idev , fomcu -> regmap );
253+ cfg -> setup (idev );
176254
177- idev_headset = devm_input_allocate_device (dev );
178- if (!idev_headset ) {
179- dev_err (dev , "Failed to allocate headset input device\n" );
180- return - ENOMEM ;
181- }
182- input -> idev_headset = idev_headset ;
183-
184- idev_headset -> name = "Flipper One Headset" ;
185- idev_headset -> phys = "flipper-one-input/input2" ;
186- idev_headset -> id .bustype = BUS_I2C ;
187-
188- /* Buttons */
189- input_set_capability (idev_btn , EV_KEY , KEY_ENTER ); /* D-pad center */
190- input_set_capability (idev_btn , EV_KEY , KEY_UP ); /* D-pad up */
191- input_set_capability (idev_btn , EV_KEY , KEY_DOWN ); /* D-pad down */
192- input_set_capability (idev_btn , EV_KEY , KEY_LEFT ); /* D-pad left */
193- input_set_capability (idev_btn , EV_KEY , KEY_RIGHT ); /* D-pad right */
194- input_set_capability (idev_btn , EV_KEY , KEY_TAB ); /* App switcher */
195- input_set_capability (idev_btn , EV_KEY , KEY_BACKSPACE ); /* Back */
196- input_set_capability (idev_btn , EV_KEY , KEY_A ); /* PTT */
197- input_set_capability (idev_btn , EV_KEY , KEY_Z ); /* Escape */
198- input_set_capability (idev_btn , EV_KEY , KEY_X ); /* View */
199- input_set_capability (idev_btn , EV_KEY , KEY_C ); /* Power */
200- input_set_capability (idev_btn , EV_KEY , KEY_V ); /* Edit */
201- input_set_capability (idev_btn , EV_KEY , KEY_B ); /* Run */
202-
203- /* Touchpad */
204- input_set_capability (idev_touch , EV_KEY , BTN_TOUCH );
205- input_set_capability (idev_touch , EV_KEY , BTN_TOOL_FINGER );
206- input_set_abs_params (idev_touch , ABS_X , 0 , 1024 , 0 , 0 );
207- input_set_abs_params (idev_touch , ABS_Y , 0 , 800 , 0 , 0 );
208- input_set_abs_params (idev_touch , ABS_PRESSURE , 0 , 12288 , 0 , 0 );
209- __set_bit (INPUT_PROP_POINTER , idev_touch -> propbit );
210-
211- /* Headset */
212- input_set_capability (idev_headset , EV_SW , SW_HEADPHONE_INSERT );
213- input_set_capability (idev_headset , EV_SW , SW_MICROPHONE_INSERT );
214- input_set_capability (idev_headset , EV_KEY , KEY_PLAYPAUSE );
215- input_set_capability (idev_headset , EV_KEY , KEY_VOLUMEUP );
216- input_set_capability (idev_headset , EV_KEY , KEY_VOLUMEDOWN );
217- input_set_capability (idev_headset , EV_KEY , KEY_VOICECOMMAND );
218-
219- device_set_wakeup_capable (dev , true);
220- device_wakeup_enable (dev );
221-
222- for (i = 0 ; i < ARRAY_SIZE (fo_irqs ); i ++ ) {
223- irq = platform_get_irq_byname (pdev , fo_irqs [i ].name );
255+ irq = platform_get_irq_byname (pdev , cfg -> irq_name );
224256 if (irq < 0 )
225257 return dev_err_probe (dev , irq , "Failed to get IRQ %s\n" ,
226- fo_irqs [ i ]. name );
258+ cfg -> irq_name );
227259
228- err = devm_request_threaded_irq (dev , irq , NULL , fo_irqs [ i ]. handler ,
260+ err = devm_request_threaded_irq (dev , irq , NULL , cfg -> handler ,
229261 IRQF_ONESHOT | IRQF_NO_SUSPEND ,
230- fo_irqs [ i ]. name , input );
262+ cfg -> irq_name , idev );
231263 if (err )
232264 return dev_err_probe (dev , err , "Failed to request IRQ %s\n" ,
233- fo_irqs [i ].name );
234- }
265+ cfg -> irq_name );
235266
236- err = input_register_device (idev_btn );
237- if (err )
238- return dev_err_probe (dev , err , "Failed to register buttons input device\n" );
239-
240- err = input_register_device (idev_touch );
241- if (err )
242- return dev_err_probe (dev , err , "Failed to register touch input device\n" );
243-
244- err = input_register_device (idev_headset );
245- if (err )
246- return dev_err_probe (dev , err , "Failed to register headset input device\n" );
267+ err = input_register_device (idev );
268+ if (err )
269+ return dev_err_probe (dev , err ,
270+ "Failed to register %s input device\n" ,
271+ cfg -> name );
272+ }
247273
248274 return 0 ;
249275}
0 commit comments