aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-07-27 11:03:57 -0400
committerLee Jones <lee.jones@linaro.org>2015-07-28 03:50:42 -0400
commit712e960f0ee9337f3473ba3de2bcfc7e87b7c5a4 (patch)
tree13e6d1dffce17d0c4cc466e484599cfc38994a05 /drivers
parent13b2c4a0c3b1cd37ee6bcfbb5b6e2b94e9a75364 (diff)
ACPI / PM: Attach ACPI power domain only once
Some devices, like MFD subdevices, share a single ACPI companion device so that they are able to access their resources and children. However, currently all these subdevices are attached to the ACPI power domain and this might cause that the power methods for the companion device get called more than once. In order to solve this we attach the ACPI power domain only to the first physical device that is bound to the ACPI companion device. In case of MFD devices, this is the parent MFD device itself. Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/device_pm.c8
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/scan.c46
3 files changed, 40 insertions, 16 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 717afcdb5f4a..08dc3ec7e892 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1123,6 +1123,14 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
1123 if (dev->pm_domain) 1123 if (dev->pm_domain)
1124 return -EEXIST; 1124 return -EEXIST;
1125 1125
1126 /*
1127 * Only attach the power domain to the first device if the
1128 * companion is shared by multiple. This is to prevent doing power
1129 * management twice.
1130 */
1131 if (!acpi_device_is_first_physical_node(adev, dev))
1132 return -EBUSY;
1133
1126 acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); 1134 acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
1127 dev->pm_domain = &acpi_general_pm_domain; 1135 dev->pm_domain = &acpi_general_pm_domain;
1128 if (power_on) { 1136 if (power_on) {
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4683a96932b9..f6aefe984941 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -97,6 +97,8 @@ void acpi_device_add_finalize(struct acpi_device *device);
97void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); 97void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
98bool acpi_device_is_present(struct acpi_device *adev); 98bool acpi_device_is_present(struct acpi_device *adev);
99bool acpi_device_is_battery(struct acpi_device *adev); 99bool acpi_device_is_battery(struct acpi_device *adev);
100bool acpi_device_is_first_physical_node(struct acpi_device *adev,
101 const struct device *dev);
100 102
101/* -------------------------------------------------------------------------- 103/* --------------------------------------------------------------------------
102 Power Resource 104 Power Resource
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ec256352f423..89ff6d2eef8a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -226,6 +226,35 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
226 return len; 226 return len;
227} 227}
228 228
229/**
230 * acpi_device_is_first_physical_node - Is given dev first physical node
231 * @adev: ACPI companion device
232 * @dev: Physical device to check
233 *
234 * Function checks if given @dev is the first physical devices attached to
235 * the ACPI companion device. This distinction is needed in some cases
236 * where the same companion device is shared between many physical devices.
237 *
238 * Note that the caller have to provide valid @adev pointer.
239 */
240bool acpi_device_is_first_physical_node(struct acpi_device *adev,
241 const struct device *dev)
242{
243 bool ret = false;
244
245 mutex_lock(&adev->physical_node_lock);
246 if (!list_empty(&adev->physical_node_list)) {
247 const struct acpi_device_physical_node *node;
248
249 node = list_first_entry(&adev->physical_node_list,
250 struct acpi_device_physical_node, node);
251 ret = node->dev == dev;
252 }
253 mutex_unlock(&adev->physical_node_lock);
254
255 return ret;
256}
257
229/* 258/*
230 * acpi_companion_match() - Can we match via ACPI companion device 259 * acpi_companion_match() - Can we match via ACPI companion device
231 * @dev: Device in question 260 * @dev: Device in question
@@ -250,7 +279,6 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
250static struct acpi_device *acpi_companion_match(const struct device *dev) 279static struct acpi_device *acpi_companion_match(const struct device *dev)
251{ 280{
252 struct acpi_device *adev; 281 struct acpi_device *adev;
253 struct mutex *physical_node_lock;
254 282
255 adev = ACPI_COMPANION(dev); 283 adev = ACPI_COMPANION(dev);
256 if (!adev) 284 if (!adev)
@@ -259,21 +287,7 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
259 if (list_empty(&adev->pnp.ids)) 287 if (list_empty(&adev->pnp.ids))
260 return NULL; 288 return NULL;
261 289
262 physical_node_lock = &adev->physical_node_lock; 290 return acpi_device_is_first_physical_node(adev, dev) ? adev : NULL;
263 mutex_lock(physical_node_lock);
264 if (list_empty(&adev->physical_node_list)) {
265 adev = NULL;
266 } else {
267 const struct acpi_device_physical_node *node;
268
269 node = list_first_entry(&adev->physical_node_list,
270 struct acpi_device_physical_node, node);
271 if (node->dev != dev)
272 adev = NULL;
273 }
274 mutex_unlock(physical_node_lock);
275
276 return adev;
277} 291}
278 292
279static int __acpi_device_uevent_modalias(struct acpi_device *adev, 293static int __acpi_device_uevent_modalias(struct acpi_device *adev,