Lines Matching +full:msm8916 +full:- +full:tsens
1 // SPDX-License-Identifier: GPL-2.0
11 #include <linux/nvmem-consumer.h>
20 #include "tsens.h"
23 * struct tsens_irq_data - IRQ status and temperature violations
74 * and offset values are derived from tz->tzp->slope and tz->tzp->offset
83 for (i = 0; i < priv->num_sensors; i++) { in compute_intercept_slope()
84 dev_dbg(priv->dev, in compute_intercept_slope()
85 "%s: sensor%d - data_point1:%#x data_point2:%#x\n", in compute_intercept_slope()
88 priv->sensor[i].slope = SLOPE_DEFAULT; in compute_intercept_slope()
91 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ in compute_intercept_slope()
92 * temp_120_degc - temp_30_degc (x2 - x1) in compute_intercept_slope()
94 num = p2[i] - p1[i]; in compute_intercept_slope()
96 den = CAL_DEGC_PT2 - CAL_DEGC_PT1; in compute_intercept_slope()
97 priv->sensor[i].slope = num / den; in compute_intercept_slope()
100 priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - in compute_intercept_slope()
102 priv->sensor[i].slope); in compute_intercept_slope()
103 dev_dbg(priv->dev, "%s: offset:%d\n", __func__, in compute_intercept_slope()
104 priv->sensor[i].offset); in compute_intercept_slope()
110 u64 code = div_u64(((u64)degc * s->slope + s->offset), SLOPE_FACTOR); in degc_to_code()
120 num = (adc_code * SLOPE_FACTOR) - s->offset; in code_to_degc()
121 den = s->slope; in code_to_degc()
126 degc = num - (den / 2); in code_to_degc()
136 * tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
148 struct tsens_priv *priv = s->priv; in tsens_hw_to_mC()
153 resolution = priv->fields[LAST_TEMP_0].msb - in tsens_hw_to_mC()
154 priv->fields[LAST_TEMP_0].lsb; in tsens_hw_to_mC()
156 ret = regmap_field_read(priv->rf[field], &temp); in tsens_hw_to_mC()
161 if (priv->feat->adc) in tsens_hw_to_mC()
164 /* deciCelsius -> milliCelsius along with sign extension */ in tsens_hw_to_mC()
169 * tsens_mC_to_hw - Convert temperature to hardware register value
180 struct tsens_priv *priv = s->priv; in tsens_mC_to_hw()
183 if (priv->feat->adc) in tsens_mC_to_hw()
192 return priv->feat->ver_major; in tsens_version()
211 regmap_field_write(priv->rf[index], enable ? 0 : 1); in tsens_set_interrupt_v1()
221 * - clear the mask bit in tsens_set_interrupt_v2()
223 * - Mask further interrupts for this sensor in tsens_set_interrupt_v2()
224 * - Write 1 followed by 0 to clear the interrupt in tsens_set_interrupt_v2()
242 regmap_field_write(priv->rf[index_mask], 0); in tsens_set_interrupt_v2()
244 regmap_field_write(priv->rf[index_mask], 1); in tsens_set_interrupt_v2()
245 regmap_field_write(priv->rf[index_clear], 1); in tsens_set_interrupt_v2()
246 regmap_field_write(priv->rf[index_clear], 0); in tsens_set_interrupt_v2()
251 * tsens_set_interrupt - Set state of an interrupt
252 * @priv: Pointer to tsens controller private data
257 * Call IP-specific function to set state of an interrupt
264 dev_dbg(priv->dev, "[%u] %s: %s -> %s\n", hw_id, __func__, in tsens_set_interrupt()
274 * tsens_threshold_violated - Check if a sensor temperature violated a preset threshold
275 * @priv: Pointer to tsens controller private data
287 ret = regmap_field_read(priv->rf[UPPER_STATUS_0 + hw_id], &d->up_viol); in tsens_threshold_violated()
290 ret = regmap_field_read(priv->rf[LOWER_STATUS_0 + hw_id], &d->low_viol); in tsens_threshold_violated()
294 if (priv->feat->crit_int) { in tsens_threshold_violated()
295 ret = regmap_field_read(priv->rf[CRITICAL_STATUS_0 + hw_id], in tsens_threshold_violated()
296 &d->crit_viol); in tsens_threshold_violated()
301 if (d->up_viol || d->low_viol || d->crit_viol) in tsens_threshold_violated()
313 ret = regmap_field_read(priv->rf[UP_INT_CLEAR_0 + hw_id], &d->up_irq_clear); in tsens_read_irq_state()
316 ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear); in tsens_read_irq_state()
320 ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask); in tsens_read_irq_state()
323 ret = regmap_field_read(priv->rf[LOW_INT_MASK_0 + hw_id], &d->low_irq_mask); in tsens_read_irq_state()
326 ret = regmap_field_read(priv->rf[CRIT_INT_CLEAR_0 + hw_id], in tsens_read_irq_state()
327 &d->crit_irq_clear); in tsens_read_irq_state()
330 ret = regmap_field_read(priv->rf[CRIT_INT_MASK_0 + hw_id], in tsens_read_irq_state()
331 &d->crit_irq_mask); in tsens_read_irq_state()
335 d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id); in tsens_read_irq_state()
337 /* No mask register on older TSENS */ in tsens_read_irq_state()
338 d->up_irq_mask = 0; in tsens_read_irq_state()
339 d->low_irq_mask = 0; in tsens_read_irq_state()
340 d->crit_irq_clear = 0; in tsens_read_irq_state()
341 d->crit_irq_mask = 0; in tsens_read_irq_state()
342 d->crit_thresh = 0; in tsens_read_irq_state()
345 d->up_thresh = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id); in tsens_read_irq_state()
346 d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id); in tsens_read_irq_state()
348 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()
350 (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "", in tsens_read_irq_state()
351 d->low_viol, d->up_viol, d->crit_viol, in tsens_read_irq_state()
352 d->low_irq_clear, d->up_irq_clear, d->crit_irq_clear, in tsens_read_irq_state()
353 d->low_irq_mask, d->up_irq_mask, d->crit_irq_mask); in tsens_read_irq_state()
354 dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d:%d)\n", hw_id, __func__, in tsens_read_irq_state()
355 (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "", in tsens_read_irq_state()
356 d->low_thresh, d->up_thresh, d->crit_thresh); in tsens_read_irq_state()
371 * tsens_critical_irq_thread() - Threaded handler for critical interrupts
373 * @data: tsens controller private data
377 * Clear and then re-enable the interrupt.
379 * The level-triggered interrupt might deassert if the temperature returned to
392 if (priv->feat->has_watchdog) { in tsens_critical_irq_thread()
393 ret = regmap_field_read(priv->rf[WDOG_BARK_STATUS], in tsens_critical_irq_thread()
400 regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 1); in tsens_critical_irq_thread()
401 regmap_field_write(priv->rf[WDOG_BARK_CLEAR], 0); in tsens_critical_irq_thread()
402 ret = regmap_field_read(priv->rf[WDOG_BARK_COUNT], in tsens_critical_irq_thread()
407 dev_dbg(priv->dev, "%s: watchdog count: %d\n", in tsens_critical_irq_thread()
414 for (i = 0; i < priv->num_sensors; i++) { in tsens_critical_irq_thread()
415 const struct tsens_sensor *s = &priv->sensor[i]; in tsens_critical_irq_thread()
416 u32 hw_id = s->hw_id; in tsens_critical_irq_thread()
418 if (IS_ERR(s->tzd)) in tsens_critical_irq_thread()
424 dev_err(priv->dev, "[%u] %s: error reading sensor\n", in tsens_critical_irq_thread()
441 * tsens_irq_thread - Threaded interrupt handler for uplow interrupts
443 * @data: tsens controller private data
447 * update the thresholds, else re-enable the interrupts.
449 * The level-triggered interrupt might deassert if the temperature returned to
463 for (i = 0; i < priv->num_sensors; i++) { in tsens_irq_thread()
465 const struct tsens_sensor *s = &priv->sensor[i]; in tsens_irq_thread()
466 u32 hw_id = s->hw_id; in tsens_irq_thread()
468 if (IS_ERR(s->tzd)) in tsens_irq_thread()
474 dev_err(priv->dev, "[%u] %s: error reading sensor\n", in tsens_irq_thread()
479 spin_lock_irqsave(&priv->ul_lock, flags); in tsens_irq_thread()
487 dev_dbg(priv->dev, "[%u] %s: re-arm upper\n", in tsens_irq_thread()
498 dev_dbg(priv->dev, "[%u] %s: re-arm low\n", in tsens_irq_thread()
507 spin_unlock_irqrestore(&priv->ul_lock, flags); in tsens_irq_thread()
510 dev_dbg(priv->dev, "[%u] %s: TZ update trigger (%d mC)\n", in tsens_irq_thread()
512 thermal_zone_device_update(s->tzd, in tsens_irq_thread()
515 dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", in tsens_irq_thread()
526 struct tsens_priv *priv = s->priv; in tsens_set_trips()
527 struct device *dev = priv->dev; in tsens_set_trips()
531 u32 hw_id = s->hw_id; in tsens_set_trips()
536 cl_high = clamp_val(high, -40000, 120000); in tsens_set_trips()
537 cl_low = clamp_val(low, -40000, 120000); in tsens_set_trips()
542 spin_lock_irqsave(&priv->ul_lock, flags); in tsens_set_trips()
547 regmap_field_write(priv->rf[LOW_THRESH_0 + hw_id], low_val); in tsens_set_trips()
548 regmap_field_write(priv->rf[UP_THRESH_0 + hw_id], high_val); in tsens_set_trips()
552 spin_unlock_irqrestore(&priv->ul_lock, flags); in tsens_set_trips()
554 dev_dbg(dev, "[%u] %s: (%d:%d)->(%d:%d)\n", in tsens_set_trips()
565 ret = regmap_field_write(priv->rf[INT_EN], val); in tsens_enable_irq()
567 dev_err(priv->dev, "%s: failed to enable interrupts\n", in tsens_enable_irq()
575 regmap_field_write(priv->rf[INT_EN], 0); in tsens_disable_irq()
580 struct tsens_priv *priv = s->priv; in get_temp_tsens_valid()
581 int hw_id = s->hw_id; in get_temp_tsens_valid()
587 ret = regmap_field_read(priv->rf[valid_idx], &valid); in get_temp_tsens_valid()
596 ret = regmap_field_read(priv->rf[valid_idx], &valid); in get_temp_tsens_valid()
609 struct tsens_priv *priv = s->priv; in get_temp_common()
610 int hw_id = s->hw_id; in get_temp_common()
613 ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); in get_temp_common()
625 struct platform_device *pdev = s->private; in dbg_sensors_show()
630 priv->feat->max_sensors, priv->num_sensors); in dbg_sensors_show()
632 seq_puts(s, " id slope offset\n--------------------------\n"); in dbg_sensors_show()
633 for (i = 0; i < priv->num_sensors; i++) { in dbg_sensors_show()
634 seq_printf(s, "%8d %8d %8d\n", priv->sensor[i].hw_id, in dbg_sensors_show()
635 priv->sensor[i].slope, priv->sensor[i].offset); in dbg_sensors_show()
643 struct platform_device *pdev = s->private; in dbg_version_show()
649 ret = regmap_field_read(priv->rf[VER_MAJOR], &maj_ver); in dbg_version_show()
652 ret = regmap_field_read(priv->rf[VER_MINOR], &min_ver); in dbg_version_show()
655 ret = regmap_field_read(priv->rf[VER_STEP], &step_ver); in dbg_version_show()
674 root = debugfs_lookup("tsens", NULL); in tsens_debug_init()
676 priv->debug_root = debugfs_create_dir("tsens", NULL); in tsens_debug_init()
678 priv->debug_root = root; in tsens_debug_init()
680 file = debugfs_lookup("version", priv->debug_root); in tsens_debug_init()
682 debugfs_create_file("version", 0444, priv->debug_root, in tsens_debug_init()
685 /* A directory for each instance of the TSENS IP */ in tsens_debug_init()
686 priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root); in tsens_debug_init()
687 debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops); in tsens_debug_init()
710 struct device *dev = priv->dev; in init_common()
715 struct platform_device *op = of_find_device_by_node(priv->dev->of_node); in init_common()
718 return -EINVAL; in init_common()
720 if (op->num_resources > 1) { in init_common()
722 priv->tm_offset = 0; in init_common()
730 priv->srot_map = devm_regmap_init_mmio(dev, srot_base, in init_common()
732 if (IS_ERR(priv->srot_map)) { in init_common()
733 ret = PTR_ERR(priv->srot_map); in init_common()
738 priv->tm_offset = 0x1000; in init_common()
748 priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); in init_common()
749 if (IS_ERR(priv->tm_map)) { in init_common()
750 ret = PTR_ERR(priv->tm_map); in init_common()
756 priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
757 priv->fields[i]); in init_common()
758 if (IS_ERR(priv->rf[i])) in init_common()
759 return PTR_ERR(priv->rf[i]); in init_common()
761 ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); in init_common()
766 priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
767 priv->fields[TSENS_EN]); in init_common()
768 if (IS_ERR(priv->rf[TSENS_EN])) { in init_common()
769 ret = PTR_ERR(priv->rf[TSENS_EN]); in init_common()
772 ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); in init_common()
777 ret = -ENODEV; in init_common()
781 priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map, in init_common()
782 priv->fields[SENSOR_EN]); in init_common()
783 if (IS_ERR(priv->rf[SENSOR_EN])) { in init_common()
784 ret = PTR_ERR(priv->rf[SENSOR_EN]); in init_common()
787 priv->rf[INT_EN] = devm_regmap_field_alloc(dev, priv->tm_map, in init_common()
788 priv->fields[INT_EN]); in init_common()
789 if (IS_ERR(priv->rf[INT_EN])) { in init_common()
790 ret = PTR_ERR(priv->rf[INT_EN]); in init_common()
796 for (i = 0; i < priv->feat->max_sensors; i++) { in init_common()
799 priv->rf[idx] = devm_regmap_field_alloc(dev, in init_common()
800 priv->tm_map, in init_common()
801 priv->fields[idx]); in init_common()
802 if (IS_ERR(priv->rf[idx])) { in init_common()
803 ret = PTR_ERR(priv->rf[idx]); in init_common()
809 if (priv->feat->crit_int) { in init_common()
812 for (i = 0; i < priv->feat->max_sensors; i++) { in init_common()
815 priv->rf[idx] = in init_common()
817 priv->tm_map, in init_common()
818 priv->fields[idx]); in init_common()
819 if (IS_ERR(priv->rf[idx])) { in init_common()
820 ret = PTR_ERR(priv->rf[idx]); in init_common()
829 priv->feat->has_watchdog = 1; in init_common()
831 priv->rf[i] = devm_regmap_field_alloc(dev, priv->tm_map, in init_common()
832 priv->fields[i]); in init_common()
833 if (IS_ERR(priv->rf[i])) { in init_common()
834 ret = PTR_ERR(priv->rf[i]); in init_common()
842 regmap_field_write(priv->rf[WDOG_BARK_MASK], 0); in init_common()
843 regmap_field_write(priv->rf[CC_MON_MASK], 1); in init_common()
846 spin_lock_init(&priv->ul_lock); in init_common()
851 put_device(&op->dev); in init_common()
858 struct tsens_priv *priv = s->priv; in tsens_get_temp()
860 return priv->ops->get_temp(s, temp); in tsens_get_temp()
866 struct tsens_priv *priv = s->priv; in tsens_get_trend()
868 if (priv->ops->get_trend) in tsens_get_trend()
869 return priv->ops->get_trend(s, trend); in tsens_get_trend()
871 return -ENOTSUPP; in tsens_get_trend()
878 if (priv->ops && priv->ops->suspend) in tsens_suspend()
879 return priv->ops->suspend(priv); in tsens_suspend()
888 if (priv->ops && priv->ops->resume) in tsens_resume()
889 return priv->ops->resume(priv); in tsens_resume()
898 .compatible = "qcom,msm8916-tsens",
901 .compatible = "qcom,msm8939-tsens",
904 .compatible = "qcom,msm8974-tsens",
907 .compatible = "qcom,msm8976-tsens",
910 .compatible = "qcom,msm8996-tsens",
913 .compatible = "qcom,tsens-v1",
916 .compatible = "qcom,tsens-v2",
935 pdev = of_find_device_by_node(priv->dev->of_node); in tsens_register_irq()
937 return -ENODEV; in tsens_register_irq()
943 if (irq == -ENXIO) in tsens_register_irq()
946 ret = devm_request_threaded_irq(&pdev->dev, irq, in tsens_register_irq()
949 dev_name(&pdev->dev), priv); in tsens_register_irq()
951 dev_err(&pdev->dev, "%s: failed to get irq\n", in tsens_register_irq()
957 put_device(&pdev->dev); in tsens_register_irq()
966 for (i = 0; i < priv->num_sensors; i++) { in tsens_register()
967 priv->sensor[i].priv = priv; in tsens_register()
968 tzd = devm_thermal_zone_of_sensor_register(priv->dev, priv->sensor[i].hw_id, in tsens_register()
969 &priv->sensor[i], in tsens_register()
973 priv->sensor[i].tzd = tzd; in tsens_register()
974 if (priv->ops->enable) in tsens_register()
975 priv->ops->enable(priv, i); in tsens_register()
982 if (priv->feat->crit_int) in tsens_register()
999 if (pdev->dev.of_node) in tsens_probe()
1000 dev = &pdev->dev; in tsens_probe()
1002 dev = pdev->dev.parent; in tsens_probe()
1004 np = dev->of_node; in tsens_probe()
1008 data = id->data; in tsens_probe()
1012 num_sensors = data->num_sensors; in tsens_probe()
1019 return -EINVAL; in tsens_probe()
1026 return -ENOMEM; in tsens_probe()
1028 priv->dev = dev; in tsens_probe()
1029 priv->num_sensors = num_sensors; in tsens_probe()
1030 priv->ops = data->ops; in tsens_probe()
1031 for (i = 0; i < priv->num_sensors; i++) { in tsens_probe()
1032 if (data->hw_ids) in tsens_probe()
1033 priv->sensor[i].hw_id = data->hw_ids[i]; in tsens_probe()
1035 priv->sensor[i].hw_id = i; in tsens_probe()
1037 priv->feat = data->feat; in tsens_probe()
1038 priv->fields = data->fields; in tsens_probe()
1042 if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) in tsens_probe()
1043 return -EINVAL; in tsens_probe()
1045 ret = priv->ops->init(priv); in tsens_probe()
1051 if (priv->ops->calibrate) { in tsens_probe()
1052 ret = priv->ops->calibrate(priv); in tsens_probe()
1054 if (ret != -EPROBE_DEFER) in tsens_probe()
1067 debugfs_remove_recursive(priv->debug_root); in tsens_remove()
1069 if (priv->ops->disable) in tsens_remove()
1070 priv->ops->disable(priv); in tsens_remove()
1079 .name = "qcom-tsens",
1088 MODULE_ALIAS("platform:qcom-tsens");