aboutsummaryrefslogtreecommitdiff
path: root/target/linux/bcm27xx/patches-6.1/950-0441-hwmon-emc2305-fixups-for-driver-submitted-to-mailing.patch
blob: abb1eacef2403e36f3ad1f2c509e2338fb3c42e7 (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
163
From c53aee9d78372213c34f5ebfb084b58be754a23c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 5 May 2022 15:46:07 +0100
Subject: [PATCH] hwmon: emc2305: fixups for driver submitted to
 mailing lists

The driver had a number of issues, checkpatch warnings/errors,
and other limitations, so fix these up to make it usable.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/hwmon/emc2305.c | 73 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -15,12 +15,13 @@
 static const unsigned short
 emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END };
 
+#define EMC2305_REG_FAN_STATUS		0x24
+#define EMC2305_REG_FAN_STALL_STATUS	0x25
 #define EMC2305_REG_DRIVE_FAIL_STATUS	0x27
 #define EMC2305_REG_VENDOR		0xfe
 #define EMC2305_FAN_MAX			0xff
 #define EMC2305_FAN_MIN			0x00
 #define EMC2305_FAN_MAX_STATE		10
-#define EMC2305_DEVICE			0x34
 #define EMC2305_VENDOR			0x5d
 #define EMC2305_REG_PRODUCT_ID		0xfd
 #define EMC2305_TACH_REGS_UNUSE_BITS	3
@@ -39,6 +40,7 @@ emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2
 #define EMC2305_RPM_FACTOR		3932160
 
 #define EMC2305_REG_FAN_DRIVE(n)	(0x30 + 0x10 * (n))
+#define EMC2305_REG_FAN_CFG(n)		(0x32 + 0x10 * (n))
 #define EMC2305_REG_FAN_MIN_DRIVE(n)	(0x38 + 0x10 * (n))
 #define EMC2305_REG_FAN_TACH(n)		(0x3e + 0x10 * (n))
 
@@ -58,6 +60,15 @@ static const struct i2c_device_id emc230
 };
 MODULE_DEVICE_TABLE(i2c, emc2305_ids);
 
+static const struct of_device_id emc2305_dt_ids[] = {
+	{ .compatible = "microchip,emc2305" },
+	{ .compatible = "microchip,emc2303" },
+	{ .compatible = "microchip,emc2302" },
+	{ .compatible = "microchip,emc2301" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, emc2305_dt_ids);
+
 /**
  * @cdev: cooling device;
  * @curr_state: cooling current state;
@@ -101,6 +112,7 @@ struct emc2305_data {
 	u8 pwm_num;
 	bool pwm_separate;
 	u8 pwm_min[EMC2305_PWM_MAX];
+	u8 pwm_max;
 	struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX];
 };
 
@@ -273,7 +285,7 @@ static int emc2305_set_pwm(struct device
 	struct i2c_client *client = data->client;
 	int ret;
 
-	if (val < data->pwm_min[channel] || val > EMC2305_FAN_MAX)
+	if (val < data->pwm_min[channel] || val > data->pwm_max)
 		return -EINVAL;
 
 	ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val);
@@ -284,6 +296,49 @@ static int emc2305_set_pwm(struct device
 	return 0;
 }
 
+static int emc2305_get_tz_of(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct emc2305_data *data = dev_get_drvdata(dev);
+	int ret = 0;
+	u32 val;
+	int i;
+
+	/* OF parameters are optional - overwrite default setting
+	 * if some of them are provided.
+	 */
+
+	ret = of_property_read_u32(np, "emc2305,cooling-levels", &val);
+	if (!ret)
+		data->max_state = (u8)val;
+	else if (ret != -EINVAL)
+		return ret;
+
+	ret = of_property_read_u32(np, "emc2305,pwm-max", &val);
+	if (!ret)
+		data->pwm_max = (u8)val;
+	else if (ret != -EINVAL)
+		return ret;
+
+	ret = of_property_read_u32(np, "emc2305,pwm-min", &val);
+	if (!ret)
+		for (i = 0; i < EMC2305_PWM_MAX; i++)
+			data->pwm_min[i] = (u8)val;
+	else if (ret != -EINVAL)
+		return ret;
+
+	/* Not defined or 0 means one thermal zone over all cooling devices.
+	 * Otherwise - separated thermal zones for each PWM channel.
+	 */
+	ret = of_property_read_u32(np, "emc2305,pwm-channel", &val);
+	if (!ret)
+		data->pwm_separate = (val != 0);
+	else if (ret != -EINVAL)
+		return ret;
+
+	return 0;
+}
+
 static int emc2305_set_single_tz(struct device *dev, int idx)
 {
 	struct emc2305_data *data = dev_get_drvdata(dev);
@@ -572,11 +627,18 @@ static int emc2305_probe(struct i2c_clie
 		data->pwm_separate = pdata->pwm_separate;
 		for (i = 0; i < EMC2305_PWM_MAX; i++)
 			data->pwm_min[i] = pdata->pwm_min[i];
+		data->pwm_max = EMC2305_FAN_MAX;
 	} else {
 		data->max_state = EMC2305_FAN_MAX_STATE;
 		data->pwm_separate = false;
 		for (i = 0; i < EMC2305_PWM_MAX; i++)
 			data->pwm_min[i] = EMC2305_FAN_MIN;
+		data->pwm_max = EMC2305_FAN_MAX;
+		if (dev->of_node) {
+			ret = emc2305_get_tz_of(dev);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data,
@@ -597,6 +659,12 @@ static int emc2305_probe(struct i2c_clie
 			return ret;
 	}
 
+	/* Acknowledge any existing faults. Stops the device responding on the
+	 * SMBus alert address.
+	 */
+	i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STALL_STATUS);
+	i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STATUS);
+
 	return 0;
 }
 
@@ -612,6 +680,7 @@ static struct i2c_driver emc2305_driver
 	.class  = I2C_CLASS_HWMON,
 	.driver = {
 		.name = "emc2305",
+		.of_match_table = emc2305_dt_ids,
 	},
 	.probe    = emc2305_probe,
 	.remove	  = emc2305_remove,