174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
38d5d45fbSJean Delvare * lm80.c - From lm_sensors, Linux kernel modules for hardware
48d5d45fbSJean Delvare * monitoring
58d5d45fbSJean Delvare * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
68d5d45fbSJean Delvare * and Philip Edelbrock <phil@netroedge.com>
78d5d45fbSJean Delvare *
88d5d45fbSJean Delvare * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org>
98d5d45fbSJean Delvare */
108d5d45fbSJean Delvare
118d5d45fbSJean Delvare #include <linux/module.h>
128d5d45fbSJean Delvare #include <linux/init.h>
138d5d45fbSJean Delvare #include <linux/slab.h>
148d5d45fbSJean Delvare #include <linux/jiffies.h>
158d5d45fbSJean Delvare #include <linux/i2c.h>
16943b0830SMark M. Hoffman #include <linux/hwmon.h>
17f8181762SJean Delvare #include <linux/hwmon-sysfs.h>
18943b0830SMark M. Hoffman #include <linux/err.h>
199a61bf63SIngo Molnar #include <linux/mutex.h>
208d5d45fbSJean Delvare
218d5d45fbSJean Delvare /* Addresses to scan */
2225e9c86dSMark M. Hoffman static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
2325e9c86dSMark M. Hoffman 0x2e, 0x2f, I2C_CLIENT_END };
248d5d45fbSJean Delvare
258d5d45fbSJean Delvare /* Many LM80 constants specified below */
268d5d45fbSJean Delvare
278d5d45fbSJean Delvare /* The LM80 registers */
288d5d45fbSJean Delvare #define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2)
298d5d45fbSJean Delvare #define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2)
308d5d45fbSJean Delvare #define LM80_REG_IN(nr) (0x20 + (nr))
318d5d45fbSJean Delvare
328d5d45fbSJean Delvare #define LM80_REG_FAN1 0x28
338d5d45fbSJean Delvare #define LM80_REG_FAN2 0x29
348d5d45fbSJean Delvare #define LM80_REG_FAN_MIN(nr) (0x3b + (nr))
358d5d45fbSJean Delvare
368d5d45fbSJean Delvare #define LM80_REG_TEMP 0x27
378d5d45fbSJean Delvare #define LM80_REG_TEMP_HOT_MAX 0x38
388d5d45fbSJean Delvare #define LM80_REG_TEMP_HOT_HYST 0x39
398d5d45fbSJean Delvare #define LM80_REG_TEMP_OS_MAX 0x3a
408d5d45fbSJean Delvare #define LM80_REG_TEMP_OS_HYST 0x3b
418d5d45fbSJean Delvare
428d5d45fbSJean Delvare #define LM80_REG_CONFIG 0x00
438d5d45fbSJean Delvare #define LM80_REG_ALARM1 0x01
448d5d45fbSJean Delvare #define LM80_REG_ALARM2 0x02
458d5d45fbSJean Delvare #define LM80_REG_MASK1 0x03
468d5d45fbSJean Delvare #define LM80_REG_MASK2 0x04
478d5d45fbSJean Delvare #define LM80_REG_FANDIV 0x05
488d5d45fbSJean Delvare #define LM80_REG_RES 0x06
498d5d45fbSJean Delvare
509908ad4cSJean Delvare #define LM96080_REG_CONV_RATE 0x07
519908ad4cSJean Delvare #define LM96080_REG_MAN_ID 0x3e
529908ad4cSJean Delvare #define LM96080_REG_DEV_ID 0x3f
539908ad4cSJean Delvare
548d5d45fbSJean Delvare
551160631bSGuenter Roeck /*
561160631bSGuenter Roeck * Conversions. Rounding and limit checking is only done on the TO_REG
571160631bSGuenter Roeck * variants. Note that you should be a bit careful with which arguments
581160631bSGuenter Roeck * these macros are called: arguments may be evaluated more than once.
591160631bSGuenter Roeck * Fixing this is just not worth it.
601160631bSGuenter Roeck */
618d5d45fbSJean Delvare
622a844c14SGuenter Roeck #define IN_TO_REG(val) (clamp_val(((val) + 5) / 10, 0, 255))
638d5d45fbSJean Delvare #define IN_FROM_REG(val) ((val) * 10)
648d5d45fbSJean Delvare
FAN_TO_REG(unsigned rpm,unsigned div)658d5d45fbSJean Delvare static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
668d5d45fbSJean Delvare {
678d5d45fbSJean Delvare if (rpm == 0)
688d5d45fbSJean Delvare return 255;
692a844c14SGuenter Roeck rpm = clamp_val(rpm, 1, 1000000);
702a844c14SGuenter Roeck return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
718d5d45fbSJean Delvare }
728d5d45fbSJean Delvare
738d5d45fbSJean Delvare #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
748d5d45fbSJean Delvare (val) == 255 ? 0 : 1350000/((div) * (val)))
758d5d45fbSJean Delvare
76688a3174SGuenter Roeck #define TEMP_FROM_REG(reg) ((reg) * 125 / 32)
77688a3174SGuenter Roeck #define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \
78688a3174SGuenter Roeck -128000, 127000), 1000) << 8)
798d5d45fbSJean Delvare
808d5d45fbSJean Delvare #define DIV_FROM_REG(val) (1 << (val))
818d5d45fbSJean Delvare
829711bcddSGuenter Roeck enum temp_index {
839711bcddSGuenter Roeck t_input = 0,
849711bcddSGuenter Roeck t_hot_max,
859711bcddSGuenter Roeck t_hot_hyst,
869711bcddSGuenter Roeck t_os_max,
879711bcddSGuenter Roeck t_os_hyst,
889711bcddSGuenter Roeck t_num_temp
899711bcddSGuenter Roeck };
909711bcddSGuenter Roeck
919711bcddSGuenter Roeck static const u8 temp_regs[t_num_temp] = {
929711bcddSGuenter Roeck [t_input] = LM80_REG_TEMP,
939711bcddSGuenter Roeck [t_hot_max] = LM80_REG_TEMP_HOT_MAX,
949711bcddSGuenter Roeck [t_hot_hyst] = LM80_REG_TEMP_HOT_HYST,
959711bcddSGuenter Roeck [t_os_max] = LM80_REG_TEMP_OS_MAX,
969711bcddSGuenter Roeck [t_os_hyst] = LM80_REG_TEMP_OS_HYST,
979711bcddSGuenter Roeck };
989711bcddSGuenter Roeck
991adf3a3eSGuenter Roeck enum in_index {
1001adf3a3eSGuenter Roeck i_input = 0,
1011adf3a3eSGuenter Roeck i_max,
1021adf3a3eSGuenter Roeck i_min,
1031adf3a3eSGuenter Roeck i_num_in
1041adf3a3eSGuenter Roeck };
1051adf3a3eSGuenter Roeck
10685b3ee07SGuenter Roeck enum fan_index {
10785b3ee07SGuenter Roeck f_input,
10885b3ee07SGuenter Roeck f_min,
10985b3ee07SGuenter Roeck f_num_fan
11085b3ee07SGuenter Roeck };
11185b3ee07SGuenter Roeck
1128d5d45fbSJean Delvare /*
1138d5d45fbSJean Delvare * Client data (each client gets its own)
1148d5d45fbSJean Delvare */
1158d5d45fbSJean Delvare
1168d5d45fbSJean Delvare struct lm80_data {
117118c9a61SGuenter Roeck struct i2c_client *client;
1189a61bf63SIngo Molnar struct mutex update_lock;
11996585f1aSFrans Meulenbroeks char error; /* !=0 if error occurred during last update */
120952a11caSPaul Fertser bool valid; /* true if following fields are valid */
1218d5d45fbSJean Delvare unsigned long last_updated; /* In jiffies */
1228d5d45fbSJean Delvare
1231adf3a3eSGuenter Roeck u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */
12485b3ee07SGuenter Roeck u8 fan[f_num_fan][2]; /* Register value, 1st index enum fan_index */
1258d5d45fbSJean Delvare u8 fan_div[2]; /* Register encoding, shifted right */
1269711bcddSGuenter Roeck s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */
1278d5d45fbSJean Delvare u16 alarms; /* Register encoding, combined */
1288d5d45fbSJean Delvare };
1298d5d45fbSJean Delvare
lm80_read_value(struct i2c_client * client,u8 reg)130c254ffdeSGuenter Roeck static int lm80_read_value(struct i2c_client *client, u8 reg)
131c254ffdeSGuenter Roeck {
132c254ffdeSGuenter Roeck return i2c_smbus_read_byte_data(client, reg);
133c254ffdeSGuenter Roeck }
134c254ffdeSGuenter Roeck
lm80_write_value(struct i2c_client * client,u8 reg,u8 value)135c254ffdeSGuenter Roeck static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
136c254ffdeSGuenter Roeck {
137c254ffdeSGuenter Roeck return i2c_smbus_write_byte_data(client, reg, value);
138c254ffdeSGuenter Roeck }
139c254ffdeSGuenter Roeck
140c254ffdeSGuenter Roeck /* Called when we have found a new LM80 and after read errors */
lm80_init_client(struct i2c_client * client)141c254ffdeSGuenter Roeck static void lm80_init_client(struct i2c_client *client)
142c254ffdeSGuenter Roeck {
1438d5d45fbSJean Delvare /*
144c254ffdeSGuenter Roeck * Reset all except Watchdog values and last conversion values
145c254ffdeSGuenter Roeck * This sets fan-divs to 2, among others. This makes most other
146c254ffdeSGuenter Roeck * initializations unnecessary
1478d5d45fbSJean Delvare */
148c254ffdeSGuenter Roeck lm80_write_value(client, LM80_REG_CONFIG, 0x80);
149c254ffdeSGuenter Roeck /* Set 11-bit temperature resolution */
150c254ffdeSGuenter Roeck lm80_write_value(client, LM80_REG_RES, 0x08);
1518d5d45fbSJean Delvare
152c254ffdeSGuenter Roeck /* Start monitoring */
153c254ffdeSGuenter Roeck lm80_write_value(client, LM80_REG_CONFIG, 0x01);
154c254ffdeSGuenter Roeck }
1558d5d45fbSJean Delvare
lm80_update_device(struct device * dev)156c254ffdeSGuenter Roeck static struct lm80_data *lm80_update_device(struct device *dev)
157c254ffdeSGuenter Roeck {
158c254ffdeSGuenter Roeck struct lm80_data *data = dev_get_drvdata(dev);
159c254ffdeSGuenter Roeck struct i2c_client *client = data->client;
160c254ffdeSGuenter Roeck int i;
161c254ffdeSGuenter Roeck int rv;
162c254ffdeSGuenter Roeck int prev_rv;
163c254ffdeSGuenter Roeck struct lm80_data *ret = data;
1648d5d45fbSJean Delvare
165c254ffdeSGuenter Roeck mutex_lock(&data->update_lock);
1668c8bacc8SJean Delvare
167c254ffdeSGuenter Roeck if (data->error)
168c254ffdeSGuenter Roeck lm80_init_client(client);
169c254ffdeSGuenter Roeck
170c254ffdeSGuenter Roeck if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
171c254ffdeSGuenter Roeck dev_dbg(dev, "Starting lm80 update\n");
172c254ffdeSGuenter Roeck for (i = 0; i <= 6; i++) {
173c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_IN(i));
174c254ffdeSGuenter Roeck if (rv < 0)
175c254ffdeSGuenter Roeck goto abort;
176c254ffdeSGuenter Roeck data->in[i_input][i] = rv;
177c254ffdeSGuenter Roeck
178c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_IN_MIN(i));
179c254ffdeSGuenter Roeck if (rv < 0)
180c254ffdeSGuenter Roeck goto abort;
181c254ffdeSGuenter Roeck data->in[i_min][i] = rv;
182c254ffdeSGuenter Roeck
183c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_IN_MAX(i));
184c254ffdeSGuenter Roeck if (rv < 0)
185c254ffdeSGuenter Roeck goto abort;
186c254ffdeSGuenter Roeck data->in[i_max][i] = rv;
187c254ffdeSGuenter Roeck }
188c254ffdeSGuenter Roeck
189c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_FAN1);
190c254ffdeSGuenter Roeck if (rv < 0)
191c254ffdeSGuenter Roeck goto abort;
192c254ffdeSGuenter Roeck data->fan[f_input][0] = rv;
193c254ffdeSGuenter Roeck
194c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
195c254ffdeSGuenter Roeck if (rv < 0)
196c254ffdeSGuenter Roeck goto abort;
197c254ffdeSGuenter Roeck data->fan[f_min][0] = rv;
198c254ffdeSGuenter Roeck
199c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_FAN2);
200c254ffdeSGuenter Roeck if (rv < 0)
201c254ffdeSGuenter Roeck goto abort;
202c254ffdeSGuenter Roeck data->fan[f_input][1] = rv;
203c254ffdeSGuenter Roeck
204c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
205c254ffdeSGuenter Roeck if (rv < 0)
206c254ffdeSGuenter Roeck goto abort;
207c254ffdeSGuenter Roeck data->fan[f_min][1] = rv;
208c254ffdeSGuenter Roeck
209c254ffdeSGuenter Roeck prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP);
210c254ffdeSGuenter Roeck if (rv < 0)
211c254ffdeSGuenter Roeck goto abort;
212c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_RES);
213c254ffdeSGuenter Roeck if (rv < 0)
214c254ffdeSGuenter Roeck goto abort;
215c254ffdeSGuenter Roeck data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0);
216c254ffdeSGuenter Roeck
217c254ffdeSGuenter Roeck for (i = t_input + 1; i < t_num_temp; i++) {
218c254ffdeSGuenter Roeck rv = lm80_read_value(client, temp_regs[i]);
219c254ffdeSGuenter Roeck if (rv < 0)
220c254ffdeSGuenter Roeck goto abort;
221c254ffdeSGuenter Roeck data->temp[i] = rv << 8;
222c254ffdeSGuenter Roeck }
223c254ffdeSGuenter Roeck
224c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_FANDIV);
225c254ffdeSGuenter Roeck if (rv < 0)
226c254ffdeSGuenter Roeck goto abort;
227c254ffdeSGuenter Roeck data->fan_div[0] = (rv >> 2) & 0x03;
228c254ffdeSGuenter Roeck data->fan_div[1] = (rv >> 4) & 0x03;
229c254ffdeSGuenter Roeck
230c254ffdeSGuenter Roeck prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1);
231c254ffdeSGuenter Roeck if (rv < 0)
232c254ffdeSGuenter Roeck goto abort;
233c254ffdeSGuenter Roeck rv = lm80_read_value(client, LM80_REG_ALARM2);
234c254ffdeSGuenter Roeck if (rv < 0)
235c254ffdeSGuenter Roeck goto abort;
236c254ffdeSGuenter Roeck data->alarms = prev_rv + (rv << 8);
237c254ffdeSGuenter Roeck
238c254ffdeSGuenter Roeck data->last_updated = jiffies;
239952a11caSPaul Fertser data->valid = true;
240c254ffdeSGuenter Roeck data->error = 0;
241c254ffdeSGuenter Roeck }
242c254ffdeSGuenter Roeck goto done;
243c254ffdeSGuenter Roeck
244c254ffdeSGuenter Roeck abort:
245c254ffdeSGuenter Roeck ret = ERR_PTR(rv);
246952a11caSPaul Fertser data->valid = false;
247c254ffdeSGuenter Roeck data->error = 1;
248c254ffdeSGuenter Roeck
249c254ffdeSGuenter Roeck done:
250c254ffdeSGuenter Roeck mutex_unlock(&data->update_lock);
251c254ffdeSGuenter Roeck
252c254ffdeSGuenter Roeck return ret;
253c254ffdeSGuenter Roeck }
2548d5d45fbSJean Delvare
2558d5d45fbSJean Delvare /*
2568d5d45fbSJean Delvare * Sysfs stuff
2578d5d45fbSJean Delvare */
2588d5d45fbSJean Delvare
in_show(struct device * dev,struct device_attribute * attr,char * buf)259fdb97a02SGuenter Roeck static ssize_t in_show(struct device *dev, struct device_attribute *attr,
2601adf3a3eSGuenter Roeck char *buf)
2611adf3a3eSGuenter Roeck {
2621adf3a3eSGuenter Roeck struct lm80_data *data = lm80_update_device(dev);
2631adf3a3eSGuenter Roeck int index = to_sensor_dev_attr_2(attr)->index;
2641adf3a3eSGuenter Roeck int nr = to_sensor_dev_attr_2(attr)->nr;
2658d5d45fbSJean Delvare
2661adf3a3eSGuenter Roeck if (IS_ERR(data))
2671adf3a3eSGuenter Roeck return PTR_ERR(data);
2681adf3a3eSGuenter Roeck return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index]));
2698d5d45fbSJean Delvare }
2701adf3a3eSGuenter Roeck
in_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)271fdb97a02SGuenter Roeck static ssize_t in_store(struct device *dev, struct device_attribute *attr,
2721adf3a3eSGuenter Roeck const char *buf, size_t count)
2731adf3a3eSGuenter Roeck {
2741adf3a3eSGuenter Roeck struct lm80_data *data = dev_get_drvdata(dev);
2751adf3a3eSGuenter Roeck struct i2c_client *client = data->client;
2761adf3a3eSGuenter Roeck int index = to_sensor_dev_attr_2(attr)->index;
2771adf3a3eSGuenter Roeck int nr = to_sensor_dev_attr_2(attr)->nr;
2781adf3a3eSGuenter Roeck long val;
2791adf3a3eSGuenter Roeck u8 reg;
2801adf3a3eSGuenter Roeck int err = kstrtol(buf, 10, &val);
2811adf3a3eSGuenter Roeck if (err < 0)
2821adf3a3eSGuenter Roeck return err;
2831adf3a3eSGuenter Roeck
2841adf3a3eSGuenter Roeck reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index);
2851adf3a3eSGuenter Roeck
2861adf3a3eSGuenter Roeck mutex_lock(&data->update_lock);
2871adf3a3eSGuenter Roeck data->in[nr][index] = IN_TO_REG(val);
2881adf3a3eSGuenter Roeck lm80_write_value(client, reg, data->in[nr][index]);
2891adf3a3eSGuenter Roeck mutex_unlock(&data->update_lock);
2901adf3a3eSGuenter Roeck return count;
2911adf3a3eSGuenter Roeck }
2928d5d45fbSJean Delvare
fan_show(struct device * dev,struct device_attribute * attr,char * buf)293fdb97a02SGuenter Roeck static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
29485b3ee07SGuenter Roeck char *buf)
29585b3ee07SGuenter Roeck {
29685b3ee07SGuenter Roeck int index = to_sensor_dev_attr_2(attr)->index;
29785b3ee07SGuenter Roeck int nr = to_sensor_dev_attr_2(attr)->nr;
29885b3ee07SGuenter Roeck struct lm80_data *data = lm80_update_device(dev);
29985b3ee07SGuenter Roeck if (IS_ERR(data))
30085b3ee07SGuenter Roeck return PTR_ERR(data);
30185b3ee07SGuenter Roeck return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index],
30285b3ee07SGuenter Roeck DIV_FROM_REG(data->fan_div[index])));
3038d5d45fbSJean Delvare }
3048d5d45fbSJean Delvare
fan_div_show(struct device * dev,struct device_attribute * attr,char * buf)305fdb97a02SGuenter Roeck static ssize_t fan_div_show(struct device *dev, struct device_attribute *attr,
306f8181762SJean Delvare char *buf)
307f8181762SJean Delvare {
308f8181762SJean Delvare int nr = to_sensor_dev_attr(attr)->index;
309f8181762SJean Delvare struct lm80_data *data = lm80_update_device(dev);
3102faaa931SFrans Meulenbroeks if (IS_ERR(data))
3112faaa931SFrans Meulenbroeks return PTR_ERR(data);
312f8181762SJean Delvare return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
3138d5d45fbSJean Delvare }
3148d5d45fbSJean Delvare
fan_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)315fdb97a02SGuenter Roeck static ssize_t fan_store(struct device *dev, struct device_attribute *attr,
316f8181762SJean Delvare const char *buf, size_t count)
317f8181762SJean Delvare {
31885b3ee07SGuenter Roeck int index = to_sensor_dev_attr_2(attr)->index;
31985b3ee07SGuenter Roeck int nr = to_sensor_dev_attr_2(attr)->nr;
320118c9a61SGuenter Roeck struct lm80_data *data = dev_get_drvdata(dev);
321118c9a61SGuenter Roeck struct i2c_client *client = data->client;
3226a9e7c4cSFrans Meulenbroeks unsigned long val;
3236a9e7c4cSFrans Meulenbroeks int err = kstrtoul(buf, 10, &val);
3246a9e7c4cSFrans Meulenbroeks if (err < 0)
3256a9e7c4cSFrans Meulenbroeks return err;
326f8181762SJean Delvare
327f8181762SJean Delvare mutex_lock(&data->update_lock);
32885b3ee07SGuenter Roeck data->fan[nr][index] = FAN_TO_REG(val,
32985b3ee07SGuenter Roeck DIV_FROM_REG(data->fan_div[index]));
33085b3ee07SGuenter Roeck lm80_write_value(client, LM80_REG_FAN_MIN(index + 1),
33185b3ee07SGuenter Roeck data->fan[nr][index]);
332f8181762SJean Delvare mutex_unlock(&data->update_lock);
333f8181762SJean Delvare return count;
3348d5d45fbSJean Delvare }
3358d5d45fbSJean Delvare
3361160631bSGuenter Roeck /*
3371160631bSGuenter Roeck * Note: we save and restore the fan minimum here, because its value is
3381160631bSGuenter Roeck * determined in part by the fan divisor. This follows the principle of
3391160631bSGuenter Roeck * least surprise; the user doesn't expect the fan minimum to change just
3401160631bSGuenter Roeck * because the divisor changed.
3411160631bSGuenter Roeck */
fan_div_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)342fdb97a02SGuenter Roeck static ssize_t fan_div_store(struct device *dev,
343fdb97a02SGuenter Roeck struct device_attribute *attr, const char *buf,
344fdb97a02SGuenter Roeck size_t count)
3458d5d45fbSJean Delvare {
346f8181762SJean Delvare int nr = to_sensor_dev_attr(attr)->index;
347118c9a61SGuenter Roeck struct lm80_data *data = dev_get_drvdata(dev);
348118c9a61SGuenter Roeck struct i2c_client *client = data->client;
3496a9e7c4cSFrans Meulenbroeks unsigned long min, val;
3508d5d45fbSJean Delvare u8 reg;
351c9c63915SKangjie Lu int rv;
352c9c63915SKangjie Lu
353c9c63915SKangjie Lu rv = kstrtoul(buf, 10, &val);
354c9c63915SKangjie Lu if (rv < 0)
355c9c63915SKangjie Lu return rv;
3568d5d45fbSJean Delvare
3578d5d45fbSJean Delvare /* Save fan_min */
3589a61bf63SIngo Molnar mutex_lock(&data->update_lock);
35985b3ee07SGuenter Roeck min = FAN_FROM_REG(data->fan[f_min][nr],
3608d5d45fbSJean Delvare DIV_FROM_REG(data->fan_div[nr]));
3618d5d45fbSJean Delvare
3628d5d45fbSJean Delvare switch (val) {
36366b3b1f7SFrans Meulenbroeks case 1:
36466b3b1f7SFrans Meulenbroeks data->fan_div[nr] = 0;
36566b3b1f7SFrans Meulenbroeks break;
36666b3b1f7SFrans Meulenbroeks case 2:
36766b3b1f7SFrans Meulenbroeks data->fan_div[nr] = 1;
36866b3b1f7SFrans Meulenbroeks break;
36966b3b1f7SFrans Meulenbroeks case 4:
37066b3b1f7SFrans Meulenbroeks data->fan_div[nr] = 2;
37166b3b1f7SFrans Meulenbroeks break;
37266b3b1f7SFrans Meulenbroeks case 8:
37366b3b1f7SFrans Meulenbroeks data->fan_div[nr] = 3;
37466b3b1f7SFrans Meulenbroeks break;
3758d5d45fbSJean Delvare default:
376118c9a61SGuenter Roeck dev_err(dev,
377b55f3757SGuenter Roeck "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
378b55f3757SGuenter Roeck val);
3799a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
3808d5d45fbSJean Delvare return -EINVAL;
3818d5d45fbSJean Delvare }
3828d5d45fbSJean Delvare
383c9c63915SKangjie Lu rv = lm80_read_value(client, LM80_REG_FANDIV);
38407bd14ccSWei Yongjun if (rv < 0) {
38507bd14ccSWei Yongjun mutex_unlock(&data->update_lock);
386c9c63915SKangjie Lu return rv;
38707bd14ccSWei Yongjun }
388c9c63915SKangjie Lu reg = (rv & ~(3 << (2 * (nr + 1))))
389c9c63915SKangjie Lu | (data->fan_div[nr] << (2 * (nr + 1)));
3908d5d45fbSJean Delvare lm80_write_value(client, LM80_REG_FANDIV, reg);
3918d5d45fbSJean Delvare
3928d5d45fbSJean Delvare /* Restore fan_min */
39385b3ee07SGuenter Roeck data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
39485b3ee07SGuenter Roeck lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1),
39585b3ee07SGuenter Roeck data->fan[f_min][nr]);
3969a61bf63SIngo Molnar mutex_unlock(&data->update_lock);
3978d5d45fbSJean Delvare
3988d5d45fbSJean Delvare return count;
3998d5d45fbSJean Delvare }
4008d5d45fbSJean Delvare
temp_show(struct device * dev,struct device_attribute * devattr,char * buf)401fdb97a02SGuenter Roeck static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
4029711bcddSGuenter Roeck char *buf)
4038d5d45fbSJean Delvare {
4049711bcddSGuenter Roeck struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
4058d5d45fbSJean Delvare struct lm80_data *data = lm80_update_device(dev);
4062faaa931SFrans Meulenbroeks if (IS_ERR(data))
4072faaa931SFrans Meulenbroeks return PTR_ERR(data);
4089711bcddSGuenter Roeck return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
4098d5d45fbSJean Delvare }
4108d5d45fbSJean Delvare
temp_store(struct device * dev,struct device_attribute * devattr,const char * buf,size_t count)411fdb97a02SGuenter Roeck static ssize_t temp_store(struct device *dev,
412fdb97a02SGuenter Roeck struct device_attribute *devattr, const char *buf,
413fdb97a02SGuenter Roeck size_t count)
4149711bcddSGuenter Roeck {
4159711bcddSGuenter Roeck struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
4169711bcddSGuenter Roeck struct lm80_data *data = dev_get_drvdata(dev);
4179711bcddSGuenter Roeck struct i2c_client *client = data->client;
4189711bcddSGuenter Roeck int nr = attr->index;
4199711bcddSGuenter Roeck long val;
4209711bcddSGuenter Roeck int err = kstrtol(buf, 10, &val);
4219711bcddSGuenter Roeck if (err < 0)
4229711bcddSGuenter Roeck return err;
4238d5d45fbSJean Delvare
4249711bcddSGuenter Roeck mutex_lock(&data->update_lock);
4259711bcddSGuenter Roeck data->temp[nr] = TEMP_TO_REG(val);
4269711bcddSGuenter Roeck lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8);
4279711bcddSGuenter Roeck mutex_unlock(&data->update_lock);
4289711bcddSGuenter Roeck return count;
4298d5d45fbSJean Delvare }
4308d5d45fbSJean Delvare
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)4311547690dSJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
4326cc37ee5SJean Delvare char *buf)
4338d5d45fbSJean Delvare {
4348d5d45fbSJean Delvare struct lm80_data *data = lm80_update_device(dev);
4352faaa931SFrans Meulenbroeks if (IS_ERR(data))
4362faaa931SFrans Meulenbroeks return PTR_ERR(data);
4378d5d45fbSJean Delvare return sprintf(buf, "%u\n", data->alarms);
4388d5d45fbSJean Delvare }
4398d5d45fbSJean Delvare
alarm_show(struct device * dev,struct device_attribute * attr,char * buf)440fdb97a02SGuenter Roeck static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
441e84542f5SJean Delvare char *buf)
442e84542f5SJean Delvare {
443e84542f5SJean Delvare int bitnr = to_sensor_dev_attr(attr)->index;
444e84542f5SJean Delvare struct lm80_data *data = lm80_update_device(dev);
4452faaa931SFrans Meulenbroeks if (IS_ERR(data))
4462faaa931SFrans Meulenbroeks return PTR_ERR(data);
447e84542f5SJean Delvare return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
448e84542f5SJean Delvare }
449e84542f5SJean Delvare
450fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in0_min, in, i_min, 0);
451fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in1_min, in, i_min, 1);
452fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in2_min, in, i_min, 2);
453fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in3_min, in, i_min, 3);
454fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in4_min, in, i_min, 4);
455fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in5_min, in, i_min, 5);
456fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in6_min, in, i_min, 6);
457fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in0_max, in, i_max, 0);
458fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in1_max, in, i_max, 1);
459fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in2_max, in, i_max, 2);
460fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in3_max, in, i_max, 3);
461fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in4_max, in, i_max, 4);
462fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in5_max, in, i_max, 5);
463fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(in6_max, in, i_max, 6);
464fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in0_input, in, i_input, 0);
465fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in1_input, in, i_input, 1);
466fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in2_input, in, i_input, 2);
467fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in3_input, in, i_input, 3);
468fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in4_input, in, i_input, 4);
469fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in5_input, in, i_input, 5);
470fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(in6_input, in, i_input, 6);
471fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(fan1_min, fan, f_min, 0);
472fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RW(fan2_min, fan, f_min, 1);
473fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(fan1_input, fan, f_input, 0);
474fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_2_RO(fan2_input, fan, f_input, 1);
475fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
476fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
477fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, t_input);
478fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, t_hot_max);
479fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp, t_hot_hyst);
480fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, t_os_max);
481fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, temp, t_os_hyst);
4821547690dSJulia Lawall static DEVICE_ATTR_RO(alarms);
483fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
484fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
485fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
486fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
487fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 4);
488fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 5);
489fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in6_alarm, alarm, 6);
490fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 10);
491fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 11);
492fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 8);
493fdb97a02SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 13);
4948d5d45fbSJean Delvare
4958d5d45fbSJean Delvare /*
4968d5d45fbSJean Delvare * Real code
4978d5d45fbSJean Delvare */
4988d5d45fbSJean Delvare
499118c9a61SGuenter Roeck static struct attribute *lm80_attrs[] = {
500f8181762SJean Delvare &sensor_dev_attr_in0_min.dev_attr.attr,
501f8181762SJean Delvare &sensor_dev_attr_in1_min.dev_attr.attr,
502f8181762SJean Delvare &sensor_dev_attr_in2_min.dev_attr.attr,
503f8181762SJean Delvare &sensor_dev_attr_in3_min.dev_attr.attr,
504f8181762SJean Delvare &sensor_dev_attr_in4_min.dev_attr.attr,
505f8181762SJean Delvare &sensor_dev_attr_in5_min.dev_attr.attr,
506f8181762SJean Delvare &sensor_dev_attr_in6_min.dev_attr.attr,
507f8181762SJean Delvare &sensor_dev_attr_in0_max.dev_attr.attr,
508f8181762SJean Delvare &sensor_dev_attr_in1_max.dev_attr.attr,
509f8181762SJean Delvare &sensor_dev_attr_in2_max.dev_attr.attr,
510f8181762SJean Delvare &sensor_dev_attr_in3_max.dev_attr.attr,
511f8181762SJean Delvare &sensor_dev_attr_in4_max.dev_attr.attr,
512f8181762SJean Delvare &sensor_dev_attr_in5_max.dev_attr.attr,
513f8181762SJean Delvare &sensor_dev_attr_in6_max.dev_attr.attr,
514f8181762SJean Delvare &sensor_dev_attr_in0_input.dev_attr.attr,
515f8181762SJean Delvare &sensor_dev_attr_in1_input.dev_attr.attr,
516f8181762SJean Delvare &sensor_dev_attr_in2_input.dev_attr.attr,
517f8181762SJean Delvare &sensor_dev_attr_in3_input.dev_attr.attr,
518f8181762SJean Delvare &sensor_dev_attr_in4_input.dev_attr.attr,
519f8181762SJean Delvare &sensor_dev_attr_in5_input.dev_attr.attr,
520f8181762SJean Delvare &sensor_dev_attr_in6_input.dev_attr.attr,
521f8181762SJean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr,
522f8181762SJean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr,
523f8181762SJean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr,
524f8181762SJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr,
525f8181762SJean Delvare &sensor_dev_attr_fan1_div.dev_attr.attr,
526f8181762SJean Delvare &sensor_dev_attr_fan2_div.dev_attr.attr,
5279711bcddSGuenter Roeck &sensor_dev_attr_temp1_input.dev_attr.attr,
5289711bcddSGuenter Roeck &sensor_dev_attr_temp1_max.dev_attr.attr,
5299711bcddSGuenter Roeck &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
5309711bcddSGuenter Roeck &sensor_dev_attr_temp1_crit.dev_attr.attr,
5319711bcddSGuenter Roeck &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
5320501a381SMark M. Hoffman &dev_attr_alarms.attr,
533e84542f5SJean Delvare &sensor_dev_attr_in0_alarm.dev_attr.attr,
534e84542f5SJean Delvare &sensor_dev_attr_in1_alarm.dev_attr.attr,
535e84542f5SJean Delvare &sensor_dev_attr_in2_alarm.dev_attr.attr,
536e84542f5SJean Delvare &sensor_dev_attr_in3_alarm.dev_attr.attr,
537e84542f5SJean Delvare &sensor_dev_attr_in4_alarm.dev_attr.attr,
538e84542f5SJean Delvare &sensor_dev_attr_in5_alarm.dev_attr.attr,
539e84542f5SJean Delvare &sensor_dev_attr_in6_alarm.dev_attr.attr,
540e84542f5SJean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr,
541e84542f5SJean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr,
542e84542f5SJean Delvare &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
543e84542f5SJean Delvare &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
5440501a381SMark M. Hoffman NULL
5450501a381SMark M. Hoffman };
546118c9a61SGuenter Roeck ATTRIBUTE_GROUPS(lm80);
5470501a381SMark M. Hoffman
5488c8bacc8SJean Delvare /* Return 0 if detection is successful, -ENODEV otherwise */
lm80_detect(struct i2c_client * client,struct i2c_board_info * info)549310ec792SJean Delvare static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
5508d5d45fbSJean Delvare {
5518c8bacc8SJean Delvare struct i2c_adapter *adapter = client->adapter;
5529908ad4cSJean Delvare int i, cur, man_id, dev_id;
5539908ad4cSJean Delvare const char *name = NULL;
5548d5d45fbSJean Delvare
5558d5d45fbSJean Delvare if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
5568c8bacc8SJean Delvare return -ENODEV;
5578d5d45fbSJean Delvare
5589908ad4cSJean Delvare /* First check for unused bits, common to both chip types */
5599908ad4cSJean Delvare if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
5609908ad4cSJean Delvare || (lm80_read_value(client, LM80_REG_CONFIG) & 0x80))
5618c8bacc8SJean Delvare return -ENODEV;
5629908ad4cSJean Delvare
5639908ad4cSJean Delvare /*
5649908ad4cSJean Delvare * The LM96080 has manufacturer and stepping/die rev registers so we
5659908ad4cSJean Delvare * can just check that. The LM80 does not have such registers so we
5669908ad4cSJean Delvare * have to use a more expensive trick.
5679908ad4cSJean Delvare */
5689908ad4cSJean Delvare man_id = lm80_read_value(client, LM96080_REG_MAN_ID);
5699908ad4cSJean Delvare dev_id = lm80_read_value(client, LM96080_REG_DEV_ID);
5709908ad4cSJean Delvare if (man_id == 0x01 && dev_id == 0x08) {
5719908ad4cSJean Delvare /* Check more unused bits for confirmation */
5729908ad4cSJean Delvare if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe)
5739908ad4cSJean Delvare return -ENODEV;
5749908ad4cSJean Delvare
5759908ad4cSJean Delvare name = "lm96080";
5769908ad4cSJean Delvare } else {
5779908ad4cSJean Delvare /* Check 6-bit addressing */
5788d5d45fbSJean Delvare for (i = 0x2a; i <= 0x3d; i++) {
5796cc37ee5SJean Delvare cur = i2c_smbus_read_byte_data(client, i);
5806cc37ee5SJean Delvare if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
5816cc37ee5SJean Delvare || (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
5826cc37ee5SJean Delvare || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
5838c8bacc8SJean Delvare return -ENODEV;
5848d5d45fbSJean Delvare }
5858d5d45fbSJean Delvare
5869908ad4cSJean Delvare name = "lm80";
5879908ad4cSJean Delvare }
5889908ad4cSJean Delvare
589f2f394dbSWolfram Sang strscpy(info->type, name, I2C_NAME_SIZE);
5908d5d45fbSJean Delvare
5918c8bacc8SJean Delvare return 0;
5928c8bacc8SJean Delvare }
5938c8bacc8SJean Delvare
lm80_probe(struct i2c_client * client)59467487038SStephen Kitt static int lm80_probe(struct i2c_client *client)
5958c8bacc8SJean Delvare {
596118c9a61SGuenter Roeck struct device *dev = &client->dev;
597118c9a61SGuenter Roeck struct device *hwmon_dev;
5988c8bacc8SJean Delvare struct lm80_data *data;
5998c8bacc8SJean Delvare
600118c9a61SGuenter Roeck data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL);
601c38b2820SGuenter Roeck if (!data)
602c38b2820SGuenter Roeck return -ENOMEM;
6038c8bacc8SJean Delvare
604118c9a61SGuenter Roeck data->client = client;
6059a61bf63SIngo Molnar mutex_init(&data->update_lock);
6068d5d45fbSJean Delvare
6078d5d45fbSJean Delvare /* Initialize the LM80 chip */
6086cc37ee5SJean Delvare lm80_init_client(client);
6098d5d45fbSJean Delvare
6108d5d45fbSJean Delvare /* A few vars need to be filled upon startup */
61199ae3417SGreg Kroah-Hartman data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
61299ae3417SGreg Kroah-Hartman data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
6138d5d45fbSJean Delvare
614118c9a61SGuenter Roeck hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
615118c9a61SGuenter Roeck data, lm80_groups);
6160501a381SMark M. Hoffman
617118c9a61SGuenter Roeck return PTR_ERR_OR_ZERO(hwmon_dev);
6188d5d45fbSJean Delvare }
6198d5d45fbSJean Delvare
6201160631bSGuenter Roeck /*
621c254ffdeSGuenter Roeck * Driver data (common to all clients)
6221160631bSGuenter Roeck */
6238d5d45fbSJean Delvare
624c254ffdeSGuenter Roeck static const struct i2c_device_id lm80_id[] = {
625c254ffdeSGuenter Roeck { "lm80", 0 },
626c254ffdeSGuenter Roeck { "lm96080", 1 },
627c254ffdeSGuenter Roeck { }
628c254ffdeSGuenter Roeck };
629c254ffdeSGuenter Roeck MODULE_DEVICE_TABLE(i2c, lm80_id);
6308d5d45fbSJean Delvare
631c254ffdeSGuenter Roeck static struct i2c_driver lm80_driver = {
632c254ffdeSGuenter Roeck .class = I2C_CLASS_HWMON,
633c254ffdeSGuenter Roeck .driver = {
634c254ffdeSGuenter Roeck .name = "lm80",
635c254ffdeSGuenter Roeck },
636*1975d167SUwe Kleine-König .probe = lm80_probe,
637c254ffdeSGuenter Roeck .id_table = lm80_id,
638c254ffdeSGuenter Roeck .detect = lm80_detect,
639c254ffdeSGuenter Roeck .address_list = normal_i2c,
640c254ffdeSGuenter Roeck };
6418d5d45fbSJean Delvare
642f0967eeaSAxel Lin module_i2c_driver(lm80_driver);
6438d5d45fbSJean Delvare
6448d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
6458d5d45fbSJean Delvare "Philip Edelbrock <phil@netroedge.com>");
6468d5d45fbSJean Delvare MODULE_DESCRIPTION("LM80 driver");
6478d5d45fbSJean Delvare MODULE_LICENSE("GPL");
648