2 * Copyright (C) 2013 Spreadtrum Communications Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/interrupt.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/err.h>
19 #include<linux/string.h>
21 #include <linux/thermal.h>
22 #include <linux/sprd_thm.h>
24 #include "linux/delay.h"
26 #include <linux/slab.h>
27 #include <linux/of_device.h>
28 //#include <linux/of_address.h>
29 #include <linux/of_irq.h>
32 struct thm_handle_ops *sprd_boardthm_handle_ops[SPRD_MAX_SENSOR] = {NULL};
33 char sprd_boardthm_name[SPRD_MAX_SENSOR][THERMAL_NAME_LENGTH] = {{0},{0}};
35 static int sprd_thm_ops_init(struct sprd_thermal_zone *pzone)
37 if((!sprd_boardthm_name[pzone->sensor_id]) ||(!sprd_boardthm_handle_ops[pzone->sensor_id]) )
39 strcpy(pzone->thermal_zone_name,sprd_boardthm_name[pzone->sensor_id]);
40 pzone->ops = sprd_boardthm_handle_ops[pzone->sensor_id];
43 int sprd_boardthm_add(struct thm_handle_ops* ops, char *p,int id)
45 if( (ops == NULL) ||( p == NULL) ||( id > (SPRD_MAX_SENSOR - 1)))
47 sprd_boardthm_handle_ops[id] = ops;
48 strcpy(sprd_boardthm_name[id],p);
51 void sprd_boardthm_delete(int id)
53 sprd_boardthm_handle_ops[id] = NULL;
54 strcpy(sprd_boardthm_name[id],"");
56 static int sprd_thermal_match_cdev(struct thermal_cooling_device *cdev,
57 struct sprd_trip_point *trip_point)
60 if (!strlen(cdev->type))
62 for (i = 0; i < COOLING_DEV_MAX; i++) {
63 if (!strcmp(trip_point->cdev_name[i], cdev->type))
69 /* Callback to bind cooling device to thermal zone */
70 static int sprd_cdev_bind(struct thermal_zone_device *thermal,
71 struct thermal_cooling_device *cdev)
73 struct sprd_thermal_zone *pzone = thermal->devdata;
74 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
77 printk(KERN_INFO "sprd_cdev_bind--%d \n", pzone->sensor_id);
78 for (i = 0; i < ptrips->num_trips; i++) {
79 if (sprd_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
81 ret = thermal_zone_bind_cooling_device(thermal, i, cdev, THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
82 dev_info(&cdev->device, "%s bind to %d: %d-%s\n", cdev->type,
83 i, ret, ret ? "fail" : "succeed");
88 /* Callback to unbind cooling device from thermal zone */
89 static int sprd_cdev_unbind(struct thermal_zone_device *thermal,
90 struct thermal_cooling_device *cdev)
92 struct sprd_thermal_zone *pzone = thermal->devdata;
93 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
96 for (i = 0; i < ptrips->num_trips; i++) {
97 if (sprd_thermal_match_cdev(cdev, &ptrips->trip_points[i]))
99 ret = thermal_zone_unbind_cooling_device(thermal, i, cdev);
100 dev_info(&cdev->device, "%s unbind from %d: %s\n",
101 cdev->type, i, ret ? "fail" : "succeed");
106 /* Callback to get current temperature */
107 static int sprd_sys_get_temp(struct thermal_zone_device *thermal,
110 struct sprd_thermal_zone *pzone = thermal->devdata;
111 if(!pzone->ops->read_temp)
113 *temp = pzone->ops->read_temp(pzone);
117 /* Callback to get thermal zone mode */
118 static int sprd_sys_get_mode(struct thermal_zone_device *thermal,
119 enum thermal_device_mode *mode)
121 struct sprd_thermal_zone *pzone = thermal->devdata;
122 mutex_lock(&pzone->th_lock);
124 mutex_unlock(&pzone->th_lock);
128 /* Callback to set thermal zone mode */
129 static int sprd_sys_set_mode(struct thermal_zone_device *thermal,
130 enum thermal_device_mode mode)
132 struct sprd_thermal_zone *pzone = thermal->devdata;
133 mutex_lock(&pzone->th_lock);
135 if (mode == THERMAL_DEVICE_ENABLED)
136 schedule_work(&pzone->therm_work);
137 mutex_unlock(&pzone->th_lock);
141 static int sprd_sys_get_regs(struct thermal_zone_device *thermal,
144 struct sprd_thermal_zone *pzone = thermal->devdata;
145 if(!pzone->ops->reg_debug_get)
147 return pzone->ops->reg_debug_get(pzone,regs);
150 static int sprd_sys_set_regs(struct thermal_zone_device *thermal,
153 struct sprd_thermal_zone *pzone = thermal->devdata;
154 if(!pzone->ops->reg_debug_set)
156 return pzone->ops->reg_debug_set(pzone,regs);
160 debug_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
162 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
164 sprd_sys_get_regs(tz,regs);
165 return sprintf(buf, "DET_PERI=%08x,MON_CTL=%08x,MON_PERI=%08x,SENSOR_CTL=%08x\n",
166 regs[0],regs[1],regs[2],regs[3]);
170 debug_reg_store(struct device *dev, struct device_attribute *attr,
171 const char *buf, size_t count)
173 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
174 unsigned int regs[4]={0};
175 if (!sscanf(buf, "%x,%x,%x,%x", ®s[0],®s[1],®s[2],®s[3]))
178 printk("%x,%x,%x,%x\n", regs[0],regs[1],regs[2],regs[3]);
179 sprd_sys_set_regs(tz,regs);
182 static DEVICE_ATTR(debug_reg, 0644,debug_reg_show, debug_reg_store);
184 static int sprd_debug_get_trip_temp(struct thermal_zone_device *thermal,
185 int trip, unsigned long *temp,unsigned long *low_off)
187 struct sprd_thermal_zone *pzone = thermal->devdata;
188 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
189 if (trip >= ptrips->num_trips)
191 *temp = ptrips->trip_points[trip].temp;
192 *low_off = ptrips->trip_points[trip].lowoff;
196 static int sprd_debug_set_trip_temp(struct thermal_zone_device *thermal,
197 int trip, unsigned long temp,unsigned long low_off)
199 struct sprd_thermal_zone *pzone = thermal->devdata;
200 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
201 if(!pzone->ops->trip_debug_set)
203 ptrips->trip_points[trip].temp = temp;
204 ptrips->trip_points[trip].lowoff = low_off;
205 return pzone->ops->trip_debug_set(pzone,trip);
208 trip_point_debug_temp_show(struct device *dev, struct device_attribute *attr,
211 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
213 long temperature,low_off;
214 if (!sscanf(attr->attr.name, "trip_%d_temp", &trip))
216 ret = sprd_debug_get_trip_temp(tz, trip, &temperature,&low_off);
220 return sprintf(buf, "tem = %ld,low_off=%ld\n", temperature,low_off);
223 trip_point_debug_temp_store(struct device *dev, struct device_attribute *attr,
224 const char *buf, size_t count)
226 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
228 unsigned long temperature,low_off;
229 if (!sscanf(attr->attr.name, "trip_%d_temp", &trip))
231 if(!sscanf(buf,"%ld,%ld",&temperature,&low_off))
233 ret = sprd_debug_set_trip_temp(tz, trip, temperature, low_off);
234 return ret ? ret : count;
237 static int create_trip_attrs(struct thermal_zone_device *tz)
240 int size = sizeof(struct thermal_attr) * tz->trips;
242 tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
243 if (!tz->trip_temp_attrs) {
247 for (indx = 0; indx < tz->trips; indx++) {
248 /* create trip temp attribute */
249 snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
250 "trip_%d_temp", indx);
252 sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
253 tz->trip_temp_attrs[indx].attr.attr.name =
254 tz->trip_temp_attrs[indx].name;
255 tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
256 tz->trip_temp_attrs[indx].attr.show = trip_point_debug_temp_show;
257 tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
258 tz->trip_temp_attrs[indx].attr.store =trip_point_debug_temp_store;
259 device_create_file(&tz->device,
260 &tz->trip_temp_attrs[indx].attr);
265 static void remove_trip_attrs(struct thermal_zone_device *tz)
268 for (indx = 0; indx < tz->trips; indx++) {
269 device_remove_file(&tz->device,
270 &tz->trip_temp_attrs[indx].attr);
272 kfree(tz->trip_temp_attrs);
275 /* Callback to get trip point type */
276 static int sprd_sys_get_trip_type(struct thermal_zone_device *thermal,
277 int trip, enum thermal_trip_type *type)
279 struct sprd_thermal_zone *pzone = thermal->devdata;
280 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
281 if (trip >= ptrips->num_trips)
283 *type = ptrips->trip_points[trip].type;
287 /* Callback to get trip point temperature */
288 static int sprd_sys_get_trip_temp(struct thermal_zone_device *thermal,
289 int trip, unsigned long *temp)
291 struct sprd_thermal_zone *pzone = thermal->devdata;
292 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
293 if (trip >= ptrips->num_trips)
295 *temp = ptrips->trip_points[trip].temp;
299 /* Callback to get critical trip point temperature */
300 static int sprd_sys_get_crit_temp(struct thermal_zone_device *thermal,
303 struct sprd_thermal_zone *pzone = thermal->devdata;
304 struct sprd_thm_platform_data *ptrips = pzone->trip_tab;
306 for (i = ptrips->num_trips - 1; i > 0; i--) {
307 if (ptrips->trip_points[i].type == THERMAL_TRIP_CRITICAL) {
308 *temp = ptrips->trip_points[i].temp;
315 static struct thermal_zone_device_ops thdev_ops = {
316 .bind = sprd_cdev_bind,
317 .unbind = sprd_cdev_unbind,
318 .get_temp = sprd_sys_get_temp,
319 .get_mode = sprd_sys_get_mode,
320 .set_mode = sprd_sys_set_mode,
321 .get_trip_type = sprd_sys_get_trip_type,
322 .get_trip_temp = sprd_sys_get_trip_temp,
323 .get_crit_temp = sprd_sys_get_crit_temp,
326 static irqreturn_t sprd_thm_irq_handler(int irq, void *irq_data)
328 struct sprd_thermal_zone *pzone = irq_data;
330 dev_dbg(&pzone->therm_dev->device, "sprd_thm_irq_handler\n");
331 if (!pzone->ops->irq_handle(pzone)) {
332 schedule_work(&pzone->therm_work);
338 static void sprd_thermal_work(struct work_struct *work)
340 enum thermal_device_mode cur_mode;
341 struct sprd_thermal_zone *pzone;
343 pzone = container_of(work, struct sprd_thermal_zone, therm_work);
344 mutex_lock(&pzone->th_lock);
345 cur_mode = pzone->mode;
346 mutex_unlock(&pzone->th_lock);
347 if (cur_mode == THERMAL_DEVICE_DISABLED)
349 thermal_zone_device_update(pzone->therm_dev);
350 dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n");
354 static void thm_read_work(struct work_struct *work)
356 struct sprd_thermal_zone *pzone;
357 pzone = container_of(work, struct sprd_thermal_zone, thm_read_work.work);
358 thermal_zone_device_update(pzone->therm_dev);
359 printk("thm sensor id:%d, pzone->temp_inteval:%ld, temp:%d\n", pzone->sensor_id,pzone->temp_inteval,pzone->therm_dev->temperature);
360 schedule_delayed_work(&pzone->thm_read_work, (HZ * pzone->temp_inteval));
363 static void sprd_thermal_resume_delay_work(struct work_struct *work)
365 struct sprd_thermal_zone *pzone;
367 pzone = container_of(work, struct sprd_thermal_zone, resume_delay_work.work);
368 dev_dbg(&pzone->therm_dev->device, "thermal resume delay work Started.\n");
369 pzone->ops->resume(pzone);
370 dev_dbg(&pzone->therm_dev->device, "thermal resume delay work finished.\n");
374 static struct sprd_thm_platform_data *thermal_detect_parse_dt(
377 struct sprd_thm_platform_data *pdata;
378 const char *cooling_names = "cooling-names";
379 const char *point_arr[5];
381 u32 trip_points_critical,trip_num,cool_num;
382 u32 trip_temp[COOLING_DEV_MAX], trip_lowoff[COOLING_DEV_MAX];
386 struct device_node *np = dev->of_node;
388 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
390 dev_err(dev, "could not allocate memory for platform data\n");
393 ret = of_property_read_u32(np, "trip_points_critical", &trip_points_critical);
395 dev_err(dev, "fail to get trip_points_critical\n");
398 ret = of_property_read_u32(np, "trip_num", &trip_num);
400 dev_err(dev, "fail to get trip_num\n");
403 ret = of_property_read_u32(np, "cool_num", &cool_num);
407 for (i = 0; i < trip_num-1; i++) {
408 ret = of_property_read_u32_index(np, "trip_points_active", i,
411 dev_err(dev, "fail to get trip_points_active\n");
414 ret = of_property_read_u32_index(np, "trip_points_lowoff", i,
417 dev_err(dev, "fail to get trip_points_lowoff\n");
422 for (j = 0; j < cool_num; ++j){
423 ret = of_property_read_string_index(np, cooling_names, j,
426 printk("cooling_names: missing %s in dt node\n", cooling_names);
428 printk("cooling_names: %s is %s\n", cooling_names, point_arr[j]);
432 pdata->num_trips = trip_num;
434 for (i = 0; i < trip_num -1; ++i){
435 pdata->trip_points[i].temp = trip_temp[i];
436 pdata->trip_points[i].lowoff = trip_lowoff[i];
437 pdata->trip_points[i].type = THERMAL_TRIP_ACTIVE;
439 for (j = 0; j < cool_num; ++j){
440 memcpy(pdata->trip_points[i].cdev_name[j],
441 point_arr[j], strlen(point_arr[j])+1);
442 dev_info(dev,"cdev name: %s is %s\n", pdata->trip_points[i].cdev_name[j], point_arr[j]);
446 memcpy(pdata->trip_points[i].cdev_name[0],
447 "thermal-cpufreq-0", sizeof("thermal-cpufreq-0"));
448 dev_info(dev, "def cdev name:is %s\n", pdata->trip_points[i].cdev_name[0]);
451 dev_info(dev, "trip[%d] temp: %d lowoff: %d\n",
452 i, trip_temp[i], trip_lowoff[i]);
455 pdata->trip_points[i].temp = trip_points_critical;
456 pdata->trip_points[i].type = THERMAL_TRIP_CRITICAL;
466 static struct sprd_board_sensor_config *sprdboard_thermal_parse_dt(
469 struct sprd_board_sensor_config *pconfig;
470 struct device_node *np = dev->of_node;
473 int temp_adc_ch,temp_adc_scale,temp_adc_sample_cnt;
474 int temp_table_mode,temp_tab_size,temp_support;
476 pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
478 dev_err(dev, "could not allocate memory for platform data\n");
481 ret =of_property_read_u32(np, "temp-adc-ch",&temp_adc_ch);
483 dev_err(dev, "sprd_thermal_probe No temp-adc-ch\n");
486 ret =of_property_read_u32(np, "temp-adc-scale",&temp_adc_scale);
488 dev_err(dev, "sprd_thermal_probe No temp_adc_scale\n");
491 ret =of_property_read_u32(np, "temp-adc-sample-cnt",&temp_adc_sample_cnt);
493 dev_err(dev, "fail to get temp_adc_sample_cnt\n");
496 ret =of_property_read_u32(np, "temp-table-mode",&temp_table_mode);
498 dev_err(dev, "fail to get temp_table_mode\n");
501 ret =of_property_read_u32(np, "temp-tab-size",&temp_tab_size);
503 dev_err(dev, "fail to get temp_tab_size\n");
506 ret =of_property_read_u32(np, "temp-support",&temp_support);
508 dev_err(dev, "fail to get temp_support\n");
511 pconfig->temp_adc_ch=temp_adc_ch;
512 pconfig->temp_adc_sample_cnt=temp_adc_sample_cnt;
513 pconfig->temp_adc_scale=temp_adc_scale;
514 pconfig->temp_table_mode=temp_table_mode;
515 pconfig->temp_support=temp_support;
516 pconfig->temp_tab_size=temp_tab_size;
517 pconfig->temp_tab = kzalloc(sizeof(struct sprdboard_table_data) *
518 pconfig->temp_tab_size-1, GFP_KERNEL);
519 for (i = 0; i < pconfig->temp_tab_size-1; i++) {
520 ret = of_property_read_u32_index(np, "temp-tab-val", i,
521 &pconfig->temp_tab[i].x);
523 dev_err(dev, "fail to get temp-tab-va\n");
526 ret = of_property_read_u32_index(np, "temp-tab-temp", i, &temp);
528 dev_err(dev, "fail to get temp-tab-temp\n");
531 pconfig->temp_tab[i].y = temp - 1000;
543 extern int of_address_to_resource(struct device_node *dev, int index,
547 static int sprd_thermal_probe(struct platform_device *pdev)
549 struct sprd_thermal_zone *pzone = NULL;
550 struct sprd_thm_platform_data *ptrips = NULL;
551 struct sprd_board_sensor_config *pconfig = NULL;
555 struct device_node *np = pdev->dev.of_node;
558 pconfig = devm_kzalloc(&pdev->dev,
559 sizeof(struct sprd_board_sensor_config),
561 printk("sprd_thermal_probe---------start\n");
565 dev_err(&pdev->dev, "device node not found\n");
568 pconfig = sprdboard_thermal_parse_dt(&pdev->dev);
571 ptrips = thermal_detect_parse_dt(&pdev->dev);
573 ptrips = dev_get_platdata(&pdev->dev);
579 pzone = devm_kzalloc(&pdev->dev, sizeof(*pzone), GFP_KERNEL);
585 mutex_init(&pzone->th_lock);
586 mutex_lock(&pzone->th_lock);
587 pzone->mode = THERMAL_DEVICE_DISABLED;
588 pzone->trip_tab = ptrips;
589 pzone->sensor_config= pconfig;
591 ret = of_property_read_u32(np, "id", &pdev->id);
592 printk(KERN_INFO " sprd_thermal_probe id:%d\n", pdev->id);
594 printk(KERN_INFO "sprd_thermal_probe No sensor ID \n");
597 pzone->sensor_id = pdev->id;
599 pzone->sensor_id = pdev->id;
602 ret = of_property_read_u32(np, "temp_inteval", &temp_inteval);
604 printk(KERN_INFO "sprd_thermal_probe No temp_inteval \n");
607 pzone->temp_inteval=temp_inteval;
608 ret = sprd_thm_ops_init(pzone);
610 dev_err(&pdev->dev, " pzone->ops =NULL id =%d\n",pzone->sensor_id);
613 ret=pzone->ops->hw_init(pzone);
615 dev_err(&pdev->dev, " pzone->ops->hw_init error id =%d\n",pzone->sensor_id);
618 INIT_WORK(&pzone->therm_work, sprd_thermal_work);
619 INIT_DELAYED_WORK(&pzone->thm_read_work, thm_read_work);
620 INIT_DELAYED_WORK(&pzone->resume_delay_work,sprd_thermal_resume_delay_work);
622 thermal_zone_device_register(pzone->thermal_zone_name,
623 ptrips->num_trips, 0, pzone,
624 &thdev_ops, 0, 0, 0);
625 if (IS_ERR_OR_NULL(pzone->therm_dev)) {
626 dev_err(&pdev->dev, "Register thermal zone device failed.\n");
627 return PTR_ERR(pzone->therm_dev);
629 dev_info(&pdev->dev, "Thermal zone device registered.\n");
630 platform_set_drvdata(pdev, pzone);
631 pzone->mode = THERMAL_DEVICE_ENABLED;
632 mutex_unlock(&pzone->th_lock);
633 schedule_delayed_work(&pzone->thm_read_work, (HZ * pzone->temp_inteval));
636 create_trip_attrs(pzone->therm_dev);
637 ret = device_create_file(&pzone->therm_dev->device, &dev_attr_debug_reg);
639 dev_err(&pdev->dev, "create regs debug fail\n");
641 printk("sprd_thermal_probe---------end\n");
645 static int sprd_thermal_remove(struct platform_device *pdev)
647 struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
649 remove_trip_attrs(pzone->therm_dev);
650 device_remove_file(&pzone->therm_dev->device, &dev_attr_debug_reg);
652 thermal_zone_device_unregister(pzone->therm_dev);
653 cancel_work_sync(&pzone->therm_work);
654 cancel_delayed_work_sync(&pzone->thm_read_work);
655 mutex_destroy(&pzone->th_lock);
659 static int sprd_thermal_suspend(struct platform_device *pdev,
662 struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
663 flush_work(&pzone->therm_work);
664 flush_delayed_work(&pzone->resume_delay_work);
665 flush_delayed_work(&pzone->thm_read_work);
666 pzone->ops->suspend(pzone);
670 static int sprd_thermal_resume(struct platform_device *pdev)
672 struct sprd_thermal_zone *pzone = platform_get_drvdata(pdev);
673 schedule_delayed_work(&pzone->resume_delay_work, (HZ * 1));
674 schedule_delayed_work(&pzone->thm_read_work, (HZ * pzone->temp_inteval));
676 //sprd_thm_hw_resume(pzone);
682 static const struct of_device_id thermal_of_match[] = {
683 { .compatible = "sprd,board-thermal", },
688 static struct platform_driver sprd_thermal_driver = {
689 .probe = sprd_thermal_probe,
690 .suspend = sprd_thermal_suspend,
691 .resume = sprd_thermal_resume,
692 .remove = sprd_thermal_remove,
694 .owner = THIS_MODULE,
695 .name = "board-thermal",
697 .of_match_table = of_match_ptr(thermal_of_match),
701 static int __init sprd_thermal_init(void)
703 return platform_driver_register(&sprd_thermal_driver);
706 static void __exit sprd_thermal_exit(void)
708 platform_driver_unregister(&sprd_thermal_driver);
713 device_initcall_sync(sprd_thermal_init);
714 module_exit(sprd_thermal_exit);
716 MODULE_AUTHOR("Mingwei Zhang <mingwei.zhang@spreadtrum.com>");
717 MODULE_DESCRIPTION("sprd thermal sensor driver");
718 MODULE_LICENSE("GPL");