Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Thermal: exynos: Add sysfs node supporting exynos's emulation mode.

This patch supports exynos's emulation mode with newly created sysfs node.
Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for thermal
management unit. Thermal emulation mode supports software debug for TMU's
operation. User can set temperature manually with software code and TMU
will read current temperature from user value not from sensor's value.
This patch includes also documentary placed under Documentation/thermal/.

Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>

authored by

Jonghwa Lee and committed by
Zhang Rui
bbf63be4 b8bb6cb9

+165
+53
Documentation/thermal/exynos_thermal_emulation
··· 1 + EXYNOS EMULATION MODE 2 + ======================== 3 + 4 + Copyright (C) 2012 Samsung Electronics 5 + 6 + Written by Jonghwa Lee <jonghwa3.lee@samsung.com> 7 + 8 + Description 9 + ----------- 10 + 11 + Exynos 4x12 (4212, 4412) and 5 series provide emulation mode for thermal management unit. 12 + Thermal emulation mode supports software debug for TMU's operation. User can set temperature 13 + manually with software code and TMU will read current temperature from user value not from 14 + sensor's value. 15 + 16 + Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available. 17 + When it's enabled, sysfs node will be created under 18 + /sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'. 19 + 20 + The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any 21 + temperature you want to update to sysfs node, it automatically enable emulation mode and 22 + current temperature will be changed into it. 23 + (Exynos also supports user changable delay time which would be used to delay of 24 + changing temperature. However, this node only uses same delay of real sensing time, 938us.) 25 + 26 + Exynos emulation mode requires synchronous of value changing and enabling. It means when you 27 + want to update the any value of delay or next temperature, then you have to enable emulation 28 + mode at the same time. (Or you have to keep the mode enabling.) If you don't, it fails to 29 + change the value to updated one and just use last succeessful value repeatedly. That's why 30 + this node gives users the right to change termerpature only. Just one interface makes it more 31 + simply to use. 32 + 33 + Disabling emulation mode only requires writing value 0 to sysfs node. 34 + 35 + 36 + TEMP 120 | 37 + | 38 + 100 | 39 + | 40 + 80 | 41 + | +----------- 42 + 60 | | | 43 + | +-------------| | 44 + 40 | | | | 45 + | | | | 46 + 20 | | | +---------- 47 + | | | | | 48 + 0 |______________|_____________|__________|__________|_________ 49 + A A A A TIME 50 + |<----->| |<----->| |<----->| | 51 + | 938us | | | | | | 52 + emulation : 0 50 | 70 | 20 | 0 53 + current temp : sensor 50 70 20 sensor
+9
drivers/thermal/Kconfig
··· 101 101 If you say yes here you get support for TMU (Thermal Management 102 102 Unit) on SAMSUNG EXYNOS series of SoC. 103 103 104 + config EXYNOS_THERMAL_EMUL 105 + bool "EXYNOS TMU emulation mode support" 106 + depends on EXYNOS_THERMAL 107 + help 108 + Exynos 4412 and 4414 and 5 series has emulation mode on TMU. 109 + Enable this option will be make sysfs node in exynos thermal platform 110 + device directory to support emulation mode. With emulation mode sysfs 111 + node, you can manually input temperature to TMU for simulation purpose. 112 + 104 113 config DB8500_THERMAL 105 114 bool "DB8500 thermal management" 106 115 depends on ARCH_U8500
+103
drivers/thermal/exynos_thermal.c
··· 99 99 #define IDLE_INTERVAL 10000 100 100 #define MCELSIUS 1000 101 101 102 + #ifdef CONFIG_EXYNOS_THERMAL_EMUL 103 + #define EXYNOS_EMUL_TIME 0x57F0 104 + #define EXYNOS_EMUL_TIME_SHIFT 16 105 + #define EXYNOS_EMUL_DATA_SHIFT 8 106 + #define EXYNOS_EMUL_DATA_MASK 0xFF 107 + #define EXYNOS_EMUL_ENABLE 0x1 108 + #endif /* CONFIG_EXYNOS_THERMAL_EMUL */ 109 + 102 110 /* CPU Zone information */ 103 111 #define PANIC_ZONE 4 104 112 #define WARN_ZONE 3 ··· 840 832 return (struct exynos_tmu_platform_data *) 841 833 platform_get_device_id(pdev)->driver_data; 842 834 } 835 + 836 + #ifdef CONFIG_EXYNOS_THERMAL_EMUL 837 + static 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 + } 862 + out: 863 + return sprintf(buf, "%d\n", temp * MCELSIUS); 864 + } 865 + 866 + static 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 + 904 + out: 905 + return count; 906 + } 907 + 908 + static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show, 909 + exynos_tmu_emulation_store); 910 + static int create_emulation_sysfs(struct device *dev) 911 + { 912 + return device_create_file(dev, &dev_attr_emulation); 913 + } 914 + static void remove_emulation_sysfs(struct device *dev) 915 + { 916 + device_remove_file(dev, &dev_attr_emulation); 917 + } 918 + #else 919 + static inline int create_emulation_sysfs(struct device *dev) { return 0; } 920 + static inline void remove_emulation_sysfs(struct device *dev) {} 921 + #endif 922 + 843 923 static int __devinit exynos_tmu_probe(struct platform_device *pdev) 844 924 { 845 925 struct exynos_tmu_data *data; ··· 1026 930 dev_err(&pdev->dev, "Failed to register thermal interface\n"); 1027 931 goto err_clk; 1028 932 } 933 + 934 + ret = create_emulation_sysfs(&pdev->dev); 935 + if (ret) 936 + dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n"); 937 + 1029 938 return 0; 1030 939 err_clk: 1031 940 platform_set_drvdata(pdev, NULL); ··· 1041 940 static int __devexit exynos_tmu_remove(struct platform_device *pdev) 1042 941 { 1043 942 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 943 + 944 + remove_emulation_sysfs(&pdev->dev); 1044 945 1045 946 exynos_tmu_control(pdev, false); 1046 947