aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/exynos_thermal.c
diff options
context:
space:
mode:
authorAmit Daniel Kachhap <amit.daniel@samsung.com>2013-02-10 22:54:23 -0500
committerZhang Rui <rui.zhang@intel.com>2013-04-02 09:29:54 -0400
commitbffd1f8ac87a798515a8aed5f64047b182e049f5 (patch)
tree9cbec975b4a18d12d686c95f57c0ecf4f56c11f9 /drivers/thermal/exynos_thermal.c
parent51d45d25948bdf7422958b92a2d91dc703b1a4cc (diff)
thermal: exynos: Adapt to temperature emulation core thermal framework
This removes the driver specific sysfs support of the temperature emulation and uses the newly added core thermal framework for thermal emulation. An exynos platform specific handler is added to support this. In this patch, the exynos senor(tmu) related code and exynos framework related (thermal zone, cooling devices) code are intentionally kept separate. So an emulated function pointer is passed from sensor to framework. This is beneficial in adding more sensor support using the same framework code which is an ongoing work. The goal is to finally split them totally. Even the existing read_temperature also follows the same execution method. Acked-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal/exynos_thermal.c')
-rw-r--r--drivers/thermal/exynos_thermal.c158
1 files changed, 63 insertions, 95 deletions
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 541257888c3e..75bca0d6daf0 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -100,13 +100,13 @@
100#define IDLE_INTERVAL 10000 100#define IDLE_INTERVAL 10000
101#define MCELSIUS 1000 101#define MCELSIUS 1000
102 102
103#ifdef CONFIG_EXYNOS_THERMAL_EMUL 103#ifdef CONFIG_THERMAL_EMULATION
104#define EXYNOS_EMUL_TIME 0x57F0 104#define EXYNOS_EMUL_TIME 0x57F0
105#define EXYNOS_EMUL_TIME_SHIFT 16 105#define EXYNOS_EMUL_TIME_SHIFT 16
106#define EXYNOS_EMUL_DATA_SHIFT 8 106#define EXYNOS_EMUL_DATA_SHIFT 8
107#define EXYNOS_EMUL_DATA_MASK 0xFF 107#define EXYNOS_EMUL_DATA_MASK 0xFF
108#define EXYNOS_EMUL_ENABLE 0x1 108#define EXYNOS_EMUL_ENABLE 0x1
109#endif /* CONFIG_EXYNOS_THERMAL_EMUL */ 109#endif /* CONFIG_THERMAL_EMULATION */
110 110
111/* CPU Zone information */ 111/* CPU Zone information */
112#define PANIC_ZONE 4 112#define PANIC_ZONE 4
@@ -145,6 +145,7 @@ struct thermal_cooling_conf {
145struct thermal_sensor_conf { 145struct thermal_sensor_conf {
146 char name[SENSOR_NAME_LEN]; 146 char name[SENSOR_NAME_LEN];
147 int (*read_temperature)(void *data); 147 int (*read_temperature)(void *data);
148 int (*write_emul_temp)(void *drv_data, unsigned long temp);
148 struct thermal_trip_point_conf trip_data; 149 struct thermal_trip_point_conf trip_data;
149 struct thermal_cooling_conf cooling_data; 150 struct thermal_cooling_conf cooling_data;
150 void *private_data; 151 void *private_data;
@@ -349,6 +350,23 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
349 return 0; 350 return 0;
350} 351}
351 352
353/* Get temperature callback functions for thermal zone */
354static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
355 unsigned long temp)
356{
357 void *data;
358 int ret = -EINVAL;
359
360 if (!th_zone->sensor_conf) {
361 pr_info("Temperature sensor not initialised\n");
362 return -EINVAL;
363 }
364 data = th_zone->sensor_conf->private_data;
365 if (th_zone->sensor_conf->write_emul_temp)
366 ret = th_zone->sensor_conf->write_emul_temp(data, temp);
367 return ret;
368}
369
352/* Get the temperature trend */ 370/* Get the temperature trend */
353static int exynos_get_trend(struct thermal_zone_device *thermal, 371static int exynos_get_trend(struct thermal_zone_device *thermal,
354 int trip, enum thermal_trend *trend) 372 int trip, enum thermal_trend *trend)
@@ -372,6 +390,7 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
372 .bind = exynos_bind, 390 .bind = exynos_bind,
373 .unbind = exynos_unbind, 391 .unbind = exynos_unbind,
374 .get_temp = exynos_get_temp, 392 .get_temp = exynos_get_temp,
393 .set_emul_temp = exynos_set_emul_temp,
375 .get_trend = exynos_get_trend, 394 .get_trend = exynos_get_trend,
376 .get_mode = exynos_get_mode, 395 .get_mode = exynos_get_mode,
377 .set_mode = exynos_set_mode, 396 .set_mode = exynos_set_mode,
@@ -694,6 +713,47 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
694 return temp; 713 return temp;
695} 714}
696 715
716#ifdef CONFIG_THERMAL_EMULATION
717static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
718{
719 struct exynos_tmu_data *data = drv_data;
720 unsigned int reg;
721 int ret = -EINVAL;
722
723 if (data->soc == SOC_ARCH_EXYNOS4210)
724 goto out;
725
726 if (temp && temp < MCELSIUS)
727 goto out;
728
729 mutex_lock(&data->lock);
730 clk_enable(data->clk);
731
732 reg = readl(data->base + EXYNOS_EMUL_CON);
733
734 if (temp) {
735 temp /= MCELSIUS;
736
737 reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
738 (temp_to_code(data, temp)
739 << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
740 } else {
741 reg &= ~EXYNOS_EMUL_ENABLE;
742 }
743
744 writel(reg, data->base + EXYNOS_EMUL_CON);
745
746 clk_disable(data->clk);
747 mutex_unlock(&data->lock);
748 return 0;
749out:
750 return ret;
751}
752#else
753static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
754 { return -EINVAL; }
755#endif/*CONFIG_THERMAL_EMULATION*/
756
697static void exynos_tmu_work(struct work_struct *work) 757static void exynos_tmu_work(struct work_struct *work)
698{ 758{
699 struct exynos_tmu_data *data = container_of(work, 759 struct exynos_tmu_data *data = container_of(work,
@@ -727,6 +787,7 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
727static struct thermal_sensor_conf exynos_sensor_conf = { 787static struct thermal_sensor_conf exynos_sensor_conf = {
728 .name = "exynos-therm", 788 .name = "exynos-therm",
729 .read_temperature = (int (*)(void *))exynos_tmu_read, 789 .read_temperature = (int (*)(void *))exynos_tmu_read,
790 .write_emul_temp = exynos_tmu_set_emulation,
730}; 791};
731 792
732#if defined(CONFIG_CPU_EXYNOS4210) 793#if defined(CONFIG_CPU_EXYNOS4210)
@@ -833,93 +894,6 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
833 platform_get_device_id(pdev)->driver_data; 894 platform_get_device_id(pdev)->driver_data;
834} 895}
835 896
836#ifdef CONFIG_EXYNOS_THERMAL_EMUL
837static ssize_t exynos_tmu_emulation_show(struct device *dev,
838 struct device_attribute *attr,
839 char *buf)
840{
841 struct platform_device *pdev = container_of(dev,
842 struct platform_device, dev);
843 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
844 unsigned int reg;
845 u8 temp_code;
846 int temp = 0;
847
848 if (data->soc == SOC_ARCH_EXYNOS4210)
849 goto out;
850
851 mutex_lock(&data->lock);
852 clk_enable(data->clk);
853 reg = readl(data->base + EXYNOS_EMUL_CON);
854 clk_disable(data->clk);
855 mutex_unlock(&data->lock);
856
857 if (reg & EXYNOS_EMUL_ENABLE) {
858 reg >>= EXYNOS_EMUL_DATA_SHIFT;
859 temp_code = reg & EXYNOS_EMUL_DATA_MASK;
860 temp = code_to_temp(data, temp_code);
861 }
862out:
863 return sprintf(buf, "%d\n", temp * MCELSIUS);
864}
865
866static ssize_t exynos_tmu_emulation_store(struct device *dev,
867 struct device_attribute *attr,
868 const char *buf, size_t count)
869{
870 struct platform_device *pdev = container_of(dev,
871 struct platform_device, dev);
872 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
873 unsigned int reg;
874 int temp;
875
876 if (data->soc == SOC_ARCH_EXYNOS4210)
877 goto out;
878
879 if (!sscanf(buf, "%d\n", &temp) || temp < 0)
880 return -EINVAL;
881
882 mutex_lock(&data->lock);
883 clk_enable(data->clk);
884
885 reg = readl(data->base + EXYNOS_EMUL_CON);
886
887 if (temp) {
888 /* Both CELSIUS and MCELSIUS type are available for input */
889 if (temp > MCELSIUS)
890 temp /= MCELSIUS;
891
892 reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
893 (temp_to_code(data, (temp / MCELSIUS))
894 << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
895 } else {
896 reg &= ~EXYNOS_EMUL_ENABLE;
897 }
898
899 writel(reg, data->base + EXYNOS_EMUL_CON);
900
901 clk_disable(data->clk);
902 mutex_unlock(&data->lock);
903
904out:
905 return count;
906}
907
908static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
909 exynos_tmu_emulation_store);
910static int create_emulation_sysfs(struct device *dev)
911{
912 return device_create_file(dev, &dev_attr_emulation);
913}
914static void remove_emulation_sysfs(struct device *dev)
915{
916 device_remove_file(dev, &dev_attr_emulation);
917}
918#else
919static inline int create_emulation_sysfs(struct device *dev) { return 0; }
920static inline void remove_emulation_sysfs(struct device *dev) {}
921#endif
922
923static int exynos_tmu_probe(struct platform_device *pdev) 897static int exynos_tmu_probe(struct platform_device *pdev)
924{ 898{
925 struct exynos_tmu_data *data; 899 struct exynos_tmu_data *data;
@@ -1019,10 +993,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
1019 goto err_clk; 993 goto err_clk;
1020 } 994 }
1021 995
1022 ret = create_emulation_sysfs(&pdev->dev);
1023 if (ret)
1024 dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
1025
1026 return 0; 996 return 0;
1027err_clk: 997err_clk:
1028 platform_set_drvdata(pdev, NULL); 998 platform_set_drvdata(pdev, NULL);
@@ -1034,8 +1004,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
1034{ 1004{
1035 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 1005 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
1036 1006
1037 remove_emulation_sysfs(&pdev->dev);
1038
1039 exynos_tmu_control(pdev, false); 1007 exynos_tmu_control(pdev, false);
1040 1008
1041 exynos_unregister_thermal(); 1009 exynos_unregister_thermal();