summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorPaul Walmsley <pwalmsley@nvidia.com>2014-02-13 15:56:18 -0800
committerDiwakar Tundlam <dtundlam@nvidia.com>2014-04-04 17:56:39 -0700
commit122912d536232a2d6cfe22ea1620125910500b05 (patch)
treed8630a761532b81c164b1ac023875a0df0fdb019 /drivers/hwmon
parent4f9d14cc1e330a0bda9b5b044d3241d4eeffe934 (diff)
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 <pwalmsley@nvidia.com> Cc: Diwakar Tundlam <dtundlam@nvidia.com> Cc: Matthew Longnecker <mlongnecker@nvidia.com> Reviewed-on: http://git-master/r/392199 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com> Tested-by: Diwakar Tundlam <dtundlam@nvidia.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig8
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/tegra-tsensor.c2140
3 files changed, 0 insertions, 2150 deletions
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 <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/hwmon.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/irqreturn.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/hwmon.h>
-#include <linux/regulator/consumer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/clk/tegra.h>
-
-#include <mach/tsensor.h>
-#include <mach/tegra_fuse.h>
-
-/* 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, &reg, &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, &reg, &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(&reg1);
- 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(&reg);
- 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(&reg);
- 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");