162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TI Bandgap temperature sensor driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
662306a36Sopenharmony_ci * Author: J Keerthy <j-keerthy@ti.com>
762306a36Sopenharmony_ci * Author: Moiz Sonasath <m-sonasath@ti.com>
862306a36Sopenharmony_ci * Couple of fixes, DT and MFD adaptation:
962306a36Sopenharmony_ci *   Eduardo Valentin <eduardo.valentin@ti.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/clk.h>
1362306a36Sopenharmony_ci#include <linux/cpu_pm.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/export.h>
1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/io.h>
2162306a36Sopenharmony_ci#include <linux/iopoll.h>
2262306a36Sopenharmony_ci#include <linux/kernel.h>
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci#include <linux/of.h>
2562306a36Sopenharmony_ci#include <linux/of_device.h>
2662306a36Sopenharmony_ci#include <linux/of_irq.h>
2762306a36Sopenharmony_ci#include <linux/of_platform.h>
2862306a36Sopenharmony_ci#include <linux/platform_device.h>
2962306a36Sopenharmony_ci#include <linux/pm.h>
3062306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3162306a36Sopenharmony_ci#include <linux/reboot.h>
3262306a36Sopenharmony_ci#include <linux/spinlock.h>
3362306a36Sopenharmony_ci#include <linux/sys_soc.h>
3462306a36Sopenharmony_ci#include <linux/types.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "ti-bandgap.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id);
3962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4062306a36Sopenharmony_cistatic int bandgap_omap_cpu_notifier(struct notifier_block *nb,
4162306a36Sopenharmony_ci				  unsigned long cmd, void *v);
4262306a36Sopenharmony_ci#endif
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/***   Helper functions to access registers and their bitfields   ***/
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * ti_bandgap_readl() - simple read helper function
4862306a36Sopenharmony_ci * @bgp: pointer to ti_bandgap structure
4962306a36Sopenharmony_ci * @reg: desired register (offset) to be read
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Helper function to read bandgap registers. It uses the io remapped area.
5262306a36Sopenharmony_ci * Return: the register value.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistatic u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return readl(bgp->base + reg);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/**
6062306a36Sopenharmony_ci * ti_bandgap_writel() - simple write helper function
6162306a36Sopenharmony_ci * @bgp: pointer to ti_bandgap structure
6262306a36Sopenharmony_ci * @val: desired register value to be written
6362306a36Sopenharmony_ci * @reg: desired register (offset) to be written
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * Helper function to write bandgap registers. It uses the io remapped area.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	writel(val, bgp->base + reg);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/**
7362306a36Sopenharmony_ci * DOC: macro to update bits.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * RMW_BITS() - used to read, modify and update bandgap bitfields.
7662306a36Sopenharmony_ci *            The value passed will be shifted.
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_ci#define RMW_BITS(bgp, id, reg, mask, val)			\
7962306a36Sopenharmony_cido {								\
8062306a36Sopenharmony_ci	struct temp_sensor_registers *t;			\
8162306a36Sopenharmony_ci	u32 r;							\
8262306a36Sopenharmony_ci								\
8362306a36Sopenharmony_ci	t = bgp->conf->sensors[(id)].registers;		\
8462306a36Sopenharmony_ci	r = ti_bandgap_readl(bgp, t->reg);			\
8562306a36Sopenharmony_ci	r &= ~t->mask;						\
8662306a36Sopenharmony_ci	r |= (val) << __ffs(t->mask);				\
8762306a36Sopenharmony_ci	ti_bandgap_writel(bgp, r, t->reg);			\
8862306a36Sopenharmony_ci} while (0)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/***   Basic helper functions   ***/
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/**
9362306a36Sopenharmony_ci * ti_bandgap_power() - controls the power state of a bandgap device
9462306a36Sopenharmony_ci * @bgp: pointer to ti_bandgap structure
9562306a36Sopenharmony_ci * @on: desired power state (1 - on, 0 - off)
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * Used to power on/off a bandgap device instance. Only used on those
9862306a36Sopenharmony_ci * that features tempsoff bit.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_cistatic int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	int i;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH))
10762306a36Sopenharmony_ci		return -ENOTSUPP;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++)
11062306a36Sopenharmony_ci		/* active on 0 */
11162306a36Sopenharmony_ci		RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * ti_errata814_bandgap_read_temp() - helper function to read dra7 sensor temperature
11762306a36Sopenharmony_ci * @bgp: pointer to ti_bandgap structure
11862306a36Sopenharmony_ci * @reg: desired register (offset) to be read
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * Function to read dra7 bandgap sensor temperature. This is done separately
12162306a36Sopenharmony_ci * so as to workaround the errata "Bandgap Temperature read Dtemp can be
12262306a36Sopenharmony_ci * corrupted" - Errata ID: i814".
12362306a36Sopenharmony_ci * Read accesses to registers listed below can be corrupted due to incorrect
12462306a36Sopenharmony_ci * resynchronization between clock domains.
12562306a36Sopenharmony_ci * Read access to registers below can be corrupted :
12662306a36Sopenharmony_ci * CTRL_CORE_DTEMP_MPU/GPU/CORE/DSPEVE/IVA_n (n = 0 to 4)
12762306a36Sopenharmony_ci * CTRL_CORE_TEMP_SENSOR_MPU/GPU/CORE/DSPEVE/IVA_n
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci * Return: the register value.
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic u32 ti_errata814_bandgap_read_temp(struct ti_bandgap *bgp,  u32 reg)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u32 val1, val2;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	val1 = ti_bandgap_readl(bgp, reg);
13662306a36Sopenharmony_ci	val2 = ti_bandgap_readl(bgp, reg);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* If both times we read the same value then that is right */
13962306a36Sopenharmony_ci	if (val1 == val2)
14062306a36Sopenharmony_ci		return val1;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* if val1 and val2 are different read it third time */
14362306a36Sopenharmony_ci	return ti_bandgap_readl(bgp, reg);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * ti_bandgap_read_temp() - helper function to read sensor temperature
14862306a36Sopenharmony_ci * @bgp: pointer to ti_bandgap structure
14962306a36Sopenharmony_ci * @id: bandgap sensor id
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * Function to concentrate the steps to read sensor temperature register.
15262306a36Sopenharmony_ci * This function is desired because, depending on bandgap device version,
15362306a36Sopenharmony_ci * it might be needed to freeze the bandgap state machine, before fetching
15462306a36Sopenharmony_ci * the register value.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * Return: temperature in ADC values.
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct temp_sensor_registers *tsr;
16162306a36Sopenharmony_ci	u32 temp, reg;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	tsr = bgp->conf->sensors[id].registers;
16462306a36Sopenharmony_ci	reg = tsr->temp_sensor_ctrl;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
16762306a36Sopenharmony_ci		RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
16862306a36Sopenharmony_ci		/*
16962306a36Sopenharmony_ci		 * In case we cannot read from cur_dtemp / dtemp_0,
17062306a36Sopenharmony_ci		 * then we read from the last valid temp read
17162306a36Sopenharmony_ci		 */
17262306a36Sopenharmony_ci		reg = tsr->ctrl_dtemp_1;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* read temperature */
17662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, ERRATA_814))
17762306a36Sopenharmony_ci		temp = ti_errata814_bandgap_read_temp(bgp, reg);
17862306a36Sopenharmony_ci	else
17962306a36Sopenharmony_ci		temp = ti_bandgap_readl(bgp, reg);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	temp &= tsr->bgap_dtemp_mask;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
18462306a36Sopenharmony_ci		RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return temp;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/***   IRQ handlers   ***/
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/**
19262306a36Sopenharmony_ci * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs
19362306a36Sopenharmony_ci * @irq: IRQ number
19462306a36Sopenharmony_ci * @data: private data (struct ti_bandgap *)
19562306a36Sopenharmony_ci *
19662306a36Sopenharmony_ci * This is the Talert handler. Use it only if bandgap device features
19762306a36Sopenharmony_ci * HAS(TALERT). This handler goes over all sensors and checks their
19862306a36Sopenharmony_ci * conditions and acts accordingly. In case there are events pending,
19962306a36Sopenharmony_ci * it will reset the event mask to wait for the opposite event (next event).
20062306a36Sopenharmony_ci * Every time there is a new event, it will be reported to thermal layer.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * Return: IRQ_HANDLED
20362306a36Sopenharmony_ci */
20462306a36Sopenharmony_cistatic irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct ti_bandgap *bgp = data;
20762306a36Sopenharmony_ci	struct temp_sensor_registers *tsr;
20862306a36Sopenharmony_ci	u32 t_hot = 0, t_cold = 0, ctrl;
20962306a36Sopenharmony_ci	int i;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	spin_lock(&bgp->lock);
21262306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
21362306a36Sopenharmony_ci		tsr = bgp->conf->sensors[i].registers;
21462306a36Sopenharmony_ci		ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		/* Read the status of t_hot */
21762306a36Sopenharmony_ci		t_hot = ctrl & tsr->status_hot_mask;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		/* Read the status of t_cold */
22062306a36Sopenharmony_ci		t_cold = ctrl & tsr->status_cold_mask;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		if (!t_cold && !t_hot)
22362306a36Sopenharmony_ci			continue;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
22662306a36Sopenharmony_ci		/*
22762306a36Sopenharmony_ci		 * One TALERT interrupt: Two sources
22862306a36Sopenharmony_ci		 * If the interrupt is due to t_hot then mask t_hot and
22962306a36Sopenharmony_ci		 * unmask t_cold else mask t_cold and unmask t_hot
23062306a36Sopenharmony_ci		 */
23162306a36Sopenharmony_ci		if (t_hot) {
23262306a36Sopenharmony_ci			ctrl &= ~tsr->mask_hot_mask;
23362306a36Sopenharmony_ci			ctrl |= tsr->mask_cold_mask;
23462306a36Sopenharmony_ci		} else if (t_cold) {
23562306a36Sopenharmony_ci			ctrl &= ~tsr->mask_cold_mask;
23662306a36Sopenharmony_ci			ctrl |= tsr->mask_hot_mask;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		dev_dbg(bgp->dev,
24262306a36Sopenharmony_ci			"%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
24362306a36Sopenharmony_ci			__func__, bgp->conf->sensors[i].domain,
24462306a36Sopenharmony_ci			t_hot, t_cold);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		/* report temperature to whom may concern */
24762306a36Sopenharmony_ci		if (bgp->conf->report_temperature)
24862306a36Sopenharmony_ci			bgp->conf->report_temperature(bgp, i);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return IRQ_HANDLED;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/**
25662306a36Sopenharmony_ci * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
25762306a36Sopenharmony_ci * @irq: IRQ number
25862306a36Sopenharmony_ci * @data: private data (unused)
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * This is the Tshut handler. Use it only if bandgap device features
26162306a36Sopenharmony_ci * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
26262306a36Sopenharmony_ci * the system.
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * Return: IRQ_HANDLED
26562306a36Sopenharmony_ci */
26662306a36Sopenharmony_cistatic irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
26962306a36Sopenharmony_ci		 __func__);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	orderly_poweroff(true);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return IRQ_HANDLED;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/***   Helper functions which manipulate conversion ADC <-> mi Celsius   ***/
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/**
27962306a36Sopenharmony_ci * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
28062306a36Sopenharmony_ci * @bgp: struct ti_bandgap pointer
28162306a36Sopenharmony_ci * @adc_val: value in ADC representation
28262306a36Sopenharmony_ci * @t: address where to write the resulting temperature in mCelsius
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci * Simple conversion from ADC representation to mCelsius. In case the ADC value
28562306a36Sopenharmony_ci * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
28662306a36Sopenharmony_ci * The conversion table is indexed by the ADC values.
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val
28962306a36Sopenharmony_ci * argument is out of the ADC conv table range.
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_cistatic
29262306a36Sopenharmony_ciint ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	const struct ti_bandgap_data *conf = bgp->conf;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* look up for temperature in the table and return the temperature */
29762306a36Sopenharmony_ci	if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val)
29862306a36Sopenharmony_ci		return -ERANGE;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	*t = bgp->conf->conv_table[adc_val - conf->adc_start_val];
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/**
30562306a36Sopenharmony_ci * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
30662306a36Sopenharmony_ci * @bgp: struct ti_bandgap pointer
30762306a36Sopenharmony_ci * @id: bandgap sensor id
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Checks if the bandgap pointer is valid and if the sensor id is also
31062306a36Sopenharmony_ci * applicable.
31162306a36Sopenharmony_ci *
31262306a36Sopenharmony_ci * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
31362306a36Sopenharmony_ci * @id cannot index @bgp sensors.
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_cistatic inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(bgp)) {
31862306a36Sopenharmony_ci		pr_err("%s: invalid bandgap pointer\n", __func__);
31962306a36Sopenharmony_ci		return -EINVAL;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if ((id < 0) || (id >= bgp->conf->sensor_count)) {
32362306a36Sopenharmony_ci		dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
32462306a36Sopenharmony_ci			__func__, id);
32562306a36Sopenharmony_ci		return -ERANGE;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/**
33262306a36Sopenharmony_ci * ti_bandgap_read_counter() - read the sensor counter
33362306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
33462306a36Sopenharmony_ci * @id: sensor id
33562306a36Sopenharmony_ci * @interval: resulting update interval in miliseconds
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_cistatic void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id,
33862306a36Sopenharmony_ci				    int *interval)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct temp_sensor_registers *tsr;
34162306a36Sopenharmony_ci	int time;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	tsr = bgp->conf->sensors[id].registers;
34462306a36Sopenharmony_ci	time = ti_bandgap_readl(bgp, tsr->bgap_counter);
34562306a36Sopenharmony_ci	time = (time & tsr->counter_mask) >>
34662306a36Sopenharmony_ci					__ffs(tsr->counter_mask);
34762306a36Sopenharmony_ci	time = time * 1000 / bgp->clk_rate;
34862306a36Sopenharmony_ci	*interval = time;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/**
35262306a36Sopenharmony_ci * ti_bandgap_read_counter_delay() - read the sensor counter delay
35362306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
35462306a36Sopenharmony_ci * @id: sensor id
35562306a36Sopenharmony_ci * @interval: resulting update interval in miliseconds
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistatic void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id,
35862306a36Sopenharmony_ci					  int *interval)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct temp_sensor_registers *tsr;
36162306a36Sopenharmony_ci	int reg_val;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	tsr = bgp->conf->sensors[id].registers;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
36662306a36Sopenharmony_ci	reg_val = (reg_val & tsr->mask_counter_delay_mask) >>
36762306a36Sopenharmony_ci				__ffs(tsr->mask_counter_delay_mask);
36862306a36Sopenharmony_ci	switch (reg_val) {
36962306a36Sopenharmony_ci	case 0:
37062306a36Sopenharmony_ci		*interval = 0;
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci	case 1:
37362306a36Sopenharmony_ci		*interval = 1;
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci	case 2:
37662306a36Sopenharmony_ci		*interval = 10;
37762306a36Sopenharmony_ci		break;
37862306a36Sopenharmony_ci	case 3:
37962306a36Sopenharmony_ci		*interval = 100;
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	case 4:
38262306a36Sopenharmony_ci		*interval = 250;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case 5:
38562306a36Sopenharmony_ci		*interval = 500;
38662306a36Sopenharmony_ci		break;
38762306a36Sopenharmony_ci	default:
38862306a36Sopenharmony_ci		dev_warn(bgp->dev, "Wrong counter delay value read from register %X",
38962306a36Sopenharmony_ci			 reg_val);
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/**
39462306a36Sopenharmony_ci * ti_bandgap_read_update_interval() - read the sensor update interval
39562306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
39662306a36Sopenharmony_ci * @id: sensor id
39762306a36Sopenharmony_ci * @interval: resulting update interval in miliseconds
39862306a36Sopenharmony_ci *
39962306a36Sopenharmony_ci * Return: 0 on success or the proper error code
40062306a36Sopenharmony_ci */
40162306a36Sopenharmony_ciint ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
40262306a36Sopenharmony_ci				    int *interval)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	int ret = 0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	ret = ti_bandgap_validate(bgp, id);
40762306a36Sopenharmony_ci	if (ret)
40862306a36Sopenharmony_ci		goto exit;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
41162306a36Sopenharmony_ci	    !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
41262306a36Sopenharmony_ci		ret = -ENOTSUPP;
41362306a36Sopenharmony_ci		goto exit;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, COUNTER)) {
41762306a36Sopenharmony_ci		ti_bandgap_read_counter(bgp, id, interval);
41862306a36Sopenharmony_ci		goto exit;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ti_bandgap_read_counter_delay(bgp, id, interval);
42262306a36Sopenharmony_ciexit:
42362306a36Sopenharmony_ci	return ret;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci/**
42762306a36Sopenharmony_ci * ti_bandgap_write_counter_delay() - set the counter_delay
42862306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
42962306a36Sopenharmony_ci * @id: sensor id
43062306a36Sopenharmony_ci * @interval: desired update interval in miliseconds
43162306a36Sopenharmony_ci *
43262306a36Sopenharmony_ci * Return: 0 on success or the proper error code
43362306a36Sopenharmony_ci */
43462306a36Sopenharmony_cistatic int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id,
43562306a36Sopenharmony_ci					  u32 interval)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	int rval;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	switch (interval) {
44062306a36Sopenharmony_ci	case 0: /* Immediate conversion */
44162306a36Sopenharmony_ci		rval = 0x0;
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	case 1: /* Conversion after ever 1ms */
44462306a36Sopenharmony_ci		rval = 0x1;
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	case 10: /* Conversion after ever 10ms */
44762306a36Sopenharmony_ci		rval = 0x2;
44862306a36Sopenharmony_ci		break;
44962306a36Sopenharmony_ci	case 100: /* Conversion after ever 100ms */
45062306a36Sopenharmony_ci		rval = 0x3;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case 250: /* Conversion after ever 250ms */
45362306a36Sopenharmony_ci		rval = 0x4;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci	case 500: /* Conversion after ever 500ms */
45662306a36Sopenharmony_ci		rval = 0x5;
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	default:
45962306a36Sopenharmony_ci		dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval);
46062306a36Sopenharmony_ci		return -EINVAL;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	spin_lock(&bgp->lock);
46462306a36Sopenharmony_ci	RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval);
46562306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/**
47162306a36Sopenharmony_ci * ti_bandgap_write_counter() - set the bandgap sensor counter
47262306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
47362306a36Sopenharmony_ci * @id: sensor id
47462306a36Sopenharmony_ci * @interval: desired update interval in miliseconds
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_cistatic void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id,
47762306a36Sopenharmony_ci				     u32 interval)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	interval = interval * bgp->clk_rate / 1000;
48062306a36Sopenharmony_ci	spin_lock(&bgp->lock);
48162306a36Sopenharmony_ci	RMW_BITS(bgp, id, bgap_counter, counter_mask, interval);
48262306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci/**
48662306a36Sopenharmony_ci * ti_bandgap_write_update_interval() - set the update interval
48762306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
48862306a36Sopenharmony_ci * @id: sensor id
48962306a36Sopenharmony_ci * @interval: desired update interval in miliseconds
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci * Return: 0 on success or the proper error code
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_ciint ti_bandgap_write_update_interval(struct ti_bandgap *bgp,
49462306a36Sopenharmony_ci				     int id, u32 interval)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	int ret = ti_bandgap_validate(bgp, id);
49762306a36Sopenharmony_ci	if (ret)
49862306a36Sopenharmony_ci		goto exit;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
50162306a36Sopenharmony_ci	    !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
50262306a36Sopenharmony_ci		ret = -ENOTSUPP;
50362306a36Sopenharmony_ci		goto exit;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, COUNTER)) {
50762306a36Sopenharmony_ci		ti_bandgap_write_counter(bgp, id, interval);
50862306a36Sopenharmony_ci		goto exit;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = ti_bandgap_write_counter_delay(bgp, id, interval);
51262306a36Sopenharmony_ciexit:
51362306a36Sopenharmony_ci	return ret;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/**
51762306a36Sopenharmony_ci * ti_bandgap_read_temperature() - report current temperature
51862306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
51962306a36Sopenharmony_ci * @id: sensor id
52062306a36Sopenharmony_ci * @temperature: resulting temperature
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * Return: 0 on success or the proper error code
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_ciint ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
52562306a36Sopenharmony_ci				int *temperature)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	u32 temp;
52862306a36Sopenharmony_ci	int ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	ret = ti_bandgap_validate(bgp, id);
53162306a36Sopenharmony_ci	if (ret)
53262306a36Sopenharmony_ci		return ret;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (!TI_BANDGAP_HAS(bgp, MODE_CONFIG)) {
53562306a36Sopenharmony_ci		ret = ti_bandgap_force_single_read(bgp, id);
53662306a36Sopenharmony_ci		if (ret)
53762306a36Sopenharmony_ci			return ret;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	spin_lock(&bgp->lock);
54162306a36Sopenharmony_ci	temp = ti_bandgap_read_temp(bgp, id);
54262306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ret = ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
54562306a36Sopenharmony_ci	if (ret)
54662306a36Sopenharmony_ci		return -EIO;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	*temperature = temp;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/**
55462306a36Sopenharmony_ci * ti_bandgap_set_sensor_data() - helper function to store thermal
55562306a36Sopenharmony_ci * framework related data.
55662306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
55762306a36Sopenharmony_ci * @id: sensor id
55862306a36Sopenharmony_ci * @data: thermal framework related data to be stored
55962306a36Sopenharmony_ci *
56062306a36Sopenharmony_ci * Return: 0 on success or the proper error code
56162306a36Sopenharmony_ci */
56262306a36Sopenharmony_ciint ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	int ret = ti_bandgap_validate(bgp, id);
56562306a36Sopenharmony_ci	if (ret)
56662306a36Sopenharmony_ci		return ret;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	bgp->regval[id].data = data;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/**
57462306a36Sopenharmony_ci * ti_bandgap_get_sensor_data() - helper function to get thermal
57562306a36Sopenharmony_ci * framework related data.
57662306a36Sopenharmony_ci * @bgp: pointer to bandgap instance
57762306a36Sopenharmony_ci * @id: sensor id
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * Return: data stored by set function with sensor id on success or NULL
58062306a36Sopenharmony_ci */
58162306a36Sopenharmony_civoid *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	int ret = ti_bandgap_validate(bgp, id);
58462306a36Sopenharmony_ci	if (ret)
58562306a36Sopenharmony_ci		return ERR_PTR(ret);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	return bgp->regval[id].data;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/***   Helper functions used during device initialization   ***/
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/**
59362306a36Sopenharmony_ci * ti_bandgap_force_single_read() - executes 1 single ADC conversion
59462306a36Sopenharmony_ci * @bgp: pointer to struct ti_bandgap
59562306a36Sopenharmony_ci * @id: sensor id which it is desired to read 1 temperature
59662306a36Sopenharmony_ci *
59762306a36Sopenharmony_ci * Used to initialize the conversion state machine and set it to a valid
59862306a36Sopenharmony_ci * state. Called during device initialization and context restore events.
59962306a36Sopenharmony_ci *
60062306a36Sopenharmony_ci * Return: 0
60162306a36Sopenharmony_ci */
60262306a36Sopenharmony_cistatic int
60362306a36Sopenharmony_citi_bandgap_force_single_read(struct ti_bandgap *bgp, int id)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct temp_sensor_registers *tsr = bgp->conf->sensors[id].registers;
60662306a36Sopenharmony_ci	void __iomem *temp_sensor_ctrl = bgp->base + tsr->temp_sensor_ctrl;
60762306a36Sopenharmony_ci	int error;
60862306a36Sopenharmony_ci	u32 val;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* Select continuous or single conversion mode */
61162306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, MODE_CONFIG)) {
61262306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, CONT_MODE_ONLY))
61362306a36Sopenharmony_ci			RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 1);
61462306a36Sopenharmony_ci		else
61562306a36Sopenharmony_ci			RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* Set Start of Conversion if available */
61962306a36Sopenharmony_ci	if (tsr->bgap_soc_mask) {
62062306a36Sopenharmony_ci		RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		/* Wait for EOCZ going up */
62362306a36Sopenharmony_ci		error = readl_poll_timeout_atomic(temp_sensor_ctrl, val,
62462306a36Sopenharmony_ci						  val & tsr->bgap_eocz_mask,
62562306a36Sopenharmony_ci						  1, 1000);
62662306a36Sopenharmony_ci		if (error)
62762306a36Sopenharmony_ci			dev_warn(bgp->dev, "eocz timed out waiting high\n");
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		/* Clear Start of Conversion if available */
63062306a36Sopenharmony_ci		RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	/* Wait for EOCZ going down, always needed even if no bgap_soc_mask */
63462306a36Sopenharmony_ci	error = readl_poll_timeout_atomic(temp_sensor_ctrl, val,
63562306a36Sopenharmony_ci					  !(val & tsr->bgap_eocz_mask),
63662306a36Sopenharmony_ci					  1, 1500);
63762306a36Sopenharmony_ci	if (error)
63862306a36Sopenharmony_ci		dev_warn(bgp->dev, "eocz timed out waiting low\n");
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/**
64462306a36Sopenharmony_ci * ti_bandgap_set_continuous_mode() - One time enabling of continuous mode
64562306a36Sopenharmony_ci * @bgp: pointer to struct ti_bandgap
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci * Call this function only if HAS(MODE_CONFIG) is set. As this driver may
64862306a36Sopenharmony_ci * be used for junction temperature monitoring, it is desirable that the
64962306a36Sopenharmony_ci * sensors are operational all the time, so that alerts are generated
65062306a36Sopenharmony_ci * properly.
65162306a36Sopenharmony_ci *
65262306a36Sopenharmony_ci * Return: 0
65362306a36Sopenharmony_ci */
65462306a36Sopenharmony_cistatic int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	int i;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
65962306a36Sopenharmony_ci		/* Perform a single read just before enabling continuous */
66062306a36Sopenharmony_ci		ti_bandgap_force_single_read(bgp, i);
66162306a36Sopenharmony_ci		RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/**
66862306a36Sopenharmony_ci * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor
66962306a36Sopenharmony_ci * @bgp: pointer to struct ti_bandgap
67062306a36Sopenharmony_ci * @id: id of the individual sensor
67162306a36Sopenharmony_ci * @trend: Pointer to trend.
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci * This function needs to be called to fetch the temperature trend of a
67462306a36Sopenharmony_ci * Particular sensor. The function computes the difference in temperature
67562306a36Sopenharmony_ci * w.r.t time. For the bandgaps with built in history buffer the temperatures
67662306a36Sopenharmony_ci * are read from the buffer and for those without the Buffer -ENOTSUPP is
67762306a36Sopenharmony_ci * returned.
67862306a36Sopenharmony_ci *
67962306a36Sopenharmony_ci * Return: 0 if no error, else return corresponding error. If no
68062306a36Sopenharmony_ci *		error then the trend value is passed on to trend parameter
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_ciint ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct temp_sensor_registers *tsr;
68562306a36Sopenharmony_ci	u32 temp1, temp2, reg1, reg2;
68662306a36Sopenharmony_ci	int t1, t2, interval, ret = 0;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	ret = ti_bandgap_validate(bgp, id);
68962306a36Sopenharmony_ci	if (ret)
69062306a36Sopenharmony_ci		goto exit;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
69362306a36Sopenharmony_ci	    !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
69462306a36Sopenharmony_ci		ret = -ENOTSUPP;
69562306a36Sopenharmony_ci		goto exit;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	spin_lock(&bgp->lock);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	tsr = bgp->conf->sensors[id].registers;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* Freeze and read the last 2 valid readings */
70362306a36Sopenharmony_ci	RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
70462306a36Sopenharmony_ci	reg1 = tsr->ctrl_dtemp_1;
70562306a36Sopenharmony_ci	reg2 = tsr->ctrl_dtemp_2;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* read temperature from history buffer */
70862306a36Sopenharmony_ci	temp1 = ti_bandgap_readl(bgp, reg1);
70962306a36Sopenharmony_ci	temp1 &= tsr->bgap_dtemp_mask;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	temp2 = ti_bandgap_readl(bgp, reg2);
71262306a36Sopenharmony_ci	temp2 &= tsr->bgap_dtemp_mask;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	/* Convert from adc values to mCelsius temperature */
71562306a36Sopenharmony_ci	ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
71662306a36Sopenharmony_ci	if (ret)
71762306a36Sopenharmony_ci		goto unfreeze;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
72062306a36Sopenharmony_ci	if (ret)
72162306a36Sopenharmony_ci		goto unfreeze;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* Fetch the update interval */
72462306a36Sopenharmony_ci	ret = ti_bandgap_read_update_interval(bgp, id, &interval);
72562306a36Sopenharmony_ci	if (ret)
72662306a36Sopenharmony_ci		goto unfreeze;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* Set the interval to 1 ms if bandgap counter delay is not set */
72962306a36Sopenharmony_ci	if (interval == 0)
73062306a36Sopenharmony_ci		interval = 1;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	*trend = (t1 - t2) / interval;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
73562306a36Sopenharmony_ci		t1, t2, *trend);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ciunfreeze:
73862306a36Sopenharmony_ci	RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
73962306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
74062306a36Sopenharmony_ciexit:
74162306a36Sopenharmony_ci	return ret;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci/**
74562306a36Sopenharmony_ci * ti_bandgap_tshut_init() - setup and initialize tshut handling
74662306a36Sopenharmony_ci * @bgp: pointer to struct ti_bandgap
74762306a36Sopenharmony_ci * @pdev: pointer to device struct platform_device
74862306a36Sopenharmony_ci *
74962306a36Sopenharmony_ci * Call this function only in case the bandgap features HAS(TSHUT).
75062306a36Sopenharmony_ci * In this case, the driver needs to handle the TSHUT signal as an IRQ.
75162306a36Sopenharmony_ci * The IRQ is wired as a GPIO, and for this purpose, it is required
75262306a36Sopenharmony_ci * to specify which GPIO line is used. TSHUT IRQ is fired anytime
75362306a36Sopenharmony_ci * one of the bandgap sensors violates the TSHUT high/hot threshold.
75462306a36Sopenharmony_ci * And in that case, the system must go off.
75562306a36Sopenharmony_ci *
75662306a36Sopenharmony_ci * Return: 0 if no error, else error status
75762306a36Sopenharmony_ci */
75862306a36Sopenharmony_cistatic int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
75962306a36Sopenharmony_ci				 struct platform_device *pdev)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	int status;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	status = request_irq(gpiod_to_irq(bgp->tshut_gpiod),
76462306a36Sopenharmony_ci			     ti_bandgap_tshut_irq_handler,
76562306a36Sopenharmony_ci			     IRQF_TRIGGER_RISING, "tshut", NULL);
76662306a36Sopenharmony_ci	if (status)
76762306a36Sopenharmony_ci		dev_err(bgp->dev, "request irq failed for TSHUT");
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	return 0;
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci/**
77362306a36Sopenharmony_ci * ti_bandgap_talert_init() - setup and initialize talert handling
77462306a36Sopenharmony_ci * @bgp: pointer to struct ti_bandgap
77562306a36Sopenharmony_ci * @pdev: pointer to device struct platform_device
77662306a36Sopenharmony_ci *
77762306a36Sopenharmony_ci * Call this function only in case the bandgap features HAS(TALERT).
77862306a36Sopenharmony_ci * In this case, the driver needs to handle the TALERT signals as an IRQs.
77962306a36Sopenharmony_ci * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold)
78062306a36Sopenharmony_ci * are violated. In these situation, the driver must reprogram the thresholds,
78162306a36Sopenharmony_ci * accordingly to specified policy.
78262306a36Sopenharmony_ci *
78362306a36Sopenharmony_ci * Return: 0 if no error, else return corresponding error.
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic int ti_bandgap_talert_init(struct ti_bandgap *bgp,
78662306a36Sopenharmony_ci				  struct platform_device *pdev)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	int ret;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	bgp->irq = platform_get_irq(pdev, 0);
79162306a36Sopenharmony_ci	if (bgp->irq < 0)
79262306a36Sopenharmony_ci		return bgp->irq;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	ret = request_threaded_irq(bgp->irq, NULL,
79562306a36Sopenharmony_ci				   ti_bandgap_talert_irq_handler,
79662306a36Sopenharmony_ci				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
79762306a36Sopenharmony_ci				   "talert", bgp);
79862306a36Sopenharmony_ci	if (ret) {
79962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Request threaded irq failed.\n");
80062306a36Sopenharmony_ci		return ret;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return 0;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic const struct of_device_id of_ti_bandgap_match[];
80762306a36Sopenharmony_ci/**
80862306a36Sopenharmony_ci * ti_bandgap_build() - parse DT and setup a struct ti_bandgap
80962306a36Sopenharmony_ci * @pdev: pointer to device struct platform_device
81062306a36Sopenharmony_ci *
81162306a36Sopenharmony_ci * Used to read the device tree properties accordingly to the bandgap
81262306a36Sopenharmony_ci * matching version. Based on bandgap version and its capabilities it
81362306a36Sopenharmony_ci * will build a struct ti_bandgap out of the required DT entries.
81462306a36Sopenharmony_ci *
81562306a36Sopenharmony_ci * Return: valid bandgap structure if successful, else returns ERR_PTR
81662306a36Sopenharmony_ci * return value must be verified with IS_ERR.
81762306a36Sopenharmony_ci */
81862306a36Sopenharmony_cistatic struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
82162306a36Sopenharmony_ci	const struct of_device_id *of_id;
82262306a36Sopenharmony_ci	struct ti_bandgap *bgp;
82362306a36Sopenharmony_ci	struct resource *res;
82462306a36Sopenharmony_ci	int i;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/* just for the sake */
82762306a36Sopenharmony_ci	if (!node) {
82862306a36Sopenharmony_ci		dev_err(&pdev->dev, "no platform information available\n");
82962306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
83362306a36Sopenharmony_ci	if (!bgp)
83462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	of_id = of_match_device(of_ti_bandgap_match, &pdev->dev);
83762306a36Sopenharmony_ci	if (of_id)
83862306a36Sopenharmony_ci		bgp->conf = of_id->data;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* register shadow for context save and restore */
84162306a36Sopenharmony_ci	bgp->regval = devm_kcalloc(&pdev->dev, bgp->conf->sensor_count,
84262306a36Sopenharmony_ci				   sizeof(*bgp->regval), GFP_KERNEL);
84362306a36Sopenharmony_ci	if (!bgp->regval)
84462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	i = 0;
84762306a36Sopenharmony_ci	do {
84862306a36Sopenharmony_ci		void __iomem *chunk;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
85162306a36Sopenharmony_ci		if (!res)
85262306a36Sopenharmony_ci			break;
85362306a36Sopenharmony_ci		chunk = devm_ioremap_resource(&pdev->dev, res);
85462306a36Sopenharmony_ci		if (i == 0)
85562306a36Sopenharmony_ci			bgp->base = chunk;
85662306a36Sopenharmony_ci		if (IS_ERR(chunk))
85762306a36Sopenharmony_ci			return ERR_CAST(chunk);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		i++;
86062306a36Sopenharmony_ci	} while (res);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TSHUT)) {
86362306a36Sopenharmony_ci		bgp->tshut_gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
86462306a36Sopenharmony_ci		if (IS_ERR(bgp->tshut_gpiod)) {
86562306a36Sopenharmony_ci			dev_err(&pdev->dev, "invalid gpio for tshut\n");
86662306a36Sopenharmony_ci			return ERR_CAST(bgp->tshut_gpiod);
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	return bgp;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci/*
87462306a36Sopenharmony_ci * List of SoCs on which the CPU PM notifier can cause erros on the DTEMP
87562306a36Sopenharmony_ci * readout.
87662306a36Sopenharmony_ci * Enabled notifier on these machines results in erroneous, random values which
87762306a36Sopenharmony_ci * could trigger unexpected thermal shutdown.
87862306a36Sopenharmony_ci */
87962306a36Sopenharmony_cistatic const struct soc_device_attribute soc_no_cpu_notifier[] = {
88062306a36Sopenharmony_ci	{ .machine = "OMAP4430" },
88162306a36Sopenharmony_ci	{ /* sentinel */ }
88262306a36Sopenharmony_ci};
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci/***   Device driver call backs   ***/
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic
88762306a36Sopenharmony_ciint ti_bandgap_probe(struct platform_device *pdev)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	struct ti_bandgap *bgp;
89062306a36Sopenharmony_ci	int clk_rate, ret, i;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	bgp = ti_bandgap_build(pdev);
89362306a36Sopenharmony_ci	if (IS_ERR(bgp)) {
89462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to fetch platform data\n");
89562306a36Sopenharmony_ci		return PTR_ERR(bgp);
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci	bgp->dev = &pdev->dev;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, UNRELIABLE))
90062306a36Sopenharmony_ci		dev_warn(&pdev->dev,
90162306a36Sopenharmony_ci			 "This OMAP thermal sensor is unreliable. You've been warned\n");
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TSHUT)) {
90462306a36Sopenharmony_ci		ret = ti_bandgap_tshut_init(bgp, pdev);
90562306a36Sopenharmony_ci		if (ret) {
90662306a36Sopenharmony_ci			dev_err(&pdev->dev,
90762306a36Sopenharmony_ci				"failed to initialize system tshut IRQ\n");
90862306a36Sopenharmony_ci			return ret;
90962306a36Sopenharmony_ci		}
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
91362306a36Sopenharmony_ci	if (IS_ERR(bgp->fclock)) {
91462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to request fclock reference\n");
91562306a36Sopenharmony_ci		ret = PTR_ERR(bgp->fclock);
91662306a36Sopenharmony_ci		goto free_irqs;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);
92062306a36Sopenharmony_ci	if (IS_ERR(bgp->div_clk)) {
92162306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n");
92262306a36Sopenharmony_ci		ret = PTR_ERR(bgp->div_clk);
92362306a36Sopenharmony_ci		goto put_fclock;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
92762306a36Sopenharmony_ci		struct temp_sensor_registers *tsr;
92862306a36Sopenharmony_ci		u32 val;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci		tsr = bgp->conf->sensors[i].registers;
93162306a36Sopenharmony_ci		/*
93262306a36Sopenharmony_ci		 * check if the efuse has a non-zero value if not
93362306a36Sopenharmony_ci		 * it is an untrimmed sample and the temperatures
93462306a36Sopenharmony_ci		 * may not be accurate
93562306a36Sopenharmony_ci		 */
93662306a36Sopenharmony_ci		val = ti_bandgap_readl(bgp, tsr->bgap_efuse);
93762306a36Sopenharmony_ci		if (!val)
93862306a36Sopenharmony_ci			dev_info(&pdev->dev,
93962306a36Sopenharmony_ci				 "Non-trimmed BGAP, Temp not accurate\n");
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	clk_rate = clk_round_rate(bgp->div_clk,
94362306a36Sopenharmony_ci				  bgp->conf->sensors[0].ts_data->max_freq);
94462306a36Sopenharmony_ci	if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq ||
94562306a36Sopenharmony_ci	    clk_rate <= 0) {
94662306a36Sopenharmony_ci		ret = -ENODEV;
94762306a36Sopenharmony_ci		dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
94862306a36Sopenharmony_ci		goto put_clks;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	ret = clk_set_rate(bgp->div_clk, clk_rate);
95262306a36Sopenharmony_ci	if (ret)
95362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	bgp->clk_rate = clk_rate;
95662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
95762306a36Sopenharmony_ci		clk_prepare_enable(bgp->fclock);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	spin_lock_init(&bgp->lock);
96162306a36Sopenharmony_ci	bgp->dev = &pdev->dev;
96262306a36Sopenharmony_ci	platform_set_drvdata(pdev, bgp);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	ti_bandgap_power(bgp, true);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* Set default counter to 1 for now */
96762306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, COUNTER))
96862306a36Sopenharmony_ci		for (i = 0; i < bgp->conf->sensor_count; i++)
96962306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* Set default thresholds for alert and shutdown */
97262306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
97362306a36Sopenharmony_ci		struct temp_sensor_data *ts_data;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		ts_data = bgp->conf->sensors[i].ts_data;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TALERT)) {
97862306a36Sopenharmony_ci			/* Set initial Talert thresholds */
97962306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_threshold,
98062306a36Sopenharmony_ci				 threshold_tcold_mask, ts_data->t_cold);
98162306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_threshold,
98262306a36Sopenharmony_ci				 threshold_thot_mask, ts_data->t_hot);
98362306a36Sopenharmony_ci			/* Enable the alert events */
98462306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
98562306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
98662306a36Sopenharmony_ci		}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) {
98962306a36Sopenharmony_ci			/* Set initial Tshut thresholds */
99062306a36Sopenharmony_ci			RMW_BITS(bgp, i, tshut_threshold,
99162306a36Sopenharmony_ci				 tshut_hot_mask, ts_data->tshut_hot);
99262306a36Sopenharmony_ci			RMW_BITS(bgp, i, tshut_threshold,
99362306a36Sopenharmony_ci				 tshut_cold_mask, ts_data->tshut_cold);
99462306a36Sopenharmony_ci		}
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
99862306a36Sopenharmony_ci		ti_bandgap_set_continuous_mode(bgp);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/* Set .250 seconds time as default counter */
100162306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, COUNTER))
100262306a36Sopenharmony_ci		for (i = 0; i < bgp->conf->sensor_count; i++)
100362306a36Sopenharmony_ci			RMW_BITS(bgp, i, bgap_counter, counter_mask,
100462306a36Sopenharmony_ci				 bgp->clk_rate / 4);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	/* Every thing is good? Then expose the sensors */
100762306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
100862306a36Sopenharmony_ci		char *domain;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		if (bgp->conf->sensors[i].register_cooling) {
101162306a36Sopenharmony_ci			ret = bgp->conf->sensors[i].register_cooling(bgp, i);
101262306a36Sopenharmony_ci			if (ret)
101362306a36Sopenharmony_ci				goto remove_sensors;
101462306a36Sopenharmony_ci		}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		if (bgp->conf->expose_sensor) {
101762306a36Sopenharmony_ci			domain = bgp->conf->sensors[i].domain;
101862306a36Sopenharmony_ci			ret = bgp->conf->expose_sensor(bgp, i, domain);
101962306a36Sopenharmony_ci			if (ret)
102062306a36Sopenharmony_ci				goto remove_last_cooling;
102162306a36Sopenharmony_ci		}
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	/*
102562306a36Sopenharmony_ci	 * Enable the Interrupts once everything is set. Otherwise irq handler
102662306a36Sopenharmony_ci	 * might be called as soon as it is enabled where as rest of framework
102762306a36Sopenharmony_ci	 * is still getting initialised.
102862306a36Sopenharmony_ci	 */
102962306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TALERT)) {
103062306a36Sopenharmony_ci		ret = ti_bandgap_talert_init(bgp, pdev);
103162306a36Sopenharmony_ci		if (ret) {
103262306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
103362306a36Sopenharmony_ci			i = bgp->conf->sensor_count;
103462306a36Sopenharmony_ci			goto disable_clk;
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
103962306a36Sopenharmony_ci	bgp->nb.notifier_call = bandgap_omap_cpu_notifier;
104062306a36Sopenharmony_ci	if (!soc_device_match(soc_no_cpu_notifier))
104162306a36Sopenharmony_ci		cpu_pm_register_notifier(&bgp->nb);
104262306a36Sopenharmony_ci#endif
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	return 0;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ciremove_last_cooling:
104762306a36Sopenharmony_ci	if (bgp->conf->sensors[i].unregister_cooling)
104862306a36Sopenharmony_ci		bgp->conf->sensors[i].unregister_cooling(bgp, i);
104962306a36Sopenharmony_ciremove_sensors:
105062306a36Sopenharmony_ci	for (i--; i >= 0; i--) {
105162306a36Sopenharmony_ci		if (bgp->conf->sensors[i].unregister_cooling)
105262306a36Sopenharmony_ci			bgp->conf->sensors[i].unregister_cooling(bgp, i);
105362306a36Sopenharmony_ci		if (bgp->conf->remove_sensor)
105462306a36Sopenharmony_ci			bgp->conf->remove_sensor(bgp, i);
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci	ti_bandgap_power(bgp, false);
105762306a36Sopenharmony_cidisable_clk:
105862306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
105962306a36Sopenharmony_ci		clk_disable_unprepare(bgp->fclock);
106062306a36Sopenharmony_ciput_clks:
106162306a36Sopenharmony_ci	clk_put(bgp->div_clk);
106262306a36Sopenharmony_ciput_fclock:
106362306a36Sopenharmony_ci	clk_put(bgp->fclock);
106462306a36Sopenharmony_cifree_irqs:
106562306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TSHUT))
106662306a36Sopenharmony_ci		free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	return ret;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic
107262306a36Sopenharmony_ciint ti_bandgap_remove(struct platform_device *pdev)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct ti_bandgap *bgp = platform_get_drvdata(pdev);
107562306a36Sopenharmony_ci	int i;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (!soc_device_match(soc_no_cpu_notifier))
107862306a36Sopenharmony_ci		cpu_pm_unregister_notifier(&bgp->nb);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	/* Remove sensor interfaces */
108162306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
108262306a36Sopenharmony_ci		if (bgp->conf->sensors[i].unregister_cooling)
108362306a36Sopenharmony_ci			bgp->conf->sensors[i].unregister_cooling(bgp, i);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		if (bgp->conf->remove_sensor)
108662306a36Sopenharmony_ci			bgp->conf->remove_sensor(bgp, i);
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	ti_bandgap_power(bgp, false);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
109262306a36Sopenharmony_ci		clk_disable_unprepare(bgp->fclock);
109362306a36Sopenharmony_ci	clk_put(bgp->fclock);
109462306a36Sopenharmony_ci	clk_put(bgp->div_clk);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TALERT))
109762306a36Sopenharmony_ci		free_irq(bgp->irq, bgp);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, TSHUT))
110062306a36Sopenharmony_ci		free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return 0;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
110662306a36Sopenharmony_cistatic int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	int i;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
111162306a36Sopenharmony_ci		struct temp_sensor_registers *tsr;
111262306a36Sopenharmony_ci		struct temp_sensor_regval *rval;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		rval = &bgp->regval[i];
111562306a36Sopenharmony_ci		tsr = bgp->conf->sensors[i].registers;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
111862306a36Sopenharmony_ci			rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
111962306a36Sopenharmony_ci							tsr->bgap_mode_ctrl);
112062306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, COUNTER))
112162306a36Sopenharmony_ci			rval->bg_counter = ti_bandgap_readl(bgp,
112262306a36Sopenharmony_ci							tsr->bgap_counter);
112362306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TALERT)) {
112462306a36Sopenharmony_ci			rval->bg_threshold = ti_bandgap_readl(bgp,
112562306a36Sopenharmony_ci							tsr->bgap_threshold);
112662306a36Sopenharmony_ci			rval->bg_ctrl = ti_bandgap_readl(bgp,
112762306a36Sopenharmony_ci						   tsr->bgap_mask_ctrl);
112862306a36Sopenharmony_ci		}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
113162306a36Sopenharmony_ci			rval->tshut_threshold = ti_bandgap_readl(bgp,
113262306a36Sopenharmony_ci						   tsr->tshut_threshold);
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	int i;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	for (i = 0; i < bgp->conf->sensor_count; i++) {
114362306a36Sopenharmony_ci		struct temp_sensor_registers *tsr;
114462306a36Sopenharmony_ci		struct temp_sensor_regval *rval;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		rval = &bgp->regval[i];
114762306a36Sopenharmony_ci		tsr = bgp->conf->sensors[i].registers;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
115062306a36Sopenharmony_ci			ti_bandgap_writel(bgp, rval->tshut_threshold,
115162306a36Sopenharmony_ci					  tsr->tshut_threshold);
115262306a36Sopenharmony_ci		/* Force immediate temperature measurement and update
115362306a36Sopenharmony_ci		 * of the DTEMP field
115462306a36Sopenharmony_ci		 */
115562306a36Sopenharmony_ci		ti_bandgap_force_single_read(bgp, i);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, COUNTER))
115862306a36Sopenharmony_ci			ti_bandgap_writel(bgp, rval->bg_counter,
115962306a36Sopenharmony_ci					  tsr->bgap_counter);
116062306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
116162306a36Sopenharmony_ci			ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
116262306a36Sopenharmony_ci					  tsr->bgap_mode_ctrl);
116362306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, TALERT)) {
116462306a36Sopenharmony_ci			ti_bandgap_writel(bgp, rval->bg_threshold,
116562306a36Sopenharmony_ci					  tsr->bgap_threshold);
116662306a36Sopenharmony_ci			ti_bandgap_writel(bgp, rval->bg_ctrl,
116762306a36Sopenharmony_ci					  tsr->bgap_mask_ctrl);
116862306a36Sopenharmony_ci		}
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	return 0;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_cistatic int ti_bandgap_suspend(struct device *dev)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct ti_bandgap *bgp = dev_get_drvdata(dev);
117762306a36Sopenharmony_ci	int err;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	err = ti_bandgap_save_ctxt(bgp);
118062306a36Sopenharmony_ci	ti_bandgap_power(bgp, false);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
118362306a36Sopenharmony_ci		clk_disable_unprepare(bgp->fclock);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	bgp->is_suspended = true;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return err;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic int bandgap_omap_cpu_notifier(struct notifier_block *nb,
119162306a36Sopenharmony_ci				  unsigned long cmd, void *v)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	struct ti_bandgap *bgp;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	bgp = container_of(nb, struct ti_bandgap, nb);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	spin_lock(&bgp->lock);
119862306a36Sopenharmony_ci	switch (cmd) {
119962306a36Sopenharmony_ci	case CPU_CLUSTER_PM_ENTER:
120062306a36Sopenharmony_ci		if (bgp->is_suspended)
120162306a36Sopenharmony_ci			break;
120262306a36Sopenharmony_ci		ti_bandgap_save_ctxt(bgp);
120362306a36Sopenharmony_ci		ti_bandgap_power(bgp, false);
120462306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
120562306a36Sopenharmony_ci			clk_disable(bgp->fclock);
120662306a36Sopenharmony_ci		break;
120762306a36Sopenharmony_ci	case CPU_CLUSTER_PM_ENTER_FAILED:
120862306a36Sopenharmony_ci	case CPU_CLUSTER_PM_EXIT:
120962306a36Sopenharmony_ci		if (bgp->is_suspended)
121062306a36Sopenharmony_ci			break;
121162306a36Sopenharmony_ci		if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
121262306a36Sopenharmony_ci			clk_enable(bgp->fclock);
121362306a36Sopenharmony_ci		ti_bandgap_power(bgp, true);
121462306a36Sopenharmony_ci		ti_bandgap_restore_ctxt(bgp);
121562306a36Sopenharmony_ci		break;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	spin_unlock(&bgp->lock);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return NOTIFY_OK;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic int ti_bandgap_resume(struct device *dev)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	struct ti_bandgap *bgp = dev_get_drvdata(dev);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
122762306a36Sopenharmony_ci		clk_prepare_enable(bgp->fclock);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	ti_bandgap_power(bgp, true);
123062306a36Sopenharmony_ci	bgp->is_suspended = false;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return ti_bandgap_restore_ctxt(bgp);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend,
123562306a36Sopenharmony_ci			 ti_bandgap_resume);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci#define DEV_PM_OPS	(&ti_bandgap_dev_pm_ops)
123862306a36Sopenharmony_ci#else
123962306a36Sopenharmony_ci#define DEV_PM_OPS	NULL
124062306a36Sopenharmony_ci#endif
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic const struct of_device_id of_ti_bandgap_match[] = {
124362306a36Sopenharmony_ci#ifdef CONFIG_OMAP3_THERMAL
124462306a36Sopenharmony_ci	{
124562306a36Sopenharmony_ci		.compatible = "ti,omap34xx-bandgap",
124662306a36Sopenharmony_ci		.data = (void *)&omap34xx_data,
124762306a36Sopenharmony_ci	},
124862306a36Sopenharmony_ci	{
124962306a36Sopenharmony_ci		.compatible = "ti,omap36xx-bandgap",
125062306a36Sopenharmony_ci		.data = (void *)&omap36xx_data,
125162306a36Sopenharmony_ci	},
125262306a36Sopenharmony_ci#endif
125362306a36Sopenharmony_ci#ifdef CONFIG_OMAP4_THERMAL
125462306a36Sopenharmony_ci	{
125562306a36Sopenharmony_ci		.compatible = "ti,omap4430-bandgap",
125662306a36Sopenharmony_ci		.data = (void *)&omap4430_data,
125762306a36Sopenharmony_ci	},
125862306a36Sopenharmony_ci	{
125962306a36Sopenharmony_ci		.compatible = "ti,omap4460-bandgap",
126062306a36Sopenharmony_ci		.data = (void *)&omap4460_data,
126162306a36Sopenharmony_ci	},
126262306a36Sopenharmony_ci	{
126362306a36Sopenharmony_ci		.compatible = "ti,omap4470-bandgap",
126462306a36Sopenharmony_ci		.data = (void *)&omap4470_data,
126562306a36Sopenharmony_ci	},
126662306a36Sopenharmony_ci#endif
126762306a36Sopenharmony_ci#ifdef CONFIG_OMAP5_THERMAL
126862306a36Sopenharmony_ci	{
126962306a36Sopenharmony_ci		.compatible = "ti,omap5430-bandgap",
127062306a36Sopenharmony_ci		.data = (void *)&omap5430_data,
127162306a36Sopenharmony_ci	},
127262306a36Sopenharmony_ci#endif
127362306a36Sopenharmony_ci#ifdef CONFIG_DRA752_THERMAL
127462306a36Sopenharmony_ci	{
127562306a36Sopenharmony_ci		.compatible = "ti,dra752-bandgap",
127662306a36Sopenharmony_ci		.data = (void *)&dra752_data,
127762306a36Sopenharmony_ci	},
127862306a36Sopenharmony_ci#endif
127962306a36Sopenharmony_ci	/* Sentinel */
128062306a36Sopenharmony_ci	{ },
128162306a36Sopenharmony_ci};
128262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic struct platform_driver ti_bandgap_sensor_driver = {
128562306a36Sopenharmony_ci	.probe = ti_bandgap_probe,
128662306a36Sopenharmony_ci	.remove = ti_bandgap_remove,
128762306a36Sopenharmony_ci	.driver = {
128862306a36Sopenharmony_ci			.name = "ti-soc-thermal",
128962306a36Sopenharmony_ci			.pm = DEV_PM_OPS,
129062306a36Sopenharmony_ci			.of_match_table	= of_ti_bandgap_match,
129162306a36Sopenharmony_ci	},
129262306a36Sopenharmony_ci};
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cimodule_platform_driver(ti_bandgap_sensor_driver);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
129762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
129862306a36Sopenharmony_ciMODULE_ALIAS("platform:ti-soc-thermal");
129962306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instrument Inc.");
1300