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