Lines Matching +full:sensor +full:- +full:channel

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Marvell EBU Armada SoCs thermal sensor driver
65 /* Marvell EBU Thermal Sensor Dev Structure */
85 /* Formula coeficients: temp = (b - m * reg) / div */
92 /* Register shift and mask to access the sensor temperature */
110 /* One sensor is in the thermal IC, the others are in the CPUs if any */
126 * struct armada_thermal_sensor - hold the information of one thermal sensor
129 * @id: identifier of the thermal sensor
139 struct armada_thermal_data *data = priv->data; in armadaxp_init()
142 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armadaxp_init()
149 /* Reset the sensor */ in armadaxp_init()
152 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armadaxp_init()
155 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armadaxp_init()
157 /* Enable the sensor */ in armadaxp_init()
158 regmap_read(priv->syscon, data->syscon_status_off, &reg); in armadaxp_init()
160 regmap_write(priv->syscon, data->syscon_status_off, reg); in armadaxp_init()
166 struct armada_thermal_data *data = priv->data; in armada370_init()
169 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada370_init()
176 /* Reset the sensor */ in armada370_init()
179 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada370_init()
187 struct armada_thermal_data *data = priv->data; in armada375_init()
190 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada375_init()
194 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada375_init()
199 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada375_init()
208 return regmap_read_poll_timeout(priv->syscon, in armada_wait_sensor_validity()
209 priv->data->syscon_status_off, reg, in armada_wait_sensor_validity()
210 reg & priv->data->is_valid_bit, in armada_wait_sensor_validity()
218 struct armada_thermal_data *data = priv->data; in armada380_init()
222 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada380_init()
225 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada380_init()
228 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada380_init()
231 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada380_init()
237 struct armada_thermal_data *data = priv->data; in armada_ap80x_init()
240 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada_ap80x_init()
250 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada_ap80x_init()
256 struct armada_thermal_data *data = priv->data; in armada_cp110_init()
262 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada_cp110_init()
264 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada_cp110_init()
267 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_cp110_init()
270 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_cp110_init()
277 if (!priv->data->is_valid_bit) in armada_is_valid()
280 regmap_read(priv->syscon, priv->data->syscon_status_off, &reg); in armada_is_valid()
282 return reg & priv->data->is_valid_bit; in armada_is_valid()
287 struct armada_thermal_data *data = priv->data; in armada_enable_overheat_interrupt()
291 regmap_read(priv->syscon, data->dfx_irq_cause_off, &reg); in armada_enable_overheat_interrupt()
294 regmap_read(priv->syscon, data->dfx_irq_mask_off, &reg); in armada_enable_overheat_interrupt()
295 reg |= data->dfx_overheat_irq; in armada_enable_overheat_interrupt()
296 regmap_write(priv->syscon, data->dfx_irq_mask_off, reg); in armada_enable_overheat_interrupt()
299 regmap_read(priv->syscon, data->dfx_server_irq_mask_off, &reg); in armada_enable_overheat_interrupt()
300 reg |= data->dfx_server_irq_en; in armada_enable_overheat_interrupt()
301 regmap_write(priv->syscon, data->dfx_server_irq_mask_off, reg); in armada_enable_overheat_interrupt()
304 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_enable_overheat_interrupt()
306 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_enable_overheat_interrupt()
312 struct armada_thermal_data *data = priv->data; in armada_disable_overheat_interrupt()
315 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_disable_overheat_interrupt()
317 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_disable_overheat_interrupt()
320 /* There is currently no board with more than one sensor per channel */
321 static int armada_select_channel(struct armada_thermal_priv *priv, int channel) in armada_select_channel() argument
323 struct armada_thermal_data *data = priv->data; in armada_select_channel()
326 if (channel < 0 || channel > priv->data->cpu_nr) in armada_select_channel()
327 return -EINVAL; in armada_select_channel()
329 if (priv->current_channel == channel) in armada_select_channel()
333 regmap_read(priv->syscon, data->syscon_control0_off, &ctrl0); in armada_select_channel()
335 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
337 /* Reset the mode, internal sensor will be automatically selected */ in armada_select_channel()
341 if (channel) { in armada_select_channel()
345 /* Select the sensor */ in armada_select_channel()
347 ctrl0 |= (channel - 1) << CONTROL0_TSEN_CHAN_SHIFT; in armada_select_channel()
350 /* Actually set the mode/channel */ in armada_select_channel()
351 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
352 priv->current_channel = channel; in armada_select_channel()
354 /* Re-start the measurements */ in armada_select_channel()
356 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
360 * we must absolutely wait for the sensor validity bit to ensure we read in armada_select_channel()
364 return -EIO; in armada_select_channel()
374 regmap_read(priv->syscon, priv->data->syscon_status_off, &reg); in armada_read_sensor()
375 reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask; in armada_read_sensor()
376 if (priv->data->signed_sample) in armada_read_sensor()
378 sample = sign_extend32(reg, fls(priv->data->temp_mask) - 1); in armada_read_sensor()
383 b = priv->data->coef_b; in armada_read_sensor()
384 m = priv->data->coef_m; in armada_read_sensor()
385 div = priv->data->coef_div; in armada_read_sensor()
387 if (priv->data->inverted) in armada_read_sensor()
388 *temp = div_s64((m * sample) - b, div); in armada_read_sensor()
390 *temp = div_s64(b - (m * sample), div); in armada_read_sensor()
403 return -EIO; in armada_get_temp_legacy()
417 struct armada_thermal_sensor *sensor = thermal_zone_device_priv(tz); in armada_get_temp() local
418 struct armada_thermal_priv *priv = sensor->priv; in armada_get_temp()
421 mutex_lock(&priv->update_lock); in armada_get_temp()
423 /* Select the desired channel */ in armada_get_temp()
424 ret = armada_select_channel(priv, sensor->id); in armada_get_temp()
434 * Select back the interrupt source channel from which a potential in armada_get_temp()
437 ret = armada_select_channel(priv, priv->interrupt_source); in armada_get_temp()
440 mutex_unlock(&priv->update_lock); in armada_get_temp()
452 s64 b = data->coef_b; in armada_mc_to_reg_temp()
453 s64 m = data->coef_m; in armada_mc_to_reg_temp()
454 s64 div = data->coef_div; in armada_mc_to_reg_temp()
457 if (data->inverted) in armada_mc_to_reg_temp()
460 sample = div_s64((b - (temp_mc * div)), m); in armada_mc_to_reg_temp()
462 return sample & data->temp_mask; in armada_mc_to_reg_temp()
467 * high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2)
483 for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--) in armada_mc_to_reg_hyst()
487 return i & data->hyst_mask; in armada_mc_to_reg_hyst()
493 struct armada_thermal_data *data = priv->data; in armada_set_overheat_thresholds()
498 regmap_read(priv->syscon, data->syscon_control1_off, &ctrl1); in armada_set_overheat_thresholds()
502 ctrl1 &= ~(data->temp_mask << data->thresh_shift); in armada_set_overheat_thresholds()
503 ctrl1 |= threshold << data->thresh_shift; in armada_set_overheat_thresholds()
504 priv->current_threshold = thresh_mc; in armada_set_overheat_thresholds()
509 ctrl1 &= ~(data->hyst_mask << data->hyst_shift); in armada_set_overheat_thresholds()
510 ctrl1 |= hysteresis << data->hyst_shift; in armada_set_overheat_thresholds()
511 priv->current_hysteresis = hyst_mc; in armada_set_overheat_thresholds()
514 regmap_write(priv->syscon, data->syscon_control1_off, ctrl1); in armada_set_overheat_thresholds()
531 int low_threshold = priv->current_threshold - priv->current_hysteresis; in armada_overheat_isr_thread()
537 thermal_zone_device_update(priv->overheat_sensor, in armada_overheat_isr_thread()
547 mutex_lock(&priv->update_lock); in armada_overheat_isr_thread()
549 mutex_unlock(&priv->update_lock); in armada_overheat_isr_thread()
554 regmap_read(priv->syscon, priv->data->dfx_irq_cause_off, &dummy); in armada_overheat_isr_thread()
557 thermal_zone_device_update(priv->overheat_sensor, in armada_overheat_isr_thread()
624 .coef_b = -150000LL,
648 .coef_b = -128900LL,
688 .compatible = "marvell,armadaxp-thermal",
692 .compatible = "marvell,armada370-thermal",
696 .compatible = "marvell,armada375-thermal",
700 .compatible = "marvell,armada380-thermal",
704 .compatible = "marvell,armada-ap806-thermal",
708 .compatible = "marvell,armada-ap807-thermal",
712 .compatible = "marvell,armada-cp110-thermal",
731 struct armada_thermal_data *data = priv->data; in armada_thermal_probe_legacy()
746 if (((unsigned long)base & ~PAGE_MASK) < data->syscon_status_off) in armada_thermal_probe_legacy()
747 return -EINVAL; in armada_thermal_probe_legacy()
748 base -= data->syscon_status_off; in armada_thermal_probe_legacy()
750 priv->syscon = devm_regmap_init_mmio(&pdev->dev, base, in armada_thermal_probe_legacy()
752 return PTR_ERR_OR_ZERO(priv->syscon); in armada_thermal_probe_legacy()
758 priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node); in armada_thermal_probe_syscon()
759 return PTR_ERR_OR_ZERO(priv->syscon); in armada_thermal_probe_syscon()
765 const char *name = dev_name(&pdev->dev); in armada_set_sane_name()
770 * form: f06f8000.system-controller:ap-thermal so stripping in armada_set_sane_name()
781 strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH); in armada_set_sane_name()
783 /* Then ensure there are no '-' or hwmon core will complain */ in armada_set_sane_name()
784 strreplace(priv->zone_name, '-', '_'); in armada_set_sane_name()
790 * source (ie. the last read sensor), which is an inconsistent behavior. Avoid
791 * possible glitches by always selecting back only one channel (arbitrarily: the
792 * first in the DT which has a critical trip point). We also disable sensor
815 priv->overheat_sensor = tz; in armada_configure_overheat_int()
816 priv->interrupt_source = sensor_id; in armada_configure_overheat_int()
825 struct armada_thermal_sensor *sensor; in armada_thermal_probe() local
832 match = of_match_device(armada_thermal_id_table, &pdev->dev); in armada_thermal_probe()
834 return -ENODEV; in armada_thermal_probe()
836 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in armada_thermal_probe()
838 return -ENOMEM; in armada_thermal_probe()
840 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); in armada_thermal_probe()
842 return -ENOMEM; in armada_thermal_probe()
844 priv->dev = &pdev->dev; in armada_thermal_probe()
845 priv->data = (struct armada_thermal_data *)match->data; in armada_thermal_probe()
847 mutex_init(&priv->update_lock); in armada_thermal_probe()
861 if (IS_ERR(syscon_node_to_regmap(pdev->dev.parent->of_node))) { in armada_thermal_probe()
869 priv->data->init(pdev, priv); in armada_thermal_probe()
874 tz = thermal_tripless_zone_device_register(priv->zone_name, in armada_thermal_probe()
878 dev_err(&pdev->dev, in armada_thermal_probe()
889 drvdata->type = LEGACY; in armada_thermal_probe()
890 drvdata->data.tz = tz; in armada_thermal_probe()
900 priv->current_channel = -1; in armada_thermal_probe()
901 priv->data->init(pdev, priv); in armada_thermal_probe()
902 drvdata->type = SYSCON; in armada_thermal_probe()
903 drvdata->data.priv = priv; in armada_thermal_probe()
907 if (irq == -EPROBE_DEFER) in armada_thermal_probe()
912 ret = devm_request_threaded_irq(&pdev->dev, irq, in armada_thermal_probe()
917 dev_err(&pdev->dev, "Cannot request threaded IRQ %d\n", in armada_thermal_probe()
924 * There is one channel for the IC and one per CPU (if any), each in armada_thermal_probe()
925 * channel has one sensor. in armada_thermal_probe()
927 for (sensor_id = 0; sensor_id <= priv->data->cpu_nr; sensor_id++) { in armada_thermal_probe()
928 sensor = devm_kzalloc(&pdev->dev, in armada_thermal_probe()
931 if (!sensor) in armada_thermal_probe()
932 return -ENOMEM; in armada_thermal_probe()
934 /* Register the sensor */ in armada_thermal_probe()
935 sensor->priv = priv; in armada_thermal_probe()
936 sensor->id = sensor_id; in armada_thermal_probe()
937 tz = devm_thermal_of_zone_register(&pdev->dev, in armada_thermal_probe()
938 sensor->id, sensor, in armada_thermal_probe()
941 dev_info(&pdev->dev, "Thermal sensor %d unavailable\n", in armada_thermal_probe()
943 devm_kfree(&pdev->dev, sensor); in armada_thermal_probe()
948 * The first channel that has a critical trip point registered in armada_thermal_probe()
952 if (irq > 0 && !priv->overheat_sensor) in armada_thermal_probe()
953 armada_configure_overheat_int(priv, tz, sensor->id); in armada_thermal_probe()
957 if (!priv->overheat_sensor) in armada_thermal_probe()
958 dev_warn(&pdev->dev, "Overheat interrupt not available\n"); in armada_thermal_probe()
967 if (drvdata->type == LEGACY) in armada_thermal_exit()
968 thermal_zone_device_unregister(drvdata->data.tz); in armada_thermal_exit()
982 MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");