diff --git a/MAINTAINERS b/MAINTAINERS index 7cebd5bba8a8..a7cf519991ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -367,6 +367,12 @@ L: linux-acpi@vger.kernel.org S: Maintained F: drivers/acpi/arm64 +ACPI I2C MULTI INSTANTIATE DRIVER +M: Hans de Goede +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/i2c-multi-instantiate.c + ACPI PMIC DRIVERS M: "Rafael J. Wysocki" M: Len Brown diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index b8eecc7b9531..9ffe01d7042a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -727,12 +727,7 @@ static const struct fault_info fault_info[] = { int handle_guest_sea(phys_addr_t addr, unsigned int esr) { - int ret = -ENOENT; - - if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) - ret = ghes_notify_sea(); - - return ret; + return ghes_notify_sea(); } asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 84b4a62018eb..292088fcc624 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -66,37 +66,10 @@ static int set_copy_dsdt(const struct dmi_system_id *id) return 0; } #endif -static int set_gbl_term_list(const struct dmi_system_id *id) -{ - acpi_gbl_execute_tables_as_methods = 1; - return 0; -} -static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { - /* - * Touchpad on Dell XPS 9570/Precision M5530 doesn't work under I2C - * mode. - * https://bugzilla.kernel.org/show_bug.cgi?id=198515 - */ - { - .callback = set_gbl_term_list, - .ident = "Dell Precision M5530", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Precision M5530"), - }, - }, - { - .callback = set_gbl_term_list, - .ident = "Dell XPS 15 9570", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9570"), - }, - }, +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { /* * Invoke DSDT corruption work-around on all Toshiba Satellite. - * DSDT will be copied to memory. * https://bugzilla.kernel.org/show_bug.cgi?id=14679 */ { @@ -110,7 +83,7 @@ static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { {} }; #else -static const struct dmi_system_id acpi_quirks_dmi_table[] __initconst = { +static const struct dmi_system_id dsdt_dmi_table[] __initconst = { {} }; #endif @@ -962,7 +935,7 @@ static int acpi_device_probe(struct device *dev) return 0; } -static int acpi_device_remove(struct device * dev) +static int acpi_device_remove(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; @@ -1060,8 +1033,11 @@ void __init acpi_early_init(void) acpi_permanent_mmap = true; - /* Check machine-specific quirks */ - dmi_check_system(acpi_quirks_dmi_table); + /* + * If the machine falls into the DMI check table, + * DSDT will be copied to memory + */ + dmi_check_system(dsdt_dmi_table); status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 917f77f4cb55..d4e5610e09c5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -2045,6 +2045,20 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"), }, }, + { + .ident = "ThinkPad X1 Carbon 6th", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"), + }, + }, + { + .ident = "ThinkPad X1 Yoga 3rd", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"), + }, + }, { }, }; diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index ec5b0f190231..06c31ec3cc70 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -62,14 +62,20 @@ static const struct always_present_id always_present_ids[] = { */ ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}), /* - * On the Dell Venue 11 Pro 7130 the DSDT hides the touchscreen ACPI - * device until a certain time after _SB.PCI0.GFX0.LCD.LCD1._ON gets - * called has passed *and* _STA has been called at least 3 times since. + * On the Dell Venue 11 Pro 7130 and 7139, the DSDT hides + * the touchscreen ACPI device until a certain time + * after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed + * *and* _STA has been called at least 3 times since. */ ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"), }), + ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_ULT), { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"), + }), + /* * The GPD win BIOS dated 20170221 has disabled the accelerometer, the * drivers sometimes cause crashes under Windows and this is how the @@ -103,13 +109,9 @@ static const struct always_present_id always_present_ids[] = { bool acpi_device_always_present(struct acpi_device *adev) { - u32 *status = (u32 *)&adev->status; - u32 old_status = *status; bool ret = false; unsigned int i; - /* acpi_match_device_ids checks status, so set it to default */ - *status = ACPI_STA_DEFAULT; for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) { if (acpi_match_device_ids(adev, always_present_ids[i].hid)) continue; @@ -125,15 +127,9 @@ bool acpi_device_always_present(struct acpi_device *adev) !dmi_check_system(always_present_ids[i].dmi_ids)) continue; - if (old_status != ACPI_STA_DEFAULT) /* Log only once */ - dev_info(&adev->dev, - "Device [%s] is in always present list\n", - adev->pnp.bus_id); - ret = true; break; } - *status = old_status; return ret; } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index ac4d48830415..107d336453b2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1218,6 +1218,17 @@ config INTEL_CHTDC_TI_PWRBTN To compile this driver as a module, choose M here: the module will be called intel_chtdc_ti_pwrbtn. +config I2C_MULTI_INSTANTIATE + tristate "I2C multi instantiate pseudo device driver" + depends on I2C && ACPI + help + Some ACPI-based systems list multiple i2c-devices in a single ACPI + firmware-node. This driver will instantiate separate i2c-clients + for each device in the firmware-node. + + To compile this driver as a module, choose M here: the module + will be called i2c-multi-instantiate. + endif # X86_PLATFORM_DEVICES config PMC_ATOM diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..50dc8f280914 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_PMC_ATOM) += pmc_atom.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o +obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o diff --git a/drivers/platform/x86/i2c-multi-instantiate.c b/drivers/platform/x86/i2c-multi-instantiate.c new file mode 100644 index 000000000000..5456581b473c --- /dev/null +++ b/drivers/platform/x86/i2c-multi-instantiate.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * I2C multi-instantiate driver, pseudo driver to instantiate multiple + * i2c-clients from a single fwnode. + * + * Copyright 2018 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include + +struct i2c_inst_data { + const char *type; + int gpio_irq_idx; +}; + +struct i2c_multi_inst_data { + int num_clients; + struct i2c_client *clients[0]; +}; + +static int i2c_multi_inst_probe(struct platform_device *pdev) +{ + struct i2c_multi_inst_data *multi; + const struct acpi_device_id *match; + const struct i2c_inst_data *inst_data; + struct i2c_board_info board_info = {}; + struct device *dev = &pdev->dev; + struct acpi_device *adev; + char name[32]; + int i, ret; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) { + dev_err(dev, "Error ACPI match data is missing\n"); + return -ENODEV; + } + inst_data = (const struct i2c_inst_data *)match->driver_data; + + adev = ACPI_COMPANION(dev); + + /* Count number of clients to instantiate */ + for (i = 0; inst_data[i].type; i++) {} + + multi = devm_kmalloc(dev, + offsetof(struct i2c_multi_inst_data, clients[i]), + GFP_KERNEL); + if (!multi) + return -ENOMEM; + + multi->num_clients = i; + + for (i = 0; i < multi->num_clients; i++) { + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, inst_data[i].type, I2C_NAME_SIZE); + snprintf(name, sizeof(name), "%s-%s", match->id, + inst_data[i].type); + board_info.dev_name = name; + board_info.irq = 0; + if (inst_data[i].gpio_irq_idx != -1) { + ret = acpi_dev_gpio_irq_get(adev, + inst_data[i].gpio_irq_idx); + if (ret < 0) { + dev_err(dev, "Error requesting irq at index %d: %d\n", + inst_data[i].gpio_irq_idx, ret); + goto error; + } + board_info.irq = ret; + } + multi->clients[i] = i2c_acpi_new_device(dev, i, &board_info); + if (!multi->clients[i]) { + dev_err(dev, "Error creating i2c-client, idx %d\n", i); + ret = -ENODEV; + goto error; + } + } + + platform_set_drvdata(pdev, multi); + return 0; + +error: + while (--i >= 0) + i2c_unregister_device(multi->clients[i]); + + return ret; +} + +static int i2c_multi_inst_remove(struct platform_device *pdev) +{ + struct i2c_multi_inst_data *multi = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < multi->num_clients; i++) + i2c_unregister_device(multi->clients[i]); + + return 0; +} + +static const struct i2c_inst_data bsg1160_data[] = { + { "bmc150_accel", 0 }, + { "bmc150_magn", -1 }, + { "bmg160", -1 }, + {} +}; + +/* + * Note new device-ids must also be added to i2c_multi_instantiate_ids in + * drivers/acpi/scan.c: acpi_device_enumeration_by_parent(). + */ +static const struct acpi_device_id i2c_multi_inst_acpi_ids[] = { + { "BSG1160", (unsigned long)bsg1160_data }, + { } +}; +MODULE_DEVICE_TABLE(acpi, i2c_multi_inst_acpi_ids); + +static struct platform_driver i2c_multi_inst_driver = { + .driver = { + .name = "I2C multi instantiate pseudo device driver", + .acpi_match_table = ACPI_PTR(i2c_multi_inst_acpi_ids), + }, + .probe = i2c_multi_inst_probe, + .remove = i2c_multi_inst_remove, +}; +module_platform_driver(i2c_multi_inst_driver); + +MODULE_DESCRIPTION("I2C multi instantiate pseudo device driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 1624e2be485c..82cb4eb225a4 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h @@ -118,6 +118,10 @@ static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata) (void *)section - (void *)(estatus + 1) < estatus->data_length; \ section = acpi_hest_get_next(section)) +#ifdef CONFIG_ACPI_APEI_SEA int ghes_notify_sea(void); +#else +static inline int ghes_notify_sea(void) { return -ENOENT; } +#endif #endif /* GHES_H */