Add support for ipq8064 tsens
v2 cover Add support for ipq8064 tsens
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. This patchset expand the 8960 unused driver with interrupt support and set_trip point. Ipq8064 needs to registed with a syscon phandle as the tsens regs on this platform are shared with the gcc controller.
v2:
* Fix dt-bindings problems
Ansuel Smith (6):
drivers: thermal: tsens: load regmap from phandle for 8960
drivers: thermal: tsens: add ipq8064 support
dt-bindings: thermal: tsens: document ipq8064 bindings
drivers: thermal: tsens: add interrupt support for 9860 driver
drivers: thermal: tsens: add support for custom set_trip function
drivers: thermal: tsens: add set_trip support for 8960
.../bindings/thermal/qcom-tsens.yaml | 53 +++- drivers/thermal/qcom/tsens-8960.c | 283 +++++++++++++++++- drivers/thermal/qcom/tsens.c | 7 + drivers/thermal/qcom/tsens.h | 3 + 4 files changed, 323 insertions(+), 23 deletions(-)
Signature · 1 line
2.27.0
PATCH v2 1/6 drivers: thermal: tsens: load regmap from phandle for 8960
Devices based on 8060 tsens driver (ipq8064) use the reg of the gcc driver. Permit to load the regmap from a syscon phandle instead of fail as the reg are already used by another driver.
--- drivers/thermal/qcom/tsens-8960.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/thermal/qcom/tsens-8960.c +7 -2
@@ -7,6 +7,7 @@#include <linux/delay.h> #include <linux/bitops.h> #include <linux/regmap.h> +#include <linux/mfd/syscon.h> #include <linux/thermal.h> #include "tsens.h"
@@ -168,8 +169,12 @@ static int init_8960(struct tsens_priv *priv)u32 reg_cntl; priv->tm_map =dev_get_regmap (priv->dev,NULL ); -if (!priv->tm_map) -return -ENODEV ; +if (!priv->tm_map) { + priv->tm_map =syscon_regmap_lookup_by_phandle ( + priv->dev->of_node,"regmap" ); +if (IS_ERR (priv->tm_map)) +return -ENODEV ; + }/* * The status registers for each sensor are discontiguous
Signature · 1 line
2.27.0
PATCH v2 2/6 drivers: thermal: tsens: add ipq8064 support
In reply to Ansuel SmithIpq8064 SoCs based use the same 8960 driver.
--- drivers/thermal/qcom/tsens.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/thermal/qcom/tsens.c +3 -0
@@ -907,6 +907,9 @@ static const struct of_device_id tsens_table[] = { .compatible = "qcom,msm8996-tsens", .data = &data_8996, }, { + .compatible = "qcom,ipq8064-tsens", + .data = &data_8060, + } { .compatible = "qcom,tsens-v1", .data = &data_tsens_v1, }, {
Signature · 1 line
2.27.0
PATCH v2 3/6 dt-bindings: thermal: tsens: document ipq8064 bindings
In reply to Ansuel SmithDocument the use of regmap phandle for ipq8064 SoCs
--- .../bindings/thermal/qcom-tsens.yaml | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +46 -7
@@ -19,6 +19,11 @@ description: | properties: compatible: oneOf: + - description: msm9860 TSENS based + items: + - enum: + - qcom,ipq8064-tsens + - description: v0.1 of TSENS items: - enum:
@@ -47,6 +52,11 @@ properties: - description: TM registers - description: SROT registers + regmap: + description: + Phandle to the gcc. On ipq8064 SoCs gcc and tsense share the same regs. + $ref: /schemas/types.yaml#/definitions/phandle + interrupts: minItems: 1 items:
@@ -85,12 +95,18 @@ properties: Number of cells required to uniquely identify the thermal sensors. Since we have multiple sensors this is set to 1 +required: + - compatible + - interrupts + - "#thermal-sensor-cells" + allOf: - if: properties: compatible: contains: enum: + - qcom,ipq8064-tsens - qcom,msm8916-tsens - qcom,msm8974-tsens - qcom,msm8976-tsens
@@ -111,17 +127,40 @@ allOf: interrupt-names: minItems: 2 -required: - - compatible - - reg - - "#qcom,sensors" - - interrupts - - interrupt-names - - "#thermal-sensor-cells" + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq8064-tsens + then: + required: + - regmap + + else: + required: + - reg + - interrupt-names + - "#qcom,sensors" additionalProperties: false examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + // Example msm9860 based SoC (ipq8064): + tsens: thermal-sensor { + compatible = "qcom,ipq8064-tsens"; + regmap = <&gcc>; + + nvmem-cells = <&tsens_calib>, <&tsens_calsel>; + nvmem-cell-names = "calib", "calib_sel"; + + interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; + + #thermal-sensor-cells = <1>; + }; + - | #include <dt-bindings/interrupt-controller/arm-gic.h> // Example 1 (legacy: for pre v1 IP):
Signature · 1 line
2.27.0
PATCH v2 4/6 drivers: thermal: tsens: add interrupt support for 9860 driver
In reply to Ansuel SmithAdd interrupt support for 9860 tsens driver used to set thermal trip point for the system.
--- drivers/thermal/qcom/tsens-8960.c | 196 +++++++++++++++++++++++++++--- drivers/thermal/qcom/tsens.h | 1 + 2 files changed, 183 insertions(+), 14 deletions(-)
drivers/thermal/qcom/tsens-8960.c +182 -14
@@ -8,6 +8,7 @@#include <linux/bitops.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> +#include <linux/interrupt.h> #include <linux/thermal.h> #include "tsens.h"
@@ -27,7 +28,6 @@/* CNTL_ADDR bitmasks */ #define EN BIT(0)#define SW_RST BIT(1) -#define SENSOR0_EN BIT(3)#define SLP_CLK_ENA BIT(26)#define SLP_CLK_ENA_8660 BIT(24)#define MEASURE_PERIOD 1
@@ -41,14 +41,26 @@#define THRESHOLD_ADDR 0x3624/* THRESHOLD_ADDR bitmasks */ +#define THRESHOLD_MAX_CODE 0x20000 +#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 0x50 -#define UPPER_LIMIT_TH 0xdf +#define LOWER_LIMIT_TH_8960 0x50 +#define UPPER_LIMIT_TH_8960 0xdf +#define LOWER_LIMIT_TH_8064 0x9d/* 95C */ +#define UPPER_LIMIT_TH_8064 0xa6/* 105C */ #define MIN_LIMIT_TH 0x0#define MAX_LIMIT_TH 0xff
@@ -57,6 +69,169 @@#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) + +u32 tsens_8960_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_mdegC (u32 adc_code,const struct tsens_sensor *s) +{ +int slope, offset; + + slope =thermal_zone_get_slope (s->tzd); + offset =CAL_MDEGC - slope * s->offset; + +return adc_code * slope + offset; +} + +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_priv *priv = + container_of(work, struct tsens_priv, tsens_work); +unsigned int threshold, threshold_low, code, reg, sensor, mask; +bool upper_th_x, lower_th_x; +int ret; + + ret =regmap_read (priv->tm_map,STATUS_CNTL_ADDR_8064 , ®); +if (ret) +return ; + reg = reg |LOWER_STATUS_CLR |UPPER_STATUS_CLR ; + ret =regmap_write (priv->tm_map,STATUS_CNTL_ADDR_8064 , reg); +if (ret) +return ; + + mask = ~(LOWER_STATUS_CLR |UPPER_STATUS_CLR ); + ret =regmap_read (priv->tm_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 (priv->tm_map,STATUS_CNTL_ADDR_8064 , ®); +if (ret) +return ; + + ret =regmap_read (priv->tm_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 (priv->tm_map, priv->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 (&priv->sensor[0 ].notify_work); +pr_debug ("Trigger (%d degrees) for sensor %d\n" , +code_to_mdegC (code, &priv->sensor[0 ]),0 ); + } + } +regmap_write (priv->tm_map,STATUS_CNTL_ADDR_8064 , reg & mask); +} + +static irqreturn_t tsens_isr (int irq,void *data) +{ +struct tsens_priv *priv = data; + +schedule_work (&priv->tsens_work); +return IRQ_HANDLED ; +} + +static void hw_init (struct tsens_priv *priv) +{ +int ret; +unsigned int reg_cntl =0 , reg_cfg =0 , reg_thr =0 ; +unsigned int reg_status_cntl =0 ; + +regmap_read (priv->tm_map,CNTL_ADDR , ®_cntl); +regmap_write (priv->tm_map,CNTL_ADDR , reg_cntl |TSENS_SW_RST ); + + reg_cntl |=SLP_CLK_ENA | (MEASURE_PERIOD <<18 ) | + (((1 << priv->num_sensors) -1 ) <<SENSOR0_SHIFT ); +regmap_write (priv->tm_map,CNTL_ADDR , reg_cntl); +regmap_read (priv->tm_map,STATUS_CNTL_ADDR_8064 , ®_status_cntl); + reg_status_cntl |=LOWER_STATUS_CLR |UPPER_STATUS_CLR | +MIN_STATUS_MASK |MAX_STATUS_MASK ; +regmap_write (priv->tm_map,STATUS_CNTL_ADDR_8064 , reg_status_cntl); + reg_cntl |=TSENS_EN ; +regmap_write (priv->tm_map,CNTL_ADDR , reg_cntl); + +regmap_read (priv->tm_map,CONFIG_ADDR , ®_cfg); +if (priv->num_sensors >1 ) + reg_cfg = (reg_cfg & ~CONFIG_MASK ) |CONFIG ; +else + reg_cfg = (reg_cfg & ~CONFIG_MASK ) | + (CONFIG <<CONFIG_SHIFT_8660 ); +regmap_write (priv->tm_map,CONFIG_ADDR , reg_cfg); + + reg_thr |= (LOWER_LIMIT_TH_8064 <<THRESHOLD_LOWER_LIMIT_SHIFT ) | + (UPPER_LIMIT_TH_8064 <<THRESHOLD_UPPER_LIMIT_SHIFT ) | + (MIN_LIMIT_TH <<THRESHOLD_MIN_LIMIT_SHIFT ) | + (MAX_LIMIT_TH <<THRESHOLD_MAX_LIMIT_SHIFT ); + +regmap_write (priv->tm_map,THRESHOLD_ADDR , reg_thr); + + ret =devm_request_irq (priv->dev, priv->tsens_irq, tsens_isr, +IRQF_TRIGGER_RISING ,"tsens_interrupt" , priv); +if (ret <0 ) { +dev_err (priv->dev,"request_irq FAIL: %d" , ret); +return ; + } + +INIT_WORK (&priv->tsens_work, tsens_scheduler_fn); +} +static int suspend_8960 (struct tsens_priv *priv) {int ret;
@@ -186,6 +361,8 @@ static int init_8960(struct tsens_priv *priv)if (i >=5 ) priv->sensor[i].status =S0_STATUS_ADDR +40 ; priv->sensor[i].status += i *4 ; + priv->sensor[i].slope = tsens_8960_slope[i]; +INIT_WORK (&priv->sensor[i].notify_work, notify_uspace_tsens_fn); } reg_cntl =SW_RST ;
@@ -236,18 +413,9 @@ static int calibrate_8960(struct tsens_priv *priv)kfree (data); -return 0 ; -} - -/* Temperature on y axis and ADC-code on x-axis */ -static inline int code_to_mdegC (u32 adc_code,const struct tsens_sensor *s) -{ -int slope, offset; +hw_init (priv); - slope =thermal_zone_get_slope (s->tzd); - offset =CAL_MDEGC - slope * s->offset; - -return adc_code * slope + offset; +return 0 ; }static int get_temp_8960 (const struct tsens_sensor *s,int *temp)
drivers/thermal/qcom/tsens.h +1 -0
@@ -48,6 +48,7 @@ enum tsens_irq_type {struct tsens_sensor {struct tsens_priv *priv;struct thermal_zone_device *tzd; +struct work_struct notify_work;int offset;unsigned int hw_id;int slope;
Signature · 1 line
2.27.0
PATCH v2 5/6 drivers: thermal: tsens: add support for custom set_trip function
In reply to Ansuel Smith8960 tsens driver have a custom implementation to set set_trip function. Permit the generic driver to use the custom function if provided.
--- drivers/thermal/qcom/tsens.c | 4 ++++ drivers/thermal/qcom/tsens.h | 2 ++ 2 files changed, 6 insertions(+)
drivers/thermal/qcom/tsens.c +4 -0
@@ -530,6 +530,10 @@ static int tsens_set_trips(void *_sensor, int low, int high)int high_val, low_val, cl_high, cl_low;u32 hw_id = s->hw_id; +// Use the driver set_trips if present +if (priv->ops->set_trip_temp) +return priv->ops->set_trip_temp (_sensor, low, high); +dev_dbg (dev,"[%u] %s: proposed thresholds: (%d:%d)\n" , hw_id, __func__, low, high);
drivers/thermal/qcom/tsens.h +2 -0
@@ -65,6 +65,7 @@ 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 get trip temp */ struct tsens_ops {/* mandatory callbacks */
@@ -77,6 +78,7 @@ struct tsens_ops {int (*suspend)(struct tsens_priv *priv);int (*resume)(struct tsens_priv *priv);int (*get_trend)(struct tsens_sensor *s,enum thermal_trend *trend); +int (*set_trip_temp)(void *data,int trip,int temp); };#define REG_FIELD_FOR_EACH_SENSOR11 (_name, _offset, _startbit, _stopbit) \
Signature · 1 line
2.27.0
PATCH v2 6/6 drivers: thermal: tsens: add set_trip support for 8960
In reply to Ansuel SmithAdd custom set_trip function for 8960 needed to set trip point to the tsens driver for 8960 driver.
--- drivers/thermal/qcom/tsens-8960.c | 78 +++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)
drivers/thermal/qcom/tsens-8960.c +78 -0
@@ -93,6 +93,15 @@ TSENS_8064_SENSOR9_EN | \ TSENS_8064_SENSOR10_EN) +/* 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_8960_slope[] = {1176 ,1176 ,1154 ,1176 ,1111 ,1132 ,1132 ,1199 ,
@@ -110,6 +119,16 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)return adc_code * slope + offset; } +static int mdegC_to_code (int degC,const struct tsens_sensor *s) +{ +int slope, offset; + + slope =thermal_zone_get_slope (s->tzd); + offset =CAL_MDEGC - slope * s->offset; + +return degC / slope - offset; +} +static void notify_uspace_tsens_fn (struct work_struct *work) { struct tsens_sensor *s = container_of(work, struct tsens_sensor,
@@ -442,6 +461,64 @@ static int get_temp_8960(const struct tsens_sensor *s, int *temp)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_priv *priv = s->priv; + + code =mdegC_to_code (temp, s); + code_chk = code; + +if (code <THRESHOLD_MIN_CODE || code >THRESHOLD_MAX_CODE ) +return -EINVAL ; + + ret =regmap_read (priv->tm_map,STATUS_CNTL_ADDR_8064 , ®_cntl); +if (ret) +return ret; + + ret =regmap_read (priv->tm_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 (priv->tm_map,THRESHOLD_ADDR , reg_th | code); +if (ret) +return ret; + +return 0 ; +} +static const struct tsens_ops ops_8960 = { .init = init_8960, .calibrate = calibrate_8960,
@@ -450,6 +527,7 @@ static const struct tsens_ops ops_8960 = { .disable = disable_8960, .suspend = suspend_8960, .resume = resume_8960, + .set_trip_temp = set_trip_temp_ipq8064, };struct tsens_plat_data data_8960 = {
Signature · 1 line
2.27.0