xref: /openbmc/linux/drivers/hwmon/gl520sm.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
343da3d12SGuenter Roeck  * gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
443da3d12SGuenter Roeck  *	       monitoring
543da3d12SGuenter Roeck  * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
643da3d12SGuenter Roeck  *			     Kyösti Mälkki <kmalkki@cc.hut.fi>
743da3d12SGuenter Roeck  * Copyright (c) 2005	Maarten Deprez <maartendeprez@users.sourceforge.net>
88d5d45fbSJean Delvare  */
98d5d45fbSJean Delvare 
108d5d45fbSJean Delvare #include <linux/module.h>
118d5d45fbSJean Delvare #include <linux/init.h>
128d5d45fbSJean Delvare #include <linux/slab.h>
130cacdf29SJean Delvare #include <linux/jiffies.h>
148d5d45fbSJean Delvare #include <linux/i2c.h>
15943b0830SMark M. Hoffman #include <linux/hwmon.h>
1686d47f12SJean Delvare #include <linux/hwmon-sysfs.h>
17303760b4SJean Delvare #include <linux/hwmon-vid.h>
18943b0830SMark M. Hoffman #include <linux/err.h>
199a61bf63SIngo Molnar #include <linux/mutex.h>
2087808be4SJean Delvare #include <linux/sysfs.h>
218d5d45fbSJean Delvare 
228d5d45fbSJean Delvare /* Type of the extra sensor */
238d5d45fbSJean Delvare static unsigned short extra_sensor_type;
248d5d45fbSJean Delvare module_param(extra_sensor_type, ushort, 0);
258d5d45fbSJean Delvare MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)");
268d5d45fbSJean Delvare 
278d5d45fbSJean Delvare /* Addresses to scan */
2825e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
298d5d45fbSJean Delvare 
3043da3d12SGuenter Roeck /*
3143da3d12SGuenter Roeck  * Many GL520 constants specified below
3243da3d12SGuenter Roeck  * One of the inputs can be configured as either temp or voltage.
3343da3d12SGuenter Roeck  * That's why _TEMP2 and _IN4 access the same register
348d5d45fbSJean Delvare  */
358d5d45fbSJean Delvare 
368d5d45fbSJean Delvare /* The GL520 registers */
378d5d45fbSJean Delvare #define GL520_REG_CHIP_ID		0x00
388d5d45fbSJean Delvare #define GL520_REG_REVISION		0x01
398d5d45fbSJean Delvare #define GL520_REG_CONF			0x03
408d5d45fbSJean Delvare #define GL520_REG_MASK			0x11
418d5d45fbSJean Delvare 
428d5d45fbSJean Delvare #define GL520_REG_VID_INPUT		0x02
438d5d45fbSJean Delvare 
448b4b0ab4SJean Delvare static const u8 GL520_REG_IN_INPUT[]	= { 0x15, 0x14, 0x13, 0x0d, 0x0e };
458b4b0ab4SJean Delvare static const u8 GL520_REG_IN_LIMIT[]	= { 0x0c, 0x09, 0x0a, 0x0b };
468b4b0ab4SJean Delvare static const u8 GL520_REG_IN_MIN[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x18 };
478b4b0ab4SJean Delvare static const u8 GL520_REG_IN_MAX[]	= { 0x0c, 0x09, 0x0a, 0x0b, 0x17 };
488d5d45fbSJean Delvare 
498b4b0ab4SJean Delvare static const u8 GL520_REG_TEMP_INPUT[]		= { 0x04, 0x0e };
508b4b0ab4SJean Delvare static const u8 GL520_REG_TEMP_MAX[]		= { 0x05, 0x17 };
518b4b0ab4SJean Delvare static const u8 GL520_REG_TEMP_MAX_HYST[]	= { 0x06, 0x18 };
528d5d45fbSJean Delvare 
538d5d45fbSJean Delvare #define GL520_REG_FAN_INPUT		0x07
548d5d45fbSJean Delvare #define GL520_REG_FAN_MIN		0x08
558d5d45fbSJean Delvare #define GL520_REG_FAN_DIV		0x0f
568d5d45fbSJean Delvare #define GL520_REG_FAN_OFF		GL520_REG_FAN_DIV
578d5d45fbSJean Delvare 
588d5d45fbSJean Delvare #define GL520_REG_ALARMS		0x12
598d5d45fbSJean Delvare #define GL520_REG_BEEP_MASK		0x10
608d5d45fbSJean Delvare #define GL520_REG_BEEP_ENABLE		GL520_REG_CONF
618d5d45fbSJean Delvare 
628d5d45fbSJean Delvare /* Client data */
638d5d45fbSJean Delvare struct gl520_data {
64d1b9c3f5SAxel Lin 	struct i2c_client *client;
65d1b9c3f5SAxel Lin 	const struct attribute_group *groups[3];
669a61bf63SIngo Molnar 	struct mutex update_lock;
67952a11caSPaul Fertser 	bool valid;		/* false until the following fields are valid */
688d5d45fbSJean Delvare 	unsigned long last_updated;	/* in jiffies */
698d5d45fbSJean Delvare 
708d5d45fbSJean Delvare 	u8 vid;
718d5d45fbSJean Delvare 	u8 vrm;
728d5d45fbSJean Delvare 	u8 in_input[5];		/* [0] = VVD */
738d5d45fbSJean Delvare 	u8 in_min[5];		/* [0] = VDD */
748d5d45fbSJean Delvare 	u8 in_max[5];		/* [0] = VDD */
758d5d45fbSJean Delvare 	u8 fan_input[2];
768d5d45fbSJean Delvare 	u8 fan_min[2];
778d5d45fbSJean Delvare 	u8 fan_div[2];
788d5d45fbSJean Delvare 	u8 fan_off;
798d5d45fbSJean Delvare 	u8 temp_input[2];
808d5d45fbSJean Delvare 	u8 temp_max[2];
818d5d45fbSJean Delvare 	u8 temp_max_hyst[2];
828d5d45fbSJean Delvare 	u8 alarms;
838d5d45fbSJean Delvare 	u8 beep_enable;
848d5d45fbSJean Delvare 	u8 beep_mask;
858d5d45fbSJean Delvare 	u8 alarm_mask;
868d5d45fbSJean Delvare 	u8 two_temps;
878d5d45fbSJean Delvare };
888d5d45fbSJean Delvare 
898d5d45fbSJean Delvare /*
90df51f2d7SAxel Lin  * Registers 0x07 to 0x0c are word-sized, others are byte-sized
91df51f2d7SAxel Lin  * GL520 uses a high-byte first convention
92df51f2d7SAxel Lin  */
gl520_read_value(struct i2c_client * client,u8 reg)93df51f2d7SAxel Lin static int gl520_read_value(struct i2c_client *client, u8 reg)
94df51f2d7SAxel Lin {
95df51f2d7SAxel Lin 	if ((reg >= 0x07) && (reg <= 0x0c))
96df51f2d7SAxel Lin 		return i2c_smbus_read_word_swapped(client, reg);
97df51f2d7SAxel Lin 	else
98df51f2d7SAxel Lin 		return i2c_smbus_read_byte_data(client, reg);
99df51f2d7SAxel Lin }
100df51f2d7SAxel Lin 
gl520_write_value(struct i2c_client * client,u8 reg,u16 value)101df51f2d7SAxel Lin static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
102df51f2d7SAxel Lin {
103df51f2d7SAxel Lin 	if ((reg >= 0x07) && (reg <= 0x0c))
104df51f2d7SAxel Lin 		return i2c_smbus_write_word_swapped(client, reg, value);
105df51f2d7SAxel Lin 	else
106df51f2d7SAxel Lin 		return i2c_smbus_write_byte_data(client, reg, value);
107df51f2d7SAxel Lin }
108df51f2d7SAxel Lin 
gl520_update_device(struct device * dev)109df51f2d7SAxel Lin static struct gl520_data *gl520_update_device(struct device *dev)
110df51f2d7SAxel Lin {
111d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
112d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
113df51f2d7SAxel Lin 	int val, i;
114df51f2d7SAxel Lin 
115df51f2d7SAxel Lin 	mutex_lock(&data->update_lock);
116df51f2d7SAxel Lin 
117df51f2d7SAxel Lin 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
118df51f2d7SAxel Lin 
119df51f2d7SAxel Lin 		dev_dbg(&client->dev, "Starting gl520sm update\n");
120df51f2d7SAxel Lin 
121df51f2d7SAxel Lin 		data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
122df51f2d7SAxel Lin 		data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
123df51f2d7SAxel Lin 		data->vid = gl520_read_value(client,
124df51f2d7SAxel Lin 					     GL520_REG_VID_INPUT) & 0x1f;
125df51f2d7SAxel Lin 
126df51f2d7SAxel Lin 		for (i = 0; i < 4; i++) {
127df51f2d7SAxel Lin 			data->in_input[i] = gl520_read_value(client,
128df51f2d7SAxel Lin 							GL520_REG_IN_INPUT[i]);
129df51f2d7SAxel Lin 			val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
130df51f2d7SAxel Lin 			data->in_min[i] = val & 0xff;
131df51f2d7SAxel Lin 			data->in_max[i] = (val >> 8) & 0xff;
132df51f2d7SAxel Lin 		}
133df51f2d7SAxel Lin 
134df51f2d7SAxel Lin 		val = gl520_read_value(client, GL520_REG_FAN_INPUT);
135df51f2d7SAxel Lin 		data->fan_input[0] = (val >> 8) & 0xff;
136df51f2d7SAxel Lin 		data->fan_input[1] = val & 0xff;
137df51f2d7SAxel Lin 
138df51f2d7SAxel Lin 		val = gl520_read_value(client, GL520_REG_FAN_MIN);
139df51f2d7SAxel Lin 		data->fan_min[0] = (val >> 8) & 0xff;
140df51f2d7SAxel Lin 		data->fan_min[1] = val & 0xff;
141df51f2d7SAxel Lin 
142df51f2d7SAxel Lin 		data->temp_input[0] = gl520_read_value(client,
143df51f2d7SAxel Lin 						GL520_REG_TEMP_INPUT[0]);
144df51f2d7SAxel Lin 		data->temp_max[0] = gl520_read_value(client,
145df51f2d7SAxel Lin 						GL520_REG_TEMP_MAX[0]);
146df51f2d7SAxel Lin 		data->temp_max_hyst[0] = gl520_read_value(client,
147df51f2d7SAxel Lin 						GL520_REG_TEMP_MAX_HYST[0]);
148df51f2d7SAxel Lin 
149df51f2d7SAxel Lin 		val = gl520_read_value(client, GL520_REG_FAN_DIV);
150df51f2d7SAxel Lin 		data->fan_div[0] = (val >> 6) & 0x03;
151df51f2d7SAxel Lin 		data->fan_div[1] = (val >> 4) & 0x03;
152df51f2d7SAxel Lin 		data->fan_off = (val >> 2) & 0x01;
153df51f2d7SAxel Lin 
154df51f2d7SAxel Lin 		data->alarms &= data->alarm_mask;
155df51f2d7SAxel Lin 
156df51f2d7SAxel Lin 		val = gl520_read_value(client, GL520_REG_CONF);
157df51f2d7SAxel Lin 		data->beep_enable = !((val >> 2) & 1);
158df51f2d7SAxel Lin 
159df51f2d7SAxel Lin 		/* Temp1 and Vin4 are the same input */
160df51f2d7SAxel Lin 		if (data->two_temps) {
161df51f2d7SAxel Lin 			data->temp_input[1] = gl520_read_value(client,
162df51f2d7SAxel Lin 						GL520_REG_TEMP_INPUT[1]);
163df51f2d7SAxel Lin 			data->temp_max[1] = gl520_read_value(client,
164df51f2d7SAxel Lin 						GL520_REG_TEMP_MAX[1]);
165df51f2d7SAxel Lin 			data->temp_max_hyst[1] = gl520_read_value(client,
166df51f2d7SAxel Lin 						GL520_REG_TEMP_MAX_HYST[1]);
167df51f2d7SAxel Lin 		} else {
168df51f2d7SAxel Lin 			data->in_input[4] = gl520_read_value(client,
169df51f2d7SAxel Lin 						GL520_REG_IN_INPUT[4]);
170df51f2d7SAxel Lin 			data->in_min[4] = gl520_read_value(client,
171df51f2d7SAxel Lin 						GL520_REG_IN_MIN[4]);
172df51f2d7SAxel Lin 			data->in_max[4] = gl520_read_value(client,
173df51f2d7SAxel Lin 						GL520_REG_IN_MAX[4]);
174df51f2d7SAxel Lin 		}
175df51f2d7SAxel Lin 
176df51f2d7SAxel Lin 		data->last_updated = jiffies;
177952a11caSPaul Fertser 		data->valid = true;
178df51f2d7SAxel Lin 	}
179df51f2d7SAxel Lin 
180df51f2d7SAxel Lin 	mutex_unlock(&data->update_lock);
181df51f2d7SAxel Lin 
182df51f2d7SAxel Lin 	return data;
183df51f2d7SAxel Lin }
184df51f2d7SAxel Lin 
185df51f2d7SAxel Lin /*
1868d5d45fbSJean Delvare  * Sysfs stuff
1878d5d45fbSJean Delvare  */
1888d5d45fbSJean Delvare 
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)1892579b7ffSJulia Lawall static ssize_t cpu0_vid_show(struct device *dev,
1902579b7ffSJulia Lawall 			     struct device_attribute *attr, char *buf)
1918d5d45fbSJean Delvare {
19286d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
1938d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
1948d5d45fbSJean Delvare }
1952579b7ffSJulia Lawall static DEVICE_ATTR_RO(cpu0_vid);
1968d5d45fbSJean Delvare 
19787cdfa9dSGuenter Roeck #define VDD_FROM_REG(val)	DIV_ROUND_CLOSEST((val) * 95, 4)
19887cdfa9dSGuenter Roeck #define VDD_CLAMP(val)		clamp_val(val, 0, 255 * 95 / 4)
19987cdfa9dSGuenter Roeck #define VDD_TO_REG(val)		DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95)
2008d5d45fbSJean Delvare 
2018d5d45fbSJean Delvare #define IN_FROM_REG(val)	((val) * 19)
20287cdfa9dSGuenter Roeck #define IN_CLAMP(val)		clamp_val(val, 0, 255 * 19)
20387cdfa9dSGuenter Roeck #define IN_TO_REG(val)		DIV_ROUND_CLOSEST(IN_CLAMP(val), 19)
2048d5d45fbSJean Delvare 
in_input_show(struct device * dev,struct device_attribute * attr,char * buf)20517de1a88SGuenter Roeck static ssize_t in_input_show(struct device *dev,
20617de1a88SGuenter Roeck 			     struct device_attribute *attr, char *buf)
2078d5d45fbSJean Delvare {
20886d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
20986d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
2108d5d45fbSJean Delvare 	u8 r = data->in_input[n];
2118d5d45fbSJean Delvare 
2128d5d45fbSJean Delvare 	if (n == 0)
2138d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
2148d5d45fbSJean Delvare 	else
2158d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", IN_FROM_REG(r));
2168d5d45fbSJean Delvare }
2178d5d45fbSJean Delvare 
in_min_show(struct device * dev,struct device_attribute * attr,char * buf)21817de1a88SGuenter Roeck static ssize_t in_min_show(struct device *dev, struct device_attribute *attr,
21986d47f12SJean Delvare 			   char *buf)
2208d5d45fbSJean Delvare {
22186d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
22286d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
2238d5d45fbSJean Delvare 	u8 r = data->in_min[n];
2248d5d45fbSJean Delvare 
2258d5d45fbSJean Delvare 	if (n == 0)
2268d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
2278d5d45fbSJean Delvare 	else
2288d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", IN_FROM_REG(r));
2298d5d45fbSJean Delvare }
2308d5d45fbSJean Delvare 
in_max_show(struct device * dev,struct device_attribute * attr,char * buf)23117de1a88SGuenter Roeck static ssize_t in_max_show(struct device *dev, struct device_attribute *attr,
23286d47f12SJean Delvare 			   char *buf)
2338d5d45fbSJean Delvare {
23486d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
23586d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
2368d5d45fbSJean Delvare 	u8 r = data->in_max[n];
2378d5d45fbSJean Delvare 
2388d5d45fbSJean Delvare 	if (n == 0)
2398d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", VDD_FROM_REG(r));
2408d5d45fbSJean Delvare 	else
2418d5d45fbSJean Delvare 		return sprintf(buf, "%d\n", IN_FROM_REG(r));
2428d5d45fbSJean Delvare }
2438d5d45fbSJean Delvare 
in_min_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)24417de1a88SGuenter Roeck static ssize_t in_min_store(struct device *dev, struct device_attribute *attr,
24586d47f12SJean Delvare 			    const char *buf, size_t count)
2468d5d45fbSJean Delvare {
247d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
248d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
24986d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
2508d5d45fbSJean Delvare 	u8 r;
25143da3d12SGuenter Roeck 	long v;
25243da3d12SGuenter Roeck 	int err;
25343da3d12SGuenter Roeck 
25443da3d12SGuenter Roeck 	err = kstrtol(buf, 10, &v);
25543da3d12SGuenter Roeck 	if (err)
25643da3d12SGuenter Roeck 		return err;
2578d5d45fbSJean Delvare 
2589a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
2598d5d45fbSJean Delvare 
2608d5d45fbSJean Delvare 	if (n == 0)
2618d5d45fbSJean Delvare 		r = VDD_TO_REG(v);
2628d5d45fbSJean Delvare 	else
2638d5d45fbSJean Delvare 		r = IN_TO_REG(v);
2648d5d45fbSJean Delvare 
2658d5d45fbSJean Delvare 	data->in_min[n] = r;
2668d5d45fbSJean Delvare 
2678d5d45fbSJean Delvare 	if (n < 4)
26886d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_IN_MIN[n],
26986d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_IN_MIN[n])
27086d47f12SJean Delvare 				   & ~0xff) | r);
2718d5d45fbSJean Delvare 	else
27286d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_IN_MIN[n], r);
2738d5d45fbSJean Delvare 
2749a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
2758d5d45fbSJean Delvare 	return count;
2768d5d45fbSJean Delvare }
2778d5d45fbSJean Delvare 
in_max_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)27817de1a88SGuenter Roeck static ssize_t in_max_store(struct device *dev, struct device_attribute *attr,
27986d47f12SJean Delvare 			    const char *buf, size_t count)
2808d5d45fbSJean Delvare {
281d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
282d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
28386d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
2848d5d45fbSJean Delvare 	u8 r;
28543da3d12SGuenter Roeck 	long v;
28643da3d12SGuenter Roeck 	int err;
28743da3d12SGuenter Roeck 
28843da3d12SGuenter Roeck 	err = kstrtol(buf, 10, &v);
28943da3d12SGuenter Roeck 	if (err)
29043da3d12SGuenter Roeck 		return err;
2918d5d45fbSJean Delvare 
2928d5d45fbSJean Delvare 	if (n == 0)
2938d5d45fbSJean Delvare 		r = VDD_TO_REG(v);
2948d5d45fbSJean Delvare 	else
2958d5d45fbSJean Delvare 		r = IN_TO_REG(v);
2968d5d45fbSJean Delvare 
2979a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
2988d5d45fbSJean Delvare 
2998d5d45fbSJean Delvare 	data->in_max[n] = r;
3008d5d45fbSJean Delvare 
3018d5d45fbSJean Delvare 	if (n < 4)
30286d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_IN_MAX[n],
30386d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_IN_MAX[n])
30486d47f12SJean Delvare 				   & ~0xff00) | (r << 8));
3058d5d45fbSJean Delvare 	else
30686d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_IN_MAX[n], r);
3078d5d45fbSJean Delvare 
3089a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3098d5d45fbSJean Delvare 	return count;
3108d5d45fbSJean Delvare }
3118d5d45fbSJean Delvare 
31217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, in_input, 0);
31317de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 1);
31417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_input, in_input, 2);
31517de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, in_input, 3);
31617de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, in_input, 4);
31717de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
31817de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
31917de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
32017de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
32117de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
32217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
32317de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
32417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
32517de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
32617de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
32786d47f12SJean Delvare 
3288d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
3298d5d45fbSJean Delvare #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
33087cdfa9dSGuenter Roeck 
33187cdfa9dSGuenter Roeck #define FAN_BASE(div)		(480000 >> (div))
33287cdfa9dSGuenter Roeck #define FAN_CLAMP(val, div)	clamp_val(val, FAN_BASE(div) / 255, \
33387cdfa9dSGuenter Roeck 					  FAN_BASE(div))
33487cdfa9dSGuenter Roeck #define FAN_TO_REG(val, div)	((val) == 0 ? 0 : \
33587cdfa9dSGuenter Roeck 				 DIV_ROUND_CLOSEST(480000, \
33687cdfa9dSGuenter Roeck 						FAN_CLAMP(val, div) << (div)))
3378d5d45fbSJean Delvare 
fan_input_show(struct device * dev,struct device_attribute * attr,char * buf)33817de1a88SGuenter Roeck static ssize_t fan_input_show(struct device *dev,
33917de1a88SGuenter Roeck 			      struct device_attribute *attr, char *buf)
3408d5d45fbSJean Delvare {
34186d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
34286d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
34386d47f12SJean Delvare 
34486d47f12SJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n],
34586d47f12SJean Delvare 						 data->fan_div[n]));
3468d5d45fbSJean Delvare }
3478d5d45fbSJean Delvare 
fan_min_show(struct device * dev,struct device_attribute * attr,char * buf)34817de1a88SGuenter Roeck static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
34986d47f12SJean Delvare 			    char *buf)
3508d5d45fbSJean Delvare {
35186d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
35286d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
35386d47f12SJean Delvare 
35486d47f12SJean Delvare 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n],
35586d47f12SJean Delvare 						 data->fan_div[n]));
3568d5d45fbSJean Delvare }
3578d5d45fbSJean Delvare 
fan_div_show(struct device * dev,struct device_attribute * attr,char * buf)35817de1a88SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *attr,
35986d47f12SJean Delvare 			    char *buf)
3608d5d45fbSJean Delvare {
36186d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
36286d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
36386d47f12SJean Delvare 
36486d47f12SJean Delvare 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n]));
3658d5d45fbSJean Delvare }
3668d5d45fbSJean Delvare 
fan1_off_show(struct device * dev,struct device_attribute * attr,char * buf)3672579b7ffSJulia Lawall static ssize_t fan1_off_show(struct device *dev,
3682579b7ffSJulia Lawall 			     struct device_attribute *attr, char *buf)
3698d5d45fbSJean Delvare {
37086d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
3718d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->fan_off);
3728d5d45fbSJean Delvare }
3738d5d45fbSJean Delvare 
fan_min_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)37417de1a88SGuenter Roeck static ssize_t fan_min_store(struct device *dev,
37517de1a88SGuenter Roeck 			     struct device_attribute *attr, const char *buf,
37617de1a88SGuenter Roeck 			     size_t count)
3778d5d45fbSJean Delvare {
378d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
379d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
38086d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
3818d5d45fbSJean Delvare 	u8 r;
38243da3d12SGuenter Roeck 	unsigned long v;
38343da3d12SGuenter Roeck 	int err;
38443da3d12SGuenter Roeck 
38543da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &v);
38643da3d12SGuenter Roeck 	if (err)
38743da3d12SGuenter Roeck 		return err;
3888d5d45fbSJean Delvare 
3899a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
39086d47f12SJean Delvare 	r = FAN_TO_REG(v, data->fan_div[n]);
39186d47f12SJean Delvare 	data->fan_min[n] = r;
3928d5d45fbSJean Delvare 
39386d47f12SJean Delvare 	if (n == 0)
39486d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_FAN_MIN,
39586d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_FAN_MIN)
39686d47f12SJean Delvare 				   & ~0xff00) | (r << 8));
3978d5d45fbSJean Delvare 	else
39886d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_FAN_MIN,
39986d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_FAN_MIN)
40086d47f12SJean Delvare 				   & ~0xff) | r);
4018d5d45fbSJean Delvare 
4028d5d45fbSJean Delvare 	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
40386d47f12SJean Delvare 	if (data->fan_min[n] == 0)
40486d47f12SJean Delvare 		data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
4058d5d45fbSJean Delvare 	else
40686d47f12SJean Delvare 		data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
4078d5d45fbSJean Delvare 	data->beep_mask &= data->alarm_mask;
4088d5d45fbSJean Delvare 	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
4098d5d45fbSJean Delvare 
4109a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4118d5d45fbSJean Delvare 	return count;
4128d5d45fbSJean Delvare }
4138d5d45fbSJean Delvare 
fan_div_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)41417de1a88SGuenter Roeck static ssize_t fan_div_store(struct device *dev,
41517de1a88SGuenter Roeck 			     struct device_attribute *attr, const char *buf,
41617de1a88SGuenter Roeck 			     size_t count)
4178d5d45fbSJean Delvare {
418d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
419d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
42086d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
4218d5d45fbSJean Delvare 	u8 r;
42243da3d12SGuenter Roeck 	unsigned long v;
42343da3d12SGuenter Roeck 	int err;
42443da3d12SGuenter Roeck 
42543da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &v);
42643da3d12SGuenter Roeck 	if (err)
42743da3d12SGuenter Roeck 		return err;
4288d5d45fbSJean Delvare 
4298d5d45fbSJean Delvare 	switch (v) {
43043da3d12SGuenter Roeck 	case 1:
43143da3d12SGuenter Roeck 		r = 0;
43243da3d12SGuenter Roeck 		break;
43343da3d12SGuenter Roeck 	case 2:
43443da3d12SGuenter Roeck 		r = 1;
43543da3d12SGuenter Roeck 		break;
43643da3d12SGuenter Roeck 	case 4:
43743da3d12SGuenter Roeck 		r = 2;
43843da3d12SGuenter Roeck 		break;
43943da3d12SGuenter Roeck 	case 8:
44043da3d12SGuenter Roeck 		r = 3;
44143da3d12SGuenter Roeck 		break;
4428d5d45fbSJean Delvare 	default:
44343da3d12SGuenter Roeck 		dev_err(&client->dev,
44443da3d12SGuenter Roeck 	"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v);
4458d5d45fbSJean Delvare 		return -EINVAL;
4468d5d45fbSJean Delvare 	}
4478d5d45fbSJean Delvare 
4489a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
44986d47f12SJean Delvare 	data->fan_div[n] = r;
4508d5d45fbSJean Delvare 
45186d47f12SJean Delvare 	if (n == 0)
45286d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_FAN_DIV,
45386d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_FAN_DIV)
45486d47f12SJean Delvare 				   & ~0xc0) | (r << 6));
4558d5d45fbSJean Delvare 	else
45686d47f12SJean Delvare 		gl520_write_value(client, GL520_REG_FAN_DIV,
45786d47f12SJean Delvare 				  (gl520_read_value(client, GL520_REG_FAN_DIV)
45886d47f12SJean Delvare 				   & ~0x30) | (r << 4));
4598d5d45fbSJean Delvare 
4609a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4618d5d45fbSJean Delvare 	return count;
4628d5d45fbSJean Delvare }
4638d5d45fbSJean Delvare 
fan1_off_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4642579b7ffSJulia Lawall static ssize_t fan1_off_store(struct device *dev,
4652579b7ffSJulia Lawall 			      struct device_attribute *attr, const char *buf,
4662579b7ffSJulia Lawall 			      size_t count)
4678d5d45fbSJean Delvare {
468d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
469d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
47043da3d12SGuenter Roeck 	u8 r;
47143da3d12SGuenter Roeck 	unsigned long v;
47243da3d12SGuenter Roeck 	int err;
47343da3d12SGuenter Roeck 
47443da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &v);
47543da3d12SGuenter Roeck 	if (err)
47643da3d12SGuenter Roeck 		return err;
47743da3d12SGuenter Roeck 
47843da3d12SGuenter Roeck 	r = (v ? 1 : 0);
4798d5d45fbSJean Delvare 
4809a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
4818d5d45fbSJean Delvare 	data->fan_off = r;
48286d47f12SJean Delvare 	gl520_write_value(client, GL520_REG_FAN_OFF,
48386d47f12SJean Delvare 			  (gl520_read_value(client, GL520_REG_FAN_OFF)
48486d47f12SJean Delvare 			   & ~0x0c) | (r << 2));
4859a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
4868d5d45fbSJean Delvare 	return count;
4878d5d45fbSJean Delvare }
4888d5d45fbSJean Delvare 
48917de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0);
49017de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1);
49117de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
49217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
49317de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
49417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
4952579b7ffSJulia Lawall static DEVICE_ATTR_RW(fan1_off);
49686d47f12SJean Delvare 
4978d5d45fbSJean Delvare #define TEMP_FROM_REG(val)	(((val) - 130) * 1000)
49887cdfa9dSGuenter Roeck #define TEMP_CLAMP(val)		clamp_val(val, -130000, 125000)
49987cdfa9dSGuenter Roeck #define TEMP_TO_REG(val)	(DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 130)
5008d5d45fbSJean Delvare 
temp_input_show(struct device * dev,struct device_attribute * attr,char * buf)50117de1a88SGuenter Roeck static ssize_t temp_input_show(struct device *dev,
50217de1a88SGuenter Roeck 			       struct device_attribute *attr, char *buf)
5038d5d45fbSJean Delvare {
50486d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
50586d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
50686d47f12SJean Delvare 
50786d47f12SJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n]));
5088d5d45fbSJean Delvare }
5098d5d45fbSJean Delvare 
temp_max_show(struct device * dev,struct device_attribute * attr,char * buf)51017de1a88SGuenter Roeck static ssize_t temp_max_show(struct device *dev,
51117de1a88SGuenter Roeck 			     struct device_attribute *attr, char *buf)
5128d5d45fbSJean Delvare {
51386d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
51486d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
51586d47f12SJean Delvare 
51686d47f12SJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n]));
5178d5d45fbSJean Delvare }
5188d5d45fbSJean Delvare 
temp_max_hyst_show(struct device * dev,struct device_attribute * attr,char * buf)51917de1a88SGuenter Roeck static ssize_t temp_max_hyst_show(struct device *dev,
52043da3d12SGuenter Roeck 				  struct device_attribute *attr, char *buf)
5218d5d45fbSJean Delvare {
52286d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
52386d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
52486d47f12SJean Delvare 
52586d47f12SJean Delvare 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n]));
5268d5d45fbSJean Delvare }
5278d5d45fbSJean Delvare 
temp_max_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)52817de1a88SGuenter Roeck static ssize_t temp_max_store(struct device *dev,
52917de1a88SGuenter Roeck 			      struct device_attribute *attr, const char *buf,
53017de1a88SGuenter Roeck 			      size_t count)
5318d5d45fbSJean Delvare {
532d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
533d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
53486d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
53543da3d12SGuenter Roeck 	long v;
53643da3d12SGuenter Roeck 	int err;
53743da3d12SGuenter Roeck 
53843da3d12SGuenter Roeck 	err = kstrtol(buf, 10, &v);
53943da3d12SGuenter Roeck 	if (err)
54043da3d12SGuenter Roeck 		return err;
5418d5d45fbSJean Delvare 
5429a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
54386d47f12SJean Delvare 	data->temp_max[n] = TEMP_TO_REG(v);
54486d47f12SJean Delvare 	gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]);
5459a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5468d5d45fbSJean Delvare 	return count;
5478d5d45fbSJean Delvare }
5488d5d45fbSJean Delvare 
temp_max_hyst_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)54917de1a88SGuenter Roeck static ssize_t temp_max_hyst_store(struct device *dev,
55017de1a88SGuenter Roeck 				   struct device_attribute *attr,
55117de1a88SGuenter Roeck 				   const char *buf, size_t count)
5528d5d45fbSJean Delvare {
553d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
554d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
55586d47f12SJean Delvare 	int n = to_sensor_dev_attr(attr)->index;
55643da3d12SGuenter Roeck 	long v;
55743da3d12SGuenter Roeck 	int err;
55843da3d12SGuenter Roeck 
55943da3d12SGuenter Roeck 	err = kstrtol(buf, 10, &v);
56043da3d12SGuenter Roeck 	if (err)
56143da3d12SGuenter Roeck 		return err;
5628d5d45fbSJean Delvare 
5639a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
56486d47f12SJean Delvare 	data->temp_max_hyst[n] = TEMP_TO_REG(v);
56586d47f12SJean Delvare 	gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n],
56686d47f12SJean Delvare 			  data->temp_max_hyst[n]);
5679a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
5688d5d45fbSJean Delvare 	return count;
5698d5d45fbSJean Delvare }
5708d5d45fbSJean Delvare 
57117de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
57217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_input, 1);
57317de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
57417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
57517de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp_max_hyst, 0);
57617de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, temp_max_hyst, 1);
57786d47f12SJean Delvare 
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)5782579b7ffSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
57986d47f12SJean Delvare 			   char *buf)
5808d5d45fbSJean Delvare {
58186d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
5828d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->alarms);
5838d5d45fbSJean Delvare }
5848d5d45fbSJean Delvare 
beep_enable_show(struct device * dev,struct device_attribute * attr,char * buf)5852579b7ffSJulia Lawall static ssize_t beep_enable_show(struct device *dev,
5862579b7ffSJulia Lawall 				struct device_attribute *attr, char *buf)
5878d5d45fbSJean Delvare {
58886d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
5898d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->beep_enable);
5908d5d45fbSJean Delvare }
5918d5d45fbSJean Delvare 
beep_mask_show(struct device * dev,struct device_attribute * attr,char * buf)5922579b7ffSJulia Lawall static ssize_t beep_mask_show(struct device *dev,
5932579b7ffSJulia Lawall 			      struct device_attribute *attr, char *buf)
5948d5d45fbSJean Delvare {
59586d47f12SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
5968d5d45fbSJean Delvare 	return sprintf(buf, "%d\n", data->beep_mask);
5978d5d45fbSJean Delvare }
5988d5d45fbSJean Delvare 
beep_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5992579b7ffSJulia Lawall static ssize_t beep_enable_store(struct device *dev,
6002579b7ffSJulia Lawall 				 struct device_attribute *attr,
6012579b7ffSJulia Lawall 				 const char *buf, size_t count)
6028d5d45fbSJean Delvare {
603d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
604d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
60543da3d12SGuenter Roeck 	u8 r;
60643da3d12SGuenter Roeck 	unsigned long v;
60743da3d12SGuenter Roeck 	int err;
60843da3d12SGuenter Roeck 
60943da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &v);
61043da3d12SGuenter Roeck 	if (err)
61143da3d12SGuenter Roeck 		return err;
61243da3d12SGuenter Roeck 
61343da3d12SGuenter Roeck 	r = (v ? 0 : 1);
6148d5d45fbSJean Delvare 
6159a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6168d5d45fbSJean Delvare 	data->beep_enable = !r;
61786d47f12SJean Delvare 	gl520_write_value(client, GL520_REG_BEEP_ENABLE,
61886d47f12SJean Delvare 			  (gl520_read_value(client, GL520_REG_BEEP_ENABLE)
61986d47f12SJean Delvare 			   & ~0x04) | (r << 2));
6209a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6218d5d45fbSJean Delvare 	return count;
6228d5d45fbSJean Delvare }
6238d5d45fbSJean Delvare 
beep_mask_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)6242579b7ffSJulia Lawall static ssize_t beep_mask_store(struct device *dev,
6252579b7ffSJulia Lawall 			       struct device_attribute *attr, const char *buf,
6262579b7ffSJulia Lawall 			       size_t count)
6278d5d45fbSJean Delvare {
628d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
629d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
63043da3d12SGuenter Roeck 	unsigned long r;
63143da3d12SGuenter Roeck 	int err;
63243da3d12SGuenter Roeck 
63343da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &r);
63443da3d12SGuenter Roeck 	if (err)
63543da3d12SGuenter Roeck 		return err;
6368d5d45fbSJean Delvare 
6379a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
6388d5d45fbSJean Delvare 	r &= data->alarm_mask;
6398d5d45fbSJean Delvare 	data->beep_mask = r;
64086d47f12SJean Delvare 	gl520_write_value(client, GL520_REG_BEEP_MASK, r);
6419a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
6428d5d45fbSJean Delvare 	return count;
6438d5d45fbSJean Delvare }
6448d5d45fbSJean Delvare 
6452579b7ffSJulia Lawall static DEVICE_ATTR_RO(alarms);
6462579b7ffSJulia Lawall static DEVICE_ATTR_RW(beep_enable);
6472579b7ffSJulia Lawall static DEVICE_ATTR_RW(beep_mask);
64886d47f12SJean Delvare 
alarm_show(struct device * dev,struct device_attribute * attr,char * buf)64917de1a88SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
650e86a7760SJean Delvare 			  char *buf)
651e86a7760SJean Delvare {
652e86a7760SJean Delvare 	int bit_nr = to_sensor_dev_attr(attr)->index;
653e86a7760SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
654e86a7760SJean Delvare 
655e86a7760SJean Delvare 	return sprintf(buf, "%d\n", (data->alarms >> bit_nr) & 1);
656e86a7760SJean Delvare }
657e86a7760SJean Delvare 
65817de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
65917de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
66017de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
66117de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
66217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
66317de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 5);
66417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 6);
66517de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 7);
66617de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 7);
667e86a7760SJean Delvare 
beep_show(struct device * dev,struct device_attribute * attr,char * buf)66817de1a88SGuenter Roeck static ssize_t beep_show(struct device *dev, struct device_attribute *attr,
669e86a7760SJean Delvare 			 char *buf)
670e86a7760SJean Delvare {
671e86a7760SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
672e86a7760SJean Delvare 	struct gl520_data *data = gl520_update_device(dev);
673e86a7760SJean Delvare 
674e86a7760SJean Delvare 	return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
675e86a7760SJean Delvare }
676e86a7760SJean Delvare 
beep_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)67717de1a88SGuenter Roeck static ssize_t beep_store(struct device *dev, struct device_attribute *attr,
678e86a7760SJean Delvare 			  const char *buf, size_t count)
679e86a7760SJean Delvare {
680d1b9c3f5SAxel Lin 	struct gl520_data *data = dev_get_drvdata(dev);
681d1b9c3f5SAxel Lin 	struct i2c_client *client = data->client;
682e86a7760SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
683e86a7760SJean Delvare 	unsigned long bit;
684e86a7760SJean Delvare 
68543da3d12SGuenter Roeck 	int err;
68643da3d12SGuenter Roeck 
68743da3d12SGuenter Roeck 	err = kstrtoul(buf, 10, &bit);
68843da3d12SGuenter Roeck 	if (err)
68943da3d12SGuenter Roeck 		return err;
690e86a7760SJean Delvare 	if (bit & ~1)
691e86a7760SJean Delvare 		return -EINVAL;
692e86a7760SJean Delvare 
693e86a7760SJean Delvare 	mutex_lock(&data->update_lock);
694e86a7760SJean Delvare 	data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
695e86a7760SJean Delvare 	if (bit)
696e86a7760SJean Delvare 		data->beep_mask |= (1 << bitnr);
697e86a7760SJean Delvare 	else
698e86a7760SJean Delvare 		data->beep_mask &= ~(1 << bitnr);
699e86a7760SJean Delvare 	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
700e86a7760SJean Delvare 	mutex_unlock(&data->update_lock);
701e86a7760SJean Delvare 	return count;
702e86a7760SJean Delvare }
703e86a7760SJean Delvare 
70417de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in0_beep, beep, 0);
70517de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in1_beep, beep, 1);
70617de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in2_beep, beep, 2);
70717de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in3_beep, beep, 3);
70817de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_beep, beep, 4);
70917de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_beep, beep, 5);
71017de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_beep, beep, 6);
71117de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp2_beep, beep, 7);
71217de1a88SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(in4_beep, beep, 7);
713e86a7760SJean Delvare 
71487808be4SJean Delvare static struct attribute *gl520_attributes[] = {
71587808be4SJean Delvare 	&dev_attr_cpu0_vid.attr,
71687808be4SJean Delvare 
71786d47f12SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
71886d47f12SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
71986d47f12SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
720e86a7760SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
721e86a7760SJean Delvare 	&sensor_dev_attr_in0_beep.dev_attr.attr,
72286d47f12SJean Delvare 	&sensor_dev_attr_in1_input.dev_attr.attr,
72386d47f12SJean Delvare 	&sensor_dev_attr_in1_min.dev_attr.attr,
72486d47f12SJean Delvare 	&sensor_dev_attr_in1_max.dev_attr.attr,
725e86a7760SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
726e86a7760SJean Delvare 	&sensor_dev_attr_in1_beep.dev_attr.attr,
72786d47f12SJean Delvare 	&sensor_dev_attr_in2_input.dev_attr.attr,
72886d47f12SJean Delvare 	&sensor_dev_attr_in2_min.dev_attr.attr,
72986d47f12SJean Delvare 	&sensor_dev_attr_in2_max.dev_attr.attr,
730e86a7760SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
731e86a7760SJean Delvare 	&sensor_dev_attr_in2_beep.dev_attr.attr,
73286d47f12SJean Delvare 	&sensor_dev_attr_in3_input.dev_attr.attr,
73386d47f12SJean Delvare 	&sensor_dev_attr_in3_min.dev_attr.attr,
73486d47f12SJean Delvare 	&sensor_dev_attr_in3_max.dev_attr.attr,
735e86a7760SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
736e86a7760SJean Delvare 	&sensor_dev_attr_in3_beep.dev_attr.attr,
73787808be4SJean Delvare 
73886d47f12SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
73986d47f12SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
74086d47f12SJean Delvare 	&sensor_dev_attr_fan1_div.dev_attr.attr,
741e86a7760SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
742e86a7760SJean Delvare 	&sensor_dev_attr_fan1_beep.dev_attr.attr,
74387808be4SJean Delvare 	&dev_attr_fan1_off.attr,
74486d47f12SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
74586d47f12SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
74686d47f12SJean Delvare 	&sensor_dev_attr_fan2_div.dev_attr.attr,
747e86a7760SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
748e86a7760SJean Delvare 	&sensor_dev_attr_fan2_beep.dev_attr.attr,
74987808be4SJean Delvare 
75086d47f12SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
75186d47f12SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
75286d47f12SJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
753e86a7760SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
754e86a7760SJean Delvare 	&sensor_dev_attr_temp1_beep.dev_attr.attr,
75587808be4SJean Delvare 
75687808be4SJean Delvare 	&dev_attr_alarms.attr,
75787808be4SJean Delvare 	&dev_attr_beep_enable.attr,
75887808be4SJean Delvare 	&dev_attr_beep_mask.attr,
75987808be4SJean Delvare 	NULL
76087808be4SJean Delvare };
76187808be4SJean Delvare 
76287808be4SJean Delvare static const struct attribute_group gl520_group = {
76387808be4SJean Delvare 	.attrs = gl520_attributes,
76487808be4SJean Delvare };
76587808be4SJean Delvare 
766f445a9afSGuenter Roeck static struct attribute *gl520_attributes_in4[] = {
76786d47f12SJean Delvare 	&sensor_dev_attr_in4_input.dev_attr.attr,
76886d47f12SJean Delvare 	&sensor_dev_attr_in4_min.dev_attr.attr,
76986d47f12SJean Delvare 	&sensor_dev_attr_in4_max.dev_attr.attr,
770e86a7760SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
771e86a7760SJean Delvare 	&sensor_dev_attr_in4_beep.dev_attr.attr,
772f445a9afSGuenter Roeck 	NULL
773f445a9afSGuenter Roeck };
77487808be4SJean Delvare 
775f445a9afSGuenter Roeck static struct attribute *gl520_attributes_temp2[] = {
77686d47f12SJean Delvare 	&sensor_dev_attr_temp2_input.dev_attr.attr,
77786d47f12SJean Delvare 	&sensor_dev_attr_temp2_max.dev_attr.attr,
77886d47f12SJean Delvare 	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
779e86a7760SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
780e86a7760SJean Delvare 	&sensor_dev_attr_temp2_beep.dev_attr.attr,
78187808be4SJean Delvare 	NULL
78287808be4SJean Delvare };
78387808be4SJean Delvare 
784f445a9afSGuenter Roeck static const struct attribute_group gl520_group_in4 = {
785f445a9afSGuenter Roeck 	.attrs = gl520_attributes_in4,
786f445a9afSGuenter Roeck };
787f445a9afSGuenter Roeck 
788f445a9afSGuenter Roeck static const struct attribute_group gl520_group_temp2 = {
789f445a9afSGuenter Roeck 	.attrs = gl520_attributes_temp2,
79087808be4SJean Delvare };
79187808be4SJean Delvare 
7928d5d45fbSJean Delvare 
7938d5d45fbSJean Delvare /*
7948d5d45fbSJean Delvare  * Real code
7958d5d45fbSJean Delvare  */
7968d5d45fbSJean Delvare 
797a23a9fe1SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
gl520_detect(struct i2c_client * client,struct i2c_board_info * info)798310ec792SJean Delvare static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info)
7998d5d45fbSJean Delvare {
800a23a9fe1SJean Delvare 	struct i2c_adapter *adapter = client->adapter;
8018d5d45fbSJean Delvare 
8028d5d45fbSJean Delvare 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
8038d5d45fbSJean Delvare 				     I2C_FUNC_SMBUS_WORD_DATA))
804a23a9fe1SJean Delvare 		return -ENODEV;
8058d5d45fbSJean Delvare 
8068d5d45fbSJean Delvare 	/* Determine the chip type. */
807f28dc2f7SJean Delvare 	if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
808f28dc2f7SJean Delvare 	    ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
809f28dc2f7SJean Delvare 	    ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
810f28dc2f7SJean Delvare 		dev_dbg(&client->dev, "Unknown chip type, skipping\n");
811a23a9fe1SJean Delvare 		return -ENODEV;
8128d5d45fbSJean Delvare 	}
8138d5d45fbSJean Delvare 
814f2f394dbSWolfram Sang 	strscpy(info->type, "gl520sm", I2C_NAME_SIZE);
815a23a9fe1SJean Delvare 
816a23a9fe1SJean Delvare 	return 0;
817a23a9fe1SJean Delvare }
818a23a9fe1SJean Delvare 
819df51f2d7SAxel Lin /* Called when we have found a new GL520SM. */
gl520_init_client(struct i2c_client * client)820df51f2d7SAxel Lin static void gl520_init_client(struct i2c_client *client)
821df51f2d7SAxel Lin {
822df51f2d7SAxel Lin 	struct gl520_data *data = i2c_get_clientdata(client);
823df51f2d7SAxel Lin 	u8 oldconf, conf;
824df51f2d7SAxel Lin 
825df51f2d7SAxel Lin 	conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
826df51f2d7SAxel Lin 
827df51f2d7SAxel Lin 	data->alarm_mask = 0xff;
828df51f2d7SAxel Lin 	data->vrm = vid_which_vrm();
829df51f2d7SAxel Lin 
830df51f2d7SAxel Lin 	if (extra_sensor_type == 1)
831df51f2d7SAxel Lin 		conf &= ~0x10;
832df51f2d7SAxel Lin 	else if (extra_sensor_type == 2)
833df51f2d7SAxel Lin 		conf |= 0x10;
834df51f2d7SAxel Lin 	data->two_temps = !(conf & 0x10);
835df51f2d7SAxel Lin 
836df51f2d7SAxel Lin 	/* If IRQ# is disabled, we can safely force comparator mode */
837df51f2d7SAxel Lin 	if (!(conf & 0x20))
838df51f2d7SAxel Lin 		conf &= 0xf7;
839df51f2d7SAxel Lin 
840df51f2d7SAxel Lin 	/* Enable monitoring if needed */
841df51f2d7SAxel Lin 	conf |= 0x40;
842df51f2d7SAxel Lin 
843df51f2d7SAxel Lin 	if (conf != oldconf)
844df51f2d7SAxel Lin 		gl520_write_value(client, GL520_REG_CONF, conf);
845df51f2d7SAxel Lin 
846df51f2d7SAxel Lin 	gl520_update_device(&(client->dev));
847df51f2d7SAxel Lin 
848df51f2d7SAxel Lin 	if (data->fan_min[0] == 0)
849df51f2d7SAxel Lin 		data->alarm_mask &= ~0x20;
850df51f2d7SAxel Lin 	if (data->fan_min[1] == 0)
851df51f2d7SAxel Lin 		data->alarm_mask &= ~0x40;
852df51f2d7SAxel Lin 
853df51f2d7SAxel Lin 	data->beep_mask &= data->alarm_mask;
854df51f2d7SAxel Lin 	gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
855df51f2d7SAxel Lin }
856df51f2d7SAxel Lin 
gl520_probe(struct i2c_client * client)85767487038SStephen Kitt static int gl520_probe(struct i2c_client *client)
858a23a9fe1SJean Delvare {
859d1b9c3f5SAxel Lin 	struct device *dev = &client->dev;
860d1b9c3f5SAxel Lin 	struct device *hwmon_dev;
861a23a9fe1SJean Delvare 	struct gl520_data *data;
862a23a9fe1SJean Delvare 
863d1b9c3f5SAxel Lin 	data = devm_kzalloc(dev, sizeof(struct gl520_data), GFP_KERNEL);
864647ff514SGuenter Roeck 	if (!data)
865647ff514SGuenter Roeck 		return -ENOMEM;
866a23a9fe1SJean Delvare 
867a23a9fe1SJean Delvare 	i2c_set_clientdata(client, data);
8689a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
869d1b9c3f5SAxel Lin 	data->client = client;
8708d5d45fbSJean Delvare 
8718d5d45fbSJean Delvare 	/* Initialize the GL520SM chip */
872f28dc2f7SJean Delvare 	gl520_init_client(client);
8738d5d45fbSJean Delvare 
874d1b9c3f5SAxel Lin 	/* sysfs hooks */
875d1b9c3f5SAxel Lin 	data->groups[0] = &gl520_group;
87687808be4SJean Delvare 
877f445a9afSGuenter Roeck 	if (data->two_temps)
878d1b9c3f5SAxel Lin 		data->groups[1] = &gl520_group_temp2;
879f445a9afSGuenter Roeck 	else
880d1b9c3f5SAxel Lin 		data->groups[1] = &gl520_group_in4;
88187808be4SJean Delvare 
882d1b9c3f5SAxel Lin 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
883d1b9c3f5SAxel Lin 							   data, data->groups);
884d1b9c3f5SAxel Lin 	return PTR_ERR_OR_ZERO(hwmon_dev);
8858d5d45fbSJean Delvare }
8868d5d45fbSJean Delvare 
887df51f2d7SAxel Lin static const struct i2c_device_id gl520_id[] = {
888df51f2d7SAxel Lin 	{ "gl520sm", 0 },
889df51f2d7SAxel Lin 	{ }
890df51f2d7SAxel Lin };
891df51f2d7SAxel Lin MODULE_DEVICE_TABLE(i2c, gl520_id);
8928d5d45fbSJean Delvare 
893df51f2d7SAxel Lin static struct i2c_driver gl520_driver = {
894df51f2d7SAxel Lin 	.class		= I2C_CLASS_HWMON,
895df51f2d7SAxel Lin 	.driver = {
896df51f2d7SAxel Lin 		.name	= "gl520sm",
897df51f2d7SAxel Lin 	},
898*1975d167SUwe Kleine-König 	.probe		= gl520_probe,
899df51f2d7SAxel Lin 	.id_table	= gl520_id,
900df51f2d7SAxel Lin 	.detect		= gl520_detect,
901df51f2d7SAxel Lin 	.address_list	= normal_i2c,
902df51f2d7SAxel Lin };
9038d5d45fbSJean Delvare 
904f0967eeaSAxel Lin module_i2c_driver(gl520_driver);
9058d5d45fbSJean Delvare 
9068d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
90796de0e25SJan Engelhardt 	"Kyösti Mälkki <kmalkki@cc.hut.fi>, "
9088d5d45fbSJean Delvare 	"Maarten Deprez <maartendeprez@users.sourceforge.net>");
9098d5d45fbSJean Delvare MODULE_DESCRIPTION("GL520SM driver");
9108d5d45fbSJean Delvare MODULE_LICENSE("GPL");
911