1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * DMI based code to deal with broken DSDTs on X86 tablets which ship with
4 * Android as (part of) the factory image. The factory kernels shipped on these
5 * devices typically have a bunch of things hardcoded, rather than specified
6 * in their DSDT.
7 *
8 * Copyright (C) 2021-2023 Hans de Goede <hdegoede@redhat.com>
9 */
10
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13#include <linux/acpi.h>
14#include <linux/dmi.h>
15#include <linux/gpio/consumer.h>
16#include <linux/gpio/machine.h>
17#include <linux/irq.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/serdev.h>
21#include <linux/string.h>
22
23#include "x86-android-tablets.h"
24#include "../serdev_helpers.h"
25
26static struct platform_device *x86_android_tablet_device;
27
28/*
29 * This helper allows getting a gpio_desc *before* the actual device consuming
30 * the GPIO has been instantiated. This function _must_ only be used to handle
31 * this special case such as e.g. :
32 *
33 * 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to
34 * i2c_client_new() to instantiate i2c_client-s; or
35 * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys
36 * platform_data which still uses old style GPIO numbers.
37 *
38 * Since the consuming device has not been instatiated yet a dynamic lookup
39 * is generated using the special x86_android_tablet dev for dev_id.
40 *
41 * For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used.
42 */
43int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
44 bool active_low, enum gpiod_flags dflags,
45 struct gpio_desc **desc)
46{
47 struct gpiod_lookup_table *lookup;
48 struct gpio_desc *gpiod;
49
50 lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
51 if (!lookup)
52 return -ENOMEM;
53
54 lookup->dev_id = KBUILD_MODNAME;
55 lookup->table[0].key = chip;
56 lookup->table[0].chip_hwnum = pin;
57 lookup->table[0].con_id = con_id;
58 lookup->table[0].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH;
59
60 gpiod_add_lookup_table(table: lookup);
61 gpiod = devm_gpiod_get(dev: &x86_android_tablet_device->dev, con_id, flags: dflags);
62 gpiod_remove_lookup_table(table: lookup);
63 kfree(objp: lookup);
64
65 if (IS_ERR(ptr: gpiod)) {
66 pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), chip, pin);
67 return PTR_ERR(ptr: gpiod);
68 }
69
70 if (desc)
71 *desc = gpiod;
72
73 return 0;
74}
75
76int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
77{
78 struct irq_fwspec fwspec = { };
79 struct irq_domain *domain;
80 struct acpi_device *adev;
81 struct gpio_desc *gpiod;
82 unsigned int irq_type;
83 acpi_handle handle;
84 acpi_status status;
85 int irq, ret;
86
87 switch (data->type) {
88 case X86_ACPI_IRQ_TYPE_APIC:
89 /*
90 * The DSDT may already reference the GSI in a device skipped by
91 * acpi_quirk_skip_i2c_client_enumeration(). Unregister the GSI
92 * to avoid EBUSY errors in this case.
93 */
94 acpi_unregister_gsi(gsi: data->index);
95 irq = acpi_register_gsi(NULL, gsi: data->index, triggering: data->trigger, polarity: data->polarity);
96 if (irq < 0)
97 pr_err("error %d getting APIC IRQ %d\n", irq, data->index);
98
99 return irq;
100 case X86_ACPI_IRQ_TYPE_GPIOINT:
101 /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
102 ret = x86_android_tablet_get_gpiod(chip: data->chip, pin: data->index, con_id: data->con_id,
103 active_low: false, dflags: GPIOD_ASIS, desc: &gpiod);
104 if (ret)
105 return ret;
106
107 irq = gpiod_to_irq(desc: gpiod);
108 if (irq < 0) {
109 pr_err("error %d getting IRQ %s %d\n", irq, data->chip, data->index);
110 return irq;
111 }
112
113 irq_type = acpi_dev_get_irq_type(triggering: data->trigger, polarity: data->polarity);
114 if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq))
115 irq_set_irq_type(irq, type: irq_type);
116
117 if (data->free_gpio)
118 devm_gpiod_put(dev: &x86_android_tablet_device->dev, desc: gpiod);
119
120 return irq;
121 case X86_ACPI_IRQ_TYPE_PMIC:
122 status = acpi_get_handle(NULL, pathname: data->chip, ret_handle: &handle);
123 if (ACPI_FAILURE(status)) {
124 pr_err("error could not get %s handle\n", data->chip);
125 return -ENODEV;
126 }
127
128 adev = acpi_fetch_acpi_dev(handle);
129 if (!adev) {
130 pr_err("error could not get %s adev\n", data->chip);
131 return -ENODEV;
132 }
133
134 fwspec.fwnode = acpi_fwnode_handle(adev);
135 domain = irq_find_matching_fwspec(fwspec: &fwspec, bus_token: data->domain);
136 if (!domain) {
137 pr_err("error could not find IRQ domain for %s\n", data->chip);
138 return -ENODEV;
139 }
140
141 return irq_create_mapping(host: domain, hwirq: data->index);
142 default:
143 return 0;
144 }
145}
146
147static int i2c_client_count;
148static int spi_dev_count;
149static int pdev_count;
150static int serdev_count;
151static struct i2c_client **i2c_clients;
152static struct spi_device **spi_devs;
153static struct platform_device **pdevs;
154static struct serdev_device **serdevs;
155static struct gpio_keys_button *buttons;
156static struct gpiod_lookup_table * const *gpiod_lookup_tables;
157static const struct software_node *bat_swnode;
158static void (*exit_handler)(void);
159
160static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
161 int idx)
162{
163 const struct x86_i2c_client_info *client_info = &dev_info->i2c_client_info[idx];
164 struct i2c_board_info board_info = client_info->board_info;
165 struct i2c_adapter *adap;
166 acpi_handle handle;
167 acpi_status status;
168
169 board_info.irq = x86_acpi_irq_helper_get(data: &client_info->irq_data);
170 if (board_info.irq < 0)
171 return board_info.irq;
172
173 status = acpi_get_handle(NULL, pathname: client_info->adapter_path, ret_handle: &handle);
174 if (ACPI_FAILURE(status)) {
175 pr_err("Error could not get %s handle\n", client_info->adapter_path);
176 return -ENODEV;
177 }
178
179 adap = i2c_acpi_find_adapter_by_handle(handle);
180 if (!adap) {
181 pr_err("error could not get %s adapter\n", client_info->adapter_path);
182 return -ENODEV;
183 }
184
185 i2c_clients[idx] = i2c_new_client_device(adap, info: &board_info);
186 put_device(dev: &adap->dev);
187 if (IS_ERR(ptr: i2c_clients[idx]))
188 return dev_err_probe(dev: &adap->dev, err: PTR_ERR(ptr: i2c_clients[idx]),
189 fmt: "creating I2C-client %d\n", idx);
190
191 return 0;
192}
193
194static __init int x86_instantiate_spi_dev(const struct x86_dev_info *dev_info, int idx)
195{
196 const struct x86_spi_dev_info *spi_dev_info = &dev_info->spi_dev_info[idx];
197 struct spi_board_info board_info = spi_dev_info->board_info;
198 struct spi_controller *controller;
199 struct acpi_device *adev;
200 acpi_handle handle;
201 acpi_status status;
202
203 board_info.irq = x86_acpi_irq_helper_get(data: &spi_dev_info->irq_data);
204 if (board_info.irq < 0)
205 return board_info.irq;
206
207 status = acpi_get_handle(NULL, pathname: spi_dev_info->ctrl_path, ret_handle: &handle);
208 if (ACPI_FAILURE(status)) {
209 pr_err("Error could not get %s handle\n", spi_dev_info->ctrl_path);
210 return -ENODEV;
211 }
212
213 adev = acpi_fetch_acpi_dev(handle);
214 if (!adev) {
215 pr_err("Error could not get adev for %s\n", spi_dev_info->ctrl_path);
216 return -ENODEV;
217 }
218
219 controller = acpi_spi_find_controller_by_adev(adev);
220 if (!controller) {
221 pr_err("Error could not get SPI controller for %s\n", spi_dev_info->ctrl_path);
222 return -ENODEV;
223 }
224
225 spi_devs[idx] = spi_new_device(controller, &board_info);
226 put_device(dev: &controller->dev);
227 if (!spi_devs[idx])
228 return dev_err_probe(dev: &controller->dev, err: -ENOMEM,
229 fmt: "creating SPI-device %d\n", idx);
230
231 return 0;
232}
233
234static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int idx)
235{
236 struct acpi_device *serdev_adev;
237 struct serdev_device *serdev;
238 struct device *ctrl_dev;
239 int ret = -ENODEV;
240
241 ctrl_dev = get_serdev_controller(serial_ctrl_hid: info->ctrl_hid, serial_ctrl_uid: info->ctrl_uid, serial_ctrl_port: 0,
242 serdev_ctrl_name: info->ctrl_devname);
243 if (IS_ERR(ptr: ctrl_dev))
244 return PTR_ERR(ptr: ctrl_dev);
245
246 serdev_adev = acpi_dev_get_first_match_dev(hid: info->serdev_hid, NULL, hrv: -1);
247 if (!serdev_adev) {
248 pr_err("error could not get %s serdev adev\n", info->serdev_hid);
249 goto put_ctrl_dev;
250 }
251
252 serdev = serdev_device_alloc(to_serdev_controller(d: ctrl_dev));
253 if (!serdev) {
254 ret = -ENOMEM;
255 goto put_serdev_adev;
256 }
257
258 ACPI_COMPANION_SET(&serdev->dev, serdev_adev);
259 acpi_device_set_enumerated(adev: serdev_adev);
260
261 ret = serdev_device_add(serdev);
262 if (ret) {
263 dev_err(&serdev->dev, "error %d adding serdev\n", ret);
264 serdev_device_put(serdev);
265 goto put_serdev_adev;
266 }
267
268 serdevs[idx] = serdev;
269
270put_serdev_adev:
271 acpi_dev_put(adev: serdev_adev);
272put_ctrl_dev:
273 put_device(dev: ctrl_dev);
274 return ret;
275}
276
277static void x86_android_tablet_remove(struct platform_device *pdev)
278{
279 int i;
280
281 for (i = 0; i < serdev_count; i++) {
282 if (serdevs[i])
283 serdev_device_remove(serdevs[i]);
284 }
285
286 kfree(objp: serdevs);
287
288 for (i = 0; i < pdev_count; i++)
289 platform_device_unregister(pdevs[i]);
290
291 kfree(objp: pdevs);
292 kfree(objp: buttons);
293
294 for (i = 0; i < spi_dev_count; i++)
295 spi_unregister_device(spi: spi_devs[i]);
296
297 kfree(objp: spi_devs);
298
299 for (i = 0; i < i2c_client_count; i++)
300 i2c_unregister_device(client: i2c_clients[i]);
301
302 kfree(objp: i2c_clients);
303
304 if (exit_handler)
305 exit_handler();
306
307 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
308 gpiod_remove_lookup_table(table: gpiod_lookup_tables[i]);
309
310 software_node_unregister(node: bat_swnode);
311}
312
313static __init int x86_android_tablet_probe(struct platform_device *pdev)
314{
315 const struct x86_dev_info *dev_info;
316 const struct dmi_system_id *id;
317 int i, ret = 0;
318
319 id = dmi_first_match(list: x86_android_tablet_ids);
320 if (!id)
321 return -ENODEV;
322
323 dev_info = id->driver_data;
324 /* Allow x86_android_tablet_device use before probe() exits */
325 x86_android_tablet_device = pdev;
326
327 /*
328 * Since this runs from module_init() it cannot use -EPROBE_DEFER,
329 * instead pre-load any modules which are listed as requirements.
330 */
331 for (i = 0; dev_info->modules && dev_info->modules[i]; i++)
332 request_module(dev_info->modules[i]);
333
334 bat_swnode = dev_info->bat_swnode;
335 if (bat_swnode) {
336 ret = software_node_register(node: bat_swnode);
337 if (ret)
338 return ret;
339 }
340
341 gpiod_lookup_tables = dev_info->gpiod_lookup_tables;
342 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
343 gpiod_add_lookup_table(table: gpiod_lookup_tables[i]);
344
345 if (dev_info->init) {
346 ret = dev_info->init();
347 if (ret < 0) {
348 x86_android_tablet_remove(pdev);
349 return ret;
350 }
351 exit_handler = dev_info->exit;
352 }
353
354 i2c_clients = kcalloc(n: dev_info->i2c_client_count, size: sizeof(*i2c_clients), GFP_KERNEL);
355 if (!i2c_clients) {
356 x86_android_tablet_remove(pdev);
357 return -ENOMEM;
358 }
359
360 i2c_client_count = dev_info->i2c_client_count;
361 for (i = 0; i < i2c_client_count; i++) {
362 ret = x86_instantiate_i2c_client(dev_info, idx: i);
363 if (ret < 0) {
364 x86_android_tablet_remove(pdev);
365 return ret;
366 }
367 }
368
369 spi_devs = kcalloc(n: dev_info->spi_dev_count, size: sizeof(*spi_devs), GFP_KERNEL);
370 if (!spi_devs) {
371 x86_android_tablet_remove(pdev);
372 return -ENOMEM;
373 }
374
375 spi_dev_count = dev_info->spi_dev_count;
376 for (i = 0; i < spi_dev_count; i++) {
377 ret = x86_instantiate_spi_dev(dev_info, idx: i);
378 if (ret < 0) {
379 x86_android_tablet_remove(pdev);
380 return ret;
381 }
382 }
383
384 /* + 1 to make space for (optional) gpio_keys_button pdev */
385 pdevs = kcalloc(n: dev_info->pdev_count + 1, size: sizeof(*pdevs), GFP_KERNEL);
386 if (!pdevs) {
387 x86_android_tablet_remove(pdev);
388 return -ENOMEM;
389 }
390
391 pdev_count = dev_info->pdev_count;
392 for (i = 0; i < pdev_count; i++) {
393 pdevs[i] = platform_device_register_full(pdevinfo: &dev_info->pdev_info[i]);
394 if (IS_ERR(ptr: pdevs[i])) {
395 x86_android_tablet_remove(pdev);
396 return PTR_ERR(ptr: pdevs[i]);
397 }
398 }
399
400 serdevs = kcalloc(n: dev_info->serdev_count, size: sizeof(*serdevs), GFP_KERNEL);
401 if (!serdevs) {
402 x86_android_tablet_remove(pdev);
403 return -ENOMEM;
404 }
405
406 serdev_count = dev_info->serdev_count;
407 for (i = 0; i < serdev_count; i++) {
408 ret = x86_instantiate_serdev(info: &dev_info->serdev_info[i], idx: i);
409 if (ret < 0) {
410 x86_android_tablet_remove(pdev);
411 return ret;
412 }
413 }
414
415 if (dev_info->gpio_button_count) {
416 struct gpio_keys_platform_data pdata = { };
417 struct gpio_desc *gpiod;
418
419 buttons = kcalloc(n: dev_info->gpio_button_count, size: sizeof(*buttons), GFP_KERNEL);
420 if (!buttons) {
421 x86_android_tablet_remove(pdev);
422 return -ENOMEM;
423 }
424
425 for (i = 0; i < dev_info->gpio_button_count; i++) {
426 ret = x86_android_tablet_get_gpiod(chip: dev_info->gpio_button[i].chip,
427 pin: dev_info->gpio_button[i].pin,
428 con_id: dev_info->gpio_button[i].button.desc,
429 active_low: false, dflags: GPIOD_IN, desc: &gpiod);
430 if (ret < 0) {
431 x86_android_tablet_remove(pdev);
432 return ret;
433 }
434
435 buttons[i] = dev_info->gpio_button[i].button;
436 buttons[i].gpio = desc_to_gpio(desc: gpiod);
437 /* Release gpiod so that gpio-keys can request it */
438 devm_gpiod_put(dev: &x86_android_tablet_device->dev, desc: gpiod);
439 }
440
441 pdata.buttons = buttons;
442 pdata.nbuttons = dev_info->gpio_button_count;
443
444 pdevs[pdev_count] = platform_device_register_data(parent: &pdev->dev, name: "gpio-keys",
445 PLATFORM_DEVID_AUTO,
446 data: &pdata, size: sizeof(pdata));
447 if (IS_ERR(ptr: pdevs[pdev_count])) {
448 x86_android_tablet_remove(pdev);
449 return PTR_ERR(ptr: pdevs[pdev_count]);
450 }
451 pdev_count++;
452 }
453
454 return 0;
455}
456
457static struct platform_driver x86_android_tablet_driver = {
458 .driver = {
459 .name = KBUILD_MODNAME,
460 },
461 .remove_new = x86_android_tablet_remove,
462};
463
464static int __init x86_android_tablet_init(void)
465{
466 x86_android_tablet_device = platform_create_bundle(&x86_android_tablet_driver,
467 x86_android_tablet_probe,
468 NULL, 0, NULL, 0);
469
470 return PTR_ERR_OR_ZERO(ptr: x86_android_tablet_device);
471}
472module_init(x86_android_tablet_init);
473
474static void __exit x86_android_tablet_exit(void)
475{
476 platform_device_unregister(x86_android_tablet_device);
477 platform_driver_unregister(&x86_android_tablet_driver);
478}
479module_exit(x86_android_tablet_exit);
480
481MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
482MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
483MODULE_LICENSE("GPL");
484

source code of linux/drivers/platform/x86/x86-android-tablets/core.c