1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f262f28cSChanwoo Choi /* 3f262f28cSChanwoo Choi * devfreq-event: a framework to provide raw data and events of devfreq devices 4f262f28cSChanwoo Choi * 5f262f28cSChanwoo Choi * Copyright (C) 2015 Samsung Electronics 6f262f28cSChanwoo Choi * Author: Chanwoo Choi <cw00.choi@samsung.com> 7f262f28cSChanwoo Choi * 8f262f28cSChanwoo Choi * This driver is based on drivers/devfreq/devfreq.c. 9f262f28cSChanwoo Choi */ 10f262f28cSChanwoo Choi 11f262f28cSChanwoo Choi #include <linux/devfreq-event.h> 12f262f28cSChanwoo Choi #include <linux/kernel.h> 13f262f28cSChanwoo Choi #include <linux/err.h> 14f262f28cSChanwoo Choi #include <linux/init.h> 15e32363bcSPaul Gortmaker #include <linux/export.h> 16f262f28cSChanwoo Choi #include <linux/slab.h> 17f262f28cSChanwoo Choi #include <linux/list.h> 18f262f28cSChanwoo Choi #include <linux/of.h> 19f262f28cSChanwoo Choi 20f262f28cSChanwoo Choi static struct class *devfreq_event_class; 21f262f28cSChanwoo Choi 22f262f28cSChanwoo Choi /* The list of all devfreq event list */ 23f262f28cSChanwoo Choi static LIST_HEAD(devfreq_event_list); 24f262f28cSChanwoo Choi static DEFINE_MUTEX(devfreq_event_list_lock); 25f262f28cSChanwoo Choi 26f262f28cSChanwoo Choi #define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev) 27f262f28cSChanwoo Choi 28f262f28cSChanwoo Choi /** 29f262f28cSChanwoo Choi * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase 30f262f28cSChanwoo Choi * the enable_count of devfreq-event dev. 31f262f28cSChanwoo Choi * @edev : the devfreq-event device 32f262f28cSChanwoo Choi * 33f262f28cSChanwoo Choi * Note that this function increase the enable_count and enable the 34f262f28cSChanwoo Choi * devfreq-event device. The devfreq-event device should be enabled before 35f262f28cSChanwoo Choi * using it by devfreq device. 36f262f28cSChanwoo Choi */ 37f262f28cSChanwoo Choi int devfreq_event_enable_edev(struct devfreq_event_dev *edev) 38f262f28cSChanwoo Choi { 39f262f28cSChanwoo Choi int ret = 0; 40f262f28cSChanwoo Choi 41f262f28cSChanwoo Choi if (!edev || !edev->desc) 42f262f28cSChanwoo Choi return -EINVAL; 43f262f28cSChanwoo Choi 44f262f28cSChanwoo Choi mutex_lock(&edev->lock); 45f262f28cSChanwoo Choi if (edev->desc->ops && edev->desc->ops->enable 46f262f28cSChanwoo Choi && edev->enable_count == 0) { 47f262f28cSChanwoo Choi ret = edev->desc->ops->enable(edev); 48f262f28cSChanwoo Choi if (ret < 0) 49f262f28cSChanwoo Choi goto err; 50f262f28cSChanwoo Choi } 51f262f28cSChanwoo Choi edev->enable_count++; 52f262f28cSChanwoo Choi err: 53f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 54f262f28cSChanwoo Choi 55f262f28cSChanwoo Choi return ret; 56f262f28cSChanwoo Choi } 57f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_enable_edev); 58f262f28cSChanwoo Choi 59f262f28cSChanwoo Choi /** 60f262f28cSChanwoo Choi * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease 61f262f28cSChanwoo Choi * the enable_count of the devfreq-event dev. 62f262f28cSChanwoo Choi * @edev : the devfreq-event device 63f262f28cSChanwoo Choi * 64f262f28cSChanwoo Choi * Note that this function decrease the enable_count and disable the 65f262f28cSChanwoo Choi * devfreq-event device. After the devfreq-event device is disabled, 66f262f28cSChanwoo Choi * devfreq device can't use the devfreq-event device for get/set/reset 67f262f28cSChanwoo Choi * operations. 68f262f28cSChanwoo Choi */ 69f262f28cSChanwoo Choi int devfreq_event_disable_edev(struct devfreq_event_dev *edev) 70f262f28cSChanwoo Choi { 71f262f28cSChanwoo Choi int ret = 0; 72f262f28cSChanwoo Choi 73f262f28cSChanwoo Choi if (!edev || !edev->desc) 74f262f28cSChanwoo Choi return -EINVAL; 75f262f28cSChanwoo Choi 76f262f28cSChanwoo Choi mutex_lock(&edev->lock); 77f262f28cSChanwoo Choi if (edev->enable_count <= 0) { 78f262f28cSChanwoo Choi dev_warn(&edev->dev, "unbalanced enable_count\n"); 79f262f28cSChanwoo Choi ret = -EIO; 80f262f28cSChanwoo Choi goto err; 81f262f28cSChanwoo Choi } 82f262f28cSChanwoo Choi 83f262f28cSChanwoo Choi if (edev->desc->ops && edev->desc->ops->disable 84f262f28cSChanwoo Choi && edev->enable_count == 1) { 85f262f28cSChanwoo Choi ret = edev->desc->ops->disable(edev); 86f262f28cSChanwoo Choi if (ret < 0) 87f262f28cSChanwoo Choi goto err; 88f262f28cSChanwoo Choi } 89f262f28cSChanwoo Choi edev->enable_count--; 90f262f28cSChanwoo Choi err: 91f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 92f262f28cSChanwoo Choi 93f262f28cSChanwoo Choi return ret; 94f262f28cSChanwoo Choi } 95f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_disable_edev); 96f262f28cSChanwoo Choi 97f262f28cSChanwoo Choi /** 98f262f28cSChanwoo Choi * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or 99f262f28cSChanwoo Choi * not. 100f262f28cSChanwoo Choi * @edev : the devfreq-event device 101f262f28cSChanwoo Choi * 102f262f28cSChanwoo Choi * Note that this function check whether devfreq-event dev is enabled or not. 103f262f28cSChanwoo Choi * If return true, the devfreq-event dev is enabeld. If return false, the 104f262f28cSChanwoo Choi * devfreq-event dev is disabled. 105f262f28cSChanwoo Choi */ 106f262f28cSChanwoo Choi bool devfreq_event_is_enabled(struct devfreq_event_dev *edev) 107f262f28cSChanwoo Choi { 108f262f28cSChanwoo Choi bool enabled = false; 109f262f28cSChanwoo Choi 110f262f28cSChanwoo Choi if (!edev || !edev->desc) 111f262f28cSChanwoo Choi return enabled; 112f262f28cSChanwoo Choi 113f262f28cSChanwoo Choi mutex_lock(&edev->lock); 114f262f28cSChanwoo Choi 115f262f28cSChanwoo Choi if (edev->enable_count > 0) 116f262f28cSChanwoo Choi enabled = true; 117f262f28cSChanwoo Choi 118f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 119f262f28cSChanwoo Choi 120f262f28cSChanwoo Choi return enabled; 121f262f28cSChanwoo Choi } 122f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_is_enabled); 123f262f28cSChanwoo Choi 124f262f28cSChanwoo Choi /** 125f262f28cSChanwoo Choi * devfreq_event_set_event() - Set event to devfreq-event dev to start. 126f262f28cSChanwoo Choi * @edev : the devfreq-event device 127f262f28cSChanwoo Choi * 128f262f28cSChanwoo Choi * Note that this function set the event to the devfreq-event device to start 129f262f28cSChanwoo Choi * for getting the event data which could be various event type. 130f262f28cSChanwoo Choi */ 131f262f28cSChanwoo Choi int devfreq_event_set_event(struct devfreq_event_dev *edev) 132f262f28cSChanwoo Choi { 133f262f28cSChanwoo Choi int ret; 134f262f28cSChanwoo Choi 135f262f28cSChanwoo Choi if (!edev || !edev->desc) 136f262f28cSChanwoo Choi return -EINVAL; 137f262f28cSChanwoo Choi 138f262f28cSChanwoo Choi if (!edev->desc->ops || !edev->desc->ops->set_event) 139f262f28cSChanwoo Choi return -EINVAL; 140f262f28cSChanwoo Choi 141f262f28cSChanwoo Choi if (!devfreq_event_is_enabled(edev)) 142f262f28cSChanwoo Choi return -EPERM; 143f262f28cSChanwoo Choi 144f262f28cSChanwoo Choi mutex_lock(&edev->lock); 145f262f28cSChanwoo Choi ret = edev->desc->ops->set_event(edev); 146f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 147f262f28cSChanwoo Choi 148f262f28cSChanwoo Choi return ret; 149f262f28cSChanwoo Choi } 150f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_set_event); 151f262f28cSChanwoo Choi 152f262f28cSChanwoo Choi /** 153f262f28cSChanwoo Choi * devfreq_event_get_event() - Get {load|total}_count from devfreq-event dev. 154f262f28cSChanwoo Choi * @edev : the devfreq-event device 155f262f28cSChanwoo Choi * @edata : the calculated data of devfreq-event device 156f262f28cSChanwoo Choi * 157f262f28cSChanwoo Choi * Note that this function get the calculated event data from devfreq-event dev 158f262f28cSChanwoo Choi * after stoping the progress of whole sequence of devfreq-event dev. 159f262f28cSChanwoo Choi */ 160f262f28cSChanwoo Choi int devfreq_event_get_event(struct devfreq_event_dev *edev, 161f262f28cSChanwoo Choi struct devfreq_event_data *edata) 162f262f28cSChanwoo Choi { 163f262f28cSChanwoo Choi int ret; 164f262f28cSChanwoo Choi 165f262f28cSChanwoo Choi if (!edev || !edev->desc) 166f262f28cSChanwoo Choi return -EINVAL; 167f262f28cSChanwoo Choi 168f262f28cSChanwoo Choi if (!edev->desc->ops || !edev->desc->ops->get_event) 169f262f28cSChanwoo Choi return -EINVAL; 170f262f28cSChanwoo Choi 171f262f28cSChanwoo Choi if (!devfreq_event_is_enabled(edev)) 172f262f28cSChanwoo Choi return -EINVAL; 173f262f28cSChanwoo Choi 174f262f28cSChanwoo Choi edata->total_count = edata->load_count = 0; 175f262f28cSChanwoo Choi 176f262f28cSChanwoo Choi mutex_lock(&edev->lock); 177f262f28cSChanwoo Choi ret = edev->desc->ops->get_event(edev, edata); 178f262f28cSChanwoo Choi if (ret < 0) 179f262f28cSChanwoo Choi edata->total_count = edata->load_count = 0; 180f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 181f262f28cSChanwoo Choi 182f262f28cSChanwoo Choi return ret; 183f262f28cSChanwoo Choi } 184f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_get_event); 185f262f28cSChanwoo Choi 186f262f28cSChanwoo Choi /** 187f262f28cSChanwoo Choi * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev. 188f262f28cSChanwoo Choi * @edev : the devfreq-event device 189f262f28cSChanwoo Choi * 190f262f28cSChanwoo Choi * Note that this function stop all operations of devfreq-event dev and reset 191f262f28cSChanwoo Choi * the current event data to make the devfreq-event device into initial state. 192f262f28cSChanwoo Choi */ 193f262f28cSChanwoo Choi int devfreq_event_reset_event(struct devfreq_event_dev *edev) 194f262f28cSChanwoo Choi { 195f262f28cSChanwoo Choi int ret = 0; 196f262f28cSChanwoo Choi 197f262f28cSChanwoo Choi if (!edev || !edev->desc) 198f262f28cSChanwoo Choi return -EINVAL; 199f262f28cSChanwoo Choi 200f262f28cSChanwoo Choi if (!devfreq_event_is_enabled(edev)) 201f262f28cSChanwoo Choi return -EPERM; 202f262f28cSChanwoo Choi 203f262f28cSChanwoo Choi mutex_lock(&edev->lock); 204f262f28cSChanwoo Choi if (edev->desc->ops && edev->desc->ops->reset) 205f262f28cSChanwoo Choi ret = edev->desc->ops->reset(edev); 206f262f28cSChanwoo Choi mutex_unlock(&edev->lock); 207f262f28cSChanwoo Choi 208f262f28cSChanwoo Choi return ret; 209f262f28cSChanwoo Choi } 210f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_reset_event); 211f262f28cSChanwoo Choi 212f262f28cSChanwoo Choi /** 213f262f28cSChanwoo Choi * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from 214f262f28cSChanwoo Choi * devicetree. 215f262f28cSChanwoo Choi * @dev : the pointer to the given device 21602bdbf7dSChanwoo Choi * @phandle_name: name of property holding a phandle value 217f262f28cSChanwoo Choi * @index : the index into list of devfreq-event device 218f262f28cSChanwoo Choi * 219f262f28cSChanwoo Choi * Note that this function return the pointer of devfreq-event device. 220f262f28cSChanwoo Choi */ 221f262f28cSChanwoo Choi struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev, 22202bdbf7dSChanwoo Choi const char *phandle_name, int index) 223f262f28cSChanwoo Choi { 224f262f28cSChanwoo Choi struct device_node *node; 225f262f28cSChanwoo Choi struct devfreq_event_dev *edev; 226f262f28cSChanwoo Choi 22702bdbf7dSChanwoo Choi if (!dev->of_node || !phandle_name) 228f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 229f262f28cSChanwoo Choi 23002bdbf7dSChanwoo Choi node = of_parse_phandle(dev->of_node, phandle_name, index); 231df678ff7SChanwoo Choi if (!node) 232f262f28cSChanwoo Choi return ERR_PTR(-ENODEV); 233f262f28cSChanwoo Choi 234f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 235f262f28cSChanwoo Choi list_for_each_entry(edev, &devfreq_event_list, node) { 23619cf91d0SChanwoo Choi if (edev->dev.parent && edev->dev.parent->of_node == node) 23719cf91d0SChanwoo Choi goto out; 23819cf91d0SChanwoo Choi } 23919cf91d0SChanwoo Choi 24019cf91d0SChanwoo Choi list_for_each_entry(edev, &devfreq_event_list, node) { 2410d00a239SRob Herring if (of_node_name_eq(node, edev->desc->name)) 242f262f28cSChanwoo Choi goto out; 243f262f28cSChanwoo Choi } 244f262f28cSChanwoo Choi edev = NULL; 245f262f28cSChanwoo Choi out: 246f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 247f262f28cSChanwoo Choi 248f262f28cSChanwoo Choi if (!edev) { 249f262f28cSChanwoo Choi of_node_put(node); 250f262f28cSChanwoo Choi return ERR_PTR(-ENODEV); 251f262f28cSChanwoo Choi } 252f262f28cSChanwoo Choi 253f262f28cSChanwoo Choi of_node_put(node); 254f262f28cSChanwoo Choi 255f262f28cSChanwoo Choi return edev; 256f262f28cSChanwoo Choi } 257f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle); 258f262f28cSChanwoo Choi 259f262f28cSChanwoo Choi /** 260f262f28cSChanwoo Choi * devfreq_event_get_edev_count() - Get the count of devfreq-event dev 261f262f28cSChanwoo Choi * @dev : the pointer to the given device 26202bdbf7dSChanwoo Choi * @phandle_name: name of property holding a phandle value 263f262f28cSChanwoo Choi * 264f262f28cSChanwoo Choi * Note that this function return the count of devfreq-event devices. 265f262f28cSChanwoo Choi */ 26602bdbf7dSChanwoo Choi int devfreq_event_get_edev_count(struct device *dev, const char *phandle_name) 267f262f28cSChanwoo Choi { 268f262f28cSChanwoo Choi int count; 269f262f28cSChanwoo Choi 27002bdbf7dSChanwoo Choi if (!dev->of_node || !phandle_name) { 271f262f28cSChanwoo Choi dev_err(dev, "device does not have a device node entry\n"); 272f262f28cSChanwoo Choi return -EINVAL; 273f262f28cSChanwoo Choi } 274f262f28cSChanwoo Choi 27502bdbf7dSChanwoo Choi count = of_property_count_elems_of_size(dev->of_node, phandle_name, 276f262f28cSChanwoo Choi sizeof(u32)); 277f262f28cSChanwoo Choi if (count < 0) { 278f262f28cSChanwoo Choi dev_err(dev, 279e8305d40SRob Herring "failed to get the count of devfreq-event in %pOF node\n", 280e8305d40SRob Herring dev->of_node); 281f262f28cSChanwoo Choi return count; 282f262f28cSChanwoo Choi } 283f262f28cSChanwoo Choi 284f262f28cSChanwoo Choi return count; 285f262f28cSChanwoo Choi } 286f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count); 287f262f28cSChanwoo Choi 288f262f28cSChanwoo Choi static void devfreq_event_release_edev(struct device *dev) 289f262f28cSChanwoo Choi { 290f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 291f262f28cSChanwoo Choi 292f262f28cSChanwoo Choi kfree(edev); 293f262f28cSChanwoo Choi } 294f262f28cSChanwoo Choi 295f262f28cSChanwoo Choi /** 296f262f28cSChanwoo Choi * devfreq_event_add_edev() - Add new devfreq-event device. 297f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 298ada79596SKieran Bingham * @desc : the devfreq-event device's descriptor which include essential 299f262f28cSChanwoo Choi * data for devfreq-event device. 300f262f28cSChanwoo Choi * 301f262f28cSChanwoo Choi * Note that this function add new devfreq-event device to devfreq-event class 302f262f28cSChanwoo Choi * list and register the device of the devfreq-event device. 303f262f28cSChanwoo Choi */ 304f262f28cSChanwoo Choi struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, 305f262f28cSChanwoo Choi struct devfreq_event_desc *desc) 306f262f28cSChanwoo Choi { 307f262f28cSChanwoo Choi struct devfreq_event_dev *edev; 308775fa8c3SChanwoo Choi static atomic_t event_no = ATOMIC_INIT(-1); 309f262f28cSChanwoo Choi int ret; 310f262f28cSChanwoo Choi 311f262f28cSChanwoo Choi if (!dev || !desc) 312f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 313f262f28cSChanwoo Choi 314f262f28cSChanwoo Choi if (!desc->name || !desc->ops) 315f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 316f262f28cSChanwoo Choi 317f262f28cSChanwoo Choi if (!desc->ops->set_event || !desc->ops->get_event) 318f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 319f262f28cSChanwoo Choi 320f262f28cSChanwoo Choi edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL); 321f262f28cSChanwoo Choi if (!edev) 322f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 323f262f28cSChanwoo Choi 324f262f28cSChanwoo Choi mutex_init(&edev->lock); 325f262f28cSChanwoo Choi edev->desc = desc; 326f262f28cSChanwoo Choi edev->enable_count = 0; 327f262f28cSChanwoo Choi edev->dev.parent = dev; 328f262f28cSChanwoo Choi edev->dev.class = devfreq_event_class; 329f262f28cSChanwoo Choi edev->dev.release = devfreq_event_release_edev; 330f262f28cSChanwoo Choi 331775fa8c3SChanwoo Choi dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); 332f262f28cSChanwoo Choi ret = device_register(&edev->dev); 333f262f28cSChanwoo Choi if (ret < 0) { 334f262f28cSChanwoo Choi put_device(&edev->dev); 335f262f28cSChanwoo Choi return ERR_PTR(ret); 336f262f28cSChanwoo Choi } 337f262f28cSChanwoo Choi dev_set_drvdata(&edev->dev, edev); 338f262f28cSChanwoo Choi 339f262f28cSChanwoo Choi INIT_LIST_HEAD(&edev->node); 340f262f28cSChanwoo Choi 341f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 342f262f28cSChanwoo Choi list_add(&edev->node, &devfreq_event_list); 343f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 344f262f28cSChanwoo Choi 345f262f28cSChanwoo Choi return edev; 346f262f28cSChanwoo Choi } 347f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_add_edev); 348f262f28cSChanwoo Choi 349f262f28cSChanwoo Choi /** 350f262f28cSChanwoo Choi * devfreq_event_remove_edev() - Remove the devfreq-event device registered. 35154cb5740SRandy Dunlap * @edev : the devfreq-event device 352f262f28cSChanwoo Choi * 35354cb5740SRandy Dunlap * Note that this function removes the registered devfreq-event device. 354f262f28cSChanwoo Choi */ 355f262f28cSChanwoo Choi int devfreq_event_remove_edev(struct devfreq_event_dev *edev) 356f262f28cSChanwoo Choi { 357f262f28cSChanwoo Choi if (!edev) 358f262f28cSChanwoo Choi return -EINVAL; 359f262f28cSChanwoo Choi 360f262f28cSChanwoo Choi WARN_ON(edev->enable_count); 361f262f28cSChanwoo Choi 362f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 363f262f28cSChanwoo Choi list_del(&edev->node); 364f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 365f262f28cSChanwoo Choi 366f262f28cSChanwoo Choi device_unregister(&edev->dev); 367f262f28cSChanwoo Choi 368f262f28cSChanwoo Choi return 0; 369f262f28cSChanwoo Choi } 370f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_remove_edev); 371f262f28cSChanwoo Choi 372f262f28cSChanwoo Choi static int devm_devfreq_event_match(struct device *dev, void *res, void *data) 373f262f28cSChanwoo Choi { 374f262f28cSChanwoo Choi struct devfreq_event_dev **r = res; 375f262f28cSChanwoo Choi 376f262f28cSChanwoo Choi if (WARN_ON(!r || !*r)) 377f262f28cSChanwoo Choi return 0; 378f262f28cSChanwoo Choi 379f262f28cSChanwoo Choi return *r == data; 380f262f28cSChanwoo Choi } 381f262f28cSChanwoo Choi 382f262f28cSChanwoo Choi static void devm_devfreq_event_release(struct device *dev, void *res) 383f262f28cSChanwoo Choi { 384f262f28cSChanwoo Choi devfreq_event_remove_edev(*(struct devfreq_event_dev **)res); 385f262f28cSChanwoo Choi } 386f262f28cSChanwoo Choi 387f262f28cSChanwoo Choi /** 388f262f28cSChanwoo Choi * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev() 389f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 390ada79596SKieran Bingham * @desc : the devfreq-event device's descriptor which include essential 391f262f28cSChanwoo Choi * data for devfreq-event device. 392f262f28cSChanwoo Choi * 393f262f28cSChanwoo Choi * Note that this function manages automatically the memory of devfreq-event 394f262f28cSChanwoo Choi * device using device resource management and simplify the free operation 395f262f28cSChanwoo Choi * for memory of devfreq-event device. 396f262f28cSChanwoo Choi */ 397f262f28cSChanwoo Choi struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev, 398f262f28cSChanwoo Choi struct devfreq_event_desc *desc) 399f262f28cSChanwoo Choi { 400f262f28cSChanwoo Choi struct devfreq_event_dev **ptr, *edev; 401f262f28cSChanwoo Choi 402e54916c6SChanwoo Choi ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), 403e54916c6SChanwoo Choi GFP_KERNEL); 404f262f28cSChanwoo Choi if (!ptr) 405f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 406f262f28cSChanwoo Choi 407f262f28cSChanwoo Choi edev = devfreq_event_add_edev(dev, desc); 408f262f28cSChanwoo Choi if (IS_ERR(edev)) { 409f262f28cSChanwoo Choi devres_free(ptr); 410f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 411f262f28cSChanwoo Choi } 412f262f28cSChanwoo Choi 413f262f28cSChanwoo Choi *ptr = edev; 414f262f28cSChanwoo Choi devres_add(dev, ptr); 415f262f28cSChanwoo Choi 416f262f28cSChanwoo Choi return edev; 417f262f28cSChanwoo Choi } 418f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev); 419f262f28cSChanwoo Choi 420f262f28cSChanwoo Choi /** 421f262f28cSChanwoo Choi * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev() 422f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 423f262f28cSChanwoo Choi * @edev : the devfreq-event device 424f262f28cSChanwoo Choi * 425f262f28cSChanwoo Choi * Note that this function manages automatically the memory of devfreq-event 426f262f28cSChanwoo Choi * device using device resource management. 427f262f28cSChanwoo Choi */ 428f262f28cSChanwoo Choi void devm_devfreq_event_remove_edev(struct device *dev, 429f262f28cSChanwoo Choi struct devfreq_event_dev *edev) 430f262f28cSChanwoo Choi { 431f262f28cSChanwoo Choi WARN_ON(devres_release(dev, devm_devfreq_event_release, 432f262f28cSChanwoo Choi devm_devfreq_event_match, edev)); 433f262f28cSChanwoo Choi } 434f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev); 435f262f28cSChanwoo Choi 436f262f28cSChanwoo Choi /* 437f262f28cSChanwoo Choi * Device attributes for devfreq-event class. 438f262f28cSChanwoo Choi */ 439f262f28cSChanwoo Choi static ssize_t name_show(struct device *dev, struct device_attribute *attr, 440f262f28cSChanwoo Choi char *buf) 441f262f28cSChanwoo Choi { 442f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 443f262f28cSChanwoo Choi 444f262f28cSChanwoo Choi if (!edev || !edev->desc) 445f262f28cSChanwoo Choi return -EINVAL; 446f262f28cSChanwoo Choi 447f262f28cSChanwoo Choi return sprintf(buf, "%s\n", edev->desc->name); 448f262f28cSChanwoo Choi } 449f262f28cSChanwoo Choi static DEVICE_ATTR_RO(name); 450f262f28cSChanwoo Choi 451f262f28cSChanwoo Choi static ssize_t enable_count_show(struct device *dev, 452f262f28cSChanwoo Choi struct device_attribute *attr, char *buf) 453f262f28cSChanwoo Choi { 454f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 455f262f28cSChanwoo Choi 456f262f28cSChanwoo Choi if (!edev || !edev->desc) 457f262f28cSChanwoo Choi return -EINVAL; 458f262f28cSChanwoo Choi 459f262f28cSChanwoo Choi return sprintf(buf, "%d\n", edev->enable_count); 460f262f28cSChanwoo Choi } 461f262f28cSChanwoo Choi static DEVICE_ATTR_RO(enable_count); 462f262f28cSChanwoo Choi 463f262f28cSChanwoo Choi static struct attribute *devfreq_event_attrs[] = { 464f262f28cSChanwoo Choi &dev_attr_name.attr, 465f262f28cSChanwoo Choi &dev_attr_enable_count.attr, 466f262f28cSChanwoo Choi NULL, 467f262f28cSChanwoo Choi }; 468f262f28cSChanwoo Choi ATTRIBUTE_GROUPS(devfreq_event); 469f262f28cSChanwoo Choi 470f262f28cSChanwoo Choi static int __init devfreq_event_init(void) 471f262f28cSChanwoo Choi { 472f262f28cSChanwoo Choi devfreq_event_class = class_create(THIS_MODULE, "devfreq-event"); 473f262f28cSChanwoo Choi if (IS_ERR(devfreq_event_class)) { 474f262f28cSChanwoo Choi pr_err("%s: couldn't create class\n", __FILE__); 475f262f28cSChanwoo Choi return PTR_ERR(devfreq_event_class); 476f262f28cSChanwoo Choi } 477f262f28cSChanwoo Choi 478f262f28cSChanwoo Choi devfreq_event_class->dev_groups = devfreq_event_groups; 479f262f28cSChanwoo Choi 480f262f28cSChanwoo Choi return 0; 481f262f28cSChanwoo Choi } 482f262f28cSChanwoo Choi subsys_initcall(devfreq_event_init); 483