• Home
  • Raw
  • Download

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

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Marvell EBU Armada SoCs thermal sensor driver
67 /* Marvell EBU Thermal Sensor Dev Structure */
87 /* Formula coeficients: temp = (b - m * reg) / div */
94 /* Register shift and mask to access the sensor temperature */
112 /* One sensor is in the thermal IC, the others are in the CPUs if any */
128 * struct armada_thermal_sensor - hold the information of one thermal sensor
131 * @id: identifier of the thermal sensor
141 struct armada_thermal_data *data = priv->data; in armadaxp_init()
144 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armadaxp_init()
151 /* Reset the sensor */ in armadaxp_init()
154 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armadaxp_init()
157 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armadaxp_init()
159 /* Enable the sensor */ in armadaxp_init()
160 regmap_read(priv->syscon, data->syscon_status_off, &reg); in armadaxp_init()
162 regmap_write(priv->syscon, data->syscon_status_off, reg); in armadaxp_init()
168 struct armada_thermal_data *data = priv->data; in armada370_init()
171 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada370_init()
178 /* Reset the sensor */ in armada370_init()
181 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada370_init()
189 struct armada_thermal_data *data = priv->data; in armada375_init()
192 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada375_init()
196 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada375_init()
201 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada375_init()
210 return regmap_read_poll_timeout(priv->syscon, in armada_wait_sensor_validity()
211 priv->data->syscon_status_off, reg, in armada_wait_sensor_validity()
212 reg & priv->data->is_valid_bit, in armada_wait_sensor_validity()
220 struct armada_thermal_data *data = priv->data; in armada380_init()
224 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada380_init()
227 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada380_init()
230 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada380_init()
233 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada380_init()
239 struct armada_thermal_data *data = priv->data; in armada_ap806_init()
242 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada_ap806_init()
252 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada_ap806_init()
258 struct armada_thermal_data *data = priv->data; in armada_cp110_init()
264 regmap_read(priv->syscon, data->syscon_control0_off, &reg); in armada_cp110_init()
266 regmap_write(priv->syscon, data->syscon_control0_off, reg); in armada_cp110_init()
269 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_cp110_init()
272 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_cp110_init()
279 if (!priv->data->is_valid_bit) in armada_is_valid()
282 regmap_read(priv->syscon, priv->data->syscon_status_off, &reg); in armada_is_valid()
284 return reg & priv->data->is_valid_bit; in armada_is_valid()
289 struct armada_thermal_data *data = priv->data; in armada_enable_overheat_interrupt()
293 regmap_read(priv->syscon, data->dfx_irq_cause_off, &reg); in armada_enable_overheat_interrupt()
296 regmap_read(priv->syscon, data->dfx_irq_mask_off, &reg); in armada_enable_overheat_interrupt()
297 reg |= data->dfx_overheat_irq; in armada_enable_overheat_interrupt()
298 regmap_write(priv->syscon, data->dfx_irq_mask_off, reg); in armada_enable_overheat_interrupt()
301 regmap_read(priv->syscon, data->dfx_server_irq_mask_off, &reg); in armada_enable_overheat_interrupt()
302 reg |= data->dfx_server_irq_en; in armada_enable_overheat_interrupt()
303 regmap_write(priv->syscon, data->dfx_server_irq_mask_off, reg); in armada_enable_overheat_interrupt()
306 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_enable_overheat_interrupt()
308 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_enable_overheat_interrupt()
314 struct armada_thermal_data *data = priv->data; in armada_disable_overheat_interrupt()
317 regmap_read(priv->syscon, data->syscon_control1_off, &reg); in armada_disable_overheat_interrupt()
319 regmap_write(priv->syscon, data->syscon_control1_off, reg); in armada_disable_overheat_interrupt()
322 /* There is currently no board with more than one sensor per channel */
323 static int armada_select_channel(struct armada_thermal_priv *priv, int channel) in armada_select_channel() argument
325 struct armada_thermal_data *data = priv->data; in armada_select_channel()
328 if (channel < 0 || channel > priv->data->cpu_nr) in armada_select_channel()
329 return -EINVAL; in armada_select_channel()
331 if (priv->current_channel == channel) in armada_select_channel()
335 regmap_read(priv->syscon, data->syscon_control0_off, &ctrl0); in armada_select_channel()
337 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
339 /* Reset the mode, internal sensor will be automatically selected */ in armada_select_channel()
343 if (channel) { in armada_select_channel()
347 /* Select the sensor */ in armada_select_channel()
349 ctrl0 |= (channel - 1) << CONTROL0_TSEN_CHAN_SHIFT; in armada_select_channel()
352 /* Actually set the mode/channel */ in armada_select_channel()
353 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
354 priv->current_channel = channel; in armada_select_channel()
356 /* Re-start the measurements */ in armada_select_channel()
358 regmap_write(priv->syscon, data->syscon_control0_off, ctrl0); in armada_select_channel()
362 * we must absolutely wait for the sensor validity bit to ensure we read in armada_select_channel()
366 dev_err(priv->dev, in armada_select_channel()
367 "Temperature sensor reading not valid\n"); in armada_select_channel()
368 return -EIO; in armada_select_channel()
379 regmap_read(priv->syscon, priv->data->syscon_status_off, &reg); in armada_read_sensor()
380 reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask; in armada_read_sensor()
381 if (priv->data->signed_sample) in armada_read_sensor()
383 sample = sign_extend32(reg, fls(priv->data->temp_mask) - 1); in armada_read_sensor()
388 b = priv->data->coef_b; in armada_read_sensor()
389 m = priv->data->coef_m; in armada_read_sensor()
390 div = priv->data->coef_div; in armada_read_sensor()
392 if (priv->data->inverted) in armada_read_sensor()
393 *temp = div_s64((m * sample) - b, div); in armada_read_sensor()
395 *temp = div_s64(b - (m * sample), div); in armada_read_sensor()
403 struct armada_thermal_priv *priv = thermal->devdata; in armada_get_temp_legacy()
408 dev_err(priv->dev, in armada_get_temp_legacy()
409 "Temperature sensor reading not valid\n"); in armada_get_temp_legacy()
410 return -EIO; in armada_get_temp_legacy()
425 struct armada_thermal_sensor *sensor = _sensor; in armada_get_temp() local
426 struct armada_thermal_priv *priv = sensor->priv; in armada_get_temp()
429 mutex_lock(&priv->update_lock); in armada_get_temp()
431 /* Select the desired channel */ in armada_get_temp()
432 ret = armada_select_channel(priv, sensor->id); in armada_get_temp()
442 * Select back the interrupt source channel from which a potential in armada_get_temp()
445 ret = armada_select_channel(priv, priv->interrupt_source); in armada_get_temp()
448 mutex_unlock(&priv->update_lock); in armada_get_temp()
460 s64 b = data->coef_b; in armada_mc_to_reg_temp()
461 s64 m = data->coef_m; in armada_mc_to_reg_temp()
462 s64 div = data->coef_div; in armada_mc_to_reg_temp()
465 if (data->inverted) in armada_mc_to_reg_temp()
468 sample = div_s64((b - (temp_mc * div)), m); in armada_mc_to_reg_temp()
470 return sample & data->temp_mask; in armada_mc_to_reg_temp()
475 * high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2)
491 for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--) in armada_mc_to_reg_hyst()
495 return i & data->hyst_mask; in armada_mc_to_reg_hyst()
501 struct armada_thermal_data *data = priv->data; in armada_set_overheat_thresholds()
506 regmap_read(priv->syscon, data->syscon_control1_off, &ctrl1); in armada_set_overheat_thresholds()
510 ctrl1 &= ~(data->temp_mask << data->thresh_shift); in armada_set_overheat_thresholds()
511 ctrl1 |= threshold << data->thresh_shift; in armada_set_overheat_thresholds()
512 priv->current_threshold = thresh_mc; in armada_set_overheat_thresholds()
517 ctrl1 &= ~(data->hyst_mask << data->hyst_shift); in armada_set_overheat_thresholds()
518 ctrl1 |= hysteresis << data->hyst_shift; in armada_set_overheat_thresholds()
519 priv->current_hysteresis = hyst_mc; in armada_set_overheat_thresholds()
522 regmap_write(priv->syscon, data->syscon_control1_off, ctrl1); in armada_set_overheat_thresholds()
539 int low_threshold = priv->current_threshold - priv->current_hysteresis; in armada_overheat_isr_thread()
545 thermal_zone_device_update(priv->overheat_sensor, in armada_overheat_isr_thread()
555 mutex_lock(&priv->update_lock); in armada_overheat_isr_thread()
557 mutex_unlock(&priv->update_lock); in armada_overheat_isr_thread()
562 regmap_read(priv->syscon, priv->data->dfx_irq_cause_off, &dummy); in armada_overheat_isr_thread()
565 thermal_zone_device_update(priv->overheat_sensor, in armada_overheat_isr_thread()
632 .coef_b = -150000LL,
672 .compatible = "marvell,armadaxp-thermal",
676 .compatible = "marvell,armada370-thermal",
680 .compatible = "marvell,armada375-thermal",
684 .compatible = "marvell,armada380-thermal",
688 .compatible = "marvell,armada-ap806-thermal",
692 .compatible = "marvell,armada-cp110-thermal",
711 struct armada_thermal_data *data = priv->data; in armada_thermal_probe_legacy()
717 base = devm_ioremap_resource(&pdev->dev, res); in armada_thermal_probe_legacy()
728 if (((unsigned long)base & ~PAGE_MASK) < data->syscon_status_off) in armada_thermal_probe_legacy()
729 return -EINVAL; in armada_thermal_probe_legacy()
730 base -= data->syscon_status_off; in armada_thermal_probe_legacy()
732 priv->syscon = devm_regmap_init_mmio(&pdev->dev, base, in armada_thermal_probe_legacy()
734 return PTR_ERR_OR_ZERO(priv->syscon); in armada_thermal_probe_legacy()
740 priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node); in armada_thermal_probe_syscon()
741 return PTR_ERR_OR_ZERO(priv->syscon); in armada_thermal_probe_syscon()
747 const char *name = dev_name(&pdev->dev); in armada_set_sane_name()
753 * form: f06f8000.system-controller:ap-thermal so stripping in armada_set_sane_name()
764 strncpy(priv->zone_name, name, THERMAL_NAME_LENGTH - 1); in armada_set_sane_name()
765 priv->zone_name[THERMAL_NAME_LENGTH - 1] = '\0'; in armada_set_sane_name()
767 /* Then check there are no '-' or hwmon core will complain */ in armada_set_sane_name()
769 insane_char = strpbrk(priv->zone_name, "-"); in armada_set_sane_name()
778 * source (ie. the last read sensor), which is an inconsistent behavior. Avoid
779 * possible glitches by always selecting back only one channel (arbitrarily: the
780 * first in the DT which has a critical trip point). We also disable sensor
793 return -EINVAL; in armada_configure_overheat_int()
800 return -EINVAL; in armada_configure_overheat_int()
809 priv->overheat_sensor = tz; in armada_configure_overheat_int()
810 priv->interrupt_source = sensor_id; in armada_configure_overheat_int()
820 struct armada_thermal_sensor *sensor; in armada_thermal_probe() local
827 match = of_match_device(armada_thermal_id_table, &pdev->dev); in armada_thermal_probe()
829 return -ENODEV; in armada_thermal_probe()
831 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in armada_thermal_probe()
833 return -ENOMEM; in armada_thermal_probe()
835 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); in armada_thermal_probe()
837 return -ENOMEM; in armada_thermal_probe()
839 priv->dev = &pdev->dev; in armada_thermal_probe()
840 priv->data = (struct armada_thermal_data *)match->data; in armada_thermal_probe()
842 mutex_init(&priv->update_lock); in armada_thermal_probe()
856 if (IS_ERR(syscon_node_to_regmap(pdev->dev.parent->of_node))) { in armada_thermal_probe()
864 priv->data->init(pdev, priv); in armada_thermal_probe()
869 tz = thermal_zone_device_register(priv->zone_name, 0, 0, priv, in armada_thermal_probe()
872 dev_err(&pdev->dev, in armada_thermal_probe()
883 drvdata->type = LEGACY; in armada_thermal_probe()
884 drvdata->data.tz = tz; in armada_thermal_probe()
894 priv->current_channel = -1; in armada_thermal_probe()
895 priv->data->init(pdev, priv); in armada_thermal_probe()
896 drvdata->type = SYSCON; in armada_thermal_probe()
897 drvdata->data.priv = priv; in armada_thermal_probe()
901 if (irq == -EPROBE_DEFER) in armada_thermal_probe()
906 ret = devm_request_threaded_irq(&pdev->dev, irq, in armada_thermal_probe()
911 dev_err(&pdev->dev, "Cannot request threaded IRQ %d\n", in armada_thermal_probe()
918 * There is one channel for the IC and one per CPU (if any), each in armada_thermal_probe()
919 * channel has one sensor. in armada_thermal_probe()
921 for (sensor_id = 0; sensor_id <= priv->data->cpu_nr; sensor_id++) { in armada_thermal_probe()
922 sensor = devm_kzalloc(&pdev->dev, in armada_thermal_probe()
925 if (!sensor) in armada_thermal_probe()
926 return -ENOMEM; in armada_thermal_probe()
928 /* Register the sensor */ in armada_thermal_probe()
929 sensor->priv = priv; in armada_thermal_probe()
930 sensor->id = sensor_id; in armada_thermal_probe()
931 tz = devm_thermal_zone_of_sensor_register(&pdev->dev, in armada_thermal_probe()
932 sensor->id, sensor, in armada_thermal_probe()
935 dev_info(&pdev->dev, "Thermal sensor %d unavailable\n", in armada_thermal_probe()
937 devm_kfree(&pdev->dev, sensor); in armada_thermal_probe()
942 * The first channel that has a critical trip point registered in armada_thermal_probe()
946 if (irq > 0 && !priv->overheat_sensor) in armada_thermal_probe()
947 armada_configure_overheat_int(priv, tz, sensor->id); in armada_thermal_probe()
951 if (!priv->overheat_sensor) in armada_thermal_probe()
952 dev_warn(&pdev->dev, "Overheat interrupt not available\n"); in armada_thermal_probe()
961 if (drvdata->type == LEGACY) in armada_thermal_exit()
962 thermal_zone_device_unregister(drvdata->data.tz); in armada_thermal_exit()
978 MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");