[Meego-kernel] patch[1/1] Medfield Thermal Driver Rework Patch
R, Durgadoss
durgadoss.r at intel.com
Sun Nov 14 22:17:46 PST 2010
From: Durgadoss R <durgadoss.r at intel.com>
Date: Fri, 12 Nov 2010 03:14:53 +0530
Subject: [PATCH 1/1] Medfield_Thermal_Driver_Rework
Hi Arjan,
I am submitting the intel_mid_thermal driver patch.
This is an incremental patch generated against the latest
meego kernel.
As per earlier comments, polling is removed from the driver.
This driver now, just registers with the thermal framework,
and converts the ADC values to temperatures.
Please review and merge.
Signed-off-by: Durgadoss R <durgadoss.r at intel.com>
---
drivers/hwmon/Kconfig | 2 +-
drivers/hwmon/intel_mid_thermal.c | 843 +++++++++++++------------------------
2 files changed, 302 insertions(+), 543 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e12b35d..fe56d9a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1127,7 +1127,7 @@ config SENSORS_MRST_ANALOG_ACCEL
config SENSORS_THERMAL_MFLD
tristate "Thermal driver for Intel Medfield platform"
- depends on INTEL_SCU_IPC
+ depends on INTEL_SCU_IPC && THERMAL
help
Say Y here to enable thermal driver on Intel Medfield
platform.
diff --git a/drivers/hwmon/intel_mid_thermal.c b/drivers/hwmon/intel_mid_thermal.c
index a10d6e4..53b11fc 100644
--- a/drivers/hwmon/intel_mid_thermal.c
+++ b/drivers/hwmon/intel_mid_thermal.c
@@ -1,7 +1,6 @@
/*
* intel_mid_thermal.c - Intel MID platform thermal driver
*
- *
* Copyright (C) 2010 Intel Corporation
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -24,447 +23,264 @@
* Author: Durgadoss <durgadoss.r at intel.com>
*/
+#define pr_fmt(fmt) "intel_mid_thermal: " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
#include <linux/param.h>
-#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pm.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/hwmon-vid.h>
+#include <linux/thermal.h>
#include <asm/intel_scu_ipc.h>
+/* Number of thermal sensors */
+#define MSIC_THERMAL_SENSORS 4
-#define DRIVER_NAME "msic_sensor"
-/*********************************************************************
- * Generic defines
- *********************************************************************/
/* ADC1 - thermal registers */
-#define MSIC_THERM_ADC1CNTL1 0x1C0
-#define MSIC_ADC_ENBL 0x18
-#define MSIC_THERM_ADC1CNTL3 0x1C2
-#define MSIC_ADCTHERM_ENBL 0x04
-#define MSIC_ADCRRDATA_ENBL 0x05
-#define MSIC_CHANL_MASK_VAL 0x0F
+#define MSIC_THERM_ADC1CNTL1 0x1C0
+#define MSIC_ADC_ENBL 0x10
+#define MSIC_ADC_START 0x08
-#define MSIC_STOPBIT_MASK 16
-#define MSIC_ADCTHERM_MASK 4
-#define ADC_CHANLS_MAX 15 /*no of adc channels*/
-#define ADC_LOOP_MAX (ADC_CHANLS_MAX - 3)
+#define MSIC_THERM_ADC1CNTL3 0x1C2
+#define MSIC_ADCTHERM_ENBL 0x04
+#define MSIC_ADCRRDATA_ENBL 0x05
+#define MSIC_CHANL_MASK_VAL 0x0F
-#define MSIC_VAUDA 0x0DB
-#define MSIC_VAUDA_VAL 0xFF
+#define MSIC_STOPBIT_MASK 16
+#define MSIC_ADCTHERM_MASK 4
+#define ADC_CHANLS_MAX 15 /* Number of ADC channels */
+#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
/* ADC channel code values */
#define SKIN_SENSOR0_CODE 0x08
#define SKIN_SENSOR1_CODE 0x09
-#define SYS_SENSOR_CODE 0x1A
+#define SYS_SENSOR_CODE 0x0A
+#define MSIC_DIE_SENSOR_CODE 0x03
#define SKIN_THERM_SENSOR0 0
#define SKIN_THERM_SENSOR1 1
#define SYS_THERM_SENSOR2 2
+#define MSIC_DIE_THERM_SENSOR3 3
/* ADC code range */
-#define ADC_MAX 977
-#define ADC_MIN 162
-#define ADC_VAL1 887
-#define ADC_VAL2 720
-#define ADC_VAL3 508
-#define ADC_VAL4 315
-
-/* Event id */
-#define HIGH_EVENT 1
-#define LOW_EVENT 2
-#define THERM_EVENT 3
-#define FAULT_EVENT 4
-
-/* Default temperature limits
- * in milli degree celsius */
-#define SKIN_SENSOR_MIN_TEMP 0
-#define SKIN_SENSOR_MAX_TEMP 35000
-#define SKIN_SENSOR_CRIT_TEMP 45000
-#define SKIN_SENSOR_THROT_START 30000
-
-#define SYS_SENSOR_MIN_TEMP 0
-#define SYS_SENSOR_MAX_TEMP 45000
-#define SYS_SENSOR_CRIT_TEMP 55000
-#define SYS_SENSOR_THROT_START 30000
+#define ADC_MAX 977
+#define ADC_MIN 162
+#define ADC_VAL1 887
+#define ADC_VAL2 720
+#define ADC_VAL3 508
+#define ADC_VAL4 315
/* ADC base addresses */
#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
+/* MSIC die attributes */
+#define MSIC_DIE_ADC_MIN 488
+#define MSIC_DIE_ADC_MAX 1004
+
+/* convert adc_val to die temperature */
+#define TO_MSIC_DIE_TEMP(adc_val) ((368 * (adc_val) / 1000) - 220)
+
static int channel_index;
-/* Generic structure for sensor */
-struct sensor {
- int curr_temp;
- unsigned int min_temp;
- unsigned int max_temp;
- unsigned int crit_temp;
- unsigned int therm_throt_temp;
+struct platform_info {
+ struct platform_device *pdev;
+ struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
};
-/*********************************************************************
- * Thermal properties
- *********************************************************************/
-struct thermal_module_info {
- struct platform_device *pdev;
- struct device *dev;
- /* thermal parameters */
- struct sensor platfrm_sens[3];
- struct workqueue_struct *therm_monitor_wqueue;
- struct delayed_work thermal_monitor;
+struct thermal_device_info {
+ unsigned int chnl_addr;
+ int direct;
+ long curr_temp;
};
-/**
- * mid_therm_event - send thermal notification event
- * @event_id: indicates criticality of thershold exceeded
- * @sensor_id: indicates the sensor
- * @curr_temp: current tempearture of sensor
- * Context: can sleep
- *
- * sends thermal notofication to the thermal management
- * on exceeding the defined thershold
- */
-static void mid_therm_event(int event_id, int sensor_id, int curr_temp)
-{
- /* for future enabling*/
- printk(KERN_INFO "called:%s", __func__);
-}
/**
- * notify_status : Notifies the thermal management when threshold exceeds
- * @sensor: sensor id
- * @therm : thermal_module_info structure
- * Context: can sleep
+ * is_valid_adc - checks whether the adc code is within the defined range
+ * @min: minimum value for the sensor
+ * @max: maximum value for the sensor
+ *
+ * Can sleep
*/
-static void notify_status(int sensor, struct thermal_module_info *therm)
+static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
{
- int temp = therm->platfrm_sens[sensor].curr_temp;
- if (temp >= therm->platfrm_sens[sensor].crit_temp) {
- dev_warn(&therm->pdev->dev,
- "%s:sensor %d: temperature is crit:%d",
- __func__, sensor, temp);
- mid_therm_event(THERM_EVENT, sensor, temp);
- } else if (temp >= therm->platfrm_sens[sensor].max_temp) {
- dev_warn(&therm->pdev->dev,
- "%s:sensor %d: temperature is max:%d",
- __func__, sensor, temp);
- mid_therm_event(HIGH_EVENT, sensor, temp);
- } else if (temp >= therm->platfrm_sens[sensor].min_temp) {
- if (temp > therm->platfrm_sens[sensor].therm_throt_temp)
- mid_therm_event(LOW_EVENT, sensor, temp);
- }
+ return (adc_val >= min) && (adc_val <= max);
}
-
/**
* adc_to_temp - converts the ADC code to temperature in C
- * @adc_val: the adc_val needs to be converted
+ * @direct: true if ths channel is direct index
+ * @adc_val: the adc_val that needs to be converted
+ * @tp: temperature return value
*
- * Linear approximation is used to covert the adc value into temperature.
+ * Linear approximation is used to covert the skin adc value into temperature.
* This technique is used to avoid very long look-up table to get
* the appropriate temp value from ADC value.
* The adc code vs sensor temp curve is split into five parts
* to achieve very close approximate temp value with less than
* 0.5C error
*/
-static int adc_to_temp(uint16_t adc_val)
+static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
{
int temp;
- if (adc_val > ADC_MAX || adc_val < ADC_MIN)
+
+ /* Direct conversion for die temperature */
+ if (direct) {
+ if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
+ *tp = (int)(TO_MSIC_DIE_TEMP(adc_val) * 1000);
+ return 0;
+ }
+ return -ERANGE;
+ }
+
+ if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
return -ERANGE;
- /* linear approximation */
+
+ /* Linear approximation for skin temperature */
if (adc_val > ADC_VAL1) /* -20 to 0C */
temp = 177 - (adc_val/5);
- else if (adc_val <= ADC_VAL1 && adc_val > ADC_VAL2) /* 0C to 20C */
+ else if ((adc_val <= ADC_VAL1) && (adc_val > ADC_VAL2)) /* 0C to 20C */
temp = 111 - (adc_val/8);
- else if (adc_val <= ADC_VAL2 && adc_val > ADC_VAL3) /* 20C to 40C */
+ else if ((adc_val <= ADC_VAL2) && (adc_val > ADC_VAL3)) /* 20C to 40C */
temp = 92 - (adc_val/10);
- else if (adc_val <= ADC_VAL3 && adc_val > ADC_VAL4) /* 40C to 60C */
+ else if ((adc_val <= ADC_VAL3) && (adc_val > ADC_VAL4)) /* 40C to 60C */
temp = 91 - (adc_val/10);
else
temp = 112 - (adc_val/6); /* 60C to 85C */
- return temp;
+ /* Convert temperature in celsius to milli degree celsius */
+ *tp = temp * 1000;
+ return 0;
}
+
/**
* mid_read_temp - read sensors for temperature
- * @sensor: sensor to be read
- * @therm: thermal module info structure
- * Context: can sleep
+ * @temp: holds the current temperature for the sensor after reading
*
- * enable and ADC conversion and read the adc value on channel
- * and convert the adc value to real time tempearture
+ * reads the adc_code from the channel and converts it to real
+ * temperature. The converted value is stored in temp.
+ *
+ * Can sleep
*/
-static int mid_read_temp(int sensor,
- struct thermal_module_info *therm)
+static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
{
+ struct thermal_device_info *td_info = tzd->devdata;
uint16_t adc_val, addr;
uint8_t data = 0;
int ret;
+ unsigned long curr_temp;
+
+
+ addr = td_info->chnl_addr;
- /* enable the msic for conversion before reading */
+ /* Enable the msic for conversion before reading */
ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc write failed\n",
- __func__);
+ if (ret)
return ret;
- }
- /* re-toggle the RRDATARD bit
- * temporary workaround */
+ /* Re-toggle the RRDATARD bit (temporary workaround) */
ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc write failed\n",
- __func__);
+ if (ret)
return ret;
- }
- /* reading the higher bits of data */
- addr = ADC_DATA_START_ADDR+2*(channel_index+sensor);
+
+ /* Read the higher bits of data */
ret = intel_scu_ipc_ioread8(addr, &data);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc read failed\n",
- __func__);
+ if (ret)
return ret;
- }
- /* shifting bits to accomodate the lower two data bits */
- adc_val = data << 2;
+
+ /* Shift bits to accomodate the lower two data bits */
+ adc_val = (data << 2);
addr++;
- ret = intel_scu_ipc_ioread8(addr, &data);/* reading lower bits */
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc read failed\n",
- __func__);
+
+ ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */
+ if (ret)
return ret;
- }
- /* adding lower two bits to the higher bits */
+
+ /* Adding lower two bits to the higher bits */
data &= 03;
adc_val += data;
- ret = adc_to_temp(adc_val);
- if (ret == -ERANGE) {
- dev_err(&therm->pdev->dev,
- "intel_mid_thermal: adc code out of range\n");
- return ret;
- }
- /* convert tempertaure in celsius to milli degree celsius */
- therm->platfrm_sens[sensor].curr_temp = ret * 1000;
- return 0;
+
+ /* Convert ADC value to temperature */
+ ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
+ if (ret == 0)
+ *temp = td_info->curr_temp = curr_temp;
+ return ret;
}
/**
- * platform_thermal_monitor - monitoring the thermal sensors
- * @work: work structure
- * Context: can sleep
+ * configure_adc - enables/disables the ADC for conversion
+ * @val: zero: disables the ADC non-zero:enables the ADC
*
- * monitors the thermal sensors on the platform and
- * notifies the thermal management if thershold is exceeded.
+ * Enable/Disable the ADC depending on the argument
+ *
+ * Can sleep
*/
-static void platform_thermal_monitor(struct work_struct *work)
+static int configure_adc(int val)
{
int ret;
- int i;
- struct thermal_module_info *therm = container_of(work,
- struct thermal_module_info, thermal_monitor.work);
- for (i = 0; i < 3; i++) {
- ret = mid_read_temp(i, therm);
- if (ret)
- dev_err(&therm->pdev->dev,
- "intel_mid_thermal:temperature \
- conversion failed: %s", __func__);
- else
- notify_status(i, therm);
- }
- queue_delayed_work(therm->therm_monitor_wqueue,
- &therm->thermal_monitor,
- round_jiffies_relative(HZ * 50));
- return;
-}
-
-
-static ssize_t show_temp_auto_offset(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
- struct thermal_module_info *therm = dev_get_drvdata(dev);
- int ret = 0;
- int sensor_index = s_attr->index;
-
- switch (s_attr->nr) {
- case 0:
- ret = therm->platfrm_sens[sensor_index].min_temp;
- break;
- case 1:
- ret = therm->platfrm_sens[sensor_index].max_temp;
- break;
- case 2:
- ret = therm->platfrm_sens[sensor_index].crit_temp;
- break;
- default:
- WARN_ON(1);
- }
- return sprintf(buf, "%d\n", ret);
-}
+ uint8_t data;
-static ssize_t store_temp_auto_offset(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
- struct thermal_module_info *therm = dev_get_drvdata(dev);
- unsigned long val;
- int sensor_index = s_attr->index;
- if (therm == NULL) {
- dev_err(&therm->pdev->dev,
- "intel_mid_thermal:using NULL pointer\n");
- return -EINVAL;
- }
- if (strict_strtoul(buf, 10, &val)) {
- return -EINVAL;
- } else {
- switch (s_attr->nr) {
- case 0:
- therm->platfrm_sens[sensor_index].min_temp = val;
- break;
- case 1:
- therm->platfrm_sens[sensor_index].max_temp = val;
- break;
- case 2:
- therm->platfrm_sens[sensor_index].crit_temp = val;
- break;
- default:
- WARN_ON(1);
- }
- return count;
- }
-}
-static ssize_t show_curr_temp(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret;
- struct thermal_module_info *therm = dev_get_drvdata(dev);
- struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
- int sensor_index = s_attr->index;
- ret = mid_read_temp(sensor_index, therm);
- if (ret) {
- dev_err(&therm->pdev->dev,
- "intel_mid_thermal: %s: failed to read curr temp",
- __func__);
+ ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
+ if (ret)
return ret;
- }
- return sprintf(buf, "%d\n",
- therm->platfrm_sens[sensor_index].curr_temp);
-}
-static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 0, 0);
-static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 1, 0);
-static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 2, 0);
-static SENSOR_DEVICE_ATTR_2(temp1_curr, S_IRUGO, show_curr_temp,
- NULL, 3, 0);
-
-static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 0, 1);
-static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 1, 1);
-static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 2, 1);
-static SENSOR_DEVICE_ATTR_2(temp2_curr, S_IRUGO, show_curr_temp,
- NULL, 3, 1);
-
-static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 0, 2);
-static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 1, 2);
-static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR,
- show_temp_auto_offset, store_temp_auto_offset, 2, 2);
-static SENSOR_DEVICE_ATTR_2(temp3_curr, S_IRUGO, show_curr_temp,
- NULL, 3, 2);
-
-static struct attribute *mid_att_thermal[] = {
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_curr.dev_attr.attr,
- &sensor_dev_attr_temp2_min.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp2_crit.dev_attr.attr,
- &sensor_dev_attr_temp2_curr.dev_attr.attr,
- &sensor_dev_attr_temp3_min.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp3_crit.dev_attr.attr,
- &sensor_dev_attr_temp3_curr.dev_attr.attr,
- NULL
-};
+ if (val)
+ /* Enable and start the ADC */
+ data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
+ else
+ /* Just stop the ADC */
+ data &= (~MSIC_ADC_START);
-static struct attribute_group mid_thermal_gr = {
- .name = "mid_thermal",
- .attrs = mid_att_thermal
-};
+ return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
+}
/**
- * set_up_therm_chnl - to set thermal for conversion
- * @base_addr: index of free msic adc channel
- * @therm: struct thermal module info
- * Context: can sleep
+ * set_up_therm_chnl - enable thermal channel for conversion
+ * @base_addr: index of free msic ADC channel
+ *
+ * Enable all the three channels for conversion
*
- * To set up the adc for reading thermistor
- * and converting the same into actual temp value
- * on the platform
+ * Can sleep
*/
-static int set_up_therm_chnl(u16 base_addr,
- struct thermal_module_info *therm)
+static int set_up_therm_chnl(u16 base_addr)
{
int ret;
- /* enabling the SKINTHERM0 channel */
+
+ /* Enable all the sensor channels */
ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE);
- if (ret) {
- dev_warn(&therm->pdev->dev,
- "%s:enabling skin therm sensor0 failed\n", __func__);
+ if (ret)
return ret;
- }
- /* enabling the SKINTHERM1 channel */
+
ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE);
- if (ret) {
- dev_warn(&therm->pdev->dev,
- "%s:enabling skin therm sensor1 failed\n", __func__);
+ if (ret)
return ret;
- }
- /* enabling the SYSTHERM2 channel */
+
ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE);
- if (ret) {
- dev_warn(&therm->pdev->dev,
- "%s:enabling sys therm sensor failed\n", __func__);
- return ret;
- }
- /* enabling the VAUDA line
- * this is a temporary workaround for MSIC issue */
- ret = intel_scu_ipc_iowrite8(MSIC_VAUDA, MSIC_VAUDA_VAL);
- if (ret) {
- dev_warn(&therm->pdev->dev,
- "%s:VAUDA:ipc write failed\n", __func__);
+ if (ret)
return ret;
- }
- ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, MSIC_ADC_ENBL);
+
+ /* Since this is the last channel, set the stop bit
+ to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
+ ret = intel_scu_ipc_iowrite8(base_addr + 3,
+ (MSIC_DIE_SENSOR_CODE | 0x10));
if (ret)
- dev_warn(&therm->pdev->dev,
- "%s:ADC CNTRL1 enabling failed\n", __func__);
- else
- dev_info(&therm->pdev->dev,
- "%s:therm channel set up successfull\n", __func__);
+ return ret;
+
+ /* Enable ADC and start it */
+ ret = configure_adc(1);
+
return ret;
}
-/*
+
+/**
* reset_stopbit - sets the stop bit to 0 on the given channel
* @addr: address of the channel
+ *
+ * Can sleep
*/
static int reset_stopbit(uint16_t addr)
{
@@ -473,22 +289,24 @@ static int reset_stopbit(uint16_t addr)
ret = intel_scu_ipc_ioread8(addr, &data);
if (ret)
return ret;
- data &= 0xEF; /*setting the stop bit to zero*/
- ret = intel_scu_ipc_iowrite8(addr, data);
- return ret;
+ /* Set the stop bit to zero */
+ return intel_scu_ipc_iowrite8(addr, (data & 0xEF));
}
-/*
+/**
* find_free_channel - finds an empty channel for conversion
- * @therm: struct thermal module info
+ *
+ * If the ADC is not enabled then start using 0th channel
+ * itself. Otherwise find an empty channel by looking for a
+ * channel in which the stopbit is set to 1. returns the index
+ * of the first free channel if succeeds or an error code.
+ *
* Context: can sleep
*
- * If adc is not enabled then start using 0th channel
- * itself. Otherwise find an empty channel by looking for
- * one in which the stopbit is set to 1.
- * returns the base address if succeeds,-EINVAL otherwise
+ * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc
+ * code.
*/
-static int find_free_channel(struct thermal_module_info *therm)
+static int find_free_channel(void)
{
int ret;
int i;
@@ -496,272 +314,225 @@ static int find_free_channel(struct thermal_module_info *therm)
/* check whether ADC is enabled */
ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc read failed\n", __func__);
+ if (ret)
return ret;
- }
- if ((data & 0x10) == 0) {
- data = data | 0x10; /*enable ADC */
- ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc write failed\n",
- __func__);
- return ret;
- }
- /* reset stop bit on the 14th channel */
- ret = reset_stopbit(ADC_CHNL_START_ADDR + 14);
- if (ret) {
- dev_warn(&therm->pdev->dev,
- "ipc r/w failed in reset stop bit\n");
- return ret;
- }
+
+ if ((data & MSIC_ADC_ENBL) == 0)
return 0;
- }
- /* ADC already enabled */
- /* Looping for empty channel */
+
+ /* ADC is already enabled; Looking for an empty channel */
for (i = 0; i < ADC_CHANLS_MAX; i++) {
ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc read failed\n",
- __func__);
+ if (ret)
return ret;
- }
+
if (data & MSIC_STOPBIT_MASK) {
ret = i;
break;
}
}
- if (ret > ADC_LOOP_MAX) {
- dev_warn(&therm->pdev->dev,
- "%s:Cannot set up adc, no channels free\n",
- __func__);
- return -EINVAL;
- }
- return ret;
+ return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
}
-/*
- * mid_initialize_adc - initializing the adc
- * @therm: struct thermal module info
- * Context: can sleep
+/**
+ * mid_initialize_adc - initializing the ADC
+ * @dev: our device structure
*
- * To initialize the adc for reading thermistor
- * and converting the same into actual temp value
- * on the platform
+ * Initialize the ADC for reading thermistor values. Can sleep.
*/
-static int mid_initialize_adc(struct thermal_module_info *therm)
+static int mid_initialize_adc(struct device *dev)
{
- u8 data = 0;
+ u8 data;
+ u16 base_addr;
int ret;
- int offset;
- /* ensure that therm conversion adctherm is disabled before we
- * initialize the adc and map the channels
+ /*
+ * Ensure that adctherm is disabled before we
+ * initialize the ADC
*/
ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data);
- if (ret) {
- dev_warn(&therm->pdev->dev, "%s:ipc read failed\n", __func__);
+ if (ret)
return ret;
- }
if (data & MSIC_ADCTHERM_MASK)
- dev_warn(&therm->pdev->dev, "%s:ADCTHERM already set\n",
- __func__);
+ dev_warn(dev, "ADCTHERM already set");
- ret = find_free_channel(therm);
- if (ret == -EINVAL)
- return ret;
+ /* Index of the first channel in which the stop bit is set */
+ channel_index = find_free_channel();
+ if (channel_index < 0) {
+ dev_err(dev, "No free ADC channels");
+ return channel_index;
+ }
- /* assign free channel index to global variable*/
- channel_index = ret;
+ base_addr = ADC_CHNL_START_ADDR + channel_index;
- offset = (ret == 0 || ret == ADC_LOOP_MAX) ? 0 : 1;
+ if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
+ /* Reset stop bit for channels other than 0 and 12 */
+ ret = reset_stopbit(base_addr);
+ if (ret)
+ return ret;
- /* base address of the free channel*/
- ret = set_up_therm_chnl(ADC_CHNL_START_ADDR + channel_index + offset,
- therm);
- if (ret)
- return ret;
+ /* Index of the first free channel */
+ base_addr++;
+ channel_index++;
+ }
- if (offset) { /* no need to reset for channels 0 and 12 */
- ret = reset_stopbit(ADC_CHNL_START_ADDR + channel_index);
- if (ret) {
- dev_err(&therm->pdev->dev,
- "%s:intel_mid_thermal:ipc r/w failed", __func__);
- return ret;
- }
+ ret = set_up_therm_chnl(base_addr);
+ if (ret) {
+ dev_err(dev, "unable to enable ADC");
+ return ret;
}
- dev_info(&therm->pdev->dev,
- "intel_mid_thermal:adc initialization successful\n");
+ dev_dbg(dev, "ADC initialization successful");
return ret;
}
/**
- * mid_set_default_temp_range - set default temp range
- * @therm: thermal module info structure
- * Context: can sleep
+ * initialize_sensor - sets default temp and timer ranges
+ * @index: index of the sensor
*
- * mid set default thermal range sets the initial temp thersholds
- * and can be reset by the thermal management solution running
- * on the platform
+ * Context: can sleep
*/
-static void mid_set_default_temp_range(struct thermal_module_info *therm)
+static struct thermal_device_info *initialize_sensor(int index)
{
- int i;
- /* setting default temp limits for skin thermal sensors */
- for (i = 0; i < 2; i++) {
- therm->platfrm_sens[i].min_temp = SKIN_SENSOR_MIN_TEMP;
- therm->platfrm_sens[i].max_temp = SKIN_SENSOR_MAX_TEMP;
- therm->platfrm_sens[i].crit_temp = SKIN_SENSOR_CRIT_TEMP;
- therm->platfrm_sens[i].therm_throt_temp =
- SKIN_SENSOR_THROT_START;
- }
-
- /* thresholds vary for system thermal sensor */
- therm->platfrm_sens[2].min_temp = SYS_SENSOR_MIN_TEMP;
- therm->platfrm_sens[2].max_temp = SYS_SENSOR_MAX_TEMP;
- therm->platfrm_sens[2].crit_temp = SYS_SENSOR_CRIT_TEMP;
- therm->platfrm_sens[2].therm_throt_temp = SYS_SENSOR_THROT_START;
+ struct thermal_device_info *td_info =
+ kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
+
+ if (!td_info)
+ return NULL;
+
+ /* Set the base addr of the channel for this sensor */
+ td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
+ /* Sensor 3 is direct conversion */
+ if (index == 3)
+ td_info->direct = 1;
+ return td_info;
}
/**
* mid_thermal_resume - resume routine
- * @dev: platform device structure
- * Context: can sleep
+ * @pdev: platform device structure
*
- * mid thermal resume re-initialize the thermal monitoring
- * of system as well as skin thermal sensors
+ * mid thermal resume: re-initializes the adc. Can sleep.
*/
-static int mid_thermal_resume(struct platform_device *dev)
+static int mid_thermal_resume(struct platform_device *pdev)
{
- struct thermal_module_info *therm = platform_get_drvdata(dev);
- if (therm) {
- queue_delayed_work(therm->therm_monitor_wqueue,
- &therm->thermal_monitor,
- round_jiffies_relative(HZ * 1));
- }
- return 0;
+ return mid_initialize_adc(&pdev->dev);
}
/**
* mid_thermal_suspend - suspend routine
- * @dev: platform device structure
- * Context: can sleep
+ * @pdev: platform device structure
*
* mid thermal suspend implements the suspend functionality
- * flushes the workqueue enabled for thermal monitoring
+ * by stopping the ADC. Can sleep.
*/
-static int mid_thermal_suspend(struct platform_device *dev, pm_message_t mesg)
+static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- struct thermal_module_info *therm = platform_get_drvdata(dev);
- if (therm) {
- cancel_rearming_delayed_workqueue(therm->therm_monitor_wqueue,
- &therm->thermal_monitor);
- flush_scheduled_work();
- }
- return 0;
+ /*
+ * This just stops the ADC and does not disable it.
+ * temporary workaround until we have a generic ADC driver.
+ * If 0 is passed, it disables the ADC.
+ */
+ return configure_adc(0);
}
/**
+ * read_curr_temp - reads the current temperature and stores in temp
+ * @temp: holds the current temperature value after reading
+ *
+ * Can sleep
+ */
+static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+{
+ WARN_ON(tzd == NULL);
+ return mid_read_temp(tzd, temp);
+}
+
+/* Can't be const */
+static struct thermal_zone_device_ops tzd_ops = {
+ .get_temp = read_curr_temp,
+};
+
+
+/**
* mid_thermal_probe - mfld thermal initialize
- * @dev: platform device structure
- * Context: can sleep
+ * @pdev: platform device structure
*
- * mid thermal probe initialize its internal data structue
- * and other infrastructure components for it to work
- * as expected
+ * mid thermal probe initializes the hardware and registers
+ * all the sensors with the generic thermal framework. Can sleep.
*/
-static int mid_thermal_probe(struct platform_device *dev)
+static int mid_thermal_probe(struct platform_device *pdev)
{
- int ret = 0;
- struct thermal_module_info *therm = NULL;
+ static char *name[MSIC_THERMAL_SENSORS] = {
+ "skin0", "skin1", "sys", "msicdie"
+ };
- therm = kzalloc(sizeof(struct thermal_module_info), GFP_KERNEL);
+ int ret;
+ int i;
+ struct platform_info *pinfo;
- if (therm == NULL) {
- dev_err(&dev->dev, "%s: Memory allocation failed",
- __func__);
+ pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
+ if (!pinfo)
return -ENOMEM;
- }
- therm->pdev = dev;
- platform_set_drvdata(dev, therm);
- /* creating a sysfs group with mid thermal attributes */
- ret = sysfs_create_group(&dev->dev.kobj, &mid_thermal_gr);
- if (ret) {
- dev_err(&dev->dev, "%s: sysfs create group failed!\n",
- __func__);
- goto thermal_error1;
- }
- /* Registering with hwmon class */
- therm->dev = hwmon_device_register(&dev->dev);
- if (IS_ERR(therm->dev)) {
- ret = PTR_ERR(therm->dev);
- therm->dev = NULL;
- dev_err(&dev->dev, "%s:Register hwmon dev Failed\n",
- __func__);
- goto thermal_error2;
- }
- /* initializing the workqueue required to poll the sensors */
- INIT_DELAYED_WORK(&therm->thermal_monitor,
- platform_thermal_monitor);
- therm->therm_monitor_wqueue =
- create_singlethread_workqueue(dev_name(&dev->dev));
- if (!therm->therm_monitor_wqueue) {
- dev_err(&dev->dev, "%s: wqueue init failed\n",
- __func__);
- ret = -ESRCH;
- goto wqueue_failed;
- }
+
/* Initializing the hardware */
- ret = mid_initialize_adc(therm);
+ ret = mid_initialize_adc(&pdev->dev);
if (ret) {
- dev_err(&dev->dev, "%s: adc init failed!\n",
- __func__);
- goto wqueue_failed;
+ dev_err(&pdev->dev, "ADC init failed");
+ kfree(pinfo);
+ return ret;
+ }
+
+ /* Register each sensor with the generic thermal framework*/
+ for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+ pinfo->tzd[i] = thermal_zone_device_register(name[i],
+ 0, initialize_sensor(i),
+ &tzd_ops, 0, 0, 0, 0);
+ if (IS_ERR(pinfo->tzd[i]))
+ goto reg_fail;
}
- /* setting the default min,max, and crit temp values */
- mid_set_default_temp_range(therm);
- queue_delayed_work(therm->therm_monitor_wqueue,
- &therm->thermal_monitor,
- round_jiffies_relative(HZ * 50));
- return ret;
-wqueue_failed:
- hwmon_device_unregister(therm->dev);
-thermal_error2:
- sysfs_remove_group(&dev->dev.kobj, &mid_thermal_gr);
-thermal_error1:
- kfree(therm);
+ pinfo->pdev = pdev;
+ platform_set_drvdata(pdev, pinfo);
+ return 0;
+
+reg_fail:
+ ret = PTR_ERR(pinfo->tzd[i]);
+ while (--i >= 0)
+ thermal_zone_device_unregister(pinfo->tzd[i]);
+ configure_adc(0);
+ kfree(pinfo);
return ret;
}
/**
* mid_thermal_remove - mfld thermal finalize
* @dev: platform device structure
- * Context: can sleep
*
- * MLFD thermal remove finalizes its internal data structue
- * and other components initialized during probe
+ * MLFD thermal remove unregisters all the sensors from the generic
+ * thermal framework. Can sleep.
*/
-static int mid_thermal_remove(struct platform_device *dev)
+static int mid_thermal_remove(struct platform_device *pdev)
{
- struct thermal_module_info *therm = platform_get_drvdata(dev);
-
- if (therm) {
- hwmon_device_unregister(therm->dev);
- sysfs_remove_group(&dev->dev.kobj, &mid_thermal_gr);
- kfree(therm);
- cancel_rearming_delayed_workqueue(therm->therm_monitor_wqueue,
- &therm->thermal_monitor);
- destroy_workqueue(therm->therm_monitor_wqueue);
- flush_scheduled_work();
- }
+ int i;
+ struct platform_info *pinfo = platform_get_drvdata(pdev);
+
+ for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
+ thermal_zone_device_unregister(pinfo->tzd[i]);
+
+ platform_set_drvdata(pdev, NULL);
+
+ /* Stop the ADC */
+ configure_adc(0);
return 0;
}
/*********************************************************************
* Driver initialisation and finalization
*********************************************************************/
+
+#define DRIVER_NAME "msic_sensor"
+
static const struct platform_device_id therm_id_table[] = {
{ DRIVER_NAME, 1 },
};
@@ -780,19 +551,7 @@ static struct platform_driver mid_thermal_driver = {
static int __init mid_thermal_module_init(void)
{
- int ret;
- struct platform_device *pdev;
- ret = platform_driver_register(&mid_thermal_driver);
- if (ret) {
- printk(KERN_INFO "intel_mid_thermal: driver_register failed");
- return ret;
- }
- pdev = platform_device_register_simple(DRIVER_NAME, 0, NULL, 0);
- if (IS_ERR(pdev)) {
- printk(KERN_INFO "intel_mid_thermal: device_register failed");
- return PTR_ERR(pdev);
- }
- return ret;
+ return platform_driver_register(&mid_thermal_driver);
}
static void __exit mid_thermal_module_exit(void)
@@ -803,6 +562,6 @@ static void __exit mid_thermal_module_exit(void)
module_init(mid_thermal_module_init);
module_exit(mid_thermal_module_exit);
-MODULE_AUTHOR("Ananth Krishna <ananth.krishna.r at intel.com>");
+MODULE_AUTHOR("Durgadoss R <durgadoss.r at intel.com>");
MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
MODULE_LICENSE("GPL");
--
1.6.5.2
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Medfield_Thermal_Driver_Rework.patch
Type: application/octet-stream
Size: 33836 bytes
Desc: 0001-Medfield_Thermal_Driver_Rework.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20101115/64d2af27/attachment-0001.obj>
More information about the MeeGo-kernel
mailing list