aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/devfreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r--drivers/devfreq/devfreq.c207
1 files changed, 206 insertions, 1 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 984c5e9e7bdd..1d6c803804d5 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -25,6 +25,7 @@
25#include <linux/list.h> 25#include <linux/list.h>
26#include <linux/printk.h> 26#include <linux/printk.h>
27#include <linux/hrtimer.h> 27#include <linux/hrtimer.h>
28#include <linux/of.h>
28#include "governor.h" 29#include "governor.h"
29 30
30static struct class *devfreq_class; 31static struct class *devfreq_class;
@@ -188,6 +189,29 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
188 return ERR_PTR(-ENODEV); 189 return ERR_PTR(-ENODEV);
189} 190}
190 191
192static int devfreq_notify_transition(struct devfreq *devfreq,
193 struct devfreq_freqs *freqs, unsigned int state)
194{
195 if (!devfreq)
196 return -EINVAL;
197
198 switch (state) {
199 case DEVFREQ_PRECHANGE:
200 srcu_notifier_call_chain(&devfreq->transition_notifier_list,
201 DEVFREQ_PRECHANGE, freqs);
202 break;
203
204 case DEVFREQ_POSTCHANGE:
205 srcu_notifier_call_chain(&devfreq->transition_notifier_list,
206 DEVFREQ_POSTCHANGE, freqs);
207 break;
208 default:
209 return -EINVAL;
210 }
211
212 return 0;
213}
214
191/* Load monitoring helper functions for governors use */ 215/* Load monitoring helper functions for governors use */
192 216
193/** 217/**
@@ -199,7 +223,8 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
199 */ 223 */
200int update_devfreq(struct devfreq *devfreq) 224int update_devfreq(struct devfreq *devfreq)
201{ 225{
202 unsigned long freq; 226 struct devfreq_freqs freqs;
227 unsigned long freq, cur_freq;
203 int err = 0; 228 int err = 0;
204 u32 flags = 0; 229 u32 flags = 0;
205 230
@@ -233,10 +258,22 @@ int update_devfreq(struct devfreq *devfreq)
233 flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ 258 flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
234 } 259 }
235 260
261 if (devfreq->profile->get_cur_freq)
262 devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
263 else
264 cur_freq = devfreq->previous_freq;
265
266 freqs.old = cur_freq;
267 freqs.new = freq;
268 devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
269
236 err = devfreq->profile->target(devfreq->dev.parent, &freq, flags); 270 err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
237 if (err) 271 if (err)
238 return err; 272 return err;
239 273
274 freqs.new = freq;
275 devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
276
240 if (devfreq->profile->freq_table) 277 if (devfreq->profile->freq_table)
241 if (devfreq_update_status(devfreq, freq)) 278 if (devfreq_update_status(devfreq, freq))
242 dev_err(&devfreq->dev, 279 dev_err(&devfreq->dev,
@@ -541,6 +578,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
541 goto err_out; 578 goto err_out;
542 } 579 }
543 580
581 srcu_init_notifier_head(&devfreq->transition_notifier_list);
582
544 mutex_unlock(&devfreq->lock); 583 mutex_unlock(&devfreq->lock);
545 584
546 mutex_lock(&devfreq_list_lock); 585 mutex_lock(&devfreq_list_lock);
@@ -639,6 +678,49 @@ struct devfreq *devm_devfreq_add_device(struct device *dev,
639} 678}
640EXPORT_SYMBOL(devm_devfreq_add_device); 679EXPORT_SYMBOL(devm_devfreq_add_device);
641 680
681#ifdef CONFIG_OF
682/*
683 * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
684 * @dev - instance to the given device
685 * @index - index into list of devfreq
686 *
687 * return the instance of devfreq device
688 */
689struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
690{
691 struct device_node *node;
692 struct devfreq *devfreq;
693
694 if (!dev)
695 return ERR_PTR(-EINVAL);
696
697 if (!dev->of_node)
698 return ERR_PTR(-EINVAL);
699
700 node = of_parse_phandle(dev->of_node, "devfreq", index);
701 if (!node)
702 return ERR_PTR(-ENODEV);
703
704 mutex_lock(&devfreq_list_lock);
705 list_for_each_entry(devfreq, &devfreq_list, node) {
706 if (devfreq->dev.parent
707 && devfreq->dev.parent->of_node == node) {
708 mutex_unlock(&devfreq_list_lock);
709 return devfreq;
710 }
711 }
712 mutex_unlock(&devfreq_list_lock);
713
714 return ERR_PTR(-EPROBE_DEFER);
715}
716#else
717struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
718{
719 return ERR_PTR(-ENODEV);
720}
721#endif /* CONFIG_OF */
722EXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_phandle);
723
642/** 724/**
643 * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device() 725 * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
644 * @dev: the device to add devfreq feature. 726 * @dev: the device to add devfreq feature.
@@ -1266,6 +1348,129 @@ void devm_devfreq_unregister_opp_notifier(struct device *dev,
1266} 1348}
1267EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier); 1349EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
1268 1350
1351/**
1352 * devfreq_register_notifier() - Register a driver with devfreq
1353 * @devfreq: The devfreq object.
1354 * @nb: The notifier block to register.
1355 * @list: DEVFREQ_TRANSITION_NOTIFIER.
1356 */
1357int devfreq_register_notifier(struct devfreq *devfreq,
1358 struct notifier_block *nb,
1359 unsigned int list)
1360{
1361 int ret = 0;
1362
1363 if (!devfreq)
1364 return -EINVAL;
1365
1366 switch (list) {
1367 case DEVFREQ_TRANSITION_NOTIFIER:
1368 ret = srcu_notifier_chain_register(
1369 &devfreq->transition_notifier_list, nb);
1370 break;
1371 default:
1372 ret = -EINVAL;
1373 }
1374
1375 return ret;
1376}
1377EXPORT_SYMBOL(devfreq_register_notifier);
1378
1379/*
1380 * devfreq_unregister_notifier() - Unregister a driver with devfreq
1381 * @devfreq: The devfreq object.
1382 * @nb: The notifier block to be unregistered.
1383 * @list: DEVFREQ_TRANSITION_NOTIFIER.
1384 */
1385int devfreq_unregister_notifier(struct devfreq *devfreq,
1386 struct notifier_block *nb,
1387 unsigned int list)
1388{
1389 int ret = 0;
1390
1391 if (!devfreq)
1392 return -EINVAL;
1393
1394 switch (list) {
1395 case DEVFREQ_TRANSITION_NOTIFIER:
1396 ret = srcu_notifier_chain_unregister(
1397 &devfreq->transition_notifier_list, nb);
1398 break;
1399 default:
1400 ret = -EINVAL;
1401 }
1402
1403 return ret;
1404}
1405EXPORT_SYMBOL(devfreq_unregister_notifier);
1406
1407struct devfreq_notifier_devres {
1408 struct devfreq *devfreq;
1409 struct notifier_block *nb;
1410 unsigned int list;
1411};
1412
1413static void devm_devfreq_notifier_release(struct device *dev, void *res)
1414{
1415 struct devfreq_notifier_devres *this = res;
1416
1417 devfreq_unregister_notifier(this->devfreq, this->nb, this->list);
1418}
1419
1420/**
1421 * devm_devfreq_register_notifier()
1422 - Resource-managed devfreq_register_notifier()
1423 * @dev: The devfreq user device. (parent of devfreq)
1424 * @devfreq: The devfreq object.
1425 * @nb: The notifier block to be unregistered.
1426 * @list: DEVFREQ_TRANSITION_NOTIFIER.
1427 */
1428int devm_devfreq_register_notifier(struct device *dev,
1429 struct devfreq *devfreq,
1430 struct notifier_block *nb,
1431 unsigned int list)
1432{
1433 struct devfreq_notifier_devres *ptr;
1434 int ret;
1435
1436 ptr = devres_alloc(devm_devfreq_notifier_release, sizeof(*ptr),
1437 GFP_KERNEL);
1438 if (!ptr)
1439 return -ENOMEM;
1440
1441 ret = devfreq_register_notifier(devfreq, nb, list);
1442 if (ret) {
1443 devres_free(ptr);
1444 return ret;
1445 }
1446
1447 ptr->devfreq = devfreq;
1448 ptr->nb = nb;
1449 ptr->list = list;
1450 devres_add(dev, ptr);
1451
1452 return 0;
1453}
1454EXPORT_SYMBOL(devm_devfreq_register_notifier);
1455
1456/**
1457 * devm_devfreq_unregister_notifier()
1458 - Resource-managed devfreq_unregister_notifier()
1459 * @dev: The devfreq user device. (parent of devfreq)
1460 * @devfreq: The devfreq object.
1461 * @nb: The notifier block to be unregistered.
1462 * @list: DEVFREQ_TRANSITION_NOTIFIER.
1463 */
1464void devm_devfreq_unregister_notifier(struct device *dev,
1465 struct devfreq *devfreq,
1466 struct notifier_block *nb,
1467 unsigned int list)
1468{
1469 WARN_ON(devres_release(dev, devm_devfreq_notifier_release,
1470 devm_devfreq_dev_match, devfreq));
1471}
1472EXPORT_SYMBOL(devm_devfreq_unregister_notifier);
1473
1269MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1474MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
1270MODULE_DESCRIPTION("devfreq class support"); 1475MODULE_DESCRIPTION("devfreq class support");
1271MODULE_LICENSE("GPL"); 1476MODULE_LICENSE("GPL");