summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/nct6775.h
blob: 296eff99d00383f1246e806e732166efcbfe208a (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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __HWMON_NCT6775_H__
#define __HWMON_NCT6775_H__

#include <linux/types.h>

enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
	     nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 };
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };

#define NUM_TEMP	12	/* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP_FIXED	6	/* Max number of fixed temp attribute sets */
#define NUM_TSI_TEMP	8	/* Max number of TSI temp register pairs */

#define NUM_REG_ALARM	7	/* Max number of alarm registers */
#define NUM_REG_BEEP	5	/* Max number of beep registers */

#define NUM_FAN		7
#define NUM_IN		18

struct nct6775_data {
	int addr;	/* IO base of hw monitor block */
	int sioreg;	/* SIO register address */
	enum kinds kind;
	const char *name;

	const struct attribute_group *groups[7];
	u8 num_groups;

	u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
				    * 3=temp_crit, 4=temp_lcrit
				    */
	u8 temp_src[NUM_TEMP];
	u16 reg_temp_config[NUM_TEMP];
	const char * const *temp_label;
	u32 temp_mask;
	u32 virt_temp_mask;

	u16 REG_CONFIG;
	u16 REG_VBAT;
	u16 REG_DIODE;
	u8 DIODE_MASK;

	const s8 *ALARM_BITS;
	const s8 *BEEP_BITS;

	const u16 *REG_VIN;
	const u16 *REG_IN_MINMAX[2];

	const u16 *REG_TARGET;
	const u16 *REG_FAN;
	const u16 *REG_FAN_MODE;
	const u16 *REG_FAN_MIN;
	const u16 *REG_FAN_PULSES;
	const u16 *FAN_PULSE_SHIFT;
	const u16 *REG_FAN_TIME[3];

	const u16 *REG_TOLERANCE_H;

	const u8 *REG_PWM_MODE;
	const u8 *PWM_MODE_MASK;

	const u16 *REG_PWM[7];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
				 * [3]=pwm_max, [4]=pwm_step,
				 * [5]=weight_duty_step, [6]=weight_duty_base
				 */
	const u16 *REG_PWM_READ;

	const u16 *REG_CRITICAL_PWM_ENABLE;
	u8 CRITICAL_PWM_ENABLE_MASK;
	const u16 *REG_CRITICAL_PWM;

	const u16 *REG_AUTO_TEMP;
	const u16 *REG_AUTO_PWM;

	const u16 *REG_CRITICAL_TEMP;
	const u16 *REG_CRITICAL_TEMP_TOLERANCE;

	const u16 *REG_TEMP_SOURCE;	/* temp register sources */
	const u16 *REG_TEMP_SEL;
	const u16 *REG_WEIGHT_TEMP_SEL;
	const u16 *REG_WEIGHT_TEMP[3];	/* 0=base, 1=tolerance, 2=step */

	const u16 *REG_TEMP_OFFSET;

	const u16 *REG_ALARM;
	const u16 *REG_BEEP;

	const u16 *REG_TSI_TEMP;

	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);

	struct mutex update_lock;
	bool valid;		/* true if following fields are valid */
	unsigned long last_updated;	/* In jiffies */

	/* Register values */
	u8 bank;		/* current register bank */
	u8 in_num;		/* number of in inputs we have */
	u8 in[NUM_IN][3];	/* [0]=in, [1]=in_max, [2]=in_min */
	const u16 *scale_in;	/* internal scaling factors */
	unsigned int rpm[NUM_FAN];
	u16 fan_min[NUM_FAN];
	u8 fan_pulses[NUM_FAN];
	u8 fan_div[NUM_FAN];
	u8 has_pwm;
	u8 has_fan;		/* some fan inputs can be disabled */
	u8 has_fan_min;		/* some fans don't have min register */
	bool has_fan_div;

	u8 num_temp_alarms;	/* 2, 3, or 6 */
	u8 num_temp_beeps;	/* 2, 3, or 6 */
	u8 temp_fixed_num;	/* 3 or 6 */
	u8 temp_type[NUM_TEMP_FIXED];
	s8 temp_offset[NUM_TEMP_FIXED];
	s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
				* 3=temp_crit, 4=temp_lcrit
				*/
	s16 tsi_temp[NUM_TSI_TEMP];
	u64 alarms;
	u64 beeps;

	u8 pwm_num;	/* number of pwm */
	u8 pwm_mode[NUM_FAN];	/* 0->DC variable voltage,
				 * 1->PWM variable duty cycle
				 */
	enum pwm_enable pwm_enable[NUM_FAN];
			/* 0->off
			 * 1->manual
			 * 2->thermal cruise mode (also called SmartFan I)
			 * 3->fan speed cruise mode
			 * 4->SmartFan III
			 * 5->enhanced variable thermal cruise (SmartFan IV)
			 */
	u8 pwm[7][NUM_FAN];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
				 * [3]=pwm_max, [4]=pwm_step,
				 * [5]=weight_duty_step, [6]=weight_duty_base
				 */

	u8 target_temp[NUM_FAN];
	u8 target_temp_mask;
	u32 target_speed[NUM_FAN];
	u32 target_speed_tolerance[NUM_FAN];
	u8 speed_tolerance_limit;

	u8 temp_tolerance[2][NUM_FAN];
	u8 tolerance_mask;

	u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */

	/* Automatic fan speed control registers */
	int auto_pwm_num;
	u8 auto_pwm[NUM_FAN][7];
	u8 auto_temp[NUM_FAN][7];
	u8 pwm_temp_sel[NUM_FAN];
	u8 pwm_weight_temp_sel[NUM_FAN];
	u8 weight_temp[3][NUM_FAN];	/* 0->temp_step, 1->temp_step_tol,
					 * 2->temp_base
					 */

	u8 vid;
	u8 vrm;

	bool have_vid;

	u16 have_temp;
	u16 have_temp_fixed;
	u16 have_tsi_temp;
	u32 have_in;

	/* Remember extra register values over suspend/resume */
	u8 vbat;
	u8 fandiv1;
	u8 fandiv2;
	u8 sio_reg_enable;

	struct regmap *regmap;
	bool read_only;

	/* driver-specific (platform, i2c) initialization hook and data */
	int (*driver_init)(struct nct6775_data *data);
	void *driver_data;
};

static inline int nct6775_read_value(struct nct6775_data *data, u16 reg, u16 *value)
{
	unsigned int tmp;
	int ret = regmap_read(data->regmap, reg, &tmp);

	if (!ret)
		*value = tmp;
	return ret;
}

static inline int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
{
	return regmap_write(data->regmap, reg, value);
}

struct nct6775_data *nct6775_update_device(struct device *dev);

bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg);
int nct6775_probe(struct device *dev, struct nct6775_data *data,
		  const struct regmap_config *regmapcfg);

ssize_t nct6775_show_alarm(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t nct6775_show_beep(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t nct6775_store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
			   size_t count);

static inline int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
{
	if (!nct6775_reg_is_word_sized(data, reg))
		value >>= 8;
	return nct6775_write_value(data, reg, value);
}

static inline umode_t nct6775_attr_mode(struct nct6775_data *data, struct attribute *attr)
{
	return data->read_only ? (attr->mode & ~0222) : attr->mode;
}

static inline int
nct6775_add_attr_group(struct nct6775_data *data, const struct attribute_group *group)
{
	/* Need to leave a NULL terminator at the end of data->groups */
	if (data->num_groups == ARRAY_SIZE(data->groups) - 1)
		return -ENOBUFS;

	data->groups[data->num_groups++] = group;
	return 0;
}

#define NCT6775_REG_BANK	0x4E
#define NCT6775_REG_CONFIG	0x40

#define NCT6775_REG_FANDIV1		0x506
#define NCT6775_REG_FANDIV2		0x507

#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE	0x28

/*
 * ALARM_BITS and BEEP_BITS store bit-index for the mask of the registers
 * loaded into data->alarm and data->beep.
 *
 * Every input register (IN/TEMP/FAN) must have a corresponding
 *   ALARM/BEEP bit at the same index BITS[BASE + index]
 * Set value to -1 to disable the visibility of that '*_alarm' attribute and
 * to pad the bits until the next BASE
 *
 * Beep has an additional GLOBAL_BEEP_ENABLE bit
 */
#define VIN_ALARM_BASE		 0
#define FAN_ALARM_BASE		24
#define TEMP_ALARM_BASE		36
#define INTRUSION_ALARM_BASE	48
#define BEEP_ENABLE_BASE	50

#define NUM_ALARM_BITS		(INTRUSION_ALARM_BASE + 4)
#define NUM_BEEP_BITS		(BEEP_ENABLE_BASE + 1)

/*
 * Not currently used:
 * REG_MAN_ID has the value 0x5ca3 for all supported chips.
 * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
 * REG_MAN_ID is at port 0x4f
 * REG_CHIP_ID is at port 0x58
 */

#endif /* __HWMON_NCT6775_H__ */