From 122912d536232a2d6cfe22ea1620125910500b05 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 13 Feb 2014 15:56:18 -0800 Subject: hwmon: tsensor: remove T30 temperature sensor code dev-kernel doesn't support Tegra30 chips any more, so remove the T30 thermal sensor code that's now dead. Bug 1201644 Bug 1380438 Bug 1482001 Change-Id: I71b2622f97147accddbeccee9a342e206dc1e322 Signed-off-by: Paul Walmsley Cc: Diwakar Tundlam Cc: Matthew Longnecker Reviewed-on: http://git-master/r/392199 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Diwakar Tundlam Tested-by: Diwakar Tundlam --- drivers/hwmon/Kconfig | 8 - drivers/hwmon/Makefile | 2 - drivers/hwmon/tegra-tsensor.c | 2140 ----------------------------------------- 3 files changed, 2150 deletions(-) delete mode 100644 drivers/hwmon/tegra-tsensor.c (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index a0becc671d88..146ef82994f8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1256,14 +1256,6 @@ config SENSORS_INA2XX This driver can also be built as a module. If so, the module will be called ina2xx. -config SENSORS_TEGRA_TSENSOR - tristate "Nvidia Tegra Integrated temperature sensor" - depends on ARCH_TEGRA_3x_SOC - default n - help - If you say yes here you get support for integrated - temperature sensor in Nvidia tegra chipset. - config SENSORS_THMC50 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index f73ea80f1553..55275e040c05 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -146,8 +146,6 @@ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_INA219) += ina219.o obj-$(CONFIG_SENSORS_INA230) += ina230.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o -CFLAGS_tegra-tsensor.o = -Werror -obj-$(CONFIG_SENSORS_TEGRA_TSENSOR) += tegra-tsensor.o obj-$(CONFIG_SENSORS_TMON_TMP411) += tmon-tmp411.o obj-$(CONFIG_PMBUS) += pmbus/ diff --git a/drivers/hwmon/tegra-tsensor.c b/drivers/hwmon/tegra-tsensor.c deleted file mode 100644 index ab2c92ad0d05..000000000000 --- a/drivers/hwmon/tegra-tsensor.c +++ /dev/null @@ -1,2140 +0,0 @@ -/* - * NVIDIA Tegra SOC - temperature sensor driver - * - * Copyright (C) 2011-2012 NVIDIA Corporation - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* HACK: These need to come from DT */ -#include "../../arch/arm/mach-tegra/iomap.h" - -/* macro to enable tsensor hw reset */ -/* FIXME: till tsensor temperature is reliable this should be 0 */ -#define ENABLE_TSENSOR_HW_RESET 1 - -/* tsensor instance used for temperature calculation */ -#define TSENSOR_FUSE_REV1 8 -#define TSENSOR_FUSE_REV2 21 - -/* version where tsensor temperature reading is accurate */ -#define STABLE_TSENSOR_FUSE_REV TSENSOR_FUSE_REV2 - -/* We have multiple tsensor instances with following registers */ -#define SENSOR_CFG0 0x40 -#define SENSOR_CFG1 0x48 -#define SENSOR_CFG2 0x4c -#define SENSOR_STATUS0 0x58 -#define SENSOR_TS_STATUS1 0x5c -#define SENSOR_TS_STATUS2 0x60 - -/* interrupt mask in tsensor status register */ -#define TSENSOR_SENSOR_X_STATUS0_0_INTR_MASK (1 << 8) - -#define SENSOR_CFG0_M_MASK 0xffff -#define SENSOR_CFG0_M_SHIFT 8 -#define SENSOR_CFG0_N_MASK 0xff -#define SENSOR_CFG0_N_SHIFT 24 -#define SENSOR_CFG0_RST_INTR_SHIFT 6 -#define SENSOR_CFG0_HW_DIV2_INTR_SHIFT 5 -#define SENSOR_CFG0_OVERFLOW_INTR 4 -#define SENSOR_CFG0_DVFS_INTR_SHIFT 3 -#define SENSOR_CFG0_RST_ENABLE_SHIFT 2 -#define SENSOR_CFG0_HW_DIV2_ENABLE_SHIFT 1 -#define SENSOR_CFG0_STOP_SHIFT 0 - -#define SENSOR_CFG_X_TH_X_MASK 0xffff -#define SENSOR_CFG1_TH2_SHIFT 16 -#define SENSOR_CFG1_TH1_SHIFT 0 -#define SENSOR_CFG2_TH3_SHIFT 0 -#define SENSOR_CFG2_TH0_SHIFT 16 - -#define SENSOR_STATUS_AVG_VALID_SHIFT 10 -#define SENSOR_STATUS_CURR_VALID_SHIFT 9 - -#define STATE_MASK 0x7 -#define STATUS0_STATE_SHIFT 0 -#define STATUS0_PREV_STATE_SHIFT 4 - -#define LOCAL_STR_SIZE1 60 -#define MAX_STR_LINE 100 -#define MAX_TSENSOR_LOOP1 (1000 * 2) - -#define TSENSOR_COUNTER_TOLERANCE 100 - -#define SENSOR_CTRL_RST_SHIFT 1 -#define RST_SRC_MASK 0x7 -#define RST_SRC_SENSOR 2 -#define CCLK_G_BURST_POLICY_REG_REL_OFFSET 0x368 -#define TSENSOR_SLOWDOWN_BIT 23 - -/* macros used for temperature calculations */ -/* assumed get_temperature_int and get_temperature_fraction - * calculate up to 6 decimal places. print temperature - * in code assumes 6 decimal place formatting */ -#define get_temperature_int(X) ((X) / 1000000) -#define get_temperature_fraction(X) (((int)(abs(X))) % 1000000) - -#define get_temperature_round(X) DIV_ROUND_CLOSEST(X, 1000000) - -#define MILLICELSIUS_TO_CELSIUS(i) ((i) / 1000) -#define CELSIUS_TO_MILLICELSIUS(i) ((i) * 1000) - -#define TSENSOR_MILLI_CELSIUS(x) \ - DIV_ROUND_CLOSEST((x), 1000) - -#define get_ts_state(data) tsensor_get_reg_field(data,\ - ((data->instance << 16) | SENSOR_STATUS0), \ - STATUS0_STATE_SHIFT, STATE_MASK) - -/* tsensor states */ -enum ts_state { - TS_INVALID = 0, - TS_LEVEL0, - TS_LEVEL1, - TS_LEVEL2, - TS_LEVEL3, - TS_OVERFLOW, - TS_MAX_STATE = TS_OVERFLOW -}; - -enum { - /* temperature is sensed from 2 points on tegra */ - TSENSOR_COUNT = 2, - TSENSOR_INSTANCE1 = 0, - TSENSOR_INSTANCE2 = 1, - /* divide by 2 temperature threshold */ - DIV2_CELSIUS_TEMP_THRESHOLD_DEFAULT = 70, - /* reset chip temperature threshold */ - RESET_CELSIUS_TEMP_THRESHOLD_DEFAULT = 75, - /* tsensor frequency in Hz for clk src CLK_M and divisor=24 */ - DEFAULT_TSENSOR_CLK_HZ = 500000, - DEFAULT_TSENSOR_N = 255, - DEFAULT_TSENSOR_M = 12500, - /* tsensor instance offset */ - TSENSOR_INSTANCE_OFFSET = 0x40, - MIN_THRESHOLD = 0x0, - MAX_THRESHOLD = 0xffff, - DEFAULT_THRESHOLD_TH0 = MAX_THRESHOLD, - DEFAULT_THRESHOLD_TH1 = MAX_THRESHOLD, - DEFAULT_THRESHOLD_TH2 = MAX_THRESHOLD, - DEFAULT_THRESHOLD_TH3 = MAX_THRESHOLD, -}; - -/* constants used to implement sysfs interface */ -enum tsensor_params { - TSENSOR_PARAM_TH1 = 0, - TSENSOR_PARAM_TH2, - TSENSOR_PARAM_TH3, - TSENSOR_TEMPERATURE, - TSENSOR_STATE, - TSENSOR_LIMITS, -}; - -enum tsensor_thresholds { - TSENSOR_TH0 = 0, - TSENSOR_TH1, - TSENSOR_TH2, - TSENSOR_TH3 -}; - -/* - * For each registered chip, we need to keep some data in memory. - * The structure is dynamically allocated. - */ -struct tegra_tsensor_data { - struct tegra_tsensor_platform_data plat_data; - struct delayed_work work; - struct workqueue_struct *workqueue; - struct mutex mutex; - struct device *hwmon_dev; - spinlock_t tsensor_lock; - struct clk *dev_clk; - /* tsensor register space */ - void __iomem *base; - unsigned long phys; - unsigned long phys_end; - /* pmc register space */ - void __iomem *pmc_rst_base; - unsigned long pmc_phys; - unsigned long pmc_phys_end; - /* clk register space */ - void __iomem *clk_rst_base; - int irq; - - /* save configuration before suspend and restore after resume */ - unsigned int config0[TSENSOR_COUNT]; - unsigned int config1[TSENSOR_COUNT]; - unsigned int config2[TSENSOR_COUNT]; - /* temperature readings from instance tsensor - 0/1 */ - unsigned int instance; - s64 A_e_minus12; - int B_e_minus6; - unsigned int fuse_T1; - unsigned int fuse_F1; - unsigned int fuse_T2; - unsigned int fuse_F2; - /* Quadratic fit coefficients: m=-0.003512 n=1.528943 p=-11.1 */ - int m_e_minus6; - int n_e_minus6; - int p_e_minus2; - - long current_hi_limit; - long current_lo_limit; - - bool is_edp_supported; - struct thermal_zone_device *thz; -}; - -enum { - TSENSOR_COEFF_SET1 = 0, - TSENSOR_COEFF_SET2, - TSENSOR_COEFF_END -}; - -struct tegra_tsensor_coeff { - int e_minus6_m; - int e_minus6_n; - int e_minus2_p; -}; - -static struct tegra_tsensor_coeff coeff_table[] = { - /* Quadratic fit coefficients: m=-0.002775 n=1.338811 p=-7.30 */ - [TSENSOR_COEFF_SET1] = { - -2775, - 1338811, - -730 - }, - /* Quadratic fit coefficients: m=-0.003512 n=1.528943 p=-11.1 */ - [TSENSOR_COEFF_SET2] = { - -3512, - 1528943, - -1110 - } - /* FIXME: add tsensor coefficients after chip characterization */ -}; - -/* pTemperature returned in 100 * Celsius */ -static int tsensor_count_2_temp(struct tegra_tsensor_data *data, - unsigned int count, int *p_temperature); -static unsigned int tsensor_get_threshold_counter( - struct tegra_tsensor_data *data, int temp); - -/* tsensor register access functions */ - -static void tsensor_writel(struct tegra_tsensor_data *data, u32 val, - unsigned long reg) -{ - unsigned int reg_offset = reg & 0xffff; - unsigned char inst = (reg >> 16) & 0xffff; - writel(val, data->base + (inst * TSENSOR_INSTANCE_OFFSET) + - reg_offset); - return; -} - -static unsigned int tsensor_readl(struct tegra_tsensor_data *data, - unsigned long reg) -{ - unsigned int reg_offset = reg & 0xffff; - unsigned char inst = (reg >> 16) & 0xffff; - return readl(data->base + - (inst * TSENSOR_INSTANCE_OFFSET) + reg_offset); -} - -static unsigned int tsensor_get_reg_field( - struct tegra_tsensor_data *data, unsigned int reg, - unsigned int shift, unsigned int mask) -{ - unsigned int reg_val; - reg_val = tsensor_readl(data, reg); - return (reg_val & (mask << shift)) >> shift; -} - -static int tsensor_set_reg_field( - struct tegra_tsensor_data *data, unsigned int value, - unsigned int reg, unsigned int shift, unsigned int mask) -{ - unsigned int reg_val; - unsigned int rd_val; - reg_val = tsensor_readl(data, reg); - reg_val &= ~(mask << shift); - reg_val |= ((value & mask) << shift); - tsensor_writel(data, reg_val, reg); - rd_val = tsensor_readl(data, reg); - if (rd_val == reg_val) - return 0; - else - return -EINVAL; -} - -/* enable argument is true to enable reset, false disables pmc reset */ -static void pmc_rst_enable(struct tegra_tsensor_data *data, bool enable) -{ - unsigned int val; - /* mapped first pmc reg is SENSOR_CTRL */ - val = readl(data->pmc_rst_base); - if (enable) - val |= (1 << SENSOR_CTRL_RST_SHIFT); - else - val &= ~(1 << SENSOR_CTRL_RST_SHIFT); - writel(val, data->pmc_rst_base); -} - -/* true returned when pmc reset source is tsensor */ -static bool pmc_check_rst_sensor(struct tegra_tsensor_data *data) -{ - unsigned int val; - unsigned char src; - val = readl(data->pmc_rst_base + 4); - src = (unsigned char)(val & RST_SRC_MASK); - if (src == RST_SRC_SENSOR) - return true; - else - return false; -} - -/* - * function to get chip revision specific tsensor coefficients - * obtained after chip characterization - */ -static void get_chip_tsensor_coeff(struct tegra_tsensor_data *data) -{ - unsigned short coeff_index; - - coeff_index = TSENSOR_COEFF_SET1; - if (data->instance == TSENSOR_INSTANCE1) - coeff_index = TSENSOR_COEFF_SET2; - data->m_e_minus6 = coeff_table[coeff_index].e_minus6_m; - data->n_e_minus6 = coeff_table[coeff_index].e_minus6_n; - data->p_e_minus2 = coeff_table[coeff_index].e_minus2_p; - pr_info("tsensor coeff: m=%d*10^-6,n=%d*10^-6,p=%d*10^-2\n", - data->m_e_minus6, data->n_e_minus6, data->p_e_minus2); -} - -/* tsensor counter read function */ -static int tsensor_read_counter( - struct tegra_tsensor_data *data, - unsigned int *p_counter) -{ - unsigned int status_reg; - unsigned int config0; - int iter_count = 0; - const int max_loop = 50; - - do { - config0 = tsensor_readl(data, ((data->instance << 16) | - SENSOR_CFG0)); - if (config0 & (1 << SENSOR_CFG0_STOP_SHIFT)) { - dev_dbg(data->hwmon_dev, "Error: tsensor " - "counter read with STOP bit not supported\n"); - *p_counter = 0; - return 0; - } - - status_reg = tsensor_readl(data, - (data->instance << 16) | SENSOR_STATUS0); - if (status_reg & (1 << - SENSOR_STATUS_CURR_VALID_SHIFT)) { - *p_counter = tsensor_readl(data, (data->instance - << 16) | SENSOR_TS_STATUS1); - break; - } - if (!(iter_count % 10)) - dev_dbg(data->hwmon_dev, "retry %d\n", iter_count); - - msleep(21); - iter_count++; - } while (iter_count < max_loop); - - if (iter_count == max_loop) - return -ENODEV; - - return 0; -} - -/* tsensor threshold print function */ -static void dump_threshold(struct tegra_tsensor_data *data) -{ - unsigned int TH_2_1, TH_0_3; - unsigned int curr_avg; - int err; - - TH_2_1 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG1); - TH_0_3 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG2); - dev_dbg(data->hwmon_dev, "Tsensor: TH_2_1=0x%x, " - "TH_0_3=0x%x\n", TH_2_1, TH_0_3); - err = tsensor_read_counter(data, &curr_avg); - if (err < 0) - pr_err("Error: tsensor counter read, " - "err=%d\n", err); - else - dev_dbg(data->hwmon_dev, "Tsensor: " - "curr_avg=0x%x\n", curr_avg); -} - -static int tsensor_get_temperature( - struct tegra_tsensor_data *data, - int *pTemp, unsigned int *pCounter) -{ - int err = 0; - unsigned int curr_avg; - - err = tsensor_read_counter(data, &curr_avg); - if (err < 0) - goto error; - - *pCounter = ((curr_avg & 0xFFFF0000) >> 16); - err = tsensor_count_2_temp(data, *pCounter, pTemp); - -error: - return err; -} - -static ssize_t tsensor_show_state(struct device *dev, - struct device_attribute *da, char *buf) -{ - int state; - struct tegra_tsensor_data *data = dev_get_drvdata(dev); - - state = get_ts_state(data); - - return snprintf(buf, 50, "%d\n", state); -} - -static ssize_t tsensor_show_limits(struct device *dev, - struct device_attribute *da, char *buf) -{ - struct tegra_tsensor_data *data = dev_get_drvdata(dev); - return snprintf(buf, 50, "%ld %ld\n", - data->current_lo_limit, data->current_hi_limit); -} - -/* tsensor temperature show function */ -static ssize_t tsensor_show_counters(struct device *dev, - struct device_attribute *da, char *buf) -{ - unsigned int curr_avg; - char err_str[] = "error-sysfs-counter-read\n"; - char fixed_str[MAX_STR_LINE]; - struct tegra_tsensor_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - int err; - int temp; - - if (attr->index == TSENSOR_TEMPERATURE) { - /* use current counter value to calculate temperature */ - err = tsensor_read_counter(data, &curr_avg); - if (err < 0) - goto error; - err = tsensor_count_2_temp(data, - ((curr_avg & 0xFFFF0000) >> 16), &temp); - if (err < 0) - goto error; - - dev_vdbg(data->hwmon_dev, "%s has curr_avg=0x%x, " - "temp0=%d\n", __func__, curr_avg, temp); - - snprintf(buf, (((LOCAL_STR_SIZE1 << 1) + 3) + - strlen(fixed_str)), - "%d.%06dC %#x\n", - get_temperature_int(temp), - get_temperature_fraction(temp), - ((curr_avg & 0xFFFF0000) >> 16)); - } - return strlen(buf); -error: - return snprintf(buf, strlen(err_str), "%s", err_str); -} - -/* utility function to check hw clock divide by 2 condition */ -static bool cclkg_check_hwdiv2_sensor(struct tegra_tsensor_data *data) -{ - unsigned int val; - val = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + - CCLK_G_BURST_POLICY_REG_REL_OFFSET)); - if ((1 << TSENSOR_SLOWDOWN_BIT) & val) { - dev_err(data->hwmon_dev, "Warning: ***** tsensor " - "slowdown bit detected\n"); - return true; - } else { - return false; - } -} - -/* - * function with table to return register, field shift and mask - * values for supported parameters - */ -static int get_param_values( - struct tegra_tsensor_data *data, unsigned int indx, - unsigned int *p_reg, unsigned int *p_sft, unsigned int *p_msk, - char *info, size_t info_len) -{ - switch (indx) { - case TSENSOR_PARAM_TH1: - *p_reg = ((data->instance << 16) | SENSOR_CFG1); - *p_sft = SENSOR_CFG1_TH1_SHIFT; - *p_msk = SENSOR_CFG_X_TH_X_MASK; - snprintf(info, info_len, "TH1[%d]: ", - data->instance); - break; - case TSENSOR_PARAM_TH2: - *p_reg = ((data->instance << 16) | SENSOR_CFG1); - *p_sft = SENSOR_CFG1_TH2_SHIFT; - *p_msk = SENSOR_CFG_X_TH_X_MASK; - snprintf(info, info_len, "TH2[%d]: ", - data->instance); - break; - case TSENSOR_PARAM_TH3: - *p_reg = ((data->instance << 16) | SENSOR_CFG2); - *p_sft = SENSOR_CFG2_TH3_SHIFT; - *p_msk = SENSOR_CFG_X_TH_X_MASK; - snprintf(info, info_len, "TH3[%d]: ", - data->instance); - break; - default: - return -ENOENT; - } - return 0; -} - -/* tsensor driver sysfs show function */ -static ssize_t show_tsensor_param(struct device *dev, - struct device_attribute *da, - char *buf) -{ - unsigned int val; - struct tegra_tsensor_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - unsigned int reg; - unsigned int sft; - unsigned int msk; - int err; - int temp; - char info[LOCAL_STR_SIZE1]; - - err = get_param_values(data, attr->index, ®, &sft, &msk, - info, sizeof(info)); - if (err < 0) - goto labelErr; - val = tsensor_get_reg_field(data, reg, sft, msk); - if (val == MAX_THRESHOLD) - snprintf(buf, PAGE_SIZE, "%s un-initialized threshold\n", info); - else { - err = tsensor_count_2_temp(data, val, &temp); - if (err != 0) - goto labelErr; - snprintf(buf, PAGE_SIZE, "%s threshold: %d.%06d Celsius\n", - info, get_temperature_int(temp), - get_temperature_fraction(temp)); - } - return strlen(buf); - -labelErr: - snprintf(buf, PAGE_SIZE, "ERROR:"); - return strlen(buf); -} - -/* tsensor driver sysfs store function */ -static ssize_t set_tsensor_param(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) -{ - int num; - struct tegra_tsensor_data *data = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - unsigned int reg; - unsigned int sft; - unsigned int msk; - int err; - unsigned int counter; - unsigned int val; - char info[LOCAL_STR_SIZE1]; - - if (kstrtoint(buf, 0, &num)) { - dev_err(dev, "file: %s, line=%d return %s()\n", - __FILE__, __LINE__, __func__); - return -EINVAL; - } - - counter = tsensor_get_threshold_counter(data, num); - - err = get_param_values(data, attr->index, ®, &sft, &msk, - info, sizeof(info)); - if (err < 0) - goto labelErr; - - err = tsensor_set_reg_field(data, counter, reg, sft, msk); - if (err < 0) - goto labelErr; - - /* TH2 clk divide check */ - if (attr->index == TSENSOR_PARAM_TH2) { - msleep(21); - (void)cclkg_check_hwdiv2_sensor(data); - } - val = tsensor_get_reg_field(data, reg, sft, msk); - dev_dbg(dev, "%s 0x%x\n", info, val); - return count; -labelErr: - dev_err(dev, "file: %s, line=%d, %s(), error=0x%x\n", __FILE__, - __LINE__, __func__, err); - return 0; -} - -static struct sensor_device_attribute tsensor_nodes[] = { - SENSOR_ATTR(tsensor_TH1, S_IRUGO | S_IWUSR, - show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH1), - SENSOR_ATTR(tsensor_TH2, S_IRUGO | S_IWUSR, - show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH2), - SENSOR_ATTR(tsensor_TH3, S_IRUGO | S_IWUSR, - show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH3), - SENSOR_ATTR(tsensor_temperature, S_IRUGO | S_IWUSR, - tsensor_show_counters, NULL, TSENSOR_TEMPERATURE), - SENSOR_ATTR(tsensor_state, S_IRUGO | S_IWUSR, - tsensor_show_state, NULL, TSENSOR_STATE), - SENSOR_ATTR(tsensor_limits, S_IRUGO | S_IWUSR, - tsensor_show_limits, NULL, TSENSOR_LIMITS), -}; - -int tsensor_thermal_get_temp(struct tegra_tsensor_data *data, - long *milli_temp) -{ - int counter, temp, err; - int temp_state, ts_state; - - err = tsensor_get_temperature(data, - &temp, - &counter); - if (err) - return err; - - /* temperature is in milli-Celsius */ - temp = TSENSOR_MILLI_CELSIUS(temp); - - mutex_lock(&data->mutex); - - /* This section of logic is done in order to make sure that - * the temperature read corresponds to the current hw state. - * If it is not, return the nearest temperature - */ - if ((data->current_lo_limit != 0) || - (data->current_hi_limit)) { - - if (temp <= data->current_lo_limit) - temp_state = TS_LEVEL0; - else if (temp < data->current_hi_limit) - temp_state = TS_LEVEL1; - else - temp_state = TS_LEVEL2; - - ts_state = get_ts_state(data); - - if (ts_state != temp_state) { - - switch (ts_state) { - case TS_LEVEL0: - temp = data->current_lo_limit - 1; - break; - case TS_LEVEL1: - if (temp_state == TS_LEVEL0) - temp = data->current_lo_limit + 1; - else - temp = data->current_hi_limit - 1; - break; - case TS_LEVEL2: - temp = data->current_hi_limit + 1; - break; - } - - } - - } - - mutex_unlock(&data->mutex); - - *milli_temp = temp; - - return 0; -} - -/* tsensor driver interrupt handler */ -static irqreturn_t tegra_tsensor_isr(int irq, void *arg_data) -{ - struct tegra_tsensor_data *data = - (struct tegra_tsensor_data *)arg_data; - unsigned long flags; - unsigned int val; - int new_state; - - spin_lock_irqsave(&data->tsensor_lock, flags); - - val = tsensor_readl(data, (data->instance << 16) | SENSOR_STATUS0); - if (val & TSENSOR_SENSOR_X_STATUS0_0_INTR_MASK) { - new_state = get_ts_state(data); - - /* counter overflow check */ - if (new_state == TS_OVERFLOW) - dev_err(data->hwmon_dev, "Warning: " - "***** OVERFLOW tsensor\n"); - - /* We only care if we go above hi or below low thresholds */ - if (data->is_edp_supported && new_state != TS_LEVEL1) - queue_delayed_work(data->workqueue, &data->work, 0); - } - - tsensor_writel(data, val, (data->instance << 16) | SENSOR_STATUS0); - - spin_unlock_irqrestore(&data->tsensor_lock, flags); - - return IRQ_HANDLED; -} - -/* - * function to read fuse registers and give - T1, T2, F1 and F2 - */ -static int read_tsensor_fuse_regs(struct tegra_tsensor_data *data) -{ - unsigned int reg1; - unsigned int T1 = 0, T2 = 0; - unsigned int spare_bits; - int err; - - /* read tsensor calibration register */ - /* - * High (~90 DegC) Temperature Calibration value (upper 16 bits of - * FUSE_TSENSOR_CALIB_0) - F2 - * Low (~25 deg C) Temperature Calibration value (lower 16 bits of - * FUSE_TSENSOR_CALIB_0) - F1 - */ - err = tegra_fuse_get_tsensor_calibration_data(®1); - if (err) - goto errLabel; - data->fuse_F1 = reg1 & 0xFFFF; - data->fuse_F2 = (reg1 >> 16) & 0xFFFF; - - err = tegra_fuse_get_tsensor_spare_bits(&spare_bits); - if (err) { - pr_err("tsensor spare bit fuse read error=%d\n", err); - goto errLabel; - } - - /* - * FUSE_TJ_ADT_LOWT = T1, FUSE_TJ_ADJ = T2 - */ - - /* - * Low temp is: - * FUSE_TJ_ADT_LOWT = bits [20:14] or’ed with bits [27:21] - */ - T1 = ((spare_bits >> 14) & 0x7F) | - ((spare_bits >> 21) & 0x7F); - dev_vdbg(data->hwmon_dev, "Tsensor low temp (T1) fuse :\n"); - - /* - * High temp is: - * FUSE_TJ_ADJ = bits [6:0] or’ed with bits [13:7] - */ - dev_vdbg(data->hwmon_dev, "Tsensor low temp (T2) fuse :\n"); - T2 = (spare_bits & 0x7F) | ((spare_bits >> 7) & 0x7F); - pr_info("Tsensor fuse calibration F1=%d(%#x), F2=%d(%#x), T1=%d, T2=%d\n", - data->fuse_F1, data->fuse_F1, - data->fuse_F2, data->fuse_F2, T1, T2); - data->fuse_T1 = T1; - data->fuse_T2 = T2; - return 0; -errLabel: - return err; -} - -/* function to calculate interim temperature */ -static int calc_interim_temp(struct tegra_tsensor_data *data, - unsigned int counter, s64 *p_interim_temp) -{ - s64 val1_64; - s64 val2; - u32 temp_rem; - bool is_neg; - u32 divisor; - - /* - * T-int = A * Counter + B - * (Counter is the sensor frequency output) - */ - if ((data->fuse_F2 - data->fuse_F1) <= (data->fuse_T2 - - data->fuse_T1)) { - dev_err(data->hwmon_dev, "Error: F2=%d, F1=%d " - "difference unexpectedly low. " - "Aborting temperature processing\n", data->fuse_F2, - data->fuse_F1); - return -EINVAL; - } else { - /* expression modified after assuming s_A is 10^6 times, - * s_B is 10^2 times and want end result to be 10^2 times - * actual value - */ - val1_64 = (data->A_e_minus12 * counter); - dev_dbg(data->hwmon_dev, "A_e_-12*counter=%lld\n", val1_64); - val2 = (s64)data->B_e_minus6 * 1000000ULL; - dev_dbg(data->hwmon_dev, "B_e_-12=%lld\n", val2); - val2 += val1_64; - dev_dbg(data->hwmon_dev, "A_counter+B=%lld\n", val2); - is_neg = false; - if (val2 < 0) { - is_neg = true; - val2 *= -1; - } - divisor = 1000000; - temp_rem = do_div(val2, divisor); - if (temp_rem > (divisor >> 1)) - val2++; - if (is_neg) - val2 *= -1; - *p_interim_temp = val2; - dev_dbg(data->hwmon_dev, "counter=%d, interim_temp=%lld\n", - counter, *p_interim_temp); - } - return 0; -} - -/* - * function to calculate final temperature, given - * interim temperature - */ -static void calc_final_temp(struct tegra_tsensor_data *data, - s64 interim_temp, int *p_final_temp) -{ - s64 temp1_64, temp2_64, temp_64, temp1_64_rem; - u32 temp_rem_32; - u32 divisor; - u64 divisor_64; - bool is_neg; - /* - * T-final = m * T-int ^2 + n * T-int + p - * m = -0.002775 - * n = 1.338811 - * p = -7.3 - */ - - temp1_64 = (interim_temp * interim_temp); - /* always positive as squaring value */ - /* losing accuracy here */ - divisor = 10000; - /* temp1_64 contains quotient and returns remainder */ - temp_rem_32 = do_div(temp1_64, divisor); - if (temp_rem_32 > (divisor >> 1)) - temp1_64++; - temp1_64 *= (s64)data->m_e_minus6; - dev_dbg(data->hwmon_dev, "m_T-interim^2_e^14=%lld\n", temp1_64); - temp1_64_rem = (s64)data->m_e_minus6 * (s64)temp_rem_32; - is_neg = false; - if (temp1_64_rem < 0) { - is_neg = true; - temp1_64_rem *= -1; - } - temp_rem_32 = do_div(temp1_64_rem, divisor); - if (temp_rem_32 > (divisor >> 1)) - temp1_64_rem++; - if (is_neg) - temp1_64_rem *= -1; - /* temp1_64 is m * t-int * t-int * 10^14 */ - - temp2_64 = (s64)data->n_e_minus6 * interim_temp * 100; - dev_dbg(data->hwmon_dev, "n_T-interim_e^14=%lld\n", temp2_64); - /* temp2_64 is n * t-int * 10^14 */ - - temp_64 = ((s64)data->p_e_minus2 * (s64)1000000000000ULL); - /* temp_64 is n * 10^14 */ - temp_64 += temp1_64 + temp2_64 + temp1_64_rem; - is_neg = false; - if (temp_64 < 0) { - is_neg = true; - temp_64 *= -1; - } - divisor_64 = 100000000ULL; - temp_rem_32 = do_div(temp_64, divisor_64); - if (temp_rem_32 > (divisor_64 >> 1)) - temp_64++; - if (is_neg) - temp_64 *= -1; - /* temperature * 10^14 / 10^8 */ - /* get LS decimal digit rounding */ - *p_final_temp = (s32)temp_64; - dev_dbg(data->hwmon_dev, "T-final stage4=%d\n", *p_final_temp); -} - -/* - * Function to compute constants A and B needed for temperature - * calculation - * A = (T2-T1) / (F2-F1) - * B = T1 – A * F1 - */ -static int tsensor_get_const_AB(struct tegra_tsensor_data *data) -{ - int err; - s64 temp_val1, temp_val2; - u32 temp_rem; - bool is_neg; - u32 divisor; - - /* - * 1. Find fusing registers for 25C (T1, F1) and 90C (T2, F2); - */ - err = read_tsensor_fuse_regs(data); - if (err) { - dev_err(data->hwmon_dev, "Fuse register read required " - "for internal tsensor returns err=%d\n", err); - return err; - } - - if (data->fuse_F2 != data->fuse_F1) { - if ((data->fuse_F2 - data->fuse_F1) <= (data->fuse_T2 - - data->fuse_T1)) { - dev_err(data->hwmon_dev, "Error: F2=%d, " - "F1=%d, difference" - " unexpectedly low. Aborting temperature" - "computation\n", data->fuse_F2, data->fuse_F1); - return -EINVAL; - } else { - temp_val1 = (s64)(data->fuse_T2 - data->fuse_T1) * - 1000000000000ULL; - /* temp_val1 always positive as fuse_T2 > fuse_T1 */ - temp_rem = do_div(temp_val1, (data->fuse_F2 - - data->fuse_F1)); - data->A_e_minus12 = temp_val1; - temp_val2 = (s64)(data->fuse_T1 * 1000000000000ULL); - temp_val2 -= (data->A_e_minus12 * data->fuse_F1); - is_neg = false; - if (temp_val2 < 0) { - is_neg = true; - temp_val2 *= -1; - } - divisor = 1000000; - temp_rem = do_div(temp_val2, divisor); - if (temp_rem > (divisor >> 1)) - temp_val2++; - if (is_neg) - temp_val2 *= -1; - data->B_e_minus6 = (s32)temp_val2; - /* B is 10^6 times now */ - } - } - dev_info(data->hwmon_dev, "A_e_minus12 = %lld\n", data->A_e_minus12); - dev_info(data->hwmon_dev, "B_e_minus6 = %d\n", data->B_e_minus6); - return 0; -} - -/* - * function calculates expected temperature corresponding to - * given tsensor counter value - * Value returned is 100 times calculated temperature since the - * calculations are using fixed point arithmetic instead of floating point - */ -static int tsensor_count_2_temp(struct tegra_tsensor_data *data, - unsigned int count, int *p_temperature) -{ - s64 interim_temp; - int err; - - /* - * - * 2. Calculate interim temperature: - */ - err = calc_interim_temp(data, count, &interim_temp); - if (err < 0) { - dev_err(data->hwmon_dev, "tsensor: cannot read temperature\n"); - *p_temperature = -1; - return err; - } - - /* - * - * 3. Calculate final temperature: - */ - calc_final_temp(data, interim_temp, p_temperature); - /* logs counter -> temperature conversion */ - dev_dbg(data->hwmon_dev, "tsensor: counter=0x%x, interim " - "temp*10^6=%lld, Final temp=%d.%06d\n", - count, interim_temp, - get_temperature_int(*p_temperature), - get_temperature_fraction(*p_temperature)); - return 0; -} - -/* - * function to solve quadratic roots of equation - * used to get counter corresponding to given temperature - */ -static void get_quadratic_roots(struct tegra_tsensor_data *data, - int temp, unsigned int *p_counter1, - unsigned int *p_counter2) -{ - /* - * Equation to solve: - * m * A^2 * Counter^2 + - * A * (2 * m * B + n) * Counter + - * (m * B^2 + n * B + p - Temperature) = 0 - - To calculate root - assume - b = A * (2 * m * B + n) - a = m * A^2 - c = ((m * B^2) + n * B + p - temp) - root1 = (-b + sqrt(b^2 - (4*a*c))) / (2 * a) - root2 = (-b - sqrt(b^2 - (4*a*c))) / (2 * a) - sqrt(k) = sqrt(k * 10^6) / sqrt(10^6) - - Roots are : - (-(2*m*B+n)+sqrt(((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp))))/(2*m*A) - and - (-(2*m*B+n)-sqrt(((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp))))/(2*m*A) - - After simplify ((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp)), - Roots are: - (-(2*m*B+n)+sqrt((n^2-4*m(p-temp))))/(2*m*A) - and - (-(2*m*B+n)-sqrt((n^2-4*m(p-temp))))/(2*m*A) - */ - - int v_e_minus6_2mB_n; - int v_e_minus6_4m_p_minusTemp; - int v_e_minus6_n2; - int v_e_minus6_b2_minus4ac; - int v_e_minus6_sqrt_b2_minus4ac; - s64 v_e_minus12_2mA; - int root1, root2; - int temp_rem; - bool is_neg; - s64 temp_64; - - dev_dbg(data->hwmon_dev, "m_e-6=%d,n_e-6=%d,p_e-2=%d,A_e-6=%lld," - "B_e-2=%d\n", data->m_e_minus6, data->n_e_minus6, - data->p_e_minus2, data->A_e_minus12, data->B_e_minus6); - - temp_64 = (2ULL * (s64)data->m_e_minus6 * (s64)data->B_e_minus6); - is_neg = false; - if (temp_64 < 0) { - is_neg = true; - temp_64 *= -1; - } - temp_rem = do_div(temp_64, 1000000); - if (is_neg) - temp_64 *= -1; - v_e_minus6_2mB_n = (s32)temp_64 + data->n_e_minus6; - /* computed 2mB + n */ - - temp_64 = ((s64)data->m_e_minus6 * (s64)data->A_e_minus12); - temp_64 *= 2; - is_neg = false; - if (temp_64 < 0) { - temp_64 *= -1; - is_neg = true; - } - temp_rem = do_div(temp_64, 1000000); - if (is_neg) - temp_64 *= -1; - v_e_minus12_2mA = temp_64; - /* computed 2mA */ - - temp_64 = ((s64)data->n_e_minus6 * (s64)data->n_e_minus6); - /* squaring give positive value */ - temp_rem = do_div(temp_64, 1000000); - v_e_minus6_n2 = (s32)temp_64; - /* computed n^2 */ - - v_e_minus6_4m_p_minusTemp = data->p_e_minus2 - (temp * 100); - v_e_minus6_4m_p_minusTemp *= 4 * data->m_e_minus6; - v_e_minus6_4m_p_minusTemp = DIV_ROUND_CLOSEST( - v_e_minus6_4m_p_minusTemp,100); - /* computed 4m*(p-T)*/ - - v_e_minus6_b2_minus4ac = (v_e_minus6_n2 - v_e_minus6_4m_p_minusTemp); - - /* To preserve 1 decimal digits for sqrt(v_e_minus6_b2_minus4ac), - Make it 100 times, so - v_e_minus6_sqrt_b2_minus4ac=(int_sqrt(v_e_minus6_b2_minus4ac *100)*10^6) - /sqrt(10^6 * 100) - To avoid overflow,Simplify it to be: - v_e_minus6_sqrt_b2_minus4ac =(int_sqrt(v_e_minus6_b2_minus4ac *100)*100) - */ - - v_e_minus6_sqrt_b2_minus4ac = (int_sqrt(v_e_minus6_b2_minus4ac * 100) - * 100); - dev_dbg(data->hwmon_dev, "A_e_minus12=%lld, B_e_minus6=%d, " - "m_e_minus6=%d, n_e_minus6=%d, p_e_minus2=%d, " - "temp=%d\n", data->A_e_minus12, data->B_e_minus6, - data->m_e_minus6, - data->n_e_minus6, data->p_e_minus2, (int)temp); - dev_dbg(data->hwmon_dev, "2mB_n=%d, 2mA=%lld, 4m_p_minusTemp=%d," - "b2_minus4ac=%d\n", v_e_minus6_2mB_n, - v_e_minus12_2mA, v_e_minus6_4m_p_minusTemp, - v_e_minus6_b2_minus4ac); - - temp_64=(s64)(-v_e_minus6_2mB_n - v_e_minus6_sqrt_b2_minus4ac) * 1000000; - root1=(s32)div64_s64(temp_64, v_e_minus12_2mA); - - temp_64=(s64)(-v_e_minus6_2mB_n + v_e_minus6_sqrt_b2_minus4ac) * 1000000; - root2=(s32)div64_s64(temp_64, v_e_minus12_2mA); - - dev_dbg(data->hwmon_dev, "new expr: temp=%d, root1=%d, root2=%d\n", - temp, root1, root2); - - *p_counter1 = root1; - *p_counter2 = root2; - /* we find that root2 is more appropriate root */ - - /* logs temperature -> counter conversion */ - dev_dbg(data->hwmon_dev, "temperature=%d, counter1=%#x, " - "counter2=%#x\n", temp, *p_counter1, *p_counter2); -} - -/* - * function returns tsensor expected counter corresponding to input - * temperature in degree Celsius. - * e.g. for temperature of 35C, temp=35 - */ -static void tsensor_temp_2_count(struct tegra_tsensor_data *data, - int temp, - unsigned int *p_counter1, - unsigned int *p_counter2) -{ - dev_dbg(data->hwmon_dev, "Trying to calculate counter" - " for requested temperature" - " threshold=%d\n", temp); - /* - * calculate the constants needed to get roots of - * following quadratic eqn: - * m * A^2 * Counter^2 + - * A * (2 * m * B + n) * Counter + - * (m * B^2 + n * B + p - Temperature) = 0 - */ - get_quadratic_roots(data, temp, p_counter1, p_counter2); - /* - * checked at current temperature=35 the counter=11418 - * for 50 deg temperature: counter1=22731, counter2=11817 - * at 35 deg temperature: counter1=23137, counter2=11411 - * hence, for above values we are assuming counter2 has - * the correct value - */ -} - -/* - * function to compare computed and expected values with - * certain tolerance setting hard coded here - */ -static bool cmp_counter( - struct tegra_tsensor_data *data, - unsigned int actual, unsigned int exp) -{ - unsigned int smaller; - unsigned int larger; - smaller = (actual > exp) ? exp : actual; - larger = (smaller == actual) ? exp : actual; - if ((larger - smaller) > TSENSOR_COUNTER_TOLERANCE) { - dev_dbg(data->hwmon_dev, "actual=%d, exp=%d, larger=%d, " - "smaller=%d, tolerance=%d\n", actual, exp, larger, smaller, - TSENSOR_COUNTER_TOLERANCE); - return false; - } - return true; -} - -/* function to print chart of counter to temperature values - - * It uses F1, F2, T1, T2 and start data gives reading - * for temperature in between the range - */ -static void print_counter_2_temperature_table( - struct tegra_tsensor_data *data) -{ - int i; - unsigned int start_counter, end_counter; - unsigned int diff; - int temperature; - const unsigned int num_readings = 40; - unsigned int index = 0; - dev_dbg(data->hwmon_dev, "***Counter and Temperature chart **********\n"); - start_counter = data->fuse_F1; - end_counter = data->fuse_F2; - diff = (end_counter - start_counter) / num_readings; - - /* We want to take num_readings counter values in between - and try to report corresponding temperature */ - for (i = start_counter; i <= (end_counter + diff); - i += diff) { - tsensor_count_2_temp(data, i, &temperature); - dev_dbg(data->hwmon_dev, "[%d]: Counter=%#x, temperature=%d.%06dC\n", - ++index, i, get_temperature_int(temperature), - get_temperature_fraction(temperature)); - } - dev_dbg(data->hwmon_dev, "\n\n"); - tsensor_count_2_temp(data, end_counter, &temperature); - dev_dbg(data->hwmon_dev, "[%d]: Counter=%#x, temperature=%d.%06dC\n", - ++index, end_counter, get_temperature_int(temperature), - get_temperature_fraction(temperature)); -} - -static bool temp_matched(int given_temp, int calc_temp) -{ - const int temp_diff_max = 4; - int diff; - - diff = given_temp - calc_temp; - if (diff < 0) - diff *= -1; - if (diff > temp_diff_max) - return false; - else - return true; -} - -/* function to print chart of temperature to counter values */ -static void print_temperature_2_counter_table( - struct tegra_tsensor_data *data) -{ - int i; - int min = -25; - int max = 120; - unsigned int counter1, counter2; - int temperature; - - dev_dbg(data->hwmon_dev, "Temperature and counter1 and " - "counter2 chart **********\n"); - for (i = min; i <= max; i++) { - tsensor_temp_2_count(data, i, - &counter1, &counter2); - dev_dbg(data->hwmon_dev, "temperature=%d, " - "counter1=0x%x, counter2=0x%x\n", - i, counter1, counter2); - /* verify the counter2 to temperature conversion */ - tsensor_count_2_temp(data, counter2, &temperature); - dev_dbg(data->hwmon_dev, "Given temp=%d: counter2=%d, conv temp=%d.%06d\n", - i, counter2, get_temperature_int(temperature), - get_temperature_fraction(temperature)); - if (!temp_matched(i, get_temperature_round(temperature))) - dev_dbg(data->hwmon_dev, "tsensor temp to counter to temp conversion failed for temp=%d\n", - i); - } - dev_dbg(data->hwmon_dev, "\n\n"); -} - -static void dump_a_tsensor_reg(struct tegra_tsensor_data *data, - unsigned int addr) -{ - dev_dbg(data->hwmon_dev, "tsensor[%d][0x%x]: 0x%x\n", (addr >> 16), - addr & 0xFFFF, tsensor_readl(data, addr)); -} - -static void dump_tsensor_regs(struct tegra_tsensor_data *data) -{ - int i; - for (i = 0; i < TSENSOR_COUNT; i++) { - /* if STOP bit is set skip this check */ - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG0)); - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG1)); - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG2)); - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_STATUS0)); - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_TS_STATUS1)); - dump_a_tsensor_reg(data, ((i << 16) | SENSOR_TS_STATUS2)); - dump_a_tsensor_reg(data, ((i << 16) | 0x0)); - dump_a_tsensor_reg(data, ((i << 16) | 0x44)); - dump_a_tsensor_reg(data, ((i << 16) | 0x50)); - dump_a_tsensor_reg(data, ((i << 16) | 0x54)); - dump_a_tsensor_reg(data, ((i << 16) | 0x64)); - dump_a_tsensor_reg(data, ((i << 16) | 0x68)); - } -} - -/* - * function to test if conversion of counter to temperature - * and vice-versa is working - */ -static int test_temperature_algo(struct tegra_tsensor_data *data) -{ - unsigned int actual_counter; - unsigned int curr_avg; - unsigned int counter1, counter2; - int T1; - int err = 0; - bool result1, result2; - bool result = false; - - /* read actual counter */ - err = tsensor_read_counter(data, &curr_avg); - if (err < 0) { - pr_err("Error: tsensor0 counter read, err=%d\n", err); - goto endLabel; - } - actual_counter = ((curr_avg & 0xFFFF0000) >> 16); - dev_dbg(data->hwmon_dev, "counter read=0x%x\n", actual_counter); - - /* calculate temperature */ - err = tsensor_count_2_temp(data, actual_counter, &T1); - dev_dbg(data->hwmon_dev, "%s actual counter=0x%x, calculated " - "temperature=%d.%06d\n", __func__, - actual_counter, get_temperature_int(T1), - get_temperature_fraction(T1)); - if (err < 0) { - pr_err("Error: calculate temperature step\n"); - goto endLabel; - } - - /* calculate counter corresponding to read temperature */ - tsensor_temp_2_count(data, get_temperature_round(T1), - &counter1, &counter2); - dev_dbg(data->hwmon_dev, "given temperature=%d, counter1=0x%x," - " counter2=0x%x\n", - get_temperature_round(T1), counter1, counter2); - - err = tsensor_count_2_temp(data, actual_counter, &T1); - dev_dbg(data->hwmon_dev, "%s 2nd time actual counter=0x%x, " - "calculated temperature=%d.%d\n", __func__, - actual_counter, get_temperature_int(T1), - get_temperature_fraction(T1)); - if (err < 0) { - pr_err("Error: calculate temperature step\n"); - goto endLabel; - } - - /* compare counter calculated with actual original counter */ - result1 = cmp_counter(data, actual_counter, counter1); - result2 = cmp_counter(data, actual_counter, counter2); - if (result1) { - dev_dbg(data->hwmon_dev, "counter1 matches: actual=%d," - " calc=%d\n", actual_counter, counter1); - result = true; - } - if (result2) { - dev_dbg(data->hwmon_dev, "counter2 matches: actual=%d," - " calc=%d\n", actual_counter, counter2); - result = true; - } - if (!result) { - pr_info("NO Match: actual=%d," - " calc counter2=%d, counter1=%d\n", actual_counter, - counter2, counter1); - err = -EIO; - } - -endLabel: - return err; -} - -/* tsensor threshold temperature to threshold counter conversion function */ -static unsigned int tsensor_get_threshold_counter( - struct tegra_tsensor_data *data, - int temp_threshold) -{ - unsigned int counter1, counter2; - unsigned int counter; - - if (temp_threshold < 0) - return MAX_THRESHOLD; - - tsensor_temp_2_count(data, temp_threshold, &counter1, &counter2); - - counter = counter2; - - return counter; -} - -/* tsensor temperature threshold setup function */ -static void tsensor_threshold_setup(struct tegra_tsensor_data *data, - unsigned char index) -{ - unsigned long config0; - unsigned char i = index; - unsigned int th2_count = DEFAULT_THRESHOLD_TH2; - unsigned int th3_count = DEFAULT_THRESHOLD_TH3; - unsigned int th1_count = DEFAULT_THRESHOLD_TH1; - int th0_diff = 0; - - dev_dbg(data->hwmon_dev, "started tsensor_threshold_setup %d\n", - index); - config0 = tsensor_readl(data, ((i << 16) | SENSOR_CFG0)); - - dev_dbg(data->hwmon_dev, "before threshold program TH dump:\n"); - dump_threshold(data); - dev_dbg(data->hwmon_dev, "th3=0x%x, th2=0x%x, th1=0x%x, th0=0x%x\n", - th3_count, th2_count, th1_count, th0_diff); - config0 = (((th2_count & SENSOR_CFG_X_TH_X_MASK) - << SENSOR_CFG1_TH2_SHIFT) | - ((th1_count & SENSOR_CFG_X_TH_X_MASK) << - SENSOR_CFG1_TH1_SHIFT)); - tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG1)); - config0 = (((th0_diff & SENSOR_CFG_X_TH_X_MASK) - << SENSOR_CFG2_TH0_SHIFT) | - ((th3_count & SENSOR_CFG_X_TH_X_MASK) << - SENSOR_CFG2_TH3_SHIFT)); - tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG2)); - dev_dbg(data->hwmon_dev, "after threshold program TH dump:\n"); - dump_threshold(data); -} - -/* tsensor config programming function */ -static int tsensor_config_setup(struct tegra_tsensor_data *data) -{ - unsigned int config0; - unsigned int i; - int err = 0; - - for (i = 0; i < TSENSOR_COUNT; i++) { - /* - * Pre-read setup: - * Set M and N values - * Enable HW features HW_FREQ_DIV_EN, THERMAL_RST_EN - */ - config0 = tsensor_readl(data, ((i << 16) | SENSOR_CFG0)); - config0 &= ~((SENSOR_CFG0_M_MASK << SENSOR_CFG0_M_SHIFT) | - (SENSOR_CFG0_N_MASK << SENSOR_CFG0_N_SHIFT) | - (1 << SENSOR_CFG0_OVERFLOW_INTR) | - (1 << SENSOR_CFG0_RST_INTR_SHIFT) | - (1 << SENSOR_CFG0_DVFS_INTR_SHIFT) | - (1 << SENSOR_CFG0_HW_DIV2_INTR_SHIFT) | - (1 << SENSOR_CFG0_RST_ENABLE_SHIFT) | - (1 << SENSOR_CFG0_HW_DIV2_ENABLE_SHIFT) - ); - /* Set STOP bit */ - /* Set M and N values */ - /* Enable HW features HW_FREQ_DIV_EN, THERMAL_RST_EN */ - config0 |= ( - ((DEFAULT_TSENSOR_M & SENSOR_CFG0_M_MASK) << - SENSOR_CFG0_M_SHIFT) | - ((DEFAULT_TSENSOR_N & SENSOR_CFG0_N_MASK) << - SENSOR_CFG0_N_SHIFT) | - (1 << SENSOR_CFG0_OVERFLOW_INTR) | - (1 << SENSOR_CFG0_DVFS_INTR_SHIFT) | - (1 << SENSOR_CFG0_HW_DIV2_INTR_SHIFT) | -#if ENABLE_TSENSOR_HW_RESET - (1 << SENSOR_CFG0_RST_ENABLE_SHIFT) | -#endif - (1 << SENSOR_CFG0_STOP_SHIFT)); - - tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG0)); - tsensor_threshold_setup(data, i); - } - - /* Disable sensor stop bit */ - config0 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG0); - config0 &= ~(1 << SENSOR_CFG0_STOP_SHIFT); - tsensor_writel(data, config0, (data->instance << 16) | SENSOR_CFG0); - - /* initialize tsensor chip coefficients */ - get_chip_tsensor_coeff(data); - - return err; -} - -/* function to enable tsensor clock */ -static int tsensor_clk_enable( - struct tegra_tsensor_data *data, - bool enable) -{ - int err = 0; - unsigned long rate; - struct clk *clk_m; - - if (enable) { - clk_prepare_enable(data->dev_clk); - rate = clk_get_rate(data->dev_clk); - clk_m = clk_get_sys(NULL, "clk_m"); - if (clk_get_parent(data->dev_clk) != clk_m) { - err = clk_set_parent(data->dev_clk, clk_m); - if (err < 0) - goto fail; - } - rate = DEFAULT_TSENSOR_CLK_HZ; - if (rate != clk_get_rate(clk_m)) { - err = clk_set_rate(data->dev_clk, rate); - if (err < 0) - goto fail; - } - } else { - clk_disable_unprepare(data->dev_clk); - clk_put(data->dev_clk); - } -fail: - return err; -} - -/* - * function to set counter threshold corresponding to - * given temperature - */ -static void tsensor_set_limits( - struct tegra_tsensor_data *data, - int temp, - int threshold_index) -{ - unsigned int th_count; - unsigned int config; - unsigned short sft, offset; - unsigned int th1_count; - - th_count = tsensor_get_threshold_counter(data, temp); - dev_dbg(data->hwmon_dev, "%s : input temp=%d, counter=0x%x\n", __func__, - temp, th_count); - switch (threshold_index) { - case TSENSOR_TH0: - sft = 16; - offset = SENSOR_CFG2; - /* assumed TH1 set before TH0, else we program - * TH0 as TH1 which means hysteresis will be - * same as TH1. Also, caller expected to pass - * (TH1 - hysteresis) as temp argument for this case */ - th1_count = tsensor_readl(data, - ((data->instance << 16) | - SENSOR_CFG1)); - th_count = (th1_count > th_count) ? - (th1_count - th_count) : - th1_count; - break; - case TSENSOR_TH1: - default: - sft = 0; - offset = SENSOR_CFG1; - break; - case TSENSOR_TH2: - sft = 16; - offset = SENSOR_CFG1; - break; - case TSENSOR_TH3: - sft = 0; - offset = SENSOR_CFG2; - break; - } - config = tsensor_readl(data, ((data->instance << 16) | offset)); - dev_dbg(data->hwmon_dev, "%s: old config=0x%x, sft=%d, offset=0x%x\n", - __func__, config, sft, offset); - config &= ~(SENSOR_CFG_X_TH_X_MASK << sft); - config |= ((th_count & SENSOR_CFG_X_TH_X_MASK) << sft); - dev_dbg(data->hwmon_dev, "new config=0x%x\n", config); - tsensor_writel(data, config, ((data->instance << 16) | offset)); -} - -static int tsensor_within_limits(struct tegra_tsensor_data *data) -{ - int ts_state = get_ts_state(data); - - return (ts_state == TS_LEVEL1); -} - -#ifdef CONFIG_THERMAL -static int tsensor_thermal_set_limits(struct tegra_tsensor_data *data, - long lo_limit_milli, - long hi_limit_milli) -{ - long lo_limit = MILLICELSIUS_TO_CELSIUS(lo_limit_milli); - long hi_limit = MILLICELSIUS_TO_CELSIUS(hi_limit_milli); - int i, j, hi_limit_first; - - if (lo_limit_milli == hi_limit_milli) - return -EINVAL; - - mutex_lock(&data->mutex); - - if (data->current_lo_limit == lo_limit_milli && - data->current_hi_limit == hi_limit_milli) { - goto done; - } - - /* If going up, change hi limit first. If going down, change lo - limit first */ - hi_limit_first = hi_limit_milli > data->current_hi_limit; - - for (i = 0; i < 2; i++) { - j = (i + hi_limit_first) % 2; - - switch (j) { - case 0: - tsensor_set_limits(data, hi_limit, TSENSOR_TH2); - data->current_hi_limit = hi_limit_milli; - break; - case 1: - tsensor_set_limits(data, lo_limit, TSENSOR_TH1); - data->current_lo_limit = lo_limit_milli; - break; - } - } - - -done: - mutex_unlock(&data->mutex); - return 0; -} - -static void tsensor_update(struct tegra_tsensor_data *data) -{ - struct thermal_zone_device *thz = data->thz; - long temp, trip_temp, low_temp = 0, high_temp = 120000; - int count; - - if (!thz) - return; - - if (!thz->passive) - thermal_zone_device_update(thz); - - thz->ops->get_temp(thz, &temp); - - for (count = 0; count < thz->trips; count++) { - thz->ops->get_trip_temp(thz, count, &trip_temp); - - if ((trip_temp >= temp) && (trip_temp < high_temp)) - high_temp = trip_temp; - - if ((trip_temp < temp) && (trip_temp > low_temp)) - low_temp = trip_temp; - } - - tsensor_thermal_set_limits(data, low_temp, high_temp); -} -#else -static void tsensor_update(struct tegra_tsensor_data *data) -{ -} -#endif - -static void tsensor_work_func(struct work_struct *work) -{ - struct tegra_tsensor_data *data = container_of(to_delayed_work(work), - struct tegra_tsensor_data, work); - - if (!tsensor_within_limits(data)) { - tsensor_update(data); - - if (!tsensor_within_limits(data)) - dev_dbg(data->hwmon_dev, - "repeated work queueing state=%d\n", - get_ts_state(data)); - queue_delayed_work(data->workqueue, &data->work, - HZ * DEFAULT_TSENSOR_M / - DEFAULT_TSENSOR_CLK_HZ); - } -} - -/* - * This function enables the tsensor using default configuration - * 1. We would need some configuration APIs to calibrate - * the tsensor counters to right temperature - * 2. hardware triggered divide cpu clock by 2 as well pmu reset is enabled - * implementation. No software actions are enabled at this point - */ -static int tegra_tsensor_setup(struct platform_device *pdev) -{ - struct tegra_tsensor_data *data = platform_get_drvdata(pdev); - struct resource *r; - int err = 0; - struct tegra_tsensor_platform_data *tsensor_data; - unsigned int reg; - - data->dev_clk = clk_get(&pdev->dev, NULL); - if ((!data->dev_clk) || ((int)data->dev_clk == -(ENOENT))) { - dev_err(&pdev->dev, "Couldn't get the clock\n"); - err = PTR_ERR(data->dev_clk); - goto fail; - } - - /* Enable tsensor clock */ - err = tsensor_clk_enable(data, true); - if (err < 0) - goto err_irq; - - /* Reset tsensor */ - dev_dbg(&pdev->dev, "before tsensor reset %s\n", __func__); - tegra_periph_reset_assert(data->dev_clk); - udelay(100); - tegra_periph_reset_deassert(data->dev_clk); - udelay(100); - - dev_dbg(&pdev->dev, "before tsensor chk pmc reset %s\n", - __func__); - /* Check for previous resets in pmc */ - if (pmc_check_rst_sensor(data)) { - dev_err(data->hwmon_dev, "Warning: ***** Last PMC " - "Reset source: tsensor detected\n"); - } - - dev_dbg(&pdev->dev, "before tsensor pmc reset enable %s\n", - __func__); - /* Enable the sensor reset in PMC */ - pmc_rst_enable(data, true); - - dev_dbg(&pdev->dev, "before tsensor get platform data %s\n", - __func__); - dev_dbg(&pdev->dev, "tsensor platform_data=0x%x\n", - (unsigned int)pdev->dev.platform_data); - tsensor_data = pdev->dev.platform_data; - - /* register interrupt */ - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!r) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); - err = -ENXIO; - goto err_irq; - } - data->irq = r->start; - err = request_irq(data->irq, tegra_tsensor_isr, - IRQF_DISABLED, pdev->name, data); - if (err < 0) { - dev_err(&pdev->dev, "Failed to register IRQ\n"); - goto err_irq; - } - - dev_dbg(&pdev->dev, "tsensor platform_data=0x%x\n", - (unsigned int)pdev->dev.platform_data); - - dev_dbg(&pdev->dev, "before tsensor_config_setup\n"); - err = tsensor_config_setup(data); - if (err) { - dev_err(&pdev->dev, "[%s,line=%d]: tsensor counters dead!\n", - __func__, __LINE__); - goto err_setup; - } - dev_dbg(&pdev->dev, "before tsensor_get_const_AB\n"); - /* calculate constants needed for temperature conversion */ - err = tsensor_get_const_AB(data); - if (err < 0) { - dev_err(&pdev->dev, "Failed to extract temperature\n" - "const\n"); - goto err_setup; - } - - /* test if counter-to-temperature and temperature-to-counter - * are matching */ - err = test_temperature_algo(data); - if (err) { - dev_err(&pdev->dev, "Error: read temperature\n" - "algorithm broken\n"); - goto err_setup; - } - - print_temperature_2_counter_table(data); - - print_counter_2_temperature_table(data); - - /* EDP and throttling support using tsensor enabled - * based on fuse revision */ - err = tegra_fuse_get_revision(®); - if (err) - goto err_setup; - - data->is_edp_supported = (reg >= STABLE_TSENSOR_FUSE_REV); - - if (data->is_edp_supported) { - data->workqueue = create_singlethread_workqueue("tsensor"); - INIT_DELAYED_WORK(&data->work, tsensor_work_func); - } - - return 0; -err_setup: - free_irq(data->irq, data); -err_irq: - tsensor_clk_enable(data, false); -fail: - dev_err(&pdev->dev, "%s error=%d returned\n", __func__, err); - return err; -} - -#ifdef CONFIG_THERMAL -static int tsensor_get_temp(struct thermal_zone_device *thz, - unsigned long *temp) -{ - struct tegra_tsensor_data *data = thz->devdata; - return tsensor_thermal_get_temp(data, temp); -} - -static int tsensor_bind(struct thermal_zone_device *thz, - struct thermal_cooling_device *cdev) -{ - int i; - struct tegra_tsensor_data *data = thz->devdata; - - if (cdev == data->plat_data.passive.cdev) - return thermal_zone_bind_cooling_device(thz, 0, cdev, - THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT); - - for (i = 0; data->plat_data.active[i].cdev; i++) - if (cdev == data->plat_data.active[i].cdev) - return thermal_zone_bind_cooling_device(thz, i+1, cdev, - THERMAL_NO_LIMIT, - THERMAL_NO_LIMIT); - - return 0; -} - -static int tsensor_unbind(struct thermal_zone_device *thz, - struct thermal_cooling_device *cdev) -{ - int i; - struct tegra_tsensor_data *data = thz->devdata; - - if (cdev == data->plat_data.passive.cdev) - return thermal_zone_unbind_cooling_device(thz, 0, cdev); - - for (i = 0; data->plat_data.active[i].cdev; i++) - if (cdev == data->plat_data.active[i].cdev) - return thermal_zone_unbind_cooling_device(thz, i+1, - cdev); - - return 0; -} - -static int tsensor_get_trip_temp(struct thermal_zone_device *thz, - int trip, - unsigned long *temp) -{ - struct tegra_tsensor_data *data = thz->devdata; - if (trip == 0) - *temp = data->plat_data.passive.trip_temp; - else - *temp = data->plat_data.active[trip-1].trip_temp; - return 0; -} - -static int tsensor_get_trip_type(struct thermal_zone_device *thz, - int trip, - enum thermal_trip_type *type) -{ - *type = (trip == 0) ? THERMAL_TRIP_PASSIVE : THERMAL_TRIP_ACTIVE; - return 0; -} - - -static struct thermal_zone_device_ops tsensor_ops = { - .get_temp = tsensor_get_temp, - .bind = tsensor_bind, - .unbind = tsensor_unbind, - .get_trip_type = tsensor_get_trip_type, - .get_trip_temp = tsensor_get_trip_temp, -}; -#endif - -static int tegra_tsensor_probe(struct platform_device *pdev) -{ - struct tegra_tsensor_data *data; - struct resource *r; - int err; - unsigned int reg; - u8 i; - struct tegra_tsensor_platform_data *tsensor_data; -#ifdef CONFIG_THERMAL - int num_trips = 0; -#endif - - data = kzalloc(sizeof(struct tegra_tsensor_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "[%s,line=%d]: Failed to allocate " - "memory\n", __func__, __LINE__); - err = -ENOMEM; - goto exit; - } - mutex_init(&data->mutex); - platform_set_drvdata(pdev, data); - - /* Register sysfs hooks */ - for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) { - err = device_create_file(&pdev->dev, - &tsensor_nodes[i].dev_attr); - if (err) { - dev_err(&pdev->dev, "device_create_file failed.\n"); - goto err0; - } - } - - data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto err1; - } - - dev_set_drvdata(data->hwmon_dev, data); - - spin_lock_init(&data->tsensor_lock); - - /* map tsensor register space */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&pdev->dev, "[%s,line=%d]: Failed to get io " - "resource\n", __func__, __LINE__); - err = -ENODEV; - goto err2; - } - - if (!request_mem_region(r->start, (r->end - r->start) + 1, - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "[%s,line=%d]: Error mem busy\n", - __func__, __LINE__); - err = -EBUSY; - goto err2; - } - - data->phys = r->start; - data->phys_end = r->end; - data->base = ioremap(r->start, r->end - r->start + 1); - if (!data->base) { - dev_err(&pdev->dev, "[%s, line=%d]: can't ioremap " - "tsensor iomem\n", __FILE__, __LINE__); - err = -ENOMEM; - goto err3; - } - - /* map pmc rst_status register */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (r == NULL) { - dev_err(&pdev->dev, "[%s,line=%d]: Failed to get io " - "resource\n", __func__, __LINE__); - err = -ENODEV; - goto err4; - } - - if (!request_mem_region(r->start, (r->end - r->start) + 1, - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "[%s, line=%d]: Error mem busy\n", - __func__, __LINE__); - err = -EBUSY; - goto err4; - } - - data->pmc_phys = r->start; - data->pmc_phys_end = r->end; - data->pmc_rst_base = ioremap(r->start, r->end - r->start + 1); - if (!data->pmc_rst_base) { - dev_err(&pdev->dev, "[%s, line=%d]: can't ioremap " - "pmc iomem\n", __FILE__, __LINE__); - err = -ENOMEM; - goto err5; - } - - /* fuse revisions less than TSENSOR_FUSE_REV1 - bypass tsensor driver init */ - /* tsensor active instance decided based on fuse revision */ - err = tegra_fuse_get_revision(®); - if (err) - goto err6; - /* check for higher revision done first */ - /* instance 0 is used for fuse revision TSENSOR_FUSE_REV2 onwards */ - if (reg >= TSENSOR_FUSE_REV2) - data->instance = TSENSOR_INSTANCE1; - /* instance 1 is used for fuse revision TSENSOR_FUSE_REV1 till - TSENSOR_FUSE_REV2 */ - else if (reg >= TSENSOR_FUSE_REV1) - data->instance = TSENSOR_INSTANCE2; - pr_info("tsensor active instance=%d\n", data->instance); - - /* tegra tsensor - setup and init */ - err = tegra_tsensor_setup(pdev); - if (err) - goto err6; - - dump_tsensor_regs(data); - dev_dbg(&pdev->dev, "end tegra_tsensor_probe\n"); - - tsensor_data = pdev->dev.platform_data; - - memcpy(&data->plat_data, tsensor_data, - sizeof(struct tegra_tsensor_platform_data)); - - tsensor_set_limits(data, tsensor_data->shutdown_temp, TSENSOR_TH3); - -#ifdef CONFIG_THERMAL - if (tsensor_data->passive.cdev) - num_trips++; - - for (i = 0; tsensor_data->active[i].cdev; i++) - num_trips++; - - data->thz = thermal_zone_device_register("tsensor", - num_trips, - 0x0, - data, - &tsensor_ops, - NULL, - tsensor_data->passive.passive_delay, - 0); - if (IS_ERR_OR_NULL(data->thz)) - goto err6; - - tsensor_update(data); -#endif - - return 0; -err6: - iounmap(data->pmc_rst_base); -err5: - release_mem_region(data->pmc_phys, (data->pmc_phys_end - - data->pmc_phys) + 1); -err4: - iounmap(data->base); -err3: - release_mem_region(data->phys, (data->phys_end - - data->phys) + 1); -err2: - hwmon_device_unregister(data->hwmon_dev); -err1: - for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) - device_remove_file(&pdev->dev, &tsensor_nodes[i].dev_attr); -err0: - kfree(data); -exit: - dev_err(&pdev->dev, "%s error=%d returned\n", __func__, err); - return err; -} - -static int tegra_tsensor_remove(struct platform_device *pdev) -{ - struct tegra_tsensor_data *data = platform_get_drvdata(pdev); - u8 i; - - hwmon_device_unregister(data->hwmon_dev); - for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) - device_remove_file(&pdev->dev, &tsensor_nodes[i].dev_attr); - - if (data->is_edp_supported) { - cancel_delayed_work_sync(&data->work); - destroy_workqueue(data->workqueue); - data->workqueue = NULL; - } - - free_irq(data->irq, data); - - iounmap(data->pmc_rst_base); - release_mem_region(data->pmc_phys, (data->pmc_phys_end - - data->pmc_phys) + 1); - iounmap(data->base); - release_mem_region(data->phys, (data->phys_end - - data->phys) + 1); - - kfree(data); - - return 0; -} - -#ifdef CONFIG_PM - -static void save_tsensor_regs(struct tegra_tsensor_data *data) -{ - int i; - for (i = 0; i < TSENSOR_COUNT; i++) { - data->config0[i] = tsensor_readl(data, - ((i << 16) | SENSOR_CFG0)); - data->config1[i] = tsensor_readl(data, - ((i << 16) | SENSOR_CFG1)); - data->config2[i] = tsensor_readl(data, - ((i << 16) | SENSOR_CFG2)); - } -} - -static void restore_tsensor_regs(struct tegra_tsensor_data *data) -{ - int i; - for (i = 0; i < TSENSOR_COUNT; i++) { - tsensor_writel(data, data->config0[i], - ((i << 16) | SENSOR_CFG0)); - tsensor_writel(data, data->config1[i], - ((i << 16) | SENSOR_CFG1)); - tsensor_writel(data, data->config2[i], - ((i << 16) | SENSOR_CFG2)); - } -} - - -static int tsensor_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct tegra_tsensor_data *data = platform_get_drvdata(pdev); - unsigned int config0; - - disable_irq(data->irq); - cancel_delayed_work_sync(&data->work); - /* set STOP bit, else OVERFLOW interrupt seen in LP1 */ - config0 = tsensor_readl(data, ((data->instance << 16) | SENSOR_CFG0)); - config0 |= (1 << SENSOR_CFG0_STOP_SHIFT); - tsensor_writel(data, config0, ((data->instance << 16) | SENSOR_CFG0)); - - /* save current settings before suspend, when STOP bit is set */ - save_tsensor_regs(data); - tsensor_clk_enable(data, false); - - return 0; -} - -static int tsensor_resume(struct platform_device *pdev) -{ - struct tegra_tsensor_data *data = platform_get_drvdata(pdev); - unsigned int config0; - - tsensor_clk_enable(data, true); - /* restore current settings before suspend, no need - * to clear STOP bit */ - restore_tsensor_regs(data); - - /* clear STOP bit, after restoring regs */ - config0 = tsensor_readl(data, ((data->instance << 16) | SENSOR_CFG0)); - config0 &= ~(1 << SENSOR_CFG0_STOP_SHIFT); - tsensor_writel(data, config0, ((data->instance << 16) | SENSOR_CFG0)); - - if (data->is_edp_supported) - schedule_delayed_work(&data->work, 0); - - enable_irq(data->irq); - return 0; -} -#endif - -static struct platform_driver tegra_tsensor_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "tegra-tsensor", - }, - .probe = tegra_tsensor_probe, - .remove = tegra_tsensor_remove, -#ifdef CONFIG_PM - .suspend = tsensor_suspend, - .resume = tsensor_resume, -#endif -}; - -static int __init tegra_tsensor_init(void) -{ - return platform_driver_register(&tegra_tsensor_driver); -} -module_init(tegra_tsensor_init); - -static void __exit tegra_tsensor_exit(void) -{ - platform_driver_unregister(&tegra_tsensor_driver); -} -module_exit(tegra_tsensor_exit); - -MODULE_AUTHOR("nvidia"); -MODULE_DESCRIPTION("Nvidia Tegra Temperature Sensor driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3