Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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(lookup);
 61	gpiod = devm_gpiod_get(&x86_android_tablet_device->dev, con_id, dflags);
 62	gpiod_remove_lookup_table(lookup);
 63	kfree(lookup);
 64
 65	if (IS_ERR(gpiod)) {
 66		pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), chip, pin);
 67		return PTR_ERR(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(data->index);
 95		irq = acpi_register_gsi(NULL, data->index, data->trigger, 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(data->chip, data->index, data->con_id,
103						   false, GPIOD_ASIS, &gpiod);
104		if (ret)
105			return ret;
106
107		irq = gpiod_to_irq(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(data->trigger, data->polarity);
114		if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq))
115			irq_set_irq_type(irq, irq_type);
116
117		if (data->free_gpio)
118			devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
119
120		return irq;
121	case X86_ACPI_IRQ_TYPE_PMIC:
122		status = acpi_get_handle(NULL, data->chip, &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, 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(domain, 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(&client_info->irq_data);
170	if (board_info.irq < 0)
171		return board_info.irq;
172
173	status = acpi_get_handle(NULL, client_info->adapter_path, &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, &board_info);
186	put_device(&adap->dev);
187	if (IS_ERR(i2c_clients[idx]))
188		return dev_err_probe(&adap->dev, PTR_ERR(i2c_clients[idx]),
189				      "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(&spi_dev_info->irq_data);
204	if (board_info.irq < 0)
205		return board_info.irq;
206
207	status = acpi_get_handle(NULL, spi_dev_info->ctrl_path, &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(&controller->dev);
227	if (!spi_devs[idx])
228		return dev_err_probe(&controller->dev, -ENOMEM,
229				     "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(info->ctrl_hid, info->ctrl_uid, 0,
242					 info->ctrl_devname);
243	if (IS_ERR(ctrl_dev))
244		return PTR_ERR(ctrl_dev);
245
246	serdev_adev = acpi_dev_get_first_match_dev(info->serdev_hid, NULL, -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(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(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(serdev_adev);
272put_ctrl_dev:
273	put_device(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(serdevs);
287
288	for (i = 0; i < pdev_count; i++)
289		platform_device_unregister(pdevs[i]);
290
291	kfree(pdevs);
292	kfree(buttons);
293
294	for (i = 0; i < spi_dev_count; i++)
295		spi_unregister_device(spi_devs[i]);
296
297	kfree(spi_devs);
298
299	for (i = 0; i < i2c_client_count; i++)
300		i2c_unregister_device(i2c_clients[i]);
301
302	kfree(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(gpiod_lookup_tables[i]);
309
310	software_node_unregister(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(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(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(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(dev_info->i2c_client_count, 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, i);
363		if (ret < 0) {
364			x86_android_tablet_remove(pdev);
365			return ret;
366		}
367	}
368
369	spi_devs = kcalloc(dev_info->spi_dev_count, 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, 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(dev_info->pdev_count + 1, 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(&dev_info->pdev_info[i]);
394		if (IS_ERR(pdevs[i])) {
395			x86_android_tablet_remove(pdev);
396			return PTR_ERR(pdevs[i]);
397		}
398	}
399
400	serdevs = kcalloc(dev_info->serdev_count, 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(&dev_info->serdev_info[i], 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(dev_info->gpio_button_count, 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(dev_info->gpio_button[i].chip,
427							   dev_info->gpio_button[i].pin,
428							   dev_info->gpio_button[i].button.desc,
429							   false, GPIOD_IN, &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(gpiod);
437			/* Release gpiod so that gpio-keys can request it */
438			devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
439		}
440
441		pdata.buttons = buttons;
442		pdata.nbuttons = dev_info->gpio_button_count;
443
444		pdevs[pdev_count] = platform_device_register_data(&pdev->dev, "gpio-keys",
445								  PLATFORM_DEVID_AUTO,
446								  &pdata, sizeof(pdata));
447		if (IS_ERR(pdevs[pdev_count])) {
448			x86_android_tablet_remove(pdev);
449			return PTR_ERR(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(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");