aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGraeme Gregory <graeme.gregory@linaro.org>2014-07-30 13:35:45 +0100
committerGraeme Gregory <graeme.gregory@linaro.org>2014-07-30 13:35:45 +0100
commit058f31d740125550ec7a65b3072de3d5ea40520a (patch)
tree837b566ee4fc5a15ae8741954a7b6f8e6abe977f /drivers
parent3fc9c4d4787a2acb86f7c559d6edee7a255327ad (diff)
parentc8f86f2b1f604dff3e71bb3a4039b7065c35c5f6 (diff)
Merge remote-tracking branch 'origin/acpi-topic-juno-fvp' into leg-kernel
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/acpi_keyvalue.c115
-rw-r--r--drivers/acpi/acpica/Makefile2
-rw-r--r--drivers/acpi/acpica/prxface.c217
-rw-r--r--drivers/acpi/internal.h6
-rw-r--r--drivers/acpi/property.c512
-rw-r--r--drivers/acpi/scan.c2
-rw-r--r--drivers/amba/Makefile2
-rw-r--r--drivers/amba/acpi.c239
-rw-r--r--drivers/clk/clk-fixed-rate.c82
-rw-r--r--drivers/mfd/vexpress-sysreg.c66
-rw-r--r--drivers/mtd/maps/Kconfig9
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/physmap_acpi.c372
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c10
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c78
-rw-r--r--drivers/spi/spi-pl022.c49
-rw-r--r--drivers/virtio/virtio_mmio.c12
18 files changed, 1769 insertions, 7 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8e9bbe6b03c0..3808499fba36 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_X86) += blacklist.o
# ACPI Core Subsystem (Interpreter)
#
obj-y += acpi.o \
+ acpi_keyvalue.o \
acpica/
# All the builtin files are in the "acpi." module_param namespace.
@@ -46,6 +47,7 @@ acpi-y += acpi_pnp.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
diff --git a/drivers/acpi/acpi_keyvalue.c b/drivers/acpi/acpi_keyvalue.c
new file mode 100644
index 000000000000..5c3cde921b22
--- /dev/null
+++ b/drivers/acpi/acpi_keyvalue.c
@@ -0,0 +1,115 @@
+/*
+ * Key/Value handler from _DSM method
+ *
+ * Copyright (C) 2013 Linaro Ltd
+ *
+ * Author: Graeme Gregory <graeme.gregory@linaro.org>
+ *
+ * Original based on code :-
+ *
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Brandon Anderson <brandon.anderson@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+
+/* UUID: a706b112-bf0b-48d2-9fa3-95591a3c4c06 (randomly generated) */
+static const char acpi_amba_dsm_uuid[] = {
+ 0xa7, 0x06, 0xb1, 0x12, 0xbf, 0x0b, 0x48, 0xd2,
+ 0x9f, 0xa3, 0x95, 0x59, 0x1a, 0x3c, 0x4c, 0x06
+};
+
+/* acpi_dsm_lookup_value()
+ *
+ * Helper to parse through ACPI _DSM object for a device. Each entry
+ * has three fields.
+ */
+int acpi_dsm_lookup_value(acpi_handle handle,
+ const char *tag, int index,
+ struct acpi_dsm_entry *entry)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object params[4];
+ union acpi_object *obj;
+ int len, match_count, i;
+
+ /* invalidate output in case there's no entry to supply */
+ entry->key = NULL;
+ entry->value = NULL;
+
+ if (!acpi_has_method(handle, "_DSM"))
+ return -ENOENT;
+
+ input.count = 4;
+ params[0].type = ACPI_TYPE_BUFFER; /* UUID */
+ params[0].buffer.length = sizeof(acpi_amba_dsm_uuid);
+ params[0].buffer.pointer = (char *)acpi_amba_dsm_uuid;
+ params[1].type = ACPI_TYPE_INTEGER; /* Revision */
+ params[1].integer.value = 1;
+ params[2].type = ACPI_TYPE_INTEGER; /* Function # */
+ params[2].integer.value = 1;
+ params[3].type = ACPI_TYPE_PACKAGE; /* Arguments */
+ params[3].package.count = 0;
+ params[3].package.elements = NULL;
+ input.pointer = params;
+
+ status = acpi_evaluate_object_typed(handle, "_DSM",
+ &input, &output, ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status)) {
+ pr_err("failed to get _DSM package for this device\n");
+ return -ENOENT;
+ }
+
+ obj = (union acpi_object *)output.pointer;
+
+ /* parse 2 objects per entry */
+ match_count = 0;
+ for (i = 0; (i + 2) <= obj->package.count; i += 2) {
+ /* key must be a string */
+ len = obj->package.elements[i].string.length;
+ if (len <= 0)
+ continue;
+
+ /* check to see if this is the entry to return */
+ if (strncmp(tag, obj->package.elements[i].string.pointer,
+ len) != 0 ||
+ match_count < index) {
+ match_count++;
+ continue;
+ }
+
+ /* copy the key */
+ entry->key = kmalloc(len + 1, GFP_KERNEL);
+ strncpy(entry->key,
+ obj->package.elements[i].string.pointer,
+ len);
+ entry->key[len] = '\0';
+
+ /* value is a string with space-delimited fields if necessary */
+ len = obj->package.elements[i + 1].string.length;
+ if (len > 0) {
+ entry->value = kmalloc(len + 1, GFP_KERNEL);
+ strncpy(entry->value,
+ obj->package.elements[i+1].string.pointer,
+ len);
+ entry->value[len] = '\0';
+ }
+
+ break;
+ }
+
+ kfree(output.pointer);
+
+ if (entry->key == NULL)
+ return -ENOENT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dsm_lookup_value);
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 8bb43f06e11f..4c2e8c0ed9da 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -177,3 +177,5 @@ acpi-y += \
acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o
+acpi-y += \
+ prxface.o
diff --git a/drivers/acpi/acpica/prxface.c b/drivers/acpi/acpica/prxface.c
new file mode 100644
index 000000000000..4e52b5143374
--- /dev/null
+++ b/drivers/acpi/acpica/prxface.c
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ *
+ * Module Name: prxface - Public interface to ACPI device properties
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <linux/export.h>
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_RESOURCES
+ACPI_MODULE_NAME("prxface")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_pr_validate_parameters
+ *
+ * PARAMETERS: device_handle - Handle to a device
+ * buffer - Pointer to a data buffer
+ * return_node - Pointer to where the device node is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Checks validity of the parameters passed to
+ * acpi_get_device_properties().
+ *
+ ******************************************************************************/
+static acpi_status
+acpi_pr_validate_parameters(acpi_handle device_handle,
+ struct acpi_buffer *buffer,
+ struct acpi_namespace_node **return_node)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_pr_validate_parameters);
+
+ if (!device_handle) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ node = acpi_ns_validate_handle(device_handle);
+ if (!node) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (node->type != ACPI_TYPE_DEVICE) {
+ return_ACPI_STATUS(AE_TYPE);
+ }
+
+ /* Make sure the buffer is valid */
+ status = acpi_ut_validate_buffer(buffer);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ *return_node = node;
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_prp_method_data
+ *
+ * PARAMETERS: node - Device node
+ * ret_buffer - Pointer to a buffer structure where the
+ * resulting properties are stored
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to evaluate _PRP method for a given
+ * device. In case of success resulting package is stored in
+ * ret_buffer.
+ *
+ * If the function fails an appropriate status will be returned and
+ * the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+static acpi_status
+acpi_pr_get_prp_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **properties;
+ acpi_status status;
+ acpi_size size;
+ int i;
+
+ ACPI_FUNCTION_TRACE(acpi_pr_get_prp_method_data);
+
+ status = acpi_ut_evaluate_object(node, METHOD_NAME__PRP,
+ ACPI_BTYPE_PACKAGE, &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Validate that the returned package is in correct format:
+ * 1) Each property is a package itself holding { key, value }
+ * 2) Key is mandatory
+ * 3) Key must be string.
+ */
+ properties = obj_desc->package.elements;
+ for (i = 0; i < obj_desc->package.count; i++) {
+ union acpi_operand_object **property;
+
+ if (properties[i]->common.type != ACPI_TYPE_PACKAGE) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+ if (properties[i]->package.count < 1) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+
+ property = properties[i]->package.elements;
+ if (property[0]->common.type != ACPI_TYPE_STRING) {
+ status = AE_BAD_DATA;
+ goto out;
+ }
+ }
+
+ /* Copy the internal buffer to ret_buffer */
+ status = acpi_ut_get_object_size(obj_desc, &size);
+ if (ACPI_FAILURE(status)) {
+ goto out;
+ }
+
+ status = acpi_ut_initialize_buffer(ret_buffer, size);
+ if (ACPI_SUCCESS(status)) {
+ status = acpi_ut_copy_iobject_to_eobject(obj_desc, ret_buffer);
+ }
+
+ out:
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_properties
+ *
+ * PARAMETERS: device_handle - Handle to the device object for the
+ * device we are querying
+ * ret_buffer - Pointer to a buffer to receive the
+ * properties for the device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get properties for
+ * a specific device The caller must first acquire a handle for the
+ * desired device The property data is placed in the buffer pointed
+ * to by the ret_buffer variable parameter.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of ret_buffer is undefined.
+ *
+ * This function attempts to execute the _PRP method contained in
+ * the object indicated by the passed device_handle.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_properties(acpi_handle device_handle, struct acpi_buffer *ret_buffer)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_get_device_properties);
+
+ status = acpi_pr_validate_parameters(device_handle, ret_buffer, &node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_pr_get_prp_method_data(node, ret_buffer);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_properties)
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 9a1822803479..4b9a3341bd64 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -188,4 +188,10 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
bool acpi_osi_is_win8(void);
#endif
+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
new file mode 100644
index 000000000000..489644c6c136
--- /dev/null
+++ b/drivers/acpi/property.c
@@ -0,0 +1,512 @@
+/*
+ * Device Tree style properties from ACPI devices.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Darren Hart <dvhart@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+struct acpi_dev_property_lookup {
+ const char *name;
+ acpi_object_type type;
+ const union acpi_object *obj;
+};
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+
+ if (ACPI_SUCCESS(acpi_get_properties(adev->handle, &buf)))
+ adev->properties = buf.pointer;
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE(adev->properties);
+ adev->properties = NULL;
+}
+
+/**
+ * acpi_dev_get_properties - get properties from a device
+ * @adev: device to get properties from
+ * @callback: callback that is called for each found property
+ * @data: data passed to @callback
+ *
+ * Function goes over device properties and for each property @callback is
+ * called. If @callback returns non-zero the iteration is terminated and
+ * that return value is returned from this function.
+ */
+int acpi_dev_get_properties(struct acpi_device *adev,
+ int (*callback)(const union acpi_object *, void *),
+ void *data)
+{
+ const union acpi_object *property;
+ int i, ret;
+
+ if (!adev)
+ return -EINVAL;
+ if (!adev->properties)
+ return -ENODATA;
+
+ for (i = 0; i < adev->properties->package.count; i++) {
+ property = &adev->properties->package.elements[i];
+ ret = callback(property, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_properties);
+
+/*
+ * Returns 0 if the property didn̈́'t match, 1 if it did and -EINVAL if the
+ * value found is not of expected type.
+ */
+static int acpi_dev_find_property(const union acpi_object *pkg, void *data)
+{
+ const union acpi_object *obj, *name = &pkg->package.elements[0];
+ struct acpi_dev_property_lookup *lookup = data;
+
+ if (strcmp(lookup->name, name->string.pointer))
+ return 0;
+
+ obj = pkg->package.count > 1 ? &pkg->package.elements[1] : NULL;
+
+ if (lookup->type == ACPI_TYPE_ANY ||
+ (obj && lookup->type == obj->type)) {
+ lookup->obj = obj;
+ return 1;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @type: expected type or %ACPI_TYPE_ANY if caller doesn't care
+ * @obj: property value is placed here if not %NULL
+ *
+ * Function looks up a property with @name and returns the resulting ACPI
+ * object in @obj if found. The returned object should not be released by
+ * the caller, it is released automatically by the ACPI core when @adev is
+ * removed.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ struct acpi_dev_property_lookup lookup = {
+ .name = name,
+ .type = type,
+ };
+ int ret;
+
+ ret = acpi_dev_get_properties(adev, acpi_dev_find_property, &lookup);
+ if (ret == 1) {
+ if (obj)
+ *obj = lookup.obj;
+ return 0;
+ }
+ return ret ? ret : -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_u64 - find and read 64-bit integer property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @value: value of the property is placed here.
+ *
+ * Search for a property with the @name and if find, place the value to
+ * @value. Returns %0 on success, %-ENODATA if the property is not found,
+ * and %-EINVAL if the property is not in correct format.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", 0x0000ffffffff0000 }
+ */
+int acpi_dev_get_property_u64(struct acpi_device *adev, const char *name,
+ u64 *value)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_INTEGER, &obj);
+ if (!ret)
+ *value = (u64)obj->integer.value;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_u64);
+
+/**
+ * acpi_dev_get_property_u32 - find and read 32-bit integer property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @value: value of the property is placed here.
+ *
+ * Search for a property with the @name and if find, place the value to
+ * @value. Returns %0 on success, %-ENODATA if the property is not found,
+ * and %-EINVAL if the property is not in correct format.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", 0x0ffffff0 }
+ */
+int acpi_dev_get_property_u32(struct acpi_device *adev, const char *name,
+ u32 *value)
+{
+ u64 tmp;
+ int ret;
+
+ ret = acpi_dev_get_property_u64(adev, name, &tmp);
+ if (!ret)
+ *value = tmp;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_u32);
+
+/**
+ * acpi_dev_get_property_u16 - find and read 16-bit integer property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @value: value of the property is placed here.
+ *
+ * Search for a property with the @name and if find, place the value to
+ * @value. Returns %0 on success, %-ENODATA if the property is not found,
+ * and %-EINVAL if the property is not in correct format.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", 0x0ff0 }
+ */
+int acpi_dev_get_property_u16(struct acpi_device *adev, const char *name,
+ u16 *value)
+{
+ u64 tmp;
+ int ret;
+
+ ret = acpi_dev_get_property_u64(adev, name, &tmp);
+ if (!ret)
+ *value = tmp;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_u16);
+
+/**
+ * acpi_dev_get_property_u8 - find and read 8-bit integer property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @value: value of the property is placed here.
+ *
+ * Search for a property with the @name and if find, place the value to
+ * @value. Returns %0 on success, %-ENODATA if the property is not found,
+ * and %-EINVAL if the property is not in correct format.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", 0x3c }
+ */
+int acpi_dev_get_property_u8(struct acpi_device *adev, const char *name,
+ u8 *value)
+{
+ u64 tmp;
+ int ret;
+
+ ret = acpi_dev_get_property_u64(adev, name, &tmp);
+ if (!ret)
+ *value = tmp;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_u8);
+
+static int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **ret_obj)
+{
+ const union acpi_object *obj;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &obj);
+ if (ret)
+ return ret;
+
+ /* Check that all elements are of correct type */
+ for (i = 0; i < obj->package.count; i++)
+ if (obj->package.elements[i].type != type)
+ return -EINVAL;
+
+ *ret_obj = obj;
+ return 0;
+}
+
+/**
+ * acpi_dev_get_property_array_u64 - find and read array of u64 from a property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @values: array where the data is placed
+ * @nvalues: number of elements in @values array
+ *
+ * Copies integer properties array with @name into @values and returns
+ * number of items in the actual array or %-ENODATA if the property doesn't
+ * exists, %-EINVAL if the array format is invalid. @values and @nvalues
+ * can be set to %NULL and %0 respectively. In that case the function
+ * returns number of items in the array but doesn't touch @values.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", Package () { 1, 2, ... } }
+ */
+int acpi_dev_get_property_array_u64(struct acpi_device *adev, const char *name,
+ u64 *values, size_t nvalues)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, name, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ if (values) {
+ int i;
+
+ for (i = 0; i < obj->package.count && i < nvalues; i++)
+ values[i] = obj->package.elements[i].integer.value;
+ }
+
+ return obj->package.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array_u64);
+
+/**
+ * acpi_dev_get_property_array_u32 - find and read array of u32 from a property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @values: array where the data is placed
+ * @nvalues: number of elements in @values array
+ *
+ * Copies integer properties array with @name into @values and returns
+ * number of items in the actual array or %-ENODATA if the property doesn't
+ * exists, %-EINVAL if the array format is invalid. @values and @nvalues
+ * can be set to %NULL and %0 respectively. In that case the function
+ * returns number of items in the array but doesn't touch @values.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", Package () { 1, 2, ... } }
+ */
+int acpi_dev_get_property_array_u32(struct acpi_device *adev, const char *name,
+ u32 *values, size_t nvalues)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, name, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ if (values) {
+ int i;
+
+ for (i = 0; i < obj->package.count && i < nvalues; i++)
+ values[i] = obj->package.elements[i].integer.value;
+ }
+
+ return obj->package.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array_u32);
+
+/**
+ * acpi_dev_get_property_array_u16 - find and read array of u16 from a property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @values: array where the data is placed
+ * @nvalues: number of elements in @values array
+ *
+ * Copies integer properties array with @name into @values and returns
+ * number of items in the actual array or %-ENODATA if the property doesn't
+ * exists, %-EINVAL if the array format is invalid. @values and @nvalues
+ * can be set to %NULL and %0 respectively. In that case the function
+ * returns number of items in the array but doesn't touch @values.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", Package () { 1, 2, ... } }
+ */
+int acpi_dev_get_property_array_u16(struct acpi_device *adev, const char *name,
+ u16 *values, size_t nvalues)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, name, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ if (values) {
+ int i;
+
+ for (i = 0; i < obj->package.count && i < nvalues; i++)
+ values[i] = obj->package.elements[i].integer.value;
+ }
+
+ return obj->package.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array_u16);
+
+/**
+ * acpi_dev_get_property_array_u8 - find and read array of u8 from a property
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @values: array where the data is placed. Caller allocated can be %NULL.
+ * @nvalues: number of items in @values array
+ *
+ * Copies integer properties array with @name into @values and returns
+ * number of items in the actual array or %-ENODATA if the property doesn't
+ * exists, %-EINVAL if the array format is invalid. @values and @nvalues
+ * can be set to %NULL and %0 respectively. In that case the function
+ * returns number of items in the array but doesn't touch @values.
+ *
+ * Function treats ACPI types package and buffer the same. It first looks
+ * for a package and then falls back to a buffer.
+ *
+ * A sample ASL might look like this if package is used:
+ * Package () { "property", Package () { 1, 2, ... } }
+ *
+ * And like this if buffer is used:
+ * Package () { "property", Buffer () { 1, 2, ... } }
+ */
+int acpi_dev_get_property_array_u8(struct acpi_device *adev, const char *name,
+ u8 *values, size_t nvalues)
+{
+ const union acpi_object *obj;
+ int ret, i;
+
+ ret = acpi_dev_get_property_array(adev, name, ACPI_TYPE_INTEGER, &obj);
+ if (!ret) {
+ if (values) {
+ const union acpi_object *elements;
+
+ elements = obj->package.elements;
+ for (i = 0; i < obj->package.count && i < nvalues; i++)
+ values[i] = elements[i].integer.value;
+ }
+ return obj->package.count;
+ }
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_BUFFER, &obj);
+ if (ret)
+ return ret;
+
+ if (values) {
+ for (i = 0; i < obj->buffer.length && i < nvalues; i++)
+ values[i] = obj->buffer.pointer[i];
+ }
+
+ return obj->buffer.length;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array_u8);
+
+/**
+ * acpi_dev_get_property_string - returns string property value
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @value: pointer to the returned string
+ *
+ * Finds property with @name, and places pointer to the string value to
+ * @value. The memory pointed by @value should not be released by the
+ * called but it will be released when the corresponding ACPI device object
+ * is removed.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", "my string property value" }
+ */
+int acpi_dev_get_property_string(struct acpi_device *adev, const char *name,
+ const char **value)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_STRING, &obj);
+ if (!ret)
+ *value = obj->string.pointer;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_string);
+
+/**
+ * acpi_dev_get_property_array_string - find and read an array of strings
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @values: array where strings are placed
+ * @nvalues: number of items in @values array
+ *
+ * Finds property with @name, verifies that it contains an array of strings
+ * and if so, fills in @values with pointers to those strings. Note that
+ * the caller shouldn't try to release those pointers. They are owned by
+ * the ACPI device @adev.
+ *
+ * String pointers will remain valid as long as the corresponding ACPI
+ * device object exists.
+ *
+ * A sample ASL might look like this:
+ * Package () {
+ * "property",
+ * Package () { "my first string", "my second string" }
+ * }
+ */
+int acpi_dev_get_property_array_string(struct acpi_device *adev,
+ const char *name, const char **values,
+ size_t nvalues)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, name, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ if (values) {
+ const union acpi_object *elements = obj->package.elements;
+ int i;
+
+ for (i = 0; i < obj->package.count && i < nvalues; i++)
+ values[i] = elements[i].string.pointer;
+ }
+
+ return obj->package.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array_string);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: name of the property
+ * @obj_handle: pointer to acpi_handle where the found ACPI handle is placed
+ *
+ * Function finds property with @name, verififies that it is an object
+ * reference and if so, returns the ACPI handle of the referenced object in
+ * @obj_handle. Returns %0 in case of success, %-ENODATA if the property
+ * doesn't exists or doesn't have a value, and %-EINVAL if the property
+ * value is not a reference.
+ *
+ * A sample ASL might look like this:
+ * Package () { "property", \_SB.PCI0.LPC }
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ acpi_handle *obj_handle)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_LOCAL_REFERENCE,
+ &obj);
+ if (!ret)
+ *obj_handle = obj->reference.handle;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index f775fa0d850f..fc97e6123864 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -880,6 +880,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1876,6 +1877,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile
index 66e81c2f1e3c..6d088e7ed24b 100644
--- a/drivers/amba/Makefile
+++ b/drivers/amba/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_ARM_AMBA) += bus.o
+obj-$(CONFIG_ARM_AMBA) += bus.o acpi.o
obj-$(CONFIG_TEGRA_AHB) += tegra-ahb.o
diff --git a/drivers/amba/acpi.c b/drivers/amba/acpi.c
new file mode 100644
index 000000000000..ae180757f335
--- /dev/null
+++ b/drivers/amba/acpi.c
@@ -0,0 +1,239 @@
+/*
+ * AMBA Connector Resource for ACPI
+ *
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Brandon Anderson <brandon.anderson@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifdef CONFIG_ACPI
+
+#include <linux/module.h>
+#include <linux/amba/bus.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/amba/acpi.h>
+
+struct acpi_amba_bus_info {
+ struct platform_device *pdev;
+ struct clk *clk;
+ char *clk_name;
+};
+
+static int acpi_amba_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct amba_device *dev = data;
+ struct resource r;
+ int irq_idx;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ if (!acpi_dev_resource_memory(ares, &dev->res))
+ pr_err("failed to map memory resource\n");
+ break;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ for (irq_idx = 0; irq_idx < AMBA_NR_IRQS; irq_idx++) {
+ if (acpi_dev_resource_interrupt(ares, irq_idx, &r))
+ dev->irq[irq_idx] = r.start;
+ else
+ break;
+ }
+
+ break;
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ /* ignore the end tag */
+ break;
+ default:
+ /* log an error, but proceed with driver probe */
+ pr_err("unhandled acpi resource type= %d\n",
+ ares->type);
+ break;
+ }
+
+ return 1; /* Tell ACPI core that this resource has been handled */
+}
+
+static struct clk *acpi_amba_get_clk(acpi_handle handle, int index,
+ char **clk_name)
+{
+ acpi_handle clk_handle;
+ struct acpi_device *adev, *clk_adev;
+ const char **clk_paths;
+ struct clk *clk = NULL;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev)) {
+ pr_err("cannot get device from handle\n");
+ return NULL;
+ }
+
+ /* Get number of entries */
+ ret = acpi_dev_get_property_array_string(adev, "clocks", NULL, 0);
+
+ if ((ret < 0) || (index >= ret))
+ return NULL;
+
+ clk_paths = kzalloc(sizeof(*clk_paths) * ret, GFP_KERNEL);
+
+ /* look under the clock device for the clock that matches the entry */
+ ret = acpi_dev_get_property_array_string(adev, "clocks", clk_paths,
+ ret);
+
+ /* Locate the acpi_device from the device name */
+ acpi_get_handle(NULL, (acpi_string)clk_paths[index], &clk_handle);
+ if (!clk_handle)
+ goto error;
+ acpi_bus_get_device(clk_handle, &clk_adev);
+ if (!clk_adev)
+ goto error;
+
+ clk = clk_get_sys(dev_name(&clk_adev->dev), NULL);
+
+error:
+ kfree(clk_paths);
+ return clk;
+}
+
+static void acpi_amba_register_clocks(struct acpi_device *adev,
+ struct clk *default_clk, const char *default_clk_name)
+{
+ struct clk *clk;
+ int i;
+ char *clk_name;
+
+ for (i = 0;; i++) {
+ clk_name = NULL;
+ clk = acpi_amba_get_clk(ACPI_HANDLE(&adev->dev), i, &clk_name);
+ if (!clk)
+ break;
+
+ clk_register_clkdev(clk, clk_name, dev_name(&adev->dev));
+
+ kfree(clk_name);
+ }
+
+ if (default_clk) {
+ /* for amba_get_enable_pclk() ... */
+ clk_register_clkdev(default_clk, default_clk_name,
+ dev_name(&adev->dev));
+ /* for devm_clk_get() ... */
+ clk_register_clkdev(default_clk, NULL, dev_name(&adev->dev));
+ }
+}
+
+/* acpi_amba_add_device()
+ *
+ * ACPI equivalent to of_amba_device_create()
+ */
+static acpi_status acpi_amba_add_device(acpi_handle handle,
+ u32 lvl_not_used, void *data, void **not_used)
+{
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ struct amba_device *dev;
+ int ret;
+ struct acpi_amba_bus_info *bus_info = data;
+ struct platform_device *bus_pdev = bus_info->pdev;
+
+ if (acpi_bus_get_device(handle, &adev)) {
+ pr_err("%s: acpi_bus_get_device failed\n", __func__);
+ return AE_OK;
+ }
+
+ pr_debug("Creating amba device %s\n", dev_name(&adev->dev));
+
+ dev = amba_device_alloc(NULL, 0, 0);
+ if (!dev) {
+ pr_err("%s(): amba_device_alloc() failed for %s\n",
+ __func__, dev_name(&adev->dev));
+ return AE_CTRL_TERMINATE;
+ }
+
+ /* setup generic device info */
+ dev->dev.coherent_dma_mask = ~0;
+ dev->dev.parent = &bus_pdev->dev;
+ dev_set_name(&dev->dev, "%s", dev_name(&adev->dev));
+
+ /* setup amba-specific device info */
+ ACPI_COMPANION_SET(&dev->dev, adev);
+ ACPI_COMPANION_SET(&adev->dev, adev);
+
+ INIT_LIST_HEAD(&resource_list);
+ acpi_dev_get_resources(adev, &resource_list,
+ acpi_amba_add_resource, dev);
+ acpi_dev_free_resource_list(&resource_list);
+
+ /* Add clocks */
+ acpi_amba_register_clocks(adev, bus_info->clk, bus_info->clk_name);
+
+ /* Read AMBA hardware ID and add device to system. If a driver matching
+ * hardware ID has already been registered, bind this device to it.
+ * Otherwise, the platform subsystem will match up the hardware ID
+ * when the matching driver is registered.
+ */
+ ret = amba_device_add(dev, &iomem_resource);
+ if (ret) {
+ pr_err("%s(): amba_device_add() failed (%d) for %s\n",
+ __func__, ret, dev_name(&adev->dev));
+ goto err_free;
+ }
+
+ return AE_OK;
+
+err_free:
+ amba_device_put(dev);
+
+ return AE_OK; /* don't prevent other devices from being probed */
+}
+
+static int acpi_amba_bus_probe(struct platform_device *pdev)
+{
+ struct acpi_amba_bus_info bus_info;
+ bus_info.clk_name = NULL;
+
+ /* see if there's a top-level clock to use as default for sub-devices */
+ bus_info.clk = acpi_amba_get_clk(ACPI_HANDLE(&pdev->dev), 0,
+ &bus_info.clk_name);
+
+ /* probe each device */
+ bus_info.pdev = pdev;
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(&pdev->dev), 1,
+ acpi_amba_add_device, NULL, &bus_info, NULL);
+
+ kfree(bus_info.clk_name);
+
+ return 0;
+}
+
+static const struct acpi_device_id amba_bus_acpi_match[] = {
+ { "LNRO001A", 0 },
+ { },
+};
+
+static struct platform_driver amba_bus_acpi_driver = {
+ .driver = {
+ .name = "amba-acpi",
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(amba_bus_acpi_match),
+ },
+ .probe = acpi_amba_bus_probe,
+};
+
+static int __init acpi_amba_bus_init(void)
+{
+ return platform_driver_register(&amba_bus_acpi_driver);
+}
+
+postcore_initcall(acpi_amba_bus_init);
+
+MODULE_AUTHOR("Brandon Anderson <brandon.anderson@amd.com>");
+MODULE_DESCRIPTION("ACPI Connector Resource for AMBA bus");
+MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:amba-acpi");
+
+#endif /* CONFIG_ACPI */
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index 0fc56ab6e844..1b9ad23409d6 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -15,6 +15,9 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
/*
* DOC: basic fixed-rate clock that cannot gate
@@ -133,5 +136,82 @@ void of_fixed_clk_setup(struct device_node *node)
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
-CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
#endif
+
+#ifdef CONFIG_ACPI
+static int fixed_clk_probe_acpi(struct platform_device *pdev)
+{
+ struct clk *clk = ERR_PTR(-ENODEV);
+ struct acpi_device *adev;
+ acpi_handle handle;
+ u64 rate = 0;
+ int ret;
+
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ ret = acpi_bus_get_device(handle, &adev);
+ if (ret)
+ return -ENODEV;
+
+ ret = acpi_dev_get_property_u64(adev, "clock-frequency", &rate);
+ if (ret)
+ return -ENODEV;
+
+ clk = clk_register_fixed_rate(NULL, dev_name(&pdev->dev), NULL,
+ CLK_IS_ROOT, rate);
+ if (IS_ERR(clk))
+ return -ENODEV;
+
+ return clk_register_clkdev(clk, NULL, dev_name(&pdev->dev));
+}
+#else
+static inline int fixed_clk_probe_acpi(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_ACPI */
+
+static int fixed_clk_probe(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node)
+ of_fixed_clk_setup(pdev->dev.of_node);
+ else if (ACPI_HANDLE(&pdev->dev))
+ return fixed_clk_probe_acpi(pdev);
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct of_device_id fixed_clk_match[] = {
+ { .compatible = "fixed-clock" },
+ {}
+};
+
+static const struct acpi_device_id fixed_clk_acpi_match[] = {
+ { "LNRO0008", 0 },
+ { },
+};
+
+static struct platform_driver fixed_clk_driver = {
+ .driver = {
+ .name = "fixed-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = fixed_clk_match,
+ .acpi_match_table = ACPI_PTR(fixed_clk_acpi_match),
+ },
+ .probe = fixed_clk_probe,
+};
+
+static int __init fixed_clk_init(void)
+{
+ return platform_driver_register(&fixed_clk_driver);
+}
+
+/**
+ * fixed clock will used for AMBA bus, UART and etc, so it should be
+ * initialized early enough.
+ */
+postcore_initcall(fixed_clk_init);
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 9e21e4fc9599..e2cd6aa46e5e 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/vexpress.h>
+#include <linux/acpi.h>
#define SYS_ID 0x000
#define SYS_SW 0x004
@@ -55,15 +56,66 @@
static void __iomem *__vexpress_sysreg_base;
+#ifdef CONFIG_ACPI
+static acpi_status check_vexpress_resource(struct acpi_resource *res,
+ void *data)
+{
+ struct resource *vexpress_res = data;
+
+ if (!acpi_dev_resource_memory(res, vexpress_res))
+ pr_err("Failed to map vexpress memory resource\n");
+
+ __vexpress_sysreg_base = ioremap(vexpress_res->start,
+ resource_size(vexpress_res));
+ if (__vexpress_sysreg_base)
+ return AE_CTRL_TERMINATE;
+
+ return AE_OK;
+}
+
+static acpi_status find_vexpress_resource(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ struct resource *vexpress_res = context;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS,
+ check_vexpress_resource, context);
+
+ if (vexpress_res->flags)
+ return AE_CTRL_TERMINATE;
+
+ return AE_OK;
+}
+
+static void acpi_vexpress_sysreg_base(void)
+{
+ struct resource vexpress_res;
+
+ acpi_get_devices("LNRO0009", find_vexpress_resource, &vexpress_res,
+ NULL);
+}
+#else
+static inline void acpi_vexpress_sysreg_base(void)
+{
+}
+#endif
+
static void __iomem *vexpress_sysreg_base(void)
{
- if (!__vexpress_sysreg_base) {
- struct device_node *node = of_find_compatible_node(NULL, NULL,
- "arm,vexpress-sysreg");
+ struct device_node *node;
+
+ if (__vexpress_sysreg_base)
+ goto ret;
+ node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
+ if (node) {
__vexpress_sysreg_base = of_iomap(node, 0);
+ goto ret;
}
+ acpi_vexpress_sysreg_base();
+
+ret:
WARN_ON(!__vexpress_sysreg_base);
return __vexpress_sysreg_base;
@@ -255,10 +307,18 @@ static const struct of_device_id vexpress_sysreg_match[] = {
{},
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id vexpress_sysreg_acpi_match[] = {
+ { "LNRO0009", },
+ { }
+};
+#endif
+
static struct platform_driver vexpress_sysreg_driver = {
.driver = {
.name = "vexpress-sysreg",
.of_match_table = vexpress_sysreg_match,
+ .acpi_match_table = ACPI_PTR(vexpress_sysreg_acpi_match),
},
.probe = vexpress_sysreg_probe,
};
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 21b2874a303b..69a44c996f20 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -74,6 +74,15 @@ config MTD_PHYSMAP_OF
physically into the CPU's memory. The mapping description here is
taken from OF device tree.
+config MTD_PHYSMAP_ACPI
+ tristate "Flash device in physical memory map based on ACPI description"
+ depends on ACPI && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
+ help
+ This provides a 'mapping' driver which allows the NOR Flash and
+ ROM driver code to communicate with chips which are mapped
+ physically into the CPU's memory. The mapping description here is
+ taken from DSDT ACPI table.
+
config MTD_PMC_MSP_EVM
tristate "CFI Flash device mapped on PMC-Sierra MSP"
depends on PMC_MSP && MTD_CFI
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 141c91a5b24c..379cfff569c5 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
+obj-$(CONFIG_MTD_PHYSMAP_ACPI) += physmap_acpi.o
obj-$(CONFIG_MTD_PISMO) += pismo.o
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
diff --git a/drivers/mtd/maps/physmap_acpi.c b/drivers/mtd/maps/physmap_acpi.c
new file mode 100644
index 000000000000..f425dfd27a7a
--- /dev/null
+++ b/drivers/mtd/maps/physmap_acpi.c
@@ -0,0 +1,372 @@
+/*
+ * Flash mappings described by the ACPI
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ * Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * Revised to handle ACPI style flash binding by:
+ * Copyright (C) 2013 Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+struct acpi_flash_list {
+ struct mtd_info *mtd;
+ struct map_info map;
+ struct resource *res;
+};
+
+struct acpi_flash {
+ struct mtd_info *cmtd;
+ int list_size; /* number of elements in acpi_flash_list */
+ struct acpi_flash_list list[0];
+};
+
+static const char * const rom_probe_types[] = {
+ "cfi_probe", "jedec_probe", "map_rom" };
+
+/* Helper function to handle probing of the obsolete "direct-mapped"
+ * compatible binding, which has an extra "probe-type" property
+ * describing the type of flash probe necessary. */
+static struct mtd_info *obsolete_probe(struct platform_device *dev,
+ struct map_info *map)
+{
+ struct acpi_dsm_entry entry;
+ struct mtd_info *mtd;
+ acpi_handle handler;
+ char *acpi_probe;
+ int i, err, len;
+
+ handler = ACPI_HANDLE(&dev->dev);
+ dev_warn(&dev->dev, "ACPI uses obsolete \"direct-mapped\" flash "
+ "binding\n");
+
+ err = acpi_dsm_lookup_value(handler, "probe-type", 0, &entry);
+ if (err || entry.value == NULL) {
+ for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
+ mtd = do_map_probe(rom_probe_types[i], map);
+ if (mtd)
+ return mtd;
+ }
+ return NULL;
+ }
+
+ len = strlen(entry.value) + 1;
+ acpi_probe = devm_kzalloc(&dev->dev, len, GFP_KERNEL);
+ strncpy(acpi_probe, entry.value, len);
+ kfree(entry.key);
+ kfree(entry.value);
+
+ if (strcmp(acpi_probe, "CFI") == 0) {
+ return do_map_probe("cfi_probe", map);
+ } else if (strcmp(acpi_probe, "JEDEC") == 0) {
+ return do_map_probe("jedec_probe", map);
+ } else {
+ if (strcmp(acpi_probe, "ROM") != 0)
+ dev_warn(&dev->dev, "obsolete_probe: don't know probe "
+ "type '%s', mapping as rom\n", acpi_probe);
+ return do_map_probe("mtd_rom", map);
+ }
+}
+
+/* When partitions are set we look for a linux,part-probe property which
+ specifies the list of partition probers to use. If none is given then the
+ default is use. These take precedence over other device tree
+ information. */
+static const char * const part_probe_types_def[] = {
+ "cmdlinepart", "RedBoot", NULL };
+
+static const char * const *acpi_get_part_probes(struct device *dev)
+{
+ struct acpi_dsm_entry entry;
+ const char **res;
+ int cplen, err, len;
+ unsigned int count = 0, i;
+ char *cp = NULL;
+
+ acpi_handle handler = ACPI_HANDLE(dev);
+
+ /* Get space separated strings */
+ err = acpi_dsm_lookup_value(handler, "linux,part-probe", 0, &entry);
+ if (err || entry.value == NULL)
+ return part_probe_types_def;
+
+ len = strlen(entry.value) + 1;
+ cp = devm_kzalloc(dev, len, GFP_KERNEL);
+ strncpy(cp, entry.value, len);
+ kfree(entry.key);
+ kfree(entry.value);
+
+ cplen = strlen(cp);
+ for (i = 0; i != cplen; i++)
+ if (cp[i] == ' ')
+ count++;
+
+ /* Create the table with references to strings */
+ res = kzalloc((count + 1) * sizeof(char *), GFP_KERNEL);
+ for (i = 0; i < count + 1; i++) {
+ res[i] = cp;
+ cp = strnchr(cp, cplen, ' ');
+ if (cp == NULL)
+ break;
+
+ *cp++ = '\0';
+ cplen = strlen(cp);
+ }
+ return res;
+}
+
+static void acpi_free_probes(const char * const *probes)
+{
+ if (probes != part_probe_types_def)
+ kfree(probes);
+}
+
+static const struct acpi_device_id acpi_flash_match[];
+static int acpi_flash_remove(struct platform_device *dev);
+
+static int acpi_flash_probe(struct platform_device *dev)
+{
+ const char * const *part_probe_types;
+ const struct acpi_device_id *id;
+ resource_size_t res_size;
+ struct acpi_flash *info;
+ const char *probe_type;
+ struct resource *res;
+ acpi_handle handler;
+ int err = 0, i;
+ int bank_width = 0, map_indirect = 0;
+ struct mtd_info **mtd_list = NULL;
+ char *mtd_name = NULL;
+ int len, count = 0;
+ struct acpi_dsm_entry entry;
+
+ handler = ACPI_HANDLE(&dev->dev);
+
+ id = acpi_match_device(acpi_flash_match, &dev->dev);
+ if (!id)
+ return -ENODEV;
+
+ probe_type = (const char *)id->driver_data;
+
+ err = acpi_dsm_lookup_value(handler, "linux,mtd-name", 0, &entry);
+ if (err == 0 && entry.value) {
+ len = strlen(entry.value) + 1;
+ mtd_name = devm_kzalloc(&dev->dev, len, GFP_KERNEL);
+ strncpy(mtd_name, entry.value, len);
+ kfree(entry.key);
+ kfree(entry.value);
+ }
+
+ err = acpi_dsm_lookup_value(handler, "no-unaligned-direct-access",
+ 0, &entry);
+ if (err == 0 && kstrtoint(entry.value, 0, &map_indirect) == 0) {
+ kfree(entry.key);
+ kfree(entry.value);
+ }
+
+ while (platform_get_resource(dev, IORESOURCE_MEM, count))
+ count++;
+
+ if (!count) {
+ dev_err(&dev->dev, "No resources found for %s device\n",
+ dev_name(&dev->dev));
+ err = -ENXIO;
+ goto err_flash_remove;
+ }
+
+ info = devm_kzalloc(&dev->dev,
+ sizeof(struct acpi_flash) +
+ sizeof(struct acpi_flash_list) * count, GFP_KERNEL);
+ if (!info) {
+ err = -ENOMEM;
+ goto err_flash_remove;
+ }
+
+ dev_set_drvdata(&dev->dev, info);
+
+ mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
+ if (!mtd_list)
+ goto err_flash_remove;
+
+ for (i = 0; i < count; i++) {
+ res = platform_get_resource(dev, IORESOURCE_MEM, i);
+ dev_dbg(&dev->dev, "resource[%d]: address 0x%lx size 0x%lx\n",
+ i, (long)res->start, (long)resource_size(res));
+
+ res_size = resource_size(res);
+ info->list[i].res = request_mem_region(res->start, res_size,
+ dev_name(&dev->dev));
+ if (!info->list[i].res) {
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ /* Mandatory property */
+ err = acpi_dsm_lookup_value(handler, "bank-width", 0, &entry);
+ if (err || kstrtoint(entry.value, 0, &bank_width) != 0) {
+ dev_err(&dev->dev,
+ "Can't get bank width from DSDT\n");
+ goto err_out;
+ }
+ kfree(entry.key);
+ kfree(entry.value);
+
+ info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
+ info->list[i].map.phys = res->start;
+ info->list[i].map.size = res_size;
+ info->list[i].map.bankwidth = bank_width;
+ info->list[i].map.virt = ioremap(info->list[i].map.phys,
+ info->list[i].map.size);
+ if (!info->list[i].map.virt) {
+ dev_err(&dev->dev, "Failed to ioremap() flash region\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ simple_map_init(&info->list[i].map);
+
+ /*
+ * On some platforms (e.g. MPC5200) a direct 1:1 mapping
+ * may cause problems with JFFS2 usage, as the local bus (LPB)
+ * doesn't support unaligned accesses as implemented in the
+ * JFFS2 code via memcpy(). By setting NO_XIP, the
+ * flash will not be exposed directly to the MTD users
+ * (e.g. JFFS2) any more.
+ */
+ if (map_indirect)
+ info->list[i].map.phys = NO_XIP;
+
+ if (probe_type) {
+ info->list[i].mtd = do_map_probe(probe_type,
+ &info->list[i].map);
+ } else {
+ info->list[i].mtd = obsolete_probe(dev,
+ &info->list[i].map);
+ }
+
+ if (!info->list[i].mtd) {
+ dev_err(&dev->dev, "do_map_probe() failed\n");
+ err = -ENXIO;
+ goto err_out;
+ } else
+ info->list_size++;
+
+ info->list[i].mtd->owner = THIS_MODULE;
+ info->list[i].mtd->dev.parent = &dev->dev;
+ mtd_list[i] = info->list[i].mtd;
+ }
+
+ info->cmtd = NULL;
+ if (info->list_size == 1) {
+ info->cmtd = info->list[0].mtd;
+ } else if (info->list_size > 1) {
+ /*
+ * We detected multiple devices. Concatenate them together.
+ */
+ info->cmtd = mtd_concat_create(mtd_list, info->list_size,
+ dev_name(&dev->dev));
+ }
+ if (info->cmtd == NULL) {
+ err = -ENXIO;
+ goto err_out;
+ }
+
+ part_probe_types = acpi_get_part_probes(&dev->dev);
+ mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
+ NULL, 0);
+ acpi_free_probes(part_probe_types);
+
+ kfree(mtd_list);
+
+ return 0;
+
+err_out:
+ kfree(mtd_list);
+err_flash_remove:
+ acpi_flash_remove(dev);
+
+ return err;
+}
+
+static int acpi_flash_remove(struct platform_device *dev)
+{
+ struct acpi_flash *info;
+ int i;
+
+ info = dev_get_drvdata(&dev->dev);
+ if (!info)
+ return 0;
+ dev_set_drvdata(&dev->dev, NULL);
+
+ if (info->cmtd != info->list[0].mtd) {
+ mtd_device_unregister(info->cmtd);
+ mtd_concat_destroy(info->cmtd);
+ }
+
+ if (info->cmtd)
+ mtd_device_unregister(info->cmtd);
+
+ for (i = 0; i < info->list_size; i++) {
+ if (info->list[i].mtd)
+ map_destroy(info->list[i].mtd);
+
+ if (info->list[i].map.virt)
+ iounmap(info->list[i].map.virt);
+
+ if (info->list[i].res) {
+ release_resource(info->list[i].res);
+ kfree(info->list[i].res);
+ }
+ }
+
+ return 0;
+}
+
+static const struct acpi_device_id acpi_flash_match[] = {
+ { "LNRO0015", (unsigned long)"cfi_probe"},
+ { "LNRO0016", (unsigned long)"jedec_probe"},
+ { "LNRO0017", (unsigned long)"map_ram"},
+ { "LNRO0018", (unsigned long)"direct-mapped"},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, acpi_flash_match);
+
+static struct platform_driver acpi_flash_driver = {
+ .driver = {
+ .name = "acpi-flash",
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(acpi_flash_match),
+ },
+ .probe = acpi_flash_probe,
+ .remove = acpi_flash_remove,
+};
+
+module_platform_driver(acpi_flash_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomasz Nowicki <tomasz.nowicki@linaro.org>");
+MODULE_DESCRIPTION("ACPI based MTD map driver");
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index bcaa41af1e62..ebad8727b327 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -81,6 +81,7 @@ static const char version[] =
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/acpi.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -2408,6 +2409,14 @@ static struct dev_pm_ops smc_drv_pm_ops = {
.resume = smc_drv_resume,
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id smc91x_acpi_match[] = {
+ { "LNRO0003", },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, smc91x_acpi_match);
+#endif
+
static struct platform_driver smc_driver = {
.probe = smc_drv_probe,
.remove = smc_drv_remove,
@@ -2416,6 +2425,7 @@ static struct platform_driver smc_driver = {
.owner = THIS_MODULE,
.pm = &smc_drv_pm_ops,
.of_match_table = of_match_ptr(smc91x_match),
+ .acpi_match_table = ACPI_PTR(smc91x_acpi_match),
},
};
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 5e13fa5524ae..2b13ad2a827f 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -59,6 +59,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
+#include <linux/acpi.h>
#include "smsc911x.h"
#define SMSC_CHIPNAME "smsc911x"
@@ -2369,9 +2370,77 @@ static inline int smsc911x_probe_config_dt(
}
#endif /* CONFIG_OF */
+#ifdef CONFIG_ACPI
+static int smsc911x_probe_config_acpi(struct smsc911x_platform_config *config,
+ acpi_handle *ahandle)
+{
+ struct acpi_device *adev;
+ u32 width = 0, prop = 0;
+ const char *phy_mode = NULL;
+ int ret, i;
+
+ if (!ahandle)
+ return -ENODEV;
+
+ ret = acpi_bus_get_device(ahandle, &adev);
+ if (ret)
+ return -ENODEV;
+
+ acpi_dev_get_property_string(adev, "phy-mode", &phy_mode);
+ if (phy_mode) {
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
+ if (!strcasecmp(phy_mode, phy_modes(i)))
+ break;
+
+ config->phy_interface = i;
+ }
+
+ acpi_dev_get_property_u32(adev, "reg-shift", &config->shift);
+
+ acpi_dev_get_property_u32(adev, "reg-io-width", &width);
+ if (width == 4)
+ config->flags |= SMSC911X_USE_32BIT;
+ else
+ config->flags |= SMSC911X_USE_16BIT;
+
+ acpi_dev_get_property_u32(adev, "smsc,irq-active-high", &prop);
+ if(prop)
+ config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
+
+ prop = 0;
+ acpi_dev_get_property_u32(adev, "smsc,irq-push-pull", &prop);
+ if (prop)
+ config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL;
+
+ prop = 0;
+ acpi_dev_get_property_u32(adev, "smsc,force-internal-phy", &prop);
+ if (prop)
+ config->flags |= SMSC911X_FORCE_INTERNAL_PHY;
+
+ prop = 0;
+ acpi_dev_get_property_u32(adev, "smsc,force-external-phy", &prop);
+ if (prop)
+ config->flags |= SMSC911X_FORCE_EXTERNAL_PHY;
+
+ prop = 0;
+ acpi_dev_get_property_u32(adev, "smsc,save-mac-address", &prop);
+ if (prop)
+ config->flags |= SMSC911X_SAVE_MAC_ADDRESS;
+
+ return 0;
+}
+#else
+static int smsc911x_probe_config_acpi(struct smsc911x_platform_config *config,
+ acpi_handle *ahandle)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_ACPI */
+
static int smsc911x_drv_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ acpi_handle *ahandle = ACPI_HANDLE(&pdev->dev);
struct net_device *dev;
struct smsc911x_data *pdata;
struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev);
@@ -2436,6 +2505,9 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
}
retval = smsc911x_probe_config_dt(&pdata->config, np);
+ if (retval)
+ retval = smsc911x_probe_config_acpi(&pdata->config, ahandle);
+
if (retval && config) {
/* copy config parameters across to pdata */
memcpy(&pdata->config, config, sizeof(pdata->config));
@@ -2606,6 +2678,11 @@ static const struct of_device_id smsc911x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
#endif
+static const struct acpi_device_id smsc911x_acpi_ids[] = {
+ { "LNRO001B", },
+ { }
+};
+
static struct platform_driver smsc911x_driver = {
.probe = smsc911x_drv_probe,
.remove = smsc911x_drv_remove,
@@ -2614,6 +2691,7 @@ static struct platform_driver smsc911x_driver = {
.owner = THIS_MODULE,
.pm = SMSC911X_PM_OPS,
.of_match_table = of_match_ptr(smsc911x_dt_ids),
+ .acpi_match_table = ACPI_PTR(smsc911x_acpi_ids),
},
};
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 66d2ae21e78e..a90f4b1228a4 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -43,6 +43,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/amba/acpi.h>
/*
* This macro is used to define some register default values.
@@ -2059,6 +2060,49 @@ pl022_platform_data_dt_get(struct device *dev)
return pd;
}
+#ifdef CONFIG_ACPI
+static struct pl022_ssp_controller *
+acpi_pl022_get_platform_data(struct device *dev)
+{
+ struct pl022_ssp_controller *pd, *ret;
+ struct acpi_amba_dsm_entry entry;
+
+ pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "cannot allocate platform data memory\n");
+ return NULL;
+ }
+ ret = pd;
+
+ pd->bus_id = -1;
+ pd->enable_dma = 1;
+ if (acpi_amba_dsm_lookup(ACPI_HANDLE(dev), "num-cs", 0, &entry) == 0) {
+ if (kstrtou8(entry.value, 0, &pd->num_chipselect) != 0) {
+ dev_err(dev, "invalid 'num-cs' in ACPI definition\n");
+ ret = NULL;
+ }
+ kfree(entry.key);
+ kfree(entry.value);
+ }
+ if (acpi_amba_dsm_lookup(ACPI_HANDLE(dev),
+ "autosuspend-delay", 0, &entry) == 0) {
+ if (kstrtoint(entry.value, 0, &pd->autosuspend_delay) != 0) {
+ dev_err(dev, "invalid 'autosuspend-delay' in ACPI definition\n");
+ ret = NULL;
+ }
+ kfree(entry.key);
+ kfree(entry.value);
+ }
+ if (acpi_amba_dsm_lookup(ACPI_HANDLE(dev), "rt", 0, &entry) == 0) {
+ pd->rt = (entry.value && strcmp(entry.value, "1") == 0);
+ kfree(entry.key);
+ kfree(entry.value);
+ }
+
+ return ret;
+}
+#endif
+
static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
@@ -2071,6 +2115,11 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
dev_info(&adev->dev,
"ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
+#ifdef CONFIG_ACPI
+ if (!platform_info && ACPI_HANDLE(dev))
+ platform_info = acpi_pl022_get_platform_data(dev);
+ else
+#endif
if (!platform_info && IS_ENABLED(CONFIG_OF))
platform_info = pl022_platform_data_dt_get(dev);
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index c600ccfd6922..10c4775368b7 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -100,8 +100,7 @@
#include <linux/virtio_config.h>
#include <linux/virtio_mmio.h>
#include <linux/virtio_ring.h>
-
-
+#include <linux/acpi.h>
/* The alignment to use between consumer and producer parts of vring.
* Currently hardcoded to the page size. */
@@ -637,6 +636,14 @@ static struct of_device_id virtio_mmio_match[] = {
};
MODULE_DEVICE_TABLE(of, virtio_mmio_match);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id virtio_mmio_acpi_match[] = {
+ { "LNRO0005", },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match);
+#endif
+
static struct platform_driver virtio_mmio_driver = {
.probe = virtio_mmio_probe,
.remove = virtio_mmio_remove,
@@ -644,6 +651,7 @@ static struct platform_driver virtio_mmio_driver = {
.name = "virtio-mmio",
.owner = THIS_MODULE,
.of_match_table = virtio_mmio_match,
+ .acpi_match_table = ACPI_PTR(virtio_mmio_acpi_match),
},
};