Blame view

drivers/hwmon/fschmd.c 38.6 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
2
3
  /*
   * fschmd.c
569ff1022   Hans de Goede   hwmon: Add new co...
4
   *
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
5
   * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
569ff1022   Hans de Goede   hwmon: Add new co...
6
7
8
9
   */
  
  /*
   *  Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
de15f093e   Hans de Goede   hwmon: (fschmd) A...
10
   *  Scylla, Heracles, Heimdall, Hades and Syleus chips
569ff1022   Hans de Goede   hwmon: Add new co...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   *
   *  Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
   *  (candidate) fschmd drivers:
   *  Copyright (C) 2006 Thilo Cestonaro
   *			<thilo.cestonaro.external@fujitsu-siemens.com>
   *  Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
   *  Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
   *  Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
   *  Copyright (C) 2000 Hermann Jung <hej@odn.de>
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  #include <linux/err.h>
  #include <linux/mutex.h>
  #include <linux/sysfs.h>
7845cd791   Hans de Goede   hwmon: (fschmd) R...
32
  #include <linux/dmi.h>
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
33
34
35
36
37
  #include <linux/fs.h>
  #include <linux/watchdog.h>
  #include <linux/miscdevice.h>
  #include <linux/uaccess.h>
  #include <linux/kref.h>
569ff1022   Hans de Goede   hwmon: Add new co...
38
39
  
  /* Addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
40
  static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
569ff1022   Hans de Goede   hwmon: Add new co...
41
42
  
  /* Insmod parameters */
86a1e1896   Wim Van Sebroeck   watchdog: nowayou...
43
44
  static bool nowayout = WATCHDOG_NOWAYOUT;
  module_param(nowayout, bool, 0);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
45
46
  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
e5e9f44c2   Jean Delvare   i2c: Drop I2C_CLI...
47
48
  
  enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
569ff1022   Hans de Goede   hwmon: Add new co...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  
  /*
   * The FSCHMD registers and other defines
   */
  
  /* chip identification */
  #define FSCHMD_REG_IDENT_0		0x00
  #define FSCHMD_REG_IDENT_1		0x01
  #define FSCHMD_REG_IDENT_2		0x02
  #define FSCHMD_REG_REVISION		0x03
  
  /* global control and status */
  #define FSCHMD_REG_EVENT_STATE		0x04
  #define FSCHMD_REG_CONTROL		0x05
453e308d7   Hans de Goede   hwmon: (fschmd) C...
63
  #define FSCHMD_CONTROL_ALERT_LED	0x01
569ff1022   Hans de Goede   hwmon: Add new co...
64

97950c3d4   Hans de Goede   hwmon: (fschmd) A...
65
  /* watchdog */
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
66
67
68
69
70
71
  static const u8 FSCHMD_REG_WDOG_CONTROL[7] = {
  	0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
  static const u8 FSCHMD_REG_WDOG_STATE[7] = {
  	0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
  static const u8 FSCHMD_REG_WDOG_PRESET[7] = {
  	0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
569ff1022   Hans de Goede   hwmon: Add new co...
72

97950c3d4   Hans de Goede   hwmon: (fschmd) A...
73
74
75
76
77
78
  #define FSCHMD_WDOG_CONTROL_TRIGGER	0x10
  #define FSCHMD_WDOG_CONTROL_STARTED	0x10 /* the same as trigger */
  #define FSCHMD_WDOG_CONTROL_STOP	0x20
  #define FSCHMD_WDOG_CONTROL_RESOLUTION	0x40
  
  #define FSCHMD_WDOG_STATE_CARDRESET	0x02
569ff1022   Hans de Goede   hwmon: Add new co...
79
  /* voltages, weird order is to keep the same order as the old drivers */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
80
  static const u8 FSCHMD_REG_VOLT[7][6] = {
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
81
82
83
84
85
  	{ 0x45, 0x42, 0x48 },				/* pos */
  	{ 0x45, 0x42, 0x48 },				/* her */
  	{ 0x45, 0x42, 0x48 },				/* scy */
  	{ 0x45, 0x42, 0x48 },				/* hrc */
  	{ 0x45, 0x42, 0x48 },				/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
86
  	{ 0x21, 0x20, 0x22 },				/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
87
88
  	{ 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 },		/* syl */
  };
de15f093e   Hans de Goede   hwmon: (fschmd) A...
89
  static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
569ff1022   Hans de Goede   hwmon: Add new co...
90

525ad3731   Guenter Roeck   hwmon: (fschmd) F...
91
  /*
2b2acdc88   Wolfram Sang   hwmon: (fschmd) f...
92
   * minimum pwm at which the fan is driven (pwm can be increased depending on
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
93
94
95
96
   * the temp. Notice that for the scy some fans share there minimum speed.
   * Also notice that with the scy the sensor order is different than with the
   * other chips, this order was in the 2.4 driver and kept for consistency.
   */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
97
  static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
569ff1022   Hans de Goede   hwmon: Add new co...
98
99
100
101
102
  	{ 0x55, 0x65 },					/* pos */
  	{ 0x55, 0x65, 0xb5 },				/* her */
  	{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 },		/* scy */
  	{ 0x55, 0x65, 0xa5, 0xb5 },			/* hrc */
  	{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
103
  	{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
104
  	{ 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 },	/* syl */
569ff1022   Hans de Goede   hwmon: Add new co...
105
106
107
  };
  
  /* actual fan speed */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
108
  static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
569ff1022   Hans de Goede   hwmon: Add new co...
109
110
111
112
113
  	{ 0x0e, 0x6b, 0xab },				/* pos */
  	{ 0x0e, 0x6b, 0xbb },				/* her */
  	{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb },		/* scy */
  	{ 0x0e, 0x6b, 0xab, 0xbb },			/* hrc */
  	{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
114
  	{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
115
  	{ 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 },	/* syl */
569ff1022   Hans de Goede   hwmon: Add new co...
116
117
118
  };
  
  /* fan status registers */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
119
  static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
569ff1022   Hans de Goede   hwmon: Add new co...
120
121
122
123
124
  	{ 0x0d, 0x62, 0xa2 },				/* pos */
  	{ 0x0d, 0x62, 0xb2 },				/* her */
  	{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 },		/* scy */
  	{ 0x0d, 0x62, 0xa2, 0xb2 },			/* hrc */
  	{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
125
  	{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
126
  	{ 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 },	/* syl */
569ff1022   Hans de Goede   hwmon: Add new co...
127
128
129
  };
  
  /* fan ripple / divider registers */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
130
  static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
569ff1022   Hans de Goede   hwmon: Add new co...
131
132
133
134
135
  	{ 0x0f, 0x6f, 0xaf },				/* pos */
  	{ 0x0f, 0x6f, 0xbf },				/* her */
  	{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf },		/* scy */
  	{ 0x0f, 0x6f, 0xaf, 0xbf },			/* hrc */
  	{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
136
  	{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
137
  	{ 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 },	/* syl */
569ff1022   Hans de Goede   hwmon: Add new co...
138
  };
de15f093e   Hans de Goede   hwmon: (fschmd) A...
139
  static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
569ff1022   Hans de Goede   hwmon: Add new co...
140
141
  
  /* Fan status register bitmasks */
453e308d7   Hans de Goede   hwmon: (fschmd) C...
142
  #define FSCHMD_FAN_ALARM	0x04 /* called fault by FSC! */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
143
144
  #define FSCHMD_FAN_NOT_PRESENT	0x08
  #define FSCHMD_FAN_DISABLED	0x80
569ff1022   Hans de Goede   hwmon: Add new co...
145
146
147
  
  
  /* actual temperature registers */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
148
  static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
569ff1022   Hans de Goede   hwmon: Add new co...
149
150
151
152
153
  	{ 0x64, 0x32, 0x35 },				/* pos */
  	{ 0x64, 0x32, 0x35 },				/* her */
  	{ 0x64, 0xD0, 0x32, 0x35 },			/* scy */
  	{ 0x64, 0x32, 0x35 },				/* hrc */
  	{ 0x70, 0x80, 0x90, 0xd0, 0xe0 },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
154
  	{ 0x70, 0x80, 0x90, 0xd0, 0xe0 },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
155
156
  	{ 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8,		/* syl */
  	  0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
569ff1022   Hans de Goede   hwmon: Add new co...
157
158
159
  };
  
  /* temperature state registers */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
160
  static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
569ff1022   Hans de Goede   hwmon: Add new co...
161
162
163
164
  	{ 0x71, 0x81, 0x91 },				/* pos */
  	{ 0x71, 0x81, 0x91 },				/* her */
  	{ 0x71, 0xd1, 0x81, 0x91 },			/* scy */
  	{ 0x71, 0x81, 0x91 },				/* hrc */
7dcf9a31e   Jean Delvare   hwmon: (fschmd) D...
165
  	{ 0x71, 0x81, 0x91, 0xd1, 0xe1 },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
166
  	{ 0x71, 0x81, 0x91, 0xd1, 0xe1 },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
167
168
  	{ 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9,		/* syl */
  	  0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
569ff1022   Hans de Goede   hwmon: Add new co...
169
  };
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
170
171
172
173
174
175
176
  /*
   * temperature high limit registers, FSC does not document these. Proven to be
   * there with field testing on the fscher and fschrc, already supported / used
   * in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
   * at these addresses, but doesn't want to confirm they are the same as with
   * the fscher??
   */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
177
  static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
569ff1022   Hans de Goede   hwmon: Add new co...
178
179
180
181
  	{ 0, 0, 0 },					/* pos */
  	{ 0x76, 0x86, 0x96 },				/* her */
  	{ 0x76, 0xd6, 0x86, 0x96 },			/* scy */
  	{ 0x76, 0x86, 0x96 },				/* hrc */
7dcf9a31e   Jean Delvare   hwmon: (fschmd) D...
182
  	{ 0x76, 0x86, 0x96, 0xd6, 0xe6 },		/* hmd */
de15f093e   Hans de Goede   hwmon: (fschmd) A...
183
  	{ 0x76, 0x86, 0x96, 0xd6, 0xe6 },		/* hds */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
184
185
  	{ 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa,		/* syl */
  	  0xba, 0xca, 0xda, 0xea, 0xfa },
569ff1022   Hans de Goede   hwmon: Add new co...
186
  };
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
187
188
189
190
191
192
193
194
195
  /*
   * These were found through experimenting with an fscher, currently they are
   * not used, but we keep them around for future reference.
   * On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
   * AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
   * the fan speed.
   * static const u8 FSCHER_REG_TEMP_AUTOP1[] =	{ 0x73, 0x83, 0x93 };
   * static const u8 FSCHER_REG_TEMP_AUTOP2[] =	{ 0x75, 0x85, 0x95 };
   */
569ff1022   Hans de Goede   hwmon: Add new co...
196

de15f093e   Hans de Goede   hwmon: (fschmd) A...
197
  static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
569ff1022   Hans de Goede   hwmon: Add new co...
198
199
  
  /* temp status register bitmasks */
453e308d7   Hans de Goede   hwmon: (fschmd) C...
200
201
  #define FSCHMD_TEMP_WORKING	0x01
  #define FSCHMD_TEMP_ALERT	0x02
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
202
  #define FSCHMD_TEMP_DISABLED	0x80
569ff1022   Hans de Goede   hwmon: Add new co...
203
204
  /* there only really is an alarm if the sensor is working and alert == 1 */
  #define FSCHMD_TEMP_ALARM_MASK \
453e308d7   Hans de Goede   hwmon: (fschmd) C...
205
  	(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
569ff1022   Hans de Goede   hwmon: Add new co...
206
207
208
209
  
  /*
   * Functions declarations
   */
674870385   Stephen Kitt   hwmon: use simple...
210
  static int fschmd_probe(struct i2c_client *client);
310ec7921   Jean Delvare   i2c: Drop the kin...
211
  static int fschmd_detect(struct i2c_client *client,
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
212
213
  			 struct i2c_board_info *info);
  static int fschmd_remove(struct i2c_client *client);
569ff1022   Hans de Goede   hwmon: Add new co...
214
215
216
217
218
  static struct fschmd_data *fschmd_update_device(struct device *dev);
  
  /*
   * Driver data (common to all clients)
   */
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
219
220
221
222
223
224
  static const struct i2c_device_id fschmd_id[] = {
  	{ "fscpos", fscpos },
  	{ "fscher", fscher },
  	{ "fscscy", fscscy },
  	{ "fschrc", fschrc },
  	{ "fschmd", fschmd },
de15f093e   Hans de Goede   hwmon: (fschmd) A...
225
  	{ "fschds", fschds },
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
226
  	{ "fscsyl", fscsyl },
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
227
228
229
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, fschmd_id);
569ff1022   Hans de Goede   hwmon: Add new co...
230
  static struct i2c_driver fschmd_driver = {
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
231
  	.class		= I2C_CLASS_HWMON,
569ff1022   Hans de Goede   hwmon: Add new co...
232
  	.driver = {
453e308d7   Hans de Goede   hwmon: (fschmd) C...
233
  		.name	= "fschmd",
569ff1022   Hans de Goede   hwmon: Add new co...
234
  	},
674870385   Stephen Kitt   hwmon: use simple...
235
  	.probe_new	= fschmd_probe,
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
236
237
238
  	.remove		= fschmd_remove,
  	.id_table	= fschmd_id,
  	.detect		= fschmd_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
239
  	.address_list	= normal_i2c,
569ff1022   Hans de Goede   hwmon: Add new co...
240
241
242
243
244
245
246
  };
  
  /*
   * Client data (each client gets its own)
   */
  
  struct fschmd_data {
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
247
  	struct i2c_client *client;
569ff1022   Hans de Goede   hwmon: Add new co...
248
249
  	struct device *hwmon_dev;
  	struct mutex update_lock;
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
250
251
252
253
  	struct mutex watchdog_lock;
  	struct list_head list; /* member of the watchdog_data_list */
  	struct kref kref;
  	struct miscdevice watchdog_miscdev;
dc71afe5a   Jean Delvare   hwmon: Fix off-by...
254
  	enum chips kind;
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
255
256
257
  	unsigned long watchdog_is_open;
  	char watchdog_expect_close;
  	char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
569ff1022   Hans de Goede   hwmon: Add new co...
258
259
260
261
  	char valid; /* zero until following fields are valid */
  	unsigned long last_updated; /* in jiffies */
  
  	/* register values */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
262
  	u8 revision;            /* chip revision */
569ff1022   Hans de Goede   hwmon: Add new co...
263
  	u8 global_control;	/* global control register */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
264
265
266
  	u8 watchdog_control;    /* watchdog control register */
  	u8 watchdog_state;      /* watchdog status register */
  	u8 watchdog_preset;     /* watchdog counter preset on trigger val */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
267
268
269
270
271
272
273
274
  	u8 volt[6];		/* voltage */
  	u8 temp_act[11];	/* temperature */
  	u8 temp_status[11];	/* status of sensor */
  	u8 temp_max[11];	/* high temp limit, notice: undocumented! */
  	u8 fan_act[7];		/* fans revolutions per second */
  	u8 fan_status[7];	/* fan status */
  	u8 fan_min[7];		/* fan min value for rps */
  	u8 fan_ripple[7];	/* divider for rps */
569ff1022   Hans de Goede   hwmon: Add new co...
275
  };
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
276
277
278
279
280
281
282
  /*
   * Global variables to hold information read from special DMI tables, which are
   * available on FSC machines with an fscher or later chip. There is no need to
   * protect these with a lock as they are only modified from our attach function
   * which always gets called with the i2c-core lock held and never accessed
   * before the attach function is done with them.
   */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
283
284
  static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
  static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
7845cd791   Hans de Goede   hwmon: (fschmd) R...
285
  static int dmi_vref = -1;
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
286
287
288
289
290
  /*
   * Somewhat ugly :( global data pointer list with all fschmd devices, so that
   * we can find our device data as when using misc_register there is no other
   * method to get to ones device data from the open fop.
   */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
291
292
293
  static LIST_HEAD(watchdog_data_list);
  /* Note this lock not only protect list access, but also data.kref access */
  static DEFINE_MUTEX(watchdog_data_mutex);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
294
295
296
297
  /*
   * Release our data struct when we're detached from the i2c client *and* all
   * references to our watchdog device are released
   */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
298
299
300
301
302
  static void fschmd_release_resources(struct kref *ref)
  {
  	struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
  	kfree(data);
  }
7845cd791   Hans de Goede   hwmon: (fschmd) R...
303

569ff1022   Hans de Goede   hwmon: Add new co...
304
305
306
  /*
   * Sysfs attr show / store functions
   */
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
307
308
  static ssize_t in_value_show(struct device *dev,
  			     struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
309
310
311
312
  {
  	const int max_reading[3] = { 14200, 6600, 3300 };
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
dc71afe5a   Jean Delvare   hwmon: Fix off-by...
313
  	if (data->kind == fscher || data->kind >= fschrc)
7845cd791   Hans de Goede   hwmon: (fschmd) R...
314
315
316
317
318
319
320
  		return sprintf(buf, "%d
  ", (data->volt[index] * dmi_vref *
  			dmi_mult[index]) / 255 + dmi_offset[index]);
  	else
  		return sprintf(buf, "%d
  ", (data->volt[index] *
  			max_reading[index] + 128) / 255);
569ff1022   Hans de Goede   hwmon: Add new co...
321
322
323
324
  }
  
  
  #define TEMP_FROM_REG(val)	(((val) - 128) * 1000)
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
325
326
  static ssize_t temp_value_show(struct device *dev,
  			       struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
327
328
329
330
331
332
333
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_act[index]));
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
334
335
  static ssize_t temp_max_show(struct device *dev,
  			     struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
336
337
338
339
340
341
342
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	return sprintf(buf, "%d
  ", TEMP_FROM_REG(data->temp_max[index]));
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
343
344
345
  static ssize_t temp_max_store(struct device *dev,
  			      struct device_attribute *devattr,
  			      const char *buf, size_t count)
569ff1022   Hans de Goede   hwmon: Add new co...
346
347
348
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = dev_get_drvdata(dev);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
349
350
351
352
353
354
  	long v;
  	int err;
  
  	err = kstrtol(buf, 10, &v);
  	if (err)
  		return err;
569ff1022   Hans de Goede   hwmon: Add new co...
355

2a844c148   Guenter Roeck   hwmon: Replace SE...
356
  	v = clamp_val(v / 1000, -128, 127) + 128;
569ff1022   Hans de Goede   hwmon: Add new co...
357
358
  
  	mutex_lock(&data->update_lock);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
359
  	i2c_smbus_write_byte_data(to_i2c_client(dev),
569ff1022   Hans de Goede   hwmon: Add new co...
360
361
362
363
364
365
  		FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
  	data->temp_max[index] = v;
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
366
367
  static ssize_t temp_fault_show(struct device *dev,
  			       struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
368
369
370
371
372
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	/* bit 0 set means sensor working ok, so no fault! */
453e308d7   Hans de Goede   hwmon: (fschmd) C...
373
  	if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
569ff1022   Hans de Goede   hwmon: Add new co...
374
375
376
377
378
379
  		return sprintf(buf, "0
  ");
  	else
  		return sprintf(buf, "1
  ");
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
380
381
  static ssize_t temp_alarm_show(struct device *dev,
  			       struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
  			FSCHMD_TEMP_ALARM_MASK)
  		return sprintf(buf, "1
  ");
  	else
  		return sprintf(buf, "0
  ");
  }
  
  
  #define RPM_FROM_REG(val)	((val) * 60)
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
397
398
  static ssize_t fan_value_show(struct device *dev,
  			      struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
399
400
401
402
403
404
405
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	return sprintf(buf, "%u
  ", RPM_FROM_REG(data->fan_act[index]));
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
406
407
  static ssize_t fan_div_show(struct device *dev,
  			    struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
408
409
410
411
412
413
414
415
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
  
  	/* bits 2..7 reserved => mask with 3 */
  	return sprintf(buf, "%d
  ", 1 << (data->fan_ripple[index] & 3));
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
416
417
418
  static ssize_t fan_div_store(struct device *dev,
  			     struct device_attribute *devattr,
  			     const char *buf, size_t count)
569ff1022   Hans de Goede   hwmon: Add new co...
419
420
421
422
423
  {
  	u8 reg;
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = dev_get_drvdata(dev);
  	/* supported values: 2, 4, 8 */
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
424
425
426
427
428
429
  	unsigned long v;
  	int err;
  
  	err = kstrtoul(buf, 10, &v);
  	if (err)
  		return err;
569ff1022   Hans de Goede   hwmon: Add new co...
430
431
  
  	switch (v) {
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
432
433
434
435
436
437
438
439
440
  	case 2:
  		v = 1;
  		break;
  	case 4:
  		v = 2;
  		break;
  	case 8:
  		v = 3;
  		break;
569ff1022   Hans de Goede   hwmon: Add new co...
441
  	default:
b55f37572   Guenter Roeck   hwmon: Fix checkp...
442
443
444
445
  		dev_err(dev,
  			"fan_div value %lu not supported. Choose one of 2, 4 or 8!
  ",
  			v);
569ff1022   Hans de Goede   hwmon: Add new co...
446
447
448
449
  		return -EINVAL;
  	}
  
  	mutex_lock(&data->update_lock);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
450
  	reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
569ff1022   Hans de Goede   hwmon: Add new co...
451
452
453
454
455
  		FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
  
  	/* bits 2..7 reserved => mask with 0x03 */
  	reg &= ~0x03;
  	reg |= v;
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
456
  	i2c_smbus_write_byte_data(to_i2c_client(dev),
569ff1022   Hans de Goede   hwmon: Add new co...
457
458
459
460
461
462
463
464
  		FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
  
  	data->fan_ripple[index] = reg;
  
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
465
466
  static ssize_t fan_alarm_show(struct device *dev,
  			      struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
467
468
469
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
453e308d7   Hans de Goede   hwmon: (fschmd) C...
470
  	if (data->fan_status[index] & FSCHMD_FAN_ALARM)
569ff1022   Hans de Goede   hwmon: Add new co...
471
472
473
474
475
476
  		return sprintf(buf, "1
  ");
  	else
  		return sprintf(buf, "0
  ");
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
477
478
  static ssize_t fan_fault_show(struct device *dev,
  			      struct device_attribute *devattr, char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
479
480
481
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = fschmd_update_device(dev);
453e308d7   Hans de Goede   hwmon: (fschmd) C...
482
  	if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
569ff1022   Hans de Goede   hwmon: Add new co...
483
484
485
486
487
488
  		return sprintf(buf, "1
  ");
  	else
  		return sprintf(buf, "0
  ");
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
489
490
491
  static ssize_t pwm_auto_point1_pwm_show(struct device *dev,
  					struct device_attribute *devattr,
  					char *buf)
569ff1022   Hans de Goede   hwmon: Add new co...
492
493
  {
  	int index = to_sensor_dev_attr(devattr)->index;
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
494
495
  	struct fschmd_data *data = fschmd_update_device(dev);
  	int val = data->fan_min[index];
569ff1022   Hans de Goede   hwmon: Add new co...
496

c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
497
  	/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
dc71afe5a   Jean Delvare   hwmon: Fix off-by...
498
  	if (val || data->kind == fscsyl)
569ff1022   Hans de Goede   hwmon: Add new co...
499
500
501
502
503
  		val = val / 2 + 128;
  
  	return sprintf(buf, "%d
  ", val);
  }
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
504
505
506
  static ssize_t pwm_auto_point1_pwm_store(struct device *dev,
  					 struct device_attribute *devattr,
  					 const char *buf, size_t count)
569ff1022   Hans de Goede   hwmon: Add new co...
507
508
509
  {
  	int index = to_sensor_dev_attr(devattr)->index;
  	struct fschmd_data *data = dev_get_drvdata(dev);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
510
511
512
513
514
515
  	unsigned long v;
  	int err;
  
  	err = kstrtoul(buf, 10, &v);
  	if (err)
  		return err;
569ff1022   Hans de Goede   hwmon: Add new co...
516

c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
517
  	/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
dc71afe5a   Jean Delvare   hwmon: Fix off-by...
518
  	if (v || data->kind == fscsyl) {
2a844c148   Guenter Roeck   hwmon: Replace SE...
519
  		v = clamp_val(v, 128, 255);
569ff1022   Hans de Goede   hwmon: Add new co...
520
521
522
523
  		v = (v - 128) * 2 + 1;
  	}
  
  	mutex_lock(&data->update_lock);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
524
  	i2c_smbus_write_byte_data(to_i2c_client(dev),
569ff1022   Hans de Goede   hwmon: Add new co...
525
526
527
528
529
530
531
  		FSCHMD_REG_FAN_MIN[data->kind][index], v);
  	data->fan_min[index] = v;
  
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
532
533
534
535
  /*
   * The FSC hwmon family has the ability to force an attached alert led to flash
   * from software, we export this as an alert_led sysfs attr
   */
e34e885b9   Julia Lawall   hwmon: (fschmd) u...
536
  static ssize_t alert_led_show(struct device *dev,
569ff1022   Hans de Goede   hwmon: Add new co...
537
538
539
  	struct device_attribute *devattr, char *buf)
  {
  	struct fschmd_data *data = fschmd_update_device(dev);
453e308d7   Hans de Goede   hwmon: (fschmd) C...
540
  	if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
569ff1022   Hans de Goede   hwmon: Add new co...
541
542
543
544
545
546
  		return sprintf(buf, "1
  ");
  	else
  		return sprintf(buf, "0
  ");
  }
e34e885b9   Julia Lawall   hwmon: (fschmd) u...
547
  static ssize_t alert_led_store(struct device *dev,
569ff1022   Hans de Goede   hwmon: Add new co...
548
549
550
551
  	struct device_attribute *devattr, const char *buf, size_t count)
  {
  	u8 reg;
  	struct fschmd_data *data = dev_get_drvdata(dev);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
552
553
554
555
556
557
  	unsigned long v;
  	int err;
  
  	err = kstrtoul(buf, 10, &v);
  	if (err)
  		return err;
569ff1022   Hans de Goede   hwmon: Add new co...
558
559
  
  	mutex_lock(&data->update_lock);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
560
  	reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
569ff1022   Hans de Goede   hwmon: Add new co...
561
562
  
  	if (v)
453e308d7   Hans de Goede   hwmon: (fschmd) C...
563
  		reg |= FSCHMD_CONTROL_ALERT_LED;
569ff1022   Hans de Goede   hwmon: Add new co...
564
  	else
453e308d7   Hans de Goede   hwmon: (fschmd) C...
565
  		reg &= ~FSCHMD_CONTROL_ALERT_LED;
569ff1022   Hans de Goede   hwmon: Add new co...
566

40ac1994b   Jean Delvare   hwmon: (fschmd) C...
567
  	i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
569ff1022   Hans de Goede   hwmon: Add new co...
568
569
570
571
572
573
574
  
  	data->global_control = reg;
  
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
e34e885b9   Julia Lawall   hwmon: (fschmd) u...
575
  static DEVICE_ATTR_RW(alert_led);
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
576

569ff1022   Hans de Goede   hwmon: Add new co...
577
  static struct sensor_device_attribute fschmd_attr[] = {
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
578
579
580
581
582
583
  	SENSOR_ATTR_RO(in0_input, in_value, 0),
  	SENSOR_ATTR_RO(in1_input, in_value, 1),
  	SENSOR_ATTR_RO(in2_input, in_value, 2),
  	SENSOR_ATTR_RO(in3_input, in_value, 3),
  	SENSOR_ATTR_RO(in4_input, in_value, 4),
  	SENSOR_ATTR_RO(in5_input, in_value, 5),
569ff1022   Hans de Goede   hwmon: Add new co...
584
585
586
  };
  
  static struct sensor_device_attribute fschmd_temp_attr[] = {
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  	SENSOR_ATTR_RO(temp1_input, temp_value, 0),
  	SENSOR_ATTR_RW(temp1_max, temp_max, 0),
  	SENSOR_ATTR_RO(temp1_fault, temp_fault, 0),
  	SENSOR_ATTR_RO(temp1_alarm, temp_alarm, 0),
  	SENSOR_ATTR_RO(temp2_input, temp_value, 1),
  	SENSOR_ATTR_RW(temp2_max, temp_max, 1),
  	SENSOR_ATTR_RO(temp2_fault, temp_fault, 1),
  	SENSOR_ATTR_RO(temp2_alarm, temp_alarm, 1),
  	SENSOR_ATTR_RO(temp3_input, temp_value, 2),
  	SENSOR_ATTR_RW(temp3_max, temp_max, 2),
  	SENSOR_ATTR_RO(temp3_fault, temp_fault, 2),
  	SENSOR_ATTR_RO(temp3_alarm, temp_alarm, 2),
  	SENSOR_ATTR_RO(temp4_input, temp_value, 3),
  	SENSOR_ATTR_RW(temp4_max, temp_max, 3),
  	SENSOR_ATTR_RO(temp4_fault, temp_fault, 3),
  	SENSOR_ATTR_RO(temp4_alarm, temp_alarm, 3),
  	SENSOR_ATTR_RO(temp5_input, temp_value, 4),
  	SENSOR_ATTR_RW(temp5_max, temp_max, 4),
  	SENSOR_ATTR_RO(temp5_fault, temp_fault, 4),
  	SENSOR_ATTR_RO(temp5_alarm, temp_alarm, 4),
  	SENSOR_ATTR_RO(temp6_input, temp_value, 5),
  	SENSOR_ATTR_RW(temp6_max, temp_max, 5),
  	SENSOR_ATTR_RO(temp6_fault, temp_fault, 5),
  	SENSOR_ATTR_RO(temp6_alarm, temp_alarm, 5),
  	SENSOR_ATTR_RO(temp7_input, temp_value, 6),
  	SENSOR_ATTR_RW(temp7_max, temp_max, 6),
  	SENSOR_ATTR_RO(temp7_fault, temp_fault, 6),
  	SENSOR_ATTR_RO(temp7_alarm, temp_alarm, 6),
  	SENSOR_ATTR_RO(temp8_input, temp_value, 7),
  	SENSOR_ATTR_RW(temp8_max, temp_max, 7),
  	SENSOR_ATTR_RO(temp8_fault, temp_fault, 7),
  	SENSOR_ATTR_RO(temp8_alarm, temp_alarm, 7),
  	SENSOR_ATTR_RO(temp9_input, temp_value, 8),
  	SENSOR_ATTR_RW(temp9_max, temp_max, 8),
  	SENSOR_ATTR_RO(temp9_fault, temp_fault, 8),
  	SENSOR_ATTR_RO(temp9_alarm, temp_alarm, 8),
  	SENSOR_ATTR_RO(temp10_input, temp_value, 9),
  	SENSOR_ATTR_RW(temp10_max, temp_max, 9),
  	SENSOR_ATTR_RO(temp10_fault, temp_fault, 9),
  	SENSOR_ATTR_RO(temp10_alarm, temp_alarm, 9),
  	SENSOR_ATTR_RO(temp11_input, temp_value, 10),
  	SENSOR_ATTR_RW(temp11_max, temp_max, 10),
  	SENSOR_ATTR_RO(temp11_fault, temp_fault, 10),
  	SENSOR_ATTR_RO(temp11_alarm, temp_alarm, 10),
569ff1022   Hans de Goede   hwmon: Add new co...
631
632
633
  };
  
  static struct sensor_device_attribute fschmd_fan_attr[] = {
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  	SENSOR_ATTR_RO(fan1_input, fan_value, 0),
  	SENSOR_ATTR_RW(fan1_div, fan_div, 0),
  	SENSOR_ATTR_RO(fan1_alarm, fan_alarm, 0),
  	SENSOR_ATTR_RO(fan1_fault, fan_fault, 0),
  	SENSOR_ATTR_RW(pwm1_auto_point1_pwm, pwm_auto_point1_pwm, 0),
  	SENSOR_ATTR_RO(fan2_input, fan_value, 1),
  	SENSOR_ATTR_RW(fan2_div, fan_div, 1),
  	SENSOR_ATTR_RO(fan2_alarm, fan_alarm, 1),
  	SENSOR_ATTR_RO(fan2_fault, fan_fault, 1),
  	SENSOR_ATTR_RW(pwm2_auto_point1_pwm, pwm_auto_point1_pwm, 1),
  	SENSOR_ATTR_RO(fan3_input, fan_value, 2),
  	SENSOR_ATTR_RW(fan3_div, fan_div, 2),
  	SENSOR_ATTR_RO(fan3_alarm, fan_alarm, 2),
  	SENSOR_ATTR_RO(fan3_fault, fan_fault, 2),
  	SENSOR_ATTR_RW(pwm3_auto_point1_pwm, pwm_auto_point1_pwm, 2),
  	SENSOR_ATTR_RO(fan4_input, fan_value, 3),
  	SENSOR_ATTR_RW(fan4_div, fan_div, 3),
  	SENSOR_ATTR_RO(fan4_alarm, fan_alarm, 3),
  	SENSOR_ATTR_RO(fan4_fault, fan_fault, 3),
  	SENSOR_ATTR_RW(pwm4_auto_point1_pwm, pwm_auto_point1_pwm, 3),
  	SENSOR_ATTR_RO(fan5_input, fan_value, 4),
  	SENSOR_ATTR_RW(fan5_div, fan_div, 4),
  	SENSOR_ATTR_RO(fan5_alarm, fan_alarm, 4),
  	SENSOR_ATTR_RO(fan5_fault, fan_fault, 4),
  	SENSOR_ATTR_RW(pwm5_auto_point1_pwm, pwm_auto_point1_pwm, 4),
  	SENSOR_ATTR_RO(fan6_input, fan_value, 5),
  	SENSOR_ATTR_RW(fan6_div, fan_div, 5),
  	SENSOR_ATTR_RO(fan6_alarm, fan_alarm, 5),
  	SENSOR_ATTR_RO(fan6_fault, fan_fault, 5),
  	SENSOR_ATTR_RW(pwm6_auto_point1_pwm, pwm_auto_point1_pwm, 5),
  	SENSOR_ATTR_RO(fan7_input, fan_value, 6),
  	SENSOR_ATTR_RW(fan7_div, fan_div, 6),
  	SENSOR_ATTR_RO(fan7_alarm, fan_alarm, 6),
  	SENSOR_ATTR_RO(fan7_fault, fan_fault, 6),
  	SENSOR_ATTR_RW(pwm7_auto_point1_pwm, pwm_auto_point1_pwm, 6),
569ff1022   Hans de Goede   hwmon: Add new co...
669
670
671
672
  };
  
  
  /*
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
   * Watchdog routines
   */
  
  static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
  {
  	int ret, resolution;
  	int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
  
  	/* 2 second or 60 second resolution? */
  	if (timeout <= 510 || kind == fscpos || kind == fscscy)
  		resolution = 2;
  	else
  		resolution = 60;
  
  	if (timeout < resolution || timeout > (resolution * 255))
  		return -EINVAL;
  
  	mutex_lock(&data->watchdog_lock);
  	if (!data->client) {
  		ret = -ENODEV;
  		goto leave;
  	}
  
  	if (resolution == 2)
  		data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
  	else
  		data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
  
  	data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
  
  	/* Write new timeout value */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
704
705
  	i2c_smbus_write_byte_data(data->client,
  		FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
706
  	/* Write new control register, do not trigger! */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
707
708
  	i2c_smbus_write_byte_data(data->client,
  		FSCHMD_REG_WDOG_CONTROL[data->kind],
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  		data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
  
  	ret = data->watchdog_preset * resolution;
  
  leave:
  	mutex_unlock(&data->watchdog_lock);
  	return ret;
  }
  
  static int watchdog_get_timeout(struct fschmd_data *data)
  {
  	int timeout;
  
  	mutex_lock(&data->watchdog_lock);
  	if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
  		timeout = data->watchdog_preset * 60;
  	else
  		timeout = data->watchdog_preset * 2;
  	mutex_unlock(&data->watchdog_lock);
  
  	return timeout;
  }
  
  static int watchdog_trigger(struct fschmd_data *data)
  {
  	int ret = 0;
  
  	mutex_lock(&data->watchdog_lock);
  	if (!data->client) {
  		ret = -ENODEV;
  		goto leave;
  	}
  
  	data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
743
744
745
  	i2c_smbus_write_byte_data(data->client,
  				  FSCHMD_REG_WDOG_CONTROL[data->kind],
  				  data->watchdog_control);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  leave:
  	mutex_unlock(&data->watchdog_lock);
  	return ret;
  }
  
  static int watchdog_stop(struct fschmd_data *data)
  {
  	int ret = 0;
  
  	mutex_lock(&data->watchdog_lock);
  	if (!data->client) {
  		ret = -ENODEV;
  		goto leave;
  	}
  
  	data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
762
763
764
765
  	/*
  	 * Don't store the stop flag in our watchdog control register copy, as
  	 * its a write only bit (read always returns 0)
  	 */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
766
767
  	i2c_smbus_write_byte_data(data->client,
  		FSCHMD_REG_WDOG_CONTROL[data->kind],
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
768
769
770
771
772
773
774
775
776
  		data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
  leave:
  	mutex_unlock(&data->watchdog_lock);
  	return ret;
  }
  
  static int watchdog_open(struct inode *inode, struct file *filp)
  {
  	struct fschmd_data *pos, *data = NULL;
c453615f7   Hans de Goede   hwmon: (fschmd) F...
777
  	int watchdog_is_open;
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
778

525ad3731   Guenter Roeck   hwmon: (fschmd) F...
779
780
781
782
783
784
  	/*
  	 * We get called from drivers/char/misc.c with misc_mtx hold, and we
  	 * call misc_register() from fschmd_probe() with watchdog_data_mutex
  	 * hold, as misc_register() takes the misc_mtx lock, this is a possible
  	 * deadlock, so we use mutex_trylock here.
  	 */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
785
786
787
788
789
790
791
792
793
  	if (!mutex_trylock(&watchdog_data_mutex))
  		return -ERESTARTSYS;
  	list_for_each_entry(pos, &watchdog_data_list, list) {
  		if (pos->watchdog_miscdev.minor == iminor(inode)) {
  			data = pos;
  			break;
  		}
  	}
  	/* Note we can never not have found data, so we don't check for this */
c453615f7   Hans de Goede   hwmon: (fschmd) F...
794
795
796
  	watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
  	if (!watchdog_is_open)
  		kref_get(&data->kref);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
797
  	mutex_unlock(&watchdog_data_mutex);
c453615f7   Hans de Goede   hwmon: (fschmd) F...
798
  	if (watchdog_is_open)
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
799
800
801
802
803
  		return -EBUSY;
  
  	/* Start the watchdog */
  	watchdog_trigger(data);
  	filp->private_data = data;
c5bf68fe0   Kirill Smelkov   *: convert stream...
804
  	return stream_open(inode, filp);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
  }
  
  static int watchdog_release(struct inode *inode, struct file *filp)
  {
  	struct fschmd_data *data = filp->private_data;
  
  	if (data->watchdog_expect_close) {
  		watchdog_stop(data);
  		data->watchdog_expect_close = 0;
  	} else {
  		watchdog_trigger(data);
  		dev_crit(&data->client->dev,
  			"unexpected close, not stopping watchdog!
  ");
  	}
  
  	clear_bit(0, &data->watchdog_is_open);
  
  	mutex_lock(&watchdog_data_mutex);
  	kref_put(&data->kref, fschmd_release_resources);
  	mutex_unlock(&watchdog_data_mutex);
  
  	return 0;
  }
  
  static ssize_t watchdog_write(struct file *filp, const char __user *buf,
  	size_t count, loff_t *offset)
  {
c7702c313   Roel Kluin   hwmon: (fschmd) F...
833
  	int ret;
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  	struct fschmd_data *data = filp->private_data;
  
  	if (count) {
  		if (!nowayout) {
  			size_t i;
  
  			/* Clear it in case it was set with a previous write */
  			data->watchdog_expect_close = 0;
  
  			for (i = 0; i != count; i++) {
  				char c;
  				if (get_user(c, buf + i))
  					return -EFAULT;
  				if (c == 'V')
  					data->watchdog_expect_close = 1;
  			}
  		}
  		ret = watchdog_trigger(data);
  		if (ret < 0)
  			return ret;
  	}
  	return count;
  }
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
857
858
  static long watchdog_ioctl(struct file *filp, unsigned int cmd,
  			   unsigned long arg)
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
859
  {
1b7243e8f   Jean Delvare   hwmon: (fschmd) D...
860
  	struct watchdog_info ident = {
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
  				WDIOF_CARDRESET,
  		.identity = "FSC watchdog"
  	};
  	int i, ret = 0;
  	struct fschmd_data *data = filp->private_data;
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		ident.firmware_version = data->revision;
  		if (!nowayout)
  			ident.options |= WDIOF_MAGICCLOSE;
  		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
  			ret = -EFAULT;
  		break;
  
  	case WDIOC_GETSTATUS:
  		ret = put_user(0, (int __user *)arg);
  		break;
  
  	case WDIOC_GETBOOTSTATUS:
  		if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
  			ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
  		else
  			ret = put_user(0, (int __user *)arg);
  		break;
  
  	case WDIOC_KEEPALIVE:
  		ret = watchdog_trigger(data);
  		break;
  
  	case WDIOC_GETTIMEOUT:
  		i = watchdog_get_timeout(data);
  		ret = put_user(i, (int __user *)arg);
  		break;
  
  	case WDIOC_SETTIMEOUT:
  		if (get_user(i, (int __user *)arg)) {
  			ret = -EFAULT;
  			break;
  		}
  		ret = watchdog_set_timeout(data, i);
  		if (ret > 0)
  			ret = put_user(ret, (int __user *)arg);
  		break;
  
  	case WDIOC_SETOPTIONS:
  		if (get_user(i, (int __user *)arg)) {
  			ret = -EFAULT;
  			break;
  		}
  
  		if (i & WDIOS_DISABLECARD)
  			ret = watchdog_stop(data);
  		else if (i & WDIOS_ENABLECARD)
  			ret = watchdog_trigger(data);
  		else
  			ret = -EINVAL;
  
  		break;
  	default:
  		ret = -ENOTTY;
  	}
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
924
925
  	return ret;
  }
828c09509   Alexey Dobriyan   const: constify r...
926
  static const struct file_operations watchdog_fops = {
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
927
928
929
930
931
  	.owner = THIS_MODULE,
  	.llseek = no_llseek,
  	.open = watchdog_open,
  	.release = watchdog_release,
  	.write = watchdog_write,
55929332c   Arnd Bergmann   drivers: Push dow...
932
  	.unlocked_ioctl = watchdog_ioctl,
b6dfb2477   Arnd Bergmann   compat_ioctl: mov...
933
  	.compat_ioctl = compat_ptr_ioctl,
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
934
935
936
937
938
  };
  
  
  /*
   * Detect, register, unregister and update device functions
569ff1022   Hans de Goede   hwmon: Add new co...
939
   */
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
940
941
942
943
  /*
   * DMI decode routine to read voltage scaling factors from special DMI tables,
   * which are available on FSC machines with an fscher or later chip.
   */
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
944
  static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
7845cd791   Hans de Goede   hwmon: (fschmd) R...
945
946
  {
  	int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
947
948
949
950
951
952
  	/*
  	 * dmi code ugliness, we get passed the address of the contents of
  	 * a complete DMI record, but in the form of a dmi_header pointer, in
  	 * reality this address holds header->length bytes of which the header
  	 * are the first 4 bytes
  	 */
7845cd791   Hans de Goede   hwmon: (fschmd) R...
953
954
955
956
957
  	u8 *dmi_data = (u8 *)header;
  
  	/* We are looking for OEM-specific type 185 */
  	if (header->type != 185)
  		return;
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
958
959
960
961
  	/*
  	 * we are looking for what Siemens calls "subtype" 19, the subtype
  	 * is stored in byte 5 of the dmi block
  	 */
7845cd791   Hans de Goede   hwmon: (fschmd) R...
962
963
  	if (header->length < 5 || dmi_data[4] != 19)
  		return;
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
964
965
966
967
968
  	/*
  	 * After the subtype comes 1 unknown byte and then blocks of 5 bytes,
  	 * consisting of what Siemens calls an "Entity" number, followed by
  	 * 2 16-bit words in LSB first order
  	 */
7845cd791   Hans de Goede   hwmon: (fschmd) R...
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
  	for (i = 6; (i + 4) < header->length; i += 5) {
  		/* entity 1 - 3: voltage multiplier and offset */
  		if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
  			/* Our in sensors order and the DMI order differ */
  			const int shuffle[3] = { 1, 0, 2 };
  			int in = shuffle[dmi_data[i] - 1];
  
  			/* Check for twice the same entity */
  			if (found & (1 << in))
  				return;
  
  			mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
  			offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
  
  			found |= 1 << in;
  		}
  
  		/* entity 7: reference voltage */
  		if (dmi_data[i] == 7) {
  			/* Check for twice the same entity */
  			if (found & 0x08)
  				return;
  
  			vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
  
  			found |= 0x08;
  		}
  	}
  
  	if (found == 0x0F) {
  		for (i = 0; i < 3; i++) {
  			dmi_mult[i] = mult[i] * 10;
  			dmi_offset[i] = offset[i] * 10;
  		}
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1003
1004
1005
1006
1007
  		/*
  		 * According to the docs there should be separate dmi entries
  		 * for the mult's and offsets of in3-5 of the syl, but on
  		 * my test machine these are not present
  		 */
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1008
1009
1010
1011
1012
1013
  		dmi_mult[3] = dmi_mult[2];
  		dmi_mult[4] = dmi_mult[1];
  		dmi_mult[5] = dmi_mult[2];
  		dmi_offset[3] = dmi_offset[2];
  		dmi_offset[4] = dmi_offset[1];
  		dmi_offset[5] = dmi_offset[2];
7845cd791   Hans de Goede   hwmon: (fschmd) R...
1014
1015
1016
  		dmi_vref = vref;
  	}
  }
310ec7921   Jean Delvare   i2c: Drop the kin...
1017
  static int fschmd_detect(struct i2c_client *client,
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1018
  			 struct i2c_board_info *info)
569ff1022   Hans de Goede   hwmon: Add new co...
1019
  {
52df6440a   Jean Delvare   hwmon: Clean up d...
1020
  	enum chips kind;
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1021
  	struct i2c_adapter *adapter = client->adapter;
52df6440a   Jean Delvare   hwmon: Clean up d...
1022
  	char id[4];
569ff1022   Hans de Goede   hwmon: Add new co...
1023
1024
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1025
  		return -ENODEV;
569ff1022   Hans de Goede   hwmon: Add new co...
1026
1027
  
  	/* Detect & Identify the chip */
52df6440a   Jean Delvare   hwmon: Clean up d...
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  	id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
  	id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
  	id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
  	id[3] = '\0';
  
  	if (!strcmp(id, "PEG"))
  		kind = fscpos;
  	else if (!strcmp(id, "HER"))
  		kind = fscher;
  	else if (!strcmp(id, "SCY"))
  		kind = fscscy;
  	else if (!strcmp(id, "HRC"))
  		kind = fschrc;
  	else if (!strcmp(id, "HMD"))
  		kind = fschmd;
  	else if (!strcmp(id, "HDS"))
  		kind = fschds;
  	else if (!strcmp(id, "SYL"))
  		kind = fscsyl;
  	else
  		return -ENODEV;
569ff1022   Hans de Goede   hwmon: Add new co...
1049

dc71afe5a   Jean Delvare   hwmon: Fix off-by...
1050
  	strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1051
1052
1053
  
  	return 0;
  }
674870385   Stephen Kitt   hwmon: use simple...
1054
  static int fschmd_probe(struct i2c_client *client)
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1055
1056
  {
  	struct fschmd_data *data;
de15f093e   Hans de Goede   hwmon: (fschmd) A...
1057
1058
  	const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
  				"Heracles", "Heimdall", "Hades", "Syleus" };
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1059
  	const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1060
  	int i, err;
674870385   Stephen Kitt   hwmon: use simple...
1061
  	enum chips kind = i2c_match_id(fschmd_id, client)->driver_data;
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1062
1063
1064
1065
1066
1067
1068
  
  	data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->update_lock);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1069
1070
1071
  	mutex_init(&data->watchdog_lock);
  	INIT_LIST_HEAD(&data->list);
  	kref_init(&data->kref);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1072
1073
1074
1075
1076
  	/*
  	 * Store client pointer in our data struct for watchdog usage
  	 * (where the client is found through a data ptr instead of the
  	 * otherway around)
  	 */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1077
  	data->client = client;
dc71afe5a   Jean Delvare   hwmon: Fix off-by...
1078
  	data->kind = kind;
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1079

569ff1022   Hans de Goede   hwmon: Add new co...
1080
  	if (kind == fscpos) {
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1081
1082
1083
1084
  		/*
  		 * The Poseidon has hardwired temp limits, fill these
  		 * in for the alarm resetting code
  		 */
569ff1022   Hans de Goede   hwmon: Add new co...
1085
1086
1087
1088
  		data->temp_max[0] = 70 + 128;
  		data->temp_max[1] = 50 + 128;
  		data->temp_max[2] = 50 + 128;
  	}
7845cd791   Hans de Goede   hwmon: (fschmd) R...
1089
  	/* Read the special DMI table for fscher and newer chips */
453e308d7   Hans de Goede   hwmon: (fschmd) C...
1090
  	if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
1091
  		dmi_walk(fschmd_dmi_decode, NULL);
7845cd791   Hans de Goede   hwmon: (fschmd) R...
1092
  		if (dmi_vref == -1) {
453e308d7   Hans de Goede   hwmon: (fschmd) C...
1093
1094
  			dev_warn(&client->dev,
  				"Couldn't get voltage scaling factors from "
7845cd791   Hans de Goede   hwmon: (fschmd) R...
1095
1096
1097
1098
1099
  				"BIOS DMI table, using builtin defaults
  ");
  			dmi_vref = 33;
  		}
  	}
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1100
1101
1102
1103
1104
  	/* Read in some never changing registers */
  	data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
  	data->global_control = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_CONTROL);
  	data->watchdog_control = i2c_smbus_read_byte_data(client,
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1105
  					FSCHMD_REG_WDOG_CONTROL[data->kind]);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1106
  	data->watchdog_state = i2c_smbus_read_byte_data(client,
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1107
  					FSCHMD_REG_WDOG_STATE[data->kind]);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1108
  	data->watchdog_preset = i2c_smbus_read_byte_data(client,
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1109
  					FSCHMD_REG_WDOG_PRESET[data->kind]);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1110

c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1111
1112
1113
  	err = device_create_file(&client->dev, &dev_attr_alert_led);
  	if (err)
  		goto exit_detach;
569ff1022   Hans de Goede   hwmon: Add new co...
1114

c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1115
  	for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
569ff1022   Hans de Goede   hwmon: Add new co...
1116
1117
1118
1119
1120
1121
1122
1123
1124
  		err = device_create_file(&client->dev,
  					&fschmd_attr[i].dev_attr);
  		if (err)
  			goto exit_detach;
  	}
  
  	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
  		/* Poseidon doesn't have TEMP_LIMIT registers */
  		if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
22ed7883c   Guenter Roeck   hwmon: (fschmd) U...
1125
  				temp_max_show)
569ff1022   Hans de Goede   hwmon: Add new co...
1126
  			continue;
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1127
1128
1129
1130
1131
1132
1133
1134
1135
  		if (kind == fscsyl) {
  			if (i % 4 == 0)
  				data->temp_status[i / 4] =
  					i2c_smbus_read_byte_data(client,
  						FSCHMD_REG_TEMP_STATE
  						[data->kind][i / 4]);
  			if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
  				continue;
  		}
569ff1022   Hans de Goede   hwmon: Add new co...
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
  		err = device_create_file(&client->dev,
  					&fschmd_temp_attr[i].dev_attr);
  		if (err)
  			goto exit_detach;
  	}
  
  	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
  		/* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
  		if (kind == fscpos &&
  				!strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
  					"pwm3_auto_point1_pwm"))
  			continue;
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1148
1149
1150
1151
1152
1153
1154
1155
1156
  		if (kind == fscsyl) {
  			if (i % 5 == 0)
  				data->fan_status[i / 5] =
  					i2c_smbus_read_byte_data(client,
  						FSCHMD_REG_FAN_STATE
  						[data->kind][i / 5]);
  			if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
  				continue;
  		}
569ff1022   Hans de Goede   hwmon: Add new co...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  		err = device_create_file(&client->dev,
  					&fschmd_fan_attr[i].dev_attr);
  		if (err)
  			goto exit_detach;
  	}
  
  	data->hwmon_dev = hwmon_device_register(&client->dev);
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
  		data->hwmon_dev = NULL;
  		goto exit_detach;
  	}
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1169
1170
1171
1172
1173
  	/*
  	 * We take the data_mutex lock early so that watchdog_open() cannot
  	 * run when misc_register() has completed, but we've not yet added
  	 * our data to the watchdog_data_list (and set the default timeout)
  	 */
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  	mutex_lock(&watchdog_data_mutex);
  	for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
  		/* Register our watchdog part */
  		snprintf(data->watchdog_name, sizeof(data->watchdog_name),
  			"watchdog%c", (i == 0) ? '\0' : ('0' + i));
  		data->watchdog_miscdev.name = data->watchdog_name;
  		data->watchdog_miscdev.fops = &watchdog_fops;
  		data->watchdog_miscdev.minor = watchdog_minors[i];
  		err = misc_register(&data->watchdog_miscdev);
  		if (err == -EBUSY)
  			continue;
  		if (err) {
  			data->watchdog_miscdev.minor = 0;
  			dev_err(&client->dev,
  				"Registering watchdog chardev: %d
  ", err);
  			break;
  		}
  
  		list_add(&data->list, &watchdog_data_list);
  		watchdog_set_timeout(data, 60);
  		dev_info(&client->dev,
  			"Registered watchdog chardev major 10, minor: %d
  ",
  			watchdog_minors[i]);
  		break;
  	}
  	if (i == ARRAY_SIZE(watchdog_minors)) {
  		data->watchdog_miscdev.minor = 0;
b55f37572   Guenter Roeck   hwmon: Fix checkp...
1203
1204
1205
  		dev_warn(&client->dev,
  			 "Couldn't register watchdog chardev (due to no free minor)
  ");
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1206
1207
  	}
  	mutex_unlock(&watchdog_data_mutex);
453e308d7   Hans de Goede   hwmon: (fschmd) C...
1208
1209
  	dev_info(&client->dev, "Detected FSC %s chip, revision: %d
  ",
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1210
  		names[data->kind], (int) data->revision);
569ff1022   Hans de Goede   hwmon: Add new co...
1211
1212
1213
1214
  
  	return 0;
  
  exit_detach:
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1215
  	fschmd_remove(client); /* will also free data for us */
569ff1022   Hans de Goede   hwmon: Add new co...
1216
1217
  	return err;
  }
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1218
  static int fschmd_remove(struct i2c_client *client)
569ff1022   Hans de Goede   hwmon: Add new co...
1219
1220
  {
  	struct fschmd_data *data = i2c_get_clientdata(client);
40ac1994b   Jean Delvare   hwmon: (fschmd) C...
1221
  	int i;
569ff1022   Hans de Goede   hwmon: Add new co...
1222

97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
  	/* Unregister the watchdog (if registered) */
  	if (data->watchdog_miscdev.minor) {
  		misc_deregister(&data->watchdog_miscdev);
  		if (data->watchdog_is_open) {
  			dev_warn(&client->dev,
  				"i2c client detached with watchdog open! "
  				"Stopping watchdog.
  ");
  			watchdog_stop(data);
  		}
  		mutex_lock(&watchdog_data_mutex);
  		list_del(&data->list);
  		mutex_unlock(&watchdog_data_mutex);
  		/* Tell the watchdog code the client is gone */
  		mutex_lock(&data->watchdog_lock);
  		data->client = NULL;
  		mutex_unlock(&data->watchdog_lock);
  	}
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1241
1242
1243
1244
  	/*
  	 * Check if registered in case we're called from fschmd_detect
  	 * to cleanup after an error
  	 */
569ff1022   Hans de Goede   hwmon: Add new co...
1245
1246
  	if (data->hwmon_dev)
  		hwmon_device_unregister(data->hwmon_dev);
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1247
1248
  	device_remove_file(&client->dev, &dev_attr_alert_led);
  	for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
569ff1022   Hans de Goede   hwmon: Add new co...
1249
1250
1251
1252
1253
1254
1255
  		device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
  	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
  		device_remove_file(&client->dev,
  					&fschmd_temp_attr[i].dev_attr);
  	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
  		device_remove_file(&client->dev,
  					&fschmd_fan_attr[i].dev_attr);
97950c3d4   Hans de Goede   hwmon: (fschmd) A...
1256
1257
1258
  	mutex_lock(&watchdog_data_mutex);
  	kref_put(&data->kref, fschmd_release_resources);
  	mutex_unlock(&watchdog_data_mutex);
569ff1022   Hans de Goede   hwmon: Add new co...
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  	return 0;
  }
  
  static struct fschmd_data *fschmd_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct fschmd_data *data = i2c_get_clientdata(client);
  	int i;
  
  	mutex_lock(&data->update_lock);
  
  	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
  
  		for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
  			data->temp_act[i] = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_TEMP_ACT[data->kind][i]);
  			data->temp_status[i] = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_TEMP_STATE[data->kind][i]);
  
  			/* The fscpos doesn't have TEMP_LIMIT registers */
  			if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
  				data->temp_max[i] = i2c_smbus_read_byte_data(
  					client,
  					FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
525ad3731   Guenter Roeck   hwmon: (fschmd) F...
1283
1284
1285
1286
  			/*
  			 * reset alarm if the alarm condition is gone,
  			 * the chip doesn't do this itself
  			 */
569ff1022   Hans de Goede   hwmon: Add new co...
1287
1288
1289
1290
1291
  			if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
  					FSCHMD_TEMP_ALARM_MASK &&
  					data->temp_act[i] < data->temp_max[i])
  				i2c_smbus_write_byte_data(client,
  					FSCHMD_REG_TEMP_STATE[data->kind][i],
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1292
  					data->temp_status[i]);
569ff1022   Hans de Goede   hwmon: Add new co...
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
  		}
  
  		for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
  			data->fan_act[i] = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_FAN_ACT[data->kind][i]);
  			data->fan_status[i] = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_FAN_STATE[data->kind][i]);
  			data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
  					FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
  
  			/* The fscpos third fan doesn't have a fan_min */
  			if (FSCHMD_REG_FAN_MIN[data->kind][i])
  				data->fan_min[i] = i2c_smbus_read_byte_data(
  					client,
  					FSCHMD_REG_FAN_MIN[data->kind][i]);
  
  			/* reset fan status if speed is back to > 0 */
453e308d7   Hans de Goede   hwmon: (fschmd) C...
1310
  			if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
569ff1022   Hans de Goede   hwmon: Add new co...
1311
1312
1313
  					data->fan_act[i])
  				i2c_smbus_write_byte_data(client,
  					FSCHMD_REG_FAN_STATE[data->kind][i],
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1314
  					data->fan_status[i]);
569ff1022   Hans de Goede   hwmon: Add new co...
1315
  		}
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1316
  		for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
569ff1022   Hans de Goede   hwmon: Add new co...
1317
  			data->volt[i] = i2c_smbus_read_byte_data(client,
c69ab2b78   Hans de Goede   hwmon: (fschmd) A...
1318
  					       FSCHMD_REG_VOLT[data->kind][i]);
569ff1022   Hans de Goede   hwmon: Add new co...
1319

569ff1022   Hans de Goede   hwmon: Add new co...
1320
1321
1322
1323
1324
1325
1326
1327
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
  
  	mutex_unlock(&data->update_lock);
  
  	return data;
  }
f0967eea8   Axel Lin   hwmon: convert dr...
1328
  module_i2c_driver(fschmd_driver);
569ff1022   Hans de Goede   hwmon: Add new co...
1329

453e308d7   Hans de Goede   hwmon: (fschmd) C...
1330
  MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
de15f093e   Hans de Goede   hwmon: (fschmd) A...
1331
1332
  MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
  			"and Syleus driver");
569ff1022   Hans de Goede   hwmon: Add new co...
1333
  MODULE_LICENSE("GPL");