aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-4.19/950-0466-thermal-brcmstb_thermal-Add-BCM2838-support.patch
blob: 3af52b9a86d1a14b3a944c9b9130195b92b5e260 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
From d49649e2dcf0d5775e92677d37e229e0387fe82a Mon Sep 17 00:00:00 2001
From: Stefan Wahren <wahrenst@gmx.net>
Date: Sat, 18 May 2019 12:26:11 +0200
Subject: [PATCH] thermal: brcmstb_thermal: Add BCM2838 support

The BCM2838 has an AVS TMON hardware block. This adds the necessary
support to the brcmstb_thermal driver ( no trip handling ).

Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
---
 drivers/thermal/broadcom/Kconfig           |  2 +-
 drivers/thermal/broadcom/brcmstb_thermal.c | 65 +++++++++++++++++++---
 2 files changed, 58 insertions(+), 9 deletions(-)

--- a/drivers/thermal/broadcom/Kconfig
+++ b/drivers/thermal/broadcom/Kconfig
@@ -8,7 +8,7 @@ config BCM2835_THERMAL
 
 config BRCMSTB_THERMAL
 	tristate "Broadcom STB AVS TMON thermal driver"
-	depends on ARCH_BRCMSTB || COMPILE_TEST
+	depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
 	help
 	  Enable this driver if you have a Broadcom STB SoC and would like
 	  thermal framework support.
--- a/drivers/thermal/broadcom/brcmstb_thermal.c
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
@@ -19,6 +19,7 @@
 #define pr_fmt(fmt)	DRV_NAME ": " fmt
 
 #include <linux/bitops.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -31,9 +32,6 @@
 #include <linux/thermal.h>
 
 #define AVS_TMON_STATUS			0x00
- #define AVS_TMON_STATUS_valid_msk	BIT(11)
- #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
- #define AVS_TMON_STATUS_data_shift	1
 
 #define AVS_TMON_EN_OVERTEMP_RESET	0x04
  #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
@@ -111,10 +109,19 @@ static struct avs_tmon_trip avs_tmon_tri
 	},
 };
 
+struct brcmstb_thermal_of_data {
+	const struct thermal_zone_of_device_ops *of_ops;
+	u32 status_valid_mask;
+	u32 status_data_mask;
+	u32 status_data_shift;
+};
+
 struct brcmstb_thermal_priv {
 	void __iomem *tmon_base;
 	struct device *dev;
 	struct thermal_zone_device *thermal;
+	struct clk *clk;
+	const struct brcmstb_thermal_of_data *socdata;
 };
 
 /* Convert a HW code to a temperature reading (millidegree celsius) */
@@ -151,17 +158,18 @@ static inline u32 avs_tmon_temp_to_code(
 static int brcmstb_get_temp(void *data, int *temp)
 {
 	struct brcmstb_thermal_priv *priv = data;
+	const struct brcmstb_thermal_of_data *socdata = priv->socdata;
 	u32 val;
 	long t;
 
 	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
 
-	if (!(val & AVS_TMON_STATUS_valid_msk)) {
+	if (!(val & socdata->status_valid_mask)) {
 		dev_err(priv->dev, "reading not valid\n");
 		return -EIO;
 	}
 
-	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
+	val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
 
 	t = avs_tmon_code_to_temp(priv->thermal, val);
 	if (t < 0)
@@ -286,13 +294,34 @@ static int brcmstb_set_trips(void *data,
 	return 0;
 }
 
-static struct thermal_zone_of_device_ops of_ops = {
+static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
 	.get_temp	= brcmstb_get_temp,
 	.set_trips	= brcmstb_set_trips,
 };
 
+static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
+	.get_temp	= brcmstb_get_temp,
+};
+
+static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
+	.of_ops = &bcm7445_thermal_of_ops,
+	.status_valid_mask = BIT(11),
+	.status_data_mask = GENMASK(10, 1),
+	.status_data_shift = 1,
+};
+
+static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
+	.of_ops = &bcm2838_thermal_of_ops,
+	.status_valid_mask = BIT(10),
+	.status_data_mask = GENMASK(9, 0),
+	.status_data_shift = 0,
+};
+
 static const struct of_device_id brcmstb_thermal_id_table[] = {
-	{ .compatible = "brcm,avs-tmon" },
+	{ .compatible = "brcm,avs-tmon",
+	  .data = &bcm7445_thermal_of_data },
+	{ .compatible = "brcm,avs-tmon-bcm2838",
+	  .data = &bcm2838_thermal_of_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
@@ -313,10 +342,27 @@ static int brcmstb_thermal_probe(struct
 	if (IS_ERR(priv->tmon_base))
 		return PTR_ERR(priv->tmon_base);
 
+	priv->socdata = of_device_get_match_data(&pdev->dev);
+	if (!priv->socdata) {
+		dev_err(&pdev->dev, "no device match found\n");
+		return -ENODEV;
+	}
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	if (!IS_ERR(priv->clk)) {
+		ret = clk_prepare_enable(priv->clk);
+		if (ret)
+			return ret;
+	}
+
 	priv->dev = &pdev->dev;
 	platform_set_drvdata(pdev, priv);
 
-	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
+	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
+						  priv->socdata->of_ops);
 	if (IS_ERR(thermal)) {
 		ret = PTR_ERR(thermal);
 		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
@@ -356,6 +402,9 @@ static int brcmstb_thermal_exit(struct p
 	if (thermal)
 		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
 
+	if (!IS_ERR(priv->clk))
+		clk_disable_unprepare(priv->clk);
+
 	return 0;
 }