1

thermal/drivers/k3_j72xx_bandgap: Implement suspend/resume support

This add suspend-to-ram support.

The derived_table is kept-as is, so the resume is only about
pm_runtime_* calls and restoring the same registers as the probe.

Extract the hardware initialization procedure to a function called at
both probe-time & resume-time.

The probe-time loop is split in two to ensure doing the hardware
initialization before registering thermal zones. That ensures our
callbacks cannot be called while in bad state.

The 100ms delay in the hardware initialization sequence was removed.
It was initially added to be sure the thresholds are programmed before
enabling the interrupt, but in fact it's not needed (tested on J7200
platform).

Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
Acked-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
Link: https://lore.kernel.org/r/20240425153238.498750-1-thomas.richard@bootlin.com
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
This commit is contained in:
Théo Lebrun 2024-04-25 17:32:38 +02:00 committed by Daniel Lezcano
parent f996e2b17a
commit 854a8e208c

View File

@ -178,6 +178,7 @@ struct k3_j72xx_bandgap {
void __iomem *base; void __iomem *base;
void __iomem *cfg2_base; void __iomem *cfg2_base;
struct k3_thermal_data *ts_data[K3_VTM_MAX_NUM_TS]; struct k3_thermal_data *ts_data[K3_VTM_MAX_NUM_TS];
int cnt;
}; };
/* common data structures */ /* common data structures */
@ -338,24 +339,52 @@ static void print_look_up_table(struct device *dev, int *ref_table)
dev_dbg(dev, "%d %d %d\n", i, derived_table[i], ref_table[i]); dev_dbg(dev, "%d %d %d\n", i, derived_table[i], ref_table[i]);
} }
static void k3_j72xx_bandgap_init_hw(struct k3_j72xx_bandgap *bgp)
{
struct k3_thermal_data *data;
int id, high_max, low_temp;
u32 val;
for (id = 0; id < bgp->cnt; id++) {
data = bgp->ts_data[id];
val = readl(bgp->cfg2_base + data->ctrl_offset);
val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN |
K3_VTM_TMPSENS_CTRL_SOC |
K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4));
writel(val, bgp->cfg2_base + data->ctrl_offset);
}
/*
* Program TSHUT thresholds
* Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2
* Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit
* This is already taken care as per of init
* Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit
*/
high_max = k3_j72xx_bandgap_temp_to_adc_code(MAX_TEMP);
low_temp = k3_j72xx_bandgap_temp_to_adc_code(COOL_DOWN_TEMP);
writel((low_temp << 16) | high_max, bgp->cfg2_base + K3_VTM_MISC_CTRL2_OFFSET);
writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, bgp->cfg2_base + K3_VTM_MISC_CTRL_OFFSET);
}
struct k3_j72xx_bandgap_data { struct k3_j72xx_bandgap_data {
const bool has_errata_i2128; const bool has_errata_i2128;
}; };
static int k3_j72xx_bandgap_probe(struct platform_device *pdev) static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
{ {
int ret = 0, cnt, val, id;
int high_max, low_temp;
struct resource *res;
struct device *dev = &pdev->dev;
struct k3_j72xx_bandgap *bgp;
struct k3_thermal_data *data;
bool workaround_needed = false;
const struct k3_j72xx_bandgap_data *driver_data; const struct k3_j72xx_bandgap_data *driver_data;
struct thermal_zone_device *ti_thermal; struct thermal_zone_device *ti_thermal;
int *ref_table; struct device *dev = &pdev->dev;
bool workaround_needed = false;
struct k3_j72xx_bandgap *bgp;
struct k3_thermal_data *data;
struct err_values err_vals; struct err_values err_vals;
void __iomem *fuse_base; void __iomem *fuse_base;
int ret = 0, val, id;
struct resource *res;
int *ref_table;
const s64 golden_factors[] = { const s64 golden_factors[] = {
-490019999999999936, -490019999999999936,
@ -422,10 +451,10 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
/* Get the sensor count in the VTM */ /* Get the sensor count in the VTM */
val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET); val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET);
cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK; bgp->cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK); bgp->cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
data = devm_kcalloc(bgp->dev, cnt, sizeof(*data), GFP_KERNEL); data = devm_kcalloc(bgp->dev, bgp->cnt, sizeof(*data), GFP_KERNEL);
if (!data) { if (!data) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_alloc; goto err_alloc;
@ -449,8 +478,8 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
else else
init_table(3, ref_table, pvt_wa_factors); init_table(3, ref_table, pvt_wa_factors);
/* Register the thermal sensors */ /* Precompute the derived table & fill each thermal sensor struct */
for (id = 0; id < cnt; id++) { for (id = 0; id < bgp->cnt; id++) {
data[id].bgp = bgp; data[id].bgp = bgp;
data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20; data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20;
data[id].stat_offset = data[id].ctrl_offset + data[id].stat_offset = data[id].ctrl_offset +
@ -470,13 +499,13 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
else if (id == 0 && !workaround_needed) else if (id == 0 && !workaround_needed)
memcpy(derived_table, ref_table, TABLE_SIZE * 4); memcpy(derived_table, ref_table, TABLE_SIZE * 4);
val = readl(data[id].bgp->cfg2_base + data[id].ctrl_offset);
val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN |
K3_VTM_TMPSENS_CTRL_SOC |
K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4));
writel(val, data[id].bgp->cfg2_base + data[id].ctrl_offset);
bgp->ts_data[id] = &data[id]; bgp->ts_data[id] = &data[id];
}
k3_j72xx_bandgap_init_hw(bgp);
/* Register the thermal sensors */
for (id = 0; id < bgp->cnt; id++) {
ti_thermal = devm_thermal_of_zone_register(bgp->dev, id, &data[id], ti_thermal = devm_thermal_of_zone_register(bgp->dev, id, &data[id],
&k3_of_thermal_ops); &k3_of_thermal_ops);
if (IS_ERR(ti_thermal)) { if (IS_ERR(ti_thermal)) {
@ -486,21 +515,7 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
} }
} }
/* platform_set_drvdata(pdev, bgp);
* Program TSHUT thresholds
* Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2
* Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit
* This is already taken care as per of init
* Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit
*/
high_max = k3_j72xx_bandgap_temp_to_adc_code(MAX_TEMP);
low_temp = k3_j72xx_bandgap_temp_to_adc_code(COOL_DOWN_TEMP);
writel((low_temp << 16) | high_max, data[0].bgp->cfg2_base +
K3_VTM_MISC_CTRL2_OFFSET);
mdelay(100);
writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, data[0].bgp->cfg2_base +
K3_VTM_MISC_CTRL_OFFSET);
print_look_up_table(dev, ref_table); print_look_up_table(dev, ref_table);
/* /*
@ -527,6 +542,35 @@ static void k3_j72xx_bandgap_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
} }
static int k3_j72xx_bandgap_suspend(struct device *dev)
{
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return 0;
}
static int k3_j72xx_bandgap_resume(struct device *dev)
{
struct k3_j72xx_bandgap *bgp = dev_get_drvdata(dev);
int ret;
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
return ret;
}
k3_j72xx_bandgap_init_hw(bgp);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(k3_j72xx_bandgap_pm_ops,
k3_j72xx_bandgap_suspend,
k3_j72xx_bandgap_resume);
static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = { static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = {
.has_errata_i2128 = true, .has_errata_i2128 = true,
}; };
@ -554,6 +598,7 @@ static struct platform_driver k3_j72xx_bandgap_sensor_driver = {
.driver = { .driver = {
.name = "k3-j72xx-soc-thermal", .name = "k3-j72xx-soc-thermal",
.of_match_table = of_k3_j72xx_bandgap_match, .of_match_table = of_k3_j72xx_bandgap_match,
.pm = pm_sleep_ptr(&k3_j72xx_bandgap_pm_ops),
}, },
}; };