.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Kontron PLD MFD core driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2010-2013 Kontron Europe GmbH |
---|
5 | 6 | * Author: Michael Brunner <michael.brunner@kontron.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License 2 as published |
---|
9 | | - * by the Free Software Foundation. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | 7 | */ |
---|
16 | 8 | |
---|
17 | 9 | #include <linux/platform_device.h> |
---|
.. | .. |
---|
21 | 13 | #include <linux/dmi.h> |
---|
22 | 14 | #include <linux/io.h> |
---|
23 | 15 | #include <linux/delay.h> |
---|
| 16 | +#include <linux/acpi.h> |
---|
24 | 17 | |
---|
25 | 18 | #define MAX_ID_LEN 4 |
---|
26 | 19 | static char force_device_id[MAX_ID_LEN + 1] = ""; |
---|
.. | .. |
---|
87 | 80 | KEMPLD_UART, |
---|
88 | 81 | }; |
---|
89 | 82 | |
---|
90 | | -static const struct mfd_cell kempld_devs[] = { |
---|
91 | | - [KEMPLD_I2C] = { |
---|
92 | | - .name = "kempld-i2c", |
---|
93 | | - }, |
---|
94 | | - [KEMPLD_WDT] = { |
---|
95 | | - .name = "kempld-wdt", |
---|
96 | | - }, |
---|
97 | | - [KEMPLD_GPIO] = { |
---|
98 | | - .name = "kempld-gpio", |
---|
99 | | - }, |
---|
100 | | - [KEMPLD_UART] = { |
---|
101 | | - .name = "kempld-uart", |
---|
102 | | - }, |
---|
| 83 | +static const char *kempld_dev_names[] = { |
---|
| 84 | + [KEMPLD_I2C] = "kempld-i2c", |
---|
| 85 | + [KEMPLD_WDT] = "kempld-wdt", |
---|
| 86 | + [KEMPLD_GPIO] = "kempld-gpio", |
---|
| 87 | + [KEMPLD_UART] = "kempld-uart", |
---|
103 | 88 | }; |
---|
104 | 89 | |
---|
105 | | -#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs) |
---|
| 90 | +#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names) |
---|
106 | 91 | |
---|
107 | 92 | static int kempld_register_cells_generic(struct kempld_device_data *pld) |
---|
108 | 93 | { |
---|
109 | | - struct mfd_cell devs[KEMPLD_MAX_DEVS]; |
---|
| 94 | + struct mfd_cell devs[KEMPLD_MAX_DEVS] = {}; |
---|
110 | 95 | int i = 0; |
---|
111 | 96 | |
---|
112 | 97 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C) |
---|
113 | | - devs[i++] = kempld_devs[KEMPLD_I2C]; |
---|
| 98 | + devs[i++].name = kempld_dev_names[KEMPLD_I2C]; |
---|
114 | 99 | |
---|
115 | 100 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG) |
---|
116 | | - devs[i++] = kempld_devs[KEMPLD_WDT]; |
---|
| 101 | + devs[i++].name = kempld_dev_names[KEMPLD_WDT]; |
---|
117 | 102 | |
---|
118 | 103 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO) |
---|
119 | | - devs[i++] = kempld_devs[KEMPLD_GPIO]; |
---|
| 104 | + devs[i++].name = kempld_dev_names[KEMPLD_GPIO]; |
---|
120 | 105 | |
---|
121 | 106 | if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART) |
---|
122 | | - devs[i++] = kempld_devs[KEMPLD_UART]; |
---|
| 107 | + devs[i++].name = kempld_dev_names[KEMPLD_UART]; |
---|
123 | 108 | |
---|
124 | 109 | return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL); |
---|
125 | 110 | } |
---|
.. | .. |
---|
140 | 125 | }; |
---|
141 | 126 | |
---|
142 | 127 | static struct platform_device *kempld_pdev; |
---|
| 128 | +static bool kempld_acpi_mode; |
---|
143 | 129 | |
---|
144 | 130 | static int kempld_create_platform_device(const struct dmi_system_id *id) |
---|
145 | 131 | { |
---|
.. | .. |
---|
442 | 428 | return ret; |
---|
443 | 429 | } |
---|
444 | 430 | |
---|
| 431 | +#ifdef CONFIG_ACPI |
---|
| 432 | +static int kempld_get_acpi_data(struct platform_device *pdev) |
---|
| 433 | +{ |
---|
| 434 | + struct list_head resource_list; |
---|
| 435 | + struct resource *resources; |
---|
| 436 | + struct resource_entry *rentry; |
---|
| 437 | + struct device *dev = &pdev->dev; |
---|
| 438 | + struct acpi_device *acpi_dev = ACPI_COMPANION(dev); |
---|
| 439 | + const struct kempld_platform_data *pdata; |
---|
| 440 | + int ret; |
---|
| 441 | + int count; |
---|
| 442 | + |
---|
| 443 | + pdata = acpi_device_get_match_data(dev); |
---|
| 444 | + ret = platform_device_add_data(pdev, pdata, |
---|
| 445 | + sizeof(struct kempld_platform_data)); |
---|
| 446 | + if (ret) |
---|
| 447 | + return ret; |
---|
| 448 | + |
---|
| 449 | + INIT_LIST_HEAD(&resource_list); |
---|
| 450 | + ret = acpi_dev_get_resources(acpi_dev, &resource_list, NULL, NULL); |
---|
| 451 | + if (ret < 0) |
---|
| 452 | + goto out; |
---|
| 453 | + |
---|
| 454 | + count = ret; |
---|
| 455 | + |
---|
| 456 | + if (count == 0) { |
---|
| 457 | + ret = platform_device_add_resources(pdev, pdata->ioresource, 1); |
---|
| 458 | + goto out; |
---|
| 459 | + } |
---|
| 460 | + |
---|
| 461 | + resources = devm_kcalloc(&acpi_dev->dev, count, sizeof(*resources), |
---|
| 462 | + GFP_KERNEL); |
---|
| 463 | + if (!resources) { |
---|
| 464 | + ret = -ENOMEM; |
---|
| 465 | + goto out; |
---|
| 466 | + } |
---|
| 467 | + |
---|
| 468 | + count = 0; |
---|
| 469 | + list_for_each_entry(rentry, &resource_list, node) { |
---|
| 470 | + memcpy(&resources[count], rentry->res, |
---|
| 471 | + sizeof(*resources)); |
---|
| 472 | + count++; |
---|
| 473 | + } |
---|
| 474 | + ret = platform_device_add_resources(pdev, resources, count); |
---|
| 475 | + |
---|
| 476 | +out: |
---|
| 477 | + acpi_dev_free_resource_list(&resource_list); |
---|
| 478 | + |
---|
| 479 | + return ret; |
---|
| 480 | +} |
---|
| 481 | +#else |
---|
| 482 | +static int kempld_get_acpi_data(struct platform_device *pdev) |
---|
| 483 | +{ |
---|
| 484 | + return -ENODEV; |
---|
| 485 | +} |
---|
| 486 | +#endif /* CONFIG_ACPI */ |
---|
| 487 | + |
---|
445 | 488 | static int kempld_probe(struct platform_device *pdev) |
---|
446 | 489 | { |
---|
447 | | - const struct kempld_platform_data *pdata = |
---|
448 | | - dev_get_platdata(&pdev->dev); |
---|
| 490 | + const struct kempld_platform_data *pdata; |
---|
449 | 491 | struct device *dev = &pdev->dev; |
---|
450 | 492 | struct kempld_device_data *pld; |
---|
451 | 493 | struct resource *ioport; |
---|
| 494 | + int ret; |
---|
| 495 | + |
---|
| 496 | + if (kempld_pdev == NULL) { |
---|
| 497 | + /* |
---|
| 498 | + * No kempld_pdev device has been registered in kempld_init, |
---|
| 499 | + * so we seem to be probing an ACPI platform device. |
---|
| 500 | + */ |
---|
| 501 | + ret = kempld_get_acpi_data(pdev); |
---|
| 502 | + if (ret) |
---|
| 503 | + return ret; |
---|
| 504 | + |
---|
| 505 | + kempld_acpi_mode = true; |
---|
| 506 | + } else if (kempld_pdev != pdev) { |
---|
| 507 | + /* |
---|
| 508 | + * The platform device we are probing is not the one we |
---|
| 509 | + * registered in kempld_init using the DMI table, so this one |
---|
| 510 | + * comes from ACPI. |
---|
| 511 | + * As we can only probe one - abort here and use the DMI |
---|
| 512 | + * based one instead. |
---|
| 513 | + */ |
---|
| 514 | + dev_notice(dev, "platform device exists - not using ACPI\n"); |
---|
| 515 | + return -ENODEV; |
---|
| 516 | + } |
---|
| 517 | + pdata = dev_get_platdata(dev); |
---|
452 | 518 | |
---|
453 | 519 | pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL); |
---|
454 | 520 | if (!pld) |
---|
.. | .. |
---|
487 | 553 | return 0; |
---|
488 | 554 | } |
---|
489 | 555 | |
---|
| 556 | +#ifdef CONFIG_ACPI |
---|
| 557 | +static const struct acpi_device_id kempld_acpi_table[] = { |
---|
| 558 | + { "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic }, |
---|
| 559 | + {} |
---|
| 560 | +}; |
---|
| 561 | +MODULE_DEVICE_TABLE(acpi, kempld_acpi_table); |
---|
| 562 | +#endif |
---|
| 563 | + |
---|
490 | 564 | static struct platform_driver kempld_driver = { |
---|
491 | 565 | .driver = { |
---|
492 | 566 | .name = "kempld", |
---|
| 567 | + .acpi_match_table = ACPI_PTR(kempld_acpi_table), |
---|
| 568 | + .probe_type = PROBE_FORCE_SYNCHRONOUS, |
---|
493 | 569 | }, |
---|
494 | 570 | .probe = kempld_probe, |
---|
495 | 571 | .remove = kempld_remove, |
---|
.. | .. |
---|
808 | 884 | static int __init kempld_init(void) |
---|
809 | 885 | { |
---|
810 | 886 | const struct dmi_system_id *id; |
---|
| 887 | + int ret; |
---|
811 | 888 | |
---|
812 | 889 | if (force_device_id[0]) { |
---|
813 | 890 | for (id = kempld_dmi_table; |
---|
.. | .. |
---|
817 | 894 | break; |
---|
818 | 895 | if (id->matches[0].slot == DMI_NONE) |
---|
819 | 896 | return -ENODEV; |
---|
820 | | - } else { |
---|
821 | | - if (!dmi_check_system(kempld_dmi_table)) |
---|
822 | | - return -ENODEV; |
---|
823 | 897 | } |
---|
824 | 898 | |
---|
825 | | - return platform_driver_register(&kempld_driver); |
---|
| 899 | + ret = platform_driver_register(&kempld_driver); |
---|
| 900 | + if (ret) |
---|
| 901 | + return ret; |
---|
| 902 | + |
---|
| 903 | + /* |
---|
| 904 | + * With synchronous probing the device should already be probed now. |
---|
| 905 | + * If no device id is forced and also no ACPI definition for the |
---|
| 906 | + * device was found, scan DMI table as fallback. |
---|
| 907 | + * |
---|
| 908 | + * If drivers_autoprobing is disabled and the device is found here, |
---|
| 909 | + * only that device can be bound manually later. |
---|
| 910 | + */ |
---|
| 911 | + if (!kempld_pdev && !kempld_acpi_mode) |
---|
| 912 | + dmi_check_system(kempld_dmi_table); |
---|
| 913 | + |
---|
| 914 | + return 0; |
---|
826 | 915 | } |
---|
827 | 916 | |
---|
828 | 917 | static void __exit kempld_exit(void) |
---|