1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * w83793.c - Linux kernel driver for hardware monitoring
4*4882a593Smuzhiyun * Copyright (C) 2006 Winbond Electronics Corp.
5*4882a593Smuzhiyun * Yuan Mu
6*4882a593Smuzhiyun * Rudolf Marek <r.marek@assembler.cz>
7*4882a593Smuzhiyun * Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG.
8*4882a593Smuzhiyun * Watchdog driver part
9*4882a593Smuzhiyun * (Based partially on fschmd driver,
10*4882a593Smuzhiyun * Copyright 2007-2008 by Hans de Goede)
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun * Supports following chips:
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
17*4882a593Smuzhiyun * w83793 10 12 8 6 0x7b 0x5ca3 yes no
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/i2c.h>
24*4882a593Smuzhiyun #include <linux/hwmon.h>
25*4882a593Smuzhiyun #include <linux/hwmon-vid.h>
26*4882a593Smuzhiyun #include <linux/hwmon-sysfs.h>
27*4882a593Smuzhiyun #include <linux/err.h>
28*4882a593Smuzhiyun #include <linux/mutex.h>
29*4882a593Smuzhiyun #include <linux/fs.h>
30*4882a593Smuzhiyun #include <linux/watchdog.h>
31*4882a593Smuzhiyun #include <linux/miscdevice.h>
32*4882a593Smuzhiyun #include <linux/uaccess.h>
33*4882a593Smuzhiyun #include <linux/kref.h>
34*4882a593Smuzhiyun #include <linux/notifier.h>
35*4882a593Smuzhiyun #include <linux/reboot.h>
36*4882a593Smuzhiyun #include <linux/jiffies.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* Default values */
39*4882a593Smuzhiyun #define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* Addresses to scan */
42*4882a593Smuzhiyun static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
43*4882a593Smuzhiyun I2C_CLIENT_END };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /* Insmod parameters */
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static unsigned short force_subclients[4];
48*4882a593Smuzhiyun module_param_array(force_subclients, short, NULL, 0);
49*4882a593Smuzhiyun MODULE_PARM_DESC(force_subclients,
50*4882a593Smuzhiyun "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun static bool reset;
53*4882a593Smuzhiyun module_param(reset, bool, 0);
54*4882a593Smuzhiyun MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static int timeout = WATCHDOG_TIMEOUT; /* default timeout in minutes */
57*4882a593Smuzhiyun module_param(timeout, int, 0);
58*4882a593Smuzhiyun MODULE_PARM_DESC(timeout,
59*4882a593Smuzhiyun "Watchdog timeout in minutes. 2<= timeout <=255 (default="
60*4882a593Smuzhiyun __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static bool nowayout = WATCHDOG_NOWAYOUT;
63*4882a593Smuzhiyun module_param(nowayout, bool, 0);
64*4882a593Smuzhiyun MODULE_PARM_DESC(nowayout,
65*4882a593Smuzhiyun "Watchdog cannot be stopped once started (default="
66*4882a593Smuzhiyun __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun * Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved
70*4882a593Smuzhiyun * as ID, Bank Select registers
71*4882a593Smuzhiyun */
72*4882a593Smuzhiyun #define W83793_REG_BANKSEL 0x00
73*4882a593Smuzhiyun #define W83793_REG_VENDORID 0x0d
74*4882a593Smuzhiyun #define W83793_REG_CHIPID 0x0e
75*4882a593Smuzhiyun #define W83793_REG_DEVICEID 0x0f
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define W83793_REG_CONFIG 0x40
78*4882a593Smuzhiyun #define W83793_REG_MFC 0x58
79*4882a593Smuzhiyun #define W83793_REG_FANIN_CTRL 0x5c
80*4882a593Smuzhiyun #define W83793_REG_FANIN_SEL 0x5d
81*4882a593Smuzhiyun #define W83793_REG_I2C_ADDR 0x0b
82*4882a593Smuzhiyun #define W83793_REG_I2C_SUBADDR 0x0c
83*4882a593Smuzhiyun #define W83793_REG_VID_INA 0x05
84*4882a593Smuzhiyun #define W83793_REG_VID_INB 0x06
85*4882a593Smuzhiyun #define W83793_REG_VID_LATCHA 0x07
86*4882a593Smuzhiyun #define W83793_REG_VID_LATCHB 0x08
87*4882a593Smuzhiyun #define W83793_REG_VID_CTRL 0x59
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun #define W83793_REG_WDT_LOCK 0x01
90*4882a593Smuzhiyun #define W83793_REG_WDT_ENABLE 0x02
91*4882a593Smuzhiyun #define W83793_REG_WDT_STATUS 0x03
92*4882a593Smuzhiyun #define W83793_REG_WDT_TIMEOUT 0x04
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f };
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun #define TEMP_READ 0
97*4882a593Smuzhiyun #define TEMP_CRIT 1
98*4882a593Smuzhiyun #define TEMP_CRIT_HYST 2
99*4882a593Smuzhiyun #define TEMP_WARN 3
100*4882a593Smuzhiyun #define TEMP_WARN_HYST 4
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun * only crit and crit_hyst affect real-time alarm status
103*4882a593Smuzhiyun * current crit crit_hyst warn warn_hyst
104*4882a593Smuzhiyun */
105*4882a593Smuzhiyun static u16 W83793_REG_TEMP[][5] = {
106*4882a593Smuzhiyun {0x1c, 0x78, 0x79, 0x7a, 0x7b},
107*4882a593Smuzhiyun {0x1d, 0x7c, 0x7d, 0x7e, 0x7f},
108*4882a593Smuzhiyun {0x1e, 0x80, 0x81, 0x82, 0x83},
109*4882a593Smuzhiyun {0x1f, 0x84, 0x85, 0x86, 0x87},
110*4882a593Smuzhiyun {0x20, 0x88, 0x89, 0x8a, 0x8b},
111*4882a593Smuzhiyun {0x21, 0x8c, 0x8d, 0x8e, 0x8f},
112*4882a593Smuzhiyun };
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun #define W83793_REG_TEMP_LOW_BITS 0x22
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun #define W83793_REG_BEEP(index) (0x53 + (index))
117*4882a593Smuzhiyun #define W83793_REG_ALARM(index) (0x4b + (index))
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun #define W83793_REG_CLR_CHASSIS 0x4a /* SMI MASK4 */
120*4882a593Smuzhiyun #define W83793_REG_IRQ_CTRL 0x50
121*4882a593Smuzhiyun #define W83793_REG_OVT_CTRL 0x51
122*4882a593Smuzhiyun #define W83793_REG_OVT_BEEP 0x52
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #define IN_READ 0
125*4882a593Smuzhiyun #define IN_MAX 1
126*4882a593Smuzhiyun #define IN_LOW 2
127*4882a593Smuzhiyun static const u16 W83793_REG_IN[][3] = {
128*4882a593Smuzhiyun /* Current, High, Low */
129*4882a593Smuzhiyun {0x10, 0x60, 0x61}, /* Vcore A */
130*4882a593Smuzhiyun {0x11, 0x62, 0x63}, /* Vcore B */
131*4882a593Smuzhiyun {0x12, 0x64, 0x65}, /* Vtt */
132*4882a593Smuzhiyun {0x14, 0x6a, 0x6b}, /* VSEN1 */
133*4882a593Smuzhiyun {0x15, 0x6c, 0x6d}, /* VSEN2 */
134*4882a593Smuzhiyun {0x16, 0x6e, 0x6f}, /* +3VSEN */
135*4882a593Smuzhiyun {0x17, 0x70, 0x71}, /* +12VSEN */
136*4882a593Smuzhiyun {0x18, 0x72, 0x73}, /* 5VDD */
137*4882a593Smuzhiyun {0x19, 0x74, 0x75}, /* 5VSB */
138*4882a593Smuzhiyun {0x1a, 0x76, 0x77}, /* VBAT */
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* Low Bits of Vcore A/B Vtt Read/High/Low */
142*4882a593Smuzhiyun static const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 };
143*4882a593Smuzhiyun static u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 };
144*4882a593Smuzhiyun static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 };
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun #define W83793_REG_FAN(index) (0x23 + 2 * (index)) /* High byte */
147*4882a593Smuzhiyun #define W83793_REG_FAN_MIN(index) (0x90 + 2 * (index)) /* High byte */
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #define W83793_REG_PWM_DEFAULT 0xb2
150*4882a593Smuzhiyun #define W83793_REG_PWM_ENABLE 0x207
151*4882a593Smuzhiyun #define W83793_REG_PWM_UPTIME 0xc3 /* Unit in 0.1 second */
152*4882a593Smuzhiyun #define W83793_REG_PWM_DOWNTIME 0xc4 /* Unit in 0.1 second */
153*4882a593Smuzhiyun #define W83793_REG_TEMP_CRITICAL 0xc5
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun #define PWM_DUTY 0
156*4882a593Smuzhiyun #define PWM_START 1
157*4882a593Smuzhiyun #define PWM_NONSTOP 2
158*4882a593Smuzhiyun #define PWM_STOP_TIME 3
159*4882a593Smuzhiyun #define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \
160*4882a593Smuzhiyun (nr) == 1 ? 0x220 : 0x218) + (index))
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /* bit field, fan1 is bit0, fan2 is bit1 ... */
163*4882a593Smuzhiyun #define W83793_REG_TEMP_FAN_MAP(index) (0x201 + (index))
164*4882a593Smuzhiyun #define W83793_REG_TEMP_TOL(index) (0x208 + (index))
165*4882a593Smuzhiyun #define W83793_REG_TEMP_CRUISE(index) (0x210 + (index))
166*4882a593Smuzhiyun #define W83793_REG_PWM_STOP_TIME(index) (0x228 + (index))
167*4882a593Smuzhiyun #define W83793_REG_SF2_TEMP(index, nr) (0x230 + ((index) << 4) + (nr))
168*4882a593Smuzhiyun #define W83793_REG_SF2_PWM(index, nr) (0x238 + ((index) << 4) + (nr))
169*4882a593Smuzhiyun
FAN_FROM_REG(u16 val)170*4882a593Smuzhiyun static inline unsigned long FAN_FROM_REG(u16 val)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun if ((val >= 0xfff) || (val == 0))
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun return 1350000UL / val;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
FAN_TO_REG(long rpm)177*4882a593Smuzhiyun static inline u16 FAN_TO_REG(long rpm)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun if (rpm <= 0)
180*4882a593Smuzhiyun return 0x0fff;
181*4882a593Smuzhiyun return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
TIME_FROM_REG(u8 reg)184*4882a593Smuzhiyun static inline unsigned long TIME_FROM_REG(u8 reg)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun return reg * 100;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
TIME_TO_REG(unsigned long val)189*4882a593Smuzhiyun static inline u8 TIME_TO_REG(unsigned long val)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun return clamp_val((val + 50) / 100, 0, 0xff);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
TEMP_FROM_REG(s8 reg)194*4882a593Smuzhiyun static inline long TEMP_FROM_REG(s8 reg)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun return reg * 1000;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
TEMP_TO_REG(long val,s8 min,s8 max)199*4882a593Smuzhiyun static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun struct w83793_data {
205*4882a593Smuzhiyun struct device *hwmon_dev;
206*4882a593Smuzhiyun struct mutex update_lock;
207*4882a593Smuzhiyun char valid; /* !=0 if following fields are valid */
208*4882a593Smuzhiyun unsigned long last_updated; /* In jiffies */
209*4882a593Smuzhiyun unsigned long last_nonvolatile; /* In jiffies, last time we update the
210*4882a593Smuzhiyun * nonvolatile registers
211*4882a593Smuzhiyun */
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun u8 bank;
214*4882a593Smuzhiyun u8 vrm;
215*4882a593Smuzhiyun u8 vid[2];
216*4882a593Smuzhiyun u8 in[10][3]; /* Register value, read/high/low */
217*4882a593Smuzhiyun u8 in_low_bits[3]; /* Additional resolution for VCore A/B Vtt */
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun u16 has_fan; /* Only fan1- fan5 has own pins */
220*4882a593Smuzhiyun u16 fan[12]; /* Register value combine */
221*4882a593Smuzhiyun u16 fan_min[12]; /* Register value combine */
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun s8 temp[6][5]; /* current, crit, crit_hyst,warn, warn_hyst */
224*4882a593Smuzhiyun u8 temp_low_bits; /* Additional resolution TD1-TD4 */
225*4882a593Smuzhiyun u8 temp_mode[2]; /* byte 0: Temp D1-D4 mode each has 2 bits
226*4882a593Smuzhiyun * byte 1: Temp R1,R2 mode, each has 1 bit
227*4882a593Smuzhiyun */
228*4882a593Smuzhiyun u8 temp_critical; /* If reached all fan will be at full speed */
229*4882a593Smuzhiyun u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun u8 has_pwm;
232*4882a593Smuzhiyun u8 has_temp;
233*4882a593Smuzhiyun u8 has_vid;
234*4882a593Smuzhiyun u8 pwm_enable; /* Register value, each Temp has 1 bit */
235*4882a593Smuzhiyun u8 pwm_uptime; /* Register value */
236*4882a593Smuzhiyun u8 pwm_downtime; /* Register value */
237*4882a593Smuzhiyun u8 pwm_default; /* All fan default pwm, next poweron valid */
238*4882a593Smuzhiyun u8 pwm[8][3]; /* Register value */
239*4882a593Smuzhiyun u8 pwm_stop_time[8];
240*4882a593Smuzhiyun u8 temp_cruise[6];
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun u8 alarms[5]; /* realtime status registers */
243*4882a593Smuzhiyun u8 beeps[5];
244*4882a593Smuzhiyun u8 beep_enable;
245*4882a593Smuzhiyun u8 tolerance[3]; /* Temp tolerance(Smart Fan I/II) */
246*4882a593Smuzhiyun u8 sf2_pwm[6][7]; /* Smart FanII: Fan duty cycle */
247*4882a593Smuzhiyun u8 sf2_temp[6][7]; /* Smart FanII: Temp level point */
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* watchdog */
250*4882a593Smuzhiyun struct i2c_client *client;
251*4882a593Smuzhiyun struct mutex watchdog_lock;
252*4882a593Smuzhiyun struct list_head list; /* member of the watchdog_data_list */
253*4882a593Smuzhiyun struct kref kref;
254*4882a593Smuzhiyun struct miscdevice watchdog_miscdev;
255*4882a593Smuzhiyun unsigned long watchdog_is_open;
256*4882a593Smuzhiyun char watchdog_expect_close;
257*4882a593Smuzhiyun char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
258*4882a593Smuzhiyun unsigned int watchdog_caused_reboot;
259*4882a593Smuzhiyun int watchdog_timeout; /* watchdog timeout in minutes */
260*4882a593Smuzhiyun };
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Somewhat ugly :( global data pointer list with all devices, so that
264*4882a593Smuzhiyun * we can find our device data as when using misc_register. There is no
265*4882a593Smuzhiyun * other method to get to one's device data from the open file-op and
266*4882a593Smuzhiyun * for usage in the reboot notifier callback.
267*4882a593Smuzhiyun */
268*4882a593Smuzhiyun static LIST_HEAD(watchdog_data_list);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /* Note this lock not only protect list access, but also data.kref access */
271*4882a593Smuzhiyun static DEFINE_MUTEX(watchdog_data_mutex);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /*
274*4882a593Smuzhiyun * Release our data struct when we're detached from the i2c client *and* all
275*4882a593Smuzhiyun * references to our watchdog device are released
276*4882a593Smuzhiyun */
w83793_release_resources(struct kref * ref)277*4882a593Smuzhiyun static void w83793_release_resources(struct kref *ref)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun struct w83793_data *data = container_of(ref, struct w83793_data, kref);
280*4882a593Smuzhiyun kfree(data);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun static u8 w83793_read_value(struct i2c_client *client, u16 reg);
284*4882a593Smuzhiyun static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
285*4882a593Smuzhiyun static int w83793_probe(struct i2c_client *client);
286*4882a593Smuzhiyun static int w83793_detect(struct i2c_client *client,
287*4882a593Smuzhiyun struct i2c_board_info *info);
288*4882a593Smuzhiyun static int w83793_remove(struct i2c_client *client);
289*4882a593Smuzhiyun static void w83793_init_client(struct i2c_client *client);
290*4882a593Smuzhiyun static void w83793_update_nonvolatile(struct device *dev);
291*4882a593Smuzhiyun static struct w83793_data *w83793_update_device(struct device *dev);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static const struct i2c_device_id w83793_id[] = {
294*4882a593Smuzhiyun { "w83793", 0 },
295*4882a593Smuzhiyun { }
296*4882a593Smuzhiyun };
297*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, w83793_id);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun static struct i2c_driver w83793_driver = {
300*4882a593Smuzhiyun .class = I2C_CLASS_HWMON,
301*4882a593Smuzhiyun .driver = {
302*4882a593Smuzhiyun .name = "w83793",
303*4882a593Smuzhiyun },
304*4882a593Smuzhiyun .probe_new = w83793_probe,
305*4882a593Smuzhiyun .remove = w83793_remove,
306*4882a593Smuzhiyun .id_table = w83793_id,
307*4882a593Smuzhiyun .detect = w83793_detect,
308*4882a593Smuzhiyun .address_list = normal_i2c,
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun static ssize_t
vrm_show(struct device * dev,struct device_attribute * attr,char * buf)312*4882a593Smuzhiyun vrm_show(struct device *dev, struct device_attribute *attr, char *buf)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun struct w83793_data *data = dev_get_drvdata(dev);
315*4882a593Smuzhiyun return sprintf(buf, "%d\n", data->vrm);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun static ssize_t
show_vid(struct device * dev,struct device_attribute * attr,char * buf)319*4882a593Smuzhiyun show_vid(struct device *dev, struct device_attribute *attr, char *buf)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
322*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
323*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
324*4882a593Smuzhiyun int index = sensor_attr->index;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return sprintf(buf, "%d\n", vid_from_reg(data->vid[index], data->vrm));
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun static ssize_t
vrm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)330*4882a593Smuzhiyun vrm_store(struct device *dev, struct device_attribute *attr,
331*4882a593Smuzhiyun const char *buf, size_t count)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun struct w83793_data *data = dev_get_drvdata(dev);
334*4882a593Smuzhiyun unsigned long val;
335*4882a593Smuzhiyun int err;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
338*4882a593Smuzhiyun if (err)
339*4882a593Smuzhiyun return err;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (val > 255)
342*4882a593Smuzhiyun return -EINVAL;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun data->vrm = val;
345*4882a593Smuzhiyun return count;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun #define ALARM_STATUS 0
349*4882a593Smuzhiyun #define BEEP_ENABLE 1
350*4882a593Smuzhiyun static ssize_t
show_alarm_beep(struct device * dev,struct device_attribute * attr,char * buf)351*4882a593Smuzhiyun show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
354*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
355*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
356*4882a593Smuzhiyun int nr = sensor_attr->nr;
357*4882a593Smuzhiyun int index = sensor_attr->index >> 3;
358*4882a593Smuzhiyun int bit = sensor_attr->index & 0x07;
359*4882a593Smuzhiyun u8 val;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (nr == ALARM_STATUS) {
362*4882a593Smuzhiyun val = (data->alarms[index] >> (bit)) & 1;
363*4882a593Smuzhiyun } else { /* BEEP_ENABLE */
364*4882a593Smuzhiyun val = (data->beeps[index] >> (bit)) & 1;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun return sprintf(buf, "%u\n", val);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun static ssize_t
store_beep(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)371*4882a593Smuzhiyun store_beep(struct device *dev, struct device_attribute *attr,
372*4882a593Smuzhiyun const char *buf, size_t count)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
375*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
376*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
377*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
378*4882a593Smuzhiyun int index = sensor_attr->index >> 3;
379*4882a593Smuzhiyun int shift = sensor_attr->index & 0x07;
380*4882a593Smuzhiyun u8 beep_bit = 1 << shift;
381*4882a593Smuzhiyun unsigned long val;
382*4882a593Smuzhiyun int err;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
385*4882a593Smuzhiyun if (err)
386*4882a593Smuzhiyun return err;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun if (val > 1)
389*4882a593Smuzhiyun return -EINVAL;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun mutex_lock(&data->update_lock);
392*4882a593Smuzhiyun data->beeps[index] = w83793_read_value(client, W83793_REG_BEEP(index));
393*4882a593Smuzhiyun data->beeps[index] &= ~beep_bit;
394*4882a593Smuzhiyun data->beeps[index] |= val << shift;
395*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_BEEP(index), data->beeps[index]);
396*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return count;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun static ssize_t
show_beep_enable(struct device * dev,struct device_attribute * attr,char * buf)402*4882a593Smuzhiyun show_beep_enable(struct device *dev, struct device_attribute *attr, char *buf)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
405*4882a593Smuzhiyun return sprintf(buf, "%u\n", (data->beep_enable >> 1) & 0x01);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun static ssize_t
store_beep_enable(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)409*4882a593Smuzhiyun store_beep_enable(struct device *dev, struct device_attribute *attr,
410*4882a593Smuzhiyun const char *buf, size_t count)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
413*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
414*4882a593Smuzhiyun unsigned long val;
415*4882a593Smuzhiyun int err;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
418*4882a593Smuzhiyun if (err)
419*4882a593Smuzhiyun return err;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (val > 1)
422*4882a593Smuzhiyun return -EINVAL;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun mutex_lock(&data->update_lock);
425*4882a593Smuzhiyun data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP)
426*4882a593Smuzhiyun & 0xfd;
427*4882a593Smuzhiyun data->beep_enable |= val << 1;
428*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_OVT_BEEP, data->beep_enable);
429*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun return count;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Write 0 to clear chassis alarm */
435*4882a593Smuzhiyun static ssize_t
store_chassis_clear(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)436*4882a593Smuzhiyun store_chassis_clear(struct device *dev,
437*4882a593Smuzhiyun struct device_attribute *attr, const char *buf,
438*4882a593Smuzhiyun size_t count)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
441*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
442*4882a593Smuzhiyun unsigned long val;
443*4882a593Smuzhiyun u8 reg;
444*4882a593Smuzhiyun int err;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
447*4882a593Smuzhiyun if (err)
448*4882a593Smuzhiyun return err;
449*4882a593Smuzhiyun if (val)
450*4882a593Smuzhiyun return -EINVAL;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun mutex_lock(&data->update_lock);
453*4882a593Smuzhiyun reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS);
454*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80);
455*4882a593Smuzhiyun data->valid = 0; /* Force cache refresh */
456*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
457*4882a593Smuzhiyun return count;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun #define FAN_INPUT 0
461*4882a593Smuzhiyun #define FAN_MIN 1
462*4882a593Smuzhiyun static ssize_t
show_fan(struct device * dev,struct device_attribute * attr,char * buf)463*4882a593Smuzhiyun show_fan(struct device *dev, struct device_attribute *attr, char *buf)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
466*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
467*4882a593Smuzhiyun int nr = sensor_attr->nr;
468*4882a593Smuzhiyun int index = sensor_attr->index;
469*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
470*4882a593Smuzhiyun u16 val;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (nr == FAN_INPUT)
473*4882a593Smuzhiyun val = data->fan[index] & 0x0fff;
474*4882a593Smuzhiyun else
475*4882a593Smuzhiyun val = data->fan_min[index] & 0x0fff;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return sprintf(buf, "%lu\n", FAN_FROM_REG(val));
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun static ssize_t
store_fan_min(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)481*4882a593Smuzhiyun store_fan_min(struct device *dev, struct device_attribute *attr,
482*4882a593Smuzhiyun const char *buf, size_t count)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
485*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
486*4882a593Smuzhiyun int index = sensor_attr->index;
487*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
488*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
489*4882a593Smuzhiyun unsigned long val;
490*4882a593Smuzhiyun int err;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
493*4882a593Smuzhiyun if (err)
494*4882a593Smuzhiyun return err;
495*4882a593Smuzhiyun val = FAN_TO_REG(val);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun mutex_lock(&data->update_lock);
498*4882a593Smuzhiyun data->fan_min[index] = val;
499*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_FAN_MIN(index),
500*4882a593Smuzhiyun (val >> 8) & 0xff);
501*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_FAN_MIN(index) + 1, val & 0xff);
502*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun return count;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun static ssize_t
show_pwm(struct device * dev,struct device_attribute * attr,char * buf)508*4882a593Smuzhiyun show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
511*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
512*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
513*4882a593Smuzhiyun u16 val;
514*4882a593Smuzhiyun int nr = sensor_attr->nr;
515*4882a593Smuzhiyun int index = sensor_attr->index;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun if (nr == PWM_STOP_TIME)
518*4882a593Smuzhiyun val = TIME_FROM_REG(data->pwm_stop_time[index]);
519*4882a593Smuzhiyun else
520*4882a593Smuzhiyun val = (data->pwm[index][nr] & 0x3f) << 2;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun return sprintf(buf, "%d\n", val);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun static ssize_t
store_pwm(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)526*4882a593Smuzhiyun store_pwm(struct device *dev, struct device_attribute *attr,
527*4882a593Smuzhiyun const char *buf, size_t count)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
530*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
531*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
532*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
533*4882a593Smuzhiyun int nr = sensor_attr->nr;
534*4882a593Smuzhiyun int index = sensor_attr->index;
535*4882a593Smuzhiyun unsigned long val;
536*4882a593Smuzhiyun int err;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
539*4882a593Smuzhiyun if (err)
540*4882a593Smuzhiyun return err;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun mutex_lock(&data->update_lock);
543*4882a593Smuzhiyun if (nr == PWM_STOP_TIME) {
544*4882a593Smuzhiyun val = TIME_TO_REG(val);
545*4882a593Smuzhiyun data->pwm_stop_time[index] = val;
546*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index),
547*4882a593Smuzhiyun val);
548*4882a593Smuzhiyun } else {
549*4882a593Smuzhiyun val = clamp_val(val, 0, 0xff) >> 2;
550*4882a593Smuzhiyun data->pwm[index][nr] =
551*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0;
552*4882a593Smuzhiyun data->pwm[index][nr] |= val;
553*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM(index, nr),
554*4882a593Smuzhiyun data->pwm[index][nr]);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
558*4882a593Smuzhiyun return count;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun static ssize_t
show_temp(struct device * dev,struct device_attribute * attr,char * buf)562*4882a593Smuzhiyun show_temp(struct device *dev, struct device_attribute *attr, char *buf)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
565*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
566*4882a593Smuzhiyun int nr = sensor_attr->nr;
567*4882a593Smuzhiyun int index = sensor_attr->index;
568*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
569*4882a593Smuzhiyun long temp = TEMP_FROM_REG(data->temp[index][nr]);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun if (nr == TEMP_READ && index < 4) { /* Only TD1-TD4 have low bits */
572*4882a593Smuzhiyun int low = ((data->temp_low_bits >> (index * 2)) & 0x03) * 250;
573*4882a593Smuzhiyun temp += temp > 0 ? low : -low;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun return sprintf(buf, "%ld\n", temp);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun static ssize_t
store_temp(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)579*4882a593Smuzhiyun store_temp(struct device *dev, struct device_attribute *attr,
580*4882a593Smuzhiyun const char *buf, size_t count)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
583*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
584*4882a593Smuzhiyun int nr = sensor_attr->nr;
585*4882a593Smuzhiyun int index = sensor_attr->index;
586*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
587*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
588*4882a593Smuzhiyun long tmp;
589*4882a593Smuzhiyun int err;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun err = kstrtol(buf, 10, &tmp);
592*4882a593Smuzhiyun if (err)
593*4882a593Smuzhiyun return err;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun mutex_lock(&data->update_lock);
596*4882a593Smuzhiyun data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127);
597*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP[index][nr],
598*4882a593Smuzhiyun data->temp[index][nr]);
599*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
600*4882a593Smuzhiyun return count;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun /*
604*4882a593Smuzhiyun * TD1-TD4
605*4882a593Smuzhiyun * each has 4 mode:(2 bits)
606*4882a593Smuzhiyun * 0: Stop monitor
607*4882a593Smuzhiyun * 1: Use internal temp sensor(default)
608*4882a593Smuzhiyun * 2: Reserved
609*4882a593Smuzhiyun * 3: Use sensor in Intel CPU and get result by PECI
610*4882a593Smuzhiyun *
611*4882a593Smuzhiyun * TR1-TR2
612*4882a593Smuzhiyun * each has 2 mode:(1 bit)
613*4882a593Smuzhiyun * 0: Disable temp sensor monitor
614*4882a593Smuzhiyun * 1: To enable temp sensors monitor
615*4882a593Smuzhiyun */
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* 0 disable, 6 PECI */
618*4882a593Smuzhiyun static u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 };
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun static ssize_t
show_temp_mode(struct device * dev,struct device_attribute * attr,char * buf)621*4882a593Smuzhiyun show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
624*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
625*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
626*4882a593Smuzhiyun int index = sensor_attr->index;
627*4882a593Smuzhiyun u8 mask = (index < 4) ? 0x03 : 0x01;
628*4882a593Smuzhiyun u8 shift = (index < 4) ? (2 * index) : (index - 4);
629*4882a593Smuzhiyun u8 tmp;
630*4882a593Smuzhiyun index = (index < 4) ? 0 : 1;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun tmp = (data->temp_mode[index] >> shift) & mask;
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun /* for the internal sensor, found out if diode or thermistor */
635*4882a593Smuzhiyun if (tmp == 1)
636*4882a593Smuzhiyun tmp = index == 0 ? 3 : 4;
637*4882a593Smuzhiyun else
638*4882a593Smuzhiyun tmp = TO_TEMP_MODE[tmp];
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun return sprintf(buf, "%d\n", tmp);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun static ssize_t
store_temp_mode(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)644*4882a593Smuzhiyun store_temp_mode(struct device *dev, struct device_attribute *attr,
645*4882a593Smuzhiyun const char *buf, size_t count)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
648*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
649*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
650*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
651*4882a593Smuzhiyun int index = sensor_attr->index;
652*4882a593Smuzhiyun u8 mask = (index < 4) ? 0x03 : 0x01;
653*4882a593Smuzhiyun u8 shift = (index < 4) ? (2 * index) : (index - 4);
654*4882a593Smuzhiyun unsigned long val;
655*4882a593Smuzhiyun int err;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
658*4882a593Smuzhiyun if (err)
659*4882a593Smuzhiyun return err;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun /* transform the sysfs interface values into table above */
662*4882a593Smuzhiyun if ((val == 6) && (index < 4)) {
663*4882a593Smuzhiyun val -= 3;
664*4882a593Smuzhiyun } else if ((val == 3 && index < 4)
665*4882a593Smuzhiyun || (val == 4 && index >= 4)) {
666*4882a593Smuzhiyun /* transform diode or thermistor into internal enable */
667*4882a593Smuzhiyun val = !!val;
668*4882a593Smuzhiyun } else {
669*4882a593Smuzhiyun return -EINVAL;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun index = (index < 4) ? 0 : 1;
673*4882a593Smuzhiyun mutex_lock(&data->update_lock);
674*4882a593Smuzhiyun data->temp_mode[index] =
675*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_MODE[index]);
676*4882a593Smuzhiyun data->temp_mode[index] &= ~(mask << shift);
677*4882a593Smuzhiyun data->temp_mode[index] |= val << shift;
678*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP_MODE[index],
679*4882a593Smuzhiyun data->temp_mode[index]);
680*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun return count;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun #define SETUP_PWM_DEFAULT 0
686*4882a593Smuzhiyun #define SETUP_PWM_UPTIME 1 /* Unit in 0.1s */
687*4882a593Smuzhiyun #define SETUP_PWM_DOWNTIME 2 /* Unit in 0.1s */
688*4882a593Smuzhiyun #define SETUP_TEMP_CRITICAL 3
689*4882a593Smuzhiyun static ssize_t
show_sf_setup(struct device * dev,struct device_attribute * attr,char * buf)690*4882a593Smuzhiyun show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
693*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
694*4882a593Smuzhiyun int nr = sensor_attr->nr;
695*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
696*4882a593Smuzhiyun u32 val = 0;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun if (nr == SETUP_PWM_DEFAULT)
699*4882a593Smuzhiyun val = (data->pwm_default & 0x3f) << 2;
700*4882a593Smuzhiyun else if (nr == SETUP_PWM_UPTIME)
701*4882a593Smuzhiyun val = TIME_FROM_REG(data->pwm_uptime);
702*4882a593Smuzhiyun else if (nr == SETUP_PWM_DOWNTIME)
703*4882a593Smuzhiyun val = TIME_FROM_REG(data->pwm_downtime);
704*4882a593Smuzhiyun else if (nr == SETUP_TEMP_CRITICAL)
705*4882a593Smuzhiyun val = TEMP_FROM_REG(data->temp_critical & 0x7f);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun return sprintf(buf, "%d\n", val);
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun static ssize_t
store_sf_setup(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)711*4882a593Smuzhiyun store_sf_setup(struct device *dev, struct device_attribute *attr,
712*4882a593Smuzhiyun const char *buf, size_t count)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
715*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
716*4882a593Smuzhiyun int nr = sensor_attr->nr;
717*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
718*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
719*4882a593Smuzhiyun long val;
720*4882a593Smuzhiyun int err;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun err = kstrtol(buf, 10, &val);
723*4882a593Smuzhiyun if (err)
724*4882a593Smuzhiyun return err;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun mutex_lock(&data->update_lock);
727*4882a593Smuzhiyun if (nr == SETUP_PWM_DEFAULT) {
728*4882a593Smuzhiyun data->pwm_default =
729*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0;
730*4882a593Smuzhiyun data->pwm_default |= clamp_val(val, 0, 0xff) >> 2;
731*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM_DEFAULT,
732*4882a593Smuzhiyun data->pwm_default);
733*4882a593Smuzhiyun } else if (nr == SETUP_PWM_UPTIME) {
734*4882a593Smuzhiyun data->pwm_uptime = TIME_TO_REG(val);
735*4882a593Smuzhiyun data->pwm_uptime += data->pwm_uptime == 0 ? 1 : 0;
736*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM_UPTIME,
737*4882a593Smuzhiyun data->pwm_uptime);
738*4882a593Smuzhiyun } else if (nr == SETUP_PWM_DOWNTIME) {
739*4882a593Smuzhiyun data->pwm_downtime = TIME_TO_REG(val);
740*4882a593Smuzhiyun data->pwm_downtime += data->pwm_downtime == 0 ? 1 : 0;
741*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM_DOWNTIME,
742*4882a593Smuzhiyun data->pwm_downtime);
743*4882a593Smuzhiyun } else { /* SETUP_TEMP_CRITICAL */
744*4882a593Smuzhiyun data->temp_critical =
745*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_CRITICAL) & 0x80;
746*4882a593Smuzhiyun data->temp_critical |= TEMP_TO_REG(val, 0, 0x7f);
747*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP_CRITICAL,
748*4882a593Smuzhiyun data->temp_critical);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
752*4882a593Smuzhiyun return count;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun /*
756*4882a593Smuzhiyun * Temp SmartFan control
757*4882a593Smuzhiyun * TEMP_FAN_MAP
758*4882a593Smuzhiyun * Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1...
759*4882a593Smuzhiyun * It's possible two or more temp channels control the same fan, w83793
760*4882a593Smuzhiyun * always prefers to pick the most critical request and applies it to
761*4882a593Smuzhiyun * the related Fan.
762*4882a593Smuzhiyun * It's possible one fan is not in any mapping of 6 temp channels, this
763*4882a593Smuzhiyun * means the fan is manual mode
764*4882a593Smuzhiyun *
765*4882a593Smuzhiyun * TEMP_PWM_ENABLE
766*4882a593Smuzhiyun * Each temp channel has its own SmartFan mode, and temp channel
767*4882a593Smuzhiyun * control fans that are set by TEMP_FAN_MAP
768*4882a593Smuzhiyun * 0: SmartFanII mode
769*4882a593Smuzhiyun * 1: Thermal Cruise Mode
770*4882a593Smuzhiyun *
771*4882a593Smuzhiyun * TEMP_CRUISE
772*4882a593Smuzhiyun * Target temperature in thermal cruise mode, w83793 will try to turn
773*4882a593Smuzhiyun * fan speed to keep the temperature of target device around this
774*4882a593Smuzhiyun * temperature.
775*4882a593Smuzhiyun *
776*4882a593Smuzhiyun * TEMP_TOLERANCE
777*4882a593Smuzhiyun * If Temp higher or lower than target with this tolerance, w83793
778*4882a593Smuzhiyun * will take actions to speed up or slow down the fan to keep the
779*4882a593Smuzhiyun * temperature within the tolerance range.
780*4882a593Smuzhiyun */
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun #define TEMP_FAN_MAP 0
783*4882a593Smuzhiyun #define TEMP_PWM_ENABLE 1
784*4882a593Smuzhiyun #define TEMP_CRUISE 2
785*4882a593Smuzhiyun #define TEMP_TOLERANCE 3
786*4882a593Smuzhiyun static ssize_t
show_sf_ctrl(struct device * dev,struct device_attribute * attr,char * buf)787*4882a593Smuzhiyun show_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
790*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
791*4882a593Smuzhiyun int nr = sensor_attr->nr;
792*4882a593Smuzhiyun int index = sensor_attr->index;
793*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
794*4882a593Smuzhiyun u32 val;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun if (nr == TEMP_FAN_MAP) {
797*4882a593Smuzhiyun val = data->temp_fan_map[index];
798*4882a593Smuzhiyun } else if (nr == TEMP_PWM_ENABLE) {
799*4882a593Smuzhiyun /* +2 to transform into 2 and 3 to conform with sysfs intf */
800*4882a593Smuzhiyun val = ((data->pwm_enable >> index) & 0x01) + 2;
801*4882a593Smuzhiyun } else if (nr == TEMP_CRUISE) {
802*4882a593Smuzhiyun val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f);
803*4882a593Smuzhiyun } else { /* TEMP_TOLERANCE */
804*4882a593Smuzhiyun val = data->tolerance[index >> 1] >> ((index & 0x01) ? 4 : 0);
805*4882a593Smuzhiyun val = TEMP_FROM_REG(val & 0x0f);
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun return sprintf(buf, "%d\n", val);
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun static ssize_t
store_sf_ctrl(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)811*4882a593Smuzhiyun store_sf_ctrl(struct device *dev, struct device_attribute *attr,
812*4882a593Smuzhiyun const char *buf, size_t count)
813*4882a593Smuzhiyun {
814*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
815*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
816*4882a593Smuzhiyun int nr = sensor_attr->nr;
817*4882a593Smuzhiyun int index = sensor_attr->index;
818*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
819*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
820*4882a593Smuzhiyun long val;
821*4882a593Smuzhiyun int err;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun err = kstrtol(buf, 10, &val);
824*4882a593Smuzhiyun if (err)
825*4882a593Smuzhiyun return err;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun mutex_lock(&data->update_lock);
828*4882a593Smuzhiyun if (nr == TEMP_FAN_MAP) {
829*4882a593Smuzhiyun val = clamp_val(val, 0, 255);
830*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val);
831*4882a593Smuzhiyun data->temp_fan_map[index] = val;
832*4882a593Smuzhiyun } else if (nr == TEMP_PWM_ENABLE) {
833*4882a593Smuzhiyun if (val == 2 || val == 3) {
834*4882a593Smuzhiyun data->pwm_enable =
835*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM_ENABLE);
836*4882a593Smuzhiyun if (val - 2)
837*4882a593Smuzhiyun data->pwm_enable |= 1 << index;
838*4882a593Smuzhiyun else
839*4882a593Smuzhiyun data->pwm_enable &= ~(1 << index);
840*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_PWM_ENABLE,
841*4882a593Smuzhiyun data->pwm_enable);
842*4882a593Smuzhiyun } else {
843*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
844*4882a593Smuzhiyun return -EINVAL;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun } else if (nr == TEMP_CRUISE) {
847*4882a593Smuzhiyun data->temp_cruise[index] =
848*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_CRUISE(index));
849*4882a593Smuzhiyun data->temp_cruise[index] &= 0x80;
850*4882a593Smuzhiyun data->temp_cruise[index] |= TEMP_TO_REG(val, 0, 0x7f);
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP_CRUISE(index),
853*4882a593Smuzhiyun data->temp_cruise[index]);
854*4882a593Smuzhiyun } else { /* TEMP_TOLERANCE */
855*4882a593Smuzhiyun int i = index >> 1;
856*4882a593Smuzhiyun u8 shift = (index & 0x01) ? 4 : 0;
857*4882a593Smuzhiyun data->tolerance[i] =
858*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_TOL(i));
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun data->tolerance[i] &= ~(0x0f << shift);
861*4882a593Smuzhiyun data->tolerance[i] |= TEMP_TO_REG(val, 0, 0x0f) << shift;
862*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_TEMP_TOL(i),
863*4882a593Smuzhiyun data->tolerance[i]);
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
867*4882a593Smuzhiyun return count;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun static ssize_t
show_sf2_pwm(struct device * dev,struct device_attribute * attr,char * buf)871*4882a593Smuzhiyun show_sf2_pwm(struct device *dev, struct device_attribute *attr, char *buf)
872*4882a593Smuzhiyun {
873*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
874*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
875*4882a593Smuzhiyun int nr = sensor_attr->nr;
876*4882a593Smuzhiyun int index = sensor_attr->index;
877*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun return sprintf(buf, "%d\n", (data->sf2_pwm[index][nr] & 0x3f) << 2);
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun static ssize_t
store_sf2_pwm(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)883*4882a593Smuzhiyun store_sf2_pwm(struct device *dev, struct device_attribute *attr,
884*4882a593Smuzhiyun const char *buf, size_t count)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
887*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
888*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
889*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
890*4882a593Smuzhiyun int nr = sensor_attr->nr;
891*4882a593Smuzhiyun int index = sensor_attr->index;
892*4882a593Smuzhiyun unsigned long val;
893*4882a593Smuzhiyun int err;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
896*4882a593Smuzhiyun if (err)
897*4882a593Smuzhiyun return err;
898*4882a593Smuzhiyun val = clamp_val(val, 0, 0xff) >> 2;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun mutex_lock(&data->update_lock);
901*4882a593Smuzhiyun data->sf2_pwm[index][nr] =
902*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_SF2_PWM(index, nr)) & 0xc0;
903*4882a593Smuzhiyun data->sf2_pwm[index][nr] |= val;
904*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_SF2_PWM(index, nr),
905*4882a593Smuzhiyun data->sf2_pwm[index][nr]);
906*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
907*4882a593Smuzhiyun return count;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun static ssize_t
show_sf2_temp(struct device * dev,struct device_attribute * attr,char * buf)911*4882a593Smuzhiyun show_sf2_temp(struct device *dev, struct device_attribute *attr, char *buf)
912*4882a593Smuzhiyun {
913*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
914*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
915*4882a593Smuzhiyun int nr = sensor_attr->nr;
916*4882a593Smuzhiyun int index = sensor_attr->index;
917*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun return sprintf(buf, "%ld\n",
920*4882a593Smuzhiyun TEMP_FROM_REG(data->sf2_temp[index][nr] & 0x7f));
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun static ssize_t
store_sf2_temp(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)924*4882a593Smuzhiyun store_sf2_temp(struct device *dev, struct device_attribute *attr,
925*4882a593Smuzhiyun const char *buf, size_t count)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
928*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
929*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
930*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
931*4882a593Smuzhiyun int nr = sensor_attr->nr;
932*4882a593Smuzhiyun int index = sensor_attr->index;
933*4882a593Smuzhiyun long val;
934*4882a593Smuzhiyun int err;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun err = kstrtol(buf, 10, &val);
937*4882a593Smuzhiyun if (err)
938*4882a593Smuzhiyun return err;
939*4882a593Smuzhiyun val = TEMP_TO_REG(val, 0, 0x7f);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun mutex_lock(&data->update_lock);
942*4882a593Smuzhiyun data->sf2_temp[index][nr] =
943*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_SF2_TEMP(index, nr)) & 0x80;
944*4882a593Smuzhiyun data->sf2_temp[index][nr] |= val;
945*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_SF2_TEMP(index, nr),
946*4882a593Smuzhiyun data->sf2_temp[index][nr]);
947*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
948*4882a593Smuzhiyun return count;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /* only Vcore A/B and Vtt have additional 2 bits precision */
952*4882a593Smuzhiyun static ssize_t
show_in(struct device * dev,struct device_attribute * attr,char * buf)953*4882a593Smuzhiyun show_in(struct device *dev, struct device_attribute *attr, char *buf)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
956*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
957*4882a593Smuzhiyun int nr = sensor_attr->nr;
958*4882a593Smuzhiyun int index = sensor_attr->index;
959*4882a593Smuzhiyun struct w83793_data *data = w83793_update_device(dev);
960*4882a593Smuzhiyun u16 val = data->in[index][nr];
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun if (index < 3) {
963*4882a593Smuzhiyun val <<= 2;
964*4882a593Smuzhiyun val += (data->in_low_bits[nr] >> (index * 2)) & 0x3;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun /* voltage inputs 5VDD and 5VSB needs 150mV offset */
967*4882a593Smuzhiyun val = val * scale_in[index] + scale_in_add[index];
968*4882a593Smuzhiyun return sprintf(buf, "%d\n", val);
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun static ssize_t
store_in(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)972*4882a593Smuzhiyun store_in(struct device *dev, struct device_attribute *attr,
973*4882a593Smuzhiyun const char *buf, size_t count)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun struct sensor_device_attribute_2 *sensor_attr =
976*4882a593Smuzhiyun to_sensor_dev_attr_2(attr);
977*4882a593Smuzhiyun int nr = sensor_attr->nr;
978*4882a593Smuzhiyun int index = sensor_attr->index;
979*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
980*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
981*4882a593Smuzhiyun unsigned long val;
982*4882a593Smuzhiyun int err;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun err = kstrtoul(buf, 10, &val);
985*4882a593Smuzhiyun if (err)
986*4882a593Smuzhiyun return err;
987*4882a593Smuzhiyun val = (val + scale_in[index] / 2) / scale_in[index];
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun mutex_lock(&data->update_lock);
990*4882a593Smuzhiyun if (index > 2) {
991*4882a593Smuzhiyun /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */
992*4882a593Smuzhiyun if (nr == 1 || nr == 2)
993*4882a593Smuzhiyun val -= scale_in_add[index] / scale_in[index];
994*4882a593Smuzhiyun val = clamp_val(val, 0, 255);
995*4882a593Smuzhiyun } else {
996*4882a593Smuzhiyun val = clamp_val(val, 0, 0x3FF);
997*4882a593Smuzhiyun data->in_low_bits[nr] =
998*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]);
999*4882a593Smuzhiyun data->in_low_bits[nr] &= ~(0x03 << (2 * index));
1000*4882a593Smuzhiyun data->in_low_bits[nr] |= (val & 0x03) << (2 * index);
1001*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_IN_LOW_BITS[nr],
1002*4882a593Smuzhiyun data->in_low_bits[nr]);
1003*4882a593Smuzhiyun val >>= 2;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun data->in[index][nr] = val;
1006*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_IN[index][nr],
1007*4882a593Smuzhiyun data->in[index][nr]);
1008*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
1009*4882a593Smuzhiyun return count;
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun #define NOT_USED -1
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun #define SENSOR_ATTR_IN(index) \
1015*4882a593Smuzhiyun SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
1016*4882a593Smuzhiyun IN_READ, index), \
1017*4882a593Smuzhiyun SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \
1018*4882a593Smuzhiyun store_in, IN_MAX, index), \
1019*4882a593Smuzhiyun SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \
1020*4882a593Smuzhiyun store_in, IN_LOW, index), \
1021*4882a593Smuzhiyun SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \
1022*4882a593Smuzhiyun NULL, ALARM_STATUS, index + ((index > 2) ? 1 : 0)), \
1023*4882a593Smuzhiyun SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \
1024*4882a593Smuzhiyun show_alarm_beep, store_beep, BEEP_ENABLE, \
1025*4882a593Smuzhiyun index + ((index > 2) ? 1 : 0))
1026*4882a593Smuzhiyun
1027*4882a593Smuzhiyun #define SENSOR_ATTR_FAN(index) \
1028*4882a593Smuzhiyun SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \
1029*4882a593Smuzhiyun NULL, ALARM_STATUS, index + 17), \
1030*4882a593Smuzhiyun SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \
1031*4882a593Smuzhiyun show_alarm_beep, store_beep, BEEP_ENABLE, index + 17), \
1032*4882a593Smuzhiyun SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \
1033*4882a593Smuzhiyun NULL, FAN_INPUT, index - 1), \
1034*4882a593Smuzhiyun SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \
1035*4882a593Smuzhiyun show_fan, store_fan_min, FAN_MIN, index - 1)
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun #define SENSOR_ATTR_PWM(index) \
1038*4882a593Smuzhiyun SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \
1039*4882a593Smuzhiyun store_pwm, PWM_DUTY, index - 1), \
1040*4882a593Smuzhiyun SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \
1041*4882a593Smuzhiyun show_pwm, store_pwm, PWM_NONSTOP, index - 1), \
1042*4882a593Smuzhiyun SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \
1043*4882a593Smuzhiyun show_pwm, store_pwm, PWM_START, index - 1), \
1044*4882a593Smuzhiyun SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \
1045*4882a593Smuzhiyun show_pwm, store_pwm, PWM_STOP_TIME, index - 1)
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun #define SENSOR_ATTR_TEMP(index) \
1048*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_type, S_IRUGO | S_IWUSR, \
1049*4882a593Smuzhiyun show_temp_mode, store_temp_mode, NOT_USED, index - 1), \
1050*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \
1051*4882a593Smuzhiyun NULL, TEMP_READ, index - 1), \
1052*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \
1053*4882a593Smuzhiyun store_temp, TEMP_CRIT, index - 1), \
1054*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \
1055*4882a593Smuzhiyun show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \
1056*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_warn, S_IRUGO | S_IWUSR, show_temp, \
1057*4882a593Smuzhiyun store_temp, TEMP_WARN, index - 1), \
1058*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_warn_hyst, S_IRUGO | S_IWUSR, \
1059*4882a593Smuzhiyun show_temp, store_temp, TEMP_WARN_HYST, index - 1), \
1060*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \
1061*4882a593Smuzhiyun show_alarm_beep, NULL, ALARM_STATUS, index + 11), \
1062*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
1063*4882a593Smuzhiyun show_alarm_beep, store_beep, BEEP_ENABLE, index + 11), \
1064*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_channels_pwm, \
1065*4882a593Smuzhiyun S_IRUGO | S_IWUSR, show_sf_ctrl, store_sf_ctrl, \
1066*4882a593Smuzhiyun TEMP_FAN_MAP, index - 1), \
1067*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \
1068*4882a593Smuzhiyun show_sf_ctrl, store_sf_ctrl, TEMP_PWM_ENABLE, \
1069*4882a593Smuzhiyun index - 1), \
1070*4882a593Smuzhiyun SENSOR_ATTR_2(thermal_cruise##index, S_IRUGO | S_IWUSR, \
1071*4882a593Smuzhiyun show_sf_ctrl, store_sf_ctrl, TEMP_CRUISE, index - 1), \
1072*4882a593Smuzhiyun SENSOR_ATTR_2(tolerance##index, S_IRUGO | S_IWUSR, show_sf_ctrl,\
1073*4882a593Smuzhiyun store_sf_ctrl, TEMP_TOLERANCE, index - 1), \
1074*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
1075*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 0, index - 1), \
1076*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
1077*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 1, index - 1), \
1078*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
1079*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 2, index - 1), \
1080*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
1081*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 3, index - 1), \
1082*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
1083*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 4, index - 1), \
1084*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
1085*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 5, index - 1), \
1086*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
1087*4882a593Smuzhiyun show_sf2_pwm, store_sf2_pwm, 6, index - 1), \
1088*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
1089*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 0, index - 1), \
1090*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
1091*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 1, index - 1), \
1092*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
1093*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 2, index - 1), \
1094*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
1095*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 3, index - 1), \
1096*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
1097*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 4, index - 1), \
1098*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
1099*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 5, index - 1), \
1100*4882a593Smuzhiyun SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
1101*4882a593Smuzhiyun show_sf2_temp, store_sf2_temp, 6, index - 1)
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun static struct sensor_device_attribute_2 w83793_sensor_attr_2[] = {
1104*4882a593Smuzhiyun SENSOR_ATTR_IN(0),
1105*4882a593Smuzhiyun SENSOR_ATTR_IN(1),
1106*4882a593Smuzhiyun SENSOR_ATTR_IN(2),
1107*4882a593Smuzhiyun SENSOR_ATTR_IN(3),
1108*4882a593Smuzhiyun SENSOR_ATTR_IN(4),
1109*4882a593Smuzhiyun SENSOR_ATTR_IN(5),
1110*4882a593Smuzhiyun SENSOR_ATTR_IN(6),
1111*4882a593Smuzhiyun SENSOR_ATTR_IN(7),
1112*4882a593Smuzhiyun SENSOR_ATTR_IN(8),
1113*4882a593Smuzhiyun SENSOR_ATTR_IN(9),
1114*4882a593Smuzhiyun SENSOR_ATTR_FAN(1),
1115*4882a593Smuzhiyun SENSOR_ATTR_FAN(2),
1116*4882a593Smuzhiyun SENSOR_ATTR_FAN(3),
1117*4882a593Smuzhiyun SENSOR_ATTR_FAN(4),
1118*4882a593Smuzhiyun SENSOR_ATTR_FAN(5),
1119*4882a593Smuzhiyun SENSOR_ATTR_PWM(1),
1120*4882a593Smuzhiyun SENSOR_ATTR_PWM(2),
1121*4882a593Smuzhiyun SENSOR_ATTR_PWM(3),
1122*4882a593Smuzhiyun };
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun static struct sensor_device_attribute_2 w83793_temp[] = {
1125*4882a593Smuzhiyun SENSOR_ATTR_TEMP(1),
1126*4882a593Smuzhiyun SENSOR_ATTR_TEMP(2),
1127*4882a593Smuzhiyun SENSOR_ATTR_TEMP(3),
1128*4882a593Smuzhiyun SENSOR_ATTR_TEMP(4),
1129*4882a593Smuzhiyun SENSOR_ATTR_TEMP(5),
1130*4882a593Smuzhiyun SENSOR_ATTR_TEMP(6),
1131*4882a593Smuzhiyun };
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* Fan6-Fan12 */
1134*4882a593Smuzhiyun static struct sensor_device_attribute_2 w83793_left_fan[] = {
1135*4882a593Smuzhiyun SENSOR_ATTR_FAN(6),
1136*4882a593Smuzhiyun SENSOR_ATTR_FAN(7),
1137*4882a593Smuzhiyun SENSOR_ATTR_FAN(8),
1138*4882a593Smuzhiyun SENSOR_ATTR_FAN(9),
1139*4882a593Smuzhiyun SENSOR_ATTR_FAN(10),
1140*4882a593Smuzhiyun SENSOR_ATTR_FAN(11),
1141*4882a593Smuzhiyun SENSOR_ATTR_FAN(12),
1142*4882a593Smuzhiyun };
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun /* Pwm4-Pwm8 */
1145*4882a593Smuzhiyun static struct sensor_device_attribute_2 w83793_left_pwm[] = {
1146*4882a593Smuzhiyun SENSOR_ATTR_PWM(4),
1147*4882a593Smuzhiyun SENSOR_ATTR_PWM(5),
1148*4882a593Smuzhiyun SENSOR_ATTR_PWM(6),
1149*4882a593Smuzhiyun SENSOR_ATTR_PWM(7),
1150*4882a593Smuzhiyun SENSOR_ATTR_PWM(8),
1151*4882a593Smuzhiyun };
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun static struct sensor_device_attribute_2 w83793_vid[] = {
1154*4882a593Smuzhiyun SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
1155*4882a593Smuzhiyun SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
1156*4882a593Smuzhiyun };
1157*4882a593Smuzhiyun static DEVICE_ATTR_RW(vrm);
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun static struct sensor_device_attribute_2 sda_single_files[] = {
1160*4882a593Smuzhiyun SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
1161*4882a593Smuzhiyun store_chassis_clear, ALARM_STATUS, 30),
1162*4882a593Smuzhiyun SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
1163*4882a593Smuzhiyun store_beep_enable, NOT_USED, NOT_USED),
1164*4882a593Smuzhiyun SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
1165*4882a593Smuzhiyun store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
1166*4882a593Smuzhiyun SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
1167*4882a593Smuzhiyun store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
1168*4882a593Smuzhiyun SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
1169*4882a593Smuzhiyun store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
1170*4882a593Smuzhiyun SENSOR_ATTR_2(temp_critical, S_IWUSR | S_IRUGO, show_sf_setup,
1171*4882a593Smuzhiyun store_sf_setup, SETUP_TEMP_CRITICAL, NOT_USED),
1172*4882a593Smuzhiyun };
1173*4882a593Smuzhiyun
w83793_init_client(struct i2c_client * client)1174*4882a593Smuzhiyun static void w83793_init_client(struct i2c_client *client)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun if (reset)
1177*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_CONFIG, 0x80);
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun /* Start monitoring */
1180*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_CONFIG,
1181*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_CONFIG) | 0x01);
1182*4882a593Smuzhiyun }
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun /*
1185*4882a593Smuzhiyun * Watchdog routines
1186*4882a593Smuzhiyun */
1187*4882a593Smuzhiyun
watchdog_set_timeout(struct w83793_data * data,int timeout)1188*4882a593Smuzhiyun static int watchdog_set_timeout(struct w83793_data *data, int timeout)
1189*4882a593Smuzhiyun {
1190*4882a593Smuzhiyun unsigned int mtimeout;
1191*4882a593Smuzhiyun int ret;
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun mtimeout = DIV_ROUND_UP(timeout, 60);
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun if (mtimeout > 255)
1196*4882a593Smuzhiyun return -EINVAL;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1199*4882a593Smuzhiyun if (!data->client) {
1200*4882a593Smuzhiyun ret = -ENODEV;
1201*4882a593Smuzhiyun goto leave;
1202*4882a593Smuzhiyun }
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun data->watchdog_timeout = mtimeout;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun /* Set Timeout value (in Minutes) */
1207*4882a593Smuzhiyun w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
1208*4882a593Smuzhiyun data->watchdog_timeout);
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun ret = mtimeout * 60;
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun leave:
1213*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1214*4882a593Smuzhiyun return ret;
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun
watchdog_get_timeout(struct w83793_data * data)1217*4882a593Smuzhiyun static int watchdog_get_timeout(struct w83793_data *data)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun int timeout;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1222*4882a593Smuzhiyun timeout = data->watchdog_timeout * 60;
1223*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun return timeout;
1226*4882a593Smuzhiyun }
1227*4882a593Smuzhiyun
watchdog_trigger(struct w83793_data * data)1228*4882a593Smuzhiyun static int watchdog_trigger(struct w83793_data *data)
1229*4882a593Smuzhiyun {
1230*4882a593Smuzhiyun int ret = 0;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1233*4882a593Smuzhiyun if (!data->client) {
1234*4882a593Smuzhiyun ret = -ENODEV;
1235*4882a593Smuzhiyun goto leave;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun /* Set Timeout value (in Minutes) */
1239*4882a593Smuzhiyun w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
1240*4882a593Smuzhiyun data->watchdog_timeout);
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun leave:
1243*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1244*4882a593Smuzhiyun return ret;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
watchdog_enable(struct w83793_data * data)1247*4882a593Smuzhiyun static int watchdog_enable(struct w83793_data *data)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun int ret = 0;
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1252*4882a593Smuzhiyun if (!data->client) {
1253*4882a593Smuzhiyun ret = -ENODEV;
1254*4882a593Smuzhiyun goto leave;
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun /* Set initial timeout */
1258*4882a593Smuzhiyun w83793_write_value(data->client, W83793_REG_WDT_TIMEOUT,
1259*4882a593Smuzhiyun data->watchdog_timeout);
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun /* Enable Soft Watchdog */
1262*4882a593Smuzhiyun w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0x55);
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun leave:
1265*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1266*4882a593Smuzhiyun return ret;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun
watchdog_disable(struct w83793_data * data)1269*4882a593Smuzhiyun static int watchdog_disable(struct w83793_data *data)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun int ret = 0;
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1274*4882a593Smuzhiyun if (!data->client) {
1275*4882a593Smuzhiyun ret = -ENODEV;
1276*4882a593Smuzhiyun goto leave;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun /* Disable Soft Watchdog */
1280*4882a593Smuzhiyun w83793_write_value(data->client, W83793_REG_WDT_LOCK, 0xAA);
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun leave:
1283*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1284*4882a593Smuzhiyun return ret;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun
watchdog_open(struct inode * inode,struct file * filp)1287*4882a593Smuzhiyun static int watchdog_open(struct inode *inode, struct file *filp)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun struct w83793_data *pos, *data = NULL;
1290*4882a593Smuzhiyun int watchdog_is_open;
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun /*
1293*4882a593Smuzhiyun * We get called from drivers/char/misc.c with misc_mtx hold, and we
1294*4882a593Smuzhiyun * call misc_register() from w83793_probe() with watchdog_data_mutex
1295*4882a593Smuzhiyun * hold, as misc_register() takes the misc_mtx lock, this is a possible
1296*4882a593Smuzhiyun * deadlock, so we use mutex_trylock here.
1297*4882a593Smuzhiyun */
1298*4882a593Smuzhiyun if (!mutex_trylock(&watchdog_data_mutex))
1299*4882a593Smuzhiyun return -ERESTARTSYS;
1300*4882a593Smuzhiyun list_for_each_entry(pos, &watchdog_data_list, list) {
1301*4882a593Smuzhiyun if (pos->watchdog_miscdev.minor == iminor(inode)) {
1302*4882a593Smuzhiyun data = pos;
1303*4882a593Smuzhiyun break;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun /* Check, if device is already open */
1308*4882a593Smuzhiyun watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /*
1311*4882a593Smuzhiyun * Increase data reference counter (if not already done).
1312*4882a593Smuzhiyun * Note we can never not have found data, so we don't check for this
1313*4882a593Smuzhiyun */
1314*4882a593Smuzhiyun if (!watchdog_is_open)
1315*4882a593Smuzhiyun kref_get(&data->kref);
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun /* Check, if device is already open and possibly issue error */
1320*4882a593Smuzhiyun if (watchdog_is_open)
1321*4882a593Smuzhiyun return -EBUSY;
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun /* Enable Soft Watchdog */
1324*4882a593Smuzhiyun watchdog_enable(data);
1325*4882a593Smuzhiyun
1326*4882a593Smuzhiyun /* Store pointer to data into filp's private data */
1327*4882a593Smuzhiyun filp->private_data = data;
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun return stream_open(inode, filp);
1330*4882a593Smuzhiyun }
1331*4882a593Smuzhiyun
watchdog_close(struct inode * inode,struct file * filp)1332*4882a593Smuzhiyun static int watchdog_close(struct inode *inode, struct file *filp)
1333*4882a593Smuzhiyun {
1334*4882a593Smuzhiyun struct w83793_data *data = filp->private_data;
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun if (data->watchdog_expect_close) {
1337*4882a593Smuzhiyun watchdog_disable(data);
1338*4882a593Smuzhiyun data->watchdog_expect_close = 0;
1339*4882a593Smuzhiyun } else {
1340*4882a593Smuzhiyun watchdog_trigger(data);
1341*4882a593Smuzhiyun dev_crit(&data->client->dev,
1342*4882a593Smuzhiyun "unexpected close, not stopping watchdog!\n");
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun clear_bit(0, &data->watchdog_is_open);
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun /* Decrease data reference counter */
1348*4882a593Smuzhiyun mutex_lock(&watchdog_data_mutex);
1349*4882a593Smuzhiyun kref_put(&data->kref, w83793_release_resources);
1350*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun return 0;
1353*4882a593Smuzhiyun }
1354*4882a593Smuzhiyun
watchdog_write(struct file * filp,const char __user * buf,size_t count,loff_t * offset)1355*4882a593Smuzhiyun static ssize_t watchdog_write(struct file *filp, const char __user *buf,
1356*4882a593Smuzhiyun size_t count, loff_t *offset)
1357*4882a593Smuzhiyun {
1358*4882a593Smuzhiyun ssize_t ret;
1359*4882a593Smuzhiyun struct w83793_data *data = filp->private_data;
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun if (count) {
1362*4882a593Smuzhiyun if (!nowayout) {
1363*4882a593Smuzhiyun size_t i;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun /* Clear it in case it was set with a previous write */
1366*4882a593Smuzhiyun data->watchdog_expect_close = 0;
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun for (i = 0; i != count; i++) {
1369*4882a593Smuzhiyun char c;
1370*4882a593Smuzhiyun if (get_user(c, buf + i))
1371*4882a593Smuzhiyun return -EFAULT;
1372*4882a593Smuzhiyun if (c == 'V')
1373*4882a593Smuzhiyun data->watchdog_expect_close = 1;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun ret = watchdog_trigger(data);
1377*4882a593Smuzhiyun if (ret < 0)
1378*4882a593Smuzhiyun return ret;
1379*4882a593Smuzhiyun }
1380*4882a593Smuzhiyun return count;
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun
watchdog_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)1383*4882a593Smuzhiyun static long watchdog_ioctl(struct file *filp, unsigned int cmd,
1384*4882a593Smuzhiyun unsigned long arg)
1385*4882a593Smuzhiyun {
1386*4882a593Smuzhiyun struct watchdog_info ident = {
1387*4882a593Smuzhiyun .options = WDIOF_KEEPALIVEPING |
1388*4882a593Smuzhiyun WDIOF_SETTIMEOUT |
1389*4882a593Smuzhiyun WDIOF_CARDRESET,
1390*4882a593Smuzhiyun .identity = "w83793 watchdog"
1391*4882a593Smuzhiyun };
1392*4882a593Smuzhiyun
1393*4882a593Smuzhiyun int val, ret = 0;
1394*4882a593Smuzhiyun struct w83793_data *data = filp->private_data;
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun switch (cmd) {
1397*4882a593Smuzhiyun case WDIOC_GETSUPPORT:
1398*4882a593Smuzhiyun if (!nowayout)
1399*4882a593Smuzhiyun ident.options |= WDIOF_MAGICCLOSE;
1400*4882a593Smuzhiyun if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
1401*4882a593Smuzhiyun ret = -EFAULT;
1402*4882a593Smuzhiyun break;
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun case WDIOC_GETSTATUS:
1405*4882a593Smuzhiyun val = data->watchdog_caused_reboot ? WDIOF_CARDRESET : 0;
1406*4882a593Smuzhiyun ret = put_user(val, (int __user *)arg);
1407*4882a593Smuzhiyun break;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun case WDIOC_GETBOOTSTATUS:
1410*4882a593Smuzhiyun ret = put_user(0, (int __user *)arg);
1411*4882a593Smuzhiyun break;
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun case WDIOC_KEEPALIVE:
1414*4882a593Smuzhiyun ret = watchdog_trigger(data);
1415*4882a593Smuzhiyun break;
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun case WDIOC_GETTIMEOUT:
1418*4882a593Smuzhiyun val = watchdog_get_timeout(data);
1419*4882a593Smuzhiyun ret = put_user(val, (int __user *)arg);
1420*4882a593Smuzhiyun break;
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun case WDIOC_SETTIMEOUT:
1423*4882a593Smuzhiyun if (get_user(val, (int __user *)arg)) {
1424*4882a593Smuzhiyun ret = -EFAULT;
1425*4882a593Smuzhiyun break;
1426*4882a593Smuzhiyun }
1427*4882a593Smuzhiyun ret = watchdog_set_timeout(data, val);
1428*4882a593Smuzhiyun if (ret > 0)
1429*4882a593Smuzhiyun ret = put_user(ret, (int __user *)arg);
1430*4882a593Smuzhiyun break;
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun case WDIOC_SETOPTIONS:
1433*4882a593Smuzhiyun if (get_user(val, (int __user *)arg)) {
1434*4882a593Smuzhiyun ret = -EFAULT;
1435*4882a593Smuzhiyun break;
1436*4882a593Smuzhiyun }
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun if (val & WDIOS_DISABLECARD)
1439*4882a593Smuzhiyun ret = watchdog_disable(data);
1440*4882a593Smuzhiyun else if (val & WDIOS_ENABLECARD)
1441*4882a593Smuzhiyun ret = watchdog_enable(data);
1442*4882a593Smuzhiyun else
1443*4882a593Smuzhiyun ret = -EINVAL;
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun break;
1446*4882a593Smuzhiyun default:
1447*4882a593Smuzhiyun ret = -ENOTTY;
1448*4882a593Smuzhiyun }
1449*4882a593Smuzhiyun return ret;
1450*4882a593Smuzhiyun }
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun static const struct file_operations watchdog_fops = {
1453*4882a593Smuzhiyun .owner = THIS_MODULE,
1454*4882a593Smuzhiyun .llseek = no_llseek,
1455*4882a593Smuzhiyun .open = watchdog_open,
1456*4882a593Smuzhiyun .release = watchdog_close,
1457*4882a593Smuzhiyun .write = watchdog_write,
1458*4882a593Smuzhiyun .unlocked_ioctl = watchdog_ioctl,
1459*4882a593Smuzhiyun .compat_ioctl = compat_ptr_ioctl,
1460*4882a593Smuzhiyun };
1461*4882a593Smuzhiyun
1462*4882a593Smuzhiyun /*
1463*4882a593Smuzhiyun * Notifier for system down
1464*4882a593Smuzhiyun */
1465*4882a593Smuzhiyun
watchdog_notify_sys(struct notifier_block * this,unsigned long code,void * unused)1466*4882a593Smuzhiyun static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
1467*4882a593Smuzhiyun void *unused)
1468*4882a593Smuzhiyun {
1469*4882a593Smuzhiyun struct w83793_data *data = NULL;
1470*4882a593Smuzhiyun
1471*4882a593Smuzhiyun if (code == SYS_DOWN || code == SYS_HALT) {
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun /* Disable each registered watchdog */
1474*4882a593Smuzhiyun mutex_lock(&watchdog_data_mutex);
1475*4882a593Smuzhiyun list_for_each_entry(data, &watchdog_data_list, list) {
1476*4882a593Smuzhiyun if (data->watchdog_miscdev.minor)
1477*4882a593Smuzhiyun watchdog_disable(data);
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun
1482*4882a593Smuzhiyun return NOTIFY_DONE;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun /*
1486*4882a593Smuzhiyun * The WDT needs to learn about soft shutdowns in order to
1487*4882a593Smuzhiyun * turn the timebomb registers off.
1488*4882a593Smuzhiyun */
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun static struct notifier_block watchdog_notifier = {
1491*4882a593Smuzhiyun .notifier_call = watchdog_notify_sys,
1492*4882a593Smuzhiyun };
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun /*
1495*4882a593Smuzhiyun * Init / remove routines
1496*4882a593Smuzhiyun */
1497*4882a593Smuzhiyun
w83793_remove(struct i2c_client * client)1498*4882a593Smuzhiyun static int w83793_remove(struct i2c_client *client)
1499*4882a593Smuzhiyun {
1500*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
1501*4882a593Smuzhiyun struct device *dev = &client->dev;
1502*4882a593Smuzhiyun int i, tmp;
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun /* Unregister the watchdog (if registered) */
1505*4882a593Smuzhiyun if (data->watchdog_miscdev.minor) {
1506*4882a593Smuzhiyun misc_deregister(&data->watchdog_miscdev);
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if (data->watchdog_is_open) {
1509*4882a593Smuzhiyun dev_warn(&client->dev,
1510*4882a593Smuzhiyun "i2c client detached with watchdog open! "
1511*4882a593Smuzhiyun "Stopping watchdog.\n");
1512*4882a593Smuzhiyun watchdog_disable(data);
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun mutex_lock(&watchdog_data_mutex);
1516*4882a593Smuzhiyun list_del(&data->list);
1517*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun /* Tell the watchdog code the client is gone */
1520*4882a593Smuzhiyun mutex_lock(&data->watchdog_lock);
1521*4882a593Smuzhiyun data->client = NULL;
1522*4882a593Smuzhiyun mutex_unlock(&data->watchdog_lock);
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun
1525*4882a593Smuzhiyun /* Reset Configuration Register to Disable Watch Dog Registers */
1526*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_CONFIG);
1527*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_CONFIG, tmp & ~0x04);
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun unregister_reboot_notifier(&watchdog_notifier);
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun hwmon_device_unregister(data->hwmon_dev);
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
1534*4882a593Smuzhiyun device_remove_file(dev,
1535*4882a593Smuzhiyun &w83793_sensor_attr_2[i].dev_attr);
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
1538*4882a593Smuzhiyun device_remove_file(dev, &sda_single_files[i].dev_attr);
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
1541*4882a593Smuzhiyun device_remove_file(dev, &w83793_vid[i].dev_attr);
1542*4882a593Smuzhiyun device_remove_file(dev, &dev_attr_vrm);
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
1545*4882a593Smuzhiyun device_remove_file(dev, &w83793_left_fan[i].dev_attr);
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
1548*4882a593Smuzhiyun device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
1551*4882a593Smuzhiyun device_remove_file(dev, &w83793_temp[i].dev_attr);
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun /* Decrease data reference counter */
1554*4882a593Smuzhiyun mutex_lock(&watchdog_data_mutex);
1555*4882a593Smuzhiyun kref_put(&data->kref, w83793_release_resources);
1556*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun return 0;
1559*4882a593Smuzhiyun }
1560*4882a593Smuzhiyun
1561*4882a593Smuzhiyun static int
w83793_detect_subclients(struct i2c_client * client)1562*4882a593Smuzhiyun w83793_detect_subclients(struct i2c_client *client)
1563*4882a593Smuzhiyun {
1564*4882a593Smuzhiyun int i, id;
1565*4882a593Smuzhiyun int address = client->addr;
1566*4882a593Smuzhiyun u8 tmp;
1567*4882a593Smuzhiyun struct i2c_adapter *adapter = client->adapter;
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun id = i2c_adapter_id(adapter);
1570*4882a593Smuzhiyun if (force_subclients[0] == id && force_subclients[1] == address) {
1571*4882a593Smuzhiyun for (i = 2; i <= 3; i++) {
1572*4882a593Smuzhiyun if (force_subclients[i] < 0x48
1573*4882a593Smuzhiyun || force_subclients[i] > 0x4f) {
1574*4882a593Smuzhiyun dev_err(&client->dev,
1575*4882a593Smuzhiyun "invalid subclient "
1576*4882a593Smuzhiyun "address %d; must be 0x48-0x4f\n",
1577*4882a593Smuzhiyun force_subclients[i]);
1578*4882a593Smuzhiyun return -EINVAL;
1579*4882a593Smuzhiyun }
1580*4882a593Smuzhiyun }
1581*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_I2C_SUBADDR,
1582*4882a593Smuzhiyun (force_subclients[2] & 0x07) |
1583*4882a593Smuzhiyun ((force_subclients[3] & 0x07) << 4));
1584*4882a593Smuzhiyun }
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun if (!(tmp & 0x88) && (tmp & 0x7) == ((tmp >> 4) & 0x7)) {
1589*4882a593Smuzhiyun dev_err(&client->dev,
1590*4882a593Smuzhiyun "duplicate addresses 0x%x, use force_subclient\n", 0x48 + (tmp & 0x7));
1591*4882a593Smuzhiyun return -ENODEV;
1592*4882a593Smuzhiyun }
1593*4882a593Smuzhiyun
1594*4882a593Smuzhiyun if (!(tmp & 0x08))
1595*4882a593Smuzhiyun devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + (tmp & 0x7));
1596*4882a593Smuzhiyun
1597*4882a593Smuzhiyun if (!(tmp & 0x80))
1598*4882a593Smuzhiyun devm_i2c_new_dummy_device(&client->dev, adapter, 0x48 + ((tmp >> 4) & 0x7));
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun return 0;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun /* Return 0 if detection is successful, -ENODEV otherwise */
w83793_detect(struct i2c_client * client,struct i2c_board_info * info)1604*4882a593Smuzhiyun static int w83793_detect(struct i2c_client *client,
1605*4882a593Smuzhiyun struct i2c_board_info *info)
1606*4882a593Smuzhiyun {
1607*4882a593Smuzhiyun u8 tmp, bank, chip_id;
1608*4882a593Smuzhiyun struct i2c_adapter *adapter = client->adapter;
1609*4882a593Smuzhiyun unsigned short address = client->addr;
1610*4882a593Smuzhiyun
1611*4882a593Smuzhiyun if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1612*4882a593Smuzhiyun return -ENODEV;
1613*4882a593Smuzhiyun
1614*4882a593Smuzhiyun bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
1615*4882a593Smuzhiyun
1616*4882a593Smuzhiyun tmp = bank & 0x80 ? 0x5c : 0xa3;
1617*4882a593Smuzhiyun /* Check Winbond vendor ID */
1618*4882a593Smuzhiyun if (tmp != i2c_smbus_read_byte_data(client, W83793_REG_VENDORID)) {
1619*4882a593Smuzhiyun pr_debug("w83793: Detection failed at check vendor id\n");
1620*4882a593Smuzhiyun return -ENODEV;
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun /*
1624*4882a593Smuzhiyun * If Winbond chip, address of chip and W83793_REG_I2C_ADDR
1625*4882a593Smuzhiyun * should match
1626*4882a593Smuzhiyun */
1627*4882a593Smuzhiyun if ((bank & 0x07) == 0
1628*4882a593Smuzhiyun && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
1629*4882a593Smuzhiyun (address << 1)) {
1630*4882a593Smuzhiyun pr_debug("w83793: Detection failed at check i2c addr\n");
1631*4882a593Smuzhiyun return -ENODEV;
1632*4882a593Smuzhiyun }
1633*4882a593Smuzhiyun
1634*4882a593Smuzhiyun /* Determine the chip type now */
1635*4882a593Smuzhiyun chip_id = i2c_smbus_read_byte_data(client, W83793_REG_CHIPID);
1636*4882a593Smuzhiyun if (chip_id != 0x7b)
1637*4882a593Smuzhiyun return -ENODEV;
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun strlcpy(info->type, "w83793", I2C_NAME_SIZE);
1640*4882a593Smuzhiyun
1641*4882a593Smuzhiyun return 0;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun
w83793_probe(struct i2c_client * client)1644*4882a593Smuzhiyun static int w83793_probe(struct i2c_client *client)
1645*4882a593Smuzhiyun {
1646*4882a593Smuzhiyun struct device *dev = &client->dev;
1647*4882a593Smuzhiyun static const int watchdog_minors[] = {
1648*4882a593Smuzhiyun WATCHDOG_MINOR, 212, 213, 214, 215
1649*4882a593Smuzhiyun };
1650*4882a593Smuzhiyun struct w83793_data *data;
1651*4882a593Smuzhiyun int i, tmp, val, err;
1652*4882a593Smuzhiyun int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
1653*4882a593Smuzhiyun int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
1654*4882a593Smuzhiyun int files_temp = ARRAY_SIZE(w83793_temp) / 6;
1655*4882a593Smuzhiyun
1656*4882a593Smuzhiyun data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL);
1657*4882a593Smuzhiyun if (!data) {
1658*4882a593Smuzhiyun err = -ENOMEM;
1659*4882a593Smuzhiyun goto exit;
1660*4882a593Smuzhiyun }
1661*4882a593Smuzhiyun
1662*4882a593Smuzhiyun i2c_set_clientdata(client, data);
1663*4882a593Smuzhiyun data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
1664*4882a593Smuzhiyun mutex_init(&data->update_lock);
1665*4882a593Smuzhiyun mutex_init(&data->watchdog_lock);
1666*4882a593Smuzhiyun INIT_LIST_HEAD(&data->list);
1667*4882a593Smuzhiyun kref_init(&data->kref);
1668*4882a593Smuzhiyun
1669*4882a593Smuzhiyun /*
1670*4882a593Smuzhiyun * Store client pointer in our data struct for watchdog usage
1671*4882a593Smuzhiyun * (where the client is found through a data ptr instead of the
1672*4882a593Smuzhiyun * otherway around)
1673*4882a593Smuzhiyun */
1674*4882a593Smuzhiyun data->client = client;
1675*4882a593Smuzhiyun
1676*4882a593Smuzhiyun err = w83793_detect_subclients(client);
1677*4882a593Smuzhiyun if (err)
1678*4882a593Smuzhiyun goto free_mem;
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun /* Initialize the chip */
1681*4882a593Smuzhiyun w83793_init_client(client);
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun /*
1684*4882a593Smuzhiyun * Only fan 1-5 has their own input pins,
1685*4882a593Smuzhiyun * Pwm 1-3 has their own pins
1686*4882a593Smuzhiyun */
1687*4882a593Smuzhiyun data->has_fan = 0x1f;
1688*4882a593Smuzhiyun data->has_pwm = 0x07;
1689*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_MFC);
1690*4882a593Smuzhiyun val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun /* check the function of pins 49-56 */
1693*4882a593Smuzhiyun if (tmp & 0x80) {
1694*4882a593Smuzhiyun data->has_vid |= 0x2; /* has VIDB */
1695*4882a593Smuzhiyun } else {
1696*4882a593Smuzhiyun data->has_pwm |= 0x18; /* pwm 4,5 */
1697*4882a593Smuzhiyun if (val & 0x01) { /* fan 6 */
1698*4882a593Smuzhiyun data->has_fan |= 0x20;
1699*4882a593Smuzhiyun data->has_pwm |= 0x20;
1700*4882a593Smuzhiyun }
1701*4882a593Smuzhiyun if (val & 0x02) { /* fan 7 */
1702*4882a593Smuzhiyun data->has_fan |= 0x40;
1703*4882a593Smuzhiyun data->has_pwm |= 0x40;
1704*4882a593Smuzhiyun }
1705*4882a593Smuzhiyun if (!(tmp & 0x40) && (val & 0x04)) { /* fan 8 */
1706*4882a593Smuzhiyun data->has_fan |= 0x80;
1707*4882a593Smuzhiyun data->has_pwm |= 0x80;
1708*4882a593Smuzhiyun }
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun /* check the function of pins 37-40 */
1712*4882a593Smuzhiyun if (!(tmp & 0x29))
1713*4882a593Smuzhiyun data->has_vid |= 0x1; /* has VIDA */
1714*4882a593Smuzhiyun if (0x08 == (tmp & 0x0c)) {
1715*4882a593Smuzhiyun if (val & 0x08) /* fan 9 */
1716*4882a593Smuzhiyun data->has_fan |= 0x100;
1717*4882a593Smuzhiyun if (val & 0x10) /* fan 10 */
1718*4882a593Smuzhiyun data->has_fan |= 0x200;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun if (0x20 == (tmp & 0x30)) {
1721*4882a593Smuzhiyun if (val & 0x20) /* fan 11 */
1722*4882a593Smuzhiyun data->has_fan |= 0x400;
1723*4882a593Smuzhiyun if (val & 0x40) /* fan 12 */
1724*4882a593Smuzhiyun data->has_fan |= 0x800;
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun
1727*4882a593Smuzhiyun if ((tmp & 0x01) && (val & 0x04)) { /* fan 8, second location */
1728*4882a593Smuzhiyun data->has_fan |= 0x80;
1729*4882a593Smuzhiyun data->has_pwm |= 0x80;
1730*4882a593Smuzhiyun }
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_FANIN_SEL);
1733*4882a593Smuzhiyun if ((tmp & 0x01) && (val & 0x08)) { /* fan 9, second location */
1734*4882a593Smuzhiyun data->has_fan |= 0x100;
1735*4882a593Smuzhiyun }
1736*4882a593Smuzhiyun if ((tmp & 0x02) && (val & 0x10)) { /* fan 10, second location */
1737*4882a593Smuzhiyun data->has_fan |= 0x200;
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun if ((tmp & 0x04) && (val & 0x20)) { /* fan 11, second location */
1740*4882a593Smuzhiyun data->has_fan |= 0x400;
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun if ((tmp & 0x08) && (val & 0x40)) { /* fan 12, second location */
1743*4882a593Smuzhiyun data->has_fan |= 0x800;
1744*4882a593Smuzhiyun }
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun /* check the temp1-6 mode, ignore former AMDSI selected inputs */
1747*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[0]);
1748*4882a593Smuzhiyun if (tmp & 0x01)
1749*4882a593Smuzhiyun data->has_temp |= 0x01;
1750*4882a593Smuzhiyun if (tmp & 0x04)
1751*4882a593Smuzhiyun data->has_temp |= 0x02;
1752*4882a593Smuzhiyun if (tmp & 0x10)
1753*4882a593Smuzhiyun data->has_temp |= 0x04;
1754*4882a593Smuzhiyun if (tmp & 0x40)
1755*4882a593Smuzhiyun data->has_temp |= 0x08;
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[1]);
1758*4882a593Smuzhiyun if (tmp & 0x01)
1759*4882a593Smuzhiyun data->has_temp |= 0x10;
1760*4882a593Smuzhiyun if (tmp & 0x02)
1761*4882a593Smuzhiyun data->has_temp |= 0x20;
1762*4882a593Smuzhiyun
1763*4882a593Smuzhiyun /* Register sysfs hooks */
1764*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
1765*4882a593Smuzhiyun err = device_create_file(dev,
1766*4882a593Smuzhiyun &w83793_sensor_attr_2[i].dev_attr);
1767*4882a593Smuzhiyun if (err)
1768*4882a593Smuzhiyun goto exit_remove;
1769*4882a593Smuzhiyun }
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) {
1772*4882a593Smuzhiyun if (!(data->has_vid & (1 << i)))
1773*4882a593Smuzhiyun continue;
1774*4882a593Smuzhiyun err = device_create_file(dev, &w83793_vid[i].dev_attr);
1775*4882a593Smuzhiyun if (err)
1776*4882a593Smuzhiyun goto exit_remove;
1777*4882a593Smuzhiyun }
1778*4882a593Smuzhiyun if (data->has_vid) {
1779*4882a593Smuzhiyun data->vrm = vid_which_vrm();
1780*4882a593Smuzhiyun err = device_create_file(dev, &dev_attr_vrm);
1781*4882a593Smuzhiyun if (err)
1782*4882a593Smuzhiyun goto exit_remove;
1783*4882a593Smuzhiyun }
1784*4882a593Smuzhiyun
1785*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
1786*4882a593Smuzhiyun err = device_create_file(dev, &sda_single_files[i].dev_attr);
1787*4882a593Smuzhiyun if (err)
1788*4882a593Smuzhiyun goto exit_remove;
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun }
1791*4882a593Smuzhiyun
1792*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
1793*4882a593Smuzhiyun int j;
1794*4882a593Smuzhiyun if (!(data->has_temp & (1 << i)))
1795*4882a593Smuzhiyun continue;
1796*4882a593Smuzhiyun for (j = 0; j < files_temp; j++) {
1797*4882a593Smuzhiyun err = device_create_file(dev,
1798*4882a593Smuzhiyun &w83793_temp[(i) * files_temp
1799*4882a593Smuzhiyun + j].dev_attr);
1800*4882a593Smuzhiyun if (err)
1801*4882a593Smuzhiyun goto exit_remove;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun for (i = 5; i < 12; i++) {
1806*4882a593Smuzhiyun int j;
1807*4882a593Smuzhiyun if (!(data->has_fan & (1 << i)))
1808*4882a593Smuzhiyun continue;
1809*4882a593Smuzhiyun for (j = 0; j < files_fan; j++) {
1810*4882a593Smuzhiyun err = device_create_file(dev,
1811*4882a593Smuzhiyun &w83793_left_fan[(i - 5) * files_fan
1812*4882a593Smuzhiyun + j].dev_attr);
1813*4882a593Smuzhiyun if (err)
1814*4882a593Smuzhiyun goto exit_remove;
1815*4882a593Smuzhiyun }
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun for (i = 3; i < 8; i++) {
1819*4882a593Smuzhiyun int j;
1820*4882a593Smuzhiyun if (!(data->has_pwm & (1 << i)))
1821*4882a593Smuzhiyun continue;
1822*4882a593Smuzhiyun for (j = 0; j < files_pwm; j++) {
1823*4882a593Smuzhiyun err = device_create_file(dev,
1824*4882a593Smuzhiyun &w83793_left_pwm[(i - 3) * files_pwm
1825*4882a593Smuzhiyun + j].dev_attr);
1826*4882a593Smuzhiyun if (err)
1827*4882a593Smuzhiyun goto exit_remove;
1828*4882a593Smuzhiyun }
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun data->hwmon_dev = hwmon_device_register(dev);
1832*4882a593Smuzhiyun if (IS_ERR(data->hwmon_dev)) {
1833*4882a593Smuzhiyun err = PTR_ERR(data->hwmon_dev);
1834*4882a593Smuzhiyun goto exit_remove;
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun /* Watchdog initialization */
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun /* Register boot notifier */
1840*4882a593Smuzhiyun err = register_reboot_notifier(&watchdog_notifier);
1841*4882a593Smuzhiyun if (err != 0) {
1842*4882a593Smuzhiyun dev_err(&client->dev,
1843*4882a593Smuzhiyun "cannot register reboot notifier (err=%d)\n", err);
1844*4882a593Smuzhiyun goto exit_devunreg;
1845*4882a593Smuzhiyun }
1846*4882a593Smuzhiyun
1847*4882a593Smuzhiyun /*
1848*4882a593Smuzhiyun * Enable Watchdog registers.
1849*4882a593Smuzhiyun * Set Configuration Register to Enable Watch Dog Registers
1850*4882a593Smuzhiyun * (Bit 2) = XXXX, X1XX.
1851*4882a593Smuzhiyun */
1852*4882a593Smuzhiyun tmp = w83793_read_value(client, W83793_REG_CONFIG);
1853*4882a593Smuzhiyun w83793_write_value(client, W83793_REG_CONFIG, tmp | 0x04);
1854*4882a593Smuzhiyun
1855*4882a593Smuzhiyun /* Set the default watchdog timeout */
1856*4882a593Smuzhiyun data->watchdog_timeout = timeout;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun /* Check, if last reboot was caused by watchdog */
1859*4882a593Smuzhiyun data->watchdog_caused_reboot =
1860*4882a593Smuzhiyun w83793_read_value(data->client, W83793_REG_WDT_STATUS) & 0x01;
1861*4882a593Smuzhiyun
1862*4882a593Smuzhiyun /* Disable Soft Watchdog during initialiation */
1863*4882a593Smuzhiyun watchdog_disable(data);
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun /*
1866*4882a593Smuzhiyun * We take the data_mutex lock early so that watchdog_open() cannot
1867*4882a593Smuzhiyun * run when misc_register() has completed, but we've not yet added
1868*4882a593Smuzhiyun * our data to the watchdog_data_list (and set the default timeout)
1869*4882a593Smuzhiyun */
1870*4882a593Smuzhiyun mutex_lock(&watchdog_data_mutex);
1871*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
1872*4882a593Smuzhiyun /* Register our watchdog part */
1873*4882a593Smuzhiyun snprintf(data->watchdog_name, sizeof(data->watchdog_name),
1874*4882a593Smuzhiyun "watchdog%c", (i == 0) ? '\0' : ('0' + i));
1875*4882a593Smuzhiyun data->watchdog_miscdev.name = data->watchdog_name;
1876*4882a593Smuzhiyun data->watchdog_miscdev.fops = &watchdog_fops;
1877*4882a593Smuzhiyun data->watchdog_miscdev.minor = watchdog_minors[i];
1878*4882a593Smuzhiyun
1879*4882a593Smuzhiyun err = misc_register(&data->watchdog_miscdev);
1880*4882a593Smuzhiyun if (err == -EBUSY)
1881*4882a593Smuzhiyun continue;
1882*4882a593Smuzhiyun if (err) {
1883*4882a593Smuzhiyun data->watchdog_miscdev.minor = 0;
1884*4882a593Smuzhiyun dev_err(&client->dev,
1885*4882a593Smuzhiyun "Registering watchdog chardev: %d\n", err);
1886*4882a593Smuzhiyun break;
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun list_add(&data->list, &watchdog_data_list);
1890*4882a593Smuzhiyun
1891*4882a593Smuzhiyun dev_info(&client->dev,
1892*4882a593Smuzhiyun "Registered watchdog chardev major 10, minor: %d\n",
1893*4882a593Smuzhiyun watchdog_minors[i]);
1894*4882a593Smuzhiyun break;
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun if (i == ARRAY_SIZE(watchdog_minors)) {
1897*4882a593Smuzhiyun data->watchdog_miscdev.minor = 0;
1898*4882a593Smuzhiyun dev_warn(&client->dev,
1899*4882a593Smuzhiyun "Couldn't register watchdog chardev (due to no free minor)\n");
1900*4882a593Smuzhiyun }
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun mutex_unlock(&watchdog_data_mutex);
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun return 0;
1905*4882a593Smuzhiyun
1906*4882a593Smuzhiyun /* Unregister hwmon device */
1907*4882a593Smuzhiyun
1908*4882a593Smuzhiyun exit_devunreg:
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun hwmon_device_unregister(data->hwmon_dev);
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun /* Unregister sysfs hooks */
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun exit_remove:
1915*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
1916*4882a593Smuzhiyun device_remove_file(dev, &w83793_sensor_attr_2[i].dev_attr);
1917*4882a593Smuzhiyun
1918*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
1919*4882a593Smuzhiyun device_remove_file(dev, &sda_single_files[i].dev_attr);
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
1922*4882a593Smuzhiyun device_remove_file(dev, &w83793_vid[i].dev_attr);
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
1925*4882a593Smuzhiyun device_remove_file(dev, &w83793_left_fan[i].dev_attr);
1926*4882a593Smuzhiyun
1927*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
1928*4882a593Smuzhiyun device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
1929*4882a593Smuzhiyun
1930*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
1931*4882a593Smuzhiyun device_remove_file(dev, &w83793_temp[i].dev_attr);
1932*4882a593Smuzhiyun free_mem:
1933*4882a593Smuzhiyun kfree(data);
1934*4882a593Smuzhiyun exit:
1935*4882a593Smuzhiyun return err;
1936*4882a593Smuzhiyun }
1937*4882a593Smuzhiyun
w83793_update_nonvolatile(struct device * dev)1938*4882a593Smuzhiyun static void w83793_update_nonvolatile(struct device *dev)
1939*4882a593Smuzhiyun {
1940*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
1941*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
1942*4882a593Smuzhiyun int i, j;
1943*4882a593Smuzhiyun /*
1944*4882a593Smuzhiyun * They are somewhat "stable" registers, and to update them every time
1945*4882a593Smuzhiyun * takes so much time, it's just not worthy. Update them in a long
1946*4882a593Smuzhiyun * interval to avoid exception.
1947*4882a593Smuzhiyun */
1948*4882a593Smuzhiyun if (!(time_after(jiffies, data->last_nonvolatile + HZ * 300)
1949*4882a593Smuzhiyun || !data->valid))
1950*4882a593Smuzhiyun return;
1951*4882a593Smuzhiyun /* update voltage limits */
1952*4882a593Smuzhiyun for (i = 1; i < 3; i++) {
1953*4882a593Smuzhiyun for (j = 0; j < ARRAY_SIZE(data->in); j++) {
1954*4882a593Smuzhiyun data->in[j][i] =
1955*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_IN[j][i]);
1956*4882a593Smuzhiyun }
1957*4882a593Smuzhiyun data->in_low_bits[i] =
1958*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_IN_LOW_BITS[i]);
1959*4882a593Smuzhiyun }
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
1962*4882a593Smuzhiyun /* Update the Fan measured value and limits */
1963*4882a593Smuzhiyun if (!(data->has_fan & (1 << i)))
1964*4882a593Smuzhiyun continue;
1965*4882a593Smuzhiyun data->fan_min[i] =
1966*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_FAN_MIN(i)) << 8;
1967*4882a593Smuzhiyun data->fan_min[i] |=
1968*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_FAN_MIN(i) + 1);
1969*4882a593Smuzhiyun }
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->temp_fan_map); i++) {
1972*4882a593Smuzhiyun if (!(data->has_temp & (1 << i)))
1973*4882a593Smuzhiyun continue;
1974*4882a593Smuzhiyun data->temp_fan_map[i] =
1975*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_FAN_MAP(i));
1976*4882a593Smuzhiyun for (j = 1; j < 5; j++) {
1977*4882a593Smuzhiyun data->temp[i][j] =
1978*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP[i][j]);
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun data->temp_cruise[i] =
1981*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_CRUISE(i));
1982*4882a593Smuzhiyun for (j = 0; j < 7; j++) {
1983*4882a593Smuzhiyun data->sf2_pwm[i][j] =
1984*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_SF2_PWM(i, j));
1985*4882a593Smuzhiyun data->sf2_temp[i][j] =
1986*4882a593Smuzhiyun w83793_read_value(client,
1987*4882a593Smuzhiyun W83793_REG_SF2_TEMP(i, j));
1988*4882a593Smuzhiyun }
1989*4882a593Smuzhiyun }
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->temp_mode); i++)
1992*4882a593Smuzhiyun data->temp_mode[i] =
1993*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_MODE[i]);
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->tolerance); i++) {
1996*4882a593Smuzhiyun data->tolerance[i] =
1997*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_TOL(i));
1998*4882a593Smuzhiyun }
1999*4882a593Smuzhiyun
2000*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
2001*4882a593Smuzhiyun if (!(data->has_pwm & (1 << i)))
2002*4882a593Smuzhiyun continue;
2003*4882a593Smuzhiyun data->pwm[i][PWM_NONSTOP] =
2004*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM(i, PWM_NONSTOP));
2005*4882a593Smuzhiyun data->pwm[i][PWM_START] =
2006*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM(i, PWM_START));
2007*4882a593Smuzhiyun data->pwm_stop_time[i] =
2008*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_PWM_STOP_TIME(i));
2009*4882a593Smuzhiyun }
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT);
2012*4882a593Smuzhiyun data->pwm_enable = w83793_read_value(client, W83793_REG_PWM_ENABLE);
2013*4882a593Smuzhiyun data->pwm_uptime = w83793_read_value(client, W83793_REG_PWM_UPTIME);
2014*4882a593Smuzhiyun data->pwm_downtime = w83793_read_value(client, W83793_REG_PWM_DOWNTIME);
2015*4882a593Smuzhiyun data->temp_critical =
2016*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_CRITICAL);
2017*4882a593Smuzhiyun data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP);
2018*4882a593Smuzhiyun
2019*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
2020*4882a593Smuzhiyun data->beeps[i] = w83793_read_value(client, W83793_REG_BEEP(i));
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun data->last_nonvolatile = jiffies;
2023*4882a593Smuzhiyun }
2024*4882a593Smuzhiyun
w83793_update_device(struct device * dev)2025*4882a593Smuzhiyun static struct w83793_data *w83793_update_device(struct device *dev)
2026*4882a593Smuzhiyun {
2027*4882a593Smuzhiyun struct i2c_client *client = to_i2c_client(dev);
2028*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
2029*4882a593Smuzhiyun int i;
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun mutex_lock(&data->update_lock);
2032*4882a593Smuzhiyun
2033*4882a593Smuzhiyun if (!(time_after(jiffies, data->last_updated + HZ * 2)
2034*4882a593Smuzhiyun || !data->valid))
2035*4882a593Smuzhiyun goto END;
2036*4882a593Smuzhiyun
2037*4882a593Smuzhiyun /* Update the voltages measured value and limits */
2038*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->in); i++)
2039*4882a593Smuzhiyun data->in[i][IN_READ] =
2040*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_IN[i][IN_READ]);
2041*4882a593Smuzhiyun
2042*4882a593Smuzhiyun data->in_low_bits[IN_READ] =
2043*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_IN_LOW_BITS[IN_READ]);
2044*4882a593Smuzhiyun
2045*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
2046*4882a593Smuzhiyun if (!(data->has_fan & (1 << i)))
2047*4882a593Smuzhiyun continue;
2048*4882a593Smuzhiyun data->fan[i] =
2049*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_FAN(i)) << 8;
2050*4882a593Smuzhiyun data->fan[i] |=
2051*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_FAN(i) + 1);
2052*4882a593Smuzhiyun }
2053*4882a593Smuzhiyun
2054*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
2055*4882a593Smuzhiyun if (!(data->has_temp & (1 << i)))
2056*4882a593Smuzhiyun continue;
2057*4882a593Smuzhiyun data->temp[i][TEMP_READ] =
2058*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP[i][TEMP_READ]);
2059*4882a593Smuzhiyun }
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun data->temp_low_bits =
2062*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_TEMP_LOW_BITS);
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->pwm); i++) {
2065*4882a593Smuzhiyun if (data->has_pwm & (1 << i))
2066*4882a593Smuzhiyun data->pwm[i][PWM_DUTY] =
2067*4882a593Smuzhiyun w83793_read_value(client,
2068*4882a593Smuzhiyun W83793_REG_PWM(i, PWM_DUTY));
2069*4882a593Smuzhiyun }
2070*4882a593Smuzhiyun
2071*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
2072*4882a593Smuzhiyun data->alarms[i] =
2073*4882a593Smuzhiyun w83793_read_value(client, W83793_REG_ALARM(i));
2074*4882a593Smuzhiyun if (data->has_vid & 0x01)
2075*4882a593Smuzhiyun data->vid[0] = w83793_read_value(client, W83793_REG_VID_INA);
2076*4882a593Smuzhiyun if (data->has_vid & 0x02)
2077*4882a593Smuzhiyun data->vid[1] = w83793_read_value(client, W83793_REG_VID_INB);
2078*4882a593Smuzhiyun w83793_update_nonvolatile(dev);
2079*4882a593Smuzhiyun data->last_updated = jiffies;
2080*4882a593Smuzhiyun data->valid = 1;
2081*4882a593Smuzhiyun
2082*4882a593Smuzhiyun END:
2083*4882a593Smuzhiyun mutex_unlock(&data->update_lock);
2084*4882a593Smuzhiyun return data;
2085*4882a593Smuzhiyun }
2086*4882a593Smuzhiyun
2087*4882a593Smuzhiyun /*
2088*4882a593Smuzhiyun * Ignore the possibility that somebody change bank outside the driver
2089*4882a593Smuzhiyun * Must be called with data->update_lock held, except during initialization
2090*4882a593Smuzhiyun */
w83793_read_value(struct i2c_client * client,u16 reg)2091*4882a593Smuzhiyun static u8 w83793_read_value(struct i2c_client *client, u16 reg)
2092*4882a593Smuzhiyun {
2093*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
2094*4882a593Smuzhiyun u8 res;
2095*4882a593Smuzhiyun u8 new_bank = reg >> 8;
2096*4882a593Smuzhiyun
2097*4882a593Smuzhiyun new_bank |= data->bank & 0xfc;
2098*4882a593Smuzhiyun if (data->bank != new_bank) {
2099*4882a593Smuzhiyun if (i2c_smbus_write_byte_data
2100*4882a593Smuzhiyun (client, W83793_REG_BANKSEL, new_bank) >= 0)
2101*4882a593Smuzhiyun data->bank = new_bank;
2102*4882a593Smuzhiyun else {
2103*4882a593Smuzhiyun dev_err(&client->dev,
2104*4882a593Smuzhiyun "set bank to %d failed, fall back "
2105*4882a593Smuzhiyun "to bank %d, read reg 0x%x error\n",
2106*4882a593Smuzhiyun new_bank, data->bank, reg);
2107*4882a593Smuzhiyun res = 0x0; /* read 0x0 from the chip */
2108*4882a593Smuzhiyun goto END;
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun }
2111*4882a593Smuzhiyun res = i2c_smbus_read_byte_data(client, reg & 0xff);
2112*4882a593Smuzhiyun END:
2113*4882a593Smuzhiyun return res;
2114*4882a593Smuzhiyun }
2115*4882a593Smuzhiyun
2116*4882a593Smuzhiyun /* Must be called with data->update_lock held, except during initialization */
w83793_write_value(struct i2c_client * client,u16 reg,u8 value)2117*4882a593Smuzhiyun static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value)
2118*4882a593Smuzhiyun {
2119*4882a593Smuzhiyun struct w83793_data *data = i2c_get_clientdata(client);
2120*4882a593Smuzhiyun int res;
2121*4882a593Smuzhiyun u8 new_bank = reg >> 8;
2122*4882a593Smuzhiyun
2123*4882a593Smuzhiyun new_bank |= data->bank & 0xfc;
2124*4882a593Smuzhiyun if (data->bank != new_bank) {
2125*4882a593Smuzhiyun res = i2c_smbus_write_byte_data(client, W83793_REG_BANKSEL,
2126*4882a593Smuzhiyun new_bank);
2127*4882a593Smuzhiyun if (res < 0) {
2128*4882a593Smuzhiyun dev_err(&client->dev,
2129*4882a593Smuzhiyun "set bank to %d failed, fall back "
2130*4882a593Smuzhiyun "to bank %d, write reg 0x%x error\n",
2131*4882a593Smuzhiyun new_bank, data->bank, reg);
2132*4882a593Smuzhiyun goto END;
2133*4882a593Smuzhiyun }
2134*4882a593Smuzhiyun data->bank = new_bank;
2135*4882a593Smuzhiyun }
2136*4882a593Smuzhiyun
2137*4882a593Smuzhiyun res = i2c_smbus_write_byte_data(client, reg & 0xff, value);
2138*4882a593Smuzhiyun END:
2139*4882a593Smuzhiyun return res;
2140*4882a593Smuzhiyun }
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun module_i2c_driver(w83793_driver);
2143*4882a593Smuzhiyun
2144*4882a593Smuzhiyun MODULE_AUTHOR("Yuan Mu, Sven Anders");
2145*4882a593Smuzhiyun MODULE_DESCRIPTION("w83793 driver");
2146*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2147