From 7c058c7c74b3dbeb7d157c273959f87faf710350 Mon Sep 17 00:00:00 2001 From: Ravi Chandra Sadineni Date: Wed, 27 Jun 2018 10:55:02 -0700 Subject: ACPI / button: increment wakeup count only when notified Because acpi_lid_initialize_state() is called on every system resume and it triggers acpi_lid_notify_state() which invokes acpi_pm_wakeup_event() for the lid device, the lid's wakeup count is incremented even if the lid was not the source of the event that woke up the system. That behavior confuses user space deamons using wakeup_count to identify the potential system wakeup source. To avoid the confusion, only trigger acpi_pm_wakeup_event() in the acpi_button_notify() path and don't do that in the acpi_lid_initialize_state() path. Signed-off-by: Ravi Chandra Sadineni Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 2345a5ee2dbb..40ed3ec9fc94 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -235,9 +235,6 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) button->last_time = ktime_get(); } - if (state) - acpi_pm_wakeup_event(&device->dev); - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); if (ret == NOTIFY_DONE) ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, @@ -366,7 +363,8 @@ int acpi_lid_open(void) } EXPORT_SYMBOL(acpi_lid_open); -static int acpi_lid_update_state(struct acpi_device *device) +static int acpi_lid_update_state(struct acpi_device *device, + bool signal_wakeup) { int state; @@ -374,6 +372,9 @@ static int acpi_lid_update_state(struct acpi_device *device) if (state < 0) return state; + if (state && signal_wakeup) + acpi_pm_wakeup_event(&device->dev); + return acpi_lid_notify_state(device, state); } @@ -384,7 +385,7 @@ static void acpi_lid_initialize_state(struct acpi_device *device) (void)acpi_lid_notify_state(device, 1); break; case ACPI_BUTTON_LID_INIT_METHOD: - (void)acpi_lid_update_state(device); + (void)acpi_lid_update_state(device, false); break; case ACPI_BUTTON_LID_INIT_IGNORE: default: @@ -409,7 +410,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) users = button->input->users; mutex_unlock(&button->input->mutex); if (users) - acpi_lid_update_state(device); + acpi_lid_update_state(device, true); } else { int keycode; -- cgit From 72a361a5b91c77b33ab2533674fdcec4de3278d0 Mon Sep 17 00:00:00 2001 From: Tristian Celestin Date: Sat, 9 Jun 2018 18:18:06 -0400 Subject: ACPI / x86: enable touchscreen on Dell Venue Pro 7139 Permanently enable the SYNA7500 touchscreen device on the Dell Venue Pro 7139. The DSDT hides the touchscreen ACPI device on the 7139 in the same fashion as the 7130, and needs to be enabled in the same way. Signed-off-by: Tristian Celestin Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/utils.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index ec5b0f190231..3a13b2af2bf8 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 -- cgit From da7f7126f04c37cf0b33a75b7a5dd3c1b2adfa2b Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Fri, 29 Jun 2018 11:28:11 -0700 Subject: ACPICA: Revert "iASL: change processing of external op namespace nodes for correctness" Revert commit b43eac6f3384 (ACPICA: iASL: change processing of external op namespace nodes for correctness; upstream ACPICA commit aa866a9b4f24bbec9f158d10325b486d7d12d90f). This was done in order to allow more relaxed usage of ASL external declarations. Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsaccess.c | 13 ++++++------- drivers/acpi/acpica/nssearch.c | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 220a718fbce9..3c571fe98990 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -608,18 +608,17 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node->object; } } +#ifdef ACPI_ASL_COMPILER + if (!acpi_gbl_disasm_flag && + (this_node->flags & ANOBJ_IS_EXTERNAL)) { + this_node->flags |= IMPLICIT_EXTERNAL; + } +#endif } /* Special handling for the last segment (num_segments == 0) */ else { -#ifdef ACPI_ASL_COMPILER - if (!acpi_gbl_disasm_flag - && (this_node->flags & ANOBJ_IS_EXTERNAL)) { - this_node->flags &= ~IMPLICIT_EXTERNAL; - } -#endif - /* * Sanity typecheck of the target object: * diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index e9c9a63bb6a4..f594ab75a5fe 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -381,7 +381,6 @@ acpi_ns_search_and_enter(u32 target_name, if (flags & ACPI_NS_EXTERNAL || (walk_state && walk_state->opcode == AML_SCOPE_OP)) { new_node->flags |= ANOBJ_IS_EXTERNAL; - new_node->flags |= IMPLICIT_EXTERNAL; } #endif -- cgit From a9efdcffd54dc1098a089c3c833eef8d7bee4d77 Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Fri, 29 Jun 2018 11:28:12 -0700 Subject: ACPICA: Revert "iASL compiler: allow compilation of externals with paths that refer to existing names" Revert commit 3ddd3f6a9410 (ACPICA: iASL compiler: allow compilation of externals with paths that refer to existing names; upstream ACPICA commit 9a252114197409290813bee570e9d53c22b99d32). This was done in order to allow more relaxed usage of ASL external declarations. Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 1 - drivers/acpi/acpica/nsaccess.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 51c386bf230d..c5367bf5487f 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -165,7 +165,6 @@ struct acpi_namespace_node { #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ -#define IMPLICIT_EXTERNAL 0x02 /* iASL only: This object created implicitly via External */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ #define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 3c571fe98990..83a593e2155d 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -608,12 +608,6 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node->object; } } -#ifdef ACPI_ASL_COMPILER - if (!acpi_gbl_disasm_flag && - (this_node->flags & ANOBJ_IS_EXTERNAL)) { - this_node->flags |= IMPLICIT_EXTERNAL; - } -#endif } /* Special handling for the last segment (num_segments == 0) */ -- cgit From e74770fb6823c6fde49c3f2b38e3a2e68ae46682 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 29 Jun 2018 11:28:13 -0700 Subject: ACPICA: Update version to 20180629 Version 20180629. Signed-off-by: Bob Moore Signed-off-by: Erik Schmauss Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 48d84f0d9547..88072c92ace2 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -12,7 +12,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20180531 +#define ACPI_CA_VERSION 0x20180629 #include #include -- cgit From 2c4c2a71bd6f75c3982ac09407889b110673ac83 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 7 Jul 2018 08:25:01 -0700 Subject: ACPI / button: fix defined but not used warning Fix a build warning in the ACPI button driver when CONFIG_PROC_FS is not enabled by marking the unused function as __maybe_unused. ../drivers/acpi/button.c:252:12: warning: 'acpi_button_state_seq_show' defined but not used [-Wunused-function] Signed-off-by: Randy Dunlap Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 40ed3ec9fc94..a19ff3977ac4 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -21,6 +21,7 @@ #define pr_fmt(fmt) "ACPI: button: " fmt +#include #include #include #include @@ -249,7 +250,8 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) return ret; } -static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) +static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, + void *offset) { struct acpi_device *device = seq->private; int state; -- cgit From ae976358cd7b0272ccfbd2517edaf0d46f2a356b Mon Sep 17 00:00:00 2001 From: Kai Heng Feng Date: Thu, 19 Jul 2018 19:00:30 +0800 Subject: Revert "ACPI / bus: Parse tables as term_list for Dell XPS 9570 and Precision M5530" Reverts commit 36904703aeee (ACPI / bus: Parse tables as term_list for Dell XPS 9570 and Precision M5530). Since commit 5a8361f7ecce (ACPICA: Integrate package handling with module-level code), acpi_gbl_execute_tables_as_methods is always true, so we can remove the quirk for XPS 9570/Precision M5530. Signed-off-by: Kai-Heng Feng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 84b4a62018eb..f61f8927d843 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 @@ -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)) { -- cgit From 887532ca7ca59fcf0547a79211756791128030a3 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 18 Jul 2018 11:46:55 -0700 Subject: ACPI / OSI: Add OEM _OSI string to enable NVidia HDMI audio Some ThinkPad systems have a power-saving feature that turns off HDMI audio device in Windows, but NVidia Linux driver does not support this feature. As a result, HDMI audio will not work on Linux. A BIOS workaround is added with an OEM_OSI string "Linux-Lenovo-NV-HDMI-Audio" to power on NVidia HDMI audio when booting. The form of the OEM _OSI strings is defined by each OEMs and is discussed in Documentation/acpi/osi.txt. Signed-off-by: Alex Hung Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index 8a8f43568510..b2a16ed7e81a 100644 --- a/drivers/acpi/osi.c +++ b/drivers/acpi/osi.c @@ -66,6 +66,14 @@ osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { * be removed if both new and old graphics cards are supported. */ {"Linux-Dell-Video", true}, + /* + * Linux-Lenovo-NV-HDMI-Audio is used by BIOS to power on NVidia's HDMI + * audio device which is turned off for power-saving in Windows OS. + * This power management feature observed on some Lenovo Thinkpad + * systems which will not be able to output audio via HDMI without + * a BIOS workaround. + */ + {"Linux-Lenovo-NV-HDMI-Audio", true}, }; static u32 acpi_osi_handler(acpi_string interface, u32 supported) -- cgit From 977d5ad39f3ea12ac0bd51d75020cea5ecdca235 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:11 +0300 Subject: ACPI: Convert ACPI reference args to generic fwnode reference args Convert all users of struct acpi_reference_args to more generic fwnode_reference_args. This will 1) avoid an ACPI specific references to device nodes with integer arguments as well as 2) allow making references to nodes other than device nodes in ACPI. As a by-product, convert the fwnode interger arguments to u64. The arguments were 64-bit integers on ACPI but the fwnode arguments were just 32-bit. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 36 ++++++++--------------- drivers/gpio/gpiolib-acpi.c | 11 ++++--- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 10 +++---- drivers/media/v4l2-core/v4l2-fwnode.c | 2 +- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 6 ++-- drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 6 ++-- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 8 +++-- include/linux/acpi.h | 17 ++++------- include/linux/fwnode.h | 2 +- 9 files changed, 43 insertions(+), 55 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 5815356ea6ad..3fa40010fd67 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -579,7 +579,7 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data, */ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const char *propname, size_t index, size_t num_args, - struct acpi_reference_args *args) + struct fwnode_reference_args *args) { const union acpi_object *element, *end; const union acpi_object *obj; @@ -607,7 +607,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (ret) return ret == -ENODEV ? -EINVAL : ret; - args->adev = device; + args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; return 0; } @@ -653,11 +653,11 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, return -EINVAL; } - if (nargs > MAX_ACPI_REFERENCE_ARGS) + if (nargs > NR_FWNODE_REFERENCE_ARGS) return -EINVAL; if (idx == index) { - args->adev = device; + args->fwnode = acpi_fwnode_handle(device); args->nargs = nargs; for (i = 0; i < nargs; i++) args->args[i] = element[i].integer.value; @@ -1089,7 +1089,7 @@ int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode, { struct fwnode_handle *fwnode; unsigned int port_nr, endpoint_nr; - struct acpi_reference_args args; + struct fwnode_reference_args args; int ret; memset(&args, 0, sizeof(args)); @@ -1098,6 +1098,10 @@ int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode, if (ret) return ret; + /* Ensure this is a device node. */ + if (!is_acpi_device_node(args.fwnode)) + return -ENODEV; + /* * Always require two arguments with the reference: port and * endpoint indices. @@ -1105,7 +1109,7 @@ int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode, if (args.nargs != 2) return -EPROTO; - fwnode = acpi_fwnode_handle(args.adev); + fwnode = args.fwnode; port_nr = args.args[0]; endpoint_nr = args.args[1]; @@ -1209,24 +1213,8 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, unsigned int args_count, unsigned int index, struct fwnode_reference_args *args) { - struct acpi_reference_args acpi_args; - unsigned int i; - int ret; - - ret = __acpi_node_get_property_reference(fwnode, prop, index, - args_count, &acpi_args); - if (ret < 0) - return ret; - if (!args) - return 0; - - args->nargs = acpi_args.nargs; - args->fwnode = acpi_fwnode_handle(acpi_args.adev); - - for (i = 0; i < NR_FWNODE_REFERENCE_ARGS; i++) - args->args[i] = i < acpi_args.nargs ? acpi_args.args[i] : 0; - - return 0; + return __acpi_node_get_property_reference(fwnode, prop, index, + args_count, args); } static struct fwnode_handle * diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index e2232cbcec8b..4e8fdae1cde4 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -353,7 +353,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, - struct acpi_reference_args *args, + struct fwnode_reference_args *args, unsigned int *quirks) { const struct acpi_gpio_mapping *gm; @@ -365,7 +365,7 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev, if (!strcmp(name, gm->name) && gm->data && index < gm->size) { const struct acpi_gpio_params *par = gm->data + index; - args->adev = adev; + args->fwnode = acpi_fwnode_handle(adev); args->args[0] = par->crs_entry_index; args->args[1] = par->line_index; args->args[2] = par->active_low; @@ -528,7 +528,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, const char *propname, int index, struct acpi_gpio_lookup *lookup) { - struct acpi_reference_args args; + struct fwnode_reference_args args; unsigned int quirks = 0; int ret; @@ -549,6 +549,8 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, * The property was found and resolved, so need to lookup the GPIO based * on returned args. */ + if (!to_acpi_device_node(args.fwnode)) + return -EINVAL; if (args.nargs != 3) return -EPROTO; @@ -556,8 +558,9 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode, lookup->pin_index = args.args[1]; lookup->active_low = !!args.args[2]; - lookup->info.adev = args.adev; + lookup->info.adev = to_acpi_device_node(args.fwnode); lookup->info.quirks = quirks; + return 0; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 8013d69c5ac4..8444234ed092 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1435,7 +1435,7 @@ static int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset) } fwnode = &dsaf_node->fwnode; } else if (is_acpi_device_node(dev->fwnode)) { - struct acpi_reference_args args; + struct fwnode_reference_args args; ret = acpi_node_get_property_reference(dev->fwnode, "dsaf-handle", 0, &args); @@ -1443,7 +1443,7 @@ static int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset) dev_err(dev, "could not find dsaf-handle\n"); return ret; } - fwnode = acpi_fwnode_handle(args.adev); + fwnode = args.fwnode; } else { dev_err(dev, "cannot read data from DT or ACPI\n"); return -ENXIO; @@ -4835,16 +4835,14 @@ static int hns_roce_get_cfg(struct hns_roce_dev *hr_dev) continue; pdev = of_find_device_by_node(net_node); } else if (is_acpi_device_node(dev->fwnode)) { - struct acpi_reference_args args; - struct fwnode_handle *fwnode; + struct fwnode_reference_args args; ret = acpi_node_get_property_reference(dev->fwnode, "eth-handle", i, &args); if (ret) continue; - fwnode = acpi_fwnode_handle(args.adev); - pdev = hns_roce_find_pdev(fwnode); + pdev = hns_roce_find_pdev(args.fwnode); } else { dev_err(dev, "cannot read data from DT or ACPI\n"); return -ENXIO; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 3f77aa318035..82595cebc0b8 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -739,7 +739,7 @@ static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop( const char * const *props, unsigned int nprops) { struct fwnode_reference_args fwnode_args; - unsigned int *args = fwnode_args.args; + u64 *args = fwnode_args.args; struct fwnode_handle *child; int ret; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 3188f553da35..078a04dc1182 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -836,19 +836,19 @@ static void xgene_enet_adjust_link(struct net_device *ndev) #ifdef CONFIG_ACPI static struct acpi_device *acpi_phy_find_device(struct device *dev) { - struct acpi_reference_args args; + struct fwnode_reference_args args; struct fwnode_handle *fw_node; int status; fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev)); status = acpi_node_get_property_reference(fw_node, "phy-handle", 0, &args); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status) || !is_acpi_device_node(args.fwnode)) { dev_dbg(dev, "No matching phy in ACPI table\n"); return NULL; } - return args.adev; + return to_acpi_device_node(args.fwnode); } #endif diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 9dcc5765f11f..794516718d9d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -708,7 +708,7 @@ hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb, static int hns_mac_register_phy(struct hns_mac_cb *mac_cb) { - struct acpi_reference_args args; + struct fwnode_reference_args args; struct platform_device *pdev; struct mii_bus *mii_bus; int rc; @@ -722,13 +722,15 @@ static int hns_mac_register_phy(struct hns_mac_cb *mac_cb) mac_cb->fw_port, "mdio-node", 0, &args); if (rc) return rc; + if (!is_acpi_device_node(args.fwnode)) + return -EINVAL; addr = hns_mac_phy_parse_addr(mac_cb->dev, mac_cb->fw_port); if (addr < 0) return addr; /* dev address in adev */ - pdev = hns_dsaf_find_platform_device(acpi_fwnode_handle(args.adev)); + pdev = hns_dsaf_find_platform_device(args.fwnode); if (!pdev) { dev_err(mac_cb->dev, "mac%d mdio pdev is NULL\n", mac_cb->mac_id); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index ef9ef703d13a..5608f807d7ba 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2377,7 +2377,7 @@ static int hns_nic_dev_probe(struct platform_device *pdev) } priv->fwnode = &ae_node->fwnode; } else if (is_acpi_node(dev->fwnode)) { - struct acpi_reference_args args; + struct fwnode_reference_args args; if (acpi_dev_found(hns_enet_acpi_match[0].id)) priv->enet_ver = AE_VERSION_1; @@ -2393,7 +2393,11 @@ static int hns_nic_dev_probe(struct platform_device *pdev) dev_err(dev, "not find ae-handle\n"); goto out_read_prop_fail; } - priv->fwnode = acpi_fwnode_handle(args.adev); + if (!is_acpi_device_node(args.fwnode)) { + ret = -EINVAL; + goto out_read_prop_fail; + } + priv->fwnode = args.fwnode; } else { dev_err(dev, "cannot read cfg data from OF or acpi\n"); return -ENXIO; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index e54f40974eb0..11cf39719fd8 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1058,27 +1058,20 @@ static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) /* Device properties */ -#define MAX_ACPI_REFERENCE_ARGS 8 -struct acpi_reference_args { - struct acpi_device *adev; - size_t nargs; - u64 args[MAX_ACPI_REFERENCE_ARGS]; -}; - #ifdef CONFIG_ACPI int acpi_dev_get_property(const struct acpi_device *adev, const char *name, acpi_object_type type, const union acpi_object **obj); int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const char *name, size_t index, size_t num_args, - struct acpi_reference_args *args); + struct fwnode_reference_args *args); static inline int acpi_node_get_property_reference( const struct fwnode_handle *fwnode, const char *name, size_t index, - struct acpi_reference_args *args) + struct fwnode_reference_args *args) { return __acpi_node_get_property_reference(fwnode, name, index, - MAX_ACPI_REFERENCE_ARGS, args); + NR_FWNODE_REFERENCE_ARGS, args); } int acpi_node_prop_get(const struct fwnode_handle *fwnode, const char *propname, @@ -1169,7 +1162,7 @@ static inline int acpi_dev_get_property(struct acpi_device *adev, static inline int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const char *name, size_t index, size_t num_args, - struct acpi_reference_args *args) + struct fwnode_reference_args *args) { return -ENXIO; } @@ -1177,7 +1170,7 @@ __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, static inline int acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const char *name, size_t index, - struct acpi_reference_args *args) + struct fwnode_reference_args *args) { return -ENXIO; } diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 4fe8f289b3f6..faebf0ca0686 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -45,7 +45,7 @@ struct fwnode_endpoint { struct fwnode_reference_args { struct fwnode_handle *fwnode; unsigned int nargs; - unsigned int args[NR_FWNODE_REFERENCE_ARGS]; + u64 args[NR_FWNODE_REFERENCE_ARGS]; }; /** -- cgit From 4eb0c3bf5ee52ffc88500763d80ba01393879794 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:12 +0300 Subject: ACPI: property: Allow making references to non-device nodes Implement references to non-device nodes using the first package entry in the hierarchical data extension reference, the second one being the name of the referred object. The data node references are parsed just after the device arguments before the integer arguments. If there are no strings after the device arguments, the parsing works exactly as it used to be. Referring to a data node called "node" under device DEV, with integer arguments 0, 2 would thus look like: Package() { DEV, "node", 0, 2 } Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 3fa40010fd67..5878d3678b38 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -542,6 +542,23 @@ static int acpi_data_get_property_array(const struct acpi_device_data *data, return 0; } +static struct fwnode_handle * +acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, + const char *childname) +{ + struct fwnode_handle *child; + + /* + * Find first matching named child node of this fwnode. + * For ACPI this will be a data only sub-node. + */ + fwnode_for_each_child_node(fwnode, child) + if (acpi_data_node_match(child, childname)) + return child; + + return NULL; +} + /** * __acpi_node_get_property_reference - returns handle to the referenced object * @fwnode: Firmware node to get the property from @@ -633,6 +650,8 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, u32 nargs, i; if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { + struct fwnode_handle *ref_fwnode; + ret = acpi_bus_get_device(element->reference.handle, &device); if (ret) @@ -641,6 +660,19 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, nargs = 0; element++; + /* + * Find the referred data extension node under the + * referred device node. + */ + for (ref_fwnode = acpi_fwnode_handle(device); + element < end && element->type == ACPI_TYPE_STRING; + element++) { + ref_fwnode = acpi_fwnode_get_named_child_node( + ref_fwnode, element->string.pointer); + if (!ref_fwnode) + return -EINVAL; + } + /* assume following integer elements are all args */ for (i = 0; element + i < end && i < num_args; i++) { int type = element[i].type; @@ -657,7 +689,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, return -EINVAL; if (idx == index) { - args->fwnode = acpi_fwnode_handle(device); + args->fwnode = ref_fwnode; args->nargs = nargs; for (i = 0; i < nargs; i++) args->args[i] = element[i].integer.value; @@ -1190,23 +1222,6 @@ acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, val, nval); } -static struct fwnode_handle * -acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, - const char *childname) -{ - struct fwnode_handle *child; - - /* - * Find first matching named child node of this fwnode. - * For ACPI this will be a data only sub-node. - */ - fwnode_for_each_child_node(fwnode, child) - if (acpi_data_node_match(child, childname)) - return child; - - return NULL; -} - static int acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, const char *prop, const char *nargs_prop, -- cgit From b10134a3643dced57976f9346764144203cfb302 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:13 +0300 Subject: ACPI: property: Document hierarchical data extension references Add documentation on how to refer to hierarchical data nodes in a generic way. This brings ACPI to feature parity with Device Tree in terms of being able to refer to any node in the tree. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/data-node-references.txt | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Documentation/acpi/dsd/data-node-references.txt diff --git a/Documentation/acpi/dsd/data-node-references.txt b/Documentation/acpi/dsd/data-node-references.txt new file mode 100644 index 000000000000..00c3b5fe1f2e --- /dev/null +++ b/Documentation/acpi/dsd/data-node-references.txt @@ -0,0 +1,69 @@ +Copyright (C) 2018 Intel Corporation +Author: Sakari Ailus + + +Referencing hierarchical data nodes +----------------------------------- + +ACPI in general allows referring to device objects in the tree only. +Hierarchical data extension nodes may not be referred to directly, hence this +document defines a scheme to implement such references. + +A reference consist of the device object name followed by one or more +hierarchical data extension [1] keys. Specifically, the hierarchical data +extension node which is referred to by the key shall lie directly under the +parent object i.e. either the device object or another hierarchical data +extension node. + +Example +------- + + In the ASL snippet below, the "reference" _DSD property [2] contains a + device object reference to DEV0 and under that device object, a + hierarchical data extension key "node" referring to the NODE object and + lastly, a hierarchical data extension key "anothernode" referring to the + ANOD object which is also the final target of the reference. + + Device (DEV0) + { + Name (_DSD, Package () { + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + Package () { + Package () { "node", NODE }, + } + }) + Name (NODE, Package() { + ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + Package () { + Package () { "anothernode", ANOD }, + } + }) + Name (ANOD, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "random-property", 0 }, + } + }) + } + + Device (DEV1) + { + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "reference", ^DEV0, "node", "anothernode" }, + } + }) + } + + +References +---------- + +[1] Hierarchical Data Extension UUID For _DSD. + , + referenced 2018-07-17. + +[2] Device Properties UUID For _DSD. + , + referenced 2016-10-04. -- cgit From 0ef7478639c5165a672f01b4024aacfffa951813 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:14 +0300 Subject: ACPI: property: Make the ACPI graph API private The fwnode graph API is preferred over the ACPI graph API. Therefore make the ACPI graph API private, and use it as a back-end for the fwnode graph API only. Unused functionality is removed while the functionality actually used remains the same. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 83 ++++++++++--------------------------------------- include/linux/acpi.h | 8 ----- 2 files changed, 16 insertions(+), 75 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 5878d3678b38..19bdada64435 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1033,10 +1033,10 @@ struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode) * @prev: Previous endpoint node or %NULL to get the first * * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns - * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case - * of success the next endpoint is returned. + * %NULL if there is no next endpoint or in case of error. In case of success + * the next endpoint is returned. */ -struct fwnode_handle *acpi_graph_get_next_endpoint( +static struct fwnode_handle *acpi_graph_get_next_endpoint( const struct fwnode_handle *fwnode, struct fwnode_handle *prev) { struct fwnode_handle *port = NULL; @@ -1065,11 +1065,9 @@ struct fwnode_handle *acpi_graph_get_next_endpoint( endpoint = fwnode_get_next_child_node(port, NULL); } - if (endpoint) { - /* Endpoints must have "endpoint" property */ - if (!fwnode_property_present(endpoint, "endpoint")) - return ERR_PTR(-EPROTO); - } + /* Endpoints must have "endpoint" property */ + if (!fwnode_property_present(endpoint, "endpoint")) + return NULL; return endpoint; } @@ -1106,18 +1104,12 @@ static struct fwnode_handle *acpi_graph_get_child_prop_value( /** * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint * @fwnode: Endpoint firmware node pointing to a remote device - * @parent: Firmware node of remote port parent is filled here if not %NULL - * @port: Firmware node of remote port is filled here if not %NULL * @endpoint: Firmware node of remote endpoint is filled here if not %NULL * - * Function parses remote end of ACPI firmware remote endpoint and fills in - * fields requested by the caller. Returns %0 in case of success and - * negative errno otherwise. + * Returns the remote endpoint corresponding to @__fwnode. NULL on error. */ -int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode, - struct fwnode_handle **parent, - struct fwnode_handle **port, - struct fwnode_handle **endpoint) +static struct fwnode_handle * +acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode) { struct fwnode_handle *fwnode; unsigned int port_nr, endpoint_nr; @@ -1128,47 +1120,27 @@ int acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode, ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0, &args); if (ret) - return ret; + return NULL; /* Ensure this is a device node. */ if (!is_acpi_device_node(args.fwnode)) - return -ENODEV; + return NULL; /* * Always require two arguments with the reference: port and * endpoint indices. */ if (args.nargs != 2) - return -EPROTO; + return NULL; fwnode = args.fwnode; port_nr = args.args[0]; endpoint_nr = args.args[1]; - if (parent) - *parent = fwnode; - - if (!port && !endpoint) - return 0; - fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr); - if (!fwnode) - return -EPROTO; - - if (port) - *port = fwnode; - - if (!endpoint) - return 0; - - fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint", - endpoint_nr); - if (!fwnode) - return -EPROTO; - *endpoint = fwnode; - - return 0; + return acpi_graph_get_child_prop_value(fwnode, "endpoint", + endpoint_nr); } static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode) @@ -1232,29 +1204,6 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, args_count, args); } -static struct fwnode_handle * -acpi_fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode, - struct fwnode_handle *prev) -{ - struct fwnode_handle *endpoint; - - endpoint = acpi_graph_get_next_endpoint(fwnode, prev); - if (IS_ERR(endpoint)) - return NULL; - - return endpoint; -} - -static struct fwnode_handle * -acpi_fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode) -{ - struct fwnode_handle *endpoint = NULL; - - acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint); - - return endpoint; -} - static struct fwnode_handle * acpi_fwnode_get_parent(struct fwnode_handle *fwnode) { @@ -1295,9 +1244,9 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, .get_named_child_node = acpi_fwnode_get_named_child_node, \ .get_reference_args = acpi_fwnode_get_reference_args, \ .graph_get_next_endpoint = \ - acpi_fwnode_graph_get_next_endpoint, \ + acpi_graph_get_next_endpoint, \ .graph_get_remote_endpoint = \ - acpi_fwnode_graph_get_remote_endpoint, \ + acpi_graph_get_remote_endpoint, \ .graph_get_port_parent = acpi_fwnode_get_parent, \ .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \ }; \ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 11cf39719fd8..de8d3d3fa651 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1089,14 +1089,6 @@ struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode, struct fwnode_handle *child); struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode); -struct fwnode_handle * -acpi_graph_get_next_endpoint(const struct fwnode_handle *fwnode, - struct fwnode_handle *prev); -int acpi_graph_get_remote_endpoint(const struct fwnode_handle *fwnode, - struct fwnode_handle **remote, - struct fwnode_handle **port, - struct fwnode_handle **endpoint); - struct acpi_probe_entry; typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *, struct acpi_probe_entry *); -- cgit From 6561eb3d3a23c4d38ba428396b7a14e184804535 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:15 +0300 Subject: ACPI: property: Allow direct graph endpoint references By using device and further data node references, allow direct references to endpoints. These are of form Package() { \DEV, "portX", "endpointY" } where X is the number of the port and Y is the number of the endpoint. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 19bdada64435..10af340eedd2 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1122,9 +1122,9 @@ acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode) if (ret) return NULL; - /* Ensure this is a device node. */ + /* Direct endpoint reference? */ if (!is_acpi_device_node(args.fwnode)) - return NULL; + return args.nargs ? NULL : args.fwnode; /* * Always require two arguments with the reference: port and -- cgit From 18f1e58d1536f69d4e35f6eabaa07e57eb317314 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:16 +0300 Subject: ACPI: property: Use data node name and reg property for graphs Instead of using the port and endpoint properties, rely on the names of the port and endpoint nodes as well as the reg property, as on DT. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 51 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 10af340eedd2..693cf05b0cc4 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1027,6 +1027,26 @@ struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode) return NULL; } +/* + * Return true if the node is an ACPI graph node. Called on either ports + * or endpoints. + */ +static bool is_acpi_graph_node(struct fwnode_handle *fwnode, + const char *str) +{ + unsigned int len = strlen(str); + const char *name; + + if (!len || !is_acpi_data_node(fwnode)) + return false; + + name = to_acpi_data_node(fwnode)->name; + + return (fwnode_property_present(fwnode, "reg") && + !strncmp(name, str, len) && name[len] == '@') || + fwnode_property_present(fwnode, str); +} + /** * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node * @fwnode: Pointer to the parent firmware node @@ -1045,8 +1065,14 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint( if (!prev) { do { port = fwnode_get_next_child_node(fwnode, port); - /* Ports must have port property */ - if (fwnode_property_present(port, "port")) + /* + * The names of the port nodes begin with "port@" + * followed by the number of the port node and they also + * have a "reg" property that also has the number of the + * port node. For compatibility reasons a node is also + * recognised as a port node from the "port" property. + */ + if (is_acpi_graph_node(port, "port")) break; } while (port); } else { @@ -1061,12 +1087,18 @@ static struct fwnode_handle *acpi_graph_get_next_endpoint( port = fwnode_get_next_child_node(fwnode, port); if (!port) break; - if (fwnode_property_present(port, "port")) + if (is_acpi_graph_node(port, "port")) endpoint = fwnode_get_next_child_node(port, NULL); } - /* Endpoints must have "endpoint" property */ - if (!fwnode_property_present(endpoint, "endpoint")) + /* + * The names of the endpoint nodes begin with "endpoint@" followed by + * the number of the endpoint node and they also have a "reg" property + * that also has the number of the endpoint node. For compatibility + * reasons a node is also recognised as an endpoint node from the + * "endpoint" property. + */ + if (!is_acpi_graph_node(endpoint, "endpoint")) return NULL; return endpoint; @@ -1139,8 +1171,7 @@ acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode) fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr); - return acpi_graph_get_child_prop_value(fwnode, "endpoint", - endpoint_nr); + return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr); } static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode) @@ -1217,8 +1248,10 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, endpoint->local_fwnode = fwnode; - fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); - fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + if (fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port)) + fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); + if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id)) + fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); return 0; } -- cgit From 2285e6d9f68912c786cfc46f798be42ef9800ae8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:17 +0300 Subject: ACPI: property: Document key numbering for hierarchical data extension refs As part of the hierarchical data extension key naming, introduce numbering scheme for the nodes that may be referred to using hierarchical data extension references. This allows iterating over particular kind of nodes recognised by the node name whilst allowing numbering the nodes, bringing ACPI to feature parity with DT in this respect. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/data-node-references.txt | 31 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Documentation/acpi/dsd/data-node-references.txt b/Documentation/acpi/dsd/data-node-references.txt index 00c3b5fe1f2e..6e9a5f925edd 100644 --- a/Documentation/acpi/dsd/data-node-references.txt +++ b/Documentation/acpi/dsd/data-node-references.txt @@ -15,24 +15,43 @@ extension node which is referred to by the key shall lie directly under the parent object i.e. either the device object or another hierarchical data extension node. +The keys in the hierarchical data nodes shall consist of the name of the node, +"@" character and the number of the node in hexadecimal notation (without pre- +or postfixes). The same ACPI object shall include the _DSD property extension +with a property "reg" that shall have the same numerical value as the number of +the node. + +In case a hierarchical data extensions node has no numerical value, then the +"reg" property shall be omitted from the ACPI object's _DSD properties and the +"@" character and the number shall be omitted from the hierarchical data +extension key. + + Example ------- In the ASL snippet below, the "reference" _DSD property [2] contains a device object reference to DEV0 and under that device object, a - hierarchical data extension key "node" referring to the NODE object and - lastly, a hierarchical data extension key "anothernode" referring to the - ANOD object which is also the final target of the reference. + hierarchical data extension key "node@1" referring to the NOD1 object + and lastly, a hierarchical data extension key "anothernode" referring to + the ANOD object which is also the final target node of the reference. Device (DEV0) { Name (_DSD, Package () { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "node", NODE }, + Package () { "node@0", NOD0 }, + Package () { "node@1", NOD1 }, + } + }) + Name (NOD0, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "random-property", 3 }, } }) - Name (NODE, Package() { + Name (NOD1, Package() { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { Package () { "anothernode", ANOD }, @@ -51,7 +70,7 @@ Example Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "reference", ^DEV0, "node", "anothernode" }, + Package () { "reference", ^DEV0, "node@1", "anothernode" }, } }) } -- cgit From e4702b2ca7b4aa81cc067c1b8e7aaa1350239fa2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:18 +0300 Subject: ACPI: property: Update documentation for hierarchical data extension 1.1 Hierarchical data extension 1.1 allows using references as the second entries of the hierearchical data extension packages. Update the references and the examples. The quotes are left in documentation for clarity. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/graph.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/acpi/dsd/graph.txt b/Documentation/acpi/dsd/graph.txt index ac09e3138b79..591c47509c63 100644 --- a/Documentation/acpi/dsd/graph.txt +++ b/Documentation/acpi/dsd/graph.txt @@ -76,7 +76,7 @@ A simple example of this is show below: }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port0", "PRT0" }, + Package () { "port0", PRT0 }, } }) Name (PRT0, Package() { @@ -86,7 +86,7 @@ A simple example of this is show below: }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", "EP00" }, + Package () { "endpoint0", EP00 }, } }) Name (EP00, Package() { @@ -106,7 +106,7 @@ A simple example of this is show below: Name (_DSD, Package () { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port4", "PRT4" }, + Package () { "port4", PRT4 }, } }) @@ -117,7 +117,7 @@ A simple example of this is show below: }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", "EP40" }, + Package () { "endpoint0", EP40 }, } }) @@ -151,7 +151,7 @@ References referenced 2016-10-04. [5] Hierarchical Data Extension UUID For _DSD. - , + , referenced 2016-10-04. [6] Advanced Configuration and Power Interface Specification. -- cgit From e58b1c6a9422b97b30838e77b7d1d2bbed121e96 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:19 +0300 Subject: ACPI: property: graph: Fix graph documentation Address a few issues in the ACPI _DSD properties graph documentation: - the extension for port nodes is a data extension (and not property extension), - clean up language in port hierarchical data extension definition, - add examples of port and endpoint packages, - port property value is the number of the "port" and not the number of the "port node", - remove word "individual" from endpoint data node description, it was redundant, - remove the extra "The" in the endpoint property description, - refer to hierarchical data extension keys and targets instead of first and second package list entries. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/graph.txt | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Documentation/acpi/dsd/graph.txt b/Documentation/acpi/dsd/graph.txt index 591c47509c63..0b007fceda0e 100644 --- a/Documentation/acpi/dsd/graph.txt +++ b/Documentation/acpi/dsd/graph.txt @@ -36,20 +36,24 @@ The port and endpoint concepts are very similar to those in Devicetree [3]. A port represents an interface in a device, and an endpoint represents a connection to that interface. -All port nodes are located under the device's "_DSD" node in the -hierarchical data extension tree. The property extension related to -each port node must contain the key "port" and an integer value which -is the number of the port. The object it refers to should be called "PRTX", -where "X" is the number of the port. - -Further on, endpoints are located under the individual port nodes. The -first hierarchical data extension package list entry of the endpoint -nodes must begin with "endpoint" and must be followed by the number -of the endpoint. The object it refers to should be called "EPXY", where -"X" is the number of the port and "Y" is the number of the endpoint. +All port nodes are located under the device's "_DSD" node in the hierarchical +data extension tree. The data extension related to each port node must begin +with "port" and must be followed by the number of the port as its key. The +target object it refers to should be called "PRTX", where "X" is the number of +the port. An example of such a package would be: + + Package() { "port4", PRT4 } + +Further on, endpoints are located under the port nodes. The hierarchical data +extension key of the endpoint nodes must begin with "endpoint" and must be +followed by the number of the endpoint. The object it refers to should be called +"EPXY", where "X" is the number of the port and "Y" is the number of the +endpoint. An example of such a package would be: + + Package() { "endpoint0", EP40 } Each port node contains a property extension key "port", the value of -which is the number of the port node. The each endpoint is similarly numbered +which is the number of the port. Each endpoint is similarly numbered with a property extension key "endpoint". Port numbers must be unique within a device and endpoint numbers must be unique within a port. -- cgit From e49363e96fd2ee3fd5259fd2a6f9050cb4af82c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:20 +0300 Subject: ACPI: property: graph: Improve graph documentation for port/ep numbering Document that if a port has a single endpoint only, its value shall be zero. Similarly, if a device object only has a single port, its value shlla be zero. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/graph.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/acpi/dsd/graph.txt b/Documentation/acpi/dsd/graph.txt index 0b007fceda0e..3131f457882b 100644 --- a/Documentation/acpi/dsd/graph.txt +++ b/Documentation/acpi/dsd/graph.txt @@ -55,7 +55,10 @@ endpoint. An example of such a package would be: Each port node contains a property extension key "port", the value of which is the number of the port. Each endpoint is similarly numbered with a property extension key "endpoint". Port numbers must be unique within a -device and endpoint numbers must be unique within a port. +device and endpoint numbers must be unique within a port. If a device object +may only has a single port, then the number of that port shall be zero. +Similarly, if a port may only have a single endpoint, the number of that +endpoint shall be zero. The endpoint reference uses property extension with "remote-endpoint" property name followed by a reference in the same package. Such references consist of the -- cgit From a4138e7c12287268348cc2dcad414a62c515d77a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 17 Jul 2018 17:19:21 +0300 Subject: ACPI: property: graph: Update graph documentation to use generic references Instead of port and endpoint properties for representing ports and endpoints, use the keys of the hierarchical data extension references when referring to the port and endpoint nodes. Additionally, use "reg" properties as in Device Tree to specify the number of the port or the endpoint. The keys of the port nodes begin with "port" and the keys of the endpoint nodes begin with "endpoint", both followed by "@" character and the number of the port or the endpoint. These changes have the advantage that no ACPI specific properties need to be added to refer to non-device nodes. Additionally, using the name of the node instead of an integer property inside the node is easier to parse in code and easier for humans to understand. Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- Documentation/acpi/dsd/data-node-references.txt | 1 + Documentation/acpi/dsd/graph.txt | 65 +++++++++++++------------ 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/Documentation/acpi/dsd/data-node-references.txt b/Documentation/acpi/dsd/data-node-references.txt index 6e9a5f925edd..c3871565c8cf 100644 --- a/Documentation/acpi/dsd/data-node-references.txt +++ b/Documentation/acpi/dsd/data-node-references.txt @@ -75,6 +75,7 @@ Example }) } +Please also see a graph example in graph.txt . References ---------- diff --git a/Documentation/acpi/dsd/graph.txt b/Documentation/acpi/dsd/graph.txt index 3131f457882b..b9ce910781dc 100644 --- a/Documentation/acpi/dsd/graph.txt +++ b/Documentation/acpi/dsd/graph.txt @@ -38,34 +38,39 @@ represents a connection to that interface. All port nodes are located under the device's "_DSD" node in the hierarchical data extension tree. The data extension related to each port node must begin -with "port" and must be followed by the number of the port as its key. The -target object it refers to should be called "PRTX", where "X" is the number of -the port. An example of such a package would be: +with "port" and must be followed by the "@" character and the number of the port +as its key. The target object it refers to should be called "PRTX", where "X" is +the number of the port. An example of such a package would be: - Package() { "port4", PRT4 } + Package() { "port@4", PRT4 } -Further on, endpoints are located under the port nodes. The hierarchical data -extension key of the endpoint nodes must begin with "endpoint" and must be -followed by the number of the endpoint. The object it refers to should be called -"EPXY", where "X" is the number of the port and "Y" is the number of the -endpoint. An example of such a package would be: +Further on, endpoints are located under the port nodes. The hierarchical +data extension key of the endpoint nodes must begin with +"endpoint" and must be followed by the "@" character and the number of the +endpoint. The object it refers to should be called "EPXY", where "X" is the +number of the port and "Y" is the number of the endpoint. An example of such a +package would be: - Package() { "endpoint0", EP40 } + Package() { "endpoint@0", EP40 } -Each port node contains a property extension key "port", the value of -which is the number of the port. Each endpoint is similarly numbered -with a property extension key "endpoint". Port numbers must be unique within a -device and endpoint numbers must be unique within a port. If a device object -may only has a single port, then the number of that port shall be zero. -Similarly, if a port may only have a single endpoint, the number of that -endpoint shall be zero. +Each port node contains a property extension key "port", the value of which is +the number of the port. Each endpoint is similarly numbered with a property +extension key "reg", the value of which is the number of the endpoint. Port +numbers must be unique within a device and endpoint numbers must be unique +within a port. If a device object may only has a single port, then the number +of that port shall be zero. Similarly, if a port may only have a single +endpoint, the number of that endpoint shall be zero. The endpoint reference uses property extension with "remote-endpoint" property name followed by a reference in the same package. Such references consist of the -the remote device reference, number of the port in the device and finally the -number of the endpoint in that port. Individual references thus appear as: +the remote device reference, the first package entry of the port data extension +reference under the device and finally the first package entry of the endpoint +data extension reference under the port. Individual references thus appear as: - Package() { device, port_number, endpoint_number } + Package() { device, "port@X", "endpoint@Y" } + +In the above example, "X" is the number of the port and "Y" is the number of the +endpoint. The references to endpoints must be always done both ways, to the remote endpoint and back from the referred remote endpoint node. @@ -83,24 +88,24 @@ A simple example of this is show below: }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port0", PRT0 }, + Package () { "port@0", PRT0 }, } }) Name (PRT0, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "port", 0 }, + Package () { "reg", 0 }, }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", EP00 }, + Package () { "endpoint@0", EP00 }, } }) Name (EP00, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "endpoint", 0 }, - Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, 4, 0 } }, + Package () { "reg", 0 }, + Package () { "remote-endpoint", Package() { \_SB.PCI0.ISP, "port@4", "endpoint@0" } }, } }) } @@ -113,26 +118,26 @@ A simple example of this is show below: Name (_DSD, Package () { ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "port4", PRT4 }, + Package () { "port@4", PRT4 }, } }) Name (PRT4, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "port", 4 }, /* CSI-2 port number */ + Package () { "reg", 4 }, /* CSI-2 port number */ }, ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () { "endpoint0", EP40 }, + Package () { "endpoint@0", EP40 }, } }) Name (EP40, Package() { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () { "endpoint", 0 }, - Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, 0, 0 } }, + Package () { "reg", 0 }, + Package () { "remote-endpoint", Package () { \_SB.PCI0.I2C2.CAM0, "port@0", "endpoint@0" } }, } }) } -- cgit From 82f2d30570b7ecdf1ce7e6376805f063ae86a7e5 Mon Sep 17 00:00:00 2001 From: Lucas Rangit Magasweran Date: Sat, 14 Jul 2018 15:40:18 -0700 Subject: ACPI: battery: remove redundant old_present check on insertion On removal battery_present changes from 1 to 0 after calling acpi_battery_get_status() and battery->update_time is set to 0 before returning. On insertion battery_present changes from 0 to 1 after calling acpi_battery_get_status() and acpi_battery_get_info() is called because battery->update_time is 0. The old_present condition is therefore redundant. This was added in the commit below when there was a path without sysfs that would skip getting the newly inserted battery info. commit 50b178512b7d ("Newly inserted battery might differ from one just removed, so update of battery info fields is required.") Signed-off-by: Lucas Rangit Magasweran Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d79ad844c78f..78e40a9f5e18 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -918,10 +918,11 @@ static void acpi_battery_quirks(struct acpi_battery *battery) static int acpi_battery_update(struct acpi_battery *battery, bool resume) { - int result, old_present = acpi_battery_present(battery); - result = acpi_battery_get_status(battery); + int result = acpi_battery_get_status(battery); + if (result) return result; + if (!acpi_battery_present(battery)) { sysfs_remove_battery(battery); battery->update_time = 0; @@ -931,8 +932,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) if (resume) return 0; - if (!battery->update_time || - old_present != acpi_battery_present(battery)) { + if (!battery->update_time) { result = acpi_battery_get_info(battery); if (result) return result; -- cgit From 3461dfbabcc40d48c7b4b3ebb26a4ec927303e16 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Tue, 24 Jul 2018 14:27:31 +0300 Subject: ACPI / battery: drop inclusion of init.h The driver can be built as a module thus inclusion of init.h is redundant in battery.c since it's always included by module.h. Suggested-by: Andy Shevchenko Signed-off-by: Dmitry Rozhkov Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 78e40a9f5e18..642e51f8f412 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- cgit From 53dd200a2eed1413f2ef980dd5a193a3d45cc9a9 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Tue, 24 Jul 2018 14:27:32 +0300 Subject: ACPI / battery: reorder headers alphabetically Headers ordered alphabetically as easier to maintain. Suggested-by: Andy Shevchenko Signed-off-by: Dmitry Rozhkov Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 642e51f8f412..321b5f98b63c 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -23,17 +23,18 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include #include #include +#include + #include #ifdef CONFIG_ACPI_PROCFS_POWER -- cgit From dd1fca9e6cd4c5c179f4e854ceddbc22890109ce Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Tue, 24 Jul 2018 14:27:33 +0300 Subject: ACPI / battery: use specialized print macros The kernel provides specialized macros for printing info and warning messages which make the code shorter. Use the specialized macros instead of bare printk()'s. Also format one user visible string literal into a searchable one line string. Suggested-by: Andy Shevchenko Signed-off-by: Dmitry Rozhkov Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 321b5f98b63c..6d302bb2f51b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -577,8 +577,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && (s16)(battery->rate_now) < 0) { battery->rate_now = abs((s16)battery->rate_now); - printk_once(KERN_WARNING FW_BUG - "battery: (dis)charge rate invalid.\n"); + pr_warn_once(FW_BUG "battery: (dis)charge rate invalid.\n"); } if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) @@ -1170,8 +1169,7 @@ static const struct file_operations acpi_battery_alarm_fops = { static int acpi_battery_add_fs(struct acpi_device *device) { - printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," - " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); + pr_warning(PREFIX "Deprecated procfs I/F for battery is loaded, please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_battery_dir); @@ -1398,7 +1396,7 @@ static int acpi_battery_add(struct acpi_device *device) } #endif - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + pr_info(PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); -- cgit From 2754435d4c820875412785da9bfa017a74fe51a7 Mon Sep 17 00:00:00 2001 From: Dmitry Rozhkov Date: Tue, 24 Jul 2018 14:27:34 +0300 Subject: ACPI / battery: get rid of negations in conditions Simple conditions without negations inflict less cognitive load on readers. Rework conditional branches not to use negations. Also add braces around single statement branches where their counterpart else-branches consist of more than one statement as suggested in the paragraph 3 of the coding style. Suggested-by: Andy Shevchenko Signed-off-by: Dmitry Rozhkov Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 6d302bb2f51b..cb664e87cde8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1020,7 +1020,7 @@ static int acpi_battery_info_proc_show(struct seq_file *seq, void *offset) acpi_battery_units(battery)); seq_printf(seq, "battery technology: %srechargeable\n", - (!battery->technology)?"non-":""); + battery->technology ? "" : "non-"); if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); @@ -1111,11 +1111,12 @@ static int acpi_battery_alarm_proc_show(struct seq_file *seq, void *offset) goto end; } seq_printf(seq, "alarm: "); - if (!battery->alarm) - seq_printf(seq, "unsupported\n"); - else + if (battery->alarm) { seq_printf(seq, "%u %sh\n", battery->alarm, acpi_battery_units(battery)); + } else { + seq_printf(seq, "unsupported\n"); + } end: if (result) seq_printf(seq, "ERROR: Unable to read battery alarm\n"); @@ -1148,9 +1149,9 @@ static ssize_t acpi_battery_write_alarm(struct file *file, } result = acpi_battery_set_alarm(battery); end: - if (!result) - return count; - return result; + if (result) + return result; + return count; } static int acpi_battery_alarm_proc_open(struct inode *inode, struct file *file) @@ -1245,7 +1246,9 @@ static int battery_notify(struct notifier_block *nb, if (!acpi_battery_present(battery)) return 0; - if (!battery->bat) { + if (battery->bat) { + acpi_battery_refresh(battery); + } else { result = acpi_battery_get_info(battery); if (result) return result; @@ -1253,8 +1256,7 @@ static int battery_notify(struct notifier_block *nb, result = sysfs_add_battery(battery); if (result) return result; - } else - acpi_battery_refresh(battery); + } acpi_battery_init_alarm(battery); acpi_battery_get_state(battery); -- cgit From b047c62e24418b9f62b721be017ec5c0364166a5 Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Tue, 31 Jul 2018 18:52:39 +0800 Subject: ACPI / EC: Use ec_no_wakeup on ThinkPad X1 Yoga 3rd Like on X1C6, on X1Y3 EC interrupts constantly wake up system from s2idle, the power consumption is extremely high. So make ec_no_wakeup be true as default to keep system in s2idle mode and reduce power consumption. Power button works when ec_no_wakeup=true. Signed-off-by: Aaron Ma Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 917f77f4cb55..6291d5c77267 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -2045,6 +2045,13 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { 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"), + }, + }, { }, }; -- cgit From b41901a2cf06f33c030be96c075872201089d47a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 7 Aug 2018 09:36:30 +0200 Subject: ACPI / battery: Do not export energy_full[_design] on devices without full_charge_capacity On some devices (with a buggy _BIX implementation) full_charge_capacity always reports as 0. This means that our energy_full sysfs attribute will also always be 0, which is not useful to export. Worse we calculate our reported capacity on full_charge_capacity and if it is 0 we always report 0. This causes userspace to immediately shutdown or hibernate the laptop since it assumes that the battery is critically low. This commit makes us not report energy_full[_design] or capacity on such broken devices, avoiding the immediate shutdown / hibernate from userspace. Link: https://bugzilla.kernel.org/show_bug.cgi?id=83941 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index cb664e87cde8..cb97b6105f52 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -364,6 +364,20 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; +static enum power_supply_property energy_battery_full_cap_broken_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_POWER_NOW, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, + POWER_SUPPLY_PROP_SERIAL_NUMBER, +}; + /* -------------------------------------------------------------------------- Battery Management -------------------------------------------------------------------------- */ @@ -798,6 +812,11 @@ static int sysfs_add_battery(struct acpi_battery *battery) battery->bat_desc.properties = charge_battery_props; battery->bat_desc.num_properties = ARRAY_SIZE(charge_battery_props); + } else if (battery->full_charge_capacity == 0) { + battery->bat_desc.properties = + energy_battery_full_cap_broken_props; + battery->bat_desc.num_properties = + ARRAY_SIZE(energy_battery_full_cap_broken_props); } else { battery->bat_desc.properties = energy_battery_props; battery->bat_desc.num_properties = -- cgit From a6f0729508df6a067c4a074ec187ecd9d2457a6b Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 7 Aug 2018 21:15:05 +0800 Subject: ACPI / scan: Add static attribute to indirect_io_hosts[] Array indirect_io_hosts[] is declared in acpi_is_indirect_io_slave() as a const array, which means that the array will be re-built for each call. Optimise by adding the static attribute, which means that the array is added to const-data pool and not re-built per function call. Reported-by: Hans de Goede Signed-off-by: John Garry Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 970dd87d347c..199c8ea6896c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1528,7 +1528,7 @@ static int acpi_check_serial_bus_slave(struct acpi_resource *ares, void *data) static bool acpi_is_indirect_io_slave(struct acpi_device *device) { struct acpi_device *parent = device->parent; - const struct acpi_device_id indirect_io_hosts[] = { + static const struct acpi_device_id indirect_io_hosts[] = { {"HISI0191", 0}, {} }; -- cgit From 1035a0783523d8c730c44944a71b254f3a649e25 Mon Sep 17 00:00:00 2001 From: Dongjiu Geng Date: Tue, 7 Aug 2018 12:26:15 -0400 Subject: arm64 / ACPI: clean the additional checks before calling ghes_notify_sea() In order to remove the additional check before calling the ghes_notify_sea(), make stub definition when !CONFIG_ACPI_APEI_SEA. After this cleanup, we can simply call the ghes_notify_sea() to let APEI driver handle the SEA notification. Signed-off-by: Dongjiu Geng Acked-by: Will Deacon Signed-off-by: Rafael J. Wysocki --- arch/arm64/mm/fault.c | 7 +------ include/acpi/ghes.h | 4 ++++ 2 files changed, 5 insertions(+), 6 deletions(-) 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/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 */ -- cgit From 67fbd0a3a802bc80218f6c33d594f34f0ecb02f9 Mon Sep 17 00:00:00 2001 From: Tom Todd Date: Wed, 8 Aug 2018 01:52:02 +0100 Subject: ACPI: bus: Fix a pointer coding style issue Fix white space in the argument list of acpi_device_remove(). Signed-off-by: Tom Todd Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index f61f8927d843..292088fcc624 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -935,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; -- cgit From 4c3be61e41b4206878cd021afbdb85f5b76f2099 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 8 Aug 2018 12:50:37 +0300 Subject: ACPI / EC: Add another entry for Thinkpad X1 Carbon 6th Commit 2c4d6baf1bc4 (ACPI / EC: Use ec_no_wakeup on more Thinkpad X1 Carbon 6th systems) changed the DMI table to match all systems where DMI product family is "Thinkpad X1 Carbon 6th". However, the system I have here has this string written differently (ThinkPad vs. Thinkpad) which makes the match fail. In addition to that, after BIOS upgrade Robin now has the same string than my system has (perhaps newer BIOS has changed the string). In any case add another DMI entry to acpi_ec_no_wakeup[] table hopefully covering all the X1 Carbon 6th systems out there. Fixes: 2c4d6baf1bc4 (ACPI / EC: Use ec_no_wakeup on more Thinkpad X1 Carbon 6th systems) Signed-off-by: Mika Westerberg [ rjw: Rebase and change the ident string to match the product familiy ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6291d5c77267..d4e5610e09c5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -2045,6 +2045,13 @@ 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 = { -- cgit From 5971b0c1594d6c34e257101ed5fdffec65205c50 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Aug 2018 10:30:03 +0200 Subject: ACPI / scan: Initialize status to ACPI_STA_DEFAULT Since commit 63347db0affa "ACPI / scan: Use acpi_bus_get_status() to initialize ACPI_TYPE_DEVICE devs" the status field of normal acpi_devices gets set to 0 by acpi_bus_type_and_status() and filled with its actual value later when acpi_add_single_object() calls acpi_bus_get_status(). This means that any acpi_match_device_ids() calls in between will always fail with -ENOENT. We already have a workaround for this, which temporary forces status to ACPI_STA_DEFAULT in drivers/acpi/x86/utils.c: acpi_device_always_present() and the next commit in this series adds another acpi_match_device_ids() call between status being initialized as 0 and the acpi_bus_get_status() call. Rather then adding another workaround, this commit makes acpi_bus_type_and_status() initialize status to ACPI_STA_DEFAULT, this is safe to do as the only code looking at status between the initialization and the acpi_bus_get_status() call is those acpi_match_device_ids() calls. Note this does mean that we need to (re)set status to 0 in case the acpi_bus_get_status() call fails. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 199c8ea6896c..798a73416af8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1612,7 +1612,8 @@ static int acpi_add_single_object(struct acpi_device **child, * Note this must be done before the get power-/wakeup_dev-flags calls. */ if (type == ACPI_BUS_TYPE_DEVICE) - acpi_bus_get_status(device); + if (acpi_bus_get_status(device) < 0) + acpi_set_device_status(device, 0); acpi_bus_get_power_flags(device); acpi_bus_get_wakeup_device_flags(device); @@ -1690,7 +1691,7 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, * acpi_add_single_object updates this once we've an acpi_device * so that acpi_bus_get_status' quirk handling can be used. */ - *sta = 0; + *sta = ACPI_STA_DEFAULT; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; -- cgit From aba941392aeef2d1bc064a1e4b09293473ef7b9b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Aug 2018 11:15:56 +0200 Subject: ACPI / scan: Create platform device for fwnodes with multiple i2c devices Some devices have multiple I2cSerialBus resources and for things to work an i2c-client must be instantiated for each, each with its own i2c_device_id. Normally we only instantiate an i2c-client for the first resource, using the ACPI HID as id. This commit adds a list of HIDs of devices, which need multiple i2c-clients instantiated from a single fwnode, to acpi_device_enumeration_by_parent and makes acpi_device_enumeration_by_parent return false for these devices so that a platform device will be instantiated. This allows the drivers/platform/x86/i2c-multi-instantiate.c driver, which knows which i2c_device_id to use for each resource, to bind to the fwnode and initiate an i2c-client for each resource. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 798a73416af8..e1b6231cfa1c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1540,6 +1540,18 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) { struct list_head resource_list; bool is_serial_bus_slave = false; + /* + * These devices have multiple I2cSerialBus resources and an i2c-client + * must be instantiated for each, each with its own i2c_device_id. + * Normally we only instantiate an i2c-client for the first resource, + * using the ACPI HID as id. These special cases are handled by the + * drivers/platform/x86/i2c-multi-instantiate.c driver, which knows + * which i2c_device_id to use for each resource. + */ + static const struct acpi_device_id i2c_multi_instantiate_ids[] = { + {"BSG1160", }, + {} + }; if (acpi_is_indirect_io_slave(device)) return true; @@ -1551,6 +1563,10 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) fwnode_property_present(&device->fwnode, "baud"))) return true; + /* Instantiate a pdev for the i2c-multi-instantiate drv to bind to */ + if (!acpi_match_device_ids(device, i2c_multi_instantiate_ids)) + return false; + INIT_LIST_HEAD(&resource_list); acpi_dev_get_resources(device, &resource_list, acpi_check_serial_bus_slave, -- cgit From 21ba074cb47171a34f60e250e8f7ef3dc1529e43 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Aug 2018 11:15:57 +0200 Subject: ACPI / x86: utils: Remove status workaround from acpi_device_always_present() Now that we init the status field to ACPI_STA_DEFAULT rather then to 0, the workaround for acpi_match_device_ids() always returning -ENOENT when status is 0 is no longer needed. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/utils.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 3a13b2af2bf8..06c31ec3cc70 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -109,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; @@ -131,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; } -- cgit From e64e84987de5486839afaccd191df71012ac1800 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Aug 2018 13:40:46 +0200 Subject: platform/x86: Add ACPI i2c-multi-instantiate pseudo driver On systems with ACPI instantiated i2c-clients, normally there is 1 fw_node per i2c-device and that fw-node contains 1 I2cSerialBus resource for that 1 i2c-device. But in some rare cases the manufacturer has decided to describe multiple i2c-devices in a single ACPI fwnode with multiple I2cSerialBus resources. An earlier attempt to fix this in the i2c-core resulted in a lot of extra code to support this corner-case. This commit introduces a new i2c-multi-instantiate driver which fixes this in a different way. This new driver can be built as a module which will only loaded on affected systems. This driver will instantiate a new i2c-client per I2cSerialBus resource, using the driver_data from the acpi_device_id it is binding to to tell it which chip-type (and optional irq-resource) to use when instantiating. Note this driver depends on a platform device being instantiated for the ACPI fwnode, see the i2c_multi_instantiate_ids list of ACPI device-ids in drivers/acpi/scan.c: acpi_device_enumeration_by_parent(). Acked-by: Andy Shevchenko Acked-by: Wolfram Sang Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- MAINTAINERS | 6 ++ drivers/platform/x86/Kconfig | 11 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/i2c-multi-instantiate.c | 132 +++++++++++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 drivers/platform/x86/i2c-multi-instantiate.c 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/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"); -- cgit