xref: /openbmc/linux/drivers/thermal/k3_bandgap.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
148b2bce8SKeerthy // SPDX-License-Identifier: GPL-2.0
248b2bce8SKeerthy /*
348b2bce8SKeerthy  * TI Bandgap temperature sensor driver for K3 SoC Family
448b2bce8SKeerthy  *
548b2bce8SKeerthy  * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
648b2bce8SKeerthy  */
748b2bce8SKeerthy 
848b2bce8SKeerthy #include <linux/err.h>
948b2bce8SKeerthy #include <linux/init.h>
1048b2bce8SKeerthy #include <linux/io.h>
1148b2bce8SKeerthy #include <linux/kernel.h>
1248b2bce8SKeerthy #include <linux/module.h>
1348b2bce8SKeerthy #include <linux/of.h>
14*f6a756e8SRob Herring #include <linux/platform_device.h>
1548b2bce8SKeerthy #include <linux/pm_runtime.h>
1648b2bce8SKeerthy #include <linux/thermal.h>
1748b2bce8SKeerthy #include <linux/types.h>
1848b2bce8SKeerthy 
199e5f5f15SMassimiliano Minella #include "thermal_hwmon.h"
209e5f5f15SMassimiliano Minella 
2148b2bce8SKeerthy #define K3_VTM_DEVINFO_PWR0_OFFSET		0x4
2248b2bce8SKeerthy #define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK	0xf0
2348b2bce8SKeerthy #define K3_VTM_TMPSENS0_CTRL_OFFSET	0x80
2448b2bce8SKeerthy #define K3_VTM_REGS_PER_TS			0x10
2548b2bce8SKeerthy #define K3_VTM_TS_STAT_DTEMP_MASK	0x3ff
2648b2bce8SKeerthy #define K3_VTM_TMPSENS_CTRL_CBIASSEL	BIT(0)
2748b2bce8SKeerthy #define K3_VTM_TMPSENS_CTRL_SOC		BIT(5)
2848b2bce8SKeerthy #define K3_VTM_TMPSENS_CTRL_CLRZ		BIT(6)
2948b2bce8SKeerthy #define K3_VTM_TMPSENS_CTRL_CLKON_REQ	BIT(7)
3048b2bce8SKeerthy 
3148b2bce8SKeerthy #define K3_VTM_ADC_BEGIN_VAL		540
3248b2bce8SKeerthy #define K3_VTM_ADC_END_VAL		944
3348b2bce8SKeerthy 
3448b2bce8SKeerthy static const int k3_adc_to_temp[] = {
3548b2bce8SKeerthy 	-40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
3648b2bce8SKeerthy 	-37800, -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200,
3748b2bce8SKeerthy 	-33800, -33400, -33000, -32600, -32200, -31800, -31400, -31000, -30600,
3848b2bce8SKeerthy 	-30200, -29800, -29400, -29000, -28600, -28200, -27700, -27100, -26600,
3948b2bce8SKeerthy 	-26200, -25800, -25400, -25000, -24600, -24200, -23800, -23400, -23000,
4048b2bce8SKeerthy 	-22600, -22200, -21800, -21400, -21000, -20500, -19900, -19400, -19000,
4148b2bce8SKeerthy 	-18600, -18200, -17800, -17400, -17000, -16600, -16200, -15800, -15400,
4248b2bce8SKeerthy 	-15000, -14600, -14200, -13800, -13400, -13000, -12500, -11900, -11400,
4348b2bce8SKeerthy 	-11000, -10600, -10200, -9800, -9400, -9000, -8600, -8200, -7800, -7400,
4448b2bce8SKeerthy 	-7000, -6600, -6200, -5800, -5400, -5000, -4500, -3900, -3400, -3000,
4548b2bce8SKeerthy 	-2600, -2200, -1800, -1400, -1000, -600, -200, 200, 600, 1000, 1400,
4648b2bce8SKeerthy 	1800, 2200, 2600, 3000, 3400, 3900, 4500, 5000, 5400, 5800, 6200, 6600,
4748b2bce8SKeerthy 	7000, 7400, 7800, 8200, 8600, 9000, 9400, 9800, 10200, 10600, 11000,
4848b2bce8SKeerthy 	11400, 11800, 12200, 12700, 13300, 13800, 14200, 14600, 15000, 15400,
4948b2bce8SKeerthy 	15800, 16200, 16600, 17000, 17400, 17800, 18200, 18600, 19000, 19400,
5048b2bce8SKeerthy 	19800, 20200, 20600, 21000, 21400, 21900, 22500, 23000, 23400, 23800,
5148b2bce8SKeerthy 	24200, 24600, 25000, 25400, 25800, 26200, 26600, 27000, 27400, 27800,
5248b2bce8SKeerthy 	28200, 28600, 29000, 29400, 29800, 30200, 30600, 31000, 31400, 31900,
5348b2bce8SKeerthy 	32500, 33000, 33400, 33800, 34200, 34600, 35000, 35400, 35800, 36200,
5448b2bce8SKeerthy 	36600, 37000, 37400, 37800, 38200, 38600, 39000, 39400, 39800, 40200,
5548b2bce8SKeerthy 	40600, 41000, 41400, 41800, 42200, 42600, 43100, 43700, 44200, 44600,
5648b2bce8SKeerthy 	45000, 45400, 45800, 46200, 46600, 47000, 47400, 47800, 48200, 48600,
5748b2bce8SKeerthy 	49000, 49400, 49800, 50200, 50600, 51000, 51400, 51800, 52200, 52600,
5848b2bce8SKeerthy 	53000, 53400, 53800, 54200, 54600, 55000, 55400, 55900, 56500, 57000,
5948b2bce8SKeerthy 	57400, 57800, 58200, 58600, 59000, 59400, 59800, 60200, 60600, 61000,
6048b2bce8SKeerthy 	61400, 61800, 62200, 62600, 63000, 63400, 63800, 64200, 64600, 65000,
6148b2bce8SKeerthy 	65400, 65800, 66200, 66600, 67000, 67400, 67800, 68200, 68600, 69000,
6248b2bce8SKeerthy 	69400, 69800, 70200, 70600, 71000, 71500, 72100, 72600, 73000, 73400,
6348b2bce8SKeerthy 	73800, 74200, 74600, 75000, 75400, 75800, 76200, 76600, 77000, 77400,
6448b2bce8SKeerthy 	77800, 78200, 78600, 79000, 79400, 79800, 80200, 80600, 81000, 81400,
6548b2bce8SKeerthy 	81800, 82200, 82600, 83000, 83400, 83800, 84200, 84600, 85000, 85400,
6648b2bce8SKeerthy 	85800, 86200, 86600, 87000, 87400, 87800, 88200, 88600, 89000, 89400,
6748b2bce8SKeerthy 	89800, 90200, 90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400,
6848b2bce8SKeerthy 	93800, 94200, 94600, 95000, 95400, 95800, 96200, 96600, 97000, 97500,
6948b2bce8SKeerthy 	98100, 98600, 99000, 99400, 99800, 100200, 100600, 101000, 101400,
7048b2bce8SKeerthy 	101800, 102200, 102600, 103000, 103400, 103800, 104200, 104600, 105000,
7148b2bce8SKeerthy 	105400, 105800, 106200, 106600, 107000, 107400, 107800, 108200, 108600,
7248b2bce8SKeerthy 	109000, 109400, 109800, 110200, 110600, 111000, 111400, 111800, 112200,
7348b2bce8SKeerthy 	112600, 113000, 113400, 113800, 114200, 114600, 115000, 115400, 115800,
7448b2bce8SKeerthy 	116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000, 119400,
7548b2bce8SKeerthy 	119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
7648b2bce8SKeerthy 	123400, 123800, 124200, 124600, 124900, 125000,
7748b2bce8SKeerthy };
7848b2bce8SKeerthy 
7948b2bce8SKeerthy struct k3_bandgap {
8048b2bce8SKeerthy 	void __iomem *base;
8148b2bce8SKeerthy 	const struct k3_bandgap_data *conf;
8248b2bce8SKeerthy };
8348b2bce8SKeerthy 
8448b2bce8SKeerthy /* common data structures */
8548b2bce8SKeerthy struct k3_thermal_data {
8648b2bce8SKeerthy 	struct thermal_zone_device *tzd;
8748b2bce8SKeerthy 	struct k3_bandgap *bgp;
8848b2bce8SKeerthy 	int sensor_id;
8948b2bce8SKeerthy 	u32 ctrl_offset;
9048b2bce8SKeerthy 	u32 stat_offset;
9148b2bce8SKeerthy };
9248b2bce8SKeerthy 
vtm_get_best_value(unsigned int s0,unsigned int s1,unsigned int s2)9348b2bce8SKeerthy static unsigned int vtm_get_best_value(unsigned int s0, unsigned int s1,
9448b2bce8SKeerthy 				       unsigned int s2)
9548b2bce8SKeerthy {
9648b2bce8SKeerthy 	int d01 = abs(s0 - s1);
9748b2bce8SKeerthy 	int d02 = abs(s0 - s2);
9848b2bce8SKeerthy 	int d12 = abs(s1 - s2);
9948b2bce8SKeerthy 
10048b2bce8SKeerthy 	if (d01 <= d02 && d01 <= d12)
10148b2bce8SKeerthy 		return (s0 + s1) / 2;
10248b2bce8SKeerthy 
10348b2bce8SKeerthy 	if (d02 <= d01 && d02 <= d12)
10448b2bce8SKeerthy 		return (s0 + s2) / 2;
10548b2bce8SKeerthy 
10648b2bce8SKeerthy 	return (s1 + s2) / 2;
10748b2bce8SKeerthy }
10848b2bce8SKeerthy 
k3_bgp_read_temp(struct k3_thermal_data * devdata,int * temp)10948b2bce8SKeerthy static int k3_bgp_read_temp(struct k3_thermal_data *devdata,
11048b2bce8SKeerthy 			    int *temp)
11148b2bce8SKeerthy {
11248b2bce8SKeerthy 	struct k3_bandgap *bgp;
11348b2bce8SKeerthy 	unsigned int dtemp, s0, s1, s2;
11448b2bce8SKeerthy 
11548b2bce8SKeerthy 	bgp = devdata->bgp;
11648b2bce8SKeerthy 
11748b2bce8SKeerthy 	/*
11848b2bce8SKeerthy 	 * Errata is applicable for am654 pg 1.0 silicon. There
11948b2bce8SKeerthy 	 * is a variation of the order for 8-10 degree centigrade.
12048b2bce8SKeerthy 	 * Work around that by getting the average of two closest
12148b2bce8SKeerthy 	 * readings out of three readings everytime we want to
12248b2bce8SKeerthy 	 * report temperatures.
12348b2bce8SKeerthy 	 *
12448b2bce8SKeerthy 	 * Errata workaround.
12548b2bce8SKeerthy 	 */
12648b2bce8SKeerthy 	s0 = readl(bgp->base + devdata->stat_offset) &
12748b2bce8SKeerthy 		K3_VTM_TS_STAT_DTEMP_MASK;
12848b2bce8SKeerthy 	s1 = readl(bgp->base + devdata->stat_offset) &
12948b2bce8SKeerthy 		K3_VTM_TS_STAT_DTEMP_MASK;
13048b2bce8SKeerthy 	s2 = readl(bgp->base + devdata->stat_offset) &
13148b2bce8SKeerthy 		K3_VTM_TS_STAT_DTEMP_MASK;
13248b2bce8SKeerthy 	dtemp = vtm_get_best_value(s0, s1, s2);
13348b2bce8SKeerthy 
13448b2bce8SKeerthy 	if (dtemp < K3_VTM_ADC_BEGIN_VAL || dtemp > K3_VTM_ADC_END_VAL)
13548b2bce8SKeerthy 		return -EINVAL;
13648b2bce8SKeerthy 
13748b2bce8SKeerthy 	*temp = k3_adc_to_temp[dtemp - K3_VTM_ADC_BEGIN_VAL];
13848b2bce8SKeerthy 
13948b2bce8SKeerthy 	return 0;
14048b2bce8SKeerthy }
14148b2bce8SKeerthy 
k3_thermal_get_temp(struct thermal_zone_device * tz,int * temp)142b86105edSDaniel Lezcano static int k3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
14348b2bce8SKeerthy {
1445f68d078SDaniel Lezcano 	struct k3_thermal_data *data = thermal_zone_device_priv(tz);
14548b2bce8SKeerthy 	int ret = 0;
14648b2bce8SKeerthy 
14748b2bce8SKeerthy 	ret = k3_bgp_read_temp(data, temp);
14848b2bce8SKeerthy 	if (ret)
14948b2bce8SKeerthy 		return ret;
15048b2bce8SKeerthy 
15148b2bce8SKeerthy 	return ret;
15248b2bce8SKeerthy }
15348b2bce8SKeerthy 
154b86105edSDaniel Lezcano static const struct thermal_zone_device_ops k3_of_thermal_ops = {
15548b2bce8SKeerthy 	.get_temp = k3_thermal_get_temp,
15648b2bce8SKeerthy };
15748b2bce8SKeerthy 
15848b2bce8SKeerthy static const struct of_device_id of_k3_bandgap_match[];
15948b2bce8SKeerthy 
k3_bandgap_probe(struct platform_device * pdev)16048b2bce8SKeerthy static int k3_bandgap_probe(struct platform_device *pdev)
16148b2bce8SKeerthy {
16248b2bce8SKeerthy 	int ret = 0, cnt, val, id;
16348b2bce8SKeerthy 	struct resource *res;
16448b2bce8SKeerthy 	struct device *dev = &pdev->dev;
16548b2bce8SKeerthy 	struct k3_bandgap *bgp;
16648b2bce8SKeerthy 	struct k3_thermal_data *data;
16748b2bce8SKeerthy 
16848b2bce8SKeerthy 	if (ARRAY_SIZE(k3_adc_to_temp) != (K3_VTM_ADC_END_VAL + 1 -
16948b2bce8SKeerthy 						K3_VTM_ADC_BEGIN_VAL))
17048b2bce8SKeerthy 		return -EINVAL;
17148b2bce8SKeerthy 
17248b2bce8SKeerthy 	bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
17348b2bce8SKeerthy 	if (!bgp)
17448b2bce8SKeerthy 		return -ENOMEM;
17548b2bce8SKeerthy 
17648b2bce8SKeerthy 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
17748b2bce8SKeerthy 	bgp->base = devm_ioremap_resource(dev, res);
17848b2bce8SKeerthy 	if (IS_ERR(bgp->base))
17948b2bce8SKeerthy 		return PTR_ERR(bgp->base);
18048b2bce8SKeerthy 
18148b2bce8SKeerthy 	pm_runtime_enable(dev);
18248b2bce8SKeerthy 	ret = pm_runtime_get_sync(dev);
18348b2bce8SKeerthy 	if (ret < 0) {
18448b2bce8SKeerthy 		pm_runtime_put_noidle(dev);
18548b2bce8SKeerthy 		pm_runtime_disable(dev);
18648b2bce8SKeerthy 		return ret;
18748b2bce8SKeerthy 	}
18848b2bce8SKeerthy 
18948b2bce8SKeerthy 	/* Get the sensor count in the VTM */
19048b2bce8SKeerthy 	val = readl(bgp->base + K3_VTM_DEVINFO_PWR0_OFFSET);
19148b2bce8SKeerthy 	cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
19248b2bce8SKeerthy 	cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
19348b2bce8SKeerthy 
19448b2bce8SKeerthy 	data = devm_kcalloc(dev, cnt, sizeof(*data), GFP_KERNEL);
19548b2bce8SKeerthy 	if (!data) {
19648b2bce8SKeerthy 		ret = -ENOMEM;
19748b2bce8SKeerthy 		goto err_alloc;
19848b2bce8SKeerthy 	}
19948b2bce8SKeerthy 
20048b2bce8SKeerthy 	/* Register the thermal sensors */
20148b2bce8SKeerthy 	for (id = 0; id < cnt; id++) {
20248b2bce8SKeerthy 		data[id].sensor_id = id;
20348b2bce8SKeerthy 		data[id].bgp = bgp;
20448b2bce8SKeerthy 		data[id].ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET +
20548b2bce8SKeerthy 					id * K3_VTM_REGS_PER_TS;
20648b2bce8SKeerthy 		data[id].stat_offset = data[id].ctrl_offset + 0x8;
20748b2bce8SKeerthy 
20848b2bce8SKeerthy 		val = readl(data[id].bgp->base + data[id].ctrl_offset);
20948b2bce8SKeerthy 		val |= (K3_VTM_TMPSENS_CTRL_SOC |
21048b2bce8SKeerthy 			K3_VTM_TMPSENS_CTRL_CLRZ |
21148b2bce8SKeerthy 			K3_VTM_TMPSENS_CTRL_CLKON_REQ);
21248b2bce8SKeerthy 		val &= ~K3_VTM_TMPSENS_CTRL_CBIASSEL;
21348b2bce8SKeerthy 		writel(val, data[id].bgp->base + data[id].ctrl_offset);
21448b2bce8SKeerthy 
21548b2bce8SKeerthy 		data[id].tzd =
216b86105edSDaniel Lezcano 		devm_thermal_of_zone_register(dev, id,
21748b2bce8SKeerthy 					      &data[id],
21848b2bce8SKeerthy 					      &k3_of_thermal_ops);
21948b2bce8SKeerthy 		if (IS_ERR(data[id].tzd)) {
22048b2bce8SKeerthy 			dev_err(dev, "thermal zone device is NULL\n");
22148b2bce8SKeerthy 			ret = PTR_ERR(data[id].tzd);
22248b2bce8SKeerthy 			goto err_alloc;
22348b2bce8SKeerthy 		}
2249e5f5f15SMassimiliano Minella 
2257c673ef5SYangtao Li 		devm_thermal_add_hwmon_sysfs(dev, data[id].tzd);
22648b2bce8SKeerthy 	}
22748b2bce8SKeerthy 
22848b2bce8SKeerthy 
22948b2bce8SKeerthy 	return 0;
23048b2bce8SKeerthy 
23148b2bce8SKeerthy err_alloc:
23248b2bce8SKeerthy 	pm_runtime_put_sync(dev);
23348b2bce8SKeerthy 	pm_runtime_disable(dev);
23448b2bce8SKeerthy 
23548b2bce8SKeerthy 	return ret;
23648b2bce8SKeerthy }
23748b2bce8SKeerthy 
k3_bandgap_remove(struct platform_device * pdev)23848b2bce8SKeerthy static int k3_bandgap_remove(struct platform_device *pdev)
23948b2bce8SKeerthy {
24048b2bce8SKeerthy 	pm_runtime_put_sync(&pdev->dev);
24148b2bce8SKeerthy 	pm_runtime_disable(&pdev->dev);
24248b2bce8SKeerthy 
24348b2bce8SKeerthy 	return 0;
24448b2bce8SKeerthy }
24548b2bce8SKeerthy 
24648b2bce8SKeerthy static const struct of_device_id of_k3_bandgap_match[] = {
24748b2bce8SKeerthy 	{
24848b2bce8SKeerthy 		.compatible = "ti,am654-vtm",
24948b2bce8SKeerthy 	},
25048b2bce8SKeerthy 	{ /* sentinel */ },
25148b2bce8SKeerthy };
25248b2bce8SKeerthy MODULE_DEVICE_TABLE(of, of_k3_bandgap_match);
25348b2bce8SKeerthy 
25448b2bce8SKeerthy static struct platform_driver k3_bandgap_sensor_driver = {
25548b2bce8SKeerthy 	.probe = k3_bandgap_probe,
25648b2bce8SKeerthy 	.remove = k3_bandgap_remove,
25748b2bce8SKeerthy 	.driver = {
25848b2bce8SKeerthy 		.name = "k3-soc-thermal",
25948b2bce8SKeerthy 		.of_match_table	= of_k3_bandgap_match,
26048b2bce8SKeerthy 	},
26148b2bce8SKeerthy };
26248b2bce8SKeerthy 
26348b2bce8SKeerthy module_platform_driver(k3_bandgap_sensor_driver);
26448b2bce8SKeerthy 
26548b2bce8SKeerthy MODULE_DESCRIPTION("K3 bandgap temperature sensor driver");
26648b2bce8SKeerthy MODULE_LICENSE("GPL v2");
26748b2bce8SKeerthy MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
268