staticint tegra_tsensor_hw_enable(conststruct tegra_tsensor *ts)
{
u32 val; int err;
err = reset_control_assert(ts->rst); if (err) {
dev_err(ts->dev, "failed to assert hardware reset: %d\n", err); return err;
}
err = clk_prepare_enable(ts->clk); if (err) {
dev_err(ts->dev, "failed to enable clock: %d\n", err); return err;
}
fsleep(1000);
err = reset_control_deassert(ts->rst); if (err) {
dev_err(ts->dev, "failed to deassert hardware reset: %d\n", err); goto disable_clk;
}
/* * Sensors are enabled after reset by default, but not gauging * until clock counter is programmed. * * M: number of reference clock pulses after which every * temperature / voltage measurement is made * * N: number of reference clock counts for which the counter runs
*/
val = FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_M, 12500);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_N, 255);
/* apply the same configuration to both channels */
writel_relaxed(val, ts->regs + 0x40 + TSENSOR_SENSOR0_CONFIG0);
writel_relaxed(val, ts->regs + 0x80 + TSENSOR_SENSOR0_CONFIG0);
return 0;
disable_clk:
clk_disable_unprepare(ts->clk);
return err;
}
staticint tegra_tsensor_hw_disable(conststruct tegra_tsensor *ts)
{ int err;
err = reset_control_assert(ts->rst); if (err) {
dev_err(ts->dev, "failed to assert hardware reset: %d\n", err); return err;
}
/* * Counter will be invalid if hardware is misprogrammed or not enough * time passed since the time when sensor was enabled.
*/
err = readl_relaxed_poll_timeout(tsc->regs + TSENSOR_SENSOR0_STATUS0, val,
val & TSENSOR_SENSOR0_STATUS0_CURRENT_VALID,
21 * USEC_PER_MSEC,
21 * USEC_PER_MSEC * 50); if (err) {
dev_err_once(ts->dev, "ch%u: counter invalid\n", tsc->id); return err;
}
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_TS_STATUS1);
counter = FIELD_GET(TSENSOR_SENSOR0_TS_STATUS1_CURRENT_COUNT, val);
/* * This shouldn't happen with a valid counter status, nevertheless * lets verify the value since it's in a separate (from status) * register.
*/ if (counter == 0xffff) {
dev_err_once(ts->dev, "ch%u: counter overflow\n", tsc->id); return -EINVAL;
}
/* * temperature = a * counter + b * temperature = m * (temperature ^ 2) + n * temperature + p
*/
c1 = DIV_ROUND_CLOSEST(ts->calib.a * counter + ts->calib.b, 1000000);
c1 = c1 ?: 1;
c2 = DIV_ROUND_CLOSEST(ts->calib.p, c1);
c3 = c1 * ts->calib.m;
c4 = ts->calib.n;
/* * TSENSOR doesn't trigger interrupt on the "low" temperature breach, * hence bail out if high temperature is unspecified.
*/ if (high == INT_MAX) return 0;
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG1);
val &= ~TSENSOR_SENSOR0_CONFIG1_TH1;
high = tegra_tsensor_temp_to_counter(ts, high);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH1, high);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG1);
staticvoid tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd, struct trip_temps *temps)
{ /* * 90C is the maximal critical temperature of all Tegra30 SoC variants, * use it for the default trip if unspecified in a device-tree.
*/
temps->hot_trip = 85000;
temps->crit_trip = 90000;
/* clamp hardware trips to the calibration limits */
temps->hot_trip = clamp(temps->hot_trip, 25000, 90000);
/* * Kernel will perform a normal system shut down if it will * see that critical temperature is breached, hence set the * hardware limit by 5C higher in order to allow system to * shut down gracefully before sending signal to the Power * Management controller.
*/
temps->crit_trip = clamp(temps->crit_trip + 5000, 25000, 90000);
}
if (!tzd) {
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0);
val &= ~TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP;
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG0);
return 0;
}
tegra_tsensor_get_hw_channel_trips(tzd, &temps);
dev_info_once(ts->dev, "ch%u: PMC emergency shutdown trip set to %dC\n",
id, DIV_ROUND_CLOSEST(temps.crit_trip, 1000));
/* program LEVEL2 counter threshold */
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG1);
val &= ~TSENSOR_SENSOR0_CONFIG1_TH2;
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH2, temps.hot_trip);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG1);
/* program LEVEL3 counter threshold */
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG2);
val &= ~TSENSOR_SENSOR0_CONFIG2_TH3;
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG2_TH3, temps.crit_trip);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG2);
/* * Enable sensor, emergency shutdown, interrupts for level 1/2/3 * breaches and counter overflow condition. * * Disable DIV2 throttle for now since we need to figure out how * to integrate it properly with the thermal framework. * * Thermal levels supported by hardware: * * Level 0 = cold * Level 1 = passive cooling (cpufreq DVFS) * Level 2 = passive cooling assisted by hardware (DIV2) * Level 3 = emergency shutdown assisted by hardware (PMC)
*/
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0);
val &= ~TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP;
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_DVFS_EN, 1);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN, 0);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_THERMAL_RST_EN, 1);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_OVERFLOW_EN, 1);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_HW_FREQ_DIV_EN, 1);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_THERMAL_RST_EN, 1);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG0);
err = thermal_zone_device_enable(tzd); if (err) {
dev_err(ts->dev, "ch%u: failed to enable zone: %d\n", id, err); return err;
}
return 0;
}
staticbool tegra_tsensor_fuse_read_spare(unsignedint spare)
{
u32 val = 0;
staticint tegra_tsensor_nvmem_setup(struct tegra_tsensor *ts)
{
u32 i, ate_ver = 0, cal = 0, t1_25C = 0, t2_90C = 0; int err, c1_25C, c2_90C;
err = tegra_fuse_readl(TEGRA30_FUSE_TEST_PROG_VER, &ate_ver); if (err) {
dev_err_probe(ts->dev, err, "failed to get ATE version\n"); return err;
}
if (ate_ver < 8) {
dev_info(ts->dev, "unsupported ATE version: %u\n", ate_ver); return -ENODEV;
}
/* * We have two TSENSOR channels in a two different spots on SoC. * Second channel provides more accurate data on older SoC versions, * use it as a primary channel.
*/ if (ate_ver <= 21) {
dev_info_once(ts->dev, "older ATE version detected, channels remapped\n");
ts->swap_channels = true;
}
err = tegra_fuse_readl(TEGRA30_FUSE_TSENSOR_CALIB, &cal); if (err) {
dev_err(ts->dev, "failed to get calibration data: %d\n", err); return err;
}
/* get calibrated counter values for 25C/90C thresholds */
c1_25C = FIELD_GET(TEGRA30_FUSE_TSENSOR_CALIB_LOW, cal);
c2_90C = FIELD_GET(TEGRA30_FUSE_TSENSOR_CALIB_HIGH, cal);
/* and calibrated temperatures corresponding to the counter values */ for (i = 0; i < 7; i++) {
t1_25C |= tegra_tsensor_fuse_read_spare(14 + i) << i;
t1_25C |= tegra_tsensor_fuse_read_spare(21 + i) << i;
ts->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ts->regs)) return PTR_ERR(ts->regs);
ts->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ts->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(ts->clk), "failed to get clock\n");
ts->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(ts->rst)) return dev_err_probe(&pdev->dev, PTR_ERR(ts->rst), "failed to get reset control\n");
err = tegra_tsensor_nvmem_setup(ts); if (err) return err;
err = tegra_tsensor_hw_enable(ts); if (err) return err;
err = devm_add_action_or_reset(&pdev->dev,
devm_tegra_tsensor_hw_disable,
ts); if (err) return err;
for (i = 0; i < ARRAY_SIZE(ts->ch); i++) {
err = tegra_tsensor_register_channel(ts, i); if (err) return err;
}
/* * Enable the channels before setting the interrupt so * set_trips() can not be called while we are setting up the * register TSENSOR_SENSOR0_CONFIG1. With this we close a * potential race window where we are setting up the TH2 and * the temperature hits TH1 resulting to an update of the * TSENSOR_SENSOR0_CONFIG1 register in the ISR.
*/ for (i = 0; i < ARRAY_SIZE(ts->ch); i++) {
err = tegra_tsensor_enable_hw_channel(ts, i); if (err) return err;
}
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
tegra_tsensor_isr, IRQF_ONESHOT, "tegra_tsensor", ts); if (err) return dev_err_probe(&pdev->dev, err, "failed to request interrupt\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.