Lines Matching +full:tsens +full:- +full:v1

1 // SPDX-License-Identifier: GPL-2.0
11 #include <linux/nvmem-consumer.h>
21 #include "tsens.h"
24 * struct tsens_irq_data - IRQ status and temperature violations
75 * and offset values are derived from tz->tzp->slope and tz->tzp->offset
84 for (i = 0; i < priv->num_sensors; i++) { in compute_intercept_slope()
85 dev_dbg(priv->dev, in compute_intercept_slope()
86 "%s: sensor%d - data_point1:%#x data_point2:%#x\n", in compute_intercept_slope()
89 if (!priv->sensor[i].slope) in compute_intercept_slope()
90 priv->sensor[i].slope = SLOPE_DEFAULT; in compute_intercept_slope()
93 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ in compute_intercept_slope()
94 * temp_120_degc - temp_30_degc (x2 - x1) in compute_intercept_slope()
96 num = p2[i] - p1[i]; in compute_intercept_slope()
98 den = CAL_DEGC_PT2 - CAL_DEGC_PT1; in compute_intercept_slope()
99 priv->sensor[i].slope = num / den; in compute_intercept_slope()
102 priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - in compute_intercept_slope()
104 priv->sensor[i].slope); in compute_intercept_slope()
105 dev_dbg(priv->dev, "%s: offset:%d\n", __func__, in compute_intercept_slope()
106 priv->sensor[i].offset); in compute_intercept_slope()
112 u64 code = div_u64(((u64)degc * s->slope + s->offset), SLOPE_FACTOR); in degc_to_code()
122 num = (adc_code * SLOPE_FACTOR) - s->offset; in code_to_degc()
123 den = s->slope; in code_to_degc()
128 degc = num - (den / 2); in code_to_degc()
138 * tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
150 struct tsens_priv *priv = s->priv; in tsens_hw_to_mC()
155 resolution = priv->fields[LAST_TEMP_0].msb - in tsens_hw_to_mC()
156 priv->fields[LAST_TEMP_0].lsb; in tsens_hw_to_mC()
158 ret = regmap_field_read(priv->rf[field], &temp); in tsens_hw_to_mC()
163 if (priv->feat->adc) in tsens_hw_to_mC()
166 /* deciCelsius -> milliCelsius along with sign extension */ in tsens_hw_to_mC()
171 * tsens_mC_to_hw - Convert temperature to hardware register value
182 struct tsens_priv *priv = s->priv; in tsens_mC_to_hw()
185 if (priv->feat->adc) in tsens_mC_to_hw()
194 return priv->feat->ver_major; in tsens_version()
213 regmap_field_write(priv->rf[index], enable ? 0 : 1); in tsens_set_interrupt_v1()
223 * - clear the mask bit in tsens_set_interrupt_v2()
225 * - Mask further interrupts for this sensor in tsens_set_interrupt_v2()
226 * - Write 1 followed by 0 to clear the interrupt in tsens_set_interrupt_v2()
244 regmap_field_write(priv->rf[index_mask], 0); in tsens_set_interrupt_v2()
246 regmap_field_write(priv->rf[index_mask], 1); in tsens_set_interrupt_v2()
247 regmap_field_write(priv->rf[index_clear], 1); in tsens_set_interrupt_v2()
248 regmap_field_write(priv->rf[index_clear], 0); in tsens_set_interrupt_v2()
253 * tsens_set_interrupt - Set state of an interrupt
254 * @priv: Pointer to tsens controller private data
259 * Call IP-specific function to set state of an interrupt
266 dev_dbg(priv->dev, "[%u] %s: %s -> %s\n", hw_id, __func__, in tsens_set_interrupt()
276 * tsens_threshold_violated - Check if a sensor temperature violated a preset threshold
277 * @priv: Pointer to tsens controller private data
289 ret = regmap_field_read(priv->rf[UPPER_STATUS_0 + hw_id], &d->up_viol); in tsens_threshold_violated()
292 ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol); in tsens_threshold_violated()
296 if (priv->feat->crit_int) { in tsens_threshold_violated()
297 ret = regmap_field_read(priv->rf[CRITICAL_STATUS_0 + hw_id], in tsens_threshold_violated()
298 &d->crit_viol); in tsens_threshold_violated()
303 if (d->up_viol || d->low_viol || d->crit_viol) in tsens_threshold_violated()
315 ret = regmap_field_read(priv->rf[UP_INT_CLEAR_0 + hw_id], &d->up_irq_clear); in tsens_read_irq_state()
318 ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear); in tsens_read_irq_state()
322 ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask); in tsens_read_irq_state()
325 ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask); in tsens_read_irq_state()
328 ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id], in tsens_read_irq_state()
329 &d->crit_irq_clear); in tsens_read_irq_state()
332 ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id], in tsens_read_irq_state()
333 &d->crit_irq_mask); in tsens_read_irq_state()
337 d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id); in tsens_read_irq_state()
339 /* No mask register on older TSENS */ in tsens_read_irq_state()
340 d->up_irq_mask = 0; in tsens_read_irq_state()
341 d->low_irq_mask = 0; in tsens_read_irq_state()
342 d->crit_irq_clear = 0; in tsens_read_irq_state()
343 d->crit_irq_mask = 0; in tsens_read_irq_state()
344 d->crit_thresh = 0; in tsens_read_irq_state()
347 d->up_thresh = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id); in tsens_read_irq_state()
348 d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id); in tsens_read_irq_state()
350 dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) | clr(%u|%u|%u) | mask(%u|%u|%u)\n", in tsens_read_irq_state()
352 (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "", in tsens_read_irq_state()
353 d->low_viol, d->up_viol, d->crit_viol, in tsens_read_irq_state()
354 d->low_irq_clear, d->up_irq_clear, d->crit_irq_clear, in tsens_read_irq_state()
355 d->low_irq_mask, d->up_irq_mask, d->crit_irq_mask); in tsens_read_irq_state()
356 dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d:%d)\n", hw_id, __func__, in tsens_read_irq_state()
357 (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "", in tsens_read_irq_state()
358 d->low_thresh, d->up_thresh, d->crit_thresh); in tsens_read_irq_state()
368 /* v1, v0.1 don't have a irq mask register */ in masked_irq()
373 * tsens_critical_irq_thread() - Threaded handler for critical interrupts
375 * @data: tsens controller private data
379 * Clear and then re-enable the interrupt.
381 * The level-triggered interrupt might deassert if the temperature returned to
394 if (priv->feat->has_watchdog) { in tsens_critical_irq_thread()
395 ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS], in tsens_critical_irq_thread()
402 regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1); in tsens_critical_irq_thread()
403 regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0); in tsens_critical_irq_thread()
404 ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT], in tsens_critical_irq_thread()
409 dev_dbg(priv->dev, "%s: watchdog count: %d\n", in tsens_critical_irq_thread()
416 for (i = 0; i < priv->num_sensors; i++) { in tsens_critical_irq_thread()
417 const struct tsens_sensor *s = &priv->sensor[i]; in tsens_critical_irq_thread()
418 u32 hw_id = s->hw_id; in tsens_critical_irq_thread()
420 if (!s->tzd) in tsens_critical_irq_thread()
426 dev_err(priv->dev, "[%u] %s: error reading sensor\n", in tsens_critical_irq_thread()
443 * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
445 * @data: tsens controller private data
449 * update the thresholds, else re-enable the interrupts.
451 * The level-triggered interrupt might deassert if the temperature returned to
465 for (i = 0; i < priv->num_sensors; i++) { in tsens_irq_thread()
467 const struct tsens_sensor *s = &priv->sensor[i]; in tsens_irq_thread()
468 u32 hw_id = s->hw_id; in tsens_irq_thread()
470 if (!s->tzd) in tsens_irq_thread()
476 dev_err(priv->dev, "[%u] %s: error reading sensor\n", in tsens_irq_thread()
481 spin_lock_irqsave(&priv->ul_lock, flags); in tsens_irq_thread()
489 dev_dbg(priv->dev, "[%u] %s: re-arm upper\n", in tsens_irq_thread()
500 dev_dbg(priv->dev, "[%u] %s: re-arm low\n", in tsens_irq_thread()
509 spin_unlock_irqrestore(&priv->ul_lock, flags); in tsens_irq_thread()
512 dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n", in tsens_irq_thread()
514 thermal_zone_device_update(s->tzd, in tsens_irq_thread()
517 dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", in tsens_irq_thread()
537 struct tsens_priv *priv = s->priv; in tsens_set_trips()
538 struct device *dev = priv->dev; in tsens_set_trips()
542 u32 hw_id = s->hw_id; in tsens_set_trips()
554 cl_high = clamp_val(high, -40000, 120000); in tsens_set_trips()
555 cl_low = clamp_val(low, -40000, 120000); in tsens_set_trips()
560 spin_lock_irqsave(&priv->ul_lock, flags); in tsens_set_trips()
565 regmap_field_write(priv->rf[LOW_THRESH_0 + hw_id], low_val); in tsens_set_trips()
566 regmap_field_write(priv->rf[UP_THRESH_0 + hw_id], high_val); in tsens_set_trips()
570 spin_unlock_irqrestore(&priv->ul_lock, flags); in tsens_set_trips()
572 dev_dbg(dev, "[%u] %s: (%d:%d)->(%d:%d)\n", in tsens_set_trips()
583 ret = regmap_field_write(priv->rf[INT_EN], val); in tsens_enable_irq()
585 dev_err(priv->dev, "%s: failed to enable interrupts\n", in tsens_enable_irq()
593 regmap_field_write(priv->rf[INT_EN], 0); in tsens_disable_irq()
598 struct tsens_priv *priv = s->priv; in get_temp_tsens_valid()
599 int hw_id = s->hw_id; in get_temp_tsens_valid()
607 ret = regmap_field_read(priv->rf[valid_idx], &valid); in get_temp_tsens_valid()
616 ret = regmap_field_read(priv->rf[valid_idx], &valid); in get_temp_tsens_valid()
630 struct tsens_priv *priv = s->priv; in get_temp_common()
631 int hw_id = s->hw_id; in get_temp_common()
638 ret = regmap_field_read(priv->rf[TRDY], &trdy); in get_temp_common()
645 ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); in get_temp_common()
654 return -ETIMEDOUT; in get_temp_common()
660 struct platform_device *pdev = s->private; in dbg_sensors_show()
665 priv->feat->max_sensors, priv->num_sensors); in dbg_sensors_show()
667 seq_puts(s, " id slope offset\n--------------------------\n"); in dbg_sensors_show()
668 for (i = 0; i < priv->num_sensors; i++) { in dbg_sensors_show()
669 seq_printf(s, "%8d %8d %8d\n", priv->sensor[i].hw_id, in dbg_sensors_show()
670 priv->sensor[i].slope, priv->sensor[i].offset); in dbg_sensors_show()
678 struct platform_device *pdev = s->private; in dbg_version_show()
684 ret = regmap_field_read(priv->rf[VER_MAJOR], &maj_ver); in dbg_version_show()
687 ret = regmap_field_read(priv->rf[VER_MINOR], &min_ver); in dbg_version_show()
690 ret = regmap_field_read(priv->rf[VER_STEP], &step_ver); in dbg_version_show()
709 root = debugfs_lookup("tsens", NULL); in tsens_debug_init()
711 priv->debug_root = debugfs_create_dir("tsens", NULL); in tsens_debug_init()
713 priv->debug_root = root; in tsens_debug_init()
715 file = debugfs_lookup("version", priv->debug_root); in tsens_debug_init()
717 debugfs_create_file("version", 0444, priv->debug_root, in tsens_debug_init()
720 /* A directory for each instance of the TSENS IP */ in tsens_debug_init()
721 priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root); in tsens_debug_init()
722 debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops); in tsens_debug_init()
745 struct device *dev = priv->dev; in init_common()
750 struct platform_device *op = of_find_device_by_node(priv->dev->of_node); in init_common()
753 return -EINVAL; in init_common()
755 if (op->num_resources > 1) { in init_common()
757 priv->tm_offset = 0; in init_common()
765 priv->srot_map = devm_regmap_init_mmio(dev, srot_base, in init_common()
767 if (IS_ERR(priv->srot_map)) { in init_common()
768 ret = PTR_ERR(priv->srot_map); in init_common()
773 priv->tm_offset = 0x1000; in init_common()
784 priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); in init_common()
786 struct device *parent = priv->dev->parent; in init_common()
789 priv->tm_map = syscon_node_to_regmap(parent->of_node); in init_common()
792 if (IS_ERR_OR_NULL(priv->tm_map)) { in init_common()
793 if (!priv->tm_map) in init_common()
794 ret = -ENODEV; in init_common()
796 ret = PTR_ERR(priv->tm_map); in init_common()
801 if (!priv->srot_map) in init_common()
802 priv->srot_map = priv->tm_map; in init_common()
806 priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
807 priv->fields[i]); in init_common()
808 if (IS_ERR(priv->rf[i])) { in init_common()
809 ret = PTR_ERR(priv->rf[i]); in init_common()
813 ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); in init_common()
818 priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
819 priv->fields[TSENS_EN]); in init_common()
820 if (IS_ERR(priv->rf[TSENS_EN])) { in init_common()
821 ret = PTR_ERR(priv->rf[TSENS_EN]); in init_common()
824 /* in VER_0 TSENS need to be explicitly enabled */ in init_common()
826 regmap_field_write(priv->rf[TSENS_EN], 1); in init_common()
828 ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); in init_common()
833 ret = -ENODEV; in init_common()
837 priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
838 priv->fields[SENSOR_EN]); in init_common()
839 if (IS_ERR(priv->rf[SENSOR_EN])) { in init_common()
840 ret = PTR_ERR(priv->rf[SENSOR_EN]); in init_common()
843 priv->rf[INT_EN] = devm_regmap_field_alloc(dev, priv->tm_map, in init_common()
844 priv->fields[INT_EN]); in init_common()
845 if (IS_ERR(priv->rf[INT_EN])) { in init_common()
846 ret = PTR_ERR(priv->rf[INT_EN]); in init_common()
850 priv->rf[TSENS_SW_RST] = in init_common()
851 devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); in init_common()
852 if (IS_ERR(priv->rf[TSENS_SW_RST])) { in init_common()
853 ret = PTR_ERR(priv->rf[TSENS_SW_RST]); in init_common()
857 priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); in init_common()
858 if (IS_ERR(priv->rf[TRDY])) { in init_common()
859 ret = PTR_ERR(priv->rf[TRDY]); in init_common()
865 for (i = 0; i < priv->feat->max_sensors; i++) { in init_common()
868 priv->rf[idx] = devm_regmap_field_alloc(dev, in init_common()
869 priv->tm_map, in init_common()
870 priv->fields[idx]); in init_common()
871 if (IS_ERR(priv->rf[idx])) { in init_common()
872 ret = PTR_ERR(priv->rf[idx]); in init_common()
878 if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { in init_common()
881 for (i = 0; i < priv->feat->max_sensors; i++) { in init_common()
884 priv->rf[idx] = in init_common()
886 priv->tm_map, in init_common()
887 priv->fields[idx]); in init_common()
888 if (IS_ERR(priv->rf[idx])) { in init_common()
889 ret = PTR_ERR(priv->rf[idx]); in init_common()
898 priv->feat->has_watchdog = 1; in init_common()
900 priv->rf[i] = devm_regmap_field_alloc(dev, priv->tm_map, in init_common()
901 priv->fields[i]); in init_common()
902 if (IS_ERR(priv->rf[i])) { in init_common()
903 ret = PTR_ERR(priv->rf[i]); in init_common()
911 regmap_field_write(priv->rf[WDOG_BARK_MASK], 0); in init_common()
912 regmap_field_write(priv->rf[CC_MON_MASK], 1); in init_common()
915 spin_lock_init(&priv->ul_lock); in init_common()
924 put_device(&op->dev); in init_common()
931 struct tsens_priv *priv = s->priv; in tsens_get_temp()
933 return priv->ops->get_temp(s, temp); in tsens_get_temp()
939 struct tsens_priv *priv = s->priv; in tsens_get_trend()
941 if (priv->ops->get_trend) in tsens_get_trend()
942 return priv->ops->get_trend(s, trend); in tsens_get_trend()
944 return -ENOTSUPP; in tsens_get_trend()
951 if (priv->ops && priv->ops->suspend) in tsens_suspend()
952 return priv->ops->suspend(priv); in tsens_suspend()
961 if (priv->ops && priv->ops->resume) in tsens_resume()
962 return priv->ops->resume(priv); in tsens_resume()
971 .compatible = "qcom,ipq8064-tsens",
974 .compatible = "qcom,mdm9607-tsens",
977 .compatible = "qcom,msm8916-tsens",
980 .compatible = "qcom,msm8939-tsens",
983 .compatible = "qcom,msm8974-tsens",
986 .compatible = "qcom,msm8976-tsens",
989 .compatible = "qcom,msm8996-tsens",
992 .compatible = "qcom,tsens-v1",
995 .compatible = "qcom,tsens-v2",
1014 pdev = of_find_device_by_node(priv->dev->of_node); in tsens_register_irq()
1016 return -ENODEV; in tsens_register_irq()
1022 if (irq == -ENXIO) in tsens_register_irq()
1027 ret = devm_request_threaded_irq(&pdev->dev, irq, in tsens_register_irq()
1030 dev_name(&pdev->dev), in tsens_register_irq()
1033 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, in tsens_register_irq()
1035 dev_name(&pdev->dev), in tsens_register_irq()
1039 dev_err(&pdev->dev, "%s: failed to get irq\n", in tsens_register_irq()
1045 put_device(&pdev->dev); in tsens_register_irq()
1054 for (i = 0; i < priv->num_sensors; i++) { in tsens_register()
1055 priv->sensor[i].priv = priv; in tsens_register()
1056 tzd = devm_thermal_zone_of_sensor_register(priv->dev, priv->sensor[i].hw_id, in tsens_register()
1057 &priv->sensor[i], in tsens_register()
1061 priv->sensor[i].tzd = tzd; in tsens_register()
1062 if (priv->ops->enable) in tsens_register()
1063 priv->ops->enable(priv, i); in tsens_register()
1068 * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C in tsens_register()
1069 * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C in tsens_register()
1072 regmap_field_write(priv->rf[CRIT_THRESH_0], in tsens_register()
1073 tsens_mC_to_hw(priv->sensor, 120000)); in tsens_register()
1075 regmap_field_write(priv->rf[CRIT_THRESH_1], in tsens_register()
1076 tsens_mC_to_hw(priv->sensor, 0)); in tsens_register()
1083 if (priv->feat->crit_int) in tsens_register()
1100 if (pdev->dev.of_node) in tsens_probe()
1101 dev = &pdev->dev; in tsens_probe()
1103 dev = pdev->dev.parent; in tsens_probe()
1105 np = dev->of_node; in tsens_probe()
1109 data = id->data; in tsens_probe()
1113 num_sensors = data->num_sensors; in tsens_probe()
1120 return -EINVAL; in tsens_probe()
1127 return -ENOMEM; in tsens_probe()
1129 priv->dev = dev; in tsens_probe()
1130 priv->num_sensors = num_sensors; in tsens_probe()
1131 priv->ops = data->ops; in tsens_probe()
1132 for (i = 0; i < priv->num_sensors; i++) { in tsens_probe()
1133 if (data->hw_ids) in tsens_probe()
1134 priv->sensor[i].hw_id = data->hw_ids[i]; in tsens_probe()
1136 priv->sensor[i].hw_id = i; in tsens_probe()
1138 priv->feat = data->feat; in tsens_probe()
1139 priv->fields = data->fields; in tsens_probe()
1143 if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) in tsens_probe()
1144 return -EINVAL; in tsens_probe()
1146 ret = priv->ops->init(priv); in tsens_probe()
1152 if (priv->ops->calibrate) { in tsens_probe()
1153 ret = priv->ops->calibrate(priv); in tsens_probe()
1155 if (ret != -EPROBE_DEFER) in tsens_probe()
1168 debugfs_remove_recursive(priv->debug_root); in tsens_remove()
1170 if (priv->ops->disable) in tsens_remove()
1171 priv->ops->disable(priv); in tsens_remove()
1180 .name = "qcom-tsens",
1189 MODULE_ALIAS("platform:qcom-tsens");