Blame view

drivers/hwmon/max6639.c 16.8 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
2
3
4
5
6
7
8
9
10
  /*
   * max6639.c - Support for Maxim MAX6639
   *
   * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller
   *
   * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
   *
   * based on the initial MAX6639 support from semptian.net
   * by He Changqing <hechangqing@semptian.com>
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
11
12
13
14
15
16
17
18
19
20
21
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  #include <linux/err.h>
  #include <linux/mutex.h>
0c9fe1614   Wolfram Sang   hwmon: (max6639) ...
22
  #include <linux/platform_data/max6639.h>
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
23
24
  
  /* Addresses to scan */
7edc8cc19   Axel Lin   hwmon: (max6639) ...
25
  static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
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
  
  /* The MAX6639 registers, valid channel numbers: 0, 1 */
  #define MAX6639_REG_TEMP(ch)			(0x00 + (ch))
  #define MAX6639_REG_STATUS			0x02
  #define MAX6639_REG_OUTPUT_MASK			0x03
  #define MAX6639_REG_GCONFIG			0x04
  #define MAX6639_REG_TEMP_EXT(ch)		(0x05 + (ch))
  #define MAX6639_REG_ALERT_LIMIT(ch)		(0x08 + (ch))
  #define MAX6639_REG_OT_LIMIT(ch)		(0x0A + (ch))
  #define MAX6639_REG_THERM_LIMIT(ch)		(0x0C + (ch))
  #define MAX6639_REG_FAN_CONFIG1(ch)		(0x10 + (ch) * 4)
  #define MAX6639_REG_FAN_CONFIG2a(ch)		(0x11 + (ch) * 4)
  #define MAX6639_REG_FAN_CONFIG2b(ch)		(0x12 + (ch) * 4)
  #define MAX6639_REG_FAN_CONFIG3(ch)		(0x13 + (ch) * 4)
  #define MAX6639_REG_FAN_CNT(ch)			(0x20 + (ch))
  #define MAX6639_REG_TARGET_CNT(ch)		(0x22 + (ch))
  #define MAX6639_REG_FAN_PPR(ch)			(0x24 + (ch))
  #define MAX6639_REG_TARGTDUTY(ch)		(0x26 + (ch))
  #define MAX6639_REG_FAN_START_TEMP(ch)		(0x28 + (ch))
  #define MAX6639_REG_DEVID			0x3D
  #define MAX6639_REG_MANUID			0x3E
  #define MAX6639_REG_DEVREV			0x3F
  
  /* Register bits */
  #define MAX6639_GCONFIG_STANDBY			0x80
  #define MAX6639_GCONFIG_POR			0x40
  #define MAX6639_GCONFIG_DISABLE_TIMEOUT		0x20
  #define MAX6639_GCONFIG_CH2_LOCAL		0x10
177f3b920   stigge@antcom.de   hwmon: (max6639) ...
54
  #define MAX6639_GCONFIG_PWM_FREQ_HI		0x08
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
55
56
  
  #define MAX6639_FAN_CONFIG1_PWM			0x80
177f3b920   stigge@antcom.de   hwmon: (max6639) ...
57
  #define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED	0x40
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
58
  static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
b63d97a36   Chris D Schimp   hwmon: (max6639) ...
59
60
  #define FAN_FROM_REG(val, rpm_range)	((val) == 0 || (val) == 255 ? \
  				0 : (rpm_ranges[rpm_range] * 30) / (val))
2a844c148   Guenter Roeck   hwmon: Replace SE...
61
  #define TEMP_LIMIT_TO_REG(val)	clamp_val((val) / 1000, 0, 255)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
62
63
64
65
66
  
  /*
   * Client data (each client gets its own)
   */
  struct max6639_data {
7981c5846   Guenter Roeck   hwmon: (max6639) ...
67
  	struct i2c_client *client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	struct mutex update_lock;
  	char valid;		/* !=0 if following fields are valid */
  	unsigned long last_updated;	/* In jiffies */
  
  	/* Register values sampled regularly */
  	u16 temp[2];		/* Temperature, in 1/8 C, 0..255 C */
  	bool temp_fault[2];	/* Detected temperature diode failure */
  	u8 fan[2];		/* Register value: TACH count for fans >=30 */
  	u8 status;		/* Detected channel alarms and fan failures */
  
  	/* Register values only written to */
  	u8 pwm[2];		/* Register value: Duty cycle 0..120 */
  	u8 temp_therm[2];	/* THERM Temperature, 0..255 C (->_max) */
  	u8 temp_alert[2];	/* ALERT Temperature, 0..255 C (->_crit) */
  	u8 temp_ot[2];		/* OT Temperature, 0..255 C (->_emergency) */
  
  	/* Register values initialized only once */
  	u8 ppr;			/* Pulses per rotation 0..3 for 1..4 ppr */
  	u8 rpm_range;		/* Index in above rpm_ranges table */
  };
  
  static struct max6639_data *max6639_update_device(struct device *dev)
  {
7981c5846   Guenter Roeck   hwmon: (max6639) ...
91
92
  	struct max6639_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
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
  	struct max6639_data *ret = data;
  	int i;
  	int status_reg;
  
  	mutex_lock(&data->update_lock);
  
  	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
  		int res;
  
  		dev_dbg(&client->dev, "Starting max6639 update
  ");
  
  		status_reg = i2c_smbus_read_byte_data(client,
  						      MAX6639_REG_STATUS);
  		if (status_reg < 0) {
  			ret = ERR_PTR(status_reg);
  			goto abort;
  		}
  
  		data->status = status_reg;
  
  		for (i = 0; i < 2; i++) {
  			res = i2c_smbus_read_byte_data(client,
  					MAX6639_REG_FAN_CNT(i));
  			if (res < 0) {
  				ret = ERR_PTR(res);
  				goto abort;
  			}
  			data->fan[i] = res;
  
  			res = i2c_smbus_read_byte_data(client,
  					MAX6639_REG_TEMP_EXT(i));
  			if (res < 0) {
  				ret = ERR_PTR(res);
  				goto abort;
  			}
  			data->temp[i] = res >> 5;
  			data->temp_fault[i] = res & 0x01;
  
  			res = i2c_smbus_read_byte_data(client,
  					MAX6639_REG_TEMP(i));
  			if (res < 0) {
  				ret = ERR_PTR(res);
  				goto abort;
  			}
  			data->temp[i] |= res << 3;
  		}
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
  abort:
  	mutex_unlock(&data->update_lock);
  
  	return ret;
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
149
  static ssize_t temp_input_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
150
151
152
153
154
155
156
157
158
159
160
161
162
  			       struct device_attribute *dev_attr, char *buf)
  {
  	long temp;
  	struct max6639_data *data = max6639_update_device(dev);
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	temp = data->temp[attr->index] * 125;
  	return sprintf(buf, "%ld
  ", temp);
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
163
  static ssize_t temp_fault_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
164
165
166
167
168
169
170
171
172
173
174
  			       struct device_attribute *dev_attr, char *buf)
  {
  	struct max6639_data *data = max6639_update_device(dev);
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	return sprintf(buf, "%d
  ", data->temp_fault[attr->index]);
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
175
  static ssize_t temp_max_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
176
177
  			     struct device_attribute *dev_attr, char *buf)
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
178
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
179
  	struct max6639_data *data = dev_get_drvdata(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
180
181
182
183
  
  	return sprintf(buf, "%d
  ", (data->temp_therm[attr->index] * 1000));
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
184
185
186
  static ssize_t temp_max_store(struct device *dev,
  			      struct device_attribute *dev_attr,
  			      const char *buf, size_t count)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
187
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
188
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
189
190
  	struct max6639_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
191
192
  	unsigned long val;
  	int res;
179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
193
  	res = kstrtoul(buf, 10, &val);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
194
195
196
197
198
199
200
201
202
203
204
  	if (res)
  		return res;
  
  	mutex_lock(&data->update_lock);
  	data->temp_therm[attr->index] = TEMP_LIMIT_TO_REG(val);
  	i2c_smbus_write_byte_data(client,
  				  MAX6639_REG_THERM_LIMIT(attr->index),
  				  data->temp_therm[attr->index]);
  	mutex_unlock(&data->update_lock);
  	return count;
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
205
  static ssize_t temp_crit_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
206
207
  			      struct device_attribute *dev_attr, char *buf)
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
208
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
209
  	struct max6639_data *data = dev_get_drvdata(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
210
211
212
213
  
  	return sprintf(buf, "%d
  ", (data->temp_alert[attr->index] * 1000));
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
214
215
216
  static ssize_t temp_crit_store(struct device *dev,
  			       struct device_attribute *dev_attr,
  			       const char *buf, size_t count)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
217
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
218
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
219
220
  	struct max6639_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
221
222
  	unsigned long val;
  	int res;
179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
223
  	res = kstrtoul(buf, 10, &val);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
224
225
226
227
228
229
230
231
232
233
234
  	if (res)
  		return res;
  
  	mutex_lock(&data->update_lock);
  	data->temp_alert[attr->index] = TEMP_LIMIT_TO_REG(val);
  	i2c_smbus_write_byte_data(client,
  				  MAX6639_REG_ALERT_LIMIT(attr->index),
  				  data->temp_alert[attr->index]);
  	mutex_unlock(&data->update_lock);
  	return count;
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
235
  static ssize_t temp_emergency_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
236
237
238
  				   struct device_attribute *dev_attr,
  				   char *buf)
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
239
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
240
  	struct max6639_data *data = dev_get_drvdata(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
241
242
243
244
  
  	return sprintf(buf, "%d
  ", (data->temp_ot[attr->index] * 1000));
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
245
246
247
  static ssize_t temp_emergency_store(struct device *dev,
  				    struct device_attribute *dev_attr,
  				    const char *buf, size_t count)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
248
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
249
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
250
251
  	struct max6639_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
252
253
  	unsigned long val;
  	int res;
179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
254
  	res = kstrtoul(buf, 10, &val);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
255
256
257
258
259
260
261
262
263
264
265
  	if (res)
  		return res;
  
  	mutex_lock(&data->update_lock);
  	data->temp_ot[attr->index] = TEMP_LIMIT_TO_REG(val);
  	i2c_smbus_write_byte_data(client,
  				  MAX6639_REG_OT_LIMIT(attr->index),
  				  data->temp_ot[attr->index]);
  	mutex_unlock(&data->update_lock);
  	return count;
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
266
267
  static ssize_t pwm_show(struct device *dev, struct device_attribute *dev_attr,
  			char *buf)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
268
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
269
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
270
  	struct max6639_data *data = dev_get_drvdata(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
271
272
273
274
  
  	return sprintf(buf, "%d
  ", data->pwm[attr->index] * 255 / 120);
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
275
276
277
  static ssize_t pwm_store(struct device *dev,
  			 struct device_attribute *dev_attr, const char *buf,
  			 size_t count)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
278
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
279
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
7981c5846   Guenter Roeck   hwmon: (max6639) ...
280
281
  	struct max6639_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
282
283
  	unsigned long val;
  	int res;
179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
284
  	res = kstrtoul(buf, 10, &val);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
285
286
  	if (res)
  		return res;
2a844c148   Guenter Roeck   hwmon: Replace SE...
287
  	val = clamp_val(val, 0, 255);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
288
289
290
291
292
293
294
295
296
  
  	mutex_lock(&data->update_lock);
  	data->pwm[attr->index] = (u8)(val * 120 / 255);
  	i2c_smbus_write_byte_data(client,
  				  MAX6639_REG_TARGTDUTY(attr->index),
  				  data->pwm[attr->index]);
  	mutex_unlock(&data->update_lock);
  	return count;
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
297
  static ssize_t fan_input_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
298
299
300
301
302
303
304
305
306
307
  			      struct device_attribute *dev_attr, char *buf)
  {
  	struct max6639_data *data = max6639_update_device(dev);
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->fan[attr->index],
b63d97a36   Chris D Schimp   hwmon: (max6639) ...
308
  		       data->rpm_range));
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
309
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
310
  static ssize_t alarm_show(struct device *dev,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
311
312
313
314
315
316
317
318
319
320
321
  			  struct device_attribute *dev_attr, char *buf)
  {
  	struct max6639_data *data = max6639_update_device(dev);
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	return sprintf(buf, "%d
  ", !!(data->status & (1 << attr->index)));
  }
0a0ab22a7   Guenter Roeck   hwmon: (max6639) ...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
  static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_input, 1);
  static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
  static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
  static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
  static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
  static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp_crit, 0);
  static SENSOR_DEVICE_ATTR_RW(temp2_crit, temp_crit, 1);
  static SENSOR_DEVICE_ATTR_RW(temp1_emergency, temp_emergency, 0);
  static SENSOR_DEVICE_ATTR_RW(temp2_emergency, temp_emergency, 1);
  static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
  static SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1);
  static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0);
  static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1);
  static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, 1);
  static SENSOR_DEVICE_ATTR_RO(fan2_fault, alarm, 0);
  static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 3);
  static SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, 2);
  static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 7);
  static SENSOR_DEVICE_ATTR_RO(temp2_crit_alarm, alarm, 6);
  static SENSOR_DEVICE_ATTR_RO(temp1_emergency_alarm, alarm, 5);
  static SENSOR_DEVICE_ATTR_RO(temp2_emergency_alarm, alarm, 4);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
344

7981c5846   Guenter Roeck   hwmon: (max6639) ...
345
  static struct attribute *max6639_attrs[] = {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp2_input.dev_attr.attr,
  	&sensor_dev_attr_temp1_fault.dev_attr.attr,
  	&sensor_dev_attr_temp2_fault.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp2_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_crit.dev_attr.attr,
  	&sensor_dev_attr_temp2_crit.dev_attr.attr,
  	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
  	&sensor_dev_attr_temp2_emergency.dev_attr.attr,
  	&sensor_dev_attr_pwm1.dev_attr.attr,
  	&sensor_dev_attr_pwm2.dev_attr.attr,
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_fault.dev_attr.attr,
  	&sensor_dev_attr_fan2_fault.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
  	NULL
  };
7981c5846   Guenter Roeck   hwmon: (max6639) ...
370
  ATTRIBUTE_GROUPS(max6639);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  
  /*
   *  returns respective index in rpm_ranges table
   *  1 by default on invalid range
   */
  static int rpm_range_to_reg(int range)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
  		if (rpm_ranges[i] == range)
  			return i;
  	}
  
  	return 1; /* default: 4000 RPM */
  }
7981c5846   Guenter Roeck   hwmon: (max6639) ...
387
388
  static int max6639_init_client(struct i2c_client *client,
  			       struct max6639_data *data)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
389
  {
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
390
  	struct max6639_platform_data *max6639_info =
a8b3a3a53   Jingoo Han   hwmon: use dev_ge...
391
  		dev_get_platdata(&client->dev);
2f2da1ac0   Chris D Schimp   hwmon: (max6639) ...
392
  	int i;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
393
  	int rpm_range = 1; /* default: 4000 RPM */
2f2da1ac0   Chris D Schimp   hwmon: (max6639) ...
394
  	int err;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
395

177f3b920   stigge@antcom.de   hwmon: (max6639) ...
396
  	/* Reset chip to default values, see below for GCONFIG setup */
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
397
398
399
400
401
402
403
404
405
406
407
408
  	err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
  				  MAX6639_GCONFIG_POR);
  	if (err)
  		goto exit;
  
  	/* Fans pulse per revolution is 2 by default */
  	if (max6639_info && max6639_info->ppr > 0 &&
  			max6639_info->ppr < 5)
  		data->ppr = max6639_info->ppr;
  	else
  		data->ppr = 2;
  	data->ppr -= 1;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
409
410
411
412
413
414
  
  	if (max6639_info)
  		rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
  	data->rpm_range = rpm_range;
  
  	for (i = 0; i < 2; i++) {
2f2da1ac0   Chris D Schimp   hwmon: (max6639) ...
415
416
417
418
419
420
  		/* Set Fan pulse per revolution */
  		err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_FAN_PPR(i),
  				data->ppr << 6);
  		if (err)
  			goto exit;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  		/* Fans config PWM, RPM */
  		err = i2c_smbus_write_byte_data(client,
  			MAX6639_REG_FAN_CONFIG1(i),
  			MAX6639_FAN_CONFIG1_PWM | rpm_range);
  		if (err)
  			goto exit;
  
  		/* Fans PWM polarity high by default */
  		if (max6639_info && max6639_info->pwm_polarity == 0)
  			err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_FAN_CONFIG2a(i), 0x00);
  		else
  			err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_FAN_CONFIG2a(i), 0x02);
  		if (err)
  			goto exit;
177f3b920   stigge@antcom.de   hwmon: (max6639) ...
437
438
439
440
441
442
443
444
445
  		/*
  		 * /THERM full speed enable,
  		 * PWM frequency 25kHz, see also GCONFIG below
  		 */
  		err = i2c_smbus_write_byte_data(client,
  			MAX6639_REG_FAN_CONFIG3(i),
  			MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
  		if (err)
  			goto exit;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  		/* Max. temp. 80C/90C/100C */
  		data->temp_therm[i] = 80;
  		data->temp_alert[i] = 90;
  		data->temp_ot[i] = 100;
  		err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_THERM_LIMIT(i),
  				data->temp_therm[i]);
  		if (err)
  			goto exit;
  		err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_ALERT_LIMIT(i),
  				data->temp_alert[i]);
  		if (err)
  			goto exit;
  		err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_OT_LIMIT(i), data->temp_ot[i]);
  		if (err)
  			goto exit;
  
  		/* PWM 120/120 (i.e. 100%) */
  		data->pwm[i] = 120;
  		err = i2c_smbus_write_byte_data(client,
  				MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
  		if (err)
  			goto exit;
  	}
  	/* Start monitoring */
  	err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
177f3b920   stigge@antcom.de   hwmon: (max6639) ...
474
475
  		MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
  		MAX6639_GCONFIG_PWM_FREQ_HI);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  exit:
  	return err;
  }
  
  /* Return 0 if detection is successful, -ENODEV otherwise */
  static int max6639_detect(struct i2c_client *client,
  			  struct i2c_board_info *info)
  {
  	struct i2c_adapter *adapter = client->adapter;
  	int dev_id, manu_id;
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  		return -ENODEV;
  
  	/* Actual detection via device and manufacturer ID */
  	dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
  	manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
  	if (dev_id != 0x58 || manu_id != 0x4D)
  		return -ENODEV;
  
  	strlcpy(info->type, "max6639", I2C_NAME_SIZE);
  
  	return 0;
  }
674870385   Stephen Kitt   hwmon: use simple...
500
  static int max6639_probe(struct i2c_client *client)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
501
  {
c1ea0a043   Guenter Roeck   hwmon: (max6639) ...
502
  	struct device *dev = &client->dev;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
503
  	struct max6639_data *data;
7981c5846   Guenter Roeck   hwmon: (max6639) ...
504
  	struct device *hwmon_dev;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
505
  	int err;
c1ea0a043   Guenter Roeck   hwmon: (max6639) ...
506
  	data = devm_kzalloc(dev, sizeof(struct max6639_data), GFP_KERNEL);
b07405fbc   Guenter Roeck   hwmon: (max6639) ...
507
508
  	if (!data)
  		return -ENOMEM;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
509

7981c5846   Guenter Roeck   hwmon: (max6639) ...
510
  	data->client = client;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
511
512
513
  	mutex_init(&data->update_lock);
  
  	/* Initialize the max6639 chip */
7981c5846   Guenter Roeck   hwmon: (max6639) ...
514
  	err = max6639_init_client(client, data);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
515
  	if (err < 0)
b07405fbc   Guenter Roeck   hwmon: (max6639) ...
516
  		return err;
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
517

7981c5846   Guenter Roeck   hwmon: (max6639) ...
518
519
520
521
  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
  							   data,
  							   max6639_groups);
  	return PTR_ERR_OR_ZERO(hwmon_dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
522
  }
52f30f771   Mark Brown   hwmon: (max6639) ...
523
524
  #ifdef CONFIG_PM_SLEEP
  static int max6639_suspend(struct device *dev)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
525
  {
52f30f771   Mark Brown   hwmon: (max6639) ...
526
  	struct i2c_client *client = to_i2c_client(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
527
528
529
530
531
532
533
  	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
  	if (data < 0)
  		return data;
  
  	return i2c_smbus_write_byte_data(client,
  			MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
  }
52f30f771   Mark Brown   hwmon: (max6639) ...
534
  static int max6639_resume(struct device *dev)
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
535
  {
52f30f771   Mark Brown   hwmon: (max6639) ...
536
  	struct i2c_client *client = to_i2c_client(dev);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
537
538
539
540
541
542
543
  	int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
  	if (data < 0)
  		return data;
  
  	return i2c_smbus_write_byte_data(client,
  			MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
  }
52f30f771   Mark Brown   hwmon: (max6639) ...
544
  #endif /* CONFIG_PM_SLEEP */
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
545
546
547
548
549
550
551
  
  static const struct i2c_device_id max6639_id[] = {
  	{"max6639", 0},
  	{ }
  };
  
  MODULE_DEVICE_TABLE(i2c, max6639_id);
768821a30   Jingoo Han   hwmon: (max6639) ...
552
  static SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
52f30f771   Mark Brown   hwmon: (max6639) ...
553

a5b79d62f   stigge@antcom.de   hwmon: Driver for...
554
555
556
557
  static struct i2c_driver max6639_driver = {
  	.class = I2C_CLASS_HWMON,
  	.driver = {
  		   .name = "max6639",
52f30f771   Mark Brown   hwmon: (max6639) ...
558
  		   .pm = &max6639_pm_ops,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
559
  		   },
674870385   Stephen Kitt   hwmon: use simple...
560
  	.probe_new = max6639_probe,
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
561
562
563
564
  	.id_table = max6639_id,
  	.detect = max6639_detect,
  	.address_list = normal_i2c,
  };
f0967eea8   Axel Lin   hwmon: convert dr...
565
  module_i2c_driver(max6639_driver);
a5b79d62f   stigge@antcom.de   hwmon: Driver for...
566
567
568
569
  
  MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
  MODULE_DESCRIPTION("max6639 driver");
  MODULE_LICENSE("GPL");