ipq806x: add ipq806x specific tsens driver
Current upstream driver doesnt fully support ipq806x devices ipq806x has 11 sensors, the upstream one doesn't allow to check sensors 0-4, only 5-10. A specific driver for ipq806x has been found in Qualcomm SDK repo. https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c089e464cd7ce652419a0dc44d7959ce4d24b8a5 https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c23d94b702c4182862e7f5051a2b7d00bb922a29 https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=742f3684b62a6b9f082cb49404b1a92dc0b16bf5 https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c0a9b2e2a382c152fa128f5b864c800dd6dfb311 Merging it into LEDE with this commit. Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
This commit is contained in:
		 Pavel Kubelun
					Pavel Kubelun
				
			
				
					committed by
					
						 John Crispin
						John Crispin
					
				
			
			
				
	
			
			
			 John Crispin
						John Crispin
					
				
			
						parent
						
							02fe942337
						
					
				
				
					commit
					dc32d0a53c
				
			| @@ -78,86 +78,354 @@ | |||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	thermal-zones { | 	thermal-zones { | ||||||
| 		cpu-thermal0 { | 		tsens_tz_sensor0 { | ||||||
| 			polling-delay-passive = <250>; | 			polling-delay-passive = <0>; | ||||||
| 			polling-delay = <1000>; | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 0>; | ||||||
| 			thermal-sensors = <&gcc 5>; |  | ||||||
| 			coefficients = <1132 0>; |  | ||||||
|  |  | ||||||
| 			trips { | 			trips { | ||||||
| 				cpu_alert0: trip0 { | 				cpu-critical-hi { | ||||||
| 					temperature = <75000>; | 					temperature = <125>; | ||||||
| 					hysteresis = <2000>; | 					hysteresis = <2>; | ||||||
| 					type = "passive"; | 					type = "critical_high"; | ||||||
| 				}; | 				}; | ||||||
| 				cpu_crit0: trip1 { |  | ||||||
| 					temperature = <110000>; | 				cpu-config-hi { | ||||||
| 					hysteresis = <2000>; | 					temperature = <105>; | ||||||
| 					type = "critical"; | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
| 				}; | 				}; | ||||||
| 			}; | 			}; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		cpu-thermal1 { | 		tsens_tz_sensor1 { | ||||||
| 			polling-delay-passive = <250>; | 			polling-delay-passive = <0>; | ||||||
| 			polling-delay = <1000>; | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 1>; | ||||||
| 			thermal-sensors = <&gcc 6>; |  | ||||||
| 			coefficients = <1132 0>; |  | ||||||
|  |  | ||||||
| 			trips { | 			trips { | ||||||
| 				cpu_alert1: trip0 { | 				cpu-critical-hi { | ||||||
| 					temperature = <75000>; | 					temperature = <125>; | ||||||
| 					hysteresis = <2000>; | 					hysteresis = <2>; | ||||||
| 					type = "passive"; | 					type = "critical_high"; | ||||||
| 				}; | 				}; | ||||||
| 				cpu_crit1: trip1 { |  | ||||||
| 					temperature = <110000>; | 				cpu-config-hi { | ||||||
| 					hysteresis = <2000>; | 					temperature = <105>; | ||||||
| 					type = "critical"; | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
| 				}; | 				}; | ||||||
| 			}; | 			}; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		cpu-thermal2 { | 		tsens_tz_sensor2 { | ||||||
| 			polling-delay-passive = <250>; | 			polling-delay-passive = <0>; | ||||||
| 			polling-delay = <1000>; | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 2>; | ||||||
| 			thermal-sensors = <&gcc 7>; |  | ||||||
| 			coefficients = <1199 0>; |  | ||||||
|  |  | ||||||
| 			trips { | 			trips { | ||||||
| 				cpu_alert2: trip0 { | 				cpu-critical-hi { | ||||||
| 					temperature = <75000>; | 					temperature = <125>; | ||||||
| 					hysteresis = <2000>; | 					hysteresis = <2>; | ||||||
| 					type = "passive"; | 					type = "critical_high"; | ||||||
| 				}; | 				}; | ||||||
| 				cpu_crit2: trip1 { |  | ||||||
| 					temperature = <110000>; | 				cpu-config-hi { | ||||||
| 					hysteresis = <2000>; | 					temperature = <105>; | ||||||
| 					type = "critical"; | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
| 				}; | 				}; | ||||||
| 			}; | 			}; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		cpu-thermal3 { | 		tsens_tz_sensor3 { | ||||||
| 			polling-delay-passive = <250>; | 			polling-delay-passive = <0>; | ||||||
| 			polling-delay = <1000>; | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 3>; | ||||||
| 			thermal-sensors = <&gcc 8>; |  | ||||||
| 			coefficients = <1132 0>; |  | ||||||
|  |  | ||||||
| 			trips { | 			trips { | ||||||
| 				cpu_alert3: trip0 { | 				cpu-critical-hi { | ||||||
| 					temperature = <75000>; | 					temperature = <125>; | ||||||
| 					hysteresis = <2000>; | 					hysteresis = <2>; | ||||||
| 					type = "passive"; | 					type = "critical_high"; | ||||||
| 				}; | 				}; | ||||||
| 				cpu_crit3: trip1 { |  | ||||||
| 					temperature = <110000>; | 				cpu-config-hi { | ||||||
| 					hysteresis = <2000>; | 					temperature = <105>; | ||||||
| 					type = "critical"; | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor4 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 4>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor5 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 5>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor6 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 6>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor7 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 7>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor8 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 8>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor9 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 9>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens_tz_sensor10 { | ||||||
|  | 			polling-delay-passive = <0>; | ||||||
|  | 			polling-delay = <0>; | ||||||
|  | 			thermal-sensors = <&tsens 10>; | ||||||
|  |  | ||||||
|  | 			trips { | ||||||
|  | 				cpu-critical-hi { | ||||||
|  | 					temperature = <125>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_high"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-hi { | ||||||
|  | 					temperature = <105>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_hi"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-config-lo { | ||||||
|  | 					temperature = <95>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "configurable_lo"; | ||||||
|  | 				}; | ||||||
|  |  | ||||||
|  | 				cpu-critical-low { | ||||||
|  | 					temperature = <0>; | ||||||
|  | 					hysteresis = <2>; | ||||||
|  | 					type = "critical_low"; | ||||||
| 				}; | 				}; | ||||||
| 			}; | 			}; | ||||||
| 		}; | 		}; | ||||||
| @@ -273,15 +541,14 @@ | |||||||
|  |  | ||||||
| 		qfprom: qfprom@700000 { | 		qfprom: qfprom@700000 { | ||||||
| 			compatible = "qcom,qfprom", "syscon"; | 			compatible = "qcom,qfprom", "syscon"; | ||||||
| 			reg = <0x00700000 0x1000>; | 			reg = <0x700000 0x1000>; | ||||||
| 			#address-cells = <1>; | 			#address-cells = <1>; | ||||||
| 			#size-cells = <1>; | 			#size-cells = <1>; | ||||||
| 			ranges; | 			status = "okay"; | ||||||
|  | 			tsens_calib: calib@400 { | ||||||
| 			tsens_calib: calib { |  | ||||||
| 				reg = <0x400 0x10>; | 				reg = <0x400 0x10>; | ||||||
| 			}; | 			}; | ||||||
| 			tsens_backup: backup_calib { | 			tsens_backup: backup@410 { | ||||||
| 				reg = <0x410 0x10>; | 				reg = <0x410 0x10>; | ||||||
| 			}; | 			}; | ||||||
| 		}; | 		}; | ||||||
| @@ -620,11 +887,17 @@ | |||||||
| 		gcc: clock-controller@900000 { | 		gcc: clock-controller@900000 { | ||||||
| 			compatible = "qcom,gcc-ipq8064"; | 			compatible = "qcom,gcc-ipq8064"; | ||||||
| 			reg = <0x00900000 0x4000>; | 			reg = <0x00900000 0x4000>; | ||||||
| 			nvmem-cells = <&tsens_calib>, <&tsens_backup>; |  | ||||||
| 			nvmem-cell-names = "calib", "calib_backup"; |  | ||||||
| 			#clock-cells = <1>; | 			#clock-cells = <1>; | ||||||
| 			#reset-cells = <1>; | 			#reset-cells = <1>; | ||||||
| 			#power-domain-cells = <1>; | 			#power-domain-cells = <1>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		tsens: thermal-sensor@900000 { | ||||||
|  | 			compatible = "qcom,ipq8064-tsens"; | ||||||
|  | 			reg = <0x900000 0x3680>; | ||||||
|  | 			nvmem-cells = <&tsens_calib>, <&tsens_backup>; | ||||||
|  | 			nvmem-cell-names = "calib", "calib_backup"; | ||||||
|  | 			interrupts = <0 178 0>; | ||||||
| 			#thermal-sensor-cells = <1>; | 			#thermal-sensor-cells = <1>; | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ Signed-off-by: John Crispin <john@phrozen.org> | |||||||
|  		.hw.init = &(struct clk_init_data){ |  		.hw.init = &(struct clk_init_data){ | ||||||
|  			.name = "gsbi1_h_clk", |  			.name = "gsbi1_h_clk", | ||||||
|  			.ops = &clk_branch_ops, |  			.ops = &clk_branch_ops, | ||||||
| ++			.flags = CLK_IGNORE_UNUSED, | +			.flags = CLK_IGNORE_UNUSED, | ||||||
|  		}, |  		}, | ||||||
|  	}, |  	}, | ||||||
|  }; |  }; | ||||||
|   | |||||||
| @@ -0,0 +1,638 @@ | |||||||
|  | From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Rajith Cherian <rajith@codeaurora.org> | ||||||
|  | Date: Tue, 14 Feb 2017 18:30:43 +0530 | ||||||
|  | Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064 | ||||||
|  |  | ||||||
|  | Add TSENS driver template to support IPQ8064. | ||||||
|  | This is a base file copied from tsens-8960.c | ||||||
|  |  | ||||||
|  | Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7 | ||||||
|  | Signed-off-by: Rajith Cherian <rajith@codeaurora.org> | ||||||
|  |  | ||||||
|  | ipq8064: tsens: TSENS driver support for IPQ8064 | ||||||
|  |  | ||||||
|  | Support for IPQ8064 tsens driver. The driver works | ||||||
|  | with the thermal framework. The driver overrides the | ||||||
|  | following fucntionalities: | ||||||
|  |  | ||||||
|  | 1. Get current temperature. | ||||||
|  | 2. Get/Set trip temperatures. | ||||||
|  | 3. Enabled/Disable trip points. | ||||||
|  | 4. ISR for threshold generated interrupt. | ||||||
|  | 5. Notify userspace when trip points are hit. | ||||||
|  |  | ||||||
|  | Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918 | ||||||
|  | Signed-off-by: Rajith Cherian <rajith@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/thermal/qcom-tsens.txt     |   1 + | ||||||
|  |  drivers/thermal/qcom/Makefile                      |   3 +- | ||||||
|  |  drivers/thermal/qcom/tsens-ipq8064.c               | 551 +++++++++++++++++++++ | ||||||
|  |  drivers/thermal/qcom/tsens.c                       |   3 + | ||||||
|  |  drivers/thermal/qcom/tsens.h                       |   2 +- | ||||||
|  |  5 files changed, 558 insertions(+), 2 deletions(-) | ||||||
|  |  create mode 100644 drivers/thermal/qcom/tsens-ipq8064.c | ||||||
|  |  | ||||||
|  | diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | index 292ed89..f4a76f6 100644 | ||||||
|  | --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | @@ -5,6 +5,7 @@ Required properties: | ||||||
|  |   - "qcom,msm8916-tsens" : For 8916 Family of SoCs | ||||||
|  |   - "qcom,msm8974-tsens" : For 8974 Family of SoCs | ||||||
|  |   - "qcom,msm8996-tsens" : For 8996 Family of SoCs | ||||||
|  | + - "qcom,ipq8064-tsens" : For IPQ8064 | ||||||
|  |   | ||||||
|  |  - reg: Address range of the thermal registers | ||||||
|  |  - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. | ||||||
|  | diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile | ||||||
|  | index 2cc2193..cc07cf4 100644 | ||||||
|  | --- a/drivers/thermal/qcom/Makefile | ||||||
|  | +++ b/drivers/thermal/qcom/Makefile | ||||||
|  | @@ -1,2 +1,3 @@ | ||||||
|  |  obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o | ||||||
|  | -qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o | ||||||
|  | +qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o \ | ||||||
|  | +				tsens-ipq8064.o | ||||||
|  | diff --git a/drivers/thermal/qcom/tsens-ipq8064.c b/drivers/thermal/qcom/tsens-ipq8064.c | ||||||
|  | new file mode 100644 | ||||||
|  | index 0000000..c52888f | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/thermal/qcom/tsens-ipq8064.c | ||||||
|  | @@ -0,0 +1,551 @@ | ||||||
|  | +/* | ||||||
|  | + * Copyright (c) 2015, The Linux Foundation. All rights reserved. | ||||||
|  | + * | ||||||
|  | + * This program is free software; you can redistribute it and/or modify | ||||||
|  | + * it under the terms of the GNU General Public License version 2 and | ||||||
|  | + * only version 2 as published by the Free Software Foundation. | ||||||
|  | + * | ||||||
|  | + * This program is distributed in the hope that it will be useful, | ||||||
|  | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | + * GNU General Public License for more details. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/bitops.h> | ||||||
|  | +#include <linux/regmap.h> | ||||||
|  | +#include <linux/thermal.h> | ||||||
|  | +#include <linux/nvmem-consumer.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | +#include "tsens.h" | ||||||
|  | + | ||||||
|  | +#define CAL_MDEGC		30000 | ||||||
|  | + | ||||||
|  | +#define CONFIG_ADDR		0x3640 | ||||||
|  | +/* CONFIG_ADDR bitmasks */ | ||||||
|  | +#define CONFIG			0x9b | ||||||
|  | +#define CONFIG_MASK		0xf | ||||||
|  | +#define CONFIG_SHIFT		0 | ||||||
|  | + | ||||||
|  | +#define STATUS_CNTL_8064	0x3660 | ||||||
|  | +#define CNTL_ADDR		0x3620 | ||||||
|  | +/* CNTL_ADDR bitmasks */ | ||||||
|  | +#define EN			BIT(0) | ||||||
|  | +#define SW_RST			BIT(1) | ||||||
|  | +#define SENSOR0_EN		BIT(3) | ||||||
|  | +#define SLP_CLK_ENA		BIT(26) | ||||||
|  | +#define MEASURE_PERIOD		1 | ||||||
|  | +#define SENSOR0_SHIFT		3 | ||||||
|  | + | ||||||
|  | +/* INT_STATUS_ADDR bitmasks */ | ||||||
|  | +#define MIN_STATUS_MASK		BIT(0) | ||||||
|  | +#define LOWER_STATUS_CLR	BIT(1) | ||||||
|  | +#define UPPER_STATUS_CLR	BIT(2) | ||||||
|  | +#define MAX_STATUS_MASK		BIT(3) | ||||||
|  | + | ||||||
|  | +#define THRESHOLD_ADDR		0x3624 | ||||||
|  | +/* THRESHOLD_ADDR bitmasks */ | ||||||
|  | +#define THRESHOLD_MAX_CODE		0xff | ||||||
|  | +#define THRESHOLD_MIN_CODE		0 | ||||||
|  | +#define THRESHOLD_MAX_LIMIT_SHIFT	24 | ||||||
|  | +#define THRESHOLD_MIN_LIMIT_SHIFT	16 | ||||||
|  | +#define THRESHOLD_UPPER_LIMIT_SHIFT	8 | ||||||
|  | +#define THRESHOLD_LOWER_LIMIT_SHIFT	0 | ||||||
|  | +#define THRESHOLD_MAX_LIMIT_MASK	(THRESHOLD_MAX_CODE << \ | ||||||
|  | +						THRESHOLD_MAX_LIMIT_SHIFT) | ||||||
|  | +#define THRESHOLD_MIN_LIMIT_MASK	(THRESHOLD_MAX_CODE << \ | ||||||
|  | +						THRESHOLD_MIN_LIMIT_SHIFT) | ||||||
|  | +#define THRESHOLD_UPPER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \ | ||||||
|  | +						THRESHOLD_UPPER_LIMIT_SHIFT) | ||||||
|  | +#define THRESHOLD_LOWER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \ | ||||||
|  | +						THRESHOLD_LOWER_LIMIT_SHIFT) | ||||||
|  | + | ||||||
|  | +/* Initial temperature threshold values */ | ||||||
|  | +#define LOWER_LIMIT_TH		0x9d /* 95C */ | ||||||
|  | +#define UPPER_LIMIT_TH		0xa6 /* 105C */ | ||||||
|  | +#define MIN_LIMIT_TH		0x0 | ||||||
|  | +#define MAX_LIMIT_TH		0xff | ||||||
|  | + | ||||||
|  | +#define S0_STATUS_ADDR		0x3628 | ||||||
|  | +#define STATUS_ADDR_OFFSET	2 | ||||||
|  | +#define SENSOR_STATUS_SIZE	4 | ||||||
|  | +#define INT_STATUS_ADDR		0x363c | ||||||
|  | +#define TRDY_MASK		BIT(7) | ||||||
|  | +#define TIMEOUT_US		100 | ||||||
|  | + | ||||||
|  | +#define TSENS_EN		BIT(0) | ||||||
|  | +#define TSENS_SW_RST		BIT(1) | ||||||
|  | +#define TSENS_ADC_CLK_SEL	BIT(2) | ||||||
|  | +#define SENSOR0_EN		BIT(3) | ||||||
|  | +#define SENSOR1_EN		BIT(4) | ||||||
|  | +#define SENSOR2_EN		BIT(5) | ||||||
|  | +#define SENSOR3_EN		BIT(6) | ||||||
|  | +#define SENSOR4_EN		BIT(7) | ||||||
|  | +#define SENSORS_EN		(SENSOR0_EN | SENSOR1_EN | \ | ||||||
|  | +				SENSOR2_EN | SENSOR3_EN | SENSOR4_EN) | ||||||
|  | +#define TSENS_8064_SENSOR5_EN				BIT(8) | ||||||
|  | +#define TSENS_8064_SENSOR6_EN				BIT(9) | ||||||
|  | +#define TSENS_8064_SENSOR7_EN				BIT(10) | ||||||
|  | +#define TSENS_8064_SENSOR8_EN				BIT(11) | ||||||
|  | +#define TSENS_8064_SENSOR9_EN				BIT(12) | ||||||
|  | +#define TSENS_8064_SENSOR10_EN				BIT(13) | ||||||
|  | +#define TSENS_8064_SENSORS_EN				(SENSORS_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR5_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR6_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR7_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR8_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR9_EN | \ | ||||||
|  | +						TSENS_8064_SENSOR10_EN) | ||||||
|  | + | ||||||
|  | +#define TSENS_8064_SEQ_SENSORS	5 | ||||||
|  | +#define TSENS_8064_S4_S5_OFFSET	40 | ||||||
|  | +#define TSENS_FACTOR		1000 | ||||||
|  | + | ||||||
|  | +/* Trips: from very hot to very cold */ | ||||||
|  | +enum tsens_trip_type { | ||||||
|  | +	TSENS_TRIP_STAGE3 = 0, | ||||||
|  | +	TSENS_TRIP_STAGE2, | ||||||
|  | +	TSENS_TRIP_STAGE1, | ||||||
|  | +	TSENS_TRIP_STAGE0, | ||||||
|  | +	TSENS_TRIP_NUM, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +u32 tsens_8064_slope[] = { | ||||||
|  | +			1176, 1176, 1154, 1176, | ||||||
|  | +			1111, 1132, 1132, 1199, | ||||||
|  | +			1132, 1199, 1132 | ||||||
|  | +			}; | ||||||
|  | + | ||||||
|  | +/* Temperature on y axis and ADC-code on x-axis */ | ||||||
|  | +static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s) | ||||||
|  | +{ | ||||||
|  | +	int degcbeforefactor, degc; | ||||||
|  | + | ||||||
|  | +	degcbeforefactor = (adc_code * s->slope) + s->offset; | ||||||
|  | + | ||||||
|  | +	if (degcbeforefactor == 0) | ||||||
|  | +		degc = degcbeforefactor; | ||||||
|  | +	else if (degcbeforefactor > 0) | ||||||
|  | +		degc = (degcbeforefactor + TSENS_FACTOR/2) | ||||||
|  | +			/ TSENS_FACTOR; | ||||||
|  | +	else | ||||||
|  | +		degc = (degcbeforefactor - TSENS_FACTOR/2) | ||||||
|  | +			/ TSENS_FACTOR; | ||||||
|  | + | ||||||
|  | +	return degc; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int degC_to_code(int degC, const struct tsens_sensor *s) | ||||||
|  | +{ | ||||||
|  | +	int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2)) | ||||||
|  | +			/ s->slope; | ||||||
|  | + | ||||||
|  | +	if (code > THRESHOLD_MAX_CODE) | ||||||
|  | +		code = THRESHOLD_MAX_CODE; | ||||||
|  | +	else if (code < THRESHOLD_MIN_CODE) | ||||||
|  | +		code = THRESHOLD_MIN_CODE; | ||||||
|  | +	return code; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int suspend_ipq8064(struct tsens_device *tmdev) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | +	unsigned int mask; | ||||||
|  | +	struct regmap *map = tmdev->map; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	mask = SLP_CLK_ENA | EN; | ||||||
|  | + | ||||||
|  | +	ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int resume_ipq8064(struct tsens_device *tmdev) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | +	struct regmap *map = tmdev->map; | ||||||
|  | + | ||||||
|  | +	ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void notify_uspace_tsens_fn(struct work_struct *work) | ||||||
|  | +{ | ||||||
|  | +	struct tsens_sensor *s = container_of(work, struct tsens_sensor, | ||||||
|  | +								notify_work); | ||||||
|  | + | ||||||
|  | +	sysfs_notify(&s->tzd->device.kobj, NULL, "type"); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void tsens_scheduler_fn(struct work_struct *work) | ||||||
|  | +{ | ||||||
|  | +	struct tsens_device *tmdev = container_of(work, struct tsens_device, | ||||||
|  | +					tsens_work); | ||||||
|  | +	unsigned int threshold, threshold_low, code, reg, sensor, mask; | ||||||
|  | +	unsigned int sensor_addr; | ||||||
|  | +	bool upper_th_x, lower_th_x; | ||||||
|  | +	int adc_code, ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®); | ||||||
|  | +	if (ret) | ||||||
|  | +		return; | ||||||
|  | +	reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR; | ||||||
|  | +	ret = regmap_write(tmdev->map, STATUS_CNTL_8064, reg); | ||||||
|  | +	if (ret) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR); | ||||||
|  | +	ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &threshold); | ||||||
|  | +	if (ret) | ||||||
|  | +		return; | ||||||
|  | +	threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) | ||||||
|  | +				>> THRESHOLD_LOWER_LIMIT_SHIFT; | ||||||
|  | +	threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) | ||||||
|  | +				>> THRESHOLD_UPPER_LIMIT_SHIFT; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®); | ||||||
|  | +	if (ret) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, CNTL_ADDR, &sensor); | ||||||
|  | +	if (ret) | ||||||
|  | +		return; | ||||||
|  | +	sensor &= (uint32_t) TSENS_8064_SENSORS_EN; | ||||||
|  | +	sensor >>= SENSOR0_SHIFT; | ||||||
|  | + | ||||||
|  | +	/* Constraint: There is only 1 interrupt control register for all | ||||||
|  | +	 * 11 temperature sensor. So monitoring more than 1 sensor based | ||||||
|  | +	 * on interrupts will yield inconsistent result. To overcome this | ||||||
|  | +	 * issue we will monitor only sensor 0 which is the master sensor. | ||||||
|  | +	 */ | ||||||
|  | + | ||||||
|  | +	/* Skip if the sensor is disabled */ | ||||||
|  | +	if (sensor & 1) { | ||||||
|  | +		ret = regmap_read(tmdev->map, tmdev->sensor[0].status, &code); | ||||||
|  | +		if (ret) | ||||||
|  | +			return; | ||||||
|  | +		upper_th_x = code >= threshold; | ||||||
|  | +		lower_th_x = code <= threshold_low; | ||||||
|  | +		if (upper_th_x) | ||||||
|  | +			mask |= UPPER_STATUS_CLR; | ||||||
|  | +		if (lower_th_x) | ||||||
|  | +			mask |= LOWER_STATUS_CLR; | ||||||
|  | +		if (upper_th_x || lower_th_x) { | ||||||
|  | +			/* Notify user space */ | ||||||
|  | +			schedule_work(&tmdev->sensor[0].notify_work); | ||||||
|  | +			regmap_read(tmdev->map, sensor_addr, &adc_code); | ||||||
|  | +			pr_debug("Trigger (%d degrees) for sensor %d\n", | ||||||
|  | +				code_to_degC(adc_code, &tmdev->sensor[0]), 0); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask); | ||||||
|  | + | ||||||
|  | +	/* force memory to sync */ | ||||||
|  | +	mb(); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static irqreturn_t tsens_isr(int irq, void *data) | ||||||
|  | +{ | ||||||
|  | +	struct tsens_device *tmdev = data; | ||||||
|  | + | ||||||
|  | +	schedule_work(&tmdev->tsens_work); | ||||||
|  | +	return IRQ_HANDLED; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void hw_init(struct tsens_device *tmdev) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | +	unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0; | ||||||
|  | +	unsigned int reg_status_cntl = 0; | ||||||
|  | + | ||||||
|  | +	regmap_read(tmdev->map, CNTL_ADDR, ®_cntl); | ||||||
|  | +	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl | TSENS_SW_RST); | ||||||
|  | + | ||||||
|  | +	reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) | ||||||
|  | +		| (((1 << tmdev->num_sensors) - 1) << SENSOR0_SHIFT); | ||||||
|  | +	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); | ||||||
|  | +	regmap_read(tmdev->map, STATUS_CNTL_8064, ®_status_cntl); | ||||||
|  | +	reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR | ||||||
|  | +			| MIN_STATUS_MASK | MAX_STATUS_MASK; | ||||||
|  | +	regmap_write(tmdev->map, STATUS_CNTL_8064, reg_status_cntl); | ||||||
|  | +	reg_cntl |= TSENS_EN; | ||||||
|  | +	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); | ||||||
|  | + | ||||||
|  | +	regmap_read(tmdev->map, CONFIG_ADDR, ®_cfg); | ||||||
|  | +	reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT); | ||||||
|  | +	regmap_write(tmdev->map, CONFIG_ADDR, reg_cfg); | ||||||
|  | + | ||||||
|  | +	reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT) | ||||||
|  | +		| (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT) | ||||||
|  | +		| (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) | ||||||
|  | +		| (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT); | ||||||
|  | + | ||||||
|  | +	regmap_write(tmdev->map, THRESHOLD_ADDR, reg_thr); | ||||||
|  | + | ||||||
|  | +	ret = devm_request_irq(tmdev->dev, tmdev->tsens_irq, tsens_isr, | ||||||
|  | +			IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev); | ||||||
|  | +	if (ret < 0) { | ||||||
|  | +		pr_err("%s: request_irq FAIL: %d\n", __func__, ret); | ||||||
|  | +		return; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int init_ipq8064(struct tsens_device *tmdev) | ||||||
|  | +{ | ||||||
|  | +	int ret, i; | ||||||
|  | +	u32 reg_cntl, offset = 0; | ||||||
|  | + | ||||||
|  | +	init_common(tmdev); | ||||||
|  | +	if (!tmdev->map) | ||||||
|  | +		return -ENODEV; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The status registers for each sensor are discontiguous | ||||||
|  | +	 * because some SoCs have 5 sensors while others have more | ||||||
|  | +	 * but the control registers stay in the same place, i.e | ||||||
|  | +	 * directly after the first 5 status registers. | ||||||
|  | +	 */ | ||||||
|  | +	for (i = 0; i < tmdev->num_sensors; i++) { | ||||||
|  | +		if (i >= TSENS_8064_SEQ_SENSORS) | ||||||
|  | +			offset = TSENS_8064_S4_S5_OFFSET; | ||||||
|  | + | ||||||
|  | +		tmdev->sensor[i].status = S0_STATUS_ADDR + offset | ||||||
|  | +					+ (i << STATUS_ADDR_OFFSET); | ||||||
|  | +		tmdev->sensor[i].slope = tsens_8064_slope[i]; | ||||||
|  | +		INIT_WORK(&tmdev->sensor[i].notify_work, | ||||||
|  | +						notify_uspace_tsens_fn); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	reg_cntl = SW_RST; | ||||||
|  | +	ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); | ||||||
|  | +	reg_cntl &= ~SW_RST; | ||||||
|  | +	ret = regmap_update_bits(tmdev->map, CONFIG_ADDR, | ||||||
|  | +					 CONFIG_MASK, CONFIG); | ||||||
|  | + | ||||||
|  | +	reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; | ||||||
|  | +	ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	reg_cntl |= EN; | ||||||
|  | +	ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int calibrate_ipq8064(struct tsens_device *tmdev) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | +	char *data, *data_backup; | ||||||
|  | + | ||||||
|  | +	ssize_t num_read = tmdev->num_sensors; | ||||||
|  | +	struct tsens_sensor *s = tmdev->sensor; | ||||||
|  | + | ||||||
|  | +	data = qfprom_read(tmdev->dev, "calib"); | ||||||
|  | +	if (IS_ERR(data)) { | ||||||
|  | +		pr_err("Calibration not found.\n"); | ||||||
|  | +		return PTR_ERR(data); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	data_backup = qfprom_read(tmdev->dev, "calib_backup"); | ||||||
|  | +	if (IS_ERR(data_backup)) { | ||||||
|  | +		pr_err("Backup calibration not found.\n"); | ||||||
|  | +		return PTR_ERR(data_backup); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < num_read; i++) { | ||||||
|  | +		s[i].calib_data = readb_relaxed(data + i); | ||||||
|  | +		s[i].calib_data_backup = readb_relaxed(data_backup + i); | ||||||
|  | + | ||||||
|  | +		if (s[i].calib_data_backup) | ||||||
|  | +			s[i].calib_data = s[i].calib_data_backup; | ||||||
|  | +		if (!s[i].calib_data) { | ||||||
|  | +			pr_err("QFPROM TSENS calibration data not present\n"); | ||||||
|  | +			return -ENODEV; | ||||||
|  | +		} | ||||||
|  | +		s[i].slope = tsens_8064_slope[i]; | ||||||
|  | +		s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	hw_init(tmdev); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | +	u32 code, trdy; | ||||||
|  | +	const struct tsens_sensor *s = &tmdev->sensor[id]; | ||||||
|  | +	unsigned long timeout; | ||||||
|  | + | ||||||
|  | +	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); | ||||||
|  | +	do { | ||||||
|  | +		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy); | ||||||
|  | +		if (ret) | ||||||
|  | +			return ret; | ||||||
|  | +		if (!(trdy & TRDY_MASK)) | ||||||
|  | +			continue; | ||||||
|  | +		ret = regmap_read(tmdev->map, s->status, &code); | ||||||
|  | +		if (ret) | ||||||
|  | +			return ret; | ||||||
|  | +		*temp = code_to_degC(code, s); | ||||||
|  | +		return 0; | ||||||
|  | +	} while (time_before(jiffies, timeout)); | ||||||
|  | + | ||||||
|  | +	return -ETIMEDOUT; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int set_trip_temp_ipq8064(void *data, int trip, int temp) | ||||||
|  | +{ | ||||||
|  | +	unsigned int reg_th, reg_cntl; | ||||||
|  | +	int ret, code, code_chk, hi_code, lo_code; | ||||||
|  | +	const struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  | + | ||||||
|  | +	code_chk = code = degC_to_code(temp, s); | ||||||
|  | + | ||||||
|  | +	if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®_cntl); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, THRESHOLD_ADDR, ®_th); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK) | ||||||
|  | +			>> THRESHOLD_UPPER_LIMIT_SHIFT; | ||||||
|  | +	lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK) | ||||||
|  | +			>> THRESHOLD_LOWER_LIMIT_SHIFT; | ||||||
|  | + | ||||||
|  | +	switch (trip) { | ||||||
|  | +	case TSENS_TRIP_STAGE3: | ||||||
|  | +		code <<= THRESHOLD_MAX_LIMIT_SHIFT; | ||||||
|  | +		reg_th &= ~THRESHOLD_MAX_LIMIT_MASK; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE2: | ||||||
|  | +		if (code_chk <= lo_code) | ||||||
|  | +			return -EINVAL; | ||||||
|  | +		code <<= THRESHOLD_UPPER_LIMIT_SHIFT; | ||||||
|  | +		reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE1: | ||||||
|  | +		if (code_chk >= hi_code) | ||||||
|  | +			return -EINVAL; | ||||||
|  | +		code <<= THRESHOLD_LOWER_LIMIT_SHIFT; | ||||||
|  | +		reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE0: | ||||||
|  | +		code <<= THRESHOLD_MIN_LIMIT_SHIFT; | ||||||
|  | +		reg_th &= ~THRESHOLD_MIN_LIMIT_MASK; | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = regmap_write(tmdev->map, THRESHOLD_ADDR, reg_th | code); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int set_trip_activate_ipq8064(void *data, int trip, | ||||||
|  | +					enum thermal_trip_activation_mode mode) | ||||||
|  | +{ | ||||||
|  | +	unsigned int reg_cntl, mask, val; | ||||||
|  | +	const struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	if (!tmdev || trip < 0) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, ®_cntl); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	switch (trip) { | ||||||
|  | +	case TSENS_TRIP_STAGE3: | ||||||
|  | +		mask = MAX_STATUS_MASK; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE2: | ||||||
|  | +		mask = UPPER_STATUS_CLR; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE1: | ||||||
|  | +		mask = LOWER_STATUS_CLR; | ||||||
|  | +		break; | ||||||
|  | +	case TSENS_TRIP_STAGE0: | ||||||
|  | +		mask = MIN_STATUS_MASK; | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) | ||||||
|  | +		val = reg_cntl | mask; | ||||||
|  | +	else | ||||||
|  | +		val = reg_cntl & ~mask; | ||||||
|  | + | ||||||
|  | +	ret = regmap_write(tmdev->map, STATUS_CNTL_8064, val); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	/* force memory to sync */ | ||||||
|  | +	mb(); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +const struct tsens_ops ops_ipq8064 = { | ||||||
|  | +	.init		= init_ipq8064, | ||||||
|  | +	.calibrate	= calibrate_ipq8064, | ||||||
|  | +	.get_temp	= get_temp_ipq8064, | ||||||
|  | +	.suspend	= suspend_ipq8064, | ||||||
|  | +	.resume		= resume_ipq8064, | ||||||
|  | +	.set_trip_temp	= set_trip_temp_ipq8064, | ||||||
|  | +	.set_trip_activate = set_trip_activate_ipq8064, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +const struct tsens_data data_ipq8064 = { | ||||||
|  | +	.num_sensors	= 11, | ||||||
|  | +	.ops		= &ops_ipq8064, | ||||||
|  | +}; | ||||||
|  | diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c | ||||||
|  | index 3f9fe6a..2d25593 100644 | ||||||
|  | --- a/drivers/thermal/qcom/tsens.c | ||||||
|  | +++ b/drivers/thermal/qcom/tsens.c | ||||||
|  | @@ -72,6 +72,9 @@ static const struct of_device_id tsens_table[] = { | ||||||
|  |  	}, { | ||||||
|  |  		.compatible = "qcom,msm8996-tsens", | ||||||
|  |  		.data = &data_8996, | ||||||
|  | +	}, { | ||||||
|  | +		.compatible = "qcom,ipq8064-tsens", | ||||||
|  | +		.data = &data_ipq8064, | ||||||
|  |  	}, | ||||||
|  |  	{} | ||||||
|  |  }; | ||||||
|  | diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h | ||||||
|  | index 911c197..31279a2 100644 | ||||||
|  | --- a/drivers/thermal/qcom/tsens.h | ||||||
|  | +++ b/drivers/thermal/qcom/tsens.h | ||||||
|  | @@ -89,6 +89,6 @@ void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32); | ||||||
|  |  int init_common(struct tsens_device *); | ||||||
|  |  int get_temp_common(struct tsens_device *, int, int *); | ||||||
|  |   | ||||||
|  | -extern const struct tsens_data data_8916, data_8974, data_8960, data_8996; | ||||||
|  | +extern const struct tsens_data data_8916, data_8974, data_8960, data_8996, data_ipq8064; | ||||||
|  |   | ||||||
|  |  #endif /* __QCOM_TSENS_H__ */ | ||||||
| @@ -0,0 +1,474 @@ | |||||||
|  | From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Rajith Cherian <rajith@codeaurora.org> | ||||||
|  | Date: Wed, 1 Feb 2017 19:00:26 +0530 | ||||||
|  | Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts | ||||||
|  |  | ||||||
|  | Provide support for adding configurable high and | ||||||
|  | configurable low trip temperatures. An interrupts is | ||||||
|  | also triggerred when these trip points are hit. The | ||||||
|  | interrupts can be activated or deactivated from sysfs. | ||||||
|  | This functionality is made available only if | ||||||
|  | CONFIG_THERMAL_WRITABLE_TRIPS is defined. | ||||||
|  |  | ||||||
|  | Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934 | ||||||
|  | Signed-off-by: Rajith Cherian <rajith@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/thermal/qcom-tsens.txt     |  4 ++ | ||||||
|  |  drivers/thermal/of-thermal.c                       | 63 ++++++++++++++++++---- | ||||||
|  |  drivers/thermal/qcom/tsens.c                       | 43 ++++++++++++--- | ||||||
|  |  drivers/thermal/qcom/tsens.h                       | 11 ++++ | ||||||
|  |  drivers/thermal/thermal_core.c                     | 44 ++++++++++++++- | ||||||
|  |  include/linux/thermal.h                            | 14 +++++ | ||||||
|  |  6 files changed, 162 insertions(+), 17 deletions(-) | ||||||
|  |  | ||||||
|  | diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | index f4a76f6..7c0a6a7 100644 | ||||||
|  | --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt | ||||||
|  | @@ -12,11 +12,15 @@ Required properties: | ||||||
|  |  - Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify | ||||||
|  |  nvmem cells | ||||||
|  |   | ||||||
|  | +Optional properties: | ||||||
|  | +- interrupts: Interrupt which gets triggered when threshold is hit | ||||||
|  | + | ||||||
|  |  Example: | ||||||
|  |  tsens: thermal-sensor@900000 { | ||||||
|  |  		compatible = "qcom,msm8916-tsens"; | ||||||
|  |  		reg = <0x4a8000 0x2000>; | ||||||
|  |  		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>; | ||||||
|  |  		nvmem-cell-names = "caldata", "calsel"; | ||||||
|  | +		interrupts = <0 178 0>; | ||||||
|  |  		#thermal-sensor-cells = <1>; | ||||||
|  |  	}; | ||||||
|  | diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c | ||||||
|  | index d04ec3b..d83697e 100644 | ||||||
|  | --- a/drivers/thermal/of-thermal.c | ||||||
|  | +++ b/drivers/thermal/of-thermal.c | ||||||
|  | @@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (!data->ops->get_temp) | ||||||
|  | +	if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EINVAL; | ||||||
|  |   | ||||||
|  |  	return data->ops->get_temp(data->sensor_data, temp); | ||||||
|  | @@ -106,7 +106,8 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (!data->ops || !data->ops->set_trips) | ||||||
|  | +	if (!data->ops || !data->ops->set_trips | ||||||
|  | +			|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EINVAL; | ||||||
|  |   | ||||||
|  |  	return data->ops->set_trips(data->sensor_data, low, high); | ||||||
|  | @@ -192,6 +193,9 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | +	if (data->mode == THERMAL_DEVICE_DISABLED) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  |  	return data->ops->set_emul_temp(data->sensor_data, temp); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -200,7 +204,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (!data->ops->get_trend) | ||||||
|  | +	if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EINVAL; | ||||||
|  |   | ||||||
|  |  	return data->ops->get_trend(data->sensor_data, trip, trend); | ||||||
|  | @@ -286,7 +290,9 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz, | ||||||
|  |  	mutex_unlock(&tz->lock); | ||||||
|  |   | ||||||
|  |  	data->mode = mode; | ||||||
|  | -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | ||||||
|  | + | ||||||
|  | +	if (mode == THERMAL_DEVICE_ENABLED) | ||||||
|  | +		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | ||||||
|  |   | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  | @@ -296,7 +302,8 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (trip >= data->ntrips || trip < 0) | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EDOM; | ||||||
|  |   | ||||||
|  |  	*type = data->trips[trip].type; | ||||||
|  | @@ -304,12 +311,39 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static int of_thermal_activate_trip_type(struct thermal_zone_device *tz, | ||||||
|  | +			int trip, enum thermal_trip_activation_mode mode) | ||||||
|  | +{ | ||||||
|  | +	struct __thermal_zone *data = tz->devdata; | ||||||
|  | + | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  | +		return -EDOM; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * The configurable_hi and configurable_lo trip points can be | ||||||
|  | +	 * activated and deactivated. | ||||||
|  | +	 */ | ||||||
|  | + | ||||||
|  | +	if (data->ops->set_trip_activate) { | ||||||
|  | +		int ret; | ||||||
|  | + | ||||||
|  | +		ret = data->ops->set_trip_activate(data->sensor_data, | ||||||
|  | +								trip, mode); | ||||||
|  | +		if (ret) | ||||||
|  | +			return ret; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, | ||||||
|  |  				    int *temp) | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (trip >= data->ntrips || trip < 0) | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EDOM; | ||||||
|  |   | ||||||
|  |  	*temp = data->trips[trip].temperature; | ||||||
|  | @@ -322,7 +356,8 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (trip >= data->ntrips || trip < 0) | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EDOM; | ||||||
|  |   | ||||||
|  |  	if (data->ops->set_trip_temp) { | ||||||
|  | @@ -344,7 +379,8 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (trip >= data->ntrips || trip < 0) | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EDOM; | ||||||
|  |   | ||||||
|  |  	*hyst = data->trips[trip].hysteresis; | ||||||
|  | @@ -357,7 +393,8 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, | ||||||
|  |  { | ||||||
|  |  	struct __thermal_zone *data = tz->devdata; | ||||||
|  |   | ||||||
|  | -	if (trip >= data->ntrips || trip < 0) | ||||||
|  | +	if (trip >= data->ntrips || trip < 0 | ||||||
|  | +				|| (data->mode == THERMAL_DEVICE_DISABLED)) | ||||||
|  |  		return -EDOM; | ||||||
|  |   | ||||||
|  |  	/* thermal framework should take care of data->mask & (1 << trip) */ | ||||||
|  | @@ -432,6 +469,9 @@ thermal_zone_of_add_sensor(struct device_node *zone, | ||||||
|  |  	if (ops->set_emul_temp) | ||||||
|  |  		tzd->ops->set_emul_temp = of_thermal_set_emul_temp; | ||||||
|  |   | ||||||
|  | +	if (ops->set_trip_activate) | ||||||
|  | +		tzd->ops->set_trip_activate = of_thermal_activate_trip_type; | ||||||
|  | + | ||||||
|  |  	mutex_unlock(&tzd->lock); | ||||||
|  |   | ||||||
|  |  	return tzd; | ||||||
|  | @@ -726,7 +766,10 @@ static const char * const trip_types[] = { | ||||||
|  |  	[THERMAL_TRIP_ACTIVE]	= "active", | ||||||
|  |  	[THERMAL_TRIP_PASSIVE]	= "passive", | ||||||
|  |  	[THERMAL_TRIP_HOT]	= "hot", | ||||||
|  | -	[THERMAL_TRIP_CRITICAL]	= "critical", | ||||||
|  | +	[THERMAL_TRIP_CRITICAL]	= "critical_high", | ||||||
|  | +	[THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi", | ||||||
|  | +	[THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo", | ||||||
|  | +	[THERMAL_TRIP_CRITICAL_LOW] = "critical_low", | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c | ||||||
|  | index 2d25593..ac68af3 100644 | ||||||
|  | --- a/drivers/thermal/qcom/tsens.c | ||||||
|  | +++ b/drivers/thermal/qcom/tsens.c | ||||||
|  | @@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, int *temp) | ||||||
|  |   | ||||||
|  |  static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) | ||||||
|  |  { | ||||||
|  | -	const struct tsens_sensor *s = p; | ||||||
|  | +	struct tsens_sensor *s = p; | ||||||
|  |  	struct tsens_device *tmdev = s->tmdev; | ||||||
|  |   | ||||||
|  |  	if (tmdev->ops->get_trend) | ||||||
|  | @@ -40,9 +40,10 @@ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) | ||||||
|  |  	return -ENOTSUPP; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int  __maybe_unused tsens_suspend(struct device *dev) | ||||||
|  | +static int  __maybe_unused tsens_suspend(void *data) | ||||||
|  |  { | ||||||
|  | -	struct tsens_device *tmdev = dev_get_drvdata(dev); | ||||||
|  | +	struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  |   | ||||||
|  |  	if (tmdev->ops && tmdev->ops->suspend) | ||||||
|  |  		return tmdev->ops->suspend(tmdev); | ||||||
|  | @@ -50,9 +51,10 @@ static int  __maybe_unused tsens_suspend(struct device *dev) | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -static int __maybe_unused tsens_resume(struct device *dev) | ||||||
|  | +static int __maybe_unused tsens_resume(void *data) | ||||||
|  |  { | ||||||
|  | -	struct tsens_device *tmdev = dev_get_drvdata(dev); | ||||||
|  | +	struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  |   | ||||||
|  |  	if (tmdev->ops && tmdev->ops->resume) | ||||||
|  |  		return tmdev->ops->resume(tmdev); | ||||||
|  | @@ -60,6 +62,30 @@ static int __maybe_unused tsens_resume(struct device *dev) | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static int  __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp) | ||||||
|  | +{ | ||||||
|  | +	struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  | + | ||||||
|  | +	if (tmdev->ops && tmdev->ops->set_trip_temp) | ||||||
|  | +		return tmdev->ops->set_trip_temp(s, trip, temp); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int __maybe_unused tsens_activate_trip_type(void *data, int trip, | ||||||
|  | +					enum thermal_trip_activation_mode mode) | ||||||
|  | +{ | ||||||
|  | +	struct tsens_sensor *s = data; | ||||||
|  | +	struct tsens_device *tmdev = s->tmdev; | ||||||
|  | + | ||||||
|  | +	if (tmdev->ops && tmdev->ops->set_trip_activate) | ||||||
|  | +		return tmdev->ops->set_trip_activate(s, trip, mode); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); | ||||||
|  |   | ||||||
|  |  static const struct of_device_id tsens_table[] = { | ||||||
|  | @@ -83,6 +109,8 @@ MODULE_DEVICE_TABLE(of, tsens_table); | ||||||
|  |  static const struct thermal_zone_of_device_ops tsens_of_ops = { | ||||||
|  |  	.get_temp = tsens_get_temp, | ||||||
|  |  	.get_trend = tsens_get_trend, | ||||||
|  | +	.set_trip_temp = tsens_set_trip_temp, | ||||||
|  | +	.set_trip_activate = tsens_activate_trip_type, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  static int tsens_register(struct tsens_device *tmdev) | ||||||
|  | @@ -131,7 +159,7 @@ static int tsens_probe(struct platform_device *pdev) | ||||||
|  |  	if (id) | ||||||
|  |  		data = id->data; | ||||||
|  |  	else | ||||||
|  | -		data = &data_8960; | ||||||
|  | +		return -EINVAL; | ||||||
|  |   | ||||||
|  |  	if (data->num_sensors <= 0) { | ||||||
|  |  		dev_err(dev, "invalid number of sensors\n"); | ||||||
|  | @@ -146,6 +174,9 @@ static int tsens_probe(struct platform_device *pdev) | ||||||
|  |  	tmdev->dev = dev; | ||||||
|  |  	tmdev->num_sensors = data->num_sensors; | ||||||
|  |  	tmdev->ops = data->ops; | ||||||
|  | + | ||||||
|  | +	tmdev->tsens_irq = platform_get_irq(pdev, 0); | ||||||
|  | + | ||||||
|  |  	for (i = 0;  i < tmdev->num_sensors; i++) { | ||||||
|  |  		if (data->hw_ids) | ||||||
|  |  			tmdev->sensor[i].hw_id = data->hw_ids[i]; | ||||||
|  | diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h | ||||||
|  | index 31279a2..54bbdc0 100644 | ||||||
|  | --- a/drivers/thermal/qcom/tsens.h | ||||||
|  | +++ b/drivers/thermal/qcom/tsens.h | ||||||
|  | @@ -24,9 +24,12 @@ struct tsens_device; | ||||||
|  |  struct tsens_sensor { | ||||||
|  |  	struct tsens_device		*tmdev; | ||||||
|  |  	struct thermal_zone_device	*tzd; | ||||||
|  | +	struct work_struct		notify_work; | ||||||
|  |  	int				offset; | ||||||
|  |  	int				id; | ||||||
|  |  	int				hw_id; | ||||||
|  | +	int				calib_data; | ||||||
|  | +	int				calib_data_backup; | ||||||
|  |  	int				slope; | ||||||
|  |  	u32				status; | ||||||
|  |  }; | ||||||
|  | @@ -41,6 +44,9 @@ struct tsens_sensor { | ||||||
|  |   * @suspend: Function to suspend the tsens device | ||||||
|  |   * @resume: Function to resume the tsens device | ||||||
|  |   * @get_trend: Function to get the thermal/temp trend | ||||||
|  | + * @set_trip_temp: Function to set trip temp | ||||||
|  | + * @get_trip_temp: Function to get trip temp | ||||||
|  | + * @set_trip_activate: Function to activate trip points | ||||||
|  |   */ | ||||||
|  |  struct tsens_ops { | ||||||
|  |  	/* mandatory callbacks */ | ||||||
|  | @@ -53,6 +59,9 @@ struct tsens_ops { | ||||||
|  |  	int (*suspend)(struct tsens_device *); | ||||||
|  |  	int (*resume)(struct tsens_device *); | ||||||
|  |  	int (*get_trend)(struct tsens_device *, int, enum thermal_trend *); | ||||||
|  | +	int (*set_trip_temp)(void *, int, int); | ||||||
|  | +	int (*set_trip_activate)(void *, int, | ||||||
|  | +					enum thermal_trip_activation_mode); | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | @@ -76,11 +85,13 @@ struct tsens_context { | ||||||
|  |  struct tsens_device { | ||||||
|  |  	struct device			*dev; | ||||||
|  |  	u32				num_sensors; | ||||||
|  | +	u32				tsens_irq; | ||||||
|  |  	struct regmap			*map; | ||||||
|  |  	struct regmap_field		*status_field; | ||||||
|  |  	struct tsens_context		ctx; | ||||||
|  |  	bool				trdy; | ||||||
|  |  	const struct tsens_ops		*ops; | ||||||
|  | +	struct work_struct		tsens_work; | ||||||
|  |  	struct tsens_sensor		sensor[0]; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c | ||||||
|  | index 226b0b4..20bd624 100644 | ||||||
|  | --- a/drivers/thermal/thermal_core.c | ||||||
|  | +++ b/drivers/thermal/thermal_core.c | ||||||
|  | @@ -732,12 +732,48 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr, | ||||||
|  |  		return sprintf(buf, "passive\n"); | ||||||
|  |  	case THERMAL_TRIP_ACTIVE: | ||||||
|  |  		return sprintf(buf, "active\n"); | ||||||
|  | +	case THERMAL_TRIP_CONFIGURABLE_HI: | ||||||
|  | +		return sprintf(buf, "configurable_hi\n"); | ||||||
|  | +	case THERMAL_TRIP_CONFIGURABLE_LOW: | ||||||
|  | +		return sprintf(buf, "configurable_low\n"); | ||||||
|  | +	case THERMAL_TRIP_CRITICAL_LOW: | ||||||
|  | +		return sprintf(buf, "critical_low\n"); | ||||||
|  |  	default: | ||||||
|  |  		return sprintf(buf, "unknown\n"); | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static ssize_t | ||||||
|  | +trip_point_type_activate(struct device *dev, struct device_attribute *attr, | ||||||
|  | +						const char *buf, size_t count) | ||||||
|  | +{ | ||||||
|  | +	struct thermal_zone_device *tz = to_thermal_zone(dev); | ||||||
|  | +	int trip, ret; | ||||||
|  | +	char *enabled = "enabled"; | ||||||
|  | +	char *disabled = "disabled"; | ||||||
|  | + | ||||||
|  | +	if (!tz->ops->set_trip_activate) | ||||||
|  | +		return -EPERM; | ||||||
|  | + | ||||||
|  | +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	if (!strncmp(buf, enabled, strlen(enabled))) | ||||||
|  | +		ret = tz->ops->set_trip_activate(tz, trip, | ||||||
|  | +				THERMAL_TRIP_ACTIVATION_ENABLED); | ||||||
|  | +	else if (!strncmp(buf, disabled, strlen(disabled))) | ||||||
|  | +		ret = tz->ops->set_trip_activate(tz, trip, | ||||||
|  | +				THERMAL_TRIP_ACTIVATION_DISABLED); | ||||||
|  | +	else | ||||||
|  | +		ret = -EINVAL; | ||||||
|  | + | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	return count; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static ssize_t | ||||||
|  |  trip_point_temp_store(struct device *dev, struct device_attribute *attr, | ||||||
|  |  		     const char *buf, size_t count) | ||||||
|  |  { | ||||||
|  | @@ -1321,7 +1357,7 @@ thermal_cooling_device_weight_store(struct device *dev, | ||||||
|  |   */ | ||||||
|  |  int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, | ||||||
|  |  				     int trip, | ||||||
|  | -				     struct thermal_cooling_device *cdev, | ||||||
|  | +					struct thermal_cooling_device *cdev, | ||||||
|  |  				     unsigned long upper, unsigned long lower, | ||||||
|  |  				     unsigned int weight) | ||||||
|  |  { | ||||||
|  | @@ -1772,6 +1808,12 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask) | ||||||
|  |  		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO; | ||||||
|  |  		tz->trip_type_attrs[indx].attr.show = trip_point_type_show; | ||||||
|  |   | ||||||
|  | +		if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) { | ||||||
|  | +			tz->trip_type_attrs[indx].attr.store | ||||||
|  | +						= trip_point_type_activate; | ||||||
|  | +			tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  |  		device_create_file(&tz->device, | ||||||
|  |  				   &tz->trip_type_attrs[indx].attr); | ||||||
|  |   | ||||||
|  | diff --git a/include/linux/thermal.h b/include/linux/thermal.h | ||||||
|  | index 511182a..510a087 100644 | ||||||
|  | --- a/include/linux/thermal.h | ||||||
|  | +++ b/include/linux/thermal.h | ||||||
|  | @@ -77,11 +77,19 @@ enum thermal_device_mode { | ||||||
|  |  	THERMAL_DEVICE_ENABLED, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +enum thermal_trip_activation_mode { | ||||||
|  | +	THERMAL_TRIP_ACTIVATION_DISABLED = 0, | ||||||
|  | +	THERMAL_TRIP_ACTIVATION_ENABLED, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  |  enum thermal_trip_type { | ||||||
|  |  	THERMAL_TRIP_ACTIVE = 0, | ||||||
|  |  	THERMAL_TRIP_PASSIVE, | ||||||
|  |  	THERMAL_TRIP_HOT, | ||||||
|  |  	THERMAL_TRIP_CRITICAL, | ||||||
|  | +	THERMAL_TRIP_CONFIGURABLE_HI, | ||||||
|  | +	THERMAL_TRIP_CONFIGURABLE_LOW, | ||||||
|  | +	THERMAL_TRIP_CRITICAL_LOW, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  enum thermal_trend { | ||||||
|  | @@ -118,6 +126,8 @@ struct thermal_zone_device_ops { | ||||||
|  |  		enum thermal_trip_type *); | ||||||
|  |  	int (*get_trip_temp) (struct thermal_zone_device *, int, int *); | ||||||
|  |  	int (*set_trip_temp) (struct thermal_zone_device *, int, int); | ||||||
|  | +	int (*set_trip_activate) (struct thermal_zone_device *, int, | ||||||
|  | +					enum thermal_trip_activation_mode); | ||||||
|  |  	int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); | ||||||
|  |  	int (*set_trip_hyst) (struct thermal_zone_device *, int, int); | ||||||
|  |  	int (*get_crit_temp) (struct thermal_zone_device *, int *); | ||||||
|  | @@ -360,6 +370,8 @@ struct thermal_genl_event { | ||||||
|  |   *		   temperature. | ||||||
|  |   * @set_trip_temp: a pointer to a function that sets the trip temperature on | ||||||
|  |   *		   hardware. | ||||||
|  | + * @activate_trip_type: a pointer to a function to enable/disable trip | ||||||
|  | + *		temperature interrupts | ||||||
|  |   */ | ||||||
|  |  struct thermal_zone_of_device_ops { | ||||||
|  |  	int (*get_temp)(void *, int *); | ||||||
|  | @@ -367,6 +379,8 @@ struct thermal_zone_of_device_ops { | ||||||
|  |  	int (*set_trips)(void *, int, int); | ||||||
|  |  	int (*set_emul_temp)(void *, int); | ||||||
|  |  	int (*set_trip_temp)(void *, int, int); | ||||||
|  | +	int (*set_trip_activate)(void *, int, | ||||||
|  | +				enum thermal_trip_activation_mode); | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| From 3064376aa3e8dae03dc2c5c3c064e2283c4337d8 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Pavel Kubelun <be.dissent@gmail.com> |  | ||||||
| Date: Tue, 22 Nov 2016 17:37:56 +0300 |  | ||||||
| Subject: [PATCH 63/69] ipq806x: clk: gcc: add tsens child node |  | ||||||
|  |  | ||||||
| Thermal sensors in ipq806x are inside a Global clock controller. |  | ||||||
| Add a child node into it to be used by the TSENS driver. |  | ||||||
|  |  | ||||||
| Signed-off-by: Pavel Kubelun <be.dissent@gmail.com> |  | ||||||
| --- |  | ||||||
|  drivers/clk/qcom/gcc-ipq806x.c | 10 +++++++++- |  | ||||||
|  1 file changed, 9 insertions(+), 1 deletion(-) |  | ||||||
|  |  | ||||||
| --- a/drivers/clk/qcom/gcc-ipq806x.c |  | ||||||
| +++ b/drivers/clk/qcom/gcc-ipq806x.c |  | ||||||
| @@ -970,7 +970,7 @@ static struct clk_branch gsbi1_h_clk = { |  | ||||||
|  		.hw.init = &(struct clk_init_data){ |  | ||||||
|  			.name = "gsbi1_h_clk", |  | ||||||
|  			.ops = &clk_branch_ops, |  | ||||||
| -+			.flags = CLK_IGNORE_UNUSED, |  | ||||||
| +			.flags = CLK_IGNORE_UNUSED, |  | ||||||
|  		}, |  | ||||||
|  	}, |  | ||||||
|  }; |  | ||||||
| @@ -3073,6 +3073,7 @@ MODULE_DEVICE_TABLE(of, gcc_ipq806x_matc |  | ||||||
|  static int gcc_ipq806x_probe(struct platform_device *pdev) |  | ||||||
|  { |  | ||||||
|  	struct device *dev = &pdev->dev; |  | ||||||
| +	struct platform_device *tsens; |  | ||||||
|  	struct regmap *regmap; |  | ||||||
|  	int ret; |  | ||||||
|   |  | ||||||
| @@ -3102,6 +3103,13 @@ static int gcc_ipq806x_probe(struct plat |  | ||||||
|  	regmap_write(regmap, 0x3cf8, 8); |  | ||||||
|  	regmap_write(regmap, 0x3d18, 8); |  | ||||||
|   |  | ||||||
| +	tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1, |  | ||||||
| +					      NULL, 0); |  | ||||||
| +	if (IS_ERR(tsens)) |  | ||||||
| +		return PTR_ERR(tsens); |  | ||||||
| + |  | ||||||
| +	platform_set_drvdata(pdev, tsens); |  | ||||||
| + |  | ||||||
|  	return 0; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
		Reference in New Issue
	
	Block a user