/** * of_devfreq_cooling_register_power() - Register devfreq cooling device, * with OF and power information. * @np: Pointer to OF device_node. * @df: Pointer to devfreq device. * @dfc_power: Pointer to devfreq_cooling_power. * * Register a devfreq cooling device. The available OPPs must be * registered on the device. * * If @dfc_power is provided, the cooling device is registered with the * power extensions. For the power extensions to work correctly, * devfreq should use the simple_ondemand governor, other governors * are not currently supported. */ struct thermal_cooling_device * of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, struct devfreq_cooling_power *dfc_power) { struct thermal_cooling_device *cdev; struct devfreq_cooling_device *dfc; char dev_name[THERMAL_NAME_LENGTH]; int err; dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); if (!dfc) return ERR_PTR(-ENOMEM); dfc->devfreq = df; if (dfc_power) { dfc->power_ops = dfc_power; devfreq_cooling_ops.get_requested_power = devfreq_cooling_get_requested_power; devfreq_cooling_ops.state2power = devfreq_cooling_state2power; devfreq_cooling_ops.power2state = devfreq_cooling_power2state; } err = devfreq_cooling_gen_tables(dfc); if (err) goto free_dfc; err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL); if (err < 0) goto free_tables; dfc->id = err; snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); cdev = thermal_of_cooling_device_register(np, dev_name, dfc, &devfreq_cooling_ops); if (IS_ERR(cdev)) { err = PTR_ERR(cdev); dev_err(df->dev.parent, "Failed to register devfreq cooling device (%d)\n", err); goto release_ida; } dfc->cdev = cdev; return cdev; release_ida: ida_simple_remove(&devfreq_ida, dfc->id); free_tables: kfree(dfc->power_table); kfree(dfc->freq_table); free_dfc: kfree(dfc); return ERR_PTR(err); }
/** * __isp_cooling_register - helper function to create isp cooling device * @np: a valid struct device_node to the cooling device device tree node * @clip_isp: ispmask of isp where the fps constraints will happen. * * This interface function registers the isp cooling device with the name * "thermal-isp-%x". This api can support multiple instances of isp * cooling devices. It also gives the opportunity to link the cooling device * with a device tree node, in order to bind it via the thermal DT code. * * Return: a valid struct thermal_cooling_device pointer on success, * on failure, it returns a corresponding ERR_PTR(). */ static struct thermal_cooling_device * __isp_cooling_register(struct device_node *np, const struct cpumask *clip_isp) { struct thermal_cooling_device *cool_dev; struct isp_cooling_device *isp_dev = NULL; char dev_name[THERMAL_NAME_LENGTH]; int ret = 0; isp_dev = kzalloc(sizeof(struct isp_cooling_device), GFP_KERNEL); if (!isp_dev) return ERR_PTR(-ENOMEM); ret = get_idr(&isp_idr, &isp_dev->id); if (ret) { kfree(isp_dev); return ERR_PTR(-EINVAL); } snprintf(dev_name, sizeof(dev_name), "thermal-isp-%d", isp_dev->id); cool_dev = thermal_of_cooling_device_register(np, dev_name, isp_dev, &isp_cooling_ops); if (IS_ERR(cool_dev)) { release_idr(&isp_idr, isp_dev->id); kfree(isp_dev); return cool_dev; } isp_dev->cool_dev = cool_dev; isp_dev->isp_state = 0; mutex_lock(&cooling_isp_lock); isp_dev_count++; mutex_unlock(&cooling_isp_lock); return cool_dev; }
/** * __cpufreq_cooling_register - helper function to create cpufreq cooling device * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq * cooling devices. It also gives the opportunity to link the cooling device * with a device tree node, in order to bind it via the thermal DT code. * * Return: a valid struct thermal_cooling_device pointer on success, * on failure, it returns a corresponding ERR_PTR(). */ static struct thermal_cooling_device * __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev = NULL; unsigned int min = 0, max = 0; char dev_name[THERMAL_NAME_LENGTH]; int ret = 0, i; struct cpufreq_policy policy; /* Verify that all the clip cpus have same freq_min, freq_max limit */ for_each_cpu(i, clip_cpus) { /* continue if cpufreq policy not found and not return error */ if (!cpufreq_get_policy(&policy, i)) continue; if (min == 0 && max == 0) { min = policy.cpuinfo.min_freq; max = policy.cpuinfo.max_freq; } else { if (min != policy.cpuinfo.min_freq || max != policy.cpuinfo.max_freq) return ERR_PTR(-EINVAL); } } cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), GFP_KERNEL); if (!cpufreq_dev) return ERR_PTR(-ENOMEM); cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { kfree(cpufreq_dev); return ERR_PTR(-EINVAL); } snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", cpufreq_dev->id); cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, &cpufreq_cooling_ops); if (IS_ERR(cool_dev)) { release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); return ERR_PTR(-EINVAL); } cpufreq_dev->cool_dev = cool_dev; cpufreq_dev->cpufreq_state = 0; mutex_lock(&cooling_cpufreq_lock); /* Register the notifier for first cpufreq cooling device */ if (cpufreq_dev_count == 0) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); cpufreq_dev_count++; mutex_unlock(&cooling_cpufreq_lock); return cool_dev; }