1*ef27bed1SRafael J. Wysocki /* 2*ef27bed1SRafael J. Wysocki * drivers/base/power/common.c - Common device power management code. 3*ef27bed1SRafael J. Wysocki * 4*ef27bed1SRafael J. Wysocki * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp. 5*ef27bed1SRafael J. Wysocki * 6*ef27bed1SRafael J. Wysocki * This file is released under the GPLv2. 7*ef27bed1SRafael J. Wysocki */ 8*ef27bed1SRafael J. Wysocki 9*ef27bed1SRafael J. Wysocki #include <linux/init.h> 10*ef27bed1SRafael J. Wysocki #include <linux/kernel.h> 11*ef27bed1SRafael J. Wysocki #include <linux/module.h> 12*ef27bed1SRafael J. Wysocki #include <linux/slab.h> 13*ef27bed1SRafael J. Wysocki #include <linux/device.h> 14*ef27bed1SRafael J. Wysocki #include <linux/pm_runtime.h> 15*ef27bed1SRafael J. Wysocki 16*ef27bed1SRafael J. Wysocki /** 17*ef27bed1SRafael J. Wysocki * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device. 18*ef27bed1SRafael J. Wysocki * @dev: Device to handle. 19*ef27bed1SRafael J. Wysocki * 20*ef27bed1SRafael J. Wysocki * If power.subsys_data is NULL, point it to a new object, otherwise increment 21*ef27bed1SRafael J. Wysocki * its reference counter. Return 1 if a new object has been created, otherwise 22*ef27bed1SRafael J. Wysocki * return 0 or error code. 23*ef27bed1SRafael J. Wysocki */ 24*ef27bed1SRafael J. Wysocki int dev_pm_get_subsys_data(struct device *dev) 25*ef27bed1SRafael J. Wysocki { 26*ef27bed1SRafael J. Wysocki struct pm_subsys_data *psd; 27*ef27bed1SRafael J. Wysocki int ret = 0; 28*ef27bed1SRafael J. Wysocki 29*ef27bed1SRafael J. Wysocki psd = kzalloc(sizeof(*psd), GFP_KERNEL); 30*ef27bed1SRafael J. Wysocki if (!psd) 31*ef27bed1SRafael J. Wysocki return -ENOMEM; 32*ef27bed1SRafael J. Wysocki 33*ef27bed1SRafael J. Wysocki spin_lock_irq(&dev->power.lock); 34*ef27bed1SRafael J. Wysocki 35*ef27bed1SRafael J. Wysocki if (dev->power.subsys_data) { 36*ef27bed1SRafael J. Wysocki dev->power.subsys_data->refcount++; 37*ef27bed1SRafael J. Wysocki } else { 38*ef27bed1SRafael J. Wysocki spin_lock_init(&psd->lock); 39*ef27bed1SRafael J. Wysocki psd->refcount = 1; 40*ef27bed1SRafael J. Wysocki dev->power.subsys_data = psd; 41*ef27bed1SRafael J. Wysocki pm_clk_init(dev); 42*ef27bed1SRafael J. Wysocki psd = NULL; 43*ef27bed1SRafael J. Wysocki ret = 1; 44*ef27bed1SRafael J. Wysocki } 45*ef27bed1SRafael J. Wysocki 46*ef27bed1SRafael J. Wysocki spin_unlock_irq(&dev->power.lock); 47*ef27bed1SRafael J. Wysocki 48*ef27bed1SRafael J. Wysocki /* kfree() verifies that its argument is nonzero. */ 49*ef27bed1SRafael J. Wysocki kfree(psd); 50*ef27bed1SRafael J. Wysocki 51*ef27bed1SRafael J. Wysocki return ret; 52*ef27bed1SRafael J. Wysocki } 53*ef27bed1SRafael J. Wysocki EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data); 54*ef27bed1SRafael J. Wysocki 55*ef27bed1SRafael J. Wysocki /** 56*ef27bed1SRafael J. Wysocki * dev_pm_put_subsys_data - Drop reference to power.subsys_data. 57*ef27bed1SRafael J. Wysocki * @dev: Device to handle. 58*ef27bed1SRafael J. Wysocki * 59*ef27bed1SRafael J. Wysocki * If the reference counter of power.subsys_data is zero after dropping the 60*ef27bed1SRafael J. Wysocki * reference, power.subsys_data is removed. Return 1 if that happens or 0 61*ef27bed1SRafael J. Wysocki * otherwise. 62*ef27bed1SRafael J. Wysocki */ 63*ef27bed1SRafael J. Wysocki int dev_pm_put_subsys_data(struct device *dev) 64*ef27bed1SRafael J. Wysocki { 65*ef27bed1SRafael J. Wysocki struct pm_subsys_data *psd; 66*ef27bed1SRafael J. Wysocki int ret = 0; 67*ef27bed1SRafael J. Wysocki 68*ef27bed1SRafael J. Wysocki spin_lock_irq(&dev->power.lock); 69*ef27bed1SRafael J. Wysocki 70*ef27bed1SRafael J. Wysocki psd = dev_to_psd(dev); 71*ef27bed1SRafael J. Wysocki if (!psd) { 72*ef27bed1SRafael J. Wysocki ret = -EINVAL; 73*ef27bed1SRafael J. Wysocki goto out; 74*ef27bed1SRafael J. Wysocki } 75*ef27bed1SRafael J. Wysocki 76*ef27bed1SRafael J. Wysocki if (--psd->refcount == 0) { 77*ef27bed1SRafael J. Wysocki dev->power.subsys_data = NULL; 78*ef27bed1SRafael J. Wysocki kfree(psd); 79*ef27bed1SRafael J. Wysocki ret = 1; 80*ef27bed1SRafael J. Wysocki } 81*ef27bed1SRafael J. Wysocki 82*ef27bed1SRafael J. Wysocki out: 83*ef27bed1SRafael J. Wysocki spin_unlock_irq(&dev->power.lock); 84*ef27bed1SRafael J. Wysocki 85*ef27bed1SRafael J. Wysocki return ret; 86*ef27bed1SRafael J. Wysocki } 87*ef27bed1SRafael J. Wysocki EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); 88