blob: ad3e46667be8ebcb03f011be14a703eb20a0bd0c [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07002/*
3 * A hwmon driver for the Analog Devices ADT7470
4 * Copyright (C) 2007 IBM
5 *
Darrick J. Wong5407e0512013-08-26 15:42:27 -07006 * Author: Darrick J. Wong <darrick.wong@oracle.com>
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07007 */
8
Joe Perches2e991202010-10-20 06:51:27 +00009#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070011#include <linux/module.h>
12#include <linux/jiffies.h>
13#include <linux/i2c.h>
14#include <linux/hwmon.h>
15#include <linux/hwmon-sysfs.h>
16#include <linux/err.h>
17#include <linux/mutex.h>
18#include <linux/delay.h>
19#include <linux/log2.h>
Darrick J. Wong89fac112009-01-06 14:41:34 -080020#include <linux/kthread.h>
Chris Packhamef679592021-08-26 14:41:19 +120021#include <linux/regmap.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Joshua Scottaa18cc92016-08-08 13:35:45 +120023#include <linux/util_macros.h>
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070024
25/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050026static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070027
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070028/* ADT7470 registers */
29#define ADT7470_REG_BASE_ADDR 0x20
30#define ADT7470_REG_TEMP_BASE_ADDR 0x20
31#define ADT7470_REG_TEMP_MAX_ADDR 0x29
32#define ADT7470_REG_FAN_BASE_ADDR 0x2A
33#define ADT7470_REG_FAN_MAX_ADDR 0x31
34#define ADT7470_REG_PWM_BASE_ADDR 0x32
35#define ADT7470_REG_PWM_MAX_ADDR 0x35
36#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38
37#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B
38#define ADT7470_REG_CFG 0x40
Chris Packhamef679592021-08-26 14:41:19 +120039#define ADT7470_STRT_MASK 0x01
40#define ADT7470_TEST_MASK 0x02
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070041#define ADT7470_FSPD_MASK 0x04
Chris Packhamef679592021-08-26 14:41:19 +120042#define ADT7470_T05_STB_MASK 0x80
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070043#define ADT7470_REG_ALARM1 0x41
Darrick J. Wongfe03f282007-12-19 14:11:25 -080044#define ADT7470_R1T_ALARM 0x01
45#define ADT7470_R2T_ALARM 0x02
46#define ADT7470_R3T_ALARM 0x04
47#define ADT7470_R4T_ALARM 0x08
48#define ADT7470_R5T_ALARM 0x10
49#define ADT7470_R6T_ALARM 0x20
50#define ADT7470_R7T_ALARM 0x40
51#define ADT7470_OOL_ALARM 0x80
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070052#define ADT7470_REG_ALARM2 0x42
Darrick J. Wongfe03f282007-12-19 14:11:25 -080053#define ADT7470_R8T_ALARM 0x01
54#define ADT7470_R9T_ALARM 0x02
55#define ADT7470_R10T_ALARM 0x04
56#define ADT7470_FAN1_ALARM 0x10
57#define ADT7470_FAN2_ALARM 0x20
58#define ADT7470_FAN3_ALARM 0x40
59#define ADT7470_FAN4_ALARM 0x80
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070060#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44
61#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57
62#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58
63#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F
64#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60
65#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67
66#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68
67#define ADT7470_REG_PWM12_CFG 0x68
68#define ADT7470_PWM2_AUTO_MASK 0x40
69#define ADT7470_PWM1_AUTO_MASK 0x80
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -080070#define ADT7470_PWM_AUTO_MASK 0xC0
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070071#define ADT7470_REG_PWM34_CFG 0x69
72#define ADT7470_PWM3_AUTO_MASK 0x40
73#define ADT7470_PWM4_AUTO_MASK 0x80
74#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A
75#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D
76#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
77#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71
Joshua Scottaa18cc92016-08-08 13:35:45 +120078#define ADT7470_REG_CFG_2 0x74
Darrick J. Wong6f9703d2007-07-31 11:06:52 -070079#define ADT7470_REG_ACOUSTICS12 0x75
80#define ADT7470_REG_ACOUSTICS34 0x76
81#define ADT7470_REG_DEVICE 0x3D
82#define ADT7470_REG_VENDOR 0x3E
83#define ADT7470_REG_REVISION 0x3F
84#define ADT7470_REG_ALARM1_MASK 0x72
85#define ADT7470_REG_ALARM2_MASK 0x73
86#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C
87#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D
88#define ADT7470_REG_MAX_ADDR 0x81
89
90#define ADT7470_TEMP_COUNT 10
91#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x))
92#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
93#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
94 ((x) * 2) + 1)
95
96#define ADT7470_FAN_COUNT 4
97#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
98#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
99#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
100
101#define ADT7470_PWM_COUNT 4
102#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x))
103#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
104#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
105#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
106#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
107#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
108 ((x) / 2))
109
Darrick J. Wongfe03f282007-12-19 14:11:25 -0800110#define ALARM2(x) ((x) << 8)
111
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700112#define ADT7470_VENDOR 0x41
113#define ADT7470_DEVICE 0x70
114/* datasheet only mentions a revision 2 */
115#define ADT7470_REVISION 0x02
116
117/* "all temps" according to hwmon sysfs interface spec */
118#define ADT7470_PWM_ALL_TEMPS 0x3FF
119
120/* How often do we reread sensors values? (In jiffies) */
121#define SENSOR_REFRESH_INTERVAL (5 * HZ)
122
123/* How often do we reread sensor limit values? (In jiffies) */
124#define LIMIT_REFRESH_INTERVAL (60 * HZ)
125
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800126/* Wait at least 200ms per sensor for 10 sensors */
127#define TEMP_COLLECTION_TIME 2000
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700128
Darrick J. Wong89fac112009-01-06 14:41:34 -0800129/* auto update thing won't fire more than every 2s */
130#define AUTO_UPDATE_INTERVAL 2000
131
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700132/* datasheet says to divide this number by the fan reading to get fan rpm */
133#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
134#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
135#define FAN_PERIOD_INVALID 65535
136#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
137
Joshua Scottaa18cc92016-08-08 13:35:45 +1200138/* Config registers 1 and 2 include fields for selecting the PWM frequency */
139#define ADT7470_CFG_LF 0x40
140#define ADT7470_FREQ_MASK 0x70
141#define ADT7470_FREQ_SHIFT 4
142
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700143struct adt7470_data {
Chris Packhamef679592021-08-26 14:41:19 +1200144 struct regmap *regmap;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700145 struct mutex lock;
146 char sensors_valid;
147 char limits_valid;
148 unsigned long sensors_last_updated; /* In jiffies */
149 unsigned long limits_last_updated; /* In jiffies */
150
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800151 int num_temp_sensors; /* -1 = probe */
Darrick J. Wong89fac112009-01-06 14:41:34 -0800152 int temperatures_probed;
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800153
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700154 s8 temp[ADT7470_TEMP_COUNT];
155 s8 temp_min[ADT7470_TEMP_COUNT];
156 s8 temp_max[ADT7470_TEMP_COUNT];
157 u16 fan[ADT7470_FAN_COUNT];
158 u16 fan_min[ADT7470_FAN_COUNT];
159 u16 fan_max[ADT7470_FAN_COUNT];
Darrick J. Wongfe03f282007-12-19 14:11:25 -0800160 u16 alarm;
161 u16 alarms_mask;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700162 u8 force_pwm_max;
163 u8 pwm[ADT7470_PWM_COUNT];
164 u8 pwm_max[ADT7470_PWM_COUNT];
165 u8 pwm_automatic[ADT7470_PWM_COUNT];
166 u8 pwm_min[ADT7470_PWM_COUNT];
167 s8 pwm_tmin[ADT7470_PWM_COUNT];
168 u8 pwm_auto_temp[ADT7470_PWM_COUNT];
Darrick J. Wong89fac112009-01-06 14:41:34 -0800169
170 struct task_struct *auto_update;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800171 unsigned int auto_update_interval;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700172};
173
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700174/*
175 * 16-bit registers on the ADT7470 are low-byte first. The data sheet says
176 * that the low byte must be read before the high byte.
177 */
Chris Packhamef679592021-08-26 14:41:19 +1200178static inline int adt7470_read_word_data(struct adt7470_data *data, unsigned int reg,
179 unsigned int *val)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700180{
Chris Packhamef679592021-08-26 14:41:19 +1200181 u8 regval[2];
182 int err;
Chris Packham23bd0222021-08-26 14:41:18 +1200183
Chris Packhamef679592021-08-26 14:41:19 +1200184 err = regmap_bulk_read(data->regmap, reg, &regval, 2);
185 if (err < 0)
186 return err;
187
188 *val = regval[0] | (regval[1] << 8);
189
190 return 0;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700191}
192
Chris Packhamef679592021-08-26 14:41:19 +1200193static inline int adt7470_write_word_data(struct adt7470_data *data, unsigned int reg,
194 unsigned int val)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700195{
Chris Packhamef679592021-08-26 14:41:19 +1200196 u8 regval[2];
197
198 regval[0] = val & 0xFF;
199 regval[1] = val >> 8;
200
201 return regmap_bulk_write(data->regmap, reg, &regval, 2);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700202}
203
Darrick J. Wong89fac112009-01-06 14:41:34 -0800204/* Probe for temperature sensors. Assumes lock is held */
Chris Packhamef679592021-08-26 14:41:19 +1200205static int adt7470_read_temperatures(struct adt7470_data *data)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700206{
Darrick J. Wong89fac112009-01-06 14:41:34 -0800207 unsigned long res;
Chris Packhamef679592021-08-26 14:41:19 +1200208 unsigned int pwm_cfg[2];
209 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700210 int i;
Chris Packhamef679592021-08-26 14:41:19 +1200211 u8 pwm[ADT7470_FAN_COUNT];
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700212
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800213 /* save pwm[1-4] config register */
Chris Packhamef679592021-08-26 14:41:19 +1200214 err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(0), &pwm_cfg[0]);
215 if (err < 0)
216 return err;
217 err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(2), &pwm_cfg[1]);
218 if (err < 0)
219 return err;
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800220
221 /* set manual pwm to whatever it is set to now */
Chris Packhamef679592021-08-26 14:41:19 +1200222 err = regmap_bulk_read(data->regmap, ADT7470_REG_PWM(0), &pwm[0],
223 ADT7470_PWM_COUNT);
224 if (err < 0)
225 return err;
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800226
227 /* put pwm in manual mode */
Chris Packhamef679592021-08-26 14:41:19 +1200228 err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(0),
229 ADT7470_PWM_AUTO_MASK, 0);
230 if (err < 0)
231 return err;
232 err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(2),
233 ADT7470_PWM_AUTO_MASK, 0);
234 if (err < 0)
235 return err;
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800236
237 /* write pwm control to whatever it was */
Chris Packhamef679592021-08-26 14:41:19 +1200238 err = regmap_bulk_write(data->regmap, ADT7470_REG_PWM(0), &pwm[0],
239 ADT7470_PWM_COUNT);
240 if (err < 0)
241 return err;
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800242
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700243 /* start reading temperature sensors */
Chris Packhamef679592021-08-26 14:41:19 +1200244 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
245 ADT7470_T05_STB_MASK, ADT7470_T05_STB_MASK);
246 if (err < 0)
247 return err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700248
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800249 /* Delay is 200ms * number of temp sensors. */
Darrick J. Wong89fac112009-01-06 14:41:34 -0800250 res = msleep_interruptible((data->num_temp_sensors >= 0 ?
251 data->num_temp_sensors * 200 :
252 TEMP_COLLECTION_TIME));
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700253
254 /* done reading temperature sensors */
Chris Packhamef679592021-08-26 14:41:19 +1200255 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
256 ADT7470_T05_STB_MASK, 0);
257 if (err < 0)
258 return err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700259
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800260 /* restore pwm[1-4] config registers */
Chris Packhamef679592021-08-26 14:41:19 +1200261 err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
262 if (err < 0)
263 return err;
264 err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
265 if (err < 0)
266 return err;
Darrick J. Wong2e75a4b2009-01-06 14:41:32 -0800267
Chris Packhamef679592021-08-26 14:41:19 +1200268 if (res)
Darrick J. Wong89fac112009-01-06 14:41:34 -0800269 return -EAGAIN;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800270
271 /* Only count fans if we have to */
272 if (data->num_temp_sensors >= 0)
273 return 0;
274
Chris Packhamef679592021-08-26 14:41:19 +1200275 err = regmap_bulk_read(data->regmap, ADT7470_TEMP_REG(0), &data->temp[0],
276 ADT7470_TEMP_COUNT);
277 if (err < 0)
278 return err;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800279 for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
Darrick J. Wong89fac112009-01-06 14:41:34 -0800280 if (data->temp[i])
281 data->num_temp_sensors = i + 1;
282 }
283 data->temperatures_probed = 1;
284 return 0;
285}
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700286
Darrick J. Wong89fac112009-01-06 14:41:34 -0800287static int adt7470_update_thread(void *p)
288{
289 struct i2c_client *client = p;
290 struct adt7470_data *data = i2c_get_clientdata(client);
291
292 while (!kthread_should_stop()) {
293 mutex_lock(&data->lock);
Chris Packhamef679592021-08-26 14:41:19 +1200294 adt7470_read_temperatures(data);
Darrick J. Wong89fac112009-01-06 14:41:34 -0800295 mutex_unlock(&data->lock);
Joshua Scott93cacfd2016-09-09 17:19:26 +1200296
297 set_current_state(TASK_INTERRUPTIBLE);
Darrick J. Wong89fac112009-01-06 14:41:34 -0800298 if (kthread_should_stop())
299 break;
Joshua Scott93cacfd2016-09-09 17:19:26 +1200300
301 schedule_timeout(msecs_to_jiffies(data->auto_update_interval));
Darrick J. Wong89fac112009-01-06 14:41:34 -0800302 }
303
Darrick J. Wong89fac112009-01-06 14:41:34 -0800304 return 0;
305}
306
Chris Packhamad00a022020-10-20 11:34:22 +1300307static int adt7470_update_sensors(struct adt7470_data *data)
Darrick J. Wong89fac112009-01-06 14:41:34 -0800308{
Chris Packhamef679592021-08-26 14:41:19 +1200309 unsigned int val;
310 int err;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800311 int i;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800312
313 if (!data->temperatures_probed)
Chris Packhamef679592021-08-26 14:41:19 +1200314 err = adt7470_read_temperatures(data);
Darrick J. Wong89fac112009-01-06 14:41:34 -0800315 else
Chris Packhamef679592021-08-26 14:41:19 +1200316 err = regmap_bulk_read(data->regmap, ADT7470_TEMP_REG(0), &data->temp[0],
317 ADT7470_TEMP_COUNT);
318 if (err < 0)
319 return err;
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800320
Chris Packhamef679592021-08-26 14:41:19 +1200321 for (i = 0; i < ADT7470_FAN_COUNT; i++) {
322 err = adt7470_read_word_data(data, ADT7470_REG_FAN(i), &val);
323 if (err < 0)
324 return err;
325 data->fan[i] = val;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700326 }
327
Chris Packhamef679592021-08-26 14:41:19 +1200328 err = regmap_bulk_read(data->regmap, ADT7470_REG_PWM(0), &data->pwm[0], ADT7470_PWM_COUNT);
329 if (err < 0)
330 return err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700331
Chris Packhamef679592021-08-26 14:41:19 +1200332 for (i = 0; i < ADT7470_PWM_COUNT; i++) {
333 unsigned int mask;
334
335 if (i % 2)
336 mask = ADT7470_PWM2_AUTO_MASK;
337 else
338 mask = ADT7470_PWM1_AUTO_MASK;
339
340 err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(i), &val);
341 if (err < 0)
342 return err;
343 data->pwm_automatic[i] = !!(val & mask);
344
345 err = regmap_read(data->regmap, ADT7470_REG_PWM_AUTO_TEMP(i), &val);
346 if (err < 0)
347 return err;
348 if (!(i % 2))
349 data->pwm_auto_temp[i] = val >> 4;
350 else
351 data->pwm_auto_temp[i] = val & 0xF;
352 }
353
354 err = regmap_read(data->regmap, ADT7470_REG_CFG, &val);
355 if (err < 0)
356 return err;
357 data->force_pwm_max = !!(val & ADT7470_FSPD_MASK);
358
359 err = regmap_read(data->regmap, ADT7470_REG_ALARM1, &val);
360 if (err < 0)
361 return err;
362 data->alarm = val;
363 if (data->alarm & ADT7470_OOL_ALARM) {
364 err = regmap_read(data->regmap, ADT7470_REG_ALARM2, &val);
365 if (err < 0)
366 return err;
367 data->alarm |= ALARM2(val);
368 }
369
370 err = adt7470_read_word_data(data, ADT7470_REG_ALARM1_MASK, &val);
371 if (err < 0)
372 return err;
373 data->alarms_mask = val;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700374
Chris Packhamad00a022020-10-20 11:34:22 +1300375 return 0;
376}
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700377
Chris Packhamad00a022020-10-20 11:34:22 +1300378static int adt7470_update_limits(struct adt7470_data *data)
379{
Chris Packhamef679592021-08-26 14:41:19 +1200380 unsigned int val;
381 int err;
Chris Packhamad00a022020-10-20 11:34:22 +1300382 int i;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700383
384 for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
Chris Packhamef679592021-08-26 14:41:19 +1200385 err = regmap_read(data->regmap, ADT7470_TEMP_MIN_REG(i), &val);
386 if (err < 0)
387 return err;
388 data->temp_min[i] = (s8)val;
389 err = regmap_read(data->regmap, ADT7470_TEMP_MAX_REG(i), &val);
390 if (err < 0)
391 return err;
392 data->temp_max[i] = (s8)val;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700393 }
394
395 for (i = 0; i < ADT7470_FAN_COUNT; i++) {
Chris Packhamef679592021-08-26 14:41:19 +1200396 err = adt7470_read_word_data(data, ADT7470_REG_FAN_MIN(i), &val);
397 if (err < 0)
398 return err;
399 data->fan_min[i] = val;
400 err = adt7470_read_word_data(data, ADT7470_REG_FAN_MAX(i), &val);
401 if (err < 0)
402 return err;
403 data->fan_max[i] = val;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700404 }
405
406 for (i = 0; i < ADT7470_PWM_COUNT; i++) {
Chris Packhamef679592021-08-26 14:41:19 +1200407 err = regmap_read(data->regmap, ADT7470_REG_PWM_MAX(i), &val);
408 if (err < 0)
409 return err;
410 data->pwm_max[i] = val;
411 err = regmap_read(data->regmap, ADT7470_REG_PWM_MIN(i), &val);
412 if (err < 0)
413 return err;
414 data->pwm_min[i] = val;
415 err = regmap_read(data->regmap, ADT7470_REG_PWM_TMIN(i), &val);
416 if (err < 0)
417 return err;
418 data->pwm_tmin[i] = (s8)val;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700419 }
420
Chris Packhamad00a022020-10-20 11:34:22 +1300421 return 0;
422}
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700423
Chris Packhamad00a022020-10-20 11:34:22 +1300424static struct adt7470_data *adt7470_update_device(struct device *dev)
425{
426 struct adt7470_data *data = dev_get_drvdata(dev);
427 unsigned long local_jiffies = jiffies;
428 int need_sensors = 1;
429 int need_limits = 1;
430 int err;
431
432 /*
433 * Figure out if we need to update the shadow registers.
434 * Lockless means that we may occasionally report out of
435 * date data.
436 */
437 if (time_before(local_jiffies, data->sensors_last_updated +
438 SENSOR_REFRESH_INTERVAL) &&
439 data->sensors_valid)
440 need_sensors = 0;
441
442 if (time_before(local_jiffies, data->limits_last_updated +
443 LIMIT_REFRESH_INTERVAL) &&
444 data->limits_valid)
445 need_limits = 0;
446
447 if (!need_sensors && !need_limits)
448 return data;
449
450 mutex_lock(&data->lock);
451 if (need_sensors) {
452 err = adt7470_update_sensors(data);
453 if (err < 0)
454 goto out;
455 data->sensors_last_updated = local_jiffies;
456 data->sensors_valid = 1;
457 }
458
459 if (need_limits) {
460 err = adt7470_update_limits(data);
461 if (err < 0)
462 goto out;
463 data->limits_last_updated = local_jiffies;
464 data->limits_valid = 1;
465 }
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700466out:
467 mutex_unlock(&data->lock);
Chris Packhamad00a022020-10-20 11:34:22 +1300468
469 return err < 0 ? ERR_PTR(err) : data;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700470}
471
Julia Lawall808fc6c2016-12-22 13:04:34 +0100472static ssize_t auto_update_interval_show(struct device *dev,
Darrick J. Wong89fac112009-01-06 14:41:34 -0800473 struct device_attribute *devattr,
474 char *buf)
475{
476 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300477
478 if (IS_ERR(data))
479 return PTR_ERR(data);
480
Darrick J. Wong89fac112009-01-06 14:41:34 -0800481 return sprintf(buf, "%d\n", data->auto_update_interval);
482}
483
Julia Lawall808fc6c2016-12-22 13:04:34 +0100484static ssize_t auto_update_interval_store(struct device *dev,
485 struct device_attribute *devattr,
486 const char *buf, size_t count)
Darrick J. Wong89fac112009-01-06 14:41:34 -0800487{
Axel Lin30485772014-07-16 23:12:54 +0800488 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong89fac112009-01-06 14:41:34 -0800489 long temp;
490
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100491 if (kstrtol(buf, 10, &temp))
Darrick J. Wong89fac112009-01-06 14:41:34 -0800492 return -EINVAL;
493
Guenter Roeck2a844c12013-01-09 08:09:34 -0800494 temp = clamp_val(temp, 0, 60000);
Darrick J. Wong89fac112009-01-06 14:41:34 -0800495
496 mutex_lock(&data->lock);
497 data->auto_update_interval = temp;
498 mutex_unlock(&data->lock);
499
500 return count;
501}
502
Julia Lawall808fc6c2016-12-22 13:04:34 +0100503static ssize_t num_temp_sensors_show(struct device *dev,
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800504 struct device_attribute *devattr,
505 char *buf)
506{
507 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300508
509 if (IS_ERR(data))
510 return PTR_ERR(data);
511
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800512 return sprintf(buf, "%d\n", data->num_temp_sensors);
513}
514
Julia Lawall808fc6c2016-12-22 13:04:34 +0100515static ssize_t num_temp_sensors_store(struct device *dev,
516 struct device_attribute *devattr,
517 const char *buf, size_t count)
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800518{
Axel Lin30485772014-07-16 23:12:54 +0800519 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800520 long temp;
521
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100522 if (kstrtol(buf, 10, &temp))
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800523 return -EINVAL;
524
Guenter Roeck2a844c12013-01-09 08:09:34 -0800525 temp = clamp_val(temp, -1, 10);
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800526
527 mutex_lock(&data->lock);
528 data->num_temp_sensors = temp;
Darrick J. Wong89fac112009-01-06 14:41:34 -0800529 if (temp < 0)
530 data->temperatures_probed = 0;
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -0800531 mutex_unlock(&data->lock);
532
533 return count;
534}
535
Guenter Roeck42291a52018-12-10 14:02:02 -0800536static ssize_t temp_min_show(struct device *dev,
537 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700538{
539 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
540 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300541
542 if (IS_ERR(data))
543 return PTR_ERR(data);
544
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700545 return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
546}
547
Guenter Roeck42291a52018-12-10 14:02:02 -0800548static ssize_t temp_min_store(struct device *dev,
549 struct device_attribute *devattr,
550 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700551{
552 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800553 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800554 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200555 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800556
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100557 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800558 return -EINVAL;
559
Guenter Roeck64bd7082016-12-03 11:10:34 -0800560 temp = clamp_val(temp, -128000, 127000);
Darrick J. Wong8f8c1fb2009-01-06 14:41:31 -0800561 temp = DIV_ROUND_CLOSEST(temp, 1000);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700562
563 mutex_lock(&data->lock);
564 data->temp_min[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200565 err = regmap_write(data->regmap, ADT7470_TEMP_MIN_REG(attr->index),
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700566 temp);
567 mutex_unlock(&data->lock);
568
Chris Packhamef679592021-08-26 14:41:19 +1200569 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700570}
571
Guenter Roeck42291a52018-12-10 14:02:02 -0800572static ssize_t temp_max_show(struct device *dev,
573 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700574{
575 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
576 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300577
578 if (IS_ERR(data))
579 return PTR_ERR(data);
580
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700581 return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
582}
583
Guenter Roeck42291a52018-12-10 14:02:02 -0800584static ssize_t temp_max_store(struct device *dev,
585 struct device_attribute *devattr,
586 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700587{
588 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800589 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800590 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200591 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800592
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100593 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800594 return -EINVAL;
595
Guenter Roeck64bd7082016-12-03 11:10:34 -0800596 temp = clamp_val(temp, -128000, 127000);
Darrick J. Wong8f8c1fb2009-01-06 14:41:31 -0800597 temp = DIV_ROUND_CLOSEST(temp, 1000);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700598
599 mutex_lock(&data->lock);
600 data->temp_max[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200601 err = regmap_write(data->regmap, ADT7470_TEMP_MAX_REG(attr->index), temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700602 mutex_unlock(&data->lock);
603
Chris Packhamef679592021-08-26 14:41:19 +1200604 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700605}
606
Guenter Roeck42291a52018-12-10 14:02:02 -0800607static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700608 char *buf)
609{
610 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
611 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300612
613 if (IS_ERR(data))
614 return PTR_ERR(data);
615
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700616 return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
617}
618
Julia Lawall808fc6c2016-12-22 13:04:34 +0100619static ssize_t alarm_mask_show(struct device *dev,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700620 struct device_attribute *devattr,
621 char *buf)
622{
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700623 struct adt7470_data *data = adt7470_update_device(dev);
624
Chris Packhamad00a022020-10-20 11:34:22 +1300625 if (IS_ERR(data))
626 return PTR_ERR(data);
627
Darrick J. Wongfe03f282007-12-19 14:11:25 -0800628 return sprintf(buf, "%x\n", data->alarms_mask);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700629}
630
Julia Lawall808fc6c2016-12-22 13:04:34 +0100631static ssize_t alarm_mask_store(struct device *dev,
632 struct device_attribute *devattr,
633 const char *buf, size_t count)
Joshua Scottfeca3132016-09-09 17:19:25 +1200634{
635 struct adt7470_data *data = dev_get_drvdata(dev);
636 long mask;
Chris Packhamef679592021-08-26 14:41:19 +1200637 int err;
Joshua Scottfeca3132016-09-09 17:19:25 +1200638
639 if (kstrtoul(buf, 0, &mask))
640 return -EINVAL;
641
642 if (mask & ~0xffff)
643 return -EINVAL;
644
645 mutex_lock(&data->lock);
646 data->alarms_mask = mask;
Chris Packhamef679592021-08-26 14:41:19 +1200647 err = adt7470_write_word_data(data, ADT7470_REG_ALARM1_MASK, mask);
Joshua Scottfeca3132016-09-09 17:19:25 +1200648 mutex_unlock(&data->lock);
649
Chris Packhamef679592021-08-26 14:41:19 +1200650 return err < 0 ? err : count;
Joshua Scottfeca3132016-09-09 17:19:25 +1200651}
652
Guenter Roeck42291a52018-12-10 14:02:02 -0800653static ssize_t fan_max_show(struct device *dev,
654 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700655{
656 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
657 struct adt7470_data *data = adt7470_update_device(dev);
658
Chris Packhamad00a022020-10-20 11:34:22 +1300659 if (IS_ERR(data))
660 return PTR_ERR(data);
661
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700662 if (FAN_DATA_VALID(data->fan_max[attr->index]))
663 return sprintf(buf, "%d\n",
664 FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
665 else
666 return sprintf(buf, "0\n");
667}
668
Guenter Roeck42291a52018-12-10 14:02:02 -0800669static ssize_t fan_max_store(struct device *dev,
670 struct device_attribute *devattr,
671 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700672{
673 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800674 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800675 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200676 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700677
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100678 if (kstrtol(buf, 10, &temp) || !temp)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700679 return -EINVAL;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800680
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700681 temp = FAN_RPM_TO_PERIOD(temp);
Guenter Roeck2a844c12013-01-09 08:09:34 -0800682 temp = clamp_val(temp, 1, 65534);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700683
684 mutex_lock(&data->lock);
685 data->fan_max[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200686 err = adt7470_write_word_data(data, ADT7470_REG_FAN_MAX(attr->index), temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700687 mutex_unlock(&data->lock);
688
Chris Packhamef679592021-08-26 14:41:19 +1200689 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700690}
691
Guenter Roeck42291a52018-12-10 14:02:02 -0800692static ssize_t fan_min_show(struct device *dev,
693 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700694{
695 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
696 struct adt7470_data *data = adt7470_update_device(dev);
697
Chris Packhamad00a022020-10-20 11:34:22 +1300698 if (IS_ERR(data))
699 return PTR_ERR(data);
700
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700701 if (FAN_DATA_VALID(data->fan_min[attr->index]))
702 return sprintf(buf, "%d\n",
703 FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
704 else
705 return sprintf(buf, "0\n");
706}
707
Guenter Roeck42291a52018-12-10 14:02:02 -0800708static ssize_t fan_min_store(struct device *dev,
709 struct device_attribute *devattr,
710 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700711{
712 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800713 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800714 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200715 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700716
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100717 if (kstrtol(buf, 10, &temp) || !temp)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700718 return -EINVAL;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800719
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700720 temp = FAN_RPM_TO_PERIOD(temp);
Guenter Roeck2a844c12013-01-09 08:09:34 -0800721 temp = clamp_val(temp, 1, 65534);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700722
723 mutex_lock(&data->lock);
724 data->fan_min[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200725 err = adt7470_write_word_data(data, ADT7470_REG_FAN_MIN(attr->index), temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700726 mutex_unlock(&data->lock);
727
Chris Packhamef679592021-08-26 14:41:19 +1200728 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700729}
730
Guenter Roeck42291a52018-12-10 14:02:02 -0800731static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700732 char *buf)
733{
734 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
735 struct adt7470_data *data = adt7470_update_device(dev);
736
Chris Packhamad00a022020-10-20 11:34:22 +1300737 if (IS_ERR(data))
738 return PTR_ERR(data);
739
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700740 if (FAN_DATA_VALID(data->fan[attr->index]))
741 return sprintf(buf, "%d\n",
742 FAN_PERIOD_TO_RPM(data->fan[attr->index]));
743 else
744 return sprintf(buf, "0\n");
745}
746
Guenter Roeck42291a52018-12-10 14:02:02 -0800747static ssize_t force_pwm_max_show(struct device *dev,
748 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700749{
750 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300751
752 if (IS_ERR(data))
753 return PTR_ERR(data);
754
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700755 return sprintf(buf, "%d\n", data->force_pwm_max);
756}
757
Guenter Roeck42291a52018-12-10 14:02:02 -0800758static ssize_t force_pwm_max_store(struct device *dev,
759 struct device_attribute *devattr,
760 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700761{
Axel Lin30485772014-07-16 23:12:54 +0800762 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800763 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200764 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700765
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100766 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800767 return -EINVAL;
768
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700769 mutex_lock(&data->lock);
770 data->force_pwm_max = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200771 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
772 ADT7470_FSPD_MASK,
773 temp ? ADT7470_FSPD_MASK : 0);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700774 mutex_unlock(&data->lock);
775
Chris Packhamef679592021-08-26 14:41:19 +1200776 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700777}
778
Guenter Roeck42291a52018-12-10 14:02:02 -0800779static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700780 char *buf)
781{
782 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
783 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300784
785 if (IS_ERR(data))
786 return PTR_ERR(data);
787
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700788 return sprintf(buf, "%d\n", data->pwm[attr->index]);
789}
790
Guenter Roeck42291a52018-12-10 14:02:02 -0800791static ssize_t pwm_store(struct device *dev, struct device_attribute *devattr,
792 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700793{
794 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800795 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800796 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200797 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800798
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100799 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800800 return -EINVAL;
801
Guenter Roeck2a844c12013-01-09 08:09:34 -0800802 temp = clamp_val(temp, 0, 255);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700803
804 mutex_lock(&data->lock);
805 data->pwm[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200806 err = regmap_write(data->regmap, ADT7470_REG_PWM(attr->index), temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700807 mutex_unlock(&data->lock);
808
Chris Packhamef679592021-08-26 14:41:19 +1200809 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700810}
811
Joshua Scottaa18cc92016-08-08 13:35:45 +1200812/* These are the valid PWM frequencies to the nearest Hz */
813static const int adt7470_freq_map[] = {
814 11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
815};
816
Julia Lawall808fc6c2016-12-22 13:04:34 +0100817static ssize_t pwm1_freq_show(struct device *dev,
818 struct device_attribute *devattr, char *buf)
Joshua Scottaa18cc92016-08-08 13:35:45 +1200819{
820 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamef679592021-08-26 14:41:19 +1200821 unsigned int cfg_reg_1, cfg_reg_2;
Joshua Scottaa18cc92016-08-08 13:35:45 +1200822 int index;
Chris Packhamef679592021-08-26 14:41:19 +1200823 int err;
824
825 if (IS_ERR(data))
826 return PTR_ERR(data);
Joshua Scottaa18cc92016-08-08 13:35:45 +1200827
828 mutex_lock(&data->lock);
Chris Packhamef679592021-08-26 14:41:19 +1200829 err = regmap_read(data->regmap, ADT7470_REG_CFG, &cfg_reg_1);
830 if (err < 0)
831 goto out;
832 err = regmap_read(data->regmap, ADT7470_REG_CFG_2, &cfg_reg_2);
833 if (err < 0)
834 goto out;
Joshua Scottaa18cc92016-08-08 13:35:45 +1200835 mutex_unlock(&data->lock);
836
837 index = (cfg_reg_2 & ADT7470_FREQ_MASK) >> ADT7470_FREQ_SHIFT;
838 if (!(cfg_reg_1 & ADT7470_CFG_LF))
839 index += 8;
840 if (index >= ARRAY_SIZE(adt7470_freq_map))
841 index = ARRAY_SIZE(adt7470_freq_map) - 1;
842
843 return scnprintf(buf, PAGE_SIZE, "%d\n", adt7470_freq_map[index]);
Chris Packhamef679592021-08-26 14:41:19 +1200844
845out:
846 mutex_unlock(&data->lock);
847 return err;
Joshua Scottaa18cc92016-08-08 13:35:45 +1200848}
849
Julia Lawall808fc6c2016-12-22 13:04:34 +0100850static ssize_t pwm1_freq_store(struct device *dev,
851 struct device_attribute *devattr,
852 const char *buf, size_t count)
Joshua Scottaa18cc92016-08-08 13:35:45 +1200853{
854 struct adt7470_data *data = dev_get_drvdata(dev);
Joshua Scottaa18cc92016-08-08 13:35:45 +1200855 long freq;
856 int index;
857 int low_freq = ADT7470_CFG_LF;
Chris Packhamef679592021-08-26 14:41:19 +1200858 int err;
Joshua Scottaa18cc92016-08-08 13:35:45 +1200859
860 if (kstrtol(buf, 10, &freq))
861 return -EINVAL;
862
863 /* Round the user value given to the closest available frequency */
864 index = find_closest(freq, adt7470_freq_map,
865 ARRAY_SIZE(adt7470_freq_map));
866
867 if (index >= 8) {
868 index -= 8;
869 low_freq = 0;
870 }
871
872 mutex_lock(&data->lock);
873 /* Configuration Register 1 */
Chris Packhamef679592021-08-26 14:41:19 +1200874 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
875 ADT7470_CFG_LF, low_freq);
876 if (err < 0)
877 goto out;
878
Joshua Scottaa18cc92016-08-08 13:35:45 +1200879 /* Configuration Register 2 */
Chris Packhamef679592021-08-26 14:41:19 +1200880 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG_2,
881 ADT7470_FREQ_MASK,
882 index << ADT7470_FREQ_SHIFT);
883out:
Joshua Scottaa18cc92016-08-08 13:35:45 +1200884 mutex_unlock(&data->lock);
885
Chris Packhamef679592021-08-26 14:41:19 +1200886 return err < 0 ? err : count;
Joshua Scottaa18cc92016-08-08 13:35:45 +1200887}
888
Guenter Roeck42291a52018-12-10 14:02:02 -0800889static ssize_t pwm_max_show(struct device *dev,
890 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700891{
892 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
893 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300894
895 if (IS_ERR(data))
896 return PTR_ERR(data);
897
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700898 return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
899}
900
Guenter Roeck42291a52018-12-10 14:02:02 -0800901static ssize_t pwm_max_store(struct device *dev,
902 struct device_attribute *devattr,
903 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700904{
905 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800906 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800907 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200908 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800909
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100910 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800911 return -EINVAL;
912
Guenter Roeck2a844c12013-01-09 08:09:34 -0800913 temp = clamp_val(temp, 0, 255);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700914
915 mutex_lock(&data->lock);
916 data->pwm_max[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200917 err = regmap_write(data->regmap, ADT7470_REG_PWM_MAX(attr->index),
918 temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700919 mutex_unlock(&data->lock);
920
Chris Packhamef679592021-08-26 14:41:19 +1200921 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700922}
923
Guenter Roeck42291a52018-12-10 14:02:02 -0800924static ssize_t pwm_min_show(struct device *dev,
925 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700926{
927 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
928 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300929
930 if (IS_ERR(data))
931 return PTR_ERR(data);
932
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700933 return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
934}
935
Guenter Roeck42291a52018-12-10 14:02:02 -0800936static ssize_t pwm_min_store(struct device *dev,
937 struct device_attribute *devattr,
938 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700939{
940 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800941 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800942 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200943 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800944
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100945 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800946 return -EINVAL;
947
Guenter Roeck2a844c12013-01-09 08:09:34 -0800948 temp = clamp_val(temp, 0, 255);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700949
950 mutex_lock(&data->lock);
951 data->pwm_min[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +1200952 err = regmap_write(data->regmap, ADT7470_REG_PWM_MIN(attr->index),
953 temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700954 mutex_unlock(&data->lock);
955
Chris Packhamef679592021-08-26 14:41:19 +1200956 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700957}
958
Guenter Roeck42291a52018-12-10 14:02:02 -0800959static ssize_t pwm_tmax_show(struct device *dev,
960 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700961{
962 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
963 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300964
965 if (IS_ERR(data))
966 return PTR_ERR(data);
967
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700968 /* the datasheet says that tmax = tmin + 20C */
969 return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
970}
971
Guenter Roeck42291a52018-12-10 14:02:02 -0800972static ssize_t pwm_tmin_show(struct device *dev,
973 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700974{
975 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
976 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +1300977
978 if (IS_ERR(data))
979 return PTR_ERR(data);
980
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700981 return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
982}
983
Guenter Roeck42291a52018-12-10 14:02:02 -0800984static ssize_t pwm_tmin_store(struct device *dev,
985 struct device_attribute *devattr,
986 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700987{
988 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +0800989 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800990 long temp;
Chris Packhamef679592021-08-26 14:41:19 +1200991 int err;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800992
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +0100993 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -0800994 return -EINVAL;
995
Guenter Roeck64bd7082016-12-03 11:10:34 -0800996 temp = clamp_val(temp, -128000, 127000);
Darrick J. Wong8f8c1fb2009-01-06 14:41:31 -0800997 temp = DIV_ROUND_CLOSEST(temp, 1000);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -0700998
999 mutex_lock(&data->lock);
1000 data->pwm_tmin[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +12001001 err = regmap_write(data->regmap, ADT7470_REG_PWM_TMIN(attr->index),
1002 temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001003 mutex_unlock(&data->lock);
1004
Chris Packhamef679592021-08-26 14:41:19 +12001005 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001006}
1007
Guenter Roeck42291a52018-12-10 14:02:02 -08001008static ssize_t pwm_auto_show(struct device *dev,
1009 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001010{
1011 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1012 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +13001013
1014 if (IS_ERR(data))
1015 return PTR_ERR(data);
1016
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001017 return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
1018}
1019
Guenter Roeck42291a52018-12-10 14:02:02 -08001020static ssize_t pwm_auto_store(struct device *dev,
1021 struct device_attribute *devattr,
1022 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001023{
1024 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +08001025 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001026 int pwm_auto_reg_mask;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -08001027 long temp;
Chris Packhamef679592021-08-26 14:41:19 +12001028 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001029
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001030 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -08001031 return -EINVAL;
1032
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001033 if (attr->index % 2)
1034 pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
1035 else
1036 pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
1037
1038 if (temp != 2 && temp != 1)
1039 return -EINVAL;
1040 temp--;
1041
1042 mutex_lock(&data->lock);
1043 data->pwm_automatic[attr->index] = temp;
Chris Packhamef679592021-08-26 14:41:19 +12001044 err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(attr->index),
1045 pwm_auto_reg_mask,
1046 temp ? pwm_auto_reg_mask : 0);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001047 mutex_unlock(&data->lock);
1048
Chris Packhamef679592021-08-26 14:41:19 +12001049 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001050}
1051
Guenter Roeck42291a52018-12-10 14:02:02 -08001052static ssize_t pwm_auto_temp_show(struct device *dev,
1053 struct device_attribute *devattr, char *buf)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001054{
1055 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1056 struct adt7470_data *data = adt7470_update_device(dev);
Chris Packhamad00a022020-10-20 11:34:22 +13001057 u8 ctrl;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001058
Chris Packhamad00a022020-10-20 11:34:22 +13001059 if (IS_ERR(data))
1060 return PTR_ERR(data);
1061
1062 ctrl = data->pwm_auto_temp[attr->index];
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001063 if (ctrl)
1064 return sprintf(buf, "%d\n", 1 << (ctrl - 1));
1065 else
1066 return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
1067}
1068
1069static int cvt_auto_temp(int input)
1070{
1071 if (input == ADT7470_PWM_ALL_TEMPS)
1072 return 0;
Robert P. J. Dayce9c2f42007-11-06 03:21:42 -05001073 if (input < 1 || !is_power_of_2(input))
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001074 return -EINVAL;
1075 return ilog2(input) + 1;
1076}
1077
Guenter Roeck42291a52018-12-10 14:02:02 -08001078static ssize_t pwm_auto_temp_store(struct device *dev,
1079 struct device_attribute *devattr,
1080 const char *buf, size_t count)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001081{
1082 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Axel Lin30485772014-07-16 23:12:54 +08001083 struct adt7470_data *data = dev_get_drvdata(dev);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001084 int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
Chris Packhamef679592021-08-26 14:41:19 +12001085 unsigned int mask, val;
Darrick J. Wong05a9bd42008-11-12 13:26:57 -08001086 long temp;
Chris Packhamef679592021-08-26 14:41:19 +12001087 int err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001088
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001089 if (kstrtol(buf, 10, &temp))
Darrick J. Wong05a9bd42008-11-12 13:26:57 -08001090 return -EINVAL;
1091
1092 temp = cvt_auto_temp(temp);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001093 if (temp < 0)
1094 return temp;
1095
1096 mutex_lock(&data->lock);
1097 data->pwm_automatic[attr->index] = temp;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001098
1099 if (!(attr->index % 2)) {
Chris Packhamef679592021-08-26 14:41:19 +12001100 mask = 0xF0;
1101 val = (temp << 4) & 0xF0;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001102 } else {
Chris Packhamef679592021-08-26 14:41:19 +12001103 mask = 0x0F;
1104 val = temp & 0x0F;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001105 }
1106
Chris Packhamef679592021-08-26 14:41:19 +12001107 err = regmap_update_bits(data->regmap, pwm_auto_reg, mask, val);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001108 mutex_unlock(&data->lock);
1109
Chris Packhamef679592021-08-26 14:41:19 +12001110 return err < 0 ? err : count;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001111}
1112
Guenter Roeck42291a52018-12-10 14:02:02 -08001113static ssize_t alarm_show(struct device *dev,
1114 struct device_attribute *devattr, char *buf)
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001115{
1116 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1117 struct adt7470_data *data = adt7470_update_device(dev);
1118
Chris Packhamef679592021-08-26 14:41:19 +12001119 if (IS_ERR(data))
1120 return PTR_ERR(data);
1121
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001122 if (data->alarm & attr->index)
1123 return sprintf(buf, "1\n");
1124 else
1125 return sprintf(buf, "0\n");
1126}
1127
Julia Lawall808fc6c2016-12-22 13:04:34 +01001128static DEVICE_ATTR_RW(alarm_mask);
1129static DEVICE_ATTR_RW(num_temp_sensors);
1130static DEVICE_ATTR_RW(auto_update_interval);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001131
Guenter Roeck42291a52018-12-10 14:02:02 -08001132static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
1133static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
1134static SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
1135static SENSOR_DEVICE_ATTR_RW(temp4_max, temp_max, 3);
1136static SENSOR_DEVICE_ATTR_RW(temp5_max, temp_max, 4);
1137static SENSOR_DEVICE_ATTR_RW(temp6_max, temp_max, 5);
1138static SENSOR_DEVICE_ATTR_RW(temp7_max, temp_max, 6);
1139static SENSOR_DEVICE_ATTR_RW(temp8_max, temp_max, 7);
1140static SENSOR_DEVICE_ATTR_RW(temp9_max, temp_max, 8);
1141static SENSOR_DEVICE_ATTR_RW(temp10_max, temp_max, 9);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001142
Guenter Roeck42291a52018-12-10 14:02:02 -08001143static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
1144static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
1145static SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
1146static SENSOR_DEVICE_ATTR_RW(temp4_min, temp_min, 3);
1147static SENSOR_DEVICE_ATTR_RW(temp5_min, temp_min, 4);
1148static SENSOR_DEVICE_ATTR_RW(temp6_min, temp_min, 5);
1149static SENSOR_DEVICE_ATTR_RW(temp7_min, temp_min, 6);
1150static SENSOR_DEVICE_ATTR_RW(temp8_min, temp_min, 7);
1151static SENSOR_DEVICE_ATTR_RW(temp9_min, temp_min, 8);
1152static SENSOR_DEVICE_ATTR_RW(temp10_min, temp_min, 9);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001153
Guenter Roeck42291a52018-12-10 14:02:02 -08001154static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
1155static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
1156static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
1157static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
1158static SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 4);
1159static SENSOR_DEVICE_ATTR_RO(temp6_input, temp, 5);
1160static SENSOR_DEVICE_ATTR_RO(temp7_input, temp, 6);
1161static SENSOR_DEVICE_ATTR_RO(temp8_input, temp, 7);
1162static SENSOR_DEVICE_ATTR_RO(temp9_input, temp, 8);
1163static SENSOR_DEVICE_ATTR_RO(temp10_input, temp, 9);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001164
Guenter Roeck42291a52018-12-10 14:02:02 -08001165static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, ADT7470_R1T_ALARM);
1166static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, ADT7470_R2T_ALARM);
1167static SENSOR_DEVICE_ATTR_RO(temp3_alarm, alarm, ADT7470_R3T_ALARM);
1168static SENSOR_DEVICE_ATTR_RO(temp4_alarm, alarm, ADT7470_R4T_ALARM);
1169static SENSOR_DEVICE_ATTR_RO(temp5_alarm, alarm, ADT7470_R5T_ALARM);
1170static SENSOR_DEVICE_ATTR_RO(temp6_alarm, alarm, ADT7470_R6T_ALARM);
1171static SENSOR_DEVICE_ATTR_RO(temp7_alarm, alarm, ADT7470_R7T_ALARM);
1172static SENSOR_DEVICE_ATTR_RO(temp8_alarm, alarm, ALARM2(ADT7470_R8T_ALARM));
1173static SENSOR_DEVICE_ATTR_RO(temp9_alarm, alarm, ALARM2(ADT7470_R9T_ALARM));
1174static SENSOR_DEVICE_ATTR_RO(temp10_alarm, alarm, ALARM2(ADT7470_R10T_ALARM));
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001175
Guenter Roeck42291a52018-12-10 14:02:02 -08001176static SENSOR_DEVICE_ATTR_RW(fan1_max, fan_max, 0);
1177static SENSOR_DEVICE_ATTR_RW(fan2_max, fan_max, 1);
1178static SENSOR_DEVICE_ATTR_RW(fan3_max, fan_max, 2);
1179static SENSOR_DEVICE_ATTR_RW(fan4_max, fan_max, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001180
Guenter Roeck42291a52018-12-10 14:02:02 -08001181static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
1182static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
1183static SENSOR_DEVICE_ATTR_RW(fan3_min, fan_min, 2);
1184static SENSOR_DEVICE_ATTR_RW(fan4_min, fan_min, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001185
Guenter Roeck42291a52018-12-10 14:02:02 -08001186static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
1187static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
1188static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
1189static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001190
Guenter Roeck42291a52018-12-10 14:02:02 -08001191static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, ALARM2(ADT7470_FAN1_ALARM));
1192static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, ALARM2(ADT7470_FAN2_ALARM));
1193static SENSOR_DEVICE_ATTR_RO(fan3_alarm, alarm, ALARM2(ADT7470_FAN3_ALARM));
1194static SENSOR_DEVICE_ATTR_RO(fan4_alarm, alarm, ALARM2(ADT7470_FAN4_ALARM));
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001195
Guenter Roeck42291a52018-12-10 14:02:02 -08001196static SENSOR_DEVICE_ATTR_RW(force_pwm_max, force_pwm_max, 0);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001197
Guenter Roeck42291a52018-12-10 14:02:02 -08001198static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
1199static SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1);
1200static SENSOR_DEVICE_ATTR_RW(pwm3, pwm, 2);
1201static SENSOR_DEVICE_ATTR_RW(pwm4, pwm, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001202
Julia Lawall808fc6c2016-12-22 13:04:34 +01001203static DEVICE_ATTR_RW(pwm1_freq);
Joshua Scottaa18cc92016-08-08 13:35:45 +12001204
Guenter Roeck42291a52018-12-10 14:02:02 -08001205static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_pwm, pwm_min, 0);
1206static SENSOR_DEVICE_ATTR_RW(pwm2_auto_point1_pwm, pwm_min, 1);
1207static SENSOR_DEVICE_ATTR_RW(pwm3_auto_point1_pwm, pwm_min, 2);
1208static SENSOR_DEVICE_ATTR_RW(pwm4_auto_point1_pwm, pwm_min, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001209
Guenter Roeck42291a52018-12-10 14:02:02 -08001210static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_pwm, pwm_max, 0);
1211static SENSOR_DEVICE_ATTR_RW(pwm2_auto_point2_pwm, pwm_max, 1);
1212static SENSOR_DEVICE_ATTR_RW(pwm3_auto_point2_pwm, pwm_max, 2);
1213static SENSOR_DEVICE_ATTR_RW(pwm4_auto_point2_pwm, pwm_max, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001214
Guenter Roeck42291a52018-12-10 14:02:02 -08001215static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, pwm_tmin, 0);
1216static SENSOR_DEVICE_ATTR_RW(pwm2_auto_point1_temp, pwm_tmin, 1);
1217static SENSOR_DEVICE_ATTR_RW(pwm3_auto_point1_temp, pwm_tmin, 2);
1218static SENSOR_DEVICE_ATTR_RW(pwm4_auto_point1_temp, pwm_tmin, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001219
Guenter Roeck42291a52018-12-10 14:02:02 -08001220static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point2_temp, pwm_tmax, 0);
1221static SENSOR_DEVICE_ATTR_RO(pwm2_auto_point2_temp, pwm_tmax, 1);
1222static SENSOR_DEVICE_ATTR_RO(pwm3_auto_point2_temp, pwm_tmax, 2);
1223static SENSOR_DEVICE_ATTR_RO(pwm4_auto_point2_temp, pwm_tmax, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001224
Guenter Roeck42291a52018-12-10 14:02:02 -08001225static SENSOR_DEVICE_ATTR_RW(pwm1_enable, pwm_auto, 0);
1226static SENSOR_DEVICE_ATTR_RW(pwm2_enable, pwm_auto, 1);
1227static SENSOR_DEVICE_ATTR_RW(pwm3_enable, pwm_auto, 2);
1228static SENSOR_DEVICE_ATTR_RW(pwm4_enable, pwm_auto, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001229
Guenter Roeck42291a52018-12-10 14:02:02 -08001230static SENSOR_DEVICE_ATTR_RW(pwm1_auto_channels_temp, pwm_auto_temp, 0);
1231static SENSOR_DEVICE_ATTR_RW(pwm2_auto_channels_temp, pwm_auto_temp, 1);
1232static SENSOR_DEVICE_ATTR_RW(pwm3_auto_channels_temp, pwm_auto_temp, 2);
1233static SENSOR_DEVICE_ATTR_RW(pwm4_auto_channels_temp, pwm_auto_temp, 3);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001234
Axel Lin30485772014-07-16 23:12:54 +08001235static struct attribute *adt7470_attrs[] = {
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001236 &dev_attr_alarm_mask.attr,
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -08001237 &dev_attr_num_temp_sensors.attr,
Darrick J. Wong89fac112009-01-06 14:41:34 -08001238 &dev_attr_auto_update_interval.attr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001239 &sensor_dev_attr_temp1_max.dev_attr.attr,
1240 &sensor_dev_attr_temp2_max.dev_attr.attr,
1241 &sensor_dev_attr_temp3_max.dev_attr.attr,
1242 &sensor_dev_attr_temp4_max.dev_attr.attr,
1243 &sensor_dev_attr_temp5_max.dev_attr.attr,
1244 &sensor_dev_attr_temp6_max.dev_attr.attr,
1245 &sensor_dev_attr_temp7_max.dev_attr.attr,
1246 &sensor_dev_attr_temp8_max.dev_attr.attr,
1247 &sensor_dev_attr_temp9_max.dev_attr.attr,
1248 &sensor_dev_attr_temp10_max.dev_attr.attr,
1249 &sensor_dev_attr_temp1_min.dev_attr.attr,
1250 &sensor_dev_attr_temp2_min.dev_attr.attr,
1251 &sensor_dev_attr_temp3_min.dev_attr.attr,
1252 &sensor_dev_attr_temp4_min.dev_attr.attr,
1253 &sensor_dev_attr_temp5_min.dev_attr.attr,
1254 &sensor_dev_attr_temp6_min.dev_attr.attr,
1255 &sensor_dev_attr_temp7_min.dev_attr.attr,
1256 &sensor_dev_attr_temp8_min.dev_attr.attr,
1257 &sensor_dev_attr_temp9_min.dev_attr.attr,
1258 &sensor_dev_attr_temp10_min.dev_attr.attr,
1259 &sensor_dev_attr_temp1_input.dev_attr.attr,
1260 &sensor_dev_attr_temp2_input.dev_attr.attr,
1261 &sensor_dev_attr_temp3_input.dev_attr.attr,
1262 &sensor_dev_attr_temp4_input.dev_attr.attr,
1263 &sensor_dev_attr_temp5_input.dev_attr.attr,
1264 &sensor_dev_attr_temp6_input.dev_attr.attr,
1265 &sensor_dev_attr_temp7_input.dev_attr.attr,
1266 &sensor_dev_attr_temp8_input.dev_attr.attr,
1267 &sensor_dev_attr_temp9_input.dev_attr.attr,
1268 &sensor_dev_attr_temp10_input.dev_attr.attr,
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001269 &sensor_dev_attr_temp1_alarm.dev_attr.attr,
1270 &sensor_dev_attr_temp2_alarm.dev_attr.attr,
1271 &sensor_dev_attr_temp3_alarm.dev_attr.attr,
1272 &sensor_dev_attr_temp4_alarm.dev_attr.attr,
1273 &sensor_dev_attr_temp5_alarm.dev_attr.attr,
1274 &sensor_dev_attr_temp6_alarm.dev_attr.attr,
1275 &sensor_dev_attr_temp7_alarm.dev_attr.attr,
1276 &sensor_dev_attr_temp8_alarm.dev_attr.attr,
1277 &sensor_dev_attr_temp9_alarm.dev_attr.attr,
1278 &sensor_dev_attr_temp10_alarm.dev_attr.attr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001279 &sensor_dev_attr_fan1_max.dev_attr.attr,
1280 &sensor_dev_attr_fan2_max.dev_attr.attr,
1281 &sensor_dev_attr_fan3_max.dev_attr.attr,
1282 &sensor_dev_attr_fan4_max.dev_attr.attr,
1283 &sensor_dev_attr_fan1_min.dev_attr.attr,
1284 &sensor_dev_attr_fan2_min.dev_attr.attr,
1285 &sensor_dev_attr_fan3_min.dev_attr.attr,
1286 &sensor_dev_attr_fan4_min.dev_attr.attr,
1287 &sensor_dev_attr_fan1_input.dev_attr.attr,
1288 &sensor_dev_attr_fan2_input.dev_attr.attr,
1289 &sensor_dev_attr_fan3_input.dev_attr.attr,
1290 &sensor_dev_attr_fan4_input.dev_attr.attr,
Darrick J. Wongfe03f282007-12-19 14:11:25 -08001291 &sensor_dev_attr_fan1_alarm.dev_attr.attr,
1292 &sensor_dev_attr_fan2_alarm.dev_attr.attr,
1293 &sensor_dev_attr_fan3_alarm.dev_attr.attr,
1294 &sensor_dev_attr_fan4_alarm.dev_attr.attr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001295 &sensor_dev_attr_force_pwm_max.dev_attr.attr,
1296 &sensor_dev_attr_pwm1.dev_attr.attr,
Joshua Scottaa18cc92016-08-08 13:35:45 +12001297 &dev_attr_pwm1_freq.attr,
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001298 &sensor_dev_attr_pwm2.dev_attr.attr,
1299 &sensor_dev_attr_pwm3.dev_attr.attr,
1300 &sensor_dev_attr_pwm4.dev_attr.attr,
1301 &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
1302 &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
1303 &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
1304 &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
1305 &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
1306 &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
1307 &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
1308 &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
1309 &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
1310 &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
1311 &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
1312 &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
1313 &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
1314 &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
1315 &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
1316 &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
1317 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
1318 &sensor_dev_attr_pwm2_enable.dev_attr.attr,
1319 &sensor_dev_attr_pwm3_enable.dev_attr.attr,
1320 &sensor_dev_attr_pwm4_enable.dev_attr.attr,
1321 &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
1322 &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
1323 &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
1324 &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
1325 NULL
1326};
1327
Axel Lin30485772014-07-16 23:12:54 +08001328ATTRIBUTE_GROUPS(adt7470);
1329
Jean Delvare008f1ca2008-07-16 19:30:10 +02001330/* Return 0 if detection is successful, -ENODEV otherwise */
Jean Delvare310ec792009-12-14 21:17:23 +01001331static int adt7470_detect(struct i2c_client *client,
Jean Delvare008f1ca2008-07-16 19:30:10 +02001332 struct i2c_board_info *info)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001333{
Jean Delvare008f1ca2008-07-16 19:30:10 +02001334 struct i2c_adapter *adapter = client->adapter;
Jean Delvare52df6442009-12-09 20:35:57 +01001335 int vendor, device, revision;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001336
1337 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Jean Delvare008f1ca2008-07-16 19:30:10 +02001338 return -ENODEV;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001339
Jean Delvare52df6442009-12-09 20:35:57 +01001340 vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
1341 if (vendor != ADT7470_VENDOR)
1342 return -ENODEV;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001343
Jean Delvare52df6442009-12-09 20:35:57 +01001344 device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
1345 if (device != ADT7470_DEVICE)
1346 return -ENODEV;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001347
Jean Delvare52df6442009-12-09 20:35:57 +01001348 revision = i2c_smbus_read_byte_data(client, ADT7470_REG_REVISION);
1349 if (revision != ADT7470_REVISION)
1350 return -ENODEV;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001351
Chris Packham23bd0222021-08-26 14:41:18 +12001352 strscpy(info->type, "adt7470", I2C_NAME_SIZE);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001353
Jean Delvare008f1ca2008-07-16 19:30:10 +02001354 return 0;
1355}
1356
Chris Packhamef679592021-08-26 14:41:19 +12001357static const struct regmap_config adt7470_regmap_config = {
1358 .reg_bits = 8,
1359 .val_bits = 8,
1360 .use_single_read = true,
1361 .use_single_write = true,
1362};
Axel Lin9027d932014-07-16 23:12:05 +08001363
Stephen Kitt67487032020-08-13 18:02:22 +02001364static int adt7470_probe(struct i2c_client *client)
Jean Delvare008f1ca2008-07-16 19:30:10 +02001365{
Axel Lin30485772014-07-16 23:12:54 +08001366 struct device *dev = &client->dev;
Jean Delvare008f1ca2008-07-16 19:30:10 +02001367 struct adt7470_data *data;
Axel Lin30485772014-07-16 23:12:54 +08001368 struct device *hwmon_dev;
Chris Packhamef679592021-08-26 14:41:19 +12001369 int err;
Jean Delvare008f1ca2008-07-16 19:30:10 +02001370
Axel Lin30485772014-07-16 23:12:54 +08001371 data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL);
Guenter Roeck9cc7dcc2012-06-02 09:58:01 -07001372 if (!data)
1373 return -ENOMEM;
Jean Delvare008f1ca2008-07-16 19:30:10 +02001374
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -08001375 data->num_temp_sensors = -1;
Darrick J. Wong89fac112009-01-06 14:41:34 -08001376 data->auto_update_interval = AUTO_UPDATE_INTERVAL;
Chris Packhamef679592021-08-26 14:41:19 +12001377 data->regmap = devm_regmap_init_i2c(client, &adt7470_regmap_config);
1378 if (IS_ERR(data->regmap))
1379 return PTR_ERR(data->regmap);
Darrick J. Wong2f22d5d2009-01-06 14:41:33 -08001380
Jean Delvare008f1ca2008-07-16 19:30:10 +02001381 i2c_set_clientdata(client, data);
1382 mutex_init(&data->lock);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001383
1384 dev_info(&client->dev, "%s chip found\n", client->name);
1385
1386 /* Initialize the ADT7470 chip */
Chris Packhamef679592021-08-26 14:41:19 +12001387 err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
1388 ADT7470_STRT_MASK | ADT7470_TEST_MASK,
1389 ADT7470_STRT_MASK | ADT7470_TEST_MASK);
1390 if (err < 0)
1391 return err;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001392
1393 /* Register sysfs hooks */
Axel Lin30485772014-07-16 23:12:54 +08001394 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
1395 data,
1396 adt7470_groups);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001397
Axel Lin30485772014-07-16 23:12:54 +08001398 if (IS_ERR(hwmon_dev))
1399 return PTR_ERR(hwmon_dev);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001400
Kees Cookf1701682013-07-03 15:04:58 -07001401 data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
Axel Lin30485772014-07-16 23:12:54 +08001402 dev_name(hwmon_dev));
Chris Packham23bd0222021-08-26 14:41:18 +12001403 if (IS_ERR(data->auto_update))
Axel Lin30485772014-07-16 23:12:54 +08001404 return PTR_ERR(data->auto_update);
Darrick J. Wong89fac112009-01-06 14:41:34 -08001405
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001406 return 0;
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001407}
1408
Jean Delvare008f1ca2008-07-16 19:30:10 +02001409static int adt7470_remove(struct i2c_client *client)
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001410{
1411 struct adt7470_data *data = i2c_get_clientdata(client);
1412
Darrick J. Wong89fac112009-01-06 14:41:34 -08001413 kthread_stop(data->auto_update);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001414 return 0;
1415}
1416
Axel Lin9027d932014-07-16 23:12:05 +08001417static const struct i2c_device_id adt7470_id[] = {
1418 { "adt7470", 0 },
1419 { }
1420};
1421MODULE_DEVICE_TABLE(i2c, adt7470_id);
1422
1423static struct i2c_driver adt7470_driver = {
1424 .class = I2C_CLASS_HWMON,
1425 .driver = {
1426 .name = "adt7470",
1427 },
Stephen Kitt67487032020-08-13 18:02:22 +02001428 .probe_new = adt7470_probe,
Axel Lin9027d932014-07-16 23:12:05 +08001429 .remove = adt7470_remove,
1430 .id_table = adt7470_id,
1431 .detect = adt7470_detect,
1432 .address_list = normal_i2c,
1433};
1434
Axel Linf0967ee2012-01-20 15:38:18 +08001435module_i2c_driver(adt7470_driver);
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001436
Darrick J. Wong5407e0512013-08-26 15:42:27 -07001437MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
Darrick J. Wong6f9703d2007-07-31 11:06:52 -07001438MODULE_DESCRIPTION("ADT7470 driver");
1439MODULE_LICENSE("GPL");