root/drivers/devfreq/governor_userspace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. devfreq_userspace_func
  2. store_freq
  3. show_freq
  4. userspace_init
  5. userspace_exit
  6. devfreq_userspace_handler
  7. devfreq_userspace_init
  8. devfreq_userspace_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/drivers/devfreq/governor_userspace.c
   4  *
   5  *  Copyright (C) 2011 Samsung Electronics
   6  *      MyungJoo Ham <myungjoo.ham@samsung.com>
   7  */
   8 
   9 #include <linux/slab.h>
  10 #include <linux/device.h>
  11 #include <linux/devfreq.h>
  12 #include <linux/pm.h>
  13 #include <linux/mutex.h>
  14 #include <linux/module.h>
  15 #include "governor.h"
  16 
  17 struct userspace_data {
  18         unsigned long user_frequency;
  19         bool valid;
  20 };
  21 
  22 static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
  23 {
  24         struct userspace_data *data = df->data;
  25 
  26         if (data->valid)
  27                 *freq = data->user_frequency;
  28         else
  29                 *freq = df->previous_freq; /* No user freq specified yet */
  30 
  31         return 0;
  32 }
  33 
  34 static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
  35                           const char *buf, size_t count)
  36 {
  37         struct devfreq *devfreq = to_devfreq(dev);
  38         struct userspace_data *data;
  39         unsigned long wanted;
  40         int err = 0;
  41 
  42         mutex_lock(&devfreq->lock);
  43         data = devfreq->data;
  44 
  45         sscanf(buf, "%lu", &wanted);
  46         data->user_frequency = wanted;
  47         data->valid = true;
  48         err = update_devfreq(devfreq);
  49         if (err == 0)
  50                 err = count;
  51         mutex_unlock(&devfreq->lock);
  52         return err;
  53 }
  54 
  55 static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
  56                          char *buf)
  57 {
  58         struct devfreq *devfreq = to_devfreq(dev);
  59         struct userspace_data *data;
  60         int err = 0;
  61 
  62         mutex_lock(&devfreq->lock);
  63         data = devfreq->data;
  64 
  65         if (data->valid)
  66                 err = sprintf(buf, "%lu\n", data->user_frequency);
  67         else
  68                 err = sprintf(buf, "undefined\n");
  69         mutex_unlock(&devfreq->lock);
  70         return err;
  71 }
  72 
  73 static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
  74 static struct attribute *dev_entries[] = {
  75         &dev_attr_set_freq.attr,
  76         NULL,
  77 };
  78 static const struct attribute_group dev_attr_group = {
  79         .name   = DEVFREQ_GOV_USERSPACE,
  80         .attrs  = dev_entries,
  81 };
  82 
  83 static int userspace_init(struct devfreq *devfreq)
  84 {
  85         int err = 0;
  86         struct userspace_data *data = kzalloc(sizeof(struct userspace_data),
  87                                               GFP_KERNEL);
  88 
  89         if (!data) {
  90                 err = -ENOMEM;
  91                 goto out;
  92         }
  93         data->valid = false;
  94         devfreq->data = data;
  95 
  96         err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
  97 out:
  98         return err;
  99 }
 100 
 101 static void userspace_exit(struct devfreq *devfreq)
 102 {
 103         /*
 104          * Remove the sysfs entry, unless this is being called after
 105          * device_del(), which should have done this already via kobject_del().
 106          */
 107         if (devfreq->dev.kobj.sd)
 108                 sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
 109 
 110         kfree(devfreq->data);
 111         devfreq->data = NULL;
 112 }
 113 
 114 static int devfreq_userspace_handler(struct devfreq *devfreq,
 115                         unsigned int event, void *data)
 116 {
 117         int ret = 0;
 118 
 119         switch (event) {
 120         case DEVFREQ_GOV_START:
 121                 ret = userspace_init(devfreq);
 122                 break;
 123         case DEVFREQ_GOV_STOP:
 124                 userspace_exit(devfreq);
 125                 break;
 126         default:
 127                 break;
 128         }
 129 
 130         return ret;
 131 }
 132 
 133 static struct devfreq_governor devfreq_userspace = {
 134         .name = "userspace",
 135         .get_target_freq = devfreq_userspace_func,
 136         .event_handler = devfreq_userspace_handler,
 137 };
 138 
 139 static int __init devfreq_userspace_init(void)
 140 {
 141         return devfreq_add_governor(&devfreq_userspace);
 142 }
 143 subsys_initcall(devfreq_userspace_init);
 144 
 145 static void __exit devfreq_userspace_exit(void)
 146 {
 147         int ret;
 148 
 149         ret = devfreq_remove_governor(&devfreq_userspace);
 150         if (ret)
 151                 pr_err("%s: failed remove governor %d\n", __func__, ret);
 152 
 153         return;
 154 }
 155 module_exit(devfreq_userspace_exit);
 156 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */