summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/nct1008.c118
1 files changed, 117 insertions, 1 deletions
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c
index f5287142252f..cd42102f432a 100644
--- a/drivers/misc/nct1008.c
+++ b/drivers/misc/nct1008.c
@@ -32,6 +32,7 @@
#include <linux/nct1008.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
+#include <linux/thermal.h>
#define DRIVER_NAME "nct1008"
@@ -96,6 +97,9 @@ struct nct1008_data {
u8 limits_sz;
void (*alarm_fn)(bool raised);
struct regulator *nct_reg;
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+ struct thermal_zone_device *thz;
+#endif
};
static inline s8 value_to_temperature(bool extended, u8 value)
@@ -604,6 +608,9 @@ static int nct1008_enable_alert(struct nct1008_data *data)
return ret;
}
+/* The thermal sysfs handles notifying the throttling
+ * cooling device */
+#ifndef CONFIG_TEGRA_THERMAL_SYSFS
static bool throttle_enb;
static void therm_throttle(struct nct1008_data *data, bool enable)
{
@@ -620,6 +627,12 @@ static void therm_throttle(struct nct1008_data *data, bool enable)
mutex_unlock(&data->mutex);
}
}
+#endif
+
+/* Thermal sysfs handles hysteresis */
+#ifndef CONFIG_TEGRA_THERMAL_SYSFS
+ #define ALERT_HYSTERESIS_THROTTLE 1
+#endif
#define ALERT_HYSTERESIS_THROTTLE 1
#define ALERT_HYSTERESIS_EDP 3
@@ -666,6 +679,9 @@ static void nct1008_work_func(struct work_struct *work)
}
hysteresis = ALERT_HYSTERESIS_EDP;
+
+/* Thermal sysfs handles hysteresis */
+#ifndef CONFIG_TEGRA_THERMAL_SYSFS
throttling_ext_limit_milli =
CELSIUS_TO_MILLICELSIUS(data->plat_data.throttling_ext_limit);
@@ -679,11 +695,13 @@ static void nct1008_work_func(struct work_struct *work)
/* switch off throttling */
therm_throttle(data, false);
}
+#endif
if (temp_milli < CELSIUS_TO_MILLICELSIUS(data->limits[0])) {
lo_limit = 0;
hi_limit = data->limits[0];
- } else if (temp_milli >= CELSIUS_TO_MILLICELSIUS(data->limits[nentries-1])) {
+ } else if (temp_milli >=
+ CELSIUS_TO_MILLICELSIUS(data->limits[nentries-1])) {
lo_limit = data->limits[nentries-1] - hysteresis;
hi_limit = data->plat_data.shutdown_ext_limit;
} else {
@@ -740,6 +758,13 @@ static void nct1008_work_func(struct work_struct *work)
edp_thermal_zone_val = temp_milli;
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+ if (data->thz) {
+ if (!data->thz->passive)
+ thermal_zone_device_update(data->thz);
+ }
+#endif
+
out:
nct1008_enable_alert(data);
@@ -971,6 +996,66 @@ static unsigned int get_ext_mode_delay_ms(unsigned int conv_rate)
}
}
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+
+static int nct1008_thermal_zone_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdevice) {
+ /* Support only Thermal Throttling (1 trip) for now */
+ return thermal_zone_bind_cooling_device(thermal, 0, cdevice);
+}
+
+static int nct1008_thermal_zone_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdevice) {
+ /* Support only Thermal Throttling (1 trip) for now */
+ return thermal_zone_unbind_cooling_device(thermal, 0, cdevice);
+}
+
+static int nct1008_thermal_zone_get_temp(struct thermal_zone_device *thermal,
+ long *temp)
+{
+ struct nct1008_data *data = thermal->devdata;
+
+ return nct1008_get_temp(&data->client->dev, temp);
+}
+
+static int nct1008_thermal_zone_get_trip_type(
+ struct thermal_zone_device *thermal,
+ int trip,
+ enum thermal_trip_type *type) {
+
+ /* Support only Thermal Throttling (1 trip) for now */
+ if (trip != 0)
+ return -EINVAL;
+
+ *type = THERMAL_TRIP_PASSIVE;
+
+ return 0;
+}
+
+static int nct1008_thermal_zone_get_trip_temp(
+ struct thermal_zone_device *thermal,
+ int trip,
+ long *temp) {
+ struct nct1008_data *data = thermal->devdata;
+
+ /* Support only Thermal Throttling (1 trip) for now */
+ if (trip != 0)
+ return -EINVAL;
+
+ *temp = CELSIUS_TO_MILLICELSIUS(data->plat_data.throttling_ext_limit);
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops nct1008_thermal_zone_ops = {
+ .bind = nct1008_thermal_zone_bind,
+ .unbind = nct1008_thermal_zone_unbind,
+ .get_temp = nct1008_thermal_zone_get_temp,
+ .get_trip_type = nct1008_thermal_zone_get_trip_type,
+ .get_trip_temp = nct1008_thermal_zone_get_trip_temp,
+};
+#endif
+
/*
* Manufacturer(OnSemi) recommended sequence for
* Extended Range mode is as follows
@@ -994,6 +1079,9 @@ static int __devinit nct1008_probe(struct i2c_client *client,
int err;
long temp_milli;
unsigned int delay;
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+ struct thermal_zone_device *thz;
+#endif
data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL);
@@ -1051,6 +1139,26 @@ static int __devinit nct1008_probe(struct i2c_client *client,
}
tegra_edp_update_thermal_zone(MILLICELSIUS_TO_CELSIUS(temp_milli));
+
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+ thz = thermal_zone_device_register("nct1008",
+ 1, /* trips */
+ data,
+ &nct1008_thermal_zone_ops,
+ 1, /* tc1 */
+ 5, /* tc2 */
+ 2000, /* passive delay */
+ 0); /* polling delay */
+
+ if (IS_ERR(thz)) {
+ data->thz = NULL;
+ err = -ENODEV;
+ goto error;
+ }
+
+ data->thz = thz;
+#endif
+
return 0;
error:
@@ -1068,6 +1176,14 @@ static int __devexit nct1008_remove(struct i2c_client *client)
if (data->dent)
debugfs_remove(data->dent);
+
+#ifdef CONFIG_TEGRA_THERMAL_SYSFS
+ if (data->thz) {
+ thermal_zone_device_unregister(data->thz);
+ data->thz = NULL;
+ }
+#endif
+
free_irq(data->client->irq, data);
cancel_work_sync(&data->work);
sysfs_remove_group(&client->dev.kobj, &nct1008_attr_group);