thermal: exynos: use device resource management infrastructure
[deliverable/linux.git] / drivers / thermal / samsung / exynos_thermal_common.c
index c9edc307dcf39916e8e5521f3d2a2a7751f212a3..4d8e4445ea102560e9f7d711560b42a82b95dcf5 100644 (file)
@@ -37,12 +37,11 @@ struct exynos_thermal_zone {
        bool bind;
 };
 
-static struct exynos_thermal_zone *th_zone;
-
 /* Get mode callback functions for thermal zone */
 static int exynos_get_mode(struct thermal_zone_device *thermal,
                        enum thermal_device_mode *mode)
 {
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
        if (th_zone)
                *mode = th_zone->mode;
        return 0;
@@ -52,25 +51,28 @@ static int exynos_get_mode(struct thermal_zone_device *thermal,
 static int exynos_set_mode(struct thermal_zone_device *thermal,
                        enum thermal_device_mode mode)
 {
-       if (!th_zone->therm_dev) {
-               pr_notice("thermal zone not registered\n");
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       if (!th_zone) {
+               dev_err(th_zone->sensor_conf->dev,
+                       "thermal zone not registered\n");
                return 0;
        }
 
-       mutex_lock(&th_zone->therm_dev->lock);
+       mutex_lock(&thermal->lock);
 
        if (mode == THERMAL_DEVICE_ENABLED &&
                !th_zone->sensor_conf->trip_data.trigger_falling)
-               th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+               thermal->polling_delay = IDLE_INTERVAL;
        else
-               th_zone->therm_dev->polling_delay = 0;
+               thermal->polling_delay = 0;
 
-       mutex_unlock(&th_zone->therm_dev->lock);
+       mutex_unlock(&thermal->lock);
 
        th_zone->mode = mode;
-       thermal_zone_device_update(th_zone->therm_dev);
-       pr_info("thermal polling set for duration=%d msec\n",
-                               th_zone->therm_dev->polling_delay);
+       thermal_zone_device_update(thermal);
+       dev_dbg(th_zone->sensor_conf->dev,
+               "thermal polling set for duration=%d msec\n",
+               thermal->polling_delay);
        return 0;
 }
 
@@ -79,17 +81,24 @@ static int exynos_set_mode(struct thermal_zone_device *thermal,
 static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
                                 enum thermal_trip_type *type)
 {
-       switch (GET_ZONE(trip)) {
-       case MONITOR_ZONE:
-       case WARN_ZONE:
-               *type = THERMAL_TRIP_ACTIVE;
-               break;
-       case PANIC_ZONE:
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+       int trip_type;
+
+       if (trip < 0 || trip >= max_trip)
+               return -EINVAL;
+
+       trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
+
+       if (trip_type == SW_TRIP)
                *type = THERMAL_TRIP_CRITICAL;
-               break;
-       default:
+       else if (trip_type == THROTTLE_ACTIVE)
+               *type = THERMAL_TRIP_ACTIVE;
+       else if (trip_type == THROTTLE_PASSIVE)
+               *type = THERMAL_TRIP_PASSIVE;
+       else
                return -EINVAL;
-       }
+
        return 0;
 }
 
@@ -97,7 +106,10 @@ static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
 static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
                                unsigned long *temp)
 {
-       if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+
+       if (trip < 0 || trip >= max_trip)
                return -EINVAL;
 
        *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
@@ -111,10 +123,10 @@ static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
 static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
                                unsigned long *temp)
 {
-       int ret;
-       /* Panic zone */
-       ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
-       return ret;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+       /* Get the temp of highest trip*/
+       return exynos_get_trip_temp(thermal, max_trip - 1, temp);
 }
 
 /* Bind callback functions for thermal zone */
@@ -123,13 +135,14 @@ static int exynos_bind(struct thermal_zone_device *thermal,
 {
        int ret = 0, i, tab_size, level;
        struct freq_clip_table *tab_ptr, *clip_data;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
        struct thermal_sensor_conf *data = th_zone->sensor_conf;
 
        tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
        tab_size = data->cooling_data.freq_clip_count;
 
        if (tab_ptr == NULL || tab_size == 0)
-               return -EINVAL;
+               return 0;
 
        /* find the cooling device registered*/
        for (i = 0; i < th_zone->cool_dev_size; i++)
@@ -151,7 +164,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
                case WARN_ZONE:
                        if (thermal_zone_bind_cooling_device(thermal, i, cdev,
                                                                level, 0)) {
-                               pr_err("error binding cdev inst %d\n", i);
+                               dev_err(data->dev,
+                                       "error unbinding cdev inst=%d\n", i);
                                ret = -EINVAL;
                        }
                        th_zone->bind = true;
@@ -169,6 +183,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
                        struct thermal_cooling_device *cdev)
 {
        int ret = 0, i, tab_size;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
        struct thermal_sensor_conf *data = th_zone->sensor_conf;
 
        if (th_zone->bind == false)
@@ -177,7 +192,7 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
        tab_size = data->cooling_data.freq_clip_count;
 
        if (tab_size == 0)
-               return -EINVAL;
+               return 0;
 
        /* find the cooling device registered*/
        for (i = 0; i < th_zone->cool_dev_size; i++)
@@ -195,7 +210,8 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
                case WARN_ZONE:
                        if (thermal_zone_unbind_cooling_device(thermal, i,
                                                                cdev)) {
-                               pr_err("error unbinding cdev inst=%d\n", i);
+                               dev_err(data->dev,
+                                       "error unbinding cdev inst=%d\n", i);
                                ret = -EINVAL;
                        }
                        th_zone->bind = false;
@@ -211,13 +227,15 @@ static int exynos_unbind(struct thermal_zone_device *thermal,
 static int exynos_get_temp(struct thermal_zone_device *thermal,
                        unsigned long *temp)
 {
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
        void *data;
 
        if (!th_zone->sensor_conf) {
-               pr_info("Temperature sensor not initialised\n");
+               dev_err(th_zone->sensor_conf->dev,
+                       "Temperature sensor not initialised\n");
                return -EINVAL;
        }
-       data = th_zone->sensor_conf->private_data;
+       data = th_zone->sensor_conf->driver_data;
        *temp = th_zone->sensor_conf->read_temperature(data);
        /* convert the temperature into millicelsius */
        *temp = *temp * MCELSIUS;
@@ -230,12 +248,14 @@ static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
 {
        void *data;
        int ret = -EINVAL;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
 
        if (!th_zone->sensor_conf) {
-               pr_info("Temperature sensor not initialised\n");
+               dev_err(th_zone->sensor_conf->dev,
+                       "Temperature sensor not initialised\n");
                return -EINVAL;
        }
-       data = th_zone->sensor_conf->private_data;
+       data = th_zone->sensor_conf->driver_data;
        if (th_zone->sensor_conf->write_emul_temp)
                ret = th_zone->sensor_conf->write_emul_temp(data, temp);
        return ret;
@@ -277,14 +297,22 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
  * This function may be called from interrupt based temperature sensor
  * when threshold is changed.
  */
-void exynos_report_trigger(void)
+void exynos_report_trigger(struct thermal_sensor_conf *conf)
 {
        unsigned int i;
        char data[10];
        char *envp[] = { data, NULL };
+       struct exynos_thermal_zone *th_zone;
 
-       if (!th_zone || !th_zone->therm_dev)
+       if (!conf || !conf->pzone_data) {
+               pr_err("Invalid temperature sensor configuration data\n");
+               return;
+       }
+
+       th_zone = conf->pzone_data;
+       if (th_zone->therm_dev)
                return;
+
        if (th_zone->bind == false) {
                for (i = 0; i < th_zone->cool_dev_size; i++) {
                        if (!th_zone->cool_dev[i])
@@ -322,54 +350,74 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
 {
        int ret;
        struct cpumask mask_val;
+       struct exynos_thermal_zone *th_zone;
 
        if (!sensor_conf || !sensor_conf->read_temperature) {
                pr_err("Temperature sensor not initialised\n");
                return -EINVAL;
        }
 
-       th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
+       th_zone = devm_kzalloc(sensor_conf->dev,
+                               sizeof(struct exynos_thermal_zone), GFP_KERNEL);
        if (!th_zone)
                return -ENOMEM;
 
        th_zone->sensor_conf = sensor_conf;
-       cpumask_set_cpu(0, &mask_val);
-       th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
-       if (IS_ERR(th_zone->cool_dev[0])) {
-               pr_err("Failed to register cpufreq cooling device\n");
-               ret = -EINVAL;
-               goto err_unregister;
+       /*
+        * TODO: 1) Handle multiple cooling devices in a thermal zone
+        *       2) Add a flag/name in cooling info to map to specific
+        *       sensor
+        */
+       if (sensor_conf->cooling_data.freq_clip_count > 0) {
+               cpumask_set_cpu(0, &mask_val);
+               th_zone->cool_dev[th_zone->cool_dev_size] =
+                                       cpufreq_cooling_register(&mask_val);
+               if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
+                       dev_err(sensor_conf->dev,
+                               "Failed to register cpufreq cooling device\n");
+                       ret = -EINVAL;
+                       goto err_unregister;
+               }
+               th_zone->cool_dev_size++;
        }
-       th_zone->cool_dev_size++;
 
-       th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
-                       EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
-                       sensor_conf->trip_data.trigger_falling ?
-                       0 : IDLE_INTERVAL);
+       th_zone->therm_dev = thermal_zone_device_register(
+                       sensor_conf->name, sensor_conf->trip_data.trip_count,
+                       0, th_zone, &exynos_dev_ops, NULL, 0,
+                       sensor_conf->trip_data.trigger_falling ? 0 :
+                       IDLE_INTERVAL);
 
        if (IS_ERR(th_zone->therm_dev)) {
-               pr_err("Failed to register thermal zone device\n");
+               dev_err(sensor_conf->dev,
+                       "Failed to register thermal zone device\n");
                ret = PTR_ERR(th_zone->therm_dev);
                goto err_unregister;
        }
        th_zone->mode = THERMAL_DEVICE_ENABLED;
+       sensor_conf->pzone_data = th_zone;
 
-       pr_info("Exynos: Kernel Thermal management registered\n");
+       dev_info(sensor_conf->dev,
+               "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
 
        return 0;
 
 err_unregister:
-       exynos_unregister_thermal();
+       exynos_unregister_thermal(sensor_conf);
        return ret;
 }
 
 /* Un-Register with the in-kernel thermal management */
-void exynos_unregister_thermal(void)
+void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
 {
        int i;
+       struct exynos_thermal_zone *th_zone;
 
-       if (!th_zone)
+       if (!sensor_conf || !sensor_conf->pzone_data) {
+               pr_err("Invalid temperature sensor configuration data\n");
                return;
+       }
+
+       th_zone = sensor_conf->pzone_data;
 
        if (th_zone->therm_dev)
                thermal_zone_device_unregister(th_zone->therm_dev);
@@ -379,6 +427,6 @@ void exynos_unregister_thermal(void)
                        cpufreq_cooling_unregister(th_zone->cool_dev[i]);
        }
 
-       kfree(th_zone);
-       pr_info("Exynos: Kernel Thermal management unregistered\n");
+       dev_info(sensor_conf->dev,
+               "Exynos: Kernel Thermal management unregistered\n");
 }
This page took 0.063269 seconds and 5 git commands to generate.