xref: /openbmc/linux/drivers/hwmon/max6650.c (revision 4f8d374b)
1d20620deSHans-Juergen Koch /*
2d20620deSHans-Juergen Koch  * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
3d20620deSHans-Juergen Koch  *             monitoring.
4d20620deSHans-Juergen Koch  *
52aa25c22SHans J. Koch  * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
6d20620deSHans-Juergen Koch  *
7d20620deSHans-Juergen Koch  * based on code written by John Morris <john.morris@spirentcom.com>
8d20620deSHans-Juergen Koch  * Copyright (c) 2003 Spirent Communications
9d20620deSHans-Juergen Koch  * and Claus Gindhart <claus.gindhart@kontron.com>
10d20620deSHans-Juergen Koch  *
11d20620deSHans-Juergen Koch  * This module has only been tested with the MAX6650 chip. It should
12d20620deSHans-Juergen Koch  * also work with the MAX6651. It does not distinguish max6650 and max6651
13d20620deSHans-Juergen Koch  * chips.
14d20620deSHans-Juergen Koch  *
1552b5226fSChristian Engelmayer  * The datasheet was last seen at:
16d20620deSHans-Juergen Koch  *
17d20620deSHans-Juergen Koch  *        http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
18d20620deSHans-Juergen Koch  *
19d20620deSHans-Juergen Koch  * This program is free software; you can redistribute it and/or modify
20d20620deSHans-Juergen Koch  * it under the terms of the GNU General Public License as published by
21d20620deSHans-Juergen Koch  * the Free Software Foundation; either version 2 of the License, or
22d20620deSHans-Juergen Koch  * (at your option) any later version.
23d20620deSHans-Juergen Koch  *
24d20620deSHans-Juergen Koch  * This program is distributed in the hope that it will be useful,
25d20620deSHans-Juergen Koch  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26d20620deSHans-Juergen Koch  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27d20620deSHans-Juergen Koch  * GNU General Public License for more details.
28d20620deSHans-Juergen Koch  *
29d20620deSHans-Juergen Koch  * You should have received a copy of the GNU General Public License
30d20620deSHans-Juergen Koch  * along with this program; if not, write to the Free Software
31d20620deSHans-Juergen Koch  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32d20620deSHans-Juergen Koch  */
33d20620deSHans-Juergen Koch 
34d20620deSHans-Juergen Koch #include <linux/module.h>
35d20620deSHans-Juergen Koch #include <linux/init.h>
36d20620deSHans-Juergen Koch #include <linux/slab.h>
37d20620deSHans-Juergen Koch #include <linux/jiffies.h>
38d20620deSHans-Juergen Koch #include <linux/i2c.h>
39d20620deSHans-Juergen Koch #include <linux/hwmon.h>
40d20620deSHans-Juergen Koch #include <linux/hwmon-sysfs.h>
41d20620deSHans-Juergen Koch #include <linux/err.h>
42a6cdeefeSMike Looijmans #include <linux/of_device.h>
434f8d374bSJean-Francois Dagenais #include <linux/thermal.h>
44d20620deSHans-Juergen Koch 
45d20620deSHans-Juergen Koch /*
46d20620deSHans-Juergen Koch  * Insmod parameters
47d20620deSHans-Juergen Koch  */
48d20620deSHans-Juergen Koch 
49d20620deSHans-Juergen Koch /* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */
50d20620deSHans-Juergen Koch static int fan_voltage;
51d20620deSHans-Juergen Koch /* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */
52d20620deSHans-Juergen Koch static int prescaler;
53a6cdeefeSMike Looijmans /* clock: The clock frequency of the chip (max6651 can be clocked externally) */
54d20620deSHans-Juergen Koch static int clock = 254000;
55d20620deSHans-Juergen Koch 
560f50b2e8SGuenter Roeck module_param(fan_voltage, int, 0444);
570f50b2e8SGuenter Roeck module_param(prescaler, int, 0444);
580f50b2e8SGuenter Roeck module_param(clock, int, 0444);
59d20620deSHans-Juergen Koch 
60d20620deSHans-Juergen Koch /*
61d20620deSHans-Juergen Koch  * MAX 6650/6651 registers
62d20620deSHans-Juergen Koch  */
63d20620deSHans-Juergen Koch 
64d20620deSHans-Juergen Koch #define MAX6650_REG_SPEED	0x00
65d20620deSHans-Juergen Koch #define MAX6650_REG_CONFIG	0x02
66d20620deSHans-Juergen Koch #define MAX6650_REG_GPIO_DEF	0x04
67d20620deSHans-Juergen Koch #define MAX6650_REG_DAC		0x06
68d20620deSHans-Juergen Koch #define MAX6650_REG_ALARM_EN	0x08
69d20620deSHans-Juergen Koch #define MAX6650_REG_ALARM	0x0A
70d20620deSHans-Juergen Koch #define MAX6650_REG_TACH0	0x0C
71d20620deSHans-Juergen Koch #define MAX6650_REG_TACH1	0x0E
72d20620deSHans-Juergen Koch #define MAX6650_REG_TACH2	0x10
73d20620deSHans-Juergen Koch #define MAX6650_REG_TACH3	0x12
74d20620deSHans-Juergen Koch #define MAX6650_REG_GPIO_STAT	0x14
75d20620deSHans-Juergen Koch #define MAX6650_REG_COUNT	0x16
76d20620deSHans-Juergen Koch 
77d20620deSHans-Juergen Koch /*
78d20620deSHans-Juergen Koch  * Config register bits
79d20620deSHans-Juergen Koch  */
80d20620deSHans-Juergen Koch 
81d20620deSHans-Juergen Koch #define MAX6650_CFG_V12			0x08
82d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_MASK	0x07
83d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_2		0x01
84d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_4		0x02
85d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_8		0x03
86d20620deSHans-Juergen Koch #define MAX6650_CFG_PRESCALER_16	0x04
87d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_MASK		0x30
88d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_ON		0x00
89d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_OFF		0x10
90d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_CLOSED_LOOP	0x20
91d20620deSHans-Juergen Koch #define MAX6650_CFG_MODE_OPEN_LOOP	0x30
92d20620deSHans-Juergen Koch #define MAX6650_COUNT_MASK		0x03
93d20620deSHans-Juergen Koch 
9452b5226fSChristian Engelmayer /*
9552b5226fSChristian Engelmayer  * Alarm status register bits
9652b5226fSChristian Engelmayer  */
9752b5226fSChristian Engelmayer 
9852b5226fSChristian Engelmayer #define MAX6650_ALRM_MAX	0x01
9952b5226fSChristian Engelmayer #define MAX6650_ALRM_MIN	0x02
10052b5226fSChristian Engelmayer #define MAX6650_ALRM_TACH	0x04
10152b5226fSChristian Engelmayer #define MAX6650_ALRM_GPIO1	0x08
10252b5226fSChristian Engelmayer #define MAX6650_ALRM_GPIO2	0x10
10352b5226fSChristian Engelmayer 
104d20620deSHans-Juergen Koch /* Minimum and maximum values of the FAN-RPM */
105d20620deSHans-Juergen Koch #define FAN_RPM_MIN 240
106d20620deSHans-Juergen Koch #define FAN_RPM_MAX 30000
107d20620deSHans-Juergen Koch 
108d20620deSHans-Juergen Koch #define DIV_FROM_REG(reg) (1 << (reg & 7))
109d20620deSHans-Juergen Koch 
110d20620deSHans-Juergen Koch /*
111d20620deSHans-Juergen Koch  * Client data (each client gets its own)
112d20620deSHans-Juergen Koch  */
113d20620deSHans-Juergen Koch 
114bafda5d0SGuenter Roeck struct max6650_data {
11517eaa25cSGuenter Roeck 	struct i2c_client *client;
11617eaa25cSGuenter Roeck 	const struct attribute_group *groups[3];
1174f8d374bSJean-Francois Dagenais 	struct thermal_cooling_device *cooling_dev;
118d20620deSHans-Juergen Koch 	struct mutex update_lock;
1199c084daeSJean Delvare 	int nr_fans;
120d20620deSHans-Juergen Koch 	char valid; /* zero until following fields are valid */
121d20620deSHans-Juergen Koch 	unsigned long last_updated; /* in jiffies */
122d20620deSHans-Juergen Koch 
123d20620deSHans-Juergen Koch 	/* register values */
124d20620deSHans-Juergen Koch 	u8 speed;
125d20620deSHans-Juergen Koch 	u8 config;
126d20620deSHans-Juergen Koch 	u8 tach[4];
127d20620deSHans-Juergen Koch 	u8 count;
128d20620deSHans-Juergen Koch 	u8 dac;
12952b5226fSChristian Engelmayer 	u8 alarm;
1304f8d374bSJean-Francois Dagenais 	unsigned long cooling_dev_state;
131d20620deSHans-Juergen Koch };
132d20620deSHans-Juergen Koch 
1331577f94bSGuenter Roeck static const u8 tach_reg[] = {
1341577f94bSGuenter Roeck 	MAX6650_REG_TACH0,
1351577f94bSGuenter Roeck 	MAX6650_REG_TACH1,
1361577f94bSGuenter Roeck 	MAX6650_REG_TACH2,
1371577f94bSGuenter Roeck 	MAX6650_REG_TACH3,
1381577f94bSGuenter Roeck };
1391577f94bSGuenter Roeck 
1402720ce7eSGuenter Roeck static const struct of_device_id __maybe_unused max6650_dt_match[] = {
141a6cdeefeSMike Looijmans 	{
142a6cdeefeSMike Looijmans 		.compatible = "maxim,max6650",
143a6cdeefeSMike Looijmans 		.data = (void *)1
144a6cdeefeSMike Looijmans 	},
145a6cdeefeSMike Looijmans 	{
146a6cdeefeSMike Looijmans 		.compatible = "maxim,max6651",
147a6cdeefeSMike Looijmans 		.data = (void *)4
148a6cdeefeSMike Looijmans 	},
149a6cdeefeSMike Looijmans 	{ },
150a6cdeefeSMike Looijmans };
151a6cdeefeSMike Looijmans MODULE_DEVICE_TABLE(of, max6650_dt_match);
152a6cdeefeSMike Looijmans 
1531577f94bSGuenter Roeck static struct max6650_data *max6650_update_device(struct device *dev)
1541577f94bSGuenter Roeck {
15517eaa25cSGuenter Roeck 	struct max6650_data *data = dev_get_drvdata(dev);
15617eaa25cSGuenter Roeck 	struct i2c_client *client = data->client;
1571577f94bSGuenter Roeck 	int i;
1581577f94bSGuenter Roeck 
1591577f94bSGuenter Roeck 	mutex_lock(&data->update_lock);
1601577f94bSGuenter Roeck 
1611577f94bSGuenter Roeck 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
1621577f94bSGuenter Roeck 		data->speed = i2c_smbus_read_byte_data(client,
1631577f94bSGuenter Roeck 						       MAX6650_REG_SPEED);
1641577f94bSGuenter Roeck 		data->config = i2c_smbus_read_byte_data(client,
1651577f94bSGuenter Roeck 							MAX6650_REG_CONFIG);
1661577f94bSGuenter Roeck 		for (i = 0; i < data->nr_fans; i++) {
1671577f94bSGuenter Roeck 			data->tach[i] = i2c_smbus_read_byte_data(client,
1681577f94bSGuenter Roeck 								 tach_reg[i]);
1691577f94bSGuenter Roeck 		}
1701577f94bSGuenter Roeck 		data->count = i2c_smbus_read_byte_data(client,
1711577f94bSGuenter Roeck 							MAX6650_REG_COUNT);
1721577f94bSGuenter Roeck 		data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
1731577f94bSGuenter Roeck 
1741577f94bSGuenter Roeck 		/*
1751577f94bSGuenter Roeck 		 * Alarms are cleared on read in case the condition that
1761577f94bSGuenter Roeck 		 * caused the alarm is removed. Keep the value latched here
1771577f94bSGuenter Roeck 		 * for providing the register through different alarm files.
1781577f94bSGuenter Roeck 		 */
1791577f94bSGuenter Roeck 		data->alarm |= i2c_smbus_read_byte_data(client,
1801577f94bSGuenter Roeck 							MAX6650_REG_ALARM);
1811577f94bSGuenter Roeck 
1821577f94bSGuenter Roeck 		data->last_updated = jiffies;
1831577f94bSGuenter Roeck 		data->valid = 1;
1841577f94bSGuenter Roeck 	}
1851577f94bSGuenter Roeck 
1861577f94bSGuenter Roeck 	mutex_unlock(&data->update_lock);
1871577f94bSGuenter Roeck 
1881577f94bSGuenter Roeck 	return data;
1891577f94bSGuenter Roeck }
1901577f94bSGuenter Roeck 
19120005cc5SMike Looijmans /*
19220005cc5SMike Looijmans  * Change the operating mode of the chip (if needed).
19320005cc5SMike Looijmans  * mode is one of the MAX6650_CFG_MODE_* values.
19420005cc5SMike Looijmans  */
19520005cc5SMike Looijmans static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)
19620005cc5SMike Looijmans {
19720005cc5SMike Looijmans 	int result;
19820005cc5SMike Looijmans 	u8 config = data->config;
19920005cc5SMike Looijmans 
20020005cc5SMike Looijmans 	if (mode == (config & MAX6650_CFG_MODE_MASK))
20120005cc5SMike Looijmans 		return 0;
20220005cc5SMike Looijmans 
20320005cc5SMike Looijmans 	config = (config & ~MAX6650_CFG_MODE_MASK) | mode;
20420005cc5SMike Looijmans 
20520005cc5SMike Looijmans 	result = i2c_smbus_write_byte_data(data->client, MAX6650_REG_CONFIG,
20620005cc5SMike Looijmans 					   config);
20720005cc5SMike Looijmans 	if (result < 0)
20820005cc5SMike Looijmans 		return result;
20920005cc5SMike Looijmans 
21020005cc5SMike Looijmans 	data->config = config;
21120005cc5SMike Looijmans 
21220005cc5SMike Looijmans 	return 0;
21320005cc5SMike Looijmans }
21420005cc5SMike Looijmans 
21544007117SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
216d20620deSHans-Juergen Koch 			char *buf)
217d20620deSHans-Juergen Koch {
218d20620deSHans-Juergen Koch 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
219d20620deSHans-Juergen Koch 	struct max6650_data *data = max6650_update_device(dev);
220d20620deSHans-Juergen Koch 	int rpm;
221d20620deSHans-Juergen Koch 
222d20620deSHans-Juergen Koch 	/*
223d20620deSHans-Juergen Koch 	 * Calculation details:
224d20620deSHans-Juergen Koch 	 *
225d20620deSHans-Juergen Koch 	 * Each tachometer counts over an interval given by the "count"
226d20620deSHans-Juergen Koch 	 * register (0.25, 0.5, 1 or 2 seconds). This module assumes
227d20620deSHans-Juergen Koch 	 * that the fans produce two pulses per revolution (this seems
228d20620deSHans-Juergen Koch 	 * to be the most common).
229d20620deSHans-Juergen Koch 	 */
230d20620deSHans-Juergen Koch 
231d20620deSHans-Juergen Koch 	rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
232d20620deSHans-Juergen Koch 	return sprintf(buf, "%d\n", rpm);
233d20620deSHans-Juergen Koch }
234d20620deSHans-Juergen Koch 
235d20620deSHans-Juergen Koch /*
236d20620deSHans-Juergen Koch  * Set the fan speed to the specified RPM (or read back the RPM setting).
237d20620deSHans-Juergen Koch  * This works in closed loop mode only. Use pwm1 for open loop speed setting.
238d20620deSHans-Juergen Koch  *
239d20620deSHans-Juergen Koch  * The MAX6650/1 will automatically control fan speed when in closed loop
240d20620deSHans-Juergen Koch  * mode.
241d20620deSHans-Juergen Koch  *
242d20620deSHans-Juergen Koch  * Assumptions:
243d20620deSHans-Juergen Koch  *
244d20620deSHans-Juergen Koch  * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use
245d20620deSHans-Juergen Koch  *    the clock module parameter if you need to fine tune this.
246d20620deSHans-Juergen Koch  *
247d20620deSHans-Juergen Koch  * 2) The prescaler (low three bits of the config register) has already
248d20620deSHans-Juergen Koch  *    been set to an appropriate value. Use the prescaler module parameter
249d20620deSHans-Juergen Koch  *    if your BIOS doesn't initialize the chip properly.
250d20620deSHans-Juergen Koch  *
251d20620deSHans-Juergen Koch  * The relevant equations are given on pages 21 and 22 of the datasheet.
252d20620deSHans-Juergen Koch  *
253d20620deSHans-Juergen Koch  * From the datasheet, the relevant equation when in regulation is:
254d20620deSHans-Juergen Koch  *
255d20620deSHans-Juergen Koch  *    [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE
256d20620deSHans-Juergen Koch  *
257d20620deSHans-Juergen Koch  * where:
258d20620deSHans-Juergen Koch  *
259d20620deSHans-Juergen Koch  *    fCLK is the oscillator frequency (either the 254kHz internal
260d20620deSHans-Juergen Koch  *         oscillator or the externally applied clock)
261d20620deSHans-Juergen Koch  *
262d20620deSHans-Juergen Koch  *    KTACH is the value in the speed register
263d20620deSHans-Juergen Koch  *
264d20620deSHans-Juergen Koch  *    FanSpeed is the speed of the fan in rps
265d20620deSHans-Juergen Koch  *
266d20620deSHans-Juergen Koch  *    KSCALE is the prescaler value (1, 2, 4, 8, or 16)
267d20620deSHans-Juergen Koch  *
268d20620deSHans-Juergen Koch  * When reading, we need to solve for FanSpeed. When writing, we need to
269d20620deSHans-Juergen Koch  * solve for KTACH.
270d20620deSHans-Juergen Koch  *
271d20620deSHans-Juergen Koch  * Note: this tachometer is completely separate from the tachometers
272d20620deSHans-Juergen Koch  * used to measure the fan speeds. Only one fan's speed (fan1) is
273d20620deSHans-Juergen Koch  * controlled.
274d20620deSHans-Juergen Koch  */
275d20620deSHans-Juergen Koch 
2761fc67376SJulia Lawall static ssize_t fan1_target_show(struct device *dev,
2771fc67376SJulia Lawall 				struct device_attribute *devattr, char *buf)
278d20620deSHans-Juergen Koch {
279d20620deSHans-Juergen Koch 	struct max6650_data *data = max6650_update_device(dev);
280d20620deSHans-Juergen Koch 	int kscale, ktach, rpm;
281d20620deSHans-Juergen Koch 
282d20620deSHans-Juergen Koch 	/*
283d20620deSHans-Juergen Koch 	 * Use the datasheet equation:
284d20620deSHans-Juergen Koch 	 *
285d20620deSHans-Juergen Koch 	 *    FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
286d20620deSHans-Juergen Koch 	 *
287d20620deSHans-Juergen Koch 	 * then multiply by 60 to give rpm.
288d20620deSHans-Juergen Koch 	 */
289d20620deSHans-Juergen Koch 
290d20620deSHans-Juergen Koch 	kscale = DIV_FROM_REG(data->config);
291d20620deSHans-Juergen Koch 	ktach = data->speed;
292d20620deSHans-Juergen Koch 	rpm = 60 * kscale * clock / (256 * (ktach + 1));
293d20620deSHans-Juergen Koch 	return sprintf(buf, "%d\n", rpm);
294d20620deSHans-Juergen Koch }
295d20620deSHans-Juergen Koch 
29620005cc5SMike Looijmans static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
297d20620deSHans-Juergen Koch {
298d20620deSHans-Juergen Koch 	int kscale, ktach;
299bafda5d0SGuenter Roeck 
30020005cc5SMike Looijmans 	if (rpm == 0)
30120005cc5SMike Looijmans 		return max6650_set_operating_mode(data, MAX6650_CFG_MODE_OFF);
302d20620deSHans-Juergen Koch 
3032a844c14SGuenter Roeck 	rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
304d20620deSHans-Juergen Koch 
305d20620deSHans-Juergen Koch 	/*
306d20620deSHans-Juergen Koch 	 * Divide the required speed by 60 to get from rpm to rps, then
307d20620deSHans-Juergen Koch 	 * use the datasheet equation:
308d20620deSHans-Juergen Koch 	 *
309d20620deSHans-Juergen Koch 	 *     KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
310d20620deSHans-Juergen Koch 	 */
311d20620deSHans-Juergen Koch 
312d20620deSHans-Juergen Koch 	kscale = DIV_FROM_REG(data->config);
313d20620deSHans-Juergen Koch 	ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;
314d20620deSHans-Juergen Koch 	if (ktach < 0)
315d20620deSHans-Juergen Koch 		ktach = 0;
316d20620deSHans-Juergen Koch 	if (ktach > 255)
317d20620deSHans-Juergen Koch 		ktach = 255;
318d20620deSHans-Juergen Koch 	data->speed = ktach;
319d20620deSHans-Juergen Koch 
32020005cc5SMike Looijmans 	return i2c_smbus_write_byte_data(data->client, MAX6650_REG_SPEED,
32120005cc5SMike Looijmans 					 data->speed);
32220005cc5SMike Looijmans }
32320005cc5SMike Looijmans 
3241fc67376SJulia Lawall static ssize_t fan1_target_store(struct device *dev,
3251fc67376SJulia Lawall 				 struct device_attribute *devattr,
32620005cc5SMike Looijmans 				 const char *buf, size_t count)
32720005cc5SMike Looijmans {
32820005cc5SMike Looijmans 	struct max6650_data *data = dev_get_drvdata(dev);
32920005cc5SMike Looijmans 	unsigned long rpm;
33020005cc5SMike Looijmans 	int err;
33120005cc5SMike Looijmans 
33220005cc5SMike Looijmans 	err = kstrtoul(buf, 10, &rpm);
33320005cc5SMike Looijmans 	if (err)
33420005cc5SMike Looijmans 		return err;
33520005cc5SMike Looijmans 
33620005cc5SMike Looijmans 	mutex_lock(&data->update_lock);
33720005cc5SMike Looijmans 
33820005cc5SMike Looijmans 	err = max6650_set_target(data, rpm);
339d20620deSHans-Juergen Koch 
340d20620deSHans-Juergen Koch 	mutex_unlock(&data->update_lock);
341d20620deSHans-Juergen Koch 
34220005cc5SMike Looijmans 	if (err < 0)
34320005cc5SMike Looijmans 		return err;
34420005cc5SMike Looijmans 
345d20620deSHans-Juergen Koch 	return count;
346d20620deSHans-Juergen Koch }
347d20620deSHans-Juergen Koch 
348d20620deSHans-Juergen Koch /*
349d20620deSHans-Juergen Koch  * Get/set the fan speed in open loop mode using pwm1 sysfs file.
350d20620deSHans-Juergen Koch  * Speed is given as a relative value from 0 to 255, where 255 is maximum
351d20620deSHans-Juergen Koch  * speed. Note that this is done by writing directly to the chip's DAC,
352d20620deSHans-Juergen Koch  * it won't change the closed loop speed set by fan1_target.
353d20620deSHans-Juergen Koch  * Also note that due to rounding errors it is possible that you don't read
354d20620deSHans-Juergen Koch  * back exactly the value you have set.
355d20620deSHans-Juergen Koch  */
356d20620deSHans-Juergen Koch 
3571fc67376SJulia Lawall static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr,
358d20620deSHans-Juergen Koch 			 char *buf)
359d20620deSHans-Juergen Koch {
360d20620deSHans-Juergen Koch 	int pwm;
361d20620deSHans-Juergen Koch 	struct max6650_data *data = max6650_update_device(dev);
362d20620deSHans-Juergen Koch 
363703af960SGuenter Roeck 	/*
364703af960SGuenter Roeck 	 * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
365703af960SGuenter Roeck 	 * Lower DAC values mean higher speeds.
366703af960SGuenter Roeck 	 */
367d20620deSHans-Juergen Koch 	if (data->config & MAX6650_CFG_V12)
368d20620deSHans-Juergen Koch 		pwm = 255 - (255 * (int)data->dac)/180;
369d20620deSHans-Juergen Koch 	else
370d20620deSHans-Juergen Koch 		pwm = 255 - (255 * (int)data->dac)/76;
371d20620deSHans-Juergen Koch 
372d20620deSHans-Juergen Koch 	if (pwm < 0)
373d20620deSHans-Juergen Koch 		pwm = 0;
374d20620deSHans-Juergen Koch 
375d20620deSHans-Juergen Koch 	return sprintf(buf, "%d\n", pwm);
376d20620deSHans-Juergen Koch }
377d20620deSHans-Juergen Koch 
3781fc67376SJulia Lawall static ssize_t pwm1_store(struct device *dev,
3791fc67376SJulia Lawall 			  struct device_attribute *devattr, const char *buf,
3801fc67376SJulia Lawall 			  size_t count)
381d20620deSHans-Juergen Koch {
38217eaa25cSGuenter Roeck 	struct max6650_data *data = dev_get_drvdata(dev);
38317eaa25cSGuenter Roeck 	struct i2c_client *client = data->client;
384bafda5d0SGuenter Roeck 	unsigned long pwm;
385bafda5d0SGuenter Roeck 	int err;
386bafda5d0SGuenter Roeck 
387bafda5d0SGuenter Roeck 	err = kstrtoul(buf, 10, &pwm);
388bafda5d0SGuenter Roeck 	if (err)
389bafda5d0SGuenter Roeck 		return err;
390d20620deSHans-Juergen Koch 
3912a844c14SGuenter Roeck 	pwm = clamp_val(pwm, 0, 255);
392d20620deSHans-Juergen Koch 
393d20620deSHans-Juergen Koch 	mutex_lock(&data->update_lock);
394d20620deSHans-Juergen Koch 
395d20620deSHans-Juergen Koch 	if (data->config & MAX6650_CFG_V12)
396d20620deSHans-Juergen Koch 		data->dac = 180 - (180 * pwm)/255;
397d20620deSHans-Juergen Koch 	else
398d20620deSHans-Juergen Koch 		data->dac = 76 - (76 * pwm)/255;
39920005cc5SMike Looijmans 	err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
400d20620deSHans-Juergen Koch 
401d20620deSHans-Juergen Koch 	mutex_unlock(&data->update_lock);
402d20620deSHans-Juergen Koch 
40320005cc5SMike Looijmans 	return err < 0 ? err : count;
404d20620deSHans-Juergen Koch }
405d20620deSHans-Juergen Koch 
406d20620deSHans-Juergen Koch /*
407d20620deSHans-Juergen Koch  * Get/Set controller mode:
408d20620deSHans-Juergen Koch  * Possible values:
409d20620deSHans-Juergen Koch  * 0 = Fan always on
410d20620deSHans-Juergen Koch  * 1 = Open loop, Voltage is set according to speed, not regulated.
411d20620deSHans-Juergen Koch  * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
41220005cc5SMike Looijmans  * 3 = Fan off
413d20620deSHans-Juergen Koch  */
4141fc67376SJulia Lawall static ssize_t pwm1_enable_show(struct device *dev,
4151fc67376SJulia Lawall 				struct device_attribute *devattr, char *buf)
416d20620deSHans-Juergen Koch {
417d20620deSHans-Juergen Koch 	struct max6650_data *data = max6650_update_device(dev);
418d20620deSHans-Juergen Koch 	int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
41920005cc5SMike Looijmans 	int sysfs_modes[4] = {0, 3, 2, 1};
420d20620deSHans-Juergen Koch 
421d20620deSHans-Juergen Koch 	return sprintf(buf, "%d\n", sysfs_modes[mode]);
422d20620deSHans-Juergen Koch }
423d20620deSHans-Juergen Koch 
4241fc67376SJulia Lawall static ssize_t pwm1_enable_store(struct device *dev,
4251fc67376SJulia Lawall 				 struct device_attribute *devattr,
426d20620deSHans-Juergen Koch 				 const char *buf, size_t count)
427d20620deSHans-Juergen Koch {
42817eaa25cSGuenter Roeck 	struct max6650_data *data = dev_get_drvdata(dev);
429bafda5d0SGuenter Roeck 	unsigned long mode;
430bafda5d0SGuenter Roeck 	int err;
43120005cc5SMike Looijmans 	const u8 max6650_modes[] = {
43220005cc5SMike Looijmans 		MAX6650_CFG_MODE_ON,
43320005cc5SMike Looijmans 		MAX6650_CFG_MODE_OPEN_LOOP,
43420005cc5SMike Looijmans 		MAX6650_CFG_MODE_CLOSED_LOOP,
43520005cc5SMike Looijmans 		MAX6650_CFG_MODE_OFF,
43620005cc5SMike Looijmans 		};
437d20620deSHans-Juergen Koch 
438bafda5d0SGuenter Roeck 	err = kstrtoul(buf, 10, &mode);
439bafda5d0SGuenter Roeck 	if (err)
440bafda5d0SGuenter Roeck 		return err;
441bafda5d0SGuenter Roeck 
44220005cc5SMike Looijmans 	if (mode >= ARRAY_SIZE(max6650_modes))
443d20620deSHans-Juergen Koch 		return -EINVAL;
444d20620deSHans-Juergen Koch 
445d20620deSHans-Juergen Koch 	mutex_lock(&data->update_lock);
446d20620deSHans-Juergen Koch 
44720005cc5SMike Looijmans 	max6650_set_operating_mode(data, max6650_modes[mode]);
448d20620deSHans-Juergen Koch 
449d20620deSHans-Juergen Koch 	mutex_unlock(&data->update_lock);
450d20620deSHans-Juergen Koch 
451d20620deSHans-Juergen Koch 	return count;
452d20620deSHans-Juergen Koch }
453d20620deSHans-Juergen Koch 
454d20620deSHans-Juergen Koch /*
455d20620deSHans-Juergen Koch  * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
456d20620deSHans-Juergen Koch  * divider. We handle this by converting between divider and counttime:
457d20620deSHans-Juergen Koch  *
458d20620deSHans-Juergen Koch  * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
459d20620deSHans-Juergen Koch  *
460d20620deSHans-Juergen Koch  * Lower values of k allow to connect a faster fan without the risk of
461d20620deSHans-Juergen Koch  * counter overflow. The price is lower resolution. You can also set counttime
462d20620deSHans-Juergen Koch  * using the module parameter. Note that the module parameter "prescaler" also
463d20620deSHans-Juergen Koch  * influences the behaviour. Unfortunately, there's no sysfs attribute
464d20620deSHans-Juergen Koch  * defined for that. See the data sheet for details.
465d20620deSHans-Juergen Koch  */
466d20620deSHans-Juergen Koch 
4671fc67376SJulia Lawall static ssize_t fan1_div_show(struct device *dev,
4681fc67376SJulia Lawall 			     struct device_attribute *devattr, char *buf)
469d20620deSHans-Juergen Koch {
470d20620deSHans-Juergen Koch 	struct max6650_data *data = max6650_update_device(dev);
471d20620deSHans-Juergen Koch 
472d20620deSHans-Juergen Koch 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
473d20620deSHans-Juergen Koch }
474d20620deSHans-Juergen Koch 
4751fc67376SJulia Lawall static ssize_t fan1_div_store(struct device *dev,
4761fc67376SJulia Lawall 			      struct device_attribute *devattr,
477d20620deSHans-Juergen Koch 			      const char *buf, size_t count)
478d20620deSHans-Juergen Koch {
47917eaa25cSGuenter Roeck 	struct max6650_data *data = dev_get_drvdata(dev);
48017eaa25cSGuenter Roeck 	struct i2c_client *client = data->client;
481bafda5d0SGuenter Roeck 	unsigned long div;
482bafda5d0SGuenter Roeck 	int err;
483bafda5d0SGuenter Roeck 
484bafda5d0SGuenter Roeck 	err = kstrtoul(buf, 10, &div);
485bafda5d0SGuenter Roeck 	if (err)
486bafda5d0SGuenter Roeck 		return err;
487d20620deSHans-Juergen Koch 
488d20620deSHans-Juergen Koch 	mutex_lock(&data->update_lock);
489d20620deSHans-Juergen Koch 	switch (div) {
490d20620deSHans-Juergen Koch 	case 1:
491d20620deSHans-Juergen Koch 		data->count = 0;
492d20620deSHans-Juergen Koch 		break;
493d20620deSHans-Juergen Koch 	case 2:
494d20620deSHans-Juergen Koch 		data->count = 1;
495d20620deSHans-Juergen Koch 		break;
496d20620deSHans-Juergen Koch 	case 4:
497d20620deSHans-Juergen Koch 		data->count = 2;
498d20620deSHans-Juergen Koch 		break;
499d20620deSHans-Juergen Koch 	case 8:
500d20620deSHans-Juergen Koch 		data->count = 3;
501d20620deSHans-Juergen Koch 		break;
502d20620deSHans-Juergen Koch 	default:
503025dc740SJiri Slaby 		mutex_unlock(&data->update_lock);
504d20620deSHans-Juergen Koch 		return -EINVAL;
505d20620deSHans-Juergen Koch 	}
506d20620deSHans-Juergen Koch 
507d20620deSHans-Juergen Koch 	i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
508d20620deSHans-Juergen Koch 	mutex_unlock(&data->update_lock);
509d20620deSHans-Juergen Koch 
510d20620deSHans-Juergen Koch 	return count;
511d20620deSHans-Juergen Koch }
512d20620deSHans-Juergen Koch 
51352b5226fSChristian Engelmayer /*
51452b5226fSChristian Engelmayer  * Get alarm stati:
51552b5226fSChristian Engelmayer  * Possible values:
51652b5226fSChristian Engelmayer  * 0 = no alarm
51752b5226fSChristian Engelmayer  * 1 = alarm
51852b5226fSChristian Engelmayer  */
51952b5226fSChristian Engelmayer 
52044007117SGuenter Roeck static ssize_t alarm_show(struct device *dev,
52144007117SGuenter Roeck 			  struct device_attribute *devattr, char *buf)
52252b5226fSChristian Engelmayer {
52352b5226fSChristian Engelmayer 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
52452b5226fSChristian Engelmayer 	struct max6650_data *data = max6650_update_device(dev);
52517eaa25cSGuenter Roeck 	struct i2c_client *client = data->client;
52652b5226fSChristian Engelmayer 	int alarm = 0;
52752b5226fSChristian Engelmayer 
52852b5226fSChristian Engelmayer 	if (data->alarm & attr->index) {
52952b5226fSChristian Engelmayer 		mutex_lock(&data->update_lock);
53052b5226fSChristian Engelmayer 		alarm = 1;
53152b5226fSChristian Engelmayer 		data->alarm &= ~attr->index;
53252b5226fSChristian Engelmayer 		data->alarm |= i2c_smbus_read_byte_data(client,
53352b5226fSChristian Engelmayer 							MAX6650_REG_ALARM);
53452b5226fSChristian Engelmayer 		mutex_unlock(&data->update_lock);
53552b5226fSChristian Engelmayer 	}
53652b5226fSChristian Engelmayer 
53752b5226fSChristian Engelmayer 	return sprintf(buf, "%d\n", alarm);
53852b5226fSChristian Engelmayer }
53952b5226fSChristian Engelmayer 
54044007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
54144007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
54244007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
54344007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
5441fc67376SJulia Lawall static DEVICE_ATTR_RW(fan1_target);
5451fc67376SJulia Lawall static DEVICE_ATTR_RW(fan1_div);
5461fc67376SJulia Lawall static DEVICE_ATTR_RW(pwm1_enable);
5471fc67376SJulia Lawall static DEVICE_ATTR_RW(pwm1);
54844007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_max_alarm, alarm, MAX6650_ALRM_MAX);
54944007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_min_alarm, alarm, MAX6650_ALRM_MIN);
55044007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, MAX6650_ALRM_TACH);
55144007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1);
55244007117SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2);
553d20620deSHans-Juergen Koch 
554587a1f16SAl Viro static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
55552b5226fSChristian Engelmayer 				    int n)
55652b5226fSChristian Engelmayer {
55752b5226fSChristian Engelmayer 	struct device *dev = container_of(kobj, struct device, kobj);
55817eaa25cSGuenter Roeck 	struct max6650_data *data = dev_get_drvdata(dev);
55917eaa25cSGuenter Roeck 	struct i2c_client *client = data->client;
56052b5226fSChristian Engelmayer 	u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
56152b5226fSChristian Engelmayer 	struct device_attribute *devattr;
56252b5226fSChristian Engelmayer 
56352b5226fSChristian Engelmayer 	/*
56452b5226fSChristian Engelmayer 	 * Hide the alarms that have not been enabled by the firmware
56552b5226fSChristian Engelmayer 	 */
56652b5226fSChristian Engelmayer 
56752b5226fSChristian Engelmayer 	devattr = container_of(a, struct device_attribute, attr);
56852b5226fSChristian Engelmayer 	if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
56952b5226fSChristian Engelmayer 	 || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
57052b5226fSChristian Engelmayer 	 || devattr == &sensor_dev_attr_fan1_fault.dev_attr
57152b5226fSChristian Engelmayer 	 || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
57252b5226fSChristian Engelmayer 	 || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
57352b5226fSChristian Engelmayer 		if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
57452b5226fSChristian Engelmayer 			return 0;
57552b5226fSChristian Engelmayer 	}
57652b5226fSChristian Engelmayer 
57752b5226fSChristian Engelmayer 	return a->mode;
57852b5226fSChristian Engelmayer }
579d20620deSHans-Juergen Koch 
580d20620deSHans-Juergen Koch static struct attribute *max6650_attrs[] = {
581d20620deSHans-Juergen Koch 	&sensor_dev_attr_fan1_input.dev_attr.attr,
582d20620deSHans-Juergen Koch 	&dev_attr_fan1_target.attr,
583d20620deSHans-Juergen Koch 	&dev_attr_fan1_div.attr,
584d20620deSHans-Juergen Koch 	&dev_attr_pwm1_enable.attr,
585d20620deSHans-Juergen Koch 	&dev_attr_pwm1.attr,
58652b5226fSChristian Engelmayer 	&sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
58752b5226fSChristian Engelmayer 	&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
58852b5226fSChristian Engelmayer 	&sensor_dev_attr_fan1_fault.dev_attr.attr,
58952b5226fSChristian Engelmayer 	&sensor_dev_attr_gpio1_alarm.dev_attr.attr,
59052b5226fSChristian Engelmayer 	&sensor_dev_attr_gpio2_alarm.dev_attr.attr,
591d20620deSHans-Juergen Koch 	NULL
592d20620deSHans-Juergen Koch };
593d20620deSHans-Juergen Koch 
59417eaa25cSGuenter Roeck static const struct attribute_group max6650_group = {
595d20620deSHans-Juergen Koch 	.attrs = max6650_attrs,
59652b5226fSChristian Engelmayer 	.is_visible = max6650_attrs_visible,
597d20620deSHans-Juergen Koch };
598d20620deSHans-Juergen Koch 
5999c084daeSJean Delvare static struct attribute *max6651_attrs[] = {
6009c084daeSJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
6019c084daeSJean Delvare 	&sensor_dev_attr_fan3_input.dev_attr.attr,
6029c084daeSJean Delvare 	&sensor_dev_attr_fan4_input.dev_attr.attr,
6039c084daeSJean Delvare 	NULL
6049c084daeSJean Delvare };
6059c084daeSJean Delvare 
60617eaa25cSGuenter Roeck static const struct attribute_group max6651_group = {
6079c084daeSJean Delvare 	.attrs = max6651_attrs,
6089c084daeSJean Delvare };
6099c084daeSJean Delvare 
610d20620deSHans-Juergen Koch /*
611d20620deSHans-Juergen Koch  * Real code
612d20620deSHans-Juergen Koch  */
613d20620deSHans-Juergen Koch 
61417eaa25cSGuenter Roeck static int max6650_init_client(struct max6650_data *data,
61517eaa25cSGuenter Roeck 			       struct i2c_client *client)
616d20620deSHans-Juergen Koch {
61771ba0f31SGuenter Roeck 	struct device *dev = &client->dev;
618d20620deSHans-Juergen Koch 	int config;
619d20620deSHans-Juergen Koch 	int err = -EIO;
620a6cdeefeSMike Looijmans 	u32 voltage;
621a6cdeefeSMike Looijmans 	u32 prescale;
62220005cc5SMike Looijmans 	u32 target_rpm;
623a6cdeefeSMike Looijmans 
624a6cdeefeSMike Looijmans 	if (of_property_read_u32(dev->of_node, "maxim,fan-microvolt",
625a6cdeefeSMike Looijmans 				 &voltage))
626a6cdeefeSMike Looijmans 		voltage = fan_voltage;
627a6cdeefeSMike Looijmans 	else
628a6cdeefeSMike Looijmans 		voltage /= 1000000; /* Microvolts to volts */
629a6cdeefeSMike Looijmans 	if (of_property_read_u32(dev->of_node, "maxim,fan-prescale",
630a6cdeefeSMike Looijmans 				 &prescale))
631a6cdeefeSMike Looijmans 		prescale = prescaler;
632d20620deSHans-Juergen Koch 
633d20620deSHans-Juergen Koch 	config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
634d20620deSHans-Juergen Koch 
635d20620deSHans-Juergen Koch 	if (config < 0) {
63671ba0f31SGuenter Roeck 		dev_err(dev, "Error reading config, aborting.\n");
637d20620deSHans-Juergen Koch 		return err;
638d20620deSHans-Juergen Koch 	}
639d20620deSHans-Juergen Koch 
640a6cdeefeSMike Looijmans 	switch (voltage) {
641d20620deSHans-Juergen Koch 	case 0:
642d20620deSHans-Juergen Koch 		break;
643d20620deSHans-Juergen Koch 	case 5:
644d20620deSHans-Juergen Koch 		config &= ~MAX6650_CFG_V12;
645d20620deSHans-Juergen Koch 		break;
646d20620deSHans-Juergen Koch 	case 12:
647d20620deSHans-Juergen Koch 		config |= MAX6650_CFG_V12;
648d20620deSHans-Juergen Koch 		break;
649d20620deSHans-Juergen Koch 	default:
650a6cdeefeSMike Looijmans 		dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);
651d20620deSHans-Juergen Koch 	}
652d20620deSHans-Juergen Koch 
653a6cdeefeSMike Looijmans 	switch (prescale) {
654d20620deSHans-Juergen Koch 	case 0:
655d20620deSHans-Juergen Koch 		break;
656d20620deSHans-Juergen Koch 	case 1:
657d20620deSHans-Juergen Koch 		config &= ~MAX6650_CFG_PRESCALER_MASK;
658d20620deSHans-Juergen Koch 		break;
659d20620deSHans-Juergen Koch 	case 2:
660d20620deSHans-Juergen Koch 		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
661d20620deSHans-Juergen Koch 			 | MAX6650_CFG_PRESCALER_2;
662d20620deSHans-Juergen Koch 		break;
663d20620deSHans-Juergen Koch 	case  4:
664d20620deSHans-Juergen Koch 		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
665d20620deSHans-Juergen Koch 			 | MAX6650_CFG_PRESCALER_4;
666d20620deSHans-Juergen Koch 		break;
667d20620deSHans-Juergen Koch 	case  8:
668d20620deSHans-Juergen Koch 		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
669d20620deSHans-Juergen Koch 			 | MAX6650_CFG_PRESCALER_8;
670d20620deSHans-Juergen Koch 		break;
671d20620deSHans-Juergen Koch 	case 16:
672d20620deSHans-Juergen Koch 		config = (config & ~MAX6650_CFG_PRESCALER_MASK)
673d20620deSHans-Juergen Koch 			 | MAX6650_CFG_PRESCALER_16;
674d20620deSHans-Juergen Koch 		break;
675d20620deSHans-Juergen Koch 	default:
676a6cdeefeSMike Looijmans 		dev_err(dev, "illegal value for prescaler (%d)\n", prescale);
677d20620deSHans-Juergen Koch 	}
678d20620deSHans-Juergen Koch 
679a6cdeefeSMike Looijmans 	dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",
680a6cdeefeSMike Looijmans 		 (config & MAX6650_CFG_V12) ? 12 : 5,
681d20620deSHans-Juergen Koch 		 1 << (config & MAX6650_CFG_PRESCALER_MASK));
682d20620deSHans-Juergen Koch 
683d20620deSHans-Juergen Koch 	if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
68471ba0f31SGuenter Roeck 		dev_err(dev, "Config write error, aborting.\n");
685d20620deSHans-Juergen Koch 		return err;
686d20620deSHans-Juergen Koch 	}
687d20620deSHans-Juergen Koch 
688d20620deSHans-Juergen Koch 	data->config = config;
689d20620deSHans-Juergen Koch 	data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
690d20620deSHans-Juergen Koch 
69120005cc5SMike Looijmans 	if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",
69220005cc5SMike Looijmans 				  &target_rpm)) {
69320005cc5SMike Looijmans 		max6650_set_target(data, target_rpm);
69420005cc5SMike Looijmans 		max6650_set_operating_mode(data, MAX6650_CFG_MODE_CLOSED_LOOP);
69520005cc5SMike Looijmans 	}
69620005cc5SMike Looijmans 
697d20620deSHans-Juergen Koch 	return 0;
698d20620deSHans-Juergen Koch }
699d20620deSHans-Juergen Koch 
7004f8d374bSJean-Francois Dagenais #if IS_ENABLED(CONFIG_THERMAL)
7014f8d374bSJean-Francois Dagenais 
7024f8d374bSJean-Francois Dagenais static int max6650_get_max_state(struct thermal_cooling_device *cdev,
7034f8d374bSJean-Francois Dagenais 				 unsigned long *state)
7044f8d374bSJean-Francois Dagenais {
7054f8d374bSJean-Francois Dagenais 	*state = 255;
7064f8d374bSJean-Francois Dagenais 
7074f8d374bSJean-Francois Dagenais 	return 0;
7084f8d374bSJean-Francois Dagenais }
7094f8d374bSJean-Francois Dagenais 
7104f8d374bSJean-Francois Dagenais static int max6650_get_cur_state(struct thermal_cooling_device *cdev,
7114f8d374bSJean-Francois Dagenais 				 unsigned long *state)
7124f8d374bSJean-Francois Dagenais {
7134f8d374bSJean-Francois Dagenais 	struct max6650_data *data = cdev->devdata;
7144f8d374bSJean-Francois Dagenais 
7154f8d374bSJean-Francois Dagenais 	*state = data->cooling_dev_state;
7164f8d374bSJean-Francois Dagenais 
7174f8d374bSJean-Francois Dagenais 	return 0;
7184f8d374bSJean-Francois Dagenais }
7194f8d374bSJean-Francois Dagenais 
7204f8d374bSJean-Francois Dagenais static int max6650_set_cur_state(struct thermal_cooling_device *cdev,
7214f8d374bSJean-Francois Dagenais 				 unsigned long state)
7224f8d374bSJean-Francois Dagenais {
7234f8d374bSJean-Francois Dagenais 	struct max6650_data *data = cdev->devdata;
7244f8d374bSJean-Francois Dagenais 	struct i2c_client *client = data->client;
7254f8d374bSJean-Francois Dagenais 	int err;
7264f8d374bSJean-Francois Dagenais 
7274f8d374bSJean-Francois Dagenais 	state = clamp_val(state, 0, 255);
7284f8d374bSJean-Francois Dagenais 
7294f8d374bSJean-Francois Dagenais 	mutex_lock(&data->update_lock);
7304f8d374bSJean-Francois Dagenais 
7314f8d374bSJean-Francois Dagenais 	if (data->config & MAX6650_CFG_V12)
7324f8d374bSJean-Francois Dagenais 		data->dac = 180 - (180 * state)/255;
7334f8d374bSJean-Francois Dagenais 	else
7344f8d374bSJean-Francois Dagenais 		data->dac = 76 - (76 * state)/255;
7354f8d374bSJean-Francois Dagenais 
7364f8d374bSJean-Francois Dagenais 	err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
7374f8d374bSJean-Francois Dagenais 
7384f8d374bSJean-Francois Dagenais 	if (!err) {
7394f8d374bSJean-Francois Dagenais 		max6650_set_operating_mode(data, state ?
7404f8d374bSJean-Francois Dagenais 						   MAX6650_CFG_MODE_OPEN_LOOP :
7414f8d374bSJean-Francois Dagenais 						   MAX6650_CFG_MODE_OFF);
7424f8d374bSJean-Francois Dagenais 		data->cooling_dev_state = state;
7434f8d374bSJean-Francois Dagenais 	}
7444f8d374bSJean-Francois Dagenais 
7454f8d374bSJean-Francois Dagenais 	mutex_unlock(&data->update_lock);
7464f8d374bSJean-Francois Dagenais 
7474f8d374bSJean-Francois Dagenais 	return err < 0 ? err : 0;
7484f8d374bSJean-Francois Dagenais }
7494f8d374bSJean-Francois Dagenais 
7504f8d374bSJean-Francois Dagenais static const struct thermal_cooling_device_ops max6650_cooling_ops = {
7514f8d374bSJean-Francois Dagenais 	.get_max_state = max6650_get_max_state,
7524f8d374bSJean-Francois Dagenais 	.get_cur_state = max6650_get_cur_state,
7534f8d374bSJean-Francois Dagenais 	.set_cur_state = max6650_set_cur_state,
7544f8d374bSJean-Francois Dagenais };
7554f8d374bSJean-Francois Dagenais #endif
7564f8d374bSJean-Francois Dagenais 
7571577f94bSGuenter Roeck static int max6650_probe(struct i2c_client *client,
7581577f94bSGuenter Roeck 			 const struct i2c_device_id *id)
759d20620deSHans-Juergen Koch {
76071ba0f31SGuenter Roeck 	struct device *dev = &client->dev;
761a6cdeefeSMike Looijmans 	const struct of_device_id *of_id =
762a6cdeefeSMike Looijmans 		of_match_device(of_match_ptr(max6650_dt_match), dev);
7631577f94bSGuenter Roeck 	struct max6650_data *data;
76417eaa25cSGuenter Roeck 	struct device *hwmon_dev;
7651577f94bSGuenter Roeck 	int err;
766d20620deSHans-Juergen Koch 
76771ba0f31SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);
7680b5e33b6SGuenter Roeck 	if (!data)
7691577f94bSGuenter Roeck 		return -ENOMEM;
7701577f94bSGuenter Roeck 
77117eaa25cSGuenter Roeck 	data->client = client;
7724f8d374bSJean-Francois Dagenais 	i2c_set_clientdata(client, data);
7731577f94bSGuenter Roeck 	mutex_init(&data->update_lock);
774a6cdeefeSMike Looijmans 	data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : id->driver_data;
775d20620deSHans-Juergen Koch 
776703af960SGuenter Roeck 	/*
7771577f94bSGuenter Roeck 	 * Initialize the max6650 chip
778703af960SGuenter Roeck 	 */
77917eaa25cSGuenter Roeck 	err = max6650_init_client(data, client);
7801577f94bSGuenter Roeck 	if (err)
7811577f94bSGuenter Roeck 		return err;
78252b5226fSChristian Engelmayer 
78317eaa25cSGuenter Roeck 	data->groups[0] = &max6650_group;
7841577f94bSGuenter Roeck 	/* 3 additional fan inputs for the MAX6651 */
7851577f94bSGuenter Roeck 	if (data->nr_fans == 4)
78617eaa25cSGuenter Roeck 		data->groups[1] = &max6651_group;
787d20620deSHans-Juergen Koch 
78871ba0f31SGuenter Roeck 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
78917eaa25cSGuenter Roeck 							   client->name, data,
79017eaa25cSGuenter Roeck 							   data->groups);
7914f8d374bSJean-Francois Dagenais 	err = PTR_ERR_OR_ZERO(hwmon_dev);
7924f8d374bSJean-Francois Dagenais 	if (err)
7934f8d374bSJean-Francois Dagenais 		return err;
7944f8d374bSJean-Francois Dagenais 
7954f8d374bSJean-Francois Dagenais #if IS_ENABLED(CONFIG_THERMAL)
7964f8d374bSJean-Francois Dagenais 	data->cooling_dev =
7974f8d374bSJean-Francois Dagenais 		thermal_of_cooling_device_register(client->dev.of_node,
7984f8d374bSJean-Francois Dagenais 						   client->name, data,
7994f8d374bSJean-Francois Dagenais 						   &max6650_cooling_ops);
8004f8d374bSJean-Francois Dagenais 	if (IS_ERR(data->cooling_dev))
8014f8d374bSJean-Francois Dagenais 		dev_warn(&client->dev,
8024f8d374bSJean-Francois Dagenais 			 "thermal cooling device register failed: %ld\n",
8034f8d374bSJean-Francois Dagenais 			 PTR_ERR(data->cooling_dev));
8044f8d374bSJean-Francois Dagenais 	else
8054f8d374bSJean-Francois Dagenais 		thermal_cdev_update(data->cooling_dev);
8064f8d374bSJean-Francois Dagenais #endif
8074f8d374bSJean-Francois Dagenais 	return 0;
8084f8d374bSJean-Francois Dagenais }
8094f8d374bSJean-Francois Dagenais 
8104f8d374bSJean-Francois Dagenais static int max6650_remove(struct i2c_client *client)
8114f8d374bSJean-Francois Dagenais {
8124f8d374bSJean-Francois Dagenais 	struct max6650_data *data = i2c_get_clientdata(client);
8134f8d374bSJean-Francois Dagenais 
8144f8d374bSJean-Francois Dagenais 	if (!IS_ERR(data->cooling_dev))
8154f8d374bSJean-Francois Dagenais 		thermal_cooling_device_unregister(data->cooling_dev);
8164f8d374bSJean-Francois Dagenais 
8174f8d374bSJean-Francois Dagenais 	return 0;
8181577f94bSGuenter Roeck }
8191577f94bSGuenter Roeck 
8201577f94bSGuenter Roeck static const struct i2c_device_id max6650_id[] = {
8211577f94bSGuenter Roeck 	{ "max6650", 1 },
8221577f94bSGuenter Roeck 	{ "max6651", 4 },
8231577f94bSGuenter Roeck 	{ }
8241577f94bSGuenter Roeck };
8251577f94bSGuenter Roeck MODULE_DEVICE_TABLE(i2c, max6650_id);
8261577f94bSGuenter Roeck 
8271577f94bSGuenter Roeck static struct i2c_driver max6650_driver = {
8281577f94bSGuenter Roeck 	.driver = {
8291577f94bSGuenter Roeck 		.name	= "max6650",
830a6cdeefeSMike Looijmans 		.of_match_table = of_match_ptr(max6650_dt_match),
8311577f94bSGuenter Roeck 	},
8321577f94bSGuenter Roeck 	.probe		= max6650_probe,
8334f8d374bSJean-Francois Dagenais 	.remove		= max6650_remove,
8341577f94bSGuenter Roeck 	.id_table	= max6650_id,
8351577f94bSGuenter Roeck };
8361577f94bSGuenter Roeck 
837f0967eeaSAxel Lin module_i2c_driver(max6650_driver);
838d20620deSHans-Juergen Koch 
839d20620deSHans-Juergen Koch MODULE_AUTHOR("Hans J. Koch");
840d20620deSHans-Juergen Koch MODULE_DESCRIPTION("MAX6650 sensor driver");
841d20620deSHans-Juergen Koch MODULE_LICENSE("GPL");
842