2 * Copyright (C) ST-Ericsson 2010 - 2013
3 * Author: Martin Persson <martin.persson@stericsson.com>
4 * Hongbo Zhang <hongbo.zhang@linaro.org>
5 * License Terms: GNU General Public License v2
7 * When the AB8500 thermal warning temperature is reached (threshold cannot
8 * be changed by SW), an interrupt is set, and if no further action is taken
9 * within a certain time frame, pm_power off will be called.
11 * When AB8500 thermal shutdown temperature is reached a hardware shutdown of
12 * the AB8500 will occur.
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/device.h>
19 #include <linux/platform_device.h>
20 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/interrupt.h>
23 #include <linux/irq.h>
25 #include <linux/delay.h>
26 #include <linux/slab.h>
27 #include <linux/workqueue.h>
28 #include <linux/ioport.h>
30 #include <linux/err.h>
31 #include <linux/hwmon.h>
32 #include <linux/hwmon-sysfs.h>
33 #include <linux/module.h>
34 #include <linux/slab.h>
35 #include <linux/sysfs.h>
37 #include <linux/timer.h>
38 #include <linux/completion.h>
39 #include <linux/of_irq.h>
40 #include <linux/regulator/consumer.h>
41 #include <linux/of_platform.h>
43 #include <linux/of_device.h>
44 #include "hwmon-rockchip.h"
47 #define DEFAULT_POWER_OFF_DELAY (HZ * 10)
48 /* Number of monitored sensors should not greater than NUM_SENSORS */
49 #define NUM_MONITORED_SENSORS 4
51 #define TSADC_USER_CON 0x00
52 #define TSADC_AUTO_CON 0x04
54 #define TSADC_CTRL_CH(ch) ((ch) << 0)
55 #define TSADC_CTRL_POWER_UP (1 << 3)
56 #define TSADC_CTRL_START (1 << 4)
58 #define TSADC_STAS_BUSY (1 << 12)
59 #define TSADC_STAS_BUSY_MASK (1 << 12)
60 #define TSADC_AUTO_STAS_BUSY (1 << 16)
61 #define TSADC_AUTO_STAS_BUSY_MASK (1 << 16)
62 #define TSADC_SAMPLE_DLY_SEL (1 << 17)
63 #define TSADC_SAMPLE_DLY_SEL_MASK (1 << 17)
65 #define TSADC_INT_EN 0x08
66 #define TSADC_INT_PD 0x0c
68 #define TSADC_DATA0 0x20
69 #define TSADC_DATA1 0x24
70 #define TSADC_DATA2 0x28
71 #define TSADC_DATA3 0x2c
72 #define TSADC_DATA_MASK 0xfff
74 #define TSADC_COMP0_INT 0x30
75 #define TSADC_COMP1_INT 0x34
76 #define TSADC_COMP2_INT 0x38
77 #define TSADC_COMP3_INT 0x3c
79 #define TSADC_COMP0_SHUT 0x40
80 #define TSADC_COMP1_SHUT 0x44
81 #define TSADC_COMP2_SHUT 0x48
82 #define TSADC_COMP3_SHUT 0x4c
84 #define TSADC_HIGHT_INT_DEBOUNCE 0x60
85 #define TSADC_HIGHT_TSHUT_DEBOUNCE 0x64
86 #define TSADC_HIGHT_INT_DEBOUNCE_TIME 0x03
87 #define TSADC_HIGHT_TSHUT_DEBOUNCE_TIME 0x03
89 #define TSADC_AUTO_PERIOD 0x68
90 #define TSADC_AUTO_PERIOD_HT 0x6c
91 #define TSADC_AUTO_PERIOD_TIME 0x10
92 #define TSADC_AUTO_PERIOD_HT_TIME 0x10
94 #define TSADC_AUTO_EVENT_NAME "tsadc"
96 #define TSADC_COMP_INT_DATA 80
97 #define TSADC_COMP_INT_DATA_MASK 0xfff
98 #define TSADC_COMP_SHUT_DATA 100
99 #define TSADC_COMP_SHUT_DATA_MASK 0xfff
100 #define TSADC_HIGH_TEMP_TO_SHUTDOWN 0 // 1: set gpio0_a0 output 0 ; 0:reset cpu
101 #define TSADC_TEMP_INT_EN 1
102 #define TSADC_TEMP_SHUT_EN 1
104 struct rockchip_tsadc_temp {
105 struct delayed_work power_off_work;
106 struct rockchip_temp *rockchip_data;
111 struct resource *ioarea;
112 struct tsadc_host *tsadc;
113 struct work_struct auto_ht_irq_work;
114 struct workqueue_struct *workqueue;
115 struct workqueue_struct *tsadc_workqueue;
123 static const struct tsadc_table table[] =
125 {TSADC_DATA_MASK, -40},
168 static struct rockchip_tsadc_temp *g_dev;
170 static DEFINE_MUTEX(tsadc_mutex);
172 static u32 tsadc_readl(u32 offset)
174 return readl_relaxed(g_dev->regs + offset);
177 static void tsadc_writel(u32 val, u32 offset)
179 writel_relaxed(val, g_dev->regs + offset);
182 void rockchip_tsadc_auto_ht_work(struct work_struct *work)
186 // printk("%s,line=%d\n", __func__,__LINE__);
188 mutex_lock(&tsadc_mutex);
190 val = tsadc_readl(TSADC_INT_PD);
191 tsadc_writel(val &(~ (1 <<8) ), TSADC_INT_PD);
192 ret = tsadc_readl(TSADC_INT_PD);
193 tsadc_writel(ret | 0xff, TSADC_INT_PD); //clr irq status
194 if ((val & 0x0f) != 0){
195 printk("rockchip tsadc is over temp . %s,line=%d\n", __func__,__LINE__);
196 pm_power_off(); //power_off
198 mutex_unlock(&tsadc_mutex);
201 static irqreturn_t rockchip_tsadc_auto_ht_interrupt(int irq, void *data)
203 struct rockchip_tsadc_temp *dev = data;
205 printk("%s,line=%d\n", __func__,__LINE__);
207 queue_work(dev->workqueue, &dev->auto_ht_irq_work);
212 static void rockchip_tsadc_set_cmpn_int_vale( int chn, int temp)
217 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
218 if (temp <= table[i].temp && temp > table[i -1].temp) {
219 code = table[i].code;
222 tsadc_writel((code & TSADC_COMP_INT_DATA_MASK), (TSADC_COMP0_INT + chn*4));
226 static void rockchip_tsadc_set_cmpn_shut_vale( int chn, int temp)
231 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
232 if (temp <= table[i].temp && temp > table[i -1].temp) {
233 code = table[i].code;
237 tsadc_writel((code & TSADC_COMP_SHUT_DATA_MASK), (TSADC_COMP0_SHUT + chn*4));
240 static void rockchip_tsadc_set_auto_int_en( int chn, int ht_int_en,int tshut_en)
243 tsadc_writel(0, TSADC_INT_EN);
245 ret = tsadc_readl(TSADC_INT_EN);
246 tsadc_writel( ret | (1 << chn), TSADC_INT_EN);
249 ret = tsadc_readl(TSADC_INT_EN);
250 #ifdef TSADC_HIGH_TEMP_TO_SHUTDOWN
251 tsadc_writel( ret | (1 << (chn + 4)), TSADC_INT_EN);
253 tsadc_writel( ret | (1 << (chn + 8)), TSADC_INT_EN);
258 static void rockchip_tsadc_auto_mode_set( int chn, int int_temp, int shut_temp,int int_en, int shut_en)
263 if (!g_dev || chn > 1)
266 mutex_lock(&tsadc_mutex);
268 clk_enable(g_dev->pclk);
269 clk_enable(g_dev->clk);
272 tsadc_writel(0, TSADC_AUTO_CON);
273 tsadc_writel( 1 << (4+chn), TSADC_AUTO_CON);
275 if ((tsadc_readl(TSADC_AUTO_CON) & TSADC_AUTO_STAS_BUSY_MASK) != TSADC_AUTO_STAS_BUSY) {
276 rockchip_tsadc_set_cmpn_int_vale(chn,int_temp);
277 rockchip_tsadc_set_cmpn_shut_vale(chn,shut_temp),
279 // tsadc_writel(TSADC_AUTO_PERIOD_TIME, TSADC_AUTO_PERIOD);
280 // tsadc_writel(TSADC_AUTO_PERIOD_HT_TIME, TSADC_AUTO_PERIOD_HT);
282 // tsadc_writel(TSADC_HIGHT_INT_DEBOUNCE_TIME, TSADC_HIGHT_INT_DEBOUNCE);
283 // tsadc_writel(TSADC_HIGHT_TSHUT_DEBOUNCE_TIME, TSADC_HIGHT_TSHUT_DEBOUNCE);
285 rockchip_tsadc_set_auto_int_en(chn,int_en,shut_en);
290 ret = tsadc_readl(TSADC_AUTO_CON);
291 tsadc_writel(ret | (1 <<0) , TSADC_AUTO_CON);
293 mutex_unlock(&tsadc_mutex);
297 int rockchip_tsadc_set_auto_temp(int chn)
299 rockchip_tsadc_auto_mode_set(chn, TSADC_COMP_INT_DATA,TSADC_COMP_SHUT_DATA,TSADC_TEMP_INT_EN,TSADC_TEMP_SHUT_EN);
302 EXPORT_SYMBOL(rockchip_tsadc_set_auto_temp);
304 static void rockchip_tsadc_get(int chn, int *temp, int *code)
309 if (!g_dev || chn > 4){
314 mutex_lock(&tsadc_mutex);
316 clk_enable(g_dev->pclk);
317 clk_enable(g_dev->clk);
320 tsadc_writel(0, TSADC_USER_CON);
321 tsadc_writel(TSADC_CTRL_POWER_UP | TSADC_CTRL_CH(chn), TSADC_USER_CON);
323 if ((tsadc_readl(TSADC_USER_CON) & TSADC_STAS_BUSY_MASK) != TSADC_STAS_BUSY) {
325 *code = tsadc_readl((TSADC_DATA0 + chn*4)) & TSADC_DATA_MASK;
326 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
327 if ((*code) <= table[i].code && (*code) > table[i + 1].code) {
328 *temp = table[i].temp + (table[i + 1].temp - table[i].temp) * (table[i].code - (*code)) / (table[i].code - table[i + 1].code);
333 tsadc_writel(0, TSADC_USER_CON);
335 clk_disable(g_dev->clk);
336 clk_disable(g_dev->pclk);
338 mutex_unlock(&tsadc_mutex);
341 int rockchip_tsadc_get_temp(int chn)
345 rockchip_tsadc_get(chn, &temp, &code);
348 EXPORT_SYMBOL(rockchip_tsadc_get_temp);
350 static ssize_t rockchip_show_name(struct device *dev,
351 struct device_attribute *devattr, char *buf)
353 return sprintf(buf, "rockchip-tsadc\n");
356 static ssize_t rockchip_show_label(struct device *dev,
357 struct device_attribute *devattr, char *buf)
360 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
361 int index = attr->index;
380 return sprintf(buf, "%s\n", label);
384 int rockchip_hwmon_init(struct rockchip_temp *data)
386 struct rockchip_tsadc_temp *rockchip_tsadc_data;
387 struct resource *res;
388 struct device_node *np = data->pdev->dev.of_node;
392 rockchip_tsadc_data = devm_kzalloc(&data->pdev->dev, sizeof(*rockchip_tsadc_data),
394 if (!rockchip_tsadc_data)
397 res = platform_get_resource(data->pdev, IORESOURCE_MEM, 0);
398 rockchip_tsadc_data->regs = devm_request_and_ioremap(&data->pdev->dev, res);
399 if (!rockchip_tsadc_data->regs) {
400 dev_err(&data->pdev->dev, "cannot map IO\n");
405 irq = platform_get_irq(data->pdev, 0);
407 dev_err(&data->pdev->dev, "no irq resource?\n");
410 rockchip_tsadc_data->irq = irq;
411 ret = request_threaded_irq(rockchip_tsadc_data->irq, NULL, rockchip_tsadc_auto_ht_interrupt, IRQF_ONESHOT, TSADC_AUTO_EVENT_NAME, rockchip_tsadc_data);
413 dev_err(&data->pdev->dev, "failed to attach tsadc irq\n");
417 rockchip_tsadc_data->workqueue = create_singlethread_workqueue("rockchip_tsadc");
418 INIT_WORK(&rockchip_tsadc_data->auto_ht_irq_work, rockchip_tsadc_auto_ht_work);
421 rockchip_tsadc_data->clk = devm_clk_get(&data->pdev->dev, "tsadc");
422 if (IS_ERR(rockchip_tsadc_data->clk)) {
423 dev_err(&data->pdev->dev, "failed to get tsadc clock\n");
424 ret = PTR_ERR(rockchip_tsadc_data->clk);
428 if(of_property_read_u32(np, "clock-frequency", &rate)) {
429 dev_err(&data->pdev->dev, "Missing clock-frequency property in the DT.\n");
433 ret = clk_set_rate(rockchip_tsadc_data->clk, rate);
435 dev_err(&data->pdev->dev, "failed to set adc clk\n");
438 clk_prepare_enable(rockchip_tsadc_data->clk);
440 rockchip_tsadc_data->pclk = devm_clk_get(&data->pdev->dev, "pclk_tsadc");
441 if (IS_ERR(rockchip_tsadc_data->pclk)) {
442 dev_err(&data->pdev->dev, "failed to get tsadc pclk\n");
443 ret = PTR_ERR(rockchip_tsadc_data->pclk);
446 clk_prepare_enable(rockchip_tsadc_data->pclk);
448 platform_set_drvdata(data->pdev, rockchip_tsadc_data);
449 g_dev = rockchip_tsadc_data;
450 data->plat_data = rockchip_tsadc_data;
452 data->monitored_sensors = NUM_MONITORED_SENSORS;
453 data->ops.read_sensor = rockchip_tsadc_get_temp;
454 data->ops.show_name = rockchip_show_name;
455 data->ops.show_label = rockchip_show_label;
456 data->ops.is_visible = NULL;
458 // rockchip_tsadc_set_auto_temp(0);
460 dev_info(&data->pdev->dev, "initialized\n");
464 EXPORT_SYMBOL(rockchip_hwmon_init);
466 MODULE_DESCRIPTION("Driver for TSADC");
467 MODULE_AUTHOR("zhangqing, zhangqing@rock-chips.com");
468 MODULE_LICENSE("GPL");