summaryrefslogtreecommitdiff
path: root/drivers/thermal/sprd_ddie_thm.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/thermal/sprd_ddie_thm.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/thermal/sprd_ddie_thm.c')
-rw-r--r--drivers/thermal/sprd_ddie_thm.c681
1 files changed, 681 insertions, 0 deletions
diff --git a/drivers/thermal/sprd_ddie_thm.c b/drivers/thermal/sprd_ddie_thm.c
new file mode 100644
index 00000000..269bda77
--- /dev/null
+++ b/drivers/thermal/sprd_ddie_thm.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2013 Spreadtrum Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/io.h>
+#include <soc/sprd/adi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include<linux/string.h>
+#include <soc/sprd/arch_misc.h>
+#include <soc/sprd/hardware.h>
+#include <linux/thermal.h>
+#include <linux/sprd_thm.h>
+#include "thm.h"
+
+#ifdef CONFIG_OF
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#endif
+
+#define THM_SENOR_NUM 8
+#define SPRD_THM_DEBUG
+#ifdef SPRD_THM_DEBUG
+#define THM_DEBUG(format, arg...) printk( "sprd thm: " "@@@" format, ## arg)
+#else
+#define THM_DEBUG(format, arg...)
+#endif
+
+#define THM_CTRL (0x0000)
+#define THM_INT_CTRL (0x0004)
+#define SENSOR_CTRL (0x0020)
+#define SENSOR_DET_PERI (0x0024)
+#define SENSOR_INT_CTRL (0x0028)
+#define SENSOR_INT_STS (0x002C)
+#define SENSOR_INT_RAW_STS (0x0030)
+#define SENSOR_INT_CLR (0x0034)
+#define SENSOR_OVERHEAT_THRES (0X0040)
+#define SENSOR_HOT_THRES (0X0044)
+#define SENSOR_HOT2NOR_THRES (0X0048)
+#define SENSOR_HIGHOFF_THRES (0X004C)
+#define SENSOR_LOWOFF_THRES (0X0050)
+#define SENSOR_MON_PERI (0X0058)
+#define SENSOR_MON_CTL (0X005c)
+#define SENSOR_TEMPER0_READ (0x0060)
+#define SENSOR_READ_STATUS (0x0070)
+
+
+#define A_SEN_OVERHEAT_INT_BIT (1 << 5)
+#define A_SEN_HOT_INT_BIT (1 << 4)
+#define A_SEN_HOT2NOR_INT_BIT (1 << 3)
+#define A_SEN_HIGHOFF_BIT (1 << 2)
+#define A_SEN_LOWOFF_INT_BIT (1 << 1)
+
+#define A_RAW_TEMP_OFFSET 8
+#define A_RAW_TEMP_RANGE_MSK 0x7F
+
+#define A_HIGH_BITS_OFFSET 4
+
+#define A_HIGH_TAB_SZ 8
+#define A_LOW_TAB_SZ 16
+
+#define A_HOT2NOR_RANGE 15
+#define A_LOCAL_SENSOR_ADDR_OFF 0x100
+#define A_DELAY_TEMPERATURE 3
+#define INTOFFSET 3
+
+#define A_TSMC_DOLPHINW4T_CHIP_ID_1 0x7715A001
+#define A_TSMC_DOLPHINW4T_CHIP_ID_2 0x7715A003
+#define A_TSMC_DOLPHINWT4T_CHIP_ID_1 0x8815A001
+
+static const short a_temp_search_high_152nm[A_HIGH_TAB_SZ] =
+ { -56, -29, -2, 26, 53, 79, 106, 133 };
+static const short a_temp_search_low_152nm[A_LOW_TAB_SZ] =
+ { 0, 2, 3, 5, 7, 8, 10, 11, 13, 15, 17, 18, 20, 21, 23, 25 };
+
+#define SEN_OVERHEAT_INT_BIT (1 << 5)
+#define SEN_HOT_INT_BIT (1 << 4)
+#define SEN_HOT2NOR_INT_BIT (1 << 3)
+#define SEN_HIGHOFF_BIT (1 << 2)
+#define SEN_LOWOFF_INT_BIT (1 << 1)
+#define SEN_OVERHEAT_ALARM_EN (1 << 7)
+#define SEN0_OVERHEAT_ALARM_EN (1 << 8)
+
+
+#define RAW_TEMP_RANGE_MSK 0x3FFF
+#define RAW_READ_RANGE_MSK 0x7FFF
+
+#define HIGH_BITS_OFFSET 4
+
+#define HOT2NOR_RANGE 15
+#define LOCAL_SENSOR_ADDR_OFF 0x100
+#define DELAY_TEMPERATURE 3
+
+#define LOCAL_THM_ADDR_OFF 0x200
+
+
+#define SEN_DET_PRECISION (0x50)
+
+#define TSMC_DOLPHINW4T_CHIP_ID_1 0x7715A001
+#define TSMC_DOLPHINW4T_CHIP_ID_2 0x7715A003
+#define TSMC_DOLPHINWT4T_CHIP_ID_1 0x8815A001
+
+#define TEMP_TO_RAM_DEGREE 8
+#define TEMP_LOW (-40000)
+#define TEMP_HIGH (120000)
+#ifdef CONFIG_ARCH_SCX20
+#define RAW_DATA_LOW (627)
+#define RAW_DATA_HIGH (1075)
+#else
+#define RAW_DATA_LOW (623)
+#define RAW_DATA_HIGH (1030)
+#endif
+#define CRITIC_TEMP 80000
+
+#define RAW_ADC_LOW (550)
+#define RAW_ADC_HIGH (1200)
+
+//static const u32 temp_to_raw[TEMP_TO_RAM_DEGREE + 1] = { RAW_DATA_LOW, 676, 725, 777, 828, 878, 928, 980,RAW_DATA_HIGH };
+
+unsigned long SPRD_THM_BASE = 0;
+unsigned int SPRD_THM_SIZE = 0;
+extern int sprd_thermal_init(struct sprd_thermal_zone *pzone);
+extern void sprd_thermal_remove(struct sprd_thermal_zone *pzone);
+
+static inline void __thm_reg_write(unsigned long reg, u16 bits, u16 clear_msk);
+static inline u32 __thm_reg_read(unsigned long reg);
+int sprd_thm_set_active_trip(struct sprd_thermal_zone *pzone, int trip );
+u32 sprd_thm_temp2rawdata( int temp);
+
+static inline void __thm_reg_write(unsigned long reg, u16 bits, u16 clear_msk)
+{
+ __raw_writel(((__raw_readl((volatile void *)reg) & ~clear_msk) | bits), ((volatile void *)reg));
+}
+
+static inline u32 __thm_reg_read(unsigned long reg)
+{
+ return __raw_readl((volatile void *)reg);
+}
+
+u32 sprd_thm_temp2rawdata( int temp)
+{
+ u32 raw_result;
+ if ((temp < TEMP_LOW) || (temp > TEMP_HIGH))
+ return 0;
+ raw_result = RAW_DATA_LOW +
+ (temp - TEMP_LOW) * (RAW_DATA_HIGH - RAW_DATA_LOW) / (TEMP_HIGH - TEMP_LOW);
+
+ return raw_result;
+}
+
+int sprd_thm_rawdata2temp( int rawdata)
+{
+ int temp_result;
+ if ((rawdata < RAW_ADC_LOW) || (rawdata > RAW_ADC_HIGH))
+ return 0;
+ temp_result = TEMP_LOW +
+ (rawdata - RAW_DATA_LOW) * (TEMP_HIGH - TEMP_LOW) / (RAW_DATA_HIGH - RAW_DATA_LOW);
+
+ return temp_result;
+}
+
+static unsigned long sprd_thm_temp_read(struct sprd_thermal_zone *pzone)
+{
+ u32 rawdata = 0;
+ int cal_offset = 0;
+ u32 sensor = pzone->sensor_id, local_sen_id = 0;
+ unsigned long local_sensor_addr;
+ unsigned long temp;
+ if(pzone->sensor_id == SPRD_GPU_SENSOR)
+ local_sen_id = 1;
+ local_sensor_addr = pzone->reg_base + local_sen_id * LOCAL_SENSOR_ADDR_OFF;
+ rawdata = __thm_reg_read(local_sensor_addr + SENSOR_TEMPER0_READ);
+ rawdata = rawdata & RAW_READ_RANGE_MSK;
+ cal_offset = pzone->thm_cal;
+ temp = sprd_thm_rawdata2temp( rawdata) -cal_offset;
+ printk("sensor id:%d, rawdata:0x%x, temp:%lu\n", sensor, rawdata,temp);
+ return temp;
+
+}
+
+
+#ifdef THM_TEST
+static int sprd_thm_regs_read(struct sprd_thermal_zone *pzone,unsigned int *regs)
+{
+ unsigned long base_addr = 0;
+ printk(" sprd_thm_regs_read\n");
+ if(pzone->sensor_id == SPRD_ARM_SENSOR){
+ base_addr = (unsigned long) pzone->reg_base;
+ *regs = __thm_reg_read((base_addr + SENSOR_DET_PERI));
+ *(regs + 1) = __thm_reg_read((base_addr + SENSOR_MON_CTL));
+ *(regs + 2) = __thm_reg_read((base_addr + SENSOR_MON_PERI));
+ *(regs + 3) = __thm_reg_read((base_addr + SENSOR_CTRL));
+ }
+ return 0;
+}
+
+static int sprd_thm_regs_set(struct sprd_thermal_zone *pzone,unsigned int*regs)
+{
+ u32 pre_data[4] = {0};
+ unsigned long gpu_sensor_addr,base_addr;
+ gpu_sensor_addr =
+ (unsigned long ) pzone->reg_base +LOCAL_SENSOR_ADDR_OFF;
+ printk("sprd_thm_regs_set\n");
+ base_addr = (unsigned long) pzone->reg_base;
+ pre_data[0] = __thm_reg_read(base_addr + SENSOR_DET_PERI);
+ pre_data[1] = __thm_reg_read(base_addr + SENSOR_MON_CTL);
+ pre_data[2] = __thm_reg_read(base_addr + SENSOR_MON_PERI);
+ pre_data[3] = __thm_reg_read(base_addr + SENSOR_CTRL);
+ __thm_reg_write((base_addr + SENSOR_CTRL), 0x00, 0x01);
+ __thm_reg_write((base_addr+ SENSOR_CTRL), 0x8, 0x08);
+ __thm_reg_write((base_addr + SENSOR_DET_PERI), regs[0], pre_data[0]);
+ __thm_reg_write((base_addr + SENSOR_MON_CTL), regs[1], pre_data[1]);
+ __thm_reg_write((base_addr + SENSOR_MON_PERI), regs[2], pre_data[2] |0x100 );
+ __thm_reg_write((base_addr + SENSOR_CTRL), regs[3], pre_data[3]);
+ __thm_reg_write((base_addr + SENSOR_CTRL), 0x8, 0x8);
+
+ pre_data[0] = __thm_reg_read(gpu_sensor_addr + SENSOR_DET_PERI);
+ pre_data[1] = __thm_reg_read(gpu_sensor_addr + SENSOR_MON_CTL);
+ pre_data[2] = __thm_reg_read(gpu_sensor_addr + SENSOR_MON_PERI);
+ pre_data[3] = __thm_reg_read(gpu_sensor_addr + SENSOR_CTRL);
+ __thm_reg_write((gpu_sensor_addr + SENSOR_CTRL), 0x00, 0x01);
+ __thm_reg_write((gpu_sensor_addr+ SENSOR_CTRL), 0x8, 0x08);
+ __thm_reg_write((gpu_sensor_addr + SENSOR_DET_PERI), regs[0], pre_data[0]);
+ __thm_reg_write((gpu_sensor_addr + SENSOR_MON_CTL), regs[1], pre_data[1]);
+ __thm_reg_write((gpu_sensor_addr + SENSOR_MON_PERI), regs[2], pre_data[2] |0x100 );
+ __thm_reg_write((gpu_sensor_addr + SENSOR_CTRL), regs[3], pre_data[3]);
+ __thm_reg_write((gpu_sensor_addr + SENSOR_CTRL), 0x8, 0x8);
+ return 0;
+}
+
+static int sprd_thm_trip_set(struct sprd_thermal_zone *pzone,int trip)
+{
+ THM_DEBUG("sprd_thm_trip_set trip=%d, temp=%ld,lowoff =%ld\n",
+ trip,pzone->trip_tab->trip_points[trip].temp,pzone->trip_tab->trip_points[trip].lowoff);
+ return 0;
+}
+
+#endif
+
+int sprd_thm_get_trend(struct sprd_thermal_zone *pzone, int trip, enum thermal_trend *ptrend)
+{
+ *ptrend = pzone->trend_val;
+ return 0;
+}
+
+int sprd_thm_get_hyst(struct sprd_thermal_zone *pzone, int trip, unsigned long *physt)
+{
+
+ struct sprd_thm_platform_data *trip_tab = pzone->trip_tab;
+ if (trip >= trip_tab->num_trips - 2){
+ *physt = 0;
+ }else{
+ *physt = trip_tab->trip_points[trip].temp - trip_tab->trip_points[trip + 1].lowoff;
+ }
+ return 0;
+}
+
+int init_flag=0;
+
+static int sprd_thm_hw_init(struct sprd_thermal_zone *pzone)
+{
+ unsigned long local_sensor_addr, base_addr = 0;
+ u32 local_sen_id = 0;
+ u32 raw_temp = 0;
+ int ret = 0;
+ int i;
+ struct sprd_thm_platform_data *trip_tab = pzone->trip_tab;
+ ret = sci_efuse_thermal_cal_get(&pzone->thm_cal) ;
+ THM_DEBUG("arm_sen_cal_offset =%d,ret =%d\n",pzone->thm_cal,ret);
+ if(pzone->sensor_id == SPRD_GPU_SENSOR)
+ local_sen_id = 1;
+ base_addr = (unsigned long) pzone->reg_base ;
+ local_sensor_addr = base_addr + local_sen_id * LOCAL_SENSOR_ADDR_OFF;
+
+ printk(KERN_NOTICE "sprd_thm_hw_init 2713s_thm id:%d,base 0x%lx \n",
+ pzone->sensor_id, base_addr);
+ if(init_flag ==0)
+ {
+ sci_glb_set(REG_AON_APB_APB_EB1, BIT_THM_EB);
+ sci_glb_set(REG_AON_APB_APB_RTC_EB,
+ (BIT_THM_RTC_EB | BIT_GPU_THMA_RTC_EB |
+ BIT_GPU_THMA_RTC_AUTO_EN | BIT_ARM_THMA_RTC_EB |BIT_ARM_THMA_RTC_AUTO_EN ) );
+ sci_glb_set(REG_AON_APB_APB_RST1,BIT_THM_SOFT_RST);
+ for(i=0; i < 10000; i++);
+ sci_glb_clr(REG_AON_APB_APB_RST1,BIT_THM_SOFT_RST);
+ __thm_reg_write((base_addr + THM_CTRL), 0x3, 0);
+ __thm_reg_write((base_addr + THM_INT_CTRL), 0x1, 0);
+ init_flag =1;
+ }
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL), 0, ~0); //disable all int
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CLR), ~0, 0); //clr all int
+#if 0
+ if (SPRD_ARM_SENSOR== pzone->sensor_id){
+ if (trip_tab->trip_points[trip_tab->num_trips - 1].type ==
+ THERMAL_TRIP_CRITICAL) {
+ raw_temp =
+ sprd_thm_temp2rawdata( trip_tab->trip_points[trip_tab->num_trips - 1].temp - cal_offset);
+ }
+// raw_temp = sprd_thm_temp2rawdata(CRITIC_TEMP - cal_offset);
+ __thm_reg_write((local_sensor_addr + SENSOR_OVERHEAT_THRES),raw_temp, RAW_TEMP_RANGE_MSK);//set overheat temp value
+ __thm_reg_write((base_addr + THM_INT_CTRL), SEN0_OVERHEAT_ALARM_EN, 0);
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL),SEN_OVERHEAT_ALARM_EN, 0);
+ }
+#endif
+ printk(KERN_NOTICE "sprd_thm_hw_init addr 0x:%lx,int ctrl 0x%x\n",
+ local_sensor_addr,
+ __thm_reg_read((local_sensor_addr + SENSOR_INT_CTRL)));
+
+ __thm_reg_write((local_sensor_addr + SENSOR_DET_PERI), 0x4000, 0x4000);
+ __thm_reg_write((local_sensor_addr + SENSOR_MON_CTL), 0x21, 0X21);
+ __thm_reg_write((local_sensor_addr + SENSOR_MON_PERI), 0x400, 0x100);
+ if (SPRD_ARM_SENSOR== pzone->sensor_id)
+ __thm_reg_write((base_addr + SENSOR_CTRL + LOCAL_SENSOR_ADDR_OFF), 0x030, 0x030);
+ __thm_reg_write((local_sensor_addr + SENSOR_CTRL), 0x39, 0x030);
+ return 0;
+}
+
+int sprd_thm_hw_disable_sensor(struct sprd_thermal_zone *pzone)
+{
+ int ret = 0;
+ /* Sensor minitor disable */
+ if (SPRD_ARM_SENSOR == pzone->sensor_id) {
+ /*__thm_reg_write((u32)(pzone->reg_base + SENSOR_CTRL), 0x00, 0x01);*/
+ __thm_reg_write((pzone->reg_base + SENSOR_CTRL), 0x8, 0x01);
+ } else if (SPRD_GPU_SENSOR == pzone->sensor_id) {
+ /*__thm_reg_write((u32)(pzone->reg_base + SENSOR_CTRL+ LOCAL_SENSOR_ADDR_OFF), 0x00, 0x01);*/
+ __thm_reg_write((pzone->reg_base + SENSOR_CTRL + LOCAL_SENSOR_ADDR_OFF), 0x8, 0x01);
+ } else {
+ THM_DEBUG("the sensor id is error \n");
+ }
+ return ret;
+}
+
+int sprd_thm_hw_enable_sensor(struct sprd_thermal_zone *pzone)
+{
+ int ret = 0;
+ // Sensor minitor enable
+ THM_DEBUG("sprd_2713S_thm enable sensor sensor_ID:0x%x \n",pzone->sensor_id);
+ if (SPRD_ARM_SENSOR == pzone->sensor_id) {
+ sci_glb_set(REG_AON_APB_APB_RTC_EB,
+ (BIT_THM_RTC_EB | BIT_GPU_THMA_RTC_EB |
+ BIT_GPU_THMA_RTC_AUTO_EN | BIT_ARM_THMA_RTC_EB | BIT_ARM_THMA_RTC_AUTO_EN));
+ __thm_reg_write((pzone->reg_base + SENSOR_CTRL + LOCAL_SENSOR_ADDR_OFF), 0x030, 0x0);
+ __thm_reg_write((pzone->reg_base + SENSOR_CTRL), 0x31, 0x0);
+ } else if (SPRD_GPU_SENSOR == pzone->sensor_id) {
+ /*sci_glb_set(REG_AON_APB_APB_RTC_EB,
+ (BIT_THM_RTC_EB | BIT_GPU_THMA_RTC_EB |
+ BIT_GPU_THMA_RTC_AUTO_EN | BIT_ARM_THMA_RTC_EB |BIT_ARM_THMA_RTC_AUTO_EN ) );*/
+ __thm_reg_write((pzone->reg_base + SENSOR_CTRL+LOCAL_SENSOR_ADDR_OFF), 0x31, 0x0);
+ } else {
+ THM_DEBUG("the sensor id is error \n");
+ }
+
+ return ret;
+}
+
+
+u16 int_ctrl_reg[SPRD_MAX_SENSOR];
+int sprd_thm_hw_suspend(struct sprd_thermal_zone *pzone)
+{
+ unsigned long local_sensor_addr;
+ int ret = 0;
+
+ local_sensor_addr = pzone->reg_base ;
+ /*int_ctrl_reg[pzone->sensor_id] = __thm_reg_read((local_sensor_addr + SENSOR_INT_CTRL));*/
+
+ sprd_thm_hw_disable_sensor(pzone);
+ if (SPRD_ARM_SENSOR == pzone->sensor_id) {
+ int_ctrl_reg[pzone->sensor_id] = __thm_reg_read((local_sensor_addr + SENSOR_INT_CTRL));
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL), 0, ~0); //disable all int
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CLR), ~0, 0); //clr all int
+
+ } else if (SPRD_GPU_SENSOR == pzone->sensor_id) {
+ int_ctrl_reg[pzone->sensor_id] =
+ __thm_reg_read((local_sensor_addr + SENSOR_INT_CTRL+LOCAL_SENSOR_ADDR_OFF));
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL+LOCAL_SENSOR_ADDR_OFF), 0, ~0); /*disable all int*/
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL+LOCAL_SENSOR_ADDR_OFF), ~0, 0); /*clr all int*/
+
+ } else {
+ THM_DEBUG("the sensor id is error \n");
+ }
+ return ret;
+}
+int sprd_thm_hw_resume(struct sprd_thermal_zone *pzone)
+{
+ unsigned long local_sensor_addr;
+ int ret = 0;
+
+ local_sensor_addr = pzone->reg_base ;
+
+ sprd_thm_hw_enable_sensor(pzone);
+ if (SPRD_ARM_SENSOR == pzone->sensor_id) {
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CLR), ~0, 0); //clr all int
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL), int_ctrl_reg[pzone->sensor_id], ~0); //enable int of saved
+ __thm_reg_write((local_sensor_addr + SENSOR_CTRL+LOCAL_SENSOR_ADDR_OFF), 0x30, 0);
+ __thm_reg_write((local_sensor_addr + SENSOR_CTRL), 0x39, 0);
+ } else if (SPRD_GPU_SENSOR == pzone->sensor_id) {
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CLR+LOCAL_SENSOR_ADDR_OFF), ~0, 0); /*clr all int*/
+ __thm_reg_write((local_sensor_addr + SENSOR_INT_CTRL+LOCAL_SENSOR_ADDR_OFF), int_ctrl_reg[pzone->sensor_id], ~0); /*enable int of saved*/
+ __thm_reg_write((local_sensor_addr + SENSOR_CTRL+LOCAL_SENSOR_ADDR_OFF), 0x39, 0);
+ } else {
+ THM_DEBUG("the sensor id is error \n");
+ }
+ return ret;
+}
+
+struct thm_handle_ops sprd_ddie_ops =
+{
+ .hw_init = sprd_thm_hw_init,
+ .read_temp = sprd_thm_temp_read,
+ .get_trend = sprd_thm_get_trend,
+ .get_hyst = sprd_thm_get_hyst,
+ .suspend = sprd_thm_hw_suspend,
+ .resume = sprd_thm_hw_resume,
+ .trip_debug_set = sprd_thm_trip_set,
+ .reg_debug_get = sprd_thm_regs_read,
+ .reg_debug_set = sprd_thm_regs_set,
+};
+
+#ifdef CONFIG_OF
+static struct sprd_thm *thermal_detect_parse_dt(
+ struct device *dev)
+{
+ struct sprd_thm_platform_data *pdata;
+ struct sprd_thm *thm_data;
+ struct device_node *np = dev->of_node,*sensor_child = NULL;
+ int nsensor,sensor_id;
+ int ret;
+ u32 trip_points_critical,trip_num;
+ int i = 0,j = 0,temp_interval;
+ char prop_name[32];
+ const char *tmp_str;
+ const char *thm_name;
+ u32 tmp_data,tmp_lowoff;
+ nsensor = of_get_child_count(np);
+ if (nsensor == 0) {
+ dev_err(dev, "fail to get child node \n");
+ goto fail;
+ }
+ printk("the nubutton %d\n",nsensor);
+ thm_data = kzalloc(sizeof(*thm_data), GFP_KERNEL);
+ if (!thm_data) {
+ dev_err(dev, "could not allocate memory for platform sprd_thm\n");
+ return NULL;
+ }
+ thm_data->nsensor = nsensor;
+ pdata = kzalloc(thm_data->nsensor*sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "could not allocate memory for platform data\n");
+ goto fail;
+ }
+ thm_data->sprd_data = pdata;
+ for_each_child_of_node(np,sensor_child) {
+ ret = of_property_read_u32(sensor_child, "trip-points-critical", &trip_points_critical);
+ if(ret){
+ dev_err(dev, "fail to get trip_points_critical\n");
+ goto fail;
+ }
+ ret = of_property_read_u32(sensor_child, "trip-num", &trip_num);
+ if(ret){
+ dev_err(dev, "fail to get trip_num\n");
+ goto fail;
+ }
+ ret = of_property_read_u32(sensor_child, "id", &sensor_id);
+ if (ret) {
+ dev_err(dev, "fail to get id\n");
+ goto fail;
+ }
+ ret = of_property_read_u32(sensor_child, "temp-inteval", &temp_interval);
+ if(ret){
+ dev_err(dev, "fail to get temp-inteval\n");
+ goto fail;
+ }
+ of_property_read_string(sensor_child, "thermal-name",
+ &thm_name);
+ strcpy(pdata->thm_name, thm_name);
+ for (i = 0; i <trip_num-1; ++i) {
+ sprintf(prop_name, "trip%d-temp-active", i);
+ if (of_property_read_u32(sensor_child, prop_name, &tmp_data)){
+ dev_err(dev, "fail to get trip%d-temp-active\n",i);
+ goto fail;
+ }
+ pdata->trip_points[i].temp = tmp_data;
+ sprintf(prop_name, "trip%d-temp-lowoff", i);
+ if (of_property_read_u32(sensor_child, prop_name, &tmp_lowoff)){
+ dev_err(dev, "fail to get trip%d-temp-lowoff\n",i);
+ goto fail;
+ }
+ pdata->trip_points[i].lowoff = tmp_lowoff;
+ sprintf(prop_name, "trip%d-type", i);
+ if (of_property_read_string(sensor_child, prop_name, &tmp_str))
+ goto fail;
+
+ if (!strcmp(tmp_str, "active"))
+ pdata->trip_points[i].type = THERMAL_TRIP_ACTIVE;
+ else if (!strcmp(tmp_str, "passive"))
+ pdata->trip_points[i].type = THERMAL_TRIP_PASSIVE;
+ else if (!strcmp(tmp_str, "hot"))
+ pdata->trip_points[i].type = THERMAL_TRIP_HOT;
+ else if (!strcmp(tmp_str, "critical"))
+ pdata->trip_points[i].type = THERMAL_TRIP_CRITICAL;
+ else
+ goto fail;
+
+ sprintf(prop_name, "trip%d-cdev-num", i);
+ if (of_property_read_u32(sensor_child, prop_name, &tmp_data))
+ goto fail;
+ for (j = 0; j < tmp_data; j++) {
+ sprintf(prop_name, "trip%d-cdev-name%d", i, j);
+ if (of_property_read_string(sensor_child, prop_name, &tmp_str))
+ goto fail;
+ strcpy(pdata->trip_points[i].cdev_name[j], tmp_str);
+ dev_info(dev,"cdev name: %s \n", pdata->trip_points[i].cdev_name[j]);
+ }
+ dev_info(dev, "trip[%d] temp: %lu lowoff: %lu\n",
+ i, pdata->trip_points[i].temp, pdata->trip_points[i].lowoff);
+ }
+ pdata->trip_points[i].temp = trip_points_critical;
+ pdata->trip_points[i].type = THERMAL_TRIP_CRITICAL;
+ dev_info(dev, "trip[%d] temp: %lu \n",
+ i, pdata->trip_points[i].temp);
+ pdata->num_trips = trip_num;
+ pdata->sensor_id = sensor_id;
+ pdata->temp_interval = temp_interval;
+ printk("the trip_num=%d,sensor_id =%d\n",pdata->num_trips,pdata->sensor_id);
+ pdata++;
+ };
+ return thm_data;
+
+fail:
+ kfree(pdata);
+ kfree(thm_data);
+ return NULL;
+
+}
+#endif
+
+static int sprd_ddie_thm_probe(struct platform_device *pdev)
+{
+ struct sprd_thm_platform_data *ptrips = NULL;
+ struct sprd_thermal_zone *pzone = NULL;
+ struct resource *res;
+ struct sprd_thm *pthm = NULL;
+ unsigned long ddie_thm_base;
+ int ret,i;
+#ifdef CONFIG_OF
+ struct device_node *np = pdev->dev.of_node;
+ if (!np) {
+ dev_err(&pdev->dev, "device node not found\n");
+ return -EINVAL;
+ }
+#endif
+ printk("sprd_ddie_thm_probe start\n");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ddie_thm_base = (unsigned long)devm_ioremap_resource(&pdev->dev, res);
+ if (!ddie_thm_base) {
+ pr_err("thermal ioremap failed!\n");
+ return -ENOMEM;
+ }
+#ifdef CONFIG_OF
+ pthm = thermal_detect_parse_dt(&pdev->dev);
+#else
+ pthm = dev_get_platdata(&pdev->dev);
+#endif
+ if (!pthm){
+ dev_err(&pdev->dev, "not found pthm\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < pthm->nsensor; i++) {
+ pzone = devm_kzalloc(&pdev->dev, sizeof(*pzone), GFP_KERNEL);
+ mutex_init(&pzone->th_lock);
+ mutex_lock(&pzone->th_lock);
+ if (!pzone)
+ return -ENOMEM;
+ pzone->reg_base= ddie_thm_base;
+ ptrips = &pthm->sprd_data[i];
+ pzone->trip_tab = ptrips;
+ pzone->temp_inteval = ptrips->temp_interval;
+ pzone->sensor_id = ptrips->sensor_id;
+ memcpy(pzone->thermal_zone_name,
+ ptrips->thm_name, strlen(ptrips->thm_name)+1);
+ printk("the thermal-name1 is %s\n",pzone->thermal_zone_name);
+ pzone->ops = &sprd_ddie_ops;
+ ret = sprd_thm_hw_init(pzone);
+ if(ret){
+ dev_err(&pdev->dev, " pzone hw init error id =%d\n",pzone->sensor_id);
+ return -ENODEV;
+ }
+ ret = sprd_thermal_init(pzone);
+ if(ret){
+ dev_err(&pdev->dev, " pzone sw init error id =%d\n",pzone->sensor_id);
+ return -ENODEV;
+ }
+ platform_set_drvdata(pdev, pzone);
+ printk("sprd_ddie_thm_probe---end\n");
+ mutex_unlock(&pzone->th_lock);
+ pzone++;
+ }
+ return 0;
+}
+
+static int sprd_ddie_thm_remove(struct platform_device *pdev)
+{
+
+ struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
+ sprd_thermal_remove(pzone);
+ return 0;
+}
+
+static int sprd_ddie_thm_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
+ flush_delayed_work(&pzone->thm_read_work);
+ //flush_delayed_work(&pzone->thm_logtime_work);
+ flush_delayed_work(&pzone->resume_delay_work);
+ pzone->ops->suspend(pzone);
+ return 0;
+}
+
+static int sprd_ddie_thm_resume(struct platform_device *pdev)
+{
+
+ struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
+ schedule_delayed_work(&pzone->resume_delay_work, (HZ * 1));
+ schedule_delayed_work(&pzone->thm_read_work, (HZ * 5));
+ //schedule_delayed_work(&pzone->thm_logtime_work, (HZ * 7));
+ //pzone->ops->resume(pzone);
+ return 0;
+}
+
+static const struct of_device_id thermal_of_match[] = {
+ { .compatible = "sprd,ddie-thermal", },
+ {}
+};
+
+static struct platform_driver sprd_thermal_driver = {
+ .probe = sprd_ddie_thm_probe,
+ .suspend = sprd_ddie_thm_suspend,
+ .resume = sprd_ddie_thm_resume,
+ .remove = sprd_ddie_thm_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ddie-thermal",
+ .of_match_table = of_match_ptr(thermal_of_match),
+ },
+};
+static int __init sprd_ddie_thermal_init(void)
+{
+ return platform_driver_register(&sprd_thermal_driver);
+}
+
+static void __exit sprd_ddie_thermal_exit(void)
+{
+ platform_driver_unregister(&sprd_thermal_driver);
+}
+
+
+device_initcall_sync(sprd_ddie_thermal_init);
+module_exit(sprd_ddie_thermal_exit);
+MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");
+MODULE_DESCRIPTION("sprd thermal driver");
+MODULE_LICENSE("GPL");
+