diff options
| -rw-r--r-- | Documentation/devicetree/bindings/thermal/exynos-thermal.txt | 21 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/thermal/thermal.txt | 74 | ||||
| -rw-r--r-- | drivers/cpufreq/Kconfig.arm | 44 | ||||
| -rw-r--r-- | drivers/cpufreq/Makefile | 9 | ||||
| -rw-r--r-- | drivers/cpufreq/exynos-cpufreq.c | 33 | ||||
| -rw-r--r-- | drivers/thermal/of-thermal.c | 3 | ||||
| -rw-r--r-- | drivers/thermal/rockchip_thermal.c | 36 | ||||
| -rw-r--r-- | drivers/thermal/samsung/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/thermal/samsung/Makefile | 2 | ||||
| -rw-r--r-- | drivers/thermal/samsung/exynos_thermal_common.c | 427 | ||||
| -rw-r--r-- | drivers/thermal/samsung/exynos_thermal_common.h | 106 | ||||
| -rw-r--r-- | drivers/thermal/samsung/exynos_tmu.c | 553 | ||||
| -rw-r--r-- | drivers/thermal/samsung/exynos_tmu.h | 77 | ||||
| -rw-r--r-- | drivers/thermal/samsung/exynos_tmu_data.c | 264 | ||||
| -rw-r--r-- | include/dt-bindings/thermal/thermal_exynos.h | 28 |
15 files changed, 596 insertions, 1090 deletions
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt index ae738f562acc..695150a4136b 100644 --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4 | 12 | "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4 |
| 13 | Exynos5420 (Must pass triminfo base and triminfo clock) | 13 | Exynos5420 (Must pass triminfo base and triminfo clock) |
| 14 | "samsung,exynos5440-tmu" | 14 | "samsung,exynos5440-tmu" |
| 15 | "samsung,exynos7-tmu" | ||
| 15 | - interrupt-parent : The phandle for the interrupt controller | 16 | - interrupt-parent : The phandle for the interrupt controller |
| 16 | - reg : Address range of the thermal registers. For soc's which has multiple | 17 | - reg : Address range of the thermal registers. For soc's which has multiple |
| 17 | instances of TMU and some registers are shared across all TMU's like | 18 | instances of TMU and some registers are shared across all TMU's like |
| @@ -32,13 +33,28 @@ | |||
| 32 | - clocks : The main clocks for TMU device | 33 | - clocks : The main clocks for TMU device |
| 33 | -- 1. operational clock for TMU channel | 34 | -- 1. operational clock for TMU channel |
| 34 | -- 2. optional clock to access the shared registers of TMU channel | 35 | -- 2. optional clock to access the shared registers of TMU channel |
| 36 | -- 3. optional special clock for functional operation | ||
| 35 | - clock-names : Thermal system clock name | 37 | - clock-names : Thermal system clock name |
| 36 | -- "tmu_apbif" operational clock for current TMU channel | 38 | -- "tmu_apbif" operational clock for current TMU channel |
| 37 | -- "tmu_triminfo_apbif" clock to access the shared triminfo register | 39 | -- "tmu_triminfo_apbif" clock to access the shared triminfo register |
| 38 | for current TMU channel | 40 | for current TMU channel |
| 41 | -- "tmu_sclk" clock for functional operation of the current TMU | ||
| 42 | channel | ||
| 39 | - vtmu-supply: This entry is optional and provides the regulator node supplying | 43 | - vtmu-supply: This entry is optional and provides the regulator node supplying |
| 40 | voltage to TMU. If needed this entry can be placed inside | 44 | voltage to TMU. If needed this entry can be placed inside |
| 41 | board/platform specific dts file. | 45 | board/platform specific dts file. |
| 46 | Following properties are mandatory (depending on SoC): | ||
| 47 | - samsung,tmu_gain: Gain value for internal TMU operation. | ||
| 48 | - samsung,tmu_reference_voltage: Value of TMU IP block's reference voltage | ||
| 49 | - samsung,tmu_noise_cancel_mode: Mode for noise cancellation | ||
| 50 | - samsung,tmu_efuse_value: Default level of temperature - it is needed when | ||
| 51 | in factory fusing produced wrong value | ||
| 52 | - samsung,tmu_min_efuse_value: Minimum temperature fused value | ||
| 53 | - samsung,tmu_max_efuse_value: Maximum temperature fused value | ||
| 54 | - samsung,tmu_first_point_trim: First point trimming value | ||
| 55 | - samsung,tmu_second_point_trim: Second point trimming value | ||
| 56 | - samsung,tmu_default_temp_offset: Default temperature offset | ||
| 57 | - samsung,tmu_cal_type: Callibration type | ||
| 42 | 58 | ||
| 43 | Example 1): | 59 | Example 1): |
| 44 | 60 | ||
| @@ -51,6 +67,7 @@ Example 1): | |||
| 51 | clock-names = "tmu_apbif"; | 67 | clock-names = "tmu_apbif"; |
| 52 | status = "disabled"; | 68 | status = "disabled"; |
| 53 | vtmu-supply = <&tmu_regulator_node>; | 69 | vtmu-supply = <&tmu_regulator_node>; |
| 70 | #include "exynos4412-tmu-sensor-conf.dtsi" | ||
| 54 | }; | 71 | }; |
| 55 | 72 | ||
| 56 | Example 2): | 73 | Example 2): |
| @@ -61,6 +78,7 @@ Example 2): | |||
| 61 | interrupts = <0 58 0>; | 78 | interrupts = <0 58 0>; |
| 62 | clocks = <&clock 21>; | 79 | clocks = <&clock 21>; |
| 63 | clock-names = "tmu_apbif"; | 80 | clock-names = "tmu_apbif"; |
| 81 | #include "exynos5440-tmu-sensor-conf.dtsi" | ||
| 64 | }; | 82 | }; |
| 65 | 83 | ||
| 66 | Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register") | 84 | Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register") |
| @@ -70,6 +88,7 @@ Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register") | |||
| 70 | interrupts = <0 184 0>; | 88 | interrupts = <0 184 0>; |
| 71 | clocks = <&clock 318>, <&clock 318>; | 89 | clocks = <&clock 318>, <&clock 318>; |
| 72 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; | 90 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; |
| 91 | #include "exynos4412-tmu-sensor-conf.dtsi" | ||
| 73 | }; | 92 | }; |
| 74 | 93 | ||
| 75 | tmu_cpu3: tmu@1006c000 { | 94 | tmu_cpu3: tmu@1006c000 { |
| @@ -78,6 +97,7 @@ Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register") | |||
| 78 | interrupts = <0 185 0>; | 97 | interrupts = <0 185 0>; |
| 79 | clocks = <&clock 318>, <&clock 319>; | 98 | clocks = <&clock 318>, <&clock 319>; |
| 80 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; | 99 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; |
| 100 | #include "exynos4412-tmu-sensor-conf.dtsi" | ||
| 81 | }; | 101 | }; |
| 82 | 102 | ||
| 83 | tmu_gpu: tmu@100a0000 { | 103 | tmu_gpu: tmu@100a0000 { |
| @@ -86,6 +106,7 @@ Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register") | |||
| 86 | interrupts = <0 215 0>; | 106 | interrupts = <0 215 0>; |
| 87 | clocks = <&clock 319>, <&clock 318>; | 107 | clocks = <&clock 319>, <&clock 318>; |
| 88 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; | 108 | clock-names = "tmu_apbif", "tmu_triminfo_apbif"; |
| 109 | #include "exynos4412-tmu-sensor-conf.dtsi" | ||
| 89 | }; | 110 | }; |
| 90 | 111 | ||
| 91 | Note: For multi-instance tmu each instance should have an alias correctly | 112 | Note: For multi-instance tmu each instance should have an alias correctly |
diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt index f5db6b72a36f..29fe0bfae38e 100644 --- a/Documentation/devicetree/bindings/thermal/thermal.txt +++ b/Documentation/devicetree/bindings/thermal/thermal.txt | |||
| @@ -251,24 +251,24 @@ ocp { | |||
| 251 | }; | 251 | }; |
| 252 | 252 | ||
| 253 | thermal-zones { | 253 | thermal-zones { |
| 254 | cpu-thermal: cpu-thermal { | 254 | cpu_thermal: cpu-thermal { |
| 255 | polling-delay-passive = <250>; /* milliseconds */ | 255 | polling-delay-passive = <250>; /* milliseconds */ |
| 256 | polling-delay = <1000>; /* milliseconds */ | 256 | polling-delay = <1000>; /* milliseconds */ |
| 257 | 257 | ||
| 258 | thermal-sensors = <&bandgap0>; | 258 | thermal-sensors = <&bandgap0>; |
| 259 | 259 | ||
| 260 | trips { | 260 | trips { |
| 261 | cpu-alert0: cpu-alert { | 261 | cpu_alert0: cpu-alert0 { |
| 262 | temperature = <90000>; /* millicelsius */ | 262 | temperature = <90000>; /* millicelsius */ |
| 263 | hysteresis = <2000>; /* millicelsius */ | 263 | hysteresis = <2000>; /* millicelsius */ |
| 264 | type = "active"; | 264 | type = "active"; |
| 265 | }; | 265 | }; |
| 266 | cpu-alert1: cpu-alert { | 266 | cpu_alert1: cpu-alert1 { |
| 267 | temperature = <100000>; /* millicelsius */ | 267 | temperature = <100000>; /* millicelsius */ |
| 268 | hysteresis = <2000>; /* millicelsius */ | 268 | hysteresis = <2000>; /* millicelsius */ |
| 269 | type = "passive"; | 269 | type = "passive"; |
| 270 | }; | 270 | }; |
| 271 | cpu-crit: cpu-crit { | 271 | cpu_crit: cpu-crit { |
| 272 | temperature = <125000>; /* millicelsius */ | 272 | temperature = <125000>; /* millicelsius */ |
| 273 | hysteresis = <2000>; /* millicelsius */ | 273 | hysteresis = <2000>; /* millicelsius */ |
| 274 | type = "critical"; | 274 | type = "critical"; |
| @@ -277,17 +277,17 @@ thermal-zones { | |||
| 277 | 277 | ||
| 278 | cooling-maps { | 278 | cooling-maps { |
| 279 | map0 { | 279 | map0 { |
| 280 | trip = <&cpu-alert0>; | 280 | trip = <&cpu_alert0>; |
| 281 | cooling-device = <&fan0 THERMAL_NO_LIMITS 4>; | 281 | cooling-device = <&fan0 THERMAL_NO_LIMIT 4>; |
| 282 | }; | 282 | }; |
| 283 | map1 { | 283 | map1 { |
| 284 | trip = <&cpu-alert1>; | 284 | trip = <&cpu_alert1>; |
| 285 | cooling-device = <&fan0 5 THERMAL_NO_LIMITS>; | 285 | cooling-device = <&fan0 5 THERMAL_NO_LIMIT>; |
| 286 | }; | 286 | }; |
| 287 | map2 { | 287 | map2 { |
| 288 | trip = <&cpu-alert1>; | 288 | trip = <&cpu_alert1>; |
| 289 | cooling-device = | 289 | cooling-device = |
| 290 | <&cpu0 THERMAL_NO_LIMITS THERMAL_NO_LIMITS>; | 290 | <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; |
| 291 | }; | 291 | }; |
| 292 | }; | 292 | }; |
| 293 | }; | 293 | }; |
| @@ -298,13 +298,13 @@ used to monitor the zone 'cpu-thermal' using its sole sensor. A fan | |||
| 298 | device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten | 298 | device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten |
| 299 | different cooling states 0-9. It is used to remove the heat out of | 299 | different cooling states 0-9. It is used to remove the heat out of |
| 300 | the thermal zone 'cpu-thermal' using its cooling states | 300 | the thermal zone 'cpu-thermal' using its cooling states |
| 301 | from its minimum to 4, when it reaches trip point 'cpu-alert0' | 301 | from its minimum to 4, when it reaches trip point 'cpu_alert0' |
| 302 | at 90C, as an example of active cooling. The same cooling device is used at | 302 | at 90C, as an example of active cooling. The same cooling device is used at |
| 303 | 'cpu-alert1', but from 5 to its maximum state. The cpu@0 device is also | 303 | 'cpu_alert1', but from 5 to its maximum state. The cpu@0 device is also |
| 304 | linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, | 304 | linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, |
| 305 | using all its cooling states at trip point 'cpu-alert1', | 305 | using all its cooling states at trip point 'cpu_alert1', |
| 306 | which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the | 306 | which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the |
| 307 | temperature of 125C, represented by the trip point 'cpu-crit', the silicon | 307 | temperature of 125C, represented by the trip point 'cpu_crit', the silicon |
| 308 | is not reliable anymore. | 308 | is not reliable anymore. |
| 309 | 309 | ||
| 310 | (b) - IC with several internal sensors | 310 | (b) - IC with several internal sensors |
| @@ -329,7 +329,7 @@ ocp { | |||
| 329 | }; | 329 | }; |
| 330 | 330 | ||
| 331 | thermal-zones { | 331 | thermal-zones { |
| 332 | cpu-thermal: cpu-thermal { | 332 | cpu_thermal: cpu-thermal { |
| 333 | polling-delay-passive = <250>; /* milliseconds */ | 333 | polling-delay-passive = <250>; /* milliseconds */ |
| 334 | polling-delay = <1000>; /* milliseconds */ | 334 | polling-delay = <1000>; /* milliseconds */ |
| 335 | 335 | ||
| @@ -338,12 +338,12 @@ thermal-zones { | |||
| 338 | 338 | ||
| 339 | trips { | 339 | trips { |
| 340 | /* each zone within the SoC may have its own trips */ | 340 | /* each zone within the SoC may have its own trips */ |
| 341 | cpu-alert: cpu-alert { | 341 | cpu_alert: cpu-alert { |
| 342 | temperature = <100000>; /* millicelsius */ | 342 | temperature = <100000>; /* millicelsius */ |
| 343 | hysteresis = <2000>; /* millicelsius */ | 343 | hysteresis = <2000>; /* millicelsius */ |
| 344 | type = "passive"; | 344 | type = "passive"; |
| 345 | }; | 345 | }; |
| 346 | cpu-crit: cpu-crit { | 346 | cpu_crit: cpu-crit { |
| 347 | temperature = <125000>; /* millicelsius */ | 347 | temperature = <125000>; /* millicelsius */ |
| 348 | hysteresis = <2000>; /* millicelsius */ | 348 | hysteresis = <2000>; /* millicelsius */ |
| 349 | type = "critical"; | 349 | type = "critical"; |
| @@ -356,7 +356,7 @@ thermal-zones { | |||
| 356 | }; | 356 | }; |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | gpu-thermal: gpu-thermal { | 359 | gpu_thermal: gpu-thermal { |
| 360 | polling-delay-passive = <120>; /* milliseconds */ | 360 | polling-delay-passive = <120>; /* milliseconds */ |
| 361 | polling-delay = <1000>; /* milliseconds */ | 361 | polling-delay = <1000>; /* milliseconds */ |
| 362 | 362 | ||
| @@ -365,12 +365,12 @@ thermal-zones { | |||
| 365 | 365 | ||
| 366 | trips { | 366 | trips { |
| 367 | /* each zone within the SoC may have its own trips */ | 367 | /* each zone within the SoC may have its own trips */ |
| 368 | gpu-alert: gpu-alert { | 368 | gpu_alert: gpu-alert { |
| 369 | temperature = <90000>; /* millicelsius */ | 369 | temperature = <90000>; /* millicelsius */ |
| 370 | hysteresis = <2000>; /* millicelsius */ | 370 | hysteresis = <2000>; /* millicelsius */ |
| 371 | type = "passive"; | 371 | type = "passive"; |
| 372 | }; | 372 | }; |
| 373 | gpu-crit: gpu-crit { | 373 | gpu_crit: gpu-crit { |
| 374 | temperature = <105000>; /* millicelsius */ | 374 | temperature = <105000>; /* millicelsius */ |
| 375 | hysteresis = <2000>; /* millicelsius */ | 375 | hysteresis = <2000>; /* millicelsius */ |
| 376 | type = "critical"; | 376 | type = "critical"; |
| @@ -383,7 +383,7 @@ thermal-zones { | |||
| 383 | }; | 383 | }; |
| 384 | }; | 384 | }; |
| 385 | 385 | ||
| 386 | dsp-thermal: dsp-thermal { | 386 | dsp_thermal: dsp-thermal { |
| 387 | polling-delay-passive = <50>; /* milliseconds */ | 387 | polling-delay-passive = <50>; /* milliseconds */ |
| 388 | polling-delay = <1000>; /* milliseconds */ | 388 | polling-delay = <1000>; /* milliseconds */ |
| 389 | 389 | ||
| @@ -392,12 +392,12 @@ thermal-zones { | |||
| 392 | 392 | ||
| 393 | trips { | 393 | trips { |
| 394 | /* each zone within the SoC may have its own trips */ | 394 | /* each zone within the SoC may have its own trips */ |
| 395 | dsp-alert: gpu-alert { | 395 | dsp_alert: dsp-alert { |
| 396 | temperature = <90000>; /* millicelsius */ | 396 | temperature = <90000>; /* millicelsius */ |
| 397 | hysteresis = <2000>; /* millicelsius */ | 397 | hysteresis = <2000>; /* millicelsius */ |
| 398 | type = "passive"; | 398 | type = "passive"; |
| 399 | }; | 399 | }; |
| 400 | dsp-crit: gpu-crit { | 400 | dsp_crit: gpu-crit { |
| 401 | temperature = <135000>; /* millicelsius */ | 401 | temperature = <135000>; /* millicelsius */ |
| 402 | hysteresis = <2000>; /* millicelsius */ | 402 | hysteresis = <2000>; /* millicelsius */ |
| 403 | type = "critical"; | 403 | type = "critical"; |
| @@ -457,7 +457,7 @@ ocp { | |||
| 457 | }; | 457 | }; |
| 458 | 458 | ||
| 459 | thermal-zones { | 459 | thermal-zones { |
| 460 | cpu-thermal: cpu-thermal { | 460 | cpu_thermal: cpu-thermal { |
| 461 | polling-delay-passive = <250>; /* milliseconds */ | 461 | polling-delay-passive = <250>; /* milliseconds */ |
| 462 | polling-delay = <1000>; /* milliseconds */ | 462 | polling-delay = <1000>; /* milliseconds */ |
| 463 | 463 | ||
| @@ -508,7 +508,7 @@ with many sensors and many cooling devices. | |||
| 508 | /* | 508 | /* |
| 509 | * An IC with several temperature sensor. | 509 | * An IC with several temperature sensor. |
| 510 | */ | 510 | */ |
| 511 | adc-dummy: sensor@0x50 { | 511 | adc_dummy: sensor@0x50 { |
| 512 | ... | 512 | ... |
| 513 | #thermal-sensor-cells = <1>; /* sensor internal ID */ | 513 | #thermal-sensor-cells = <1>; /* sensor internal ID */ |
| 514 | }; | 514 | }; |
| @@ -520,7 +520,7 @@ thermal-zones { | |||
| 520 | polling-delay = <2500>; /* milliseconds */ | 520 | polling-delay = <2500>; /* milliseconds */ |
| 521 | 521 | ||
| 522 | /* sensor ID */ | 522 | /* sensor ID */ |
| 523 | thermal-sensors = <&adc-dummy 4>; | 523 | thermal-sensors = <&adc_dummy 4>; |
| 524 | 524 | ||
| 525 | trips { | 525 | trips { |
| 526 | ... | 526 | ... |
| @@ -531,14 +531,14 @@ thermal-zones { | |||
| 531 | }; | 531 | }; |
| 532 | }; | 532 | }; |
| 533 | 533 | ||
| 534 | board-thermal: board-thermal { | 534 | board_thermal: board-thermal { |
| 535 | polling-delay-passive = <1000>; /* milliseconds */ | 535 | polling-delay-passive = <1000>; /* milliseconds */ |
| 536 | polling-delay = <2500>; /* milliseconds */ | 536 | polling-delay = <2500>; /* milliseconds */ |
| 537 | 537 | ||
| 538 | /* sensor ID */ | 538 | /* sensor ID */ |
| 539 | thermal-sensors = <&adc-dummy 0>, /* pcb top edge */ | 539 | thermal-sensors = <&adc_dummy 0>, /* pcb top edge */ |
| 540 | <&adc-dummy 1>, /* lcd */ | 540 | <&adc_dummy 1>, /* lcd */ |
| 541 | <&adc-dymmy 2>; /* back cover */ | 541 | <&adc_dummy 2>; /* back cover */ |
| 542 | /* | 542 | /* |
| 543 | * An array of coefficients describing the sensor | 543 | * An array of coefficients describing the sensor |
| 544 | * linear relation. E.g.: | 544 | * linear relation. E.g.: |
| @@ -548,22 +548,22 @@ thermal-zones { | |||
| 548 | 548 | ||
| 549 | trips { | 549 | trips { |
| 550 | /* Trips are based on resulting linear equation */ | 550 | /* Trips are based on resulting linear equation */ |
| 551 | cpu-trip: cpu-trip { | 551 | cpu_trip: cpu-trip { |
| 552 | temperature = <60000>; /* millicelsius */ | 552 | temperature = <60000>; /* millicelsius */ |
| 553 | hysteresis = <2000>; /* millicelsius */ | 553 | hysteresis = <2000>; /* millicelsius */ |
| 554 | type = "passive"; | 554 | type = "passive"; |
| 555 | }; | 555 | }; |
| 556 | gpu-trip: gpu-trip { | 556 | gpu_trip: gpu-trip { |
| 557 | temperature = <55000>; /* millicelsius */ | 557 | temperature = <55000>; /* millicelsius */ |
| 558 | hysteresis = <2000>; /* millicelsius */ | 558 | hysteresis = <2000>; /* millicelsius */ |
| 559 | type = "passive"; | 559 | type = "passive"; |
| 560 | } | 560 | } |
| 561 | lcd-trip: lcp-trip { | 561 | lcd_trip: lcp-trip { |
| 562 | temperature = <53000>; /* millicelsius */ | 562 | temperature = <53000>; /* millicelsius */ |
| 563 | hysteresis = <2000>; /* millicelsius */ | 563 | hysteresis = <2000>; /* millicelsius */ |
| 564 | type = "passive"; | 564 | type = "passive"; |
| 565 | }; | 565 | }; |
| 566 | crit-trip: crit-trip { | 566 | crit_trip: crit-trip { |
| 567 | temperature = <68000>; /* millicelsius */ | 567 | temperature = <68000>; /* millicelsius */ |
| 568 | hysteresis = <2000>; /* millicelsius */ | 568 | hysteresis = <2000>; /* millicelsius */ |
| 569 | type = "critical"; | 569 | type = "critical"; |
| @@ -572,17 +572,17 @@ thermal-zones { | |||
| 572 | 572 | ||
| 573 | cooling-maps { | 573 | cooling-maps { |
| 574 | map0 { | 574 | map0 { |
| 575 | trip = <&cpu-trip>; | 575 | trip = <&cpu_trip>; |
| 576 | cooling-device = <&cpu0 0 2>; | 576 | cooling-device = <&cpu0 0 2>; |
| 577 | contribution = <55>; | 577 | contribution = <55>; |
| 578 | }; | 578 | }; |
| 579 | map1 { | 579 | map1 { |
| 580 | trip = <&gpu-trip>; | 580 | trip = <&gpu_trip>; |
| 581 | cooling-device = <&gpu0 0 2>; | 581 | cooling-device = <&gpu0 0 2>; |
| 582 | contribution = <20>; | 582 | contribution = <20>; |
| 583 | }; | 583 | }; |
| 584 | map2 { | 584 | map2 { |
| 585 | trip = <&lcd-trip>; | 585 | trip = <&lcd_trip>; |
| 586 | cooling-device = <&lcd0 5 10>; | 586 | cooling-device = <&lcd0 5 10>; |
| 587 | contribution = <15>; | 587 | contribution = <15>; |
| 588 | }; | 588 | }; |
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0f9a2c3c0e0d..1b06fc4640e2 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm | |||
| @@ -26,13 +26,21 @@ config ARM_VEXPRESS_SPC_CPUFREQ | |||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | config ARM_EXYNOS_CPUFREQ | 28 | config ARM_EXYNOS_CPUFREQ |
| 29 | bool | 29 | tristate "SAMSUNG EXYNOS CPUfreq Driver" |
| 30 | depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 | ||
| 31 | depends on THERMAL | ||
| 32 | help | ||
| 33 | This adds the CPUFreq driver for Samsung EXYNOS platforms. | ||
| 34 | Supported SoC versions are: | ||
| 35 | Exynos4210, Exynos4212, Exynos4412, and Exynos5250. | ||
| 36 | |||
| 37 | If in doubt, say N. | ||
| 30 | 38 | ||
| 31 | config ARM_EXYNOS4210_CPUFREQ | 39 | config ARM_EXYNOS4210_CPUFREQ |
| 32 | bool "SAMSUNG EXYNOS4210" | 40 | bool "SAMSUNG EXYNOS4210" |
| 33 | depends on CPU_EXYNOS4210 | 41 | depends on CPU_EXYNOS4210 |
| 42 | depends on ARM_EXYNOS_CPUFREQ | ||
| 34 | default y | 43 | default y |
| 35 | select ARM_EXYNOS_CPUFREQ | ||
| 36 | help | 44 | help |
| 37 | This adds the CPUFreq driver for Samsung EXYNOS4210 | 45 | This adds the CPUFreq driver for Samsung EXYNOS4210 |
| 38 | SoC (S5PV310 or S5PC210). | 46 | SoC (S5PV310 or S5PC210). |
| @@ -42,8 +50,8 @@ config ARM_EXYNOS4210_CPUFREQ | |||
| 42 | config ARM_EXYNOS4X12_CPUFREQ | 50 | config ARM_EXYNOS4X12_CPUFREQ |
| 43 | bool "SAMSUNG EXYNOS4x12" | 51 | bool "SAMSUNG EXYNOS4x12" |
| 44 | depends on SOC_EXYNOS4212 || SOC_EXYNOS4412 | 52 | depends on SOC_EXYNOS4212 || SOC_EXYNOS4412 |
| 53 | depends on ARM_EXYNOS_CPUFREQ | ||
| 45 | default y | 54 | default y |
| 46 | select ARM_EXYNOS_CPUFREQ | ||
| 47 | help | 55 | help |
| 48 | This adds the CPUFreq driver for Samsung EXYNOS4X12 | 56 | This adds the CPUFreq driver for Samsung EXYNOS4X12 |
| 49 | SoC (EXYNOS4212 or EXYNOS4412). | 57 | SoC (EXYNOS4212 or EXYNOS4412). |
| @@ -53,28 +61,14 @@ config ARM_EXYNOS4X12_CPUFREQ | |||
| 53 | config ARM_EXYNOS5250_CPUFREQ | 61 | config ARM_EXYNOS5250_CPUFREQ |
| 54 | bool "SAMSUNG EXYNOS5250" | 62 | bool "SAMSUNG EXYNOS5250" |
| 55 | depends on SOC_EXYNOS5250 | 63 | depends on SOC_EXYNOS5250 |
| 64 | depends on ARM_EXYNOS_CPUFREQ | ||
| 56 | default y | 65 | default y |
| 57 | select ARM_EXYNOS_CPUFREQ | ||
| 58 | help | 66 | help |
| 59 | This adds the CPUFreq driver for Samsung EXYNOS5250 | 67 | This adds the CPUFreq driver for Samsung EXYNOS5250 |
| 60 | SoC. | 68 | SoC. |
| 61 | 69 | ||
| 62 | If in doubt, say N. | 70 | If in doubt, say N. |
| 63 | 71 | ||
| 64 | config ARM_EXYNOS5440_CPUFREQ | ||
| 65 | bool "SAMSUNG EXYNOS5440" | ||
| 66 | depends on SOC_EXYNOS5440 | ||
| 67 | depends on HAVE_CLK && OF | ||
| 68 | select PM_OPP | ||
| 69 | default y | ||
| 70 | help | ||
| 71 | This adds the CPUFreq driver for Samsung EXYNOS5440 | ||
| 72 | SoC. The nature of exynos5440 clock controller is | ||
| 73 | different than previous exynos controllers so not using | ||
| 74 | the common exynos framework. | ||
| 75 | |||
| 76 | If in doubt, say N. | ||
| 77 | |||
| 78 | config ARM_EXYNOS_CPU_FREQ_BOOST_SW | 72 | config ARM_EXYNOS_CPU_FREQ_BOOST_SW |
| 79 | bool "EXYNOS Frequency Overclocking - Software" | 73 | bool "EXYNOS Frequency Overclocking - Software" |
| 80 | depends on ARM_EXYNOS_CPUFREQ && THERMAL | 74 | depends on ARM_EXYNOS_CPUFREQ && THERMAL |
| @@ -90,6 +84,20 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW | |||
| 90 | 84 | ||
| 91 | If in doubt, say N. | 85 | If in doubt, say N. |
| 92 | 86 | ||
| 87 | config ARM_EXYNOS5440_CPUFREQ | ||
| 88 | tristate "SAMSUNG EXYNOS5440" | ||
| 89 | depends on SOC_EXYNOS5440 | ||
| 90 | depends on HAVE_CLK && OF | ||
| 91 | select PM_OPP | ||
| 92 | default y | ||
| 93 | help | ||
| 94 | This adds the CPUFreq driver for Samsung EXYNOS5440 | ||
| 95 | SoC. The nature of exynos5440 clock controller is | ||
| 96 | different than previous exynos controllers so not using | ||
| 97 | the common exynos framework. | ||
| 98 | |||
| 99 | If in doubt, say N. | ||
| 100 | |||
| 93 | config ARM_HIGHBANK_CPUFREQ | 101 | config ARM_HIGHBANK_CPUFREQ |
| 94 | tristate "Calxeda Highbank-based" | 102 | tristate "Calxeda Highbank-based" |
| 95 | depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR | 103 | depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR |
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 8b4220ac888b..82a1821471fd 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
| @@ -52,10 +52,11 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o | |||
| 52 | 52 | ||
| 53 | obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o | 53 | obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o |
| 54 | obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o | 54 | obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o |
| 55 | obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o | 55 | obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += arm-exynos-cpufreq.o |
| 56 | obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o | 56 | arm-exynos-cpufreq-y := exynos-cpufreq.o |
| 57 | obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o | 57 | arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o |
| 58 | obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o | 58 | arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o |
| 59 | arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o | ||
| 59 | obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o | 60 | obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o |
| 60 | obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o | 61 | obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o |
| 61 | obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o | 62 | obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o |
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index f99a0b0b7c06..5e98c6b1f284 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c | |||
| @@ -18,10 +18,13 @@ | |||
| 18 | #include <linux/cpufreq.h> | 18 | #include <linux/cpufreq.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
| 21 | #include <linux/cpu_cooling.h> | ||
| 22 | #include <linux/cpu.h> | ||
| 21 | 23 | ||
| 22 | #include "exynos-cpufreq.h" | 24 | #include "exynos-cpufreq.h" |
| 23 | 25 | ||
| 24 | static struct exynos_dvfs_info *exynos_info; | 26 | static struct exynos_dvfs_info *exynos_info; |
| 27 | static struct thermal_cooling_device *cdev; | ||
| 25 | static struct regulator *arm_regulator; | 28 | static struct regulator *arm_regulator; |
| 26 | static unsigned int locking_frequency; | 29 | static unsigned int locking_frequency; |
| 27 | 30 | ||
| @@ -156,6 +159,7 @@ static struct cpufreq_driver exynos_driver = { | |||
| 156 | 159 | ||
| 157 | static int exynos_cpufreq_probe(struct platform_device *pdev) | 160 | static int exynos_cpufreq_probe(struct platform_device *pdev) |
| 158 | { | 161 | { |
| 162 | struct device_node *cpus, *np; | ||
| 159 | int ret = -EINVAL; | 163 | int ret = -EINVAL; |
| 160 | 164 | ||
| 161 | exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL); | 165 | exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL); |
| @@ -198,9 +202,36 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) | |||
| 198 | /* Done here as we want to capture boot frequency */ | 202 | /* Done here as we want to capture boot frequency */ |
| 199 | locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000; | 203 | locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000; |
| 200 | 204 | ||
| 201 | if (!cpufreq_register_driver(&exynos_driver)) | 205 | ret = cpufreq_register_driver(&exynos_driver); |
| 206 | if (ret) | ||
| 207 | goto err_cpufreq_reg; | ||
| 208 | |||
| 209 | cpus = of_find_node_by_path("/cpus"); | ||
| 210 | if (!cpus) { | ||
| 211 | pr_err("failed to find cpus node\n"); | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | np = of_get_next_child(cpus, NULL); | ||
| 216 | if (!np) { | ||
| 217 | pr_err("failed to find cpus child node\n"); | ||
| 218 | of_node_put(cpus); | ||
| 202 | return 0; | 219 | return 0; |
| 220 | } | ||
| 221 | |||
| 222 | if (of_find_property(np, "#cooling-cells", NULL)) { | ||
| 223 | cdev = of_cpufreq_cooling_register(np, | ||
| 224 | cpu_present_mask); | ||
| 225 | if (IS_ERR(cdev)) | ||
| 226 | pr_err("running cpufreq without cooling device: %ld\n", | ||
| 227 | PTR_ERR(cdev)); | ||
| 228 | } | ||
| 229 | of_node_put(np); | ||
| 230 | of_node_put(cpus); | ||
| 231 | |||
| 232 | return 0; | ||
| 203 | 233 | ||
| 234 | err_cpufreq_reg: | ||
| 204 | dev_err(&pdev->dev, "failed to register cpufreq driver\n"); | 235 | dev_err(&pdev->dev, "failed to register cpufreq driver\n"); |
| 205 | regulator_put(arm_regulator); | 236 | regulator_put(arm_regulator); |
| 206 | err_vdd_arm: | 237 | err_vdd_arm: |
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index d717f3dab6f1..668fb1bdea9e 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c | |||
| @@ -497,6 +497,9 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, | |||
| 497 | if (sensor_specs.np == sensor_np && id == sensor_id) { | 497 | if (sensor_specs.np == sensor_np && id == sensor_id) { |
| 498 | tzd = thermal_zone_of_add_sensor(child, sensor_np, | 498 | tzd = thermal_zone_of_add_sensor(child, sensor_np, |
| 499 | data, ops); | 499 | data, ops); |
| 500 | if (!IS_ERR(tzd)) | ||
| 501 | tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED); | ||
| 502 | |||
| 500 | of_node_put(sensor_specs.np); | 503 | of_node_put(sensor_specs.np); |
| 501 | of_node_put(child); | 504 | of_node_put(child); |
| 502 | goto exit; | 505 | goto exit; |
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 9c6ce548e363..3aa46ac7cdbc 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c | |||
| @@ -193,19 +193,20 @@ static u32 rk_tsadcv2_temp_to_code(long temp) | |||
| 193 | 193 | ||
| 194 | static long rk_tsadcv2_code_to_temp(u32 code) | 194 | static long rk_tsadcv2_code_to_temp(u32 code) |
| 195 | { | 195 | { |
| 196 | int high, low, mid; | 196 | unsigned int low = 0; |
| 197 | 197 | unsigned int high = ARRAY_SIZE(v2_code_table) - 1; | |
| 198 | low = 0; | 198 | unsigned int mid = (low + high) / 2; |
| 199 | high = ARRAY_SIZE(v2_code_table) - 1; | 199 | unsigned int num; |
| 200 | mid = (high + low) / 2; | 200 | unsigned long denom; |
| 201 | 201 | ||
| 202 | if (code > v2_code_table[low].code || code < v2_code_table[high].code) | 202 | /* Invalid code, return -EAGAIN */ |
| 203 | return 125000; /* No code available, return max temperature */ | 203 | if (code > TSADCV2_DATA_MASK) |
| 204 | return -EAGAIN; | ||
| 204 | 205 | ||
| 205 | while (low <= high) { | 206 | while (low <= high && mid) { |
| 206 | if (code >= v2_code_table[mid].code && code < | 207 | if (code >= v2_code_table[mid].code && |
| 207 | v2_code_table[mid - 1].code) | 208 | code < v2_code_table[mid - 1].code) |
| 208 | return v2_code_table[mid].temp; | 209 | break; |
| 209 | else if (code < v2_code_table[mid].code) | 210 | else if (code < v2_code_table[mid].code) |
| 210 | low = mid + 1; | 211 | low = mid + 1; |
| 211 | else | 212 | else |
| @@ -213,7 +214,16 @@ static long rk_tsadcv2_code_to_temp(u32 code) | |||
| 213 | mid = (low + high) / 2; | 214 | mid = (low + high) / 2; |
| 214 | } | 215 | } |
| 215 | 216 | ||
| 216 | return 125000; | 217 | /* |
| 218 | * The 5C granularity provided by the table is too much. Let's | ||
| 219 | * assume that the relationship between sensor readings and | ||
| 220 | * temperature between 2 table entries is linear and interpolate | ||
| 221 | * to produce less granular result. | ||
| 222 | */ | ||
| 223 | num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp; | ||
| 224 | num *= v2_code_table[mid - 1].code - code; | ||
| 225 | denom = v2_code_table[mid - 1].code - v2_code_table[mid].code; | ||
| 226 | return v2_code_table[mid - 1].temp + (num / denom); | ||
| 217 | } | 227 | } |
| 218 | 228 | ||
| 219 | /** | 229 | /** |
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index c43306ecc0ab..c8e35c1a43dc 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig | |||
| @@ -7,12 +7,3 @@ config EXYNOS_THERMAL | |||
| 7 | the TMU, reports temperature and handles cooling action if defined. | 7 | the TMU, reports temperature and handles cooling action if defined. |
| 8 | This driver uses the Exynos core thermal APIs and TMU configuration | 8 | This driver uses the Exynos core thermal APIs and TMU configuration |
| 9 | data from the supported SoCs. | 9 | data from the supported SoCs. |
| 10 | |||
| 11 | config EXYNOS_THERMAL_CORE | ||
| 12 | bool "Core thermal framework support for EXYNOS SOCs" | ||
| 13 | depends on EXYNOS_THERMAL | ||
| 14 | help | ||
| 15 | If you say yes here you get support for EXYNOS TMU | ||
| 16 | (Thermal Management Unit) common registration/unregistration | ||
| 17 | functions to the core thermal layer and also to use the generic | ||
| 18 | CPU cooling APIs. | ||
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile index c09d83095dc2..1e47d0d89ce0 100644 --- a/drivers/thermal/samsung/Makefile +++ b/drivers/thermal/samsung/Makefile | |||
| @@ -3,5 +3,3 @@ | |||
| 3 | # | 3 | # |
| 4 | obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o | 4 | obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o |
| 5 | exynos_thermal-y := exynos_tmu.o | 5 | exynos_thermal-y := exynos_tmu.o |
| 6 | exynos_thermal-y += exynos_tmu_data.o | ||
| 7 | exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o | ||
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c deleted file mode 100644 index 6dc3815cc73f..000000000000 --- a/drivers/thermal/samsung/exynos_thermal_common.c +++ /dev/null | |||
| @@ -1,427 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * exynos_thermal_common.c - Samsung EXYNOS common thermal file | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Samsung Electronics | ||
| 5 | * Amit Daniel Kachhap <amit.daniel@samsung.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/cpu_cooling.h> | ||
| 24 | #include <linux/err.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/thermal.h> | ||
| 27 | |||
| 28 | #include "exynos_thermal_common.h" | ||
| 29 | |||
| 30 | struct exynos_thermal_zone { | ||
| 31 | enum thermal_device_mode mode; | ||
| 32 | struct thermal_zone_device *therm_dev; | ||
| 33 | struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE]; | ||
| 34 | unsigned int cool_dev_size; | ||
| 35 | struct platform_device *exynos4_dev; | ||
| 36 | struct thermal_sensor_conf *sensor_conf; | ||
| 37 | bool bind; | ||
| 38 | }; | ||
| 39 | |||
| 40 | /* Get mode callback functions for thermal zone */ | ||
| 41 | static int exynos_get_mode(struct thermal_zone_device *thermal, | ||
| 42 | enum thermal_device_mode *mode) | ||
| 43 | { | ||
| 44 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 45 | if (th_zone) | ||
| 46 | *mode = th_zone->mode; | ||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* Set mode callback functions for thermal zone */ | ||
| 51 | static int exynos_set_mode(struct thermal_zone_device *thermal, | ||
| 52 | enum thermal_device_mode mode) | ||
| 53 | { | ||
| 54 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 55 | if (!th_zone) { | ||
| 56 | dev_err(&thermal->device, | ||
| 57 | "thermal zone not registered\n"); | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | mutex_lock(&thermal->lock); | ||
| 62 | |||
| 63 | if (mode == THERMAL_DEVICE_ENABLED && | ||
| 64 | !th_zone->sensor_conf->trip_data.trigger_falling) | ||
| 65 | thermal->polling_delay = IDLE_INTERVAL; | ||
| 66 | else | ||
| 67 | thermal->polling_delay = 0; | ||
| 68 | |||
| 69 | mutex_unlock(&thermal->lock); | ||
| 70 | |||
| 71 | th_zone->mode = mode; | ||
| 72 | thermal_zone_device_update(thermal); | ||
| 73 | dev_dbg(th_zone->sensor_conf->dev, | ||
| 74 | "thermal polling set for duration=%d msec\n", | ||
| 75 | thermal->polling_delay); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | /* Get trip type callback functions for thermal zone */ | ||
| 81 | static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip, | ||
| 82 | enum thermal_trip_type *type) | ||
| 83 | { | ||
| 84 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 85 | int max_trip = th_zone->sensor_conf->trip_data.trip_count; | ||
| 86 | int trip_type; | ||
| 87 | |||
| 88 | if (trip < 0 || trip >= max_trip) | ||
| 89 | return -EINVAL; | ||
| 90 | |||
| 91 | trip_type = th_zone->sensor_conf->trip_data.trip_type[trip]; | ||
| 92 | |||
| 93 | if (trip_type == SW_TRIP) | ||
| 94 | *type = THERMAL_TRIP_CRITICAL; | ||
| 95 | else if (trip_type == THROTTLE_ACTIVE) | ||
| 96 | *type = THERMAL_TRIP_ACTIVE; | ||
| 97 | else if (trip_type == THROTTLE_PASSIVE) | ||
| 98 | *type = THERMAL_TRIP_PASSIVE; | ||
| 99 | else | ||
| 100 | return -EINVAL; | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* Get trip temperature callback functions for thermal zone */ | ||
| 106 | static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip, | ||
| 107 | unsigned long *temp) | ||
| 108 | { | ||
| 109 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 110 | int max_trip = th_zone->sensor_conf->trip_data.trip_count; | ||
| 111 | |||
| 112 | if (trip < 0 || trip >= max_trip) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | *temp = th_zone->sensor_conf->trip_data.trip_val[trip]; | ||
| 116 | /* convert the temperature into millicelsius */ | ||
| 117 | *temp = *temp * MCELSIUS; | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Get critical temperature callback functions for thermal zone */ | ||
| 123 | static int exynos_get_crit_temp(struct thermal_zone_device *thermal, | ||
| 124 | unsigned long *temp) | ||
| 125 | { | ||
| 126 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 127 | int max_trip = th_zone->sensor_conf->trip_data.trip_count; | ||
| 128 | /* Get the temp of highest trip*/ | ||
| 129 | return exynos_get_trip_temp(thermal, max_trip - 1, temp); | ||
| 130 | } | ||
| 131 | |||
| 132 | /* Bind callback functions for thermal zone */ | ||
| 133 | static int exynos_bind(struct thermal_zone_device *thermal, | ||
| 134 | struct thermal_cooling_device *cdev) | ||
| 135 | { | ||
| 136 | int ret = 0, i, tab_size, level; | ||
| 137 | struct freq_clip_table *tab_ptr, *clip_data; | ||
| 138 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 139 | struct thermal_sensor_conf *data = th_zone->sensor_conf; | ||
| 140 | |||
| 141 | tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data; | ||
| 142 | tab_size = data->cooling_data.freq_clip_count; | ||
| 143 | |||
| 144 | if (tab_ptr == NULL || tab_size == 0) | ||
| 145 | return 0; | ||
| 146 | |||
| 147 | /* find the cooling device registered*/ | ||
| 148 | for (i = 0; i < th_zone->cool_dev_size; i++) | ||
| 149 | if (cdev == th_zone->cool_dev[i]) | ||
| 150 | break; | ||
| 151 | |||
| 152 | /* No matching cooling device */ | ||
| 153 | if (i == th_zone->cool_dev_size) | ||
| 154 | return 0; | ||
| 155 | |||
| 156 | /* Bind the thermal zone to the cpufreq cooling device */ | ||
| 157 | for (i = 0; i < tab_size; i++) { | ||
| 158 | clip_data = (struct freq_clip_table *)&(tab_ptr[i]); | ||
| 159 | level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max); | ||
| 160 | if (level == THERMAL_CSTATE_INVALID) | ||
| 161 | return 0; | ||
| 162 | switch (GET_ZONE(i)) { | ||
| 163 | case MONITOR_ZONE: | ||
| 164 | case WARN_ZONE: | ||
| 165 | if (thermal_zone_bind_cooling_device(thermal, i, cdev, | ||
| 166 | level, 0)) { | ||
| 167 | dev_err(data->dev, | ||
| 168 | "error unbinding cdev inst=%d\n", i); | ||
| 169 | ret = -EINVAL; | ||
| 170 | } | ||
| 171 | th_zone->bind = true; | ||
| 172 | break; | ||
| 173 | default: | ||
| 174 | ret = -EINVAL; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | return ret; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Unbind callback functions for thermal zone */ | ||
| 182 | static int exynos_unbind(struct thermal_zone_device *thermal, | ||
| 183 | struct thermal_cooling_device *cdev) | ||
| 184 | { | ||
| 185 | int ret = 0, i, tab_size; | ||
| 186 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 187 | struct thermal_sensor_conf *data = th_zone->sensor_conf; | ||
| 188 | |||
| 189 | if (th_zone->bind == false) | ||
| 190 | return 0; | ||
| 191 | |||
| 192 | tab_size = data->cooling_data.freq_clip_count; | ||
| 193 | |||
| 194 | if (tab_size == 0) | ||
| 195 | return 0; | ||
| 196 | |||
| 197 | /* find the cooling device registered*/ | ||
| 198 | for (i = 0; i < th_zone->cool_dev_size; i++) | ||
| 199 | if (cdev == th_zone->cool_dev[i]) | ||
| 200 | break; | ||
| 201 | |||
| 202 | /* No matching cooling device */ | ||
| 203 | if (i == th_zone->cool_dev_size) | ||
| 204 | return 0; | ||
| 205 | |||
| 206 | /* Bind the thermal zone to the cpufreq cooling device */ | ||
| 207 | for (i = 0; i < tab_size; i++) { | ||
| 208 | switch (GET_ZONE(i)) { | ||
| 209 | case MONITOR_ZONE: | ||
| 210 | case WARN_ZONE: | ||
| 211 | if (thermal_zone_unbind_cooling_device(thermal, i, | ||
| 212 | cdev)) { | ||
| 213 | dev_err(data->dev, | ||
| 214 | "error unbinding cdev inst=%d\n", i); | ||
| 215 | ret = -EINVAL; | ||
| 216 | } | ||
| 217 | th_zone->bind = false; | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | ret = -EINVAL; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* Get temperature callback functions for thermal zone */ | ||
| 227 | static int exynos_get_temp(struct thermal_zone_device *thermal, | ||
| 228 | unsigned long *temp) | ||
| 229 | { | ||
| 230 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 231 | void *data; | ||
| 232 | |||
| 233 | if (!th_zone->sensor_conf) { | ||
| 234 | dev_err(&thermal->device, | ||
| 235 | "Temperature sensor not initialised\n"); | ||
| 236 | return -EINVAL; | ||
| 237 | } | ||
| 238 | data = th_zone->sensor_conf->driver_data; | ||
| 239 | *temp = th_zone->sensor_conf->read_temperature(data); | ||
| 240 | /* convert the temperature into millicelsius */ | ||
| 241 | *temp = *temp * MCELSIUS; | ||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Get temperature callback functions for thermal zone */ | ||
| 246 | static int exynos_set_emul_temp(struct thermal_zone_device *thermal, | ||
| 247 | unsigned long temp) | ||
| 248 | { | ||
| 249 | void *data; | ||
| 250 | int ret = -EINVAL; | ||
| 251 | struct exynos_thermal_zone *th_zone = thermal->devdata; | ||
| 252 | |||
| 253 | if (!th_zone->sensor_conf) { | ||
| 254 | dev_err(&thermal->device, | ||
| 255 | "Temperature sensor not initialised\n"); | ||
| 256 | return -EINVAL; | ||
| 257 | } | ||
| 258 | data = th_zone->sensor_conf->driver_data; | ||
| 259 | if (th_zone->sensor_conf->write_emul_temp) | ||
| 260 | ret = th_zone->sensor_conf->write_emul_temp(data, temp); | ||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | |||
| 264 | /* Get the temperature trend */ | ||
| 265 | static int exynos_get_trend(struct thermal_zone_device *thermal, | ||
| 266 | int trip, enum thermal_trend *trend) | ||
| 267 | { | ||
| 268 | int ret; | ||
| 269 | unsigned long trip_temp; | ||
| 270 | |||
| 271 | ret = exynos_get_trip_temp(thermal, trip, &trip_temp); | ||
| 272 | if (ret < 0) | ||
| 273 | return ret; | ||
| 274 | |||
| 275 | if (thermal->temperature >= trip_temp) | ||
| 276 | *trend = THERMAL_TREND_RAISE_FULL; | ||
| 277 | else | ||
| 278 | *trend = THERMAL_TREND_DROP_FULL; | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | /* Operation callback functions for thermal zone */ | ||
| 283 | static struct thermal_zone_device_ops exynos_dev_ops = { | ||
| 284 | .bind = exynos_bind, | ||
| 285 | .unbind = exynos_unbind, | ||
| 286 | .get_temp = exynos_get_temp, | ||
| 287 | .set_emul_temp = exynos_set_emul_temp, | ||
| 288 | .get_trend = exynos_get_trend, | ||
| 289 | .get_mode = exynos_get_mode, | ||
| 290 | .set_mode = exynos_set_mode, | ||
| 291 | .get_trip_type = exynos_get_trip_type, | ||
| 292 | .get_trip_temp = exynos_get_trip_temp, | ||
| 293 | .get_crit_temp = exynos_get_crit_temp, | ||
| 294 | }; | ||
| 295 | |||
| 296 | /* | ||
| 297 | * This function may be called from interrupt based temperature sensor | ||
| 298 | * when threshold is changed. | ||
| 299 | */ | ||
| 300 | void exynos_report_trigger(struct thermal_sensor_conf *conf) | ||
| 301 | { | ||
| 302 | unsigned int i; | ||
| 303 | char data[10]; | ||
| 304 | char *envp[] = { data, NULL }; | ||
| 305 | struct exynos_thermal_zone *th_zone; | ||
| 306 | |||
| 307 | if (!conf || !conf->pzone_data) { | ||
| 308 | pr_err("Invalid temperature sensor configuration data\n"); | ||
| 309 | return; | ||
| 310 | } | ||
| 311 | |||
| 312 | th_zone = conf->pzone_data; | ||
| 313 | |||
| 314 | if (th_zone->bind == false) { | ||
| 315 | for (i = 0; i < th_zone->cool_dev_size; i++) { | ||
| 316 | if (!th_zone->cool_dev[i]) | ||
| 317 | continue; | ||
| 318 | exynos_bind(th_zone->therm_dev, | ||
| 319 | th_zone->cool_dev[i]); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | thermal_zone_device_update(th_zone->therm_dev); | ||
| 324 | |||
| 325 | mutex_lock(&th_zone->therm_dev->lock); | ||
| 326 | /* Find the level for which trip happened */ | ||
| 327 | for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) { | ||
| 328 | if (th_zone->therm_dev->last_temperature < | ||
| 329 | th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS) | ||
| 330 | break; | ||
| 331 | } | ||
| 332 | |||
| 333 | if (th_zone->mode == THERMAL_DEVICE_ENABLED && | ||
| 334 | !th_zone->sensor_conf->trip_data.trigger_falling) { | ||
| 335 | if (i > 0) | ||
| 336 | th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL; | ||
| 337 | else | ||
| 338 | th_zone->therm_dev->polling_delay = IDLE_INTERVAL; | ||
| 339 | } | ||
| 340 | |||
| 341 | snprintf(data, sizeof(data), "%u", i); | ||
| 342 | kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp); | ||
| 343 | mutex_unlock(&th_zone->therm_dev->lock); | ||
| 344 | } | ||
| 345 | |||
| 346 | /* Register with the in-kernel thermal management */ | ||
| 347 | int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) | ||
| 348 | { | ||
| 349 | int ret; | ||
| 350 | struct exynos_thermal_zone *th_zone; | ||
| 351 | |||
| 352 | if (!sensor_conf || !sensor_conf->read_temperature) { | ||
| 353 | pr_err("Temperature sensor not initialised\n"); | ||
| 354 | return -EINVAL; | ||
| 355 | } | ||
| 356 | |||
| 357 | th_zone = devm_kzalloc(sensor_conf->dev, | ||
| 358 | sizeof(struct exynos_thermal_zone), GFP_KERNEL); | ||
| 359 | if (!th_zone) | ||
| 360 | return -ENOMEM; | ||
| 361 | |||
| 362 | th_zone->sensor_conf = sensor_conf; | ||
| 363 | /* | ||
| 364 | * TODO: 1) Handle multiple cooling devices in a thermal zone | ||
| 365 | * 2) Add a flag/name in cooling info to map to specific | ||
| 366 | * sensor | ||
| 367 | */ | ||
| 368 | if (sensor_conf->cooling_data.freq_clip_count > 0) { | ||
| 369 | th_zone->cool_dev[th_zone->cool_dev_size] = | ||
| 370 | cpufreq_cooling_register(cpu_present_mask); | ||
| 371 | if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) { | ||
| 372 | ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]); | ||
| 373 | if (ret != -EPROBE_DEFER) | ||
| 374 | dev_err(sensor_conf->dev, | ||
| 375 | "Failed to register cpufreq cooling device: %d\n", | ||
| 376 | ret); | ||
| 377 | goto err_unregister; | ||
| 378 | } | ||
| 379 | th_zone->cool_dev_size++; | ||
| 380 | } | ||
| 381 | |||
| 382 | th_zone->therm_dev = thermal_zone_device_register( | ||
| 383 | sensor_conf->name, sensor_conf->trip_data.trip_count, | ||
| 384 | 0, th_zone, &exynos_dev_ops, NULL, 0, | ||
| 385 | sensor_conf->trip_data.trigger_falling ? 0 : | ||
| 386 | IDLE_INTERVAL); | ||
| 387 | |||
| 388 | if (IS_ERR(th_zone->therm_dev)) { | ||
| 389 | dev_err(sensor_conf->dev, | ||
| 390 | "Failed to register thermal zone device\n"); | ||
| 391 | ret = PTR_ERR(th_zone->therm_dev); | ||
| 392 | goto err_unregister; | ||
| 393 | } | ||
| 394 | th_zone->mode = THERMAL_DEVICE_ENABLED; | ||
| 395 | sensor_conf->pzone_data = th_zone; | ||
| 396 | |||
| 397 | dev_info(sensor_conf->dev, | ||
| 398 | "Exynos: Thermal zone(%s) registered\n", sensor_conf->name); | ||
| 399 | |||
| 400 | return 0; | ||
| 401 | |||
| 402 | err_unregister: | ||
| 403 | exynos_unregister_thermal(sensor_conf); | ||
| 404 | return ret; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* Un-Register with the in-kernel thermal management */ | ||
| 408 | void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) | ||
| 409 | { | ||
| 410 | int i; | ||
| 411 | struct exynos_thermal_zone *th_zone; | ||
| 412 | |||
| 413 | if (!sensor_conf || !sensor_conf->pzone_data) { | ||
| 414 | pr_err("Invalid temperature sensor configuration data\n"); | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | |||
| 418 | th_zone = sensor_conf->pzone_data; | ||
| 419 | |||
| 420 | thermal_zone_device_unregister(th_zone->therm_dev); | ||
| 421 | |||
| 422 | for (i = 0; i < th_zone->cool_dev_size; ++i) | ||
| 423 | cpufreq_cooling_unregister(th_zone->cool_dev[i]); | ||
| 424 | |||
| 425 | dev_info(sensor_conf->dev, | ||
| 426 | "Exynos: Kernel Thermal management unregistered\n"); | ||
| 427 | } | ||
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h deleted file mode 100644 index cd4471925cdd..000000000000 --- a/drivers/thermal/samsung/exynos_thermal_common.h +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * exynos_thermal_common.h - Samsung EXYNOS common header file | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Samsung Electronics | ||
| 5 | * Amit Daniel Kachhap <amit.daniel@samsung.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef _EXYNOS_THERMAL_COMMON_H | ||
| 24 | #define _EXYNOS_THERMAL_COMMON_H | ||
| 25 | |||
| 26 | /* In-kernel thermal framework related macros & definations */ | ||
| 27 | #define SENSOR_NAME_LEN 16 | ||
| 28 | #define MAX_TRIP_COUNT 8 | ||
| 29 | #define MAX_COOLING_DEVICE 4 | ||
| 30 | |||
| 31 | #define ACTIVE_INTERVAL 500 | ||
| 32 | #define IDLE_INTERVAL 10000 | ||
| 33 | #define MCELSIUS 1000 | ||
| 34 | |||
| 35 | /* CPU Zone information */ | ||
| 36 | #define PANIC_ZONE 4 | ||
| 37 | #define WARN_ZONE 3 | ||
| 38 | #define MONITOR_ZONE 2 | ||
| 39 | #define SAFE_ZONE 1 | ||
| 40 | |||
| 41 | #define GET_ZONE(trip) (trip + 2) | ||
| 42 | #define GET_TRIP(zone) (zone - 2) | ||
| 43 | |||
| 44 | enum trigger_type { | ||
| 45 | THROTTLE_ACTIVE = 1, | ||
| 46 | THROTTLE_PASSIVE, | ||
| 47 | SW_TRIP, | ||
| 48 | HW_TRIP, | ||
| 49 | }; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * struct freq_clip_table | ||
| 53 | * @freq_clip_max: maximum frequency allowed for this cooling state. | ||
| 54 | * @temp_level: Temperature level at which the temperature clipping will | ||
| 55 | * happen. | ||
| 56 | * @mask_val: cpumask of the allowed cpu's where the clipping will take place. | ||
| 57 | * | ||
| 58 | * This structure is required to be filled and passed to the | ||
| 59 | * cpufreq_cooling_unregister function. | ||
| 60 | */ | ||
| 61 | struct freq_clip_table { | ||
| 62 | unsigned int freq_clip_max; | ||
| 63 | unsigned int temp_level; | ||
| 64 | const struct cpumask *mask_val; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct thermal_trip_point_conf { | ||
| 68 | int trip_val[MAX_TRIP_COUNT]; | ||
| 69 | int trip_type[MAX_TRIP_COUNT]; | ||
| 70 | int trip_count; | ||
| 71 | unsigned char trigger_falling; | ||
| 72 | }; | ||
| 73 | |||
| 74 | struct thermal_cooling_conf { | ||
| 75 | struct freq_clip_table freq_data[MAX_TRIP_COUNT]; | ||
| 76 | int freq_clip_count; | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct thermal_sensor_conf { | ||
| 80 | char name[SENSOR_NAME_LEN]; | ||
| 81 | int (*read_temperature)(void *data); | ||
| 82 | int (*write_emul_temp)(void *drv_data, unsigned long temp); | ||
| 83 | struct thermal_trip_point_conf trip_data; | ||
| 84 | struct thermal_cooling_conf cooling_data; | ||
| 85 | void *driver_data; | ||
| 86 | void *pzone_data; | ||
| 87 | struct device *dev; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /*Functions used exynos based thermal sensor driver*/ | ||
| 91 | #ifdef CONFIG_EXYNOS_THERMAL_CORE | ||
| 92 | void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf); | ||
| 93 | int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf); | ||
| 94 | void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf); | ||
| 95 | #else | ||
| 96 | static inline void | ||
| 97 | exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; } | ||
| 98 | |||
| 99 | static inline int | ||
| 100 | exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; } | ||
| 101 | |||
| 102 | static inline void | ||
| 103 | exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; } | ||
| 104 | |||
| 105 | #endif /* CONFIG_EXYNOS_THERMAL_CORE */ | ||
| 106 | #endif /* _EXYNOS_THERMAL_COMMON_H */ | ||
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index d2f1e62a4232..fbeedc072cc2 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit) | 2 | * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit) |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2014 Samsung Electronics | ||
| 5 | * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> | ||
| 6 | * Lukasz Majewski <l.majewski@samsung.com> | ||
| 7 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics | 8 | * Copyright (C) 2011 Samsung Electronics |
| 5 | * Donggeun Kim <dg77.kim@samsung.com> | 9 | * Donggeun Kim <dg77.kim@samsung.com> |
| 6 | * Amit Daniel Kachhap <amit.kachhap@linaro.org> | 10 | * Amit Daniel Kachhap <amit.kachhap@linaro.org> |
| @@ -31,8 +35,8 @@ | |||
| 31 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
| 32 | #include <linux/regulator/consumer.h> | 36 | #include <linux/regulator/consumer.h> |
| 33 | 37 | ||
| 34 | #include "exynos_thermal_common.h" | ||
| 35 | #include "exynos_tmu.h" | 38 | #include "exynos_tmu.h" |
| 39 | #include "../thermal_core.h" | ||
| 36 | 40 | ||
| 37 | /* Exynos generic registers */ | 41 | /* Exynos generic registers */ |
| 38 | #define EXYNOS_TMU_REG_TRIMINFO 0x0 | 42 | #define EXYNOS_TMU_REG_TRIMINFO 0x0 |
| @@ -115,6 +119,27 @@ | |||
| 115 | #define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 | 119 | #define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 |
| 116 | #define EXYNOS5440_EFUSE_SWAP_OFFSET 8 | 120 | #define EXYNOS5440_EFUSE_SWAP_OFFSET 8 |
| 117 | 121 | ||
| 122 | /* Exynos7 specific registers */ | ||
| 123 | #define EXYNOS7_THD_TEMP_RISE7_6 0x50 | ||
| 124 | #define EXYNOS7_THD_TEMP_FALL7_6 0x60 | ||
| 125 | #define EXYNOS7_TMU_REG_INTEN 0x110 | ||
| 126 | #define EXYNOS7_TMU_REG_INTPEND 0x118 | ||
| 127 | #define EXYNOS7_TMU_REG_EMUL_CON 0x160 | ||
| 128 | |||
| 129 | #define EXYNOS7_TMU_TEMP_MASK 0x1ff | ||
| 130 | #define EXYNOS7_PD_DET_EN_SHIFT 23 | ||
| 131 | #define EXYNOS7_TMU_INTEN_RISE0_SHIFT 0 | ||
| 132 | #define EXYNOS7_TMU_INTEN_RISE1_SHIFT 1 | ||
| 133 | #define EXYNOS7_TMU_INTEN_RISE2_SHIFT 2 | ||
| 134 | #define EXYNOS7_TMU_INTEN_RISE3_SHIFT 3 | ||
| 135 | #define EXYNOS7_TMU_INTEN_RISE4_SHIFT 4 | ||
| 136 | #define EXYNOS7_TMU_INTEN_RISE5_SHIFT 5 | ||
| 137 | #define EXYNOS7_TMU_INTEN_RISE6_SHIFT 6 | ||
| 138 | #define EXYNOS7_TMU_INTEN_RISE7_SHIFT 7 | ||
| 139 | #define EXYNOS7_EMUL_DATA_SHIFT 7 | ||
| 140 | #define EXYNOS7_EMUL_DATA_MASK 0x1ff | ||
| 141 | |||
| 142 | #define MCELSIUS 1000 | ||
| 118 | /** | 143 | /** |
| 119 | * struct exynos_tmu_data : A structure to hold the private data of the TMU | 144 | * struct exynos_tmu_data : A structure to hold the private data of the TMU |
| 120 | driver | 145 | driver |
| @@ -128,6 +153,7 @@ | |||
| 128 | * @lock: lock to implement synchronization. | 153 | * @lock: lock to implement synchronization. |
| 129 | * @clk: pointer to the clock structure. | 154 | * @clk: pointer to the clock structure. |
| 130 | * @clk_sec: pointer to the clock structure for accessing the base_second. | 155 | * @clk_sec: pointer to the clock structure for accessing the base_second. |
| 156 | * @sclk: pointer to the clock structure for accessing the tmu special clk. | ||
| 131 | * @temp_error1: fused value of the first point trim. | 157 | * @temp_error1: fused value of the first point trim. |
| 132 | * @temp_error2: fused value of the second point trim. | 158 | * @temp_error2: fused value of the second point trim. |
| 133 | * @regulator: pointer to the TMU regulator structure. | 159 | * @regulator: pointer to the TMU regulator structure. |
| @@ -147,10 +173,11 @@ struct exynos_tmu_data { | |||
| 147 | enum soc_type soc; | 173 | enum soc_type soc; |
| 148 | struct work_struct irq_work; | 174 | struct work_struct irq_work; |
| 149 | struct mutex lock; | 175 | struct mutex lock; |
| 150 | struct clk *clk, *clk_sec; | 176 | struct clk *clk, *clk_sec, *sclk; |
| 151 | u8 temp_error1, temp_error2; | 177 | u16 temp_error1, temp_error2; |
| 152 | struct regulator *regulator; | 178 | struct regulator *regulator; |
| 153 | struct thermal_sensor_conf *reg_conf; | 179 | struct thermal_zone_device *tzd; |
| 180 | |||
| 154 | int (*tmu_initialize)(struct platform_device *pdev); | 181 | int (*tmu_initialize)(struct platform_device *pdev); |
| 155 | void (*tmu_control)(struct platform_device *pdev, bool on); | 182 | void (*tmu_control)(struct platform_device *pdev, bool on); |
| 156 | int (*tmu_read)(struct exynos_tmu_data *data); | 183 | int (*tmu_read)(struct exynos_tmu_data *data); |
| @@ -159,6 +186,33 @@ struct exynos_tmu_data { | |||
| 159 | void (*tmu_clear_irqs)(struct exynos_tmu_data *data); | 186 | void (*tmu_clear_irqs)(struct exynos_tmu_data *data); |
| 160 | }; | 187 | }; |
| 161 | 188 | ||
| 189 | static void exynos_report_trigger(struct exynos_tmu_data *p) | ||
| 190 | { | ||
| 191 | char data[10], *envp[] = { data, NULL }; | ||
| 192 | struct thermal_zone_device *tz = p->tzd; | ||
| 193 | unsigned long temp; | ||
| 194 | unsigned int i; | ||
| 195 | |||
| 196 | if (!tz) { | ||
| 197 | pr_err("No thermal zone device defined\n"); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | thermal_zone_device_update(tz); | ||
| 202 | |||
| 203 | mutex_lock(&tz->lock); | ||
| 204 | /* Find the level for which trip happened */ | ||
| 205 | for (i = 0; i < of_thermal_get_ntrips(tz); i++) { | ||
| 206 | tz->ops->get_trip_temp(tz, i, &temp); | ||
| 207 | if (tz->last_temperature < temp) | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | |||
| 211 | snprintf(data, sizeof(data), "%u", i); | ||
| 212 | kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp); | ||
| 213 | mutex_unlock(&tz->lock); | ||
| 214 | } | ||
| 215 | |||
| 162 | /* | 216 | /* |
| 163 | * TMU treats temperature as a mapped temperature code. | 217 | * TMU treats temperature as a mapped temperature code. |
| 164 | * The temperature is converted differently depending on the calibration type. | 218 | * The temperature is converted differently depending on the calibration type. |
| @@ -190,7 +244,7 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp) | |||
| 190 | * Calculate a temperature value from a temperature code. | 244 | * Calculate a temperature value from a temperature code. |
| 191 | * The unit of the temperature is degree Celsius. | 245 | * The unit of the temperature is degree Celsius. |
| 192 | */ | 246 | */ |
| 193 | static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code) | 247 | static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code) |
| 194 | { | 248 | { |
| 195 | struct exynos_tmu_platform_data *pdata = data->pdata; | 249 | struct exynos_tmu_platform_data *pdata = data->pdata; |
| 196 | int temp; | 250 | int temp; |
| @@ -234,14 +288,25 @@ static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) | |||
| 234 | 288 | ||
| 235 | static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling) | 289 | static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling) |
| 236 | { | 290 | { |
| 237 | struct exynos_tmu_platform_data *pdata = data->pdata; | 291 | struct thermal_zone_device *tz = data->tzd; |
| 292 | const struct thermal_trip * const trips = | ||
| 293 | of_thermal_get_trip_points(tz); | ||
| 294 | unsigned long temp; | ||
| 238 | int i; | 295 | int i; |
| 239 | 296 | ||
| 240 | for (i = 0; i < pdata->non_hw_trigger_levels; i++) { | 297 | if (!trips) { |
| 241 | u8 temp = pdata->trigger_levels[i]; | 298 | pr_err("%s: Cannot get trip points from of-thermal.c!\n", |
| 299 | __func__); | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | for (i = 0; i < of_thermal_get_ntrips(tz); i++) { | ||
| 304 | if (trips[i].type == THERMAL_TRIP_CRITICAL) | ||
| 305 | continue; | ||
| 242 | 306 | ||
| 307 | temp = trips[i].temperature / MCELSIUS; | ||
| 243 | if (falling) | 308 | if (falling) |
| 244 | temp -= pdata->threshold_falling; | 309 | temp -= (trips[i].hysteresis / MCELSIUS); |
| 245 | else | 310 | else |
| 246 | threshold &= ~(0xff << 8 * i); | 311 | threshold &= ~(0xff << 8 * i); |
| 247 | 312 | ||
| @@ -305,9 +370,19 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) | |||
| 305 | static int exynos4210_tmu_initialize(struct platform_device *pdev) | 370 | static int exynos4210_tmu_initialize(struct platform_device *pdev) |
| 306 | { | 371 | { |
| 307 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 372 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 308 | struct exynos_tmu_platform_data *pdata = data->pdata; | 373 | struct thermal_zone_device *tz = data->tzd; |
| 309 | unsigned int status; | 374 | const struct thermal_trip * const trips = |
| 375 | of_thermal_get_trip_points(tz); | ||
| 310 | int ret = 0, threshold_code, i; | 376 | int ret = 0, threshold_code, i; |
| 377 | unsigned long reference, temp; | ||
| 378 | unsigned int status; | ||
| 379 | |||
| 380 | if (!trips) { | ||
| 381 | pr_err("%s: Cannot get trip points from of-thermal.c!\n", | ||
| 382 | __func__); | ||
| 383 | ret = -ENODEV; | ||
| 384 | goto out; | ||
| 385 | } | ||
| 311 | 386 | ||
| 312 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); | 387 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); |
| 313 | if (!status) { | 388 | if (!status) { |
| @@ -318,12 +393,19 @@ static int exynos4210_tmu_initialize(struct platform_device *pdev) | |||
| 318 | sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO)); | 393 | sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO)); |
| 319 | 394 | ||
| 320 | /* Write temperature code for threshold */ | 395 | /* Write temperature code for threshold */ |
| 321 | threshold_code = temp_to_code(data, pdata->threshold); | 396 | reference = trips[0].temperature / MCELSIUS; |
| 397 | threshold_code = temp_to_code(data, reference); | ||
| 398 | if (threshold_code < 0) { | ||
| 399 | ret = threshold_code; | ||
| 400 | goto out; | ||
| 401 | } | ||
| 322 | writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); | 402 | writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); |
| 323 | 403 | ||
| 324 | for (i = 0; i < pdata->non_hw_trigger_levels; i++) | 404 | for (i = 0; i < of_thermal_get_ntrips(tz); i++) { |
| 325 | writeb(pdata->trigger_levels[i], data->base + | 405 | temp = trips[i].temperature / MCELSIUS; |
| 406 | writeb(temp - reference, data->base + | ||
| 326 | EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4); | 407 | EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4); |
| 408 | } | ||
| 327 | 409 | ||
| 328 | data->tmu_clear_irqs(data); | 410 | data->tmu_clear_irqs(data); |
| 329 | out: | 411 | out: |
| @@ -333,9 +415,11 @@ out: | |||
| 333 | static int exynos4412_tmu_initialize(struct platform_device *pdev) | 415 | static int exynos4412_tmu_initialize(struct platform_device *pdev) |
| 334 | { | 416 | { |
| 335 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 417 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 336 | struct exynos_tmu_platform_data *pdata = data->pdata; | 418 | const struct thermal_trip * const trips = |
| 419 | of_thermal_get_trip_points(data->tzd); | ||
| 337 | unsigned int status, trim_info, con, ctrl, rising_threshold; | 420 | unsigned int status, trim_info, con, ctrl, rising_threshold; |
| 338 | int ret = 0, threshold_code, i; | 421 | int ret = 0, threshold_code, i; |
| 422 | unsigned long crit_temp = 0; | ||
| 339 | 423 | ||
| 340 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); | 424 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); |
| 341 | if (!status) { | 425 | if (!status) { |
| @@ -373,17 +457,29 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev) | |||
| 373 | data->tmu_clear_irqs(data); | 457 | data->tmu_clear_irqs(data); |
| 374 | 458 | ||
| 375 | /* if last threshold limit is also present */ | 459 | /* if last threshold limit is also present */ |
| 376 | i = pdata->max_trigger_level - 1; | 460 | for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) { |
| 377 | if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) { | 461 | if (trips[i].type == THERMAL_TRIP_CRITICAL) { |
| 378 | threshold_code = temp_to_code(data, pdata->trigger_levels[i]); | 462 | crit_temp = trips[i].temperature; |
| 379 | /* 1-4 level to be assigned in th0 reg */ | 463 | break; |
| 380 | rising_threshold &= ~(0xff << 8 * i); | 464 | } |
| 381 | rising_threshold |= threshold_code << 8 * i; | ||
| 382 | writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); | ||
| 383 | con = readl(data->base + EXYNOS_TMU_REG_CONTROL); | ||
| 384 | con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); | ||
| 385 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); | ||
| 386 | } | 465 | } |
| 466 | |||
| 467 | if (i == of_thermal_get_ntrips(data->tzd)) { | ||
| 468 | pr_err("%s: No CRITICAL trip point defined at of-thermal.c!\n", | ||
| 469 | __func__); | ||
| 470 | ret = -EINVAL; | ||
| 471 | goto out; | ||
| 472 | } | ||
| 473 | |||
| 474 | threshold_code = temp_to_code(data, crit_temp / MCELSIUS); | ||
| 475 | /* 1-4 level to be assigned in th0 reg */ | ||
| 476 | rising_threshold &= ~(0xff << 8 * i); | ||
| 477 | rising_threshold |= threshold_code << 8 * i; | ||
| 478 | writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); | ||
| 479 | con = readl(data->base + EXYNOS_TMU_REG_CONTROL); | ||
| 480 | con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); | ||
| 481 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); | ||
| 482 | |||
| 387 | out: | 483 | out: |
| 388 | return ret; | 484 | return ret; |
| 389 | } | 485 | } |
| @@ -391,9 +487,9 @@ out: | |||
| 391 | static int exynos5440_tmu_initialize(struct platform_device *pdev) | 487 | static int exynos5440_tmu_initialize(struct platform_device *pdev) |
| 392 | { | 488 | { |
| 393 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 489 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 394 | struct exynos_tmu_platform_data *pdata = data->pdata; | ||
| 395 | unsigned int trim_info = 0, con, rising_threshold; | 490 | unsigned int trim_info = 0, con, rising_threshold; |
| 396 | int ret = 0, threshold_code, i; | 491 | int ret = 0, threshold_code; |
| 492 | unsigned long crit_temp = 0; | ||
| 397 | 493 | ||
| 398 | /* | 494 | /* |
| 399 | * For exynos5440 soc triminfo value is swapped between TMU0 and | 495 | * For exynos5440 soc triminfo value is swapped between TMU0 and |
| @@ -422,9 +518,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) | |||
| 422 | data->tmu_clear_irqs(data); | 518 | data->tmu_clear_irqs(data); |
| 423 | 519 | ||
| 424 | /* if last threshold limit is also present */ | 520 | /* if last threshold limit is also present */ |
| 425 | i = pdata->max_trigger_level - 1; | 521 | if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp)) { |
| 426 | if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) { | 522 | threshold_code = temp_to_code(data, crit_temp / MCELSIUS); |
| 427 | threshold_code = temp_to_code(data, pdata->trigger_levels[i]); | ||
| 428 | /* 5th level to be assigned in th2 reg */ | 523 | /* 5th level to be assigned in th2 reg */ |
| 429 | rising_threshold = | 524 | rising_threshold = |
| 430 | threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT; | 525 | threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT; |
| @@ -439,10 +534,88 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) | |||
| 439 | return ret; | 534 | return ret; |
| 440 | } | 535 | } |
| 441 | 536 | ||
| 442 | static void exynos4210_tmu_control(struct platform_device *pdev, bool on) | 537 | static int exynos7_tmu_initialize(struct platform_device *pdev) |
| 443 | { | 538 | { |
| 444 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 539 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 540 | struct thermal_zone_device *tz = data->tzd; | ||
| 445 | struct exynos_tmu_platform_data *pdata = data->pdata; | 541 | struct exynos_tmu_platform_data *pdata = data->pdata; |
| 542 | unsigned int status, trim_info; | ||
| 543 | unsigned int rising_threshold = 0, falling_threshold = 0; | ||
| 544 | int ret = 0, threshold_code, i; | ||
| 545 | unsigned long temp, temp_hist; | ||
| 546 | unsigned int reg_off, bit_off; | ||
| 547 | |||
| 548 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); | ||
| 549 | if (!status) { | ||
| 550 | ret = -EBUSY; | ||
| 551 | goto out; | ||
| 552 | } | ||
| 553 | |||
| 554 | trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); | ||
| 555 | |||
| 556 | data->temp_error1 = trim_info & EXYNOS7_TMU_TEMP_MASK; | ||
| 557 | if (!data->temp_error1 || | ||
| 558 | (pdata->min_efuse_value > data->temp_error1) || | ||
| 559 | (data->temp_error1 > pdata->max_efuse_value)) | ||
| 560 | data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK; | ||
| 561 | |||
| 562 | /* Write temperature code for rising and falling threshold */ | ||
| 563 | for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) { | ||
| 564 | /* | ||
| 565 | * On exynos7 there are 4 rising and 4 falling threshold | ||
| 566 | * registers (0x50-0x5c and 0x60-0x6c respectively). Each | ||
| 567 | * register holds the value of two threshold levels (at bit | ||
| 568 | * offsets 0 and 16). Based on the fact that there are atmost | ||
| 569 | * eight possible trigger levels, calculate the register and | ||
| 570 | * bit offsets where the threshold levels are to be written. | ||
| 571 | * | ||
| 572 | * e.g. EXYNOS7_THD_TEMP_RISE7_6 (0x50) | ||
| 573 | * [24:16] - Threshold level 7 | ||
| 574 | * [8:0] - Threshold level 6 | ||
| 575 | * e.g. EXYNOS7_THD_TEMP_RISE5_4 (0x54) | ||
| 576 | * [24:16] - Threshold level 5 | ||
| 577 | * [8:0] - Threshold level 4 | ||
| 578 | * | ||
| 579 | * and similarly for falling thresholds. | ||
| 580 | * | ||
| 581 | * Based on the above, calculate the register and bit offsets | ||
| 582 | * for rising/falling threshold levels and populate them. | ||
| 583 | */ | ||
| 584 | reg_off = ((7 - i) / 2) * 4; | ||
| 585 | bit_off = ((8 - i) % 2); | ||
| 586 | |||
| 587 | tz->ops->get_trip_temp(tz, i, &temp); | ||
| 588 | temp /= MCELSIUS; | ||
| 589 | |||
| 590 | tz->ops->get_trip_hyst(tz, i, &temp_hist); | ||
| 591 | temp_hist = temp - (temp_hist / MCELSIUS); | ||
| 592 | |||
| 593 | /* Set 9-bit temperature code for rising threshold levels */ | ||
| 594 | threshold_code = temp_to_code(data, temp); | ||
| 595 | rising_threshold = readl(data->base + | ||
| 596 | EXYNOS7_THD_TEMP_RISE7_6 + reg_off); | ||
| 597 | rising_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); | ||
| 598 | rising_threshold |= threshold_code << (16 * bit_off); | ||
| 599 | writel(rising_threshold, | ||
| 600 | data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); | ||
| 601 | |||
| 602 | /* Set 9-bit temperature code for falling threshold levels */ | ||
| 603 | threshold_code = temp_to_code(data, temp_hist); | ||
| 604 | falling_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); | ||
| 605 | falling_threshold |= threshold_code << (16 * bit_off); | ||
| 606 | writel(falling_threshold, | ||
| 607 | data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); | ||
| 608 | } | ||
| 609 | |||
| 610 | data->tmu_clear_irqs(data); | ||
| 611 | out: | ||
| 612 | return ret; | ||
| 613 | } | ||
| 614 | |||
| 615 | static void exynos4210_tmu_control(struct platform_device *pdev, bool on) | ||
| 616 | { | ||
| 617 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | ||
| 618 | struct thermal_zone_device *tz = data->tzd; | ||
| 446 | unsigned int con, interrupt_en; | 619 | unsigned int con, interrupt_en; |
| 447 | 620 | ||
| 448 | con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); | 621 | con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); |
| @@ -450,10 +623,15 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on) | |||
| 450 | if (on) { | 623 | if (on) { |
| 451 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); | 624 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); |
| 452 | interrupt_en = | 625 | interrupt_en = |
| 453 | pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT | | 626 | (of_thermal_is_trip_valid(tz, 3) |
| 454 | pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT | | 627 | << EXYNOS_TMU_INTEN_RISE3_SHIFT) | |
| 455 | pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT | | 628 | (of_thermal_is_trip_valid(tz, 2) |
| 456 | pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT; | 629 | << EXYNOS_TMU_INTEN_RISE2_SHIFT) | |
| 630 | (of_thermal_is_trip_valid(tz, 1) | ||
| 631 | << EXYNOS_TMU_INTEN_RISE1_SHIFT) | | ||
| 632 | (of_thermal_is_trip_valid(tz, 0) | ||
| 633 | << EXYNOS_TMU_INTEN_RISE0_SHIFT); | ||
| 634 | |||
| 457 | if (data->soc != SOC_ARCH_EXYNOS4210) | 635 | if (data->soc != SOC_ARCH_EXYNOS4210) |
| 458 | interrupt_en |= | 636 | interrupt_en |= |
| 459 | interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; | 637 | interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; |
| @@ -468,7 +646,7 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on) | |||
| 468 | static void exynos5440_tmu_control(struct platform_device *pdev, bool on) | 646 | static void exynos5440_tmu_control(struct platform_device *pdev, bool on) |
| 469 | { | 647 | { |
| 470 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 648 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 471 | struct exynos_tmu_platform_data *pdata = data->pdata; | 649 | struct thermal_zone_device *tz = data->tzd; |
| 472 | unsigned int con, interrupt_en; | 650 | unsigned int con, interrupt_en; |
| 473 | 651 | ||
| 474 | con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL)); | 652 | con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL)); |
| @@ -476,11 +654,16 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on) | |||
| 476 | if (on) { | 654 | if (on) { |
| 477 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); | 655 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); |
| 478 | interrupt_en = | 656 | interrupt_en = |
| 479 | pdata->trigger_enable[3] << EXYNOS5440_TMU_INTEN_RISE3_SHIFT | | 657 | (of_thermal_is_trip_valid(tz, 3) |
| 480 | pdata->trigger_enable[2] << EXYNOS5440_TMU_INTEN_RISE2_SHIFT | | 658 | << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) | |
| 481 | pdata->trigger_enable[1] << EXYNOS5440_TMU_INTEN_RISE1_SHIFT | | 659 | (of_thermal_is_trip_valid(tz, 2) |
| 482 | pdata->trigger_enable[0] << EXYNOS5440_TMU_INTEN_RISE0_SHIFT; | 660 | << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) | |
| 483 | interrupt_en |= interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT; | 661 | (of_thermal_is_trip_valid(tz, 1) |
| 662 | << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) | | ||
| 663 | (of_thermal_is_trip_valid(tz, 0) | ||
| 664 | << EXYNOS5440_TMU_INTEN_RISE0_SHIFT); | ||
| 665 | interrupt_en |= | ||
| 666 | interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT; | ||
| 484 | } else { | 667 | } else { |
| 485 | con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); | 668 | con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); |
| 486 | interrupt_en = 0; /* Disable all interrupts */ | 669 | interrupt_en = 0; /* Disable all interrupts */ |
| @@ -489,19 +672,62 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on) | |||
| 489 | writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); | 672 | writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); |
| 490 | } | 673 | } |
| 491 | 674 | ||
| 492 | static int exynos_tmu_read(struct exynos_tmu_data *data) | 675 | static void exynos7_tmu_control(struct platform_device *pdev, bool on) |
| 493 | { | 676 | { |
| 494 | int ret; | 677 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 678 | struct thermal_zone_device *tz = data->tzd; | ||
| 679 | unsigned int con, interrupt_en; | ||
| 680 | |||
| 681 | con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); | ||
| 682 | |||
| 683 | if (on) { | ||
| 684 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); | ||
| 685 | interrupt_en = | ||
| 686 | (of_thermal_is_trip_valid(tz, 7) | ||
| 687 | << EXYNOS7_TMU_INTEN_RISE7_SHIFT) | | ||
| 688 | (of_thermal_is_trip_valid(tz, 6) | ||
| 689 | << EXYNOS7_TMU_INTEN_RISE6_SHIFT) | | ||
| 690 | (of_thermal_is_trip_valid(tz, 5) | ||
| 691 | << EXYNOS7_TMU_INTEN_RISE5_SHIFT) | | ||
| 692 | (of_thermal_is_trip_valid(tz, 4) | ||
| 693 | << EXYNOS7_TMU_INTEN_RISE4_SHIFT) | | ||
| 694 | (of_thermal_is_trip_valid(tz, 3) | ||
| 695 | << EXYNOS7_TMU_INTEN_RISE3_SHIFT) | | ||
| 696 | (of_thermal_is_trip_valid(tz, 2) | ||
| 697 | << EXYNOS7_TMU_INTEN_RISE2_SHIFT) | | ||
| 698 | (of_thermal_is_trip_valid(tz, 1) | ||
| 699 | << EXYNOS7_TMU_INTEN_RISE1_SHIFT) | | ||
| 700 | (of_thermal_is_trip_valid(tz, 0) | ||
| 701 | << EXYNOS7_TMU_INTEN_RISE0_SHIFT); | ||
| 702 | |||
| 703 | interrupt_en |= | ||
| 704 | interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; | ||
| 705 | } else { | ||
| 706 | con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); | ||
| 707 | interrupt_en = 0; /* Disable all interrupts */ | ||
| 708 | } | ||
| 709 | con |= 1 << EXYNOS7_PD_DET_EN_SHIFT; | ||
| 710 | |||
| 711 | writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN); | ||
| 712 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); | ||
| 713 | } | ||
| 714 | |||
| 715 | static int exynos_get_temp(void *p, long *temp) | ||
| 716 | { | ||
| 717 | struct exynos_tmu_data *data = p; | ||
| 718 | |||
| 719 | if (!data) | ||
| 720 | return -EINVAL; | ||
| 495 | 721 | ||
| 496 | mutex_lock(&data->lock); | 722 | mutex_lock(&data->lock); |
| 497 | clk_enable(data->clk); | 723 | clk_enable(data->clk); |
| 498 | ret = data->tmu_read(data); | 724 | |
| 499 | if (ret >= 0) | 725 | *temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS; |
| 500 | ret = code_to_temp(data, ret); | 726 | |
| 501 | clk_disable(data->clk); | 727 | clk_disable(data->clk); |
| 502 | mutex_unlock(&data->lock); | 728 | mutex_unlock(&data->lock); |
| 503 | 729 | ||
| 504 | return ret; | 730 | return 0; |
| 505 | } | 731 | } |
| 506 | 732 | ||
| 507 | #ifdef CONFIG_THERMAL_EMULATION | 733 | #ifdef CONFIG_THERMAL_EMULATION |
| @@ -515,9 +741,19 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, | |||
| 515 | val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); | 741 | val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); |
| 516 | val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); | 742 | val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); |
| 517 | } | 743 | } |
| 518 | val &= ~(EXYNOS_EMUL_DATA_MASK << EXYNOS_EMUL_DATA_SHIFT); | 744 | if (data->soc == SOC_ARCH_EXYNOS7) { |
| 519 | val |= (temp_to_code(data, temp) << EXYNOS_EMUL_DATA_SHIFT) | | 745 | val &= ~(EXYNOS7_EMUL_DATA_MASK << |
| 520 | EXYNOS_EMUL_ENABLE; | 746 | EXYNOS7_EMUL_DATA_SHIFT); |
| 747 | val |= (temp_to_code(data, temp) << | ||
| 748 | EXYNOS7_EMUL_DATA_SHIFT) | | ||
| 749 | EXYNOS_EMUL_ENABLE; | ||
| 750 | } else { | ||
| 751 | val &= ~(EXYNOS_EMUL_DATA_MASK << | ||
| 752 | EXYNOS_EMUL_DATA_SHIFT); | ||
| 753 | val |= (temp_to_code(data, temp) << | ||
| 754 | EXYNOS_EMUL_DATA_SHIFT) | | ||
| 755 | EXYNOS_EMUL_ENABLE; | ||
| 756 | } | ||
| 521 | } else { | 757 | } else { |
| 522 | val &= ~EXYNOS_EMUL_ENABLE; | 758 | val &= ~EXYNOS_EMUL_ENABLE; |
| 523 | } | 759 | } |
| @@ -533,6 +769,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, | |||
| 533 | 769 | ||
| 534 | if (data->soc == SOC_ARCH_EXYNOS5260) | 770 | if (data->soc == SOC_ARCH_EXYNOS5260) |
| 535 | emul_con = EXYNOS5260_EMUL_CON; | 771 | emul_con = EXYNOS5260_EMUL_CON; |
| 772 | else if (data->soc == SOC_ARCH_EXYNOS7) | ||
| 773 | emul_con = EXYNOS7_TMU_REG_EMUL_CON; | ||
| 536 | else | 774 | else |
| 537 | emul_con = EXYNOS_EMUL_CON; | 775 | emul_con = EXYNOS_EMUL_CON; |
| 538 | 776 | ||
| @@ -576,7 +814,7 @@ out: | |||
| 576 | #define exynos5440_tmu_set_emulation NULL | 814 | #define exynos5440_tmu_set_emulation NULL |
| 577 | static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) | 815 | static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) |
| 578 | { return -EINVAL; } | 816 | { return -EINVAL; } |
| 579 | #endif/*CONFIG_THERMAL_EMULATION*/ | 817 | #endif /* CONFIG_THERMAL_EMULATION */ |
| 580 | 818 | ||
| 581 | static int exynos4210_tmu_read(struct exynos_tmu_data *data) | 819 | static int exynos4210_tmu_read(struct exynos_tmu_data *data) |
| 582 | { | 820 | { |
| @@ -596,6 +834,12 @@ static int exynos5440_tmu_read(struct exynos_tmu_data *data) | |||
| 596 | return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP); | 834 | return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP); |
| 597 | } | 835 | } |
| 598 | 836 | ||
| 837 | static int exynos7_tmu_read(struct exynos_tmu_data *data) | ||
| 838 | { | ||
| 839 | return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) & | ||
| 840 | EXYNOS7_TMU_TEMP_MASK; | ||
| 841 | } | ||
| 842 | |||
| 599 | static void exynos_tmu_work(struct work_struct *work) | 843 | static void exynos_tmu_work(struct work_struct *work) |
| 600 | { | 844 | { |
| 601 | struct exynos_tmu_data *data = container_of(work, | 845 | struct exynos_tmu_data *data = container_of(work, |
| @@ -613,7 +857,7 @@ static void exynos_tmu_work(struct work_struct *work) | |||
| 613 | if (!IS_ERR(data->clk_sec)) | 857 | if (!IS_ERR(data->clk_sec)) |
| 614 | clk_disable(data->clk_sec); | 858 | clk_disable(data->clk_sec); |
| 615 | 859 | ||
| 616 | exynos_report_trigger(data->reg_conf); | 860 | exynos_report_trigger(data); |
| 617 | mutex_lock(&data->lock); | 861 | mutex_lock(&data->lock); |
| 618 | clk_enable(data->clk); | 862 | clk_enable(data->clk); |
| 619 | 863 | ||
| @@ -634,6 +878,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) | |||
| 634 | if (data->soc == SOC_ARCH_EXYNOS5260) { | 878 | if (data->soc == SOC_ARCH_EXYNOS5260) { |
| 635 | tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT; | 879 | tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT; |
| 636 | tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR; | 880 | tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR; |
| 881 | } else if (data->soc == SOC_ARCH_EXYNOS7) { | ||
| 882 | tmu_intstat = EXYNOS7_TMU_REG_INTPEND; | ||
| 883 | tmu_intclear = EXYNOS7_TMU_REG_INTPEND; | ||
| 637 | } else { | 884 | } else { |
| 638 | tmu_intstat = EXYNOS_TMU_REG_INTSTAT; | 885 | tmu_intstat = EXYNOS_TMU_REG_INTSTAT; |
| 639 | tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; | 886 | tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; |
| @@ -673,55 +920,94 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id) | |||
| 673 | static const struct of_device_id exynos_tmu_match[] = { | 920 | static const struct of_device_id exynos_tmu_match[] = { |
| 674 | { | 921 | { |
| 675 | .compatible = "samsung,exynos3250-tmu", | 922 | .compatible = "samsung,exynos3250-tmu", |
| 676 | .data = &exynos3250_default_tmu_data, | ||
| 677 | }, | 923 | }, |
| 678 | { | 924 | { |
| 679 | .compatible = "samsung,exynos4210-tmu", | 925 | .compatible = "samsung,exynos4210-tmu", |
| 680 | .data = &exynos4210_default_tmu_data, | ||
| 681 | }, | 926 | }, |
| 682 | { | 927 | { |
| 683 | .compatible = "samsung,exynos4412-tmu", | 928 | .compatible = "samsung,exynos4412-tmu", |
| 684 | .data = &exynos4412_default_tmu_data, | ||
| 685 | }, | 929 | }, |
| 686 | { | 930 | { |
| 687 | .compatible = "samsung,exynos5250-tmu", | 931 | .compatible = "samsung,exynos5250-tmu", |
| 688 | .data = &exynos5250_default_tmu_data, | ||
| 689 | }, | 932 | }, |
| 690 | { | 933 | { |
| 691 | .compatible = "samsung,exynos5260-tmu", | 934 | .compatible = "samsung,exynos5260-tmu", |
| 692 | .data = &exynos5260_default_tmu_data, | ||
| 693 | }, | 935 | }, |
| 694 | { | 936 | { |
| 695 | .compatible = "samsung,exynos5420-tmu", | 937 | .compatible = "samsung,exynos5420-tmu", |
| 696 | .data = &exynos5420_default_tmu_data, | ||
| 697 | }, | 938 | }, |
| 698 | { | 939 | { |
| 699 | .compatible = "samsung,exynos5420-tmu-ext-triminfo", | 940 | .compatible = "samsung,exynos5420-tmu-ext-triminfo", |
| 700 | .data = &exynos5420_default_tmu_data, | ||
| 701 | }, | 941 | }, |
| 702 | { | 942 | { |
| 703 | .compatible = "samsung,exynos5440-tmu", | 943 | .compatible = "samsung,exynos5440-tmu", |
| 704 | .data = &exynos5440_default_tmu_data, | 944 | }, |
| 945 | { | ||
| 946 | .compatible = "samsung,exynos7-tmu", | ||
| 705 | }, | 947 | }, |
| 706 | {}, | 948 | {}, |
| 707 | }; | 949 | }; |
| 708 | MODULE_DEVICE_TABLE(of, exynos_tmu_match); | 950 | MODULE_DEVICE_TABLE(of, exynos_tmu_match); |
| 709 | 951 | ||
| 710 | static inline struct exynos_tmu_platform_data *exynos_get_driver_data( | 952 | static int exynos_of_get_soc_type(struct device_node *np) |
| 711 | struct platform_device *pdev, int id) | 953 | { |
| 954 | if (of_device_is_compatible(np, "samsung,exynos3250-tmu")) | ||
| 955 | return SOC_ARCH_EXYNOS3250; | ||
| 956 | else if (of_device_is_compatible(np, "samsung,exynos4210-tmu")) | ||
| 957 | return SOC_ARCH_EXYNOS4210; | ||
| 958 | else if (of_device_is_compatible(np, "samsung,exynos4412-tmu")) | ||
| 959 | return SOC_ARCH_EXYNOS4412; | ||
| 960 | else if (of_device_is_compatible(np, "samsung,exynos5250-tmu")) | ||
| 961 | return SOC_ARCH_EXYNOS5250; | ||
| 962 | else if (of_device_is_compatible(np, "samsung,exynos5260-tmu")) | ||
| 963 | return SOC_ARCH_EXYNOS5260; | ||
| 964 | else if (of_device_is_compatible(np, "samsung,exynos5420-tmu")) | ||
| 965 | return SOC_ARCH_EXYNOS5420; | ||
| 966 | else if (of_device_is_compatible(np, | ||
| 967 | "samsung,exynos5420-tmu-ext-triminfo")) | ||
| 968 | return SOC_ARCH_EXYNOS5420_TRIMINFO; | ||
| 969 | else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) | ||
| 970 | return SOC_ARCH_EXYNOS5440; | ||
| 971 | else if (of_device_is_compatible(np, "samsung,exynos7-tmu")) | ||
| 972 | return SOC_ARCH_EXYNOS7; | ||
| 973 | |||
| 974 | return -EINVAL; | ||
| 975 | } | ||
| 976 | |||
| 977 | static int exynos_of_sensor_conf(struct device_node *np, | ||
| 978 | struct exynos_tmu_platform_data *pdata) | ||
| 712 | { | 979 | { |
| 713 | struct exynos_tmu_init_data *data_table; | 980 | u32 value; |
| 714 | struct exynos_tmu_platform_data *tmu_data; | 981 | int ret; |
| 715 | const struct of_device_id *match; | ||
| 716 | 982 | ||
| 717 | match = of_match_node(exynos_tmu_match, pdev->dev.of_node); | 983 | of_node_get(np); |
| 718 | if (!match) | 984 | |
| 719 | return NULL; | 985 | ret = of_property_read_u32(np, "samsung,tmu_gain", &value); |
| 720 | data_table = (struct exynos_tmu_init_data *) match->data; | 986 | pdata->gain = (u8)value; |
| 721 | if (!data_table || id >= data_table->tmu_count) | 987 | of_property_read_u32(np, "samsung,tmu_reference_voltage", &value); |
| 722 | return NULL; | 988 | pdata->reference_voltage = (u8)value; |
| 723 | tmu_data = data_table->tmu_data; | 989 | of_property_read_u32(np, "samsung,tmu_noise_cancel_mode", &value); |
| 724 | return (struct exynos_tmu_platform_data *) (tmu_data + id); | 990 | pdata->noise_cancel_mode = (u8)value; |
| 991 | |||
| 992 | of_property_read_u32(np, "samsung,tmu_efuse_value", | ||
| 993 | &pdata->efuse_value); | ||
| 994 | of_property_read_u32(np, "samsung,tmu_min_efuse_value", | ||
| 995 | &pdata->min_efuse_value); | ||
| 996 | of_property_read_u32(np, "samsung,tmu_max_efuse_value", | ||
| 997 | &pdata->max_efuse_value); | ||
| 998 | |||
| 999 | of_property_read_u32(np, "samsung,tmu_first_point_trim", &value); | ||
| 1000 | pdata->first_point_trim = (u8)value; | ||
| 1001 | of_property_read_u32(np, "samsung,tmu_second_point_trim", &value); | ||
| 1002 | pdata->second_point_trim = (u8)value; | ||
| 1003 | of_property_read_u32(np, "samsung,tmu_default_temp_offset", &value); | ||
| 1004 | pdata->default_temp_offset = (u8)value; | ||
| 1005 | |||
| 1006 | of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type); | ||
| 1007 | of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode); | ||
| 1008 | |||
| 1009 | of_node_put(np); | ||
| 1010 | return 0; | ||
| 725 | } | 1011 | } |
| 726 | 1012 | ||
| 727 | static int exynos_map_dt_data(struct platform_device *pdev) | 1013 | static int exynos_map_dt_data(struct platform_device *pdev) |
| @@ -771,14 +1057,15 @@ static int exynos_map_dt_data(struct platform_device *pdev) | |||
| 771 | return -EADDRNOTAVAIL; | 1057 | return -EADDRNOTAVAIL; |
| 772 | } | 1058 | } |
| 773 | 1059 | ||
| 774 | pdata = exynos_get_driver_data(pdev, data->id); | 1060 | pdata = devm_kzalloc(&pdev->dev, |
| 775 | if (!pdata) { | 1061 | sizeof(struct exynos_tmu_platform_data), |
| 776 | dev_err(&pdev->dev, "No platform init data supplied.\n"); | 1062 | GFP_KERNEL); |
| 777 | return -ENODEV; | 1063 | if (!pdata) |
| 778 | } | 1064 | return -ENOMEM; |
| 779 | 1065 | ||
| 1066 | exynos_of_sensor_conf(pdev->dev.of_node, pdata); | ||
| 780 | data->pdata = pdata; | 1067 | data->pdata = pdata; |
| 781 | data->soc = pdata->type; | 1068 | data->soc = exynos_of_get_soc_type(pdev->dev.of_node); |
| 782 | 1069 | ||
| 783 | switch (data->soc) { | 1070 | switch (data->soc) { |
| 784 | case SOC_ARCH_EXYNOS4210: | 1071 | case SOC_ARCH_EXYNOS4210: |
| @@ -806,6 +1093,13 @@ static int exynos_map_dt_data(struct platform_device *pdev) | |||
| 806 | data->tmu_set_emulation = exynos5440_tmu_set_emulation; | 1093 | data->tmu_set_emulation = exynos5440_tmu_set_emulation; |
| 807 | data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; | 1094 | data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; |
| 808 | break; | 1095 | break; |
| 1096 | case SOC_ARCH_EXYNOS7: | ||
| 1097 | data->tmu_initialize = exynos7_tmu_initialize; | ||
| 1098 | data->tmu_control = exynos7_tmu_control; | ||
| 1099 | data->tmu_read = exynos7_tmu_read; | ||
| 1100 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; | ||
| 1101 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; | ||
| 1102 | break; | ||
| 809 | default: | 1103 | default: |
| 810 | dev_err(&pdev->dev, "Platform not supported\n"); | 1104 | dev_err(&pdev->dev, "Platform not supported\n"); |
| 811 | return -EINVAL; | 1105 | return -EINVAL; |
| @@ -834,12 +1128,16 @@ static int exynos_map_dt_data(struct platform_device *pdev) | |||
| 834 | return 0; | 1128 | return 0; |
| 835 | } | 1129 | } |
| 836 | 1130 | ||
| 1131 | static struct thermal_zone_of_device_ops exynos_sensor_ops = { | ||
| 1132 | .get_temp = exynos_get_temp, | ||
| 1133 | .set_emul_temp = exynos_tmu_set_emulation, | ||
| 1134 | }; | ||
| 1135 | |||
| 837 | static int exynos_tmu_probe(struct platform_device *pdev) | 1136 | static int exynos_tmu_probe(struct platform_device *pdev) |
| 838 | { | 1137 | { |
| 839 | struct exynos_tmu_data *data; | ||
| 840 | struct exynos_tmu_platform_data *pdata; | 1138 | struct exynos_tmu_platform_data *pdata; |
| 841 | struct thermal_sensor_conf *sensor_conf; | 1139 | struct exynos_tmu_data *data; |
| 842 | int ret, i; | 1140 | int ret; |
| 843 | 1141 | ||
| 844 | data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data), | 1142 | data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data), |
| 845 | GFP_KERNEL); | 1143 | GFP_KERNEL); |
| @@ -849,9 +1147,15 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
| 849 | platform_set_drvdata(pdev, data); | 1147 | platform_set_drvdata(pdev, data); |
| 850 | mutex_init(&data->lock); | 1148 | mutex_init(&data->lock); |
| 851 | 1149 | ||
| 1150 | data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, | ||
| 1151 | &exynos_sensor_ops); | ||
| 1152 | if (IS_ERR(data->tzd)) { | ||
| 1153 | pr_err("thermal: tz: %p ERROR\n", data->tzd); | ||
| 1154 | return PTR_ERR(data->tzd); | ||
| 1155 | } | ||
| 852 | ret = exynos_map_dt_data(pdev); | 1156 | ret = exynos_map_dt_data(pdev); |
| 853 | if (ret) | 1157 | if (ret) |
| 854 | return ret; | 1158 | goto err_sensor; |
| 855 | 1159 | ||
| 856 | pdata = data->pdata; | 1160 | pdata = data->pdata; |
| 857 | 1161 | ||
| @@ -860,20 +1164,22 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
| 860 | data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); | 1164 | data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); |
| 861 | if (IS_ERR(data->clk)) { | 1165 | if (IS_ERR(data->clk)) { |
| 862 | dev_err(&pdev->dev, "Failed to get clock\n"); | 1166 | dev_err(&pdev->dev, "Failed to get clock\n"); |
| 863 | return PTR_ERR(data->clk); | 1167 | ret = PTR_ERR(data->clk); |
| 1168 | goto err_sensor; | ||
| 864 | } | 1169 | } |
| 865 | 1170 | ||
| 866 | data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif"); | 1171 | data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif"); |
| 867 | if (IS_ERR(data->clk_sec)) { | 1172 | if (IS_ERR(data->clk_sec)) { |
| 868 | if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { | 1173 | if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { |
| 869 | dev_err(&pdev->dev, "Failed to get triminfo clock\n"); | 1174 | dev_err(&pdev->dev, "Failed to get triminfo clock\n"); |
| 870 | return PTR_ERR(data->clk_sec); | 1175 | ret = PTR_ERR(data->clk_sec); |
| 1176 | goto err_sensor; | ||
| 871 | } | 1177 | } |
| 872 | } else { | 1178 | } else { |
| 873 | ret = clk_prepare(data->clk_sec); | 1179 | ret = clk_prepare(data->clk_sec); |
| 874 | if (ret) { | 1180 | if (ret) { |
| 875 | dev_err(&pdev->dev, "Failed to get clock\n"); | 1181 | dev_err(&pdev->dev, "Failed to get clock\n"); |
| 876 | return ret; | 1182 | goto err_sensor; |
| 877 | } | 1183 | } |
| 878 | } | 1184 | } |
| 879 | 1185 | ||
| @@ -883,82 +1189,57 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
| 883 | goto err_clk_sec; | 1189 | goto err_clk_sec; |
| 884 | } | 1190 | } |
| 885 | 1191 | ||
| 886 | ret = exynos_tmu_initialize(pdev); | 1192 | if (data->soc == SOC_ARCH_EXYNOS7) { |
| 887 | if (ret) { | 1193 | data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk"); |
| 888 | dev_err(&pdev->dev, "Failed to initialize TMU\n"); | 1194 | if (IS_ERR(data->sclk)) { |
| 889 | goto err_clk; | 1195 | dev_err(&pdev->dev, "Failed to get sclk\n"); |
| 1196 | goto err_clk; | ||
| 1197 | } else { | ||
| 1198 | ret = clk_prepare_enable(data->sclk); | ||
| 1199 | if (ret) { | ||
| 1200 | dev_err(&pdev->dev, "Failed to enable sclk\n"); | ||
| 1201 | goto err_clk; | ||
| 1202 | } | ||
| 1203 | } | ||
| 890 | } | 1204 | } |
| 891 | 1205 | ||
| 892 | exynos_tmu_control(pdev, true); | 1206 | ret = exynos_tmu_initialize(pdev); |
| 893 | |||
| 894 | /* Allocate a structure to register with the exynos core thermal */ | ||
| 895 | sensor_conf = devm_kzalloc(&pdev->dev, | ||
| 896 | sizeof(struct thermal_sensor_conf), GFP_KERNEL); | ||
| 897 | if (!sensor_conf) { | ||
| 898 | ret = -ENOMEM; | ||
| 899 | goto err_clk; | ||
| 900 | } | ||
| 901 | sprintf(sensor_conf->name, "therm_zone%d", data->id); | ||
| 902 | sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read; | ||
| 903 | sensor_conf->write_emul_temp = | ||
| 904 | (int (*)(void *, unsigned long))exynos_tmu_set_emulation; | ||
| 905 | sensor_conf->driver_data = data; | ||
| 906 | sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] + | ||
| 907 | pdata->trigger_enable[1] + pdata->trigger_enable[2]+ | ||
| 908 | pdata->trigger_enable[3]; | ||
| 909 | |||
| 910 | for (i = 0; i < sensor_conf->trip_data.trip_count; i++) { | ||
| 911 | sensor_conf->trip_data.trip_val[i] = | ||
| 912 | pdata->threshold + pdata->trigger_levels[i]; | ||
| 913 | sensor_conf->trip_data.trip_type[i] = | ||
| 914 | pdata->trigger_type[i]; | ||
| 915 | } | ||
| 916 | |||
| 917 | sensor_conf->trip_data.trigger_falling = pdata->threshold_falling; | ||
| 918 | |||
| 919 | sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count; | ||
| 920 | for (i = 0; i < pdata->freq_tab_count; i++) { | ||
| 921 | sensor_conf->cooling_data.freq_data[i].freq_clip_max = | ||
| 922 | pdata->freq_tab[i].freq_clip_max; | ||
| 923 | sensor_conf->cooling_data.freq_data[i].temp_level = | ||
| 924 | pdata->freq_tab[i].temp_level; | ||
| 925 | } | ||
| 926 | sensor_conf->dev = &pdev->dev; | ||
| 927 | /* Register the sensor with thermal management interface */ | ||
| 928 | ret = exynos_register_thermal(sensor_conf); | ||
| 929 | if (ret) { | 1207 | if (ret) { |
| 930 | if (ret != -EPROBE_DEFER) | 1208 | dev_err(&pdev->dev, "Failed to initialize TMU\n"); |
| 931 | dev_err(&pdev->dev, | 1209 | goto err_sclk; |
| 932 | "Failed to register thermal interface: %d\n", | ||
| 933 | ret); | ||
| 934 | goto err_clk; | ||
| 935 | } | 1210 | } |
| 936 | data->reg_conf = sensor_conf; | ||
| 937 | 1211 | ||
| 938 | ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, | 1212 | ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, |
| 939 | IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); | 1213 | IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); |
| 940 | if (ret) { | 1214 | if (ret) { |
| 941 | dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); | 1215 | dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); |
| 942 | goto err_clk; | 1216 | goto err_sclk; |
| 943 | } | 1217 | } |
| 944 | 1218 | ||
| 1219 | exynos_tmu_control(pdev, true); | ||
| 945 | return 0; | 1220 | return 0; |
| 1221 | err_sclk: | ||
| 1222 | clk_disable_unprepare(data->sclk); | ||
| 946 | err_clk: | 1223 | err_clk: |
| 947 | clk_unprepare(data->clk); | 1224 | clk_unprepare(data->clk); |
| 948 | err_clk_sec: | 1225 | err_clk_sec: |
| 949 | if (!IS_ERR(data->clk_sec)) | 1226 | if (!IS_ERR(data->clk_sec)) |
| 950 | clk_unprepare(data->clk_sec); | 1227 | clk_unprepare(data->clk_sec); |
| 1228 | err_sensor: | ||
| 1229 | thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); | ||
| 1230 | |||
| 951 | return ret; | 1231 | return ret; |
| 952 | } | 1232 | } |
| 953 | 1233 | ||
| 954 | static int exynos_tmu_remove(struct platform_device *pdev) | 1234 | static int exynos_tmu_remove(struct platform_device *pdev) |
| 955 | { | 1235 | { |
| 956 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 1236 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
| 1237 | struct thermal_zone_device *tzd = data->tzd; | ||
| 957 | 1238 | ||
| 958 | exynos_unregister_thermal(data->reg_conf); | 1239 | thermal_zone_of_sensor_unregister(&pdev->dev, tzd); |
| 959 | |||
| 960 | exynos_tmu_control(pdev, false); | 1240 | exynos_tmu_control(pdev, false); |
| 961 | 1241 | ||
| 1242 | clk_disable_unprepare(data->sclk); | ||
| 962 | clk_unprepare(data->clk); | 1243 | clk_unprepare(data->clk); |
| 963 | if (!IS_ERR(data->clk_sec)) | 1244 | if (!IS_ERR(data->clk_sec)) |
| 964 | clk_unprepare(data->clk_sec); | 1245 | clk_unprepare(data->clk_sec); |
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h index da3009bff6c4..4d71ec6c9aa0 100644 --- a/drivers/thermal/samsung/exynos_tmu.h +++ b/drivers/thermal/samsung/exynos_tmu.h | |||
| @@ -23,16 +23,7 @@ | |||
| 23 | #ifndef _EXYNOS_TMU_H | 23 | #ifndef _EXYNOS_TMU_H |
| 24 | #define _EXYNOS_TMU_H | 24 | #define _EXYNOS_TMU_H |
| 25 | #include <linux/cpu_cooling.h> | 25 | #include <linux/cpu_cooling.h> |
| 26 | 26 | #include <dt-bindings/thermal/thermal_exynos.h> | |
| 27 | #include "exynos_thermal_common.h" | ||
| 28 | |||
| 29 | enum calibration_type { | ||
| 30 | TYPE_ONE_POINT_TRIMMING, | ||
| 31 | TYPE_ONE_POINT_TRIMMING_25, | ||
| 32 | TYPE_ONE_POINT_TRIMMING_85, | ||
| 33 | TYPE_TWO_POINT_TRIMMING, | ||
| 34 | TYPE_NONE, | ||
| 35 | }; | ||
| 36 | 27 | ||
| 37 | enum soc_type { | 28 | enum soc_type { |
| 38 | SOC_ARCH_EXYNOS3250 = 1, | 29 | SOC_ARCH_EXYNOS3250 = 1, |
| @@ -43,38 +34,11 @@ enum soc_type { | |||
| 43 | SOC_ARCH_EXYNOS5420, | 34 | SOC_ARCH_EXYNOS5420, |
| 44 | SOC_ARCH_EXYNOS5420_TRIMINFO, | 35 | SOC_ARCH_EXYNOS5420_TRIMINFO, |
| 45 | SOC_ARCH_EXYNOS5440, | 36 | SOC_ARCH_EXYNOS5440, |
| 37 | SOC_ARCH_EXYNOS7, | ||
| 46 | }; | 38 | }; |
| 47 | 39 | ||
| 48 | /** | 40 | /** |
| 49 | * struct exynos_tmu_platform_data | 41 | * struct exynos_tmu_platform_data |
| 50 | * @threshold: basic temperature for generating interrupt | ||
| 51 | * 25 <= threshold <= 125 [unit: degree Celsius] | ||
| 52 | * @threshold_falling: differntial value for setting threshold | ||
| 53 | * of temperature falling interrupt. | ||
| 54 | * @trigger_levels: array for each interrupt levels | ||
| 55 | * [unit: degree Celsius] | ||
| 56 | * 0: temperature for trigger_level0 interrupt | ||
| 57 | * condition for trigger_level0 interrupt: | ||
| 58 | * current temperature > threshold + trigger_levels[0] | ||
| 59 | * 1: temperature for trigger_level1 interrupt | ||
| 60 | * condition for trigger_level1 interrupt: | ||
| 61 | * current temperature > threshold + trigger_levels[1] | ||
| 62 | * 2: temperature for trigger_level2 interrupt | ||
| 63 | * condition for trigger_level2 interrupt: | ||
| 64 | * current temperature > threshold + trigger_levels[2] | ||
| 65 | * 3: temperature for trigger_level3 interrupt | ||
| 66 | * condition for trigger_level3 interrupt: | ||
| 67 | * current temperature > threshold + trigger_levels[3] | ||
| 68 | * @trigger_type: defines the type of trigger. Possible values are, | ||
| 69 | * THROTTLE_ACTIVE trigger type | ||
| 70 | * THROTTLE_PASSIVE trigger type | ||
| 71 | * SW_TRIP trigger type | ||
| 72 | * HW_TRIP | ||
| 73 | * @trigger_enable[]: array to denote which trigger levels are enabled. | ||
| 74 | * 1 = enable trigger_level[] interrupt, | ||
| 75 | * 0 = disable trigger_level[] interrupt | ||
| 76 | * @max_trigger_level: max trigger level supported by the TMU | ||
| 77 | * @non_hw_trigger_levels: number of defined non-hardware trigger levels | ||
| 78 | * @gain: gain of amplifier in the positive-TC generator block | 42 | * @gain: gain of amplifier in the positive-TC generator block |
| 79 | * 0 < gain <= 15 | 43 | * 0 < gain <= 15 |
| 80 | * @reference_voltage: reference voltage of amplifier | 44 | * @reference_voltage: reference voltage of amplifier |
| @@ -86,24 +50,12 @@ enum soc_type { | |||
| 86 | * @efuse_value: platform defined fuse value | 50 | * @efuse_value: platform defined fuse value |
| 87 | * @min_efuse_value: minimum valid trimming data | 51 | * @min_efuse_value: minimum valid trimming data |
| 88 | * @max_efuse_value: maximum valid trimming data | 52 | * @max_efuse_value: maximum valid trimming data |
| 89 | * @first_point_trim: temp value of the first point trimming | ||
| 90 | * @second_point_trim: temp value of the second point trimming | ||
| 91 | * @default_temp_offset: default temperature offset in case of no trimming | 53 | * @default_temp_offset: default temperature offset in case of no trimming |
| 92 | * @cal_type: calibration type for temperature | 54 | * @cal_type: calibration type for temperature |
| 93 | * @freq_clip_table: Table representing frequency reduction percentage. | ||
| 94 | * @freq_tab_count: Count of the above table as frequency reduction may | ||
| 95 | * applicable to only some of the trigger levels. | ||
| 96 | * | 55 | * |
| 97 | * This structure is required for configuration of exynos_tmu driver. | 56 | * This structure is required for configuration of exynos_tmu driver. |
| 98 | */ | 57 | */ |
| 99 | struct exynos_tmu_platform_data { | 58 | struct exynos_tmu_platform_data { |
| 100 | u8 threshold; | ||
| 101 | u8 threshold_falling; | ||
| 102 | u8 trigger_levels[MAX_TRIP_COUNT]; | ||
| 103 | enum trigger_type trigger_type[MAX_TRIP_COUNT]; | ||
| 104 | bool trigger_enable[MAX_TRIP_COUNT]; | ||
| 105 | u8 max_trigger_level; | ||
| 106 | u8 non_hw_trigger_levels; | ||
| 107 | u8 gain; | 59 | u8 gain; |
| 108 | u8 reference_voltage; | 60 | u8 reference_voltage; |
| 109 | u8 noise_cancel_mode; | 61 | u8 noise_cancel_mode; |
| @@ -115,30 +67,9 @@ struct exynos_tmu_platform_data { | |||
| 115 | u8 second_point_trim; | 67 | u8 second_point_trim; |
| 116 | u8 default_temp_offset; | 68 | u8 default_temp_offset; |
| 117 | 69 | ||
| 118 | enum calibration_type cal_type; | ||
| 119 | enum soc_type type; | 70 | enum soc_type type; |
| 120 | struct freq_clip_table freq_tab[4]; | 71 | u32 cal_type; |
| 121 | unsigned int freq_tab_count; | 72 | u32 cal_mode; |
| 122 | }; | ||
| 123 | |||
| 124 | /** | ||
| 125 | * struct exynos_tmu_init_data | ||
| 126 | * @tmu_count: number of TMU instances. | ||
| 127 | * @tmu_data: platform data of all TMU instances. | ||
| 128 | * This structure is required to store data for multi-instance exynos tmu | ||
| 129 | * driver. | ||
| 130 | */ | ||
| 131 | struct exynos_tmu_init_data { | ||
| 132 | int tmu_count; | ||
| 133 | struct exynos_tmu_platform_data tmu_data[]; | ||
| 134 | }; | 73 | }; |
| 135 | 74 | ||
| 136 | extern struct exynos_tmu_init_data const exynos3250_default_tmu_data; | ||
| 137 | extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; | ||
| 138 | extern struct exynos_tmu_init_data const exynos4412_default_tmu_data; | ||
| 139 | extern struct exynos_tmu_init_data const exynos5250_default_tmu_data; | ||
| 140 | extern struct exynos_tmu_init_data const exynos5260_default_tmu_data; | ||
| 141 | extern struct exynos_tmu_init_data const exynos5420_default_tmu_data; | ||
| 142 | extern struct exynos_tmu_init_data const exynos5440_default_tmu_data; | ||
| 143 | |||
| 144 | #endif /* _EXYNOS_TMU_H */ | 75 | #endif /* _EXYNOS_TMU_H */ |
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c deleted file mode 100644 index b23910069f68..000000000000 --- a/drivers/thermal/samsung/exynos_tmu_data.c +++ /dev/null | |||
| @@ -1,264 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * exynos_tmu_data.c - Samsung EXYNOS tmu data file | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Samsung Electronics | ||
| 5 | * Amit Daniel Kachhap <amit.daniel@samsung.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include "exynos_thermal_common.h" | ||
| 24 | #include "exynos_tmu.h" | ||
| 25 | |||
| 26 | struct exynos_tmu_init_data const exynos4210_default_tmu_data = { | ||
| 27 | .tmu_data = { | ||
| 28 | { | ||
| 29 | .threshold = 80, | ||
| 30 | .trigger_levels[0] = 5, | ||
| 31 | .trigger_levels[1] = 20, | ||
| 32 | .trigger_levels[2] = 30, | ||
| 33 | .trigger_enable[0] = true, | ||
| 34 | .trigger_enable[1] = true, | ||
| 35 | .trigger_enable[2] = true, | ||
| 36 | .trigger_enable[3] = false, | ||
| 37 | .trigger_type[0] = THROTTLE_ACTIVE, | ||
| 38 | .trigger_type[1] = THROTTLE_ACTIVE, | ||
| 39 | .trigger_type[2] = SW_TRIP, | ||
| 40 | .max_trigger_level = 4, | ||
| 41 | .non_hw_trigger_levels = 3, | ||
| 42 | .gain = 15, | ||
| 43 | .reference_voltage = 7, | ||
| 44 | .cal_type = TYPE_ONE_POINT_TRIMMING, | ||
| 45 | .min_efuse_value = 40, | ||
| 46 | .max_efuse_value = 100, | ||
| 47 | .first_point_trim = 25, | ||
| 48 | .second_point_trim = 85, | ||
| 49 | .default_temp_offset = 50, | ||
| 50 | .freq_tab[0] = { | ||
| 51 | .freq_clip_max = 800 * 1000, | ||
| 52 | .temp_level = 85, | ||
| 53 | }, | ||
| 54 | .freq_tab[1] = { | ||
| 55 | .freq_clip_max = 200 * 1000, | ||
| 56 | .temp_level = 100, | ||
| 57 | }, | ||
| 58 | .freq_tab_count = 2, | ||
| 59 | .type = SOC_ARCH_EXYNOS4210, | ||
| 60 | }, | ||
| 61 | }, | ||
| 62 | .tmu_count = 1, | ||
| 63 | }; | ||
| 64 | |||
| 65 | #define EXYNOS3250_TMU_DATA \ | ||
| 66 | .threshold_falling = 10, \ | ||
| 67 | .trigger_levels[0] = 70, \ | ||
| 68 | .trigger_levels[1] = 95, \ | ||
| 69 | .trigger_levels[2] = 110, \ | ||
| 70 | .trigger_levels[3] = 120, \ | ||
| 71 | .trigger_enable[0] = true, \ | ||
| 72 | .trigger_enable[1] = true, \ | ||
| 73 | .trigger_enable[2] = true, \ | ||
| 74 | .trigger_enable[3] = false, \ | ||
| 75 | .trigger_type[0] = THROTTLE_ACTIVE, \ | ||
| 76 | .trigger_type[1] = THROTTLE_ACTIVE, \ | ||
| 77 | .trigger_type[2] = SW_TRIP, \ | ||
| 78 | .trigger_type[3] = HW_TRIP, \ | ||
| 79 | .max_trigger_level = 4, \ | ||
| 80 | .non_hw_trigger_levels = 3, \ | ||
| 81 | .gain = 8, \ | ||
| 82 | .reference_voltage = 16, \ | ||
| 83 | .noise_cancel_mode = 4, \ | ||
| 84 | .cal_type = TYPE_TWO_POINT_TRIMMING, \ | ||
| 85 | .efuse_value = 55, \ | ||
| 86 | .min_efuse_value = 40, \ | ||
| 87 | .max_efuse_value = 100, \ | ||
| 88 | .first_point_trim = 25, \ | ||
| 89 | .second_point_trim = 85, \ | ||
| 90 | .default_temp_offset = 50, \ | ||
| 91 | .freq_tab[0] = { \ | ||
| 92 | .freq_clip_max = 800 * 1000, \ | ||
| 93 | .temp_level = 70, \ | ||
| 94 | }, \ | ||
| 95 | .freq_tab[1] = { \ | ||
| 96 | .freq_clip_max = 400 * 1000, \ | ||
| 97 | .temp_level = 95, \ | ||
| 98 | }, \ | ||
| 99 | .freq_tab_count = 2 | ||
| 100 | |||
| 101 | struct exynos_tmu_init_data const exynos3250_default_tmu_data = { | ||
| 102 | .tmu_data = { | ||
| 103 | { | ||
| 104 | EXYNOS3250_TMU_DATA, | ||
| 105 | .type = SOC_ARCH_EXYNOS3250, | ||
| 106 | }, | ||
| 107 | }, | ||
| 108 | .tmu_count = 1, | ||
| 109 | }; | ||
| 110 | |||
| 111 | #define EXYNOS4412_TMU_DATA \ | ||
| 112 | .threshold_falling = 10, \ | ||
| 113 | .trigger_levels[0] = 70, \ | ||
| 114 | .trigger_levels[1] = 95, \ | ||
| 115 | .trigger_levels[2] = 110, \ | ||
| 116 | .trigger_levels[3] = 120, \ | ||
| 117 | .trigger_enable[0] = true, \ | ||
| 118 | .trigger_enable[1] = true, \ | ||
| 119 | .trigger_enable[2] = true, \ | ||
| 120 | .trigger_enable[3] = false, \ | ||
| 121 | .trigger_type[0] = THROTTLE_ACTIVE, \ | ||
| 122 | .trigger_type[1] = THROTTLE_ACTIVE, \ | ||
| 123 | .trigger_type[2] = SW_TRIP, \ | ||
| 124 | .trigger_type[3] = HW_TRIP, \ | ||
| 125 | .max_trigger_level = 4, \ | ||
| 126 | .non_hw_trigger_levels = 3, \ | ||
| 127 | .gain = 8, \ | ||
| 128 | .reference_voltage = 16, \ | ||
| 129 | .noise_cancel_mode = 4, \ | ||
| 130 | .cal_type = TYPE_ONE_POINT_TRIMMING, \ | ||
| 131 | .efuse_value = 55, \ | ||
| 132 | .min_efuse_value = 40, \ | ||
| 133 | .max_efuse_value = 100, \ | ||
| 134 | .first_point_trim = 25, \ | ||
| 135 | .second_point_trim = 85, \ | ||
| 136 | .default_temp_offset = 50, \ | ||
| 137 | .freq_tab[0] = { \ | ||
| 138 | .freq_clip_max = 1400 * 1000, \ | ||
| 139 | .temp_level = 70, \ | ||
| 140 | }, \ | ||
| 141 | .freq_tab[1] = { \ | ||
| 142 | .freq_clip_max = 400 * 1000, \ | ||
| 143 | .temp_level = 95, \ | ||
| 144 | }, \ | ||
| 145 | .freq_tab_count = 2 | ||
| 146 | |||
| 147 | struct exynos_tmu_init_data const exynos4412_default_tmu_data = { | ||
| 148 | .tmu_data = { | ||
| 149 | { | ||
| 150 | EXYNOS4412_TMU_DATA, | ||
| 151 | .type = SOC_ARCH_EXYNOS4412, | ||
| 152 | }, | ||
| 153 | }, | ||
| 154 | .tmu_count = 1, | ||
| 155 | }; | ||
| 156 | |||
| 157 | struct exynos_tmu_init_data const exynos5250_default_tmu_data = { | ||
| 158 | .tmu_data = { | ||
| 159 | { | ||
| 160 | EXYNOS4412_TMU_DATA, | ||
| 161 | .type = SOC_ARCH_EXYNOS5250, | ||
| 162 | }, | ||
| 163 | }, | ||
| 164 | .tmu_count = 1, | ||
| 165 | }; | ||
| 166 | |||
| 167 | #define __EXYNOS5260_TMU_DATA \ | ||
| 168 | .threshold_falling = 10, \ | ||
| 169 | .trigger_levels[0] = 85, \ | ||
| 170 | .trigger_levels[1] = 103, \ | ||
| 171 | .trigger_levels[2] = 110, \ | ||
| 172 | .trigger_levels[3] = 120, \ | ||
| 173 | .trigger_enable[0] = true, \ | ||
| 174 | .trigger_enable[1] = true, \ | ||
| 175 | .trigger_enable[2] = true, \ | ||
| 176 | .trigger_enable[3] = false, \ | ||
| 177 | .trigger_type[0] = THROTTLE_ACTIVE, \ | ||
| 178 | .trigger_type[1] = THROTTLE_ACTIVE, \ | ||
| 179 | .trigger_type[2] = SW_TRIP, \ | ||
| 180 | .trigger_type[3] = HW_TRIP, \ | ||
| 181 | .max_trigger_level = 4, \ | ||
| 182 | .non_hw_trigger_levels = 3, \ | ||
| 183 | .gain = 8, \ | ||
| 184 | .reference_voltage = 16, \ | ||
| 185 | .noise_cancel_mode = 4, \ | ||
| 186 | .cal_type = TYPE_ONE_POINT_TRIMMING, \ | ||
| 187 | .efuse_value = 55, \ | ||
| 188 | .min_efuse_value = 40, \ | ||
| 189 | .max_efuse_value = 100, \ | ||
| 190 | .first_point_trim = 25, \ | ||
| 191 | .second_point_trim = 85, \ | ||
| 192 | .default_temp_offset = 50, \ | ||
| 193 | .freq_tab[0] = { \ | ||
| 194 | .freq_clip_max = 800 * 1000, \ | ||
| 195 | .temp_level = 85, \ | ||
| 196 | }, \ | ||
| 197 | .freq_tab[1] = { \ | ||
| 198 | .freq_clip_max = 200 * 1000, \ | ||
| 199 | .temp_level = 103, \ | ||
| 200 | }, \ | ||
| 201 | .freq_tab_count = 2, \ | ||
| 202 | |||
| 203 | #define EXYNOS5260_TMU_DATA \ | ||
| 204 | __EXYNOS5260_TMU_DATA \ | ||
| 205 | .type = SOC_ARCH_EXYNOS5260 | ||
| 206 | |||
| 207 | struct exynos_tmu_init_data const exynos5260_default_tmu_data = { | ||
| 208 | .tmu_data = { | ||
| 209 | { EXYNOS5260_TMU_DATA }, | ||
| 210 | { EXYNOS5260_TMU_DATA }, | ||
| 211 | { EXYNOS5260_TMU_DATA }, | ||
| 212 | { EXYNOS5260_TMU_DATA }, | ||
| 213 | { EXYNOS5260_TMU_DATA }, | ||
| 214 | }, | ||
| 215 | .tmu_count = 5, | ||
| 216 | }; | ||
| 217 | |||
| 218 | #define EXYNOS5420_TMU_DATA \ | ||
| 219 | __EXYNOS5260_TMU_DATA \ | ||
| 220 | .type = SOC_ARCH_EXYNOS5420 | ||
| 221 | |||
| 222 | #define EXYNOS5420_TMU_DATA_SHARED \ | ||
| 223 | __EXYNOS5260_TMU_DATA \ | ||
| 224 | .type = SOC_ARCH_EXYNOS5420_TRIMINFO | ||
| 225 | |||
| 226 | struct exynos_tmu_init_data const exynos5420_default_tmu_data = { | ||
| 227 | .tmu_data = { | ||
| 228 | { EXYNOS5420_TMU_DATA }, | ||
| 229 | { EXYNOS5420_TMU_DATA }, | ||
| 230 | { EXYNOS5420_TMU_DATA_SHARED }, | ||
| 231 | { EXYNOS5420_TMU_DATA_SHARED }, | ||
| 232 | { EXYNOS5420_TMU_DATA_SHARED }, | ||
| 233 | }, | ||
| 234 | .tmu_count = 5, | ||
| 235 | }; | ||
| 236 | |||
| 237 | #define EXYNOS5440_TMU_DATA \ | ||
| 238 | .trigger_levels[0] = 100, \ | ||
| 239 | .trigger_levels[4] = 105, \ | ||
| 240 | .trigger_enable[0] = 1, \ | ||
| 241 | .trigger_type[0] = SW_TRIP, \ | ||
| 242 | .trigger_type[4] = HW_TRIP, \ | ||
| 243 | .max_trigger_level = 5, \ | ||
| 244 | .non_hw_trigger_levels = 1, \ | ||
| 245 | .gain = 5, \ | ||
| 246 | .reference_voltage = 16, \ | ||
| 247 | .noise_cancel_mode = 4, \ | ||
| 248 | .cal_type = TYPE_ONE_POINT_TRIMMING, \ | ||
| 249 | .efuse_value = 0x5b2d, \ | ||
| 250 | .min_efuse_value = 16, \ | ||
| 251 | .max_efuse_value = 76, \ | ||
| 252 | .first_point_trim = 25, \ | ||
| 253 | .second_point_trim = 70, \ | ||
| 254 | .default_temp_offset = 25, \ | ||
| 255 | .type = SOC_ARCH_EXYNOS5440 | ||
| 256 | |||
| 257 | struct exynos_tmu_init_data const exynos5440_default_tmu_data = { | ||
| 258 | .tmu_data = { | ||
| 259 | { EXYNOS5440_TMU_DATA } , | ||
| 260 | { EXYNOS5440_TMU_DATA } , | ||
| 261 | { EXYNOS5440_TMU_DATA } , | ||
| 262 | }, | ||
| 263 | .tmu_count = 3, | ||
| 264 | }; | ||
diff --git a/include/dt-bindings/thermal/thermal_exynos.h b/include/dt-bindings/thermal/thermal_exynos.h new file mode 100644 index 000000000000..0646500bca69 --- /dev/null +++ b/include/dt-bindings/thermal/thermal_exynos.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * thermal_exynos.h - Samsung EXYNOS TMU device tree definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Samsung Electronics | ||
| 5 | * Lukasz Majewski <l.majewski@samsung.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef _EXYNOS_THERMAL_TMU_DT_H | ||
| 20 | #define _EXYNOS_THERMAL_TMU_DT_H | ||
| 21 | |||
| 22 | #define TYPE_ONE_POINT_TRIMMING 0 | ||
| 23 | #define TYPE_ONE_POINT_TRIMMING_25 1 | ||
| 24 | #define TYPE_ONE_POINT_TRIMMING_85 2 | ||
| 25 | #define TYPE_TWO_POINT_TRIMMING 3 | ||
| 26 | #define TYPE_NONE 4 | ||
| 27 | |||
| 28 | #endif /* _EXYNOS_THERMAL_TMU_DT_H */ | ||
