![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0 0002 /* 0003 * drivers/base/power/common.c - Common device power management code. 0004 * 0005 * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. 0006 */ 0007 #include <linux/kernel.h> 0008 #include <linux/device.h> 0009 #include <linux/export.h> 0010 #include <linux/slab.h> 0011 #include <linux/pm_clock.h> 0012 #include <linux/acpi.h> 0013 #include <linux/pm_domain.h> 0014 0015 #include "power.h" 0016 0017 /** 0018 * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device. 0019 * @dev: Device to handle. 0020 * 0021 * If power.subsys_data is NULL, point it to a new object, otherwise increment 0022 * its reference counter. Return 0 if new object has been created or refcount 0023 * increased, otherwise negative error code. 0024 */ 0025 int dev_pm_get_subsys_data(struct device *dev) 0026 { 0027 struct pm_subsys_data *psd; 0028 0029 psd = kzalloc(sizeof(*psd), GFP_KERNEL); 0030 if (!psd) 0031 return -ENOMEM; 0032 0033 spin_lock_irq(&dev->power.lock); 0034 0035 if (dev->power.subsys_data) { 0036 dev->power.subsys_data->refcount++; 0037 } else { 0038 spin_lock_init(&psd->lock); 0039 psd->refcount = 1; 0040 dev->power.subsys_data = psd; 0041 pm_clk_init(dev); 0042 psd = NULL; 0043 } 0044 0045 spin_unlock_irq(&dev->power.lock); 0046 0047 /* kfree() verifies that its argument is nonzero. */ 0048 kfree(psd); 0049 0050 return 0; 0051 } 0052 EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data); 0053 0054 /** 0055 * dev_pm_put_subsys_data - Drop reference to power.subsys_data. 0056 * @dev: Device to handle. 0057 * 0058 * If the reference counter of power.subsys_data is zero after dropping the 0059 * reference, power.subsys_data is removed. 0060 */ 0061 void dev_pm_put_subsys_data(struct device *dev) 0062 { 0063 struct pm_subsys_data *psd; 0064 0065 spin_lock_irq(&dev->power.lock); 0066 0067 psd = dev_to_psd(dev); 0068 if (!psd) 0069 goto out; 0070 0071 if (--psd->refcount == 0) 0072 dev->power.subsys_data = NULL; 0073 else 0074 psd = NULL; 0075 0076 out: 0077 spin_unlock_irq(&dev->power.lock); 0078 kfree(psd); 0079 } 0080 EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); 0081 0082 /** 0083 * dev_pm_domain_attach - Attach a device to its PM domain. 0084 * @dev: Device to attach. 0085 * @power_on: Used to indicate whether we should power on the device. 0086 * 0087 * The @dev may only be attached to a single PM domain. By iterating through 0088 * the available alternatives we try to find a valid PM domain for the device. 0089 * As attachment succeeds, the ->detach() callback in the struct dev_pm_domain 0090 * should be assigned by the corresponding attach function. 0091 * 0092 * This function should typically be invoked from subsystem level code during 0093 * the probe phase. Especially for those that holds devices which requires 0094 * power management through PM domains. 0095 * 0096 * Callers must ensure proper synchronization of this function with power 0097 * management callbacks. 0098 * 0099 * Returns 0 on successfully attached PM domain, or when it is found that the 0100 * device doesn't need a PM domain, else a negative error code. 0101 */ 0102 int dev_pm_domain_attach(struct device *dev, bool power_on) 0103 { 0104 int ret; 0105 0106 if (dev->pm_domain) 0107 return 0; 0108 0109 ret = acpi_dev_pm_attach(dev, power_on); 0110 if (!ret) 0111 ret = genpd_dev_pm_attach(dev); 0112 0113 return ret < 0 ? ret : 0; 0114 } 0115 EXPORT_SYMBOL_GPL(dev_pm_domain_attach); 0116 0117 /** 0118 * dev_pm_domain_attach_by_id - Associate a device with one of its PM domains. 0119 * @dev: The device used to lookup the PM domain. 0120 * @index: The index of the PM domain. 0121 * 0122 * As @dev may only be attached to a single PM domain, the backend PM domain 0123 * provider creates a virtual device to attach instead. If attachment succeeds, 0124 * the ->detach() callback in the struct dev_pm_domain are assigned by the 0125 * corresponding backend attach function, as to deal with detaching of the 0126 * created virtual device. 0127 * 0128 * This function should typically be invoked by a driver during the probe phase, 0129 * in case its device requires power management through multiple PM domains. The 0130 * driver may benefit from using the received device, to configure device-links 0131 * towards its original device. Depending on the use-case and if needed, the 0132 * links may be dynamically changed by the driver, which allows it to control 0133 * the power to the PM domains independently from each other. 0134 * 0135 * Callers must ensure proper synchronization of this function with power 0136 * management callbacks. 0137 * 0138 * Returns the virtual created device when successfully attached to its PM 0139 * domain, NULL in case @dev don't need a PM domain, else an ERR_PTR(). 0140 * Note that, to detach the returned virtual device, the driver shall call 0141 * dev_pm_domain_detach() on it, typically during the remove phase. 0142 */ 0143 struct device *dev_pm_domain_attach_by_id(struct device *dev, 0144 unsigned int index) 0145 { 0146 if (dev->pm_domain) 0147 return ERR_PTR(-EEXIST); 0148 0149 return genpd_dev_pm_attach_by_id(dev, index); 0150 } 0151 EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id); 0152 0153 /** 0154 * dev_pm_domain_attach_by_name - Associate a device with one of its PM domains. 0155 * @dev: The device used to lookup the PM domain. 0156 * @name: The name of the PM domain. 0157 * 0158 * For a detailed function description, see dev_pm_domain_attach_by_id(). 0159 */ 0160 struct device *dev_pm_domain_attach_by_name(struct device *dev, 0161 const char *name) 0162 { 0163 if (dev->pm_domain) 0164 return ERR_PTR(-EEXIST); 0165 0166 return genpd_dev_pm_attach_by_name(dev, name); 0167 } 0168 EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_name); 0169 0170 /** 0171 * dev_pm_domain_detach - Detach a device from its PM domain. 0172 * @dev: Device to detach. 0173 * @power_off: Used to indicate whether we should power off the device. 0174 * 0175 * This functions will reverse the actions from dev_pm_domain_attach(), 0176 * dev_pm_domain_attach_by_id() and dev_pm_domain_attach_by_name(), thus it 0177 * detaches @dev from its PM domain. Typically it should be invoked during the 0178 * remove phase, either from subsystem level code or from drivers. 0179 * 0180 * Callers must ensure proper synchronization of this function with power 0181 * management callbacks. 0182 */ 0183 void dev_pm_domain_detach(struct device *dev, bool power_off) 0184 { 0185 if (dev->pm_domain && dev->pm_domain->detach) 0186 dev->pm_domain->detach(dev, power_off); 0187 } 0188 EXPORT_SYMBOL_GPL(dev_pm_domain_detach); 0189 0190 /** 0191 * dev_pm_domain_start - Start the device through its PM domain. 0192 * @dev: Device to start. 0193 * 0194 * This function should typically be called during probe by a subsystem/driver, 0195 * when it needs to start its device from the PM domain's perspective. Note 0196 * that, it's assumed that the PM domain is already powered on when this 0197 * function is called. 0198 * 0199 * Returns 0 on success and negative error values on failures. 0200 */ 0201 int dev_pm_domain_start(struct device *dev) 0202 { 0203 if (dev->pm_domain && dev->pm_domain->start) 0204 return dev->pm_domain->start(dev); 0205 0206 return 0; 0207 } 0208 EXPORT_SYMBOL_GPL(dev_pm_domain_start); 0209 0210 /** 0211 * dev_pm_domain_set - Set PM domain of a device. 0212 * @dev: Device whose PM domain is to be set. 0213 * @pd: PM domain to be set, or NULL. 0214 * 0215 * Sets the PM domain the device belongs to. The PM domain of a device needs 0216 * to be set before its probe finishes (it's bound to a driver). 0217 * 0218 * This function must be called with the device lock held. 0219 */ 0220 void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd) 0221 { 0222 if (dev->pm_domain == pd) 0223 return; 0224 0225 WARN(pd && device_is_bound(dev), 0226 "PM domains can only be changed for unbound devices\n"); 0227 dev->pm_domain = pd; 0228 device_pm_check_callbacks(dev); 0229 } 0230 EXPORT_SYMBOL_GPL(dev_pm_domain_set);
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |