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 216f262f28cSChanwoo Choi * @index : the index into list of devfreq-event device 217f262f28cSChanwoo Choi * 218f262f28cSChanwoo Choi * Note that this function return the pointer of devfreq-event device. 219f262f28cSChanwoo Choi */ 220f262f28cSChanwoo Choi struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev, 221f262f28cSChanwoo Choi int index) 222f262f28cSChanwoo Choi { 223f262f28cSChanwoo Choi struct device_node *node; 224f262f28cSChanwoo Choi struct devfreq_event_dev *edev; 225f262f28cSChanwoo Choi 226df678ff7SChanwoo Choi if (!dev->of_node) 227f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 228f262f28cSChanwoo Choi 229f262f28cSChanwoo Choi node = of_parse_phandle(dev->of_node, "devfreq-events", index); 230df678ff7SChanwoo Choi if (!node) 231f262f28cSChanwoo Choi return ERR_PTR(-ENODEV); 232f262f28cSChanwoo Choi 233f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 234f262f28cSChanwoo Choi list_for_each_entry(edev, &devfreq_event_list, node) { 23519cf91d0SChanwoo Choi if (edev->dev.parent && edev->dev.parent->of_node == node) 23619cf91d0SChanwoo Choi goto out; 23719cf91d0SChanwoo Choi } 23819cf91d0SChanwoo Choi 23919cf91d0SChanwoo Choi list_for_each_entry(edev, &devfreq_event_list, node) { 2400d00a239SRob Herring if (of_node_name_eq(node, edev->desc->name)) 241f262f28cSChanwoo Choi goto out; 242f262f28cSChanwoo Choi } 243f262f28cSChanwoo Choi edev = NULL; 244f262f28cSChanwoo Choi out: 245f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 246f262f28cSChanwoo Choi 247f262f28cSChanwoo Choi if (!edev) { 248f262f28cSChanwoo Choi of_node_put(node); 249f262f28cSChanwoo Choi return ERR_PTR(-ENODEV); 250f262f28cSChanwoo Choi } 251f262f28cSChanwoo Choi 252f262f28cSChanwoo Choi of_node_put(node); 253f262f28cSChanwoo Choi 254f262f28cSChanwoo Choi return edev; 255f262f28cSChanwoo Choi } 256f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle); 257f262f28cSChanwoo Choi 258f262f28cSChanwoo Choi /** 259f262f28cSChanwoo Choi * devfreq_event_get_edev_count() - Get the count of devfreq-event dev 260f262f28cSChanwoo Choi * @dev : the pointer to the given device 261f262f28cSChanwoo Choi * 262f262f28cSChanwoo Choi * Note that this function return the count of devfreq-event devices. 263f262f28cSChanwoo Choi */ 264f262f28cSChanwoo Choi int devfreq_event_get_edev_count(struct device *dev) 265f262f28cSChanwoo Choi { 266f262f28cSChanwoo Choi int count; 267f262f28cSChanwoo Choi 268f262f28cSChanwoo Choi if (!dev->of_node) { 269f262f28cSChanwoo Choi dev_err(dev, "device does not have a device node entry\n"); 270f262f28cSChanwoo Choi return -EINVAL; 271f262f28cSChanwoo Choi } 272f262f28cSChanwoo Choi 273f262f28cSChanwoo Choi count = of_property_count_elems_of_size(dev->of_node, "devfreq-events", 274f262f28cSChanwoo Choi sizeof(u32)); 275f262f28cSChanwoo Choi if (count < 0) { 276f262f28cSChanwoo Choi dev_err(dev, 277e8305d40SRob Herring "failed to get the count of devfreq-event in %pOF node\n", 278e8305d40SRob Herring dev->of_node); 279f262f28cSChanwoo Choi return count; 280f262f28cSChanwoo Choi } 281f262f28cSChanwoo Choi 282f262f28cSChanwoo Choi return count; 283f262f28cSChanwoo Choi } 284f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count); 285f262f28cSChanwoo Choi 286f262f28cSChanwoo Choi static void devfreq_event_release_edev(struct device *dev) 287f262f28cSChanwoo Choi { 288f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 289f262f28cSChanwoo Choi 290f262f28cSChanwoo Choi kfree(edev); 291f262f28cSChanwoo Choi } 292f262f28cSChanwoo Choi 293f262f28cSChanwoo Choi /** 294f262f28cSChanwoo Choi * devfreq_event_add_edev() - Add new devfreq-event device. 295f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 296f262f28cSChanwoo Choi * @desc : the devfreq-event device's decriptor which include essential 297f262f28cSChanwoo Choi * data for devfreq-event device. 298f262f28cSChanwoo Choi * 299f262f28cSChanwoo Choi * Note that this function add new devfreq-event device to devfreq-event class 300f262f28cSChanwoo Choi * list and register the device of the devfreq-event device. 301f262f28cSChanwoo Choi */ 302f262f28cSChanwoo Choi struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, 303f262f28cSChanwoo Choi struct devfreq_event_desc *desc) 304f262f28cSChanwoo Choi { 305f262f28cSChanwoo Choi struct devfreq_event_dev *edev; 306775fa8c3SChanwoo Choi static atomic_t event_no = ATOMIC_INIT(-1); 307f262f28cSChanwoo Choi int ret; 308f262f28cSChanwoo Choi 309f262f28cSChanwoo Choi if (!dev || !desc) 310f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 311f262f28cSChanwoo Choi 312f262f28cSChanwoo Choi if (!desc->name || !desc->ops) 313f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 314f262f28cSChanwoo Choi 315f262f28cSChanwoo Choi if (!desc->ops->set_event || !desc->ops->get_event) 316f262f28cSChanwoo Choi return ERR_PTR(-EINVAL); 317f262f28cSChanwoo Choi 318f262f28cSChanwoo Choi edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL); 319f262f28cSChanwoo Choi if (!edev) 320f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 321f262f28cSChanwoo Choi 322f262f28cSChanwoo Choi mutex_init(&edev->lock); 323f262f28cSChanwoo Choi edev->desc = desc; 324f262f28cSChanwoo Choi edev->enable_count = 0; 325f262f28cSChanwoo Choi edev->dev.parent = dev; 326f262f28cSChanwoo Choi edev->dev.class = devfreq_event_class; 327f262f28cSChanwoo Choi edev->dev.release = devfreq_event_release_edev; 328f262f28cSChanwoo Choi 329775fa8c3SChanwoo Choi dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); 330f262f28cSChanwoo Choi ret = device_register(&edev->dev); 331f262f28cSChanwoo Choi if (ret < 0) { 332f262f28cSChanwoo Choi put_device(&edev->dev); 333f262f28cSChanwoo Choi return ERR_PTR(ret); 334f262f28cSChanwoo Choi } 335f262f28cSChanwoo Choi dev_set_drvdata(&edev->dev, edev); 336f262f28cSChanwoo Choi 337f262f28cSChanwoo Choi INIT_LIST_HEAD(&edev->node); 338f262f28cSChanwoo Choi 339f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 340f262f28cSChanwoo Choi list_add(&edev->node, &devfreq_event_list); 341f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 342f262f28cSChanwoo Choi 343f262f28cSChanwoo Choi return edev; 344f262f28cSChanwoo Choi } 345f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_add_edev); 346f262f28cSChanwoo Choi 347f262f28cSChanwoo Choi /** 348f262f28cSChanwoo Choi * devfreq_event_remove_edev() - Remove the devfreq-event device registered. 349f262f28cSChanwoo Choi * @dev : the devfreq-event device 350f262f28cSChanwoo Choi * 351f262f28cSChanwoo Choi * Note that this function remove the registered devfreq-event device. 352f262f28cSChanwoo Choi */ 353f262f28cSChanwoo Choi int devfreq_event_remove_edev(struct devfreq_event_dev *edev) 354f262f28cSChanwoo Choi { 355f262f28cSChanwoo Choi if (!edev) 356f262f28cSChanwoo Choi return -EINVAL; 357f262f28cSChanwoo Choi 358f262f28cSChanwoo Choi WARN_ON(edev->enable_count); 359f262f28cSChanwoo Choi 360f262f28cSChanwoo Choi mutex_lock(&devfreq_event_list_lock); 361f262f28cSChanwoo Choi list_del(&edev->node); 362f262f28cSChanwoo Choi mutex_unlock(&devfreq_event_list_lock); 363f262f28cSChanwoo Choi 364f262f28cSChanwoo Choi device_unregister(&edev->dev); 365f262f28cSChanwoo Choi 366f262f28cSChanwoo Choi return 0; 367f262f28cSChanwoo Choi } 368f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devfreq_event_remove_edev); 369f262f28cSChanwoo Choi 370f262f28cSChanwoo Choi static int devm_devfreq_event_match(struct device *dev, void *res, void *data) 371f262f28cSChanwoo Choi { 372f262f28cSChanwoo Choi struct devfreq_event_dev **r = res; 373f262f28cSChanwoo Choi 374f262f28cSChanwoo Choi if (WARN_ON(!r || !*r)) 375f262f28cSChanwoo Choi return 0; 376f262f28cSChanwoo Choi 377f262f28cSChanwoo Choi return *r == data; 378f262f28cSChanwoo Choi } 379f262f28cSChanwoo Choi 380f262f28cSChanwoo Choi static void devm_devfreq_event_release(struct device *dev, void *res) 381f262f28cSChanwoo Choi { 382f262f28cSChanwoo Choi devfreq_event_remove_edev(*(struct devfreq_event_dev **)res); 383f262f28cSChanwoo Choi } 384f262f28cSChanwoo Choi 385f262f28cSChanwoo Choi /** 386f262f28cSChanwoo Choi * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev() 387f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 388f262f28cSChanwoo Choi * @desc : the devfreq-event device's decriptor which include essential 389f262f28cSChanwoo Choi * data for devfreq-event device. 390f262f28cSChanwoo Choi * 391f262f28cSChanwoo Choi * Note that this function manages automatically the memory of devfreq-event 392f262f28cSChanwoo Choi * device using device resource management and simplify the free operation 393f262f28cSChanwoo Choi * for memory of devfreq-event device. 394f262f28cSChanwoo Choi */ 395f262f28cSChanwoo Choi struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev, 396f262f28cSChanwoo Choi struct devfreq_event_desc *desc) 397f262f28cSChanwoo Choi { 398f262f28cSChanwoo Choi struct devfreq_event_dev **ptr, *edev; 399f262f28cSChanwoo Choi 400e54916c6SChanwoo Choi ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), 401e54916c6SChanwoo Choi GFP_KERNEL); 402f262f28cSChanwoo Choi if (!ptr) 403f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 404f262f28cSChanwoo Choi 405f262f28cSChanwoo Choi edev = devfreq_event_add_edev(dev, desc); 406f262f28cSChanwoo Choi if (IS_ERR(edev)) { 407f262f28cSChanwoo Choi devres_free(ptr); 408f262f28cSChanwoo Choi return ERR_PTR(-ENOMEM); 409f262f28cSChanwoo Choi } 410f262f28cSChanwoo Choi 411f262f28cSChanwoo Choi *ptr = edev; 412f262f28cSChanwoo Choi devres_add(dev, ptr); 413f262f28cSChanwoo Choi 414f262f28cSChanwoo Choi return edev; 415f262f28cSChanwoo Choi } 416f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev); 417f262f28cSChanwoo Choi 418f262f28cSChanwoo Choi /** 419f262f28cSChanwoo Choi * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev() 420f262f28cSChanwoo Choi * @dev : the device owning the devfreq-event device being created 421f262f28cSChanwoo Choi * @edev : the devfreq-event device 422f262f28cSChanwoo Choi * 423f262f28cSChanwoo Choi * Note that this function manages automatically the memory of devfreq-event 424f262f28cSChanwoo Choi * device using device resource management. 425f262f28cSChanwoo Choi */ 426f262f28cSChanwoo Choi void devm_devfreq_event_remove_edev(struct device *dev, 427f262f28cSChanwoo Choi struct devfreq_event_dev *edev) 428f262f28cSChanwoo Choi { 429f262f28cSChanwoo Choi WARN_ON(devres_release(dev, devm_devfreq_event_release, 430f262f28cSChanwoo Choi devm_devfreq_event_match, edev)); 431f262f28cSChanwoo Choi } 432f262f28cSChanwoo Choi EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev); 433f262f28cSChanwoo Choi 434f262f28cSChanwoo Choi /* 435f262f28cSChanwoo Choi * Device attributes for devfreq-event class. 436f262f28cSChanwoo Choi */ 437f262f28cSChanwoo Choi static ssize_t name_show(struct device *dev, struct device_attribute *attr, 438f262f28cSChanwoo Choi char *buf) 439f262f28cSChanwoo Choi { 440f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 441f262f28cSChanwoo Choi 442f262f28cSChanwoo Choi if (!edev || !edev->desc) 443f262f28cSChanwoo Choi return -EINVAL; 444f262f28cSChanwoo Choi 445f262f28cSChanwoo Choi return sprintf(buf, "%s\n", edev->desc->name); 446f262f28cSChanwoo Choi } 447f262f28cSChanwoo Choi static DEVICE_ATTR_RO(name); 448f262f28cSChanwoo Choi 449f262f28cSChanwoo Choi static ssize_t enable_count_show(struct device *dev, 450f262f28cSChanwoo Choi struct device_attribute *attr, char *buf) 451f262f28cSChanwoo Choi { 452f262f28cSChanwoo Choi struct devfreq_event_dev *edev = to_devfreq_event(dev); 453f262f28cSChanwoo Choi 454f262f28cSChanwoo Choi if (!edev || !edev->desc) 455f262f28cSChanwoo Choi return -EINVAL; 456f262f28cSChanwoo Choi 457f262f28cSChanwoo Choi return sprintf(buf, "%d\n", edev->enable_count); 458f262f28cSChanwoo Choi } 459f262f28cSChanwoo Choi static DEVICE_ATTR_RO(enable_count); 460f262f28cSChanwoo Choi 461f262f28cSChanwoo Choi static struct attribute *devfreq_event_attrs[] = { 462f262f28cSChanwoo Choi &dev_attr_name.attr, 463f262f28cSChanwoo Choi &dev_attr_enable_count.attr, 464f262f28cSChanwoo Choi NULL, 465f262f28cSChanwoo Choi }; 466f262f28cSChanwoo Choi ATTRIBUTE_GROUPS(devfreq_event); 467f262f28cSChanwoo Choi 468f262f28cSChanwoo Choi static int __init devfreq_event_init(void) 469f262f28cSChanwoo Choi { 470f262f28cSChanwoo Choi devfreq_event_class = class_create(THIS_MODULE, "devfreq-event"); 471f262f28cSChanwoo Choi if (IS_ERR(devfreq_event_class)) { 472f262f28cSChanwoo Choi pr_err("%s: couldn't create class\n", __FILE__); 473f262f28cSChanwoo Choi return PTR_ERR(devfreq_event_class); 474f262f28cSChanwoo Choi } 475f262f28cSChanwoo Choi 476f262f28cSChanwoo Choi devfreq_event_class->dev_groups = devfreq_event_groups; 477f262f28cSChanwoo Choi 478f262f28cSChanwoo Choi return 0; 479f262f28cSChanwoo Choi } 480f262f28cSChanwoo Choi subsys_initcall(devfreq_event_init); 481