summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/mfd-core.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2014-09-16 14:52:36 +0300
committerLee Jones <lee.jones@linaro.org>2014-09-26 08:24:05 +0100
commit6ab3430129e258ea31dd214adf1c760dfafde67a (patch)
treeff8b82f6039f2d7b2761da82ab5ca5ac37f27114 /drivers/mfd/mfd-core.c
parent7be180cc7a0c5768a984126d9468afc82dcf93a2 (diff)
downloadlinux-6ab3430129e258ea31dd214adf1c760dfafde67a.tar.bz2
mfd: Add ACPI support
If an MFD device is backed by ACPI namespace, we should allow subdevice drivers to access their corresponding ACPI companion devices through normal means (e.g using ACPI_COMPANION()). This patch adds such support to the MFD core. If the MFD parent device does not specify any ACPI _HID/_CID for the child device, the child device will share the parent ACPI companion device. Otherwise the child device will be assigned with the corresponding ACPI companion, if found in the namespace below the parent. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Darren Hart <dvhart@linux.intel.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd/mfd-core.c')
-rw-r--r--drivers/mfd/mfd-core.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 5d0fbe1e097a..f3338fe9d069 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -78,6 +78,44 @@ static int mfd_platform_add_cell(struct platform_device *pdev,
return 0;
}
+#if IS_ENABLED(CONFIG_ACPI)
+static void mfd_acpi_add_device(const struct mfd_cell *cell,
+ struct platform_device *pdev)
+{
+ struct acpi_device *parent_adev;
+ struct acpi_device *adev;
+
+ parent_adev = ACPI_COMPANION(pdev->dev.parent);
+ if (!parent_adev)
+ return;
+
+ /*
+ * MFD child device gets its ACPI handle either from the ACPI
+ * device directly under the parent that matches the acpi_pnpid or
+ * it will use the parent handle if is no acpi_pnpid is given.
+ */
+ adev = parent_adev;
+ if (cell->acpi_pnpid) {
+ struct acpi_device_id ids[2] = {};
+ struct acpi_device *child_adev;
+
+ strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id));
+ list_for_each_entry(child_adev, &parent_adev->children, node)
+ if (acpi_match_device_ids(child_adev, ids)) {
+ adev = child_adev;
+ break;
+ }
+ }
+
+ ACPI_COMPANION_SET(&pdev->dev, adev);
+}
+#else
+static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
+ struct platform_device *pdev)
+{
+}
+#endif
+
static int mfd_add_device(struct device *parent, int id,
const struct mfd_cell *cell, atomic_t *usage_count,
struct resource *mem_base,
@@ -119,6 +157,8 @@ static int mfd_add_device(struct device *parent, int id,
}
}
+ mfd_acpi_add_device(cell, pdev);
+
if (cell->pdata_size) {
ret = platform_device_add_data(pdev,
cell->platform_data, cell->pdata_size);