1212
1313#include <linux/acpi.h>
1414#include <linux/dmi.h>
15- #include <linux/gpio/driver .h>
15+ #include <linux/gpio/consumer .h>
1616#include <linux/gpio/machine.h>
1717#include <linux/irq.h>
1818#include <linux/module.h>
2121#include <linux/string.h>
2222
2323#include "x86-android-tablets.h"
24- /* For gpiochip_get_desc() which is EXPORT_SYMBOL_GPL() */
25- #include "../../../gpio/gpiolib.h"
26- #include "../../../gpio/gpiolib-acpi.h"
2724
28- static int gpiochip_find_match_label (struct gpio_chip * gc , void * data )
29- {
30- return gc -> label && !strcmp (gc -> label , data );
31- }
25+ static struct platform_device * x86_android_tablet_device ;
3226
33- int x86_android_tablet_get_gpiod (const char * label , int pin , struct gpio_desc * * desc )
27+ /*
28+ * This helper allows getting a gpio_desc *before* the actual device consuming
29+ * the GPIO has been instantiated. This function _must_ only be used to handle
30+ * this special case such as e.g. :
31+ *
32+ * 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to
33+ * i2c_client_new() to instantiate i2c_client-s; or
34+ * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys
35+ * platform_data which still uses old style GPIO numbers.
36+ *
37+ * Since the consuming device has not been instatiated yet a dynamic lookup
38+ * is generated using the special x86_android_tablet dev for dev_id.
39+ *
40+ * For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used.
41+ */
42+ int x86_android_tablet_get_gpiod (const char * chip , int pin , const char * con_id ,
43+ bool active_low , enum gpiod_flags dflags ,
44+ struct gpio_desc * * desc )
3445{
46+ struct gpiod_lookup_table * lookup ;
3547 struct gpio_desc * gpiod ;
36- struct gpio_chip * chip ;
3748
38- chip = gpiochip_find ((void * )label , gpiochip_find_match_label );
39- if (!chip ) {
40- pr_err ("error cannot find GPIO chip %s\n" , label );
41- return - ENODEV ;
42- }
49+ lookup = kzalloc (struct_size (lookup , table , 2 ), GFP_KERNEL );
50+ if (!lookup )
51+ return - ENOMEM ;
52+
53+ lookup -> dev_id = KBUILD_MODNAME ;
54+ lookup -> table [0 ].key = chip ;
55+ lookup -> table [0 ].chip_hwnum = pin ;
56+ lookup -> table [0 ].con_id = con_id ;
57+ lookup -> table [0 ].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH ;
58+
59+ gpiod_add_lookup_table (lookup );
60+ gpiod = devm_gpiod_get (& x86_android_tablet_device -> dev , con_id , dflags );
61+ gpiod_remove_lookup_table (lookup );
62+ kfree (lookup );
4363
44- gpiod = gpiochip_get_desc (chip , pin );
4564 if (IS_ERR (gpiod )) {
46- pr_err ("error %ld getting GPIO %s %d\n" , PTR_ERR (gpiod ), label , pin );
65+ pr_err ("error %ld getting GPIO %s %d\n" , PTR_ERR (gpiod ), chip , pin );
4766 return PTR_ERR (gpiod );
4867 }
4968
50- * desc = gpiod ;
69+ if (desc )
70+ * desc = gpiod ;
71+
5172 return 0 ;
5273}
5374
@@ -77,7 +98,8 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
7798 return irq ;
7899 case X86_ACPI_IRQ_TYPE_GPIOINT :
79100 /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
80- ret = x86_android_tablet_get_gpiod (data -> chip , data -> index , & gpiod );
101+ ret = x86_android_tablet_get_gpiod (data -> chip , data -> index , data -> con_id ,
102+ false, GPIOD_ASIS , & gpiod );
81103 if (ret )
82104 return ret ;
83105
@@ -224,7 +246,7 @@ static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int
224246 return ret ;
225247}
226248
227- static void x86_android_tablet_cleanup ( void )
249+ static void x86_android_tablet_remove ( struct platform_device * pdev )
228250{
229251 int i ;
230252
@@ -255,32 +277,19 @@ static void x86_android_tablet_cleanup(void)
255277 software_node_unregister (bat_swnode );
256278}
257279
258- static __init int x86_android_tablet_init ( void )
280+ static __init int x86_android_tablet_probe ( struct platform_device * pdev )
259281{
260282 const struct x86_dev_info * dev_info ;
261283 const struct dmi_system_id * id ;
262- struct gpio_chip * chip ;
263284 int i , ret = 0 ;
264285
265286 id = dmi_first_match (x86_android_tablet_ids );
266287 if (!id )
267288 return - ENODEV ;
268289
269290 dev_info = id -> driver_data ;
270-
271- /*
272- * The broken DSDTs on these devices often also include broken
273- * _AEI (ACPI Event Interrupt) handlers, disable these.
274- */
275- if (dev_info -> invalid_aei_gpiochip ) {
276- chip = gpiochip_find (dev_info -> invalid_aei_gpiochip ,
277- gpiochip_find_match_label );
278- if (!chip ) {
279- pr_err ("error cannot find GPIO chip %s\n" , dev_info -> invalid_aei_gpiochip );
280- return - ENODEV ;
281- }
282- acpi_gpiochip_free_interrupts (chip );
283- }
291+ /* Allow x86_android_tablet_device use before probe() exits */
292+ x86_android_tablet_device = pdev ;
284293
285294 /*
286295 * Since this runs from module_init() it cannot use -EPROBE_DEFER,
@@ -303,54 +312,54 @@ static __init int x86_android_tablet_init(void)
303312 if (dev_info -> init ) {
304313 ret = dev_info -> init ();
305314 if (ret < 0 ) {
306- x86_android_tablet_cleanup ( );
315+ x86_android_tablet_remove ( pdev );
307316 return ret ;
308317 }
309318 exit_handler = dev_info -> exit ;
310319 }
311320
312321 i2c_clients = kcalloc (dev_info -> i2c_client_count , sizeof (* i2c_clients ), GFP_KERNEL );
313322 if (!i2c_clients ) {
314- x86_android_tablet_cleanup ( );
323+ x86_android_tablet_remove ( pdev );
315324 return - ENOMEM ;
316325 }
317326
318327 i2c_client_count = dev_info -> i2c_client_count ;
319328 for (i = 0 ; i < i2c_client_count ; i ++ ) {
320329 ret = x86_instantiate_i2c_client (dev_info , i );
321330 if (ret < 0 ) {
322- x86_android_tablet_cleanup ( );
331+ x86_android_tablet_remove ( pdev );
323332 return ret ;
324333 }
325334 }
326335
327336 /* + 1 to make space for (optional) gpio_keys_button pdev */
328337 pdevs = kcalloc (dev_info -> pdev_count + 1 , sizeof (* pdevs ), GFP_KERNEL );
329338 if (!pdevs ) {
330- x86_android_tablet_cleanup ( );
339+ x86_android_tablet_remove ( pdev );
331340 return - ENOMEM ;
332341 }
333342
334343 pdev_count = dev_info -> pdev_count ;
335344 for (i = 0 ; i < pdev_count ; i ++ ) {
336345 pdevs [i ] = platform_device_register_full (& dev_info -> pdev_info [i ]);
337346 if (IS_ERR (pdevs [i ])) {
338- x86_android_tablet_cleanup ( );
347+ x86_android_tablet_remove ( pdev );
339348 return PTR_ERR (pdevs [i ]);
340349 }
341350 }
342351
343352 serdevs = kcalloc (dev_info -> serdev_count , sizeof (* serdevs ), GFP_KERNEL );
344353 if (!serdevs ) {
345- x86_android_tablet_cleanup ( );
354+ x86_android_tablet_remove ( pdev );
346355 return - ENOMEM ;
347356 }
348357
349358 serdev_count = dev_info -> serdev_count ;
350359 for (i = 0 ; i < serdev_count ; i ++ ) {
351360 ret = x86_instantiate_serdev (& dev_info -> serdev_info [i ], i );
352361 if (ret < 0 ) {
353- x86_android_tablet_cleanup ( );
362+ x86_android_tablet_remove ( pdev );
354363 return ret ;
355364 }
356365 }
@@ -361,30 +370,34 @@ static __init int x86_android_tablet_init(void)
361370
362371 buttons = kcalloc (dev_info -> gpio_button_count , sizeof (* buttons ), GFP_KERNEL );
363372 if (!buttons ) {
364- x86_android_tablet_cleanup ( );
373+ x86_android_tablet_remove ( pdev );
365374 return - ENOMEM ;
366375 }
367376
368377 for (i = 0 ; i < dev_info -> gpio_button_count ; i ++ ) {
369378 ret = x86_android_tablet_get_gpiod (dev_info -> gpio_button [i ].chip ,
370- dev_info -> gpio_button [i ].pin , & gpiod );
379+ dev_info -> gpio_button [i ].pin ,
380+ dev_info -> gpio_button [i ].button .desc ,
381+ false, GPIOD_IN , & gpiod );
371382 if (ret < 0 ) {
372- x86_android_tablet_cleanup ( );
383+ x86_android_tablet_remove ( pdev );
373384 return ret ;
374385 }
375386
376387 buttons [i ] = dev_info -> gpio_button [i ].button ;
377388 buttons [i ].gpio = desc_to_gpio (gpiod );
389+ /* Release gpiod so that gpio-keys can request it */
390+ devm_gpiod_put (& x86_android_tablet_device -> dev , gpiod );
378391 }
379392
380393 pdata .buttons = buttons ;
381394 pdata .nbuttons = dev_info -> gpio_button_count ;
382395
383- pdevs [pdev_count ] = platform_device_register_data (NULL , "gpio-keys" ,
396+ pdevs [pdev_count ] = platform_device_register_data (& pdev -> dev , "gpio-keys" ,
384397 PLATFORM_DEVID_AUTO ,
385398 & pdata , sizeof (pdata ));
386399 if (IS_ERR (pdevs [pdev_count ])) {
387- x86_android_tablet_cleanup ( );
400+ x86_android_tablet_remove ( pdev );
388401 return PTR_ERR (pdevs [pdev_count ]);
389402 }
390403 pdev_count ++ ;
@@ -393,8 +406,29 @@ static __init int x86_android_tablet_init(void)
393406 return 0 ;
394407}
395408
409+ static struct platform_driver x86_android_tablet_driver = {
410+ .driver = {
411+ .name = KBUILD_MODNAME ,
412+ },
413+ .remove_new = x86_android_tablet_remove ,
414+ };
415+
416+ static int __init x86_android_tablet_init (void )
417+ {
418+ x86_android_tablet_device = platform_create_bundle (& x86_android_tablet_driver ,
419+ x86_android_tablet_probe ,
420+ NULL , 0 , NULL , 0 );
421+
422+ return PTR_ERR_OR_ZERO (x86_android_tablet_device );
423+ }
396424module_init (x86_android_tablet_init );
397- module_exit (x86_android_tablet_cleanup );
425+
426+ static void __exit x86_android_tablet_exit (void )
427+ {
428+ platform_device_unregister (x86_android_tablet_device );
429+ platform_driver_unregister (& x86_android_tablet_driver );
430+ }
431+ module_exit (x86_android_tablet_exit );
398432
399433MODULE_AUTHOR ("Hans de Goede <hdegoede@redhat.com>" );
400434MODULE_DESCRIPTION ("X86 Android tablets DSDT fixups driver" );
0 commit comments