Blame view
drivers/hwmon/fschmd.c
38.6 KB
74ba9207e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
525ad3731 hwmon: (fschmd) F... |
2 3 |
/* * fschmd.c |
569ff1022 hwmon: Add new co... |
4 |
* |
c69ab2b78 hwmon: (fschmd) A... |
5 |
* Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> |
569ff1022 hwmon: Add new co... |
6 7 8 9 |
*/ /* * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, |
de15f093e hwmon: (fschmd) A... |
10 |
* Scylla, Heracles, Heimdall, Hades and Syleus chips |
569ff1022 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 hwmon: (fschmd) R... |
32 |
#include <linux/dmi.h> |
97950c3d4 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 hwmon: Add new co... |
38 39 |
/* Addresses to scan */ |
25e9c86d5 hwmon: normal_i2c... |
40 |
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; |
569ff1022 hwmon: Add new co... |
41 42 |
/* Insmod parameters */ |
86a1e1896 watchdog: nowayou... |
43 44 |
static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); |
97950c3d4 hwmon: (fschmd) A... |
45 46 |
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
e5e9f44c2 i2c: Drop I2C_CLI... |
47 48 |
enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl }; |
569ff1022 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 hwmon: (fschmd) C... |
63 |
#define FSCHMD_CONTROL_ALERT_LED 0x01 |
569ff1022 hwmon: Add new co... |
64 |
|
97950c3d4 hwmon: (fschmd) A... |
65 |
/* watchdog */ |
525ad3731 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 hwmon: Add new co... |
72 |
|
97950c3d4 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 hwmon: Add new co... |
79 |
/* voltages, weird order is to keep the same order as the old drivers */ |
de15f093e hwmon: (fschmd) A... |
80 |
static const u8 FSCHMD_REG_VOLT[7][6] = { |
c69ab2b78 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 hwmon: (fschmd) A... |
86 |
{ 0x21, 0x20, 0x22 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
87 88 |
{ 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ }; |
de15f093e hwmon: (fschmd) A... |
89 |
static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; |
569ff1022 hwmon: Add new co... |
90 |
|
525ad3731 hwmon: (fschmd) F... |
91 |
/* |
2b2acdc88 hwmon: (fschmd) f... |
92 |
* minimum pwm at which the fan is driven (pwm can be increased depending on |
525ad3731 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 hwmon: (fschmd) A... |
97 |
static const u8 FSCHMD_REG_FAN_MIN[7][7] = { |
569ff1022 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 hwmon: (fschmd) A... |
103 |
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
104 |
{ 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ |
569ff1022 hwmon: Add new co... |
105 106 107 |
}; /* actual fan speed */ |
de15f093e hwmon: (fschmd) A... |
108 |
static const u8 FSCHMD_REG_FAN_ACT[7][7] = { |
569ff1022 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 hwmon: (fschmd) A... |
114 |
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
115 |
{ 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ |
569ff1022 hwmon: Add new co... |
116 117 118 |
}; /* fan status registers */ |
de15f093e hwmon: (fschmd) A... |
119 |
static const u8 FSCHMD_REG_FAN_STATE[7][7] = { |
569ff1022 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 hwmon: (fschmd) A... |
125 |
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
126 |
{ 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ |
569ff1022 hwmon: Add new co... |
127 128 129 |
}; /* fan ripple / divider registers */ |
de15f093e hwmon: (fschmd) A... |
130 |
static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = { |
569ff1022 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 hwmon: (fschmd) A... |
136 |
{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
137 |
{ 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ |
569ff1022 hwmon: Add new co... |
138 |
}; |
de15f093e hwmon: (fschmd) A... |
139 |
static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 }; |
569ff1022 hwmon: Add new co... |
140 141 |
/* Fan status register bitmasks */ |
453e308d7 hwmon: (fschmd) C... |
142 |
#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ |
c69ab2b78 hwmon: (fschmd) A... |
143 144 |
#define FSCHMD_FAN_NOT_PRESENT 0x08 #define FSCHMD_FAN_DISABLED 0x80 |
569ff1022 hwmon: Add new co... |
145 146 147 |
/* actual temperature registers */ |
de15f093e hwmon: (fschmd) A... |
148 |
static const u8 FSCHMD_REG_TEMP_ACT[7][11] = { |
569ff1022 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 hwmon: (fschmd) A... |
154 |
{ 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
155 156 |
{ 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, |
569ff1022 hwmon: Add new co... |
157 158 159 |
}; /* temperature state registers */ |
de15f093e hwmon: (fschmd) A... |
160 |
static const u8 FSCHMD_REG_TEMP_STATE[7][11] = { |
569ff1022 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 hwmon: (fschmd) D... |
165 |
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ |
de15f093e hwmon: (fschmd) A... |
166 |
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
167 168 |
{ 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, |
569ff1022 hwmon: Add new co... |
169 |
}; |
525ad3731 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 hwmon: (fschmd) A... |
177 |
static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { |
569ff1022 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 hwmon: (fschmd) D... |
182 |
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ |
de15f093e hwmon: (fschmd) A... |
183 |
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */ |
c69ab2b78 hwmon: (fschmd) A... |
184 185 |
{ 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ 0xba, 0xca, 0xda, 0xea, 0xfa }, |
569ff1022 hwmon: Add new co... |
186 |
}; |
525ad3731 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 hwmon: Add new co... |
196 |
|
de15f093e hwmon: (fschmd) A... |
197 |
static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; |
569ff1022 hwmon: Add new co... |
198 199 |
/* temp status register bitmasks */ |
453e308d7 hwmon: (fschmd) C... |
200 201 |
#define FSCHMD_TEMP_WORKING 0x01 #define FSCHMD_TEMP_ALERT 0x02 |
c69ab2b78 hwmon: (fschmd) A... |
202 |
#define FSCHMD_TEMP_DISABLED 0x80 |
569ff1022 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 hwmon: (fschmd) C... |
205 |
(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) |
569ff1022 hwmon: Add new co... |
206 207 208 209 |
/* * Functions declarations */ |
674870385 hwmon: use simple... |
210 |
static int fschmd_probe(struct i2c_client *client); |
310ec7921 i2c: Drop the kin... |
211 |
static int fschmd_detect(struct i2c_client *client, |
40ac1994b hwmon: (fschmd) C... |
212 213 |
struct i2c_board_info *info); static int fschmd_remove(struct i2c_client *client); |
569ff1022 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 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 hwmon: (fschmd) A... |
225 |
{ "fschds", fschds }, |
c69ab2b78 hwmon: (fschmd) A... |
226 |
{ "fscsyl", fscsyl }, |
40ac1994b hwmon: (fschmd) C... |
227 228 229 |
{ } }; MODULE_DEVICE_TABLE(i2c, fschmd_id); |
569ff1022 hwmon: Add new co... |
230 |
static struct i2c_driver fschmd_driver = { |
40ac1994b hwmon: (fschmd) C... |
231 |
.class = I2C_CLASS_HWMON, |
569ff1022 hwmon: Add new co... |
232 |
.driver = { |
453e308d7 hwmon: (fschmd) C... |
233 |
.name = "fschmd", |
569ff1022 hwmon: Add new co... |
234 |
}, |
674870385 hwmon: use simple... |
235 |
.probe_new = fschmd_probe, |
40ac1994b hwmon: (fschmd) C... |
236 237 238 |
.remove = fschmd_remove, .id_table = fschmd_id, .detect = fschmd_detect, |
c3813d6af i2c: Get rid of s... |
239 |
.address_list = normal_i2c, |
569ff1022 hwmon: Add new co... |
240 241 242 243 244 245 246 |
}; /* * Client data (each client gets its own) */ struct fschmd_data { |
97950c3d4 hwmon: (fschmd) A... |
247 |
struct i2c_client *client; |
569ff1022 hwmon: Add new co... |
248 249 |
struct device *hwmon_dev; struct mutex update_lock; |
97950c3d4 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 hwmon: Fix off-by... |
254 |
enum chips kind; |
97950c3d4 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 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 hwmon: (fschmd) A... |
262 |
u8 revision; /* chip revision */ |
569ff1022 hwmon: Add new co... |
263 |
u8 global_control; /* global control register */ |
97950c3d4 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 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 hwmon: Add new co... |
275 |
}; |
525ad3731 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 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 hwmon: (fschmd) R... |
285 |
static int dmi_vref = -1; |
525ad3731 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 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 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 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 hwmon: (fschmd) R... |
303 |
|
569ff1022 hwmon: Add new co... |
304 305 306 |
/* * Sysfs attr show / store functions */ |
22ed7883c hwmon: (fschmd) U... |
307 308 |
static ssize_t in_value_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 hwmon: Fix off-by... |
313 |
if (data->kind == fscher || data->kind >= fschrc) |
7845cd791 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 hwmon: Add new co... |
321 322 323 324 |
} #define TEMP_FROM_REG(val) (((val) - 128) * 1000) |
22ed7883c hwmon: (fschmd) U... |
325 326 |
static ssize_t temp_value_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 hwmon: (fschmd) U... |
334 335 |
static ssize_t temp_max_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 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 hwmon: Add new co... |
346 347 348 |
{ int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); |
525ad3731 hwmon: (fschmd) F... |
349 350 351 352 353 354 |
long v; int err; err = kstrtol(buf, 10, &v); if (err) return err; |
569ff1022 hwmon: Add new co... |
355 |
|
2a844c148 hwmon: Replace SE... |
356 |
v = clamp_val(v / 1000, -128, 127) + 128; |
569ff1022 hwmon: Add new co... |
357 358 |
mutex_lock(&data->update_lock); |
40ac1994b hwmon: (fschmd) C... |
359 |
i2c_smbus_write_byte_data(to_i2c_client(dev), |
569ff1022 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 hwmon: (fschmd) U... |
366 367 |
static ssize_t temp_fault_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 hwmon: (fschmd) C... |
373 |
if (data->temp_status[index] & FSCHMD_TEMP_WORKING) |
569ff1022 hwmon: Add new co... |
374 375 376 377 378 379 |
return sprintf(buf, "0 "); else return sprintf(buf, "1 "); } |
22ed7883c hwmon: (fschmd) U... |
380 381 |
static ssize_t temp_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 hwmon: (fschmd) U... |
397 398 |
static ssize_t fan_value_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 hwmon: (fschmd) U... |
406 407 |
static ssize_t fan_div_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 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 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 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 hwmon: (fschmd) F... |
424 425 426 427 428 429 |
unsigned long v; int err; err = kstrtoul(buf, 10, &v); if (err) return err; |
569ff1022 hwmon: Add new co... |
430 431 |
switch (v) { |
525ad3731 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 hwmon: Add new co... |
441 |
default: |
b55f37572 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 hwmon: Add new co... |
446 447 448 449 |
return -EINVAL; } mutex_lock(&data->update_lock); |
40ac1994b hwmon: (fschmd) C... |
450 |
reg = i2c_smbus_read_byte_data(to_i2c_client(dev), |
569ff1022 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 hwmon: (fschmd) C... |
456 |
i2c_smbus_write_byte_data(to_i2c_client(dev), |
569ff1022 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 hwmon: (fschmd) U... |
465 466 |
static ssize_t fan_alarm_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 hwmon: Add new co... |
467 468 469 |
{ int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = fschmd_update_device(dev); |
453e308d7 hwmon: (fschmd) C... |
470 |
if (data->fan_status[index] & FSCHMD_FAN_ALARM) |
569ff1022 hwmon: Add new co... |
471 472 473 474 475 476 |
return sprintf(buf, "1 "); else return sprintf(buf, "0 "); } |
22ed7883c hwmon: (fschmd) U... |
477 478 |
static ssize_t fan_fault_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 hwmon: Add new co... |
479 480 481 |
{ int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = fschmd_update_device(dev); |
453e308d7 hwmon: (fschmd) C... |
482 |
if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT) |
569ff1022 hwmon: Add new co... |
483 484 485 486 487 488 |
return sprintf(buf, "1 "); else return sprintf(buf, "0 "); } |
22ed7883c hwmon: (fschmd) U... |
489 490 491 |
static ssize_t pwm_auto_point1_pwm_show(struct device *dev, struct device_attribute *devattr, char *buf) |
569ff1022 hwmon: Add new co... |
492 493 |
{ int index = to_sensor_dev_attr(devattr)->index; |
c69ab2b78 hwmon: (fschmd) A... |
494 495 |
struct fschmd_data *data = fschmd_update_device(dev); int val = data->fan_min[index]; |
569ff1022 hwmon: Add new co... |
496 |
|
c69ab2b78 hwmon: (fschmd) A... |
497 |
/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
dc71afe5a hwmon: Fix off-by... |
498 |
if (val || data->kind == fscsyl) |
569ff1022 hwmon: Add new co... |
499 500 501 502 503 |
val = val / 2 + 128; return sprintf(buf, "%d ", val); } |
22ed7883c 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 hwmon: Add new co... |
507 508 509 |
{ int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); |
525ad3731 hwmon: (fschmd) F... |
510 511 512 513 514 515 |
unsigned long v; int err; err = kstrtoul(buf, 10, &v); if (err) return err; |
569ff1022 hwmon: Add new co... |
516 |
|
c69ab2b78 hwmon: (fschmd) A... |
517 |
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
dc71afe5a hwmon: Fix off-by... |
518 |
if (v || data->kind == fscsyl) { |
2a844c148 hwmon: Replace SE... |
519 |
v = clamp_val(v, 128, 255); |
569ff1022 hwmon: Add new co... |
520 521 522 523 |
v = (v - 128) * 2 + 1; } mutex_lock(&data->update_lock); |
40ac1994b hwmon: (fschmd) C... |
524 |
i2c_smbus_write_byte_data(to_i2c_client(dev), |
569ff1022 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 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 hwmon: (fschmd) u... |
536 |
static ssize_t alert_led_show(struct device *dev, |
569ff1022 hwmon: Add new co... |
537 538 539 |
struct device_attribute *devattr, char *buf) { struct fschmd_data *data = fschmd_update_device(dev); |
453e308d7 hwmon: (fschmd) C... |
540 |
if (data->global_control & FSCHMD_CONTROL_ALERT_LED) |
569ff1022 hwmon: Add new co... |
541 542 543 544 545 546 |
return sprintf(buf, "1 "); else return sprintf(buf, "0 "); } |
e34e885b9 hwmon: (fschmd) u... |
547 |
static ssize_t alert_led_store(struct device *dev, |
569ff1022 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 hwmon: (fschmd) F... |
552 553 554 555 556 557 |
unsigned long v; int err; err = kstrtoul(buf, 10, &v); if (err) return err; |
569ff1022 hwmon: Add new co... |
558 559 |
mutex_lock(&data->update_lock); |
40ac1994b hwmon: (fschmd) C... |
560 |
reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL); |
569ff1022 hwmon: Add new co... |
561 562 |
if (v) |
453e308d7 hwmon: (fschmd) C... |
563 |
reg |= FSCHMD_CONTROL_ALERT_LED; |
569ff1022 hwmon: Add new co... |
564 |
else |
453e308d7 hwmon: (fschmd) C... |
565 |
reg &= ~FSCHMD_CONTROL_ALERT_LED; |
569ff1022 hwmon: Add new co... |
566 |
|
40ac1994b hwmon: (fschmd) C... |
567 |
i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg); |
569ff1022 hwmon: Add new co... |
568 569 570 571 572 573 574 |
data->global_control = reg; mutex_unlock(&data->update_lock); return count; } |
e34e885b9 hwmon: (fschmd) u... |
575 |
static DEVICE_ATTR_RW(alert_led); |
c69ab2b78 hwmon: (fschmd) A... |
576 |
|
569ff1022 hwmon: Add new co... |
577 |
static struct sensor_device_attribute fschmd_attr[] = { |
22ed7883c 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 hwmon: Add new co... |
584 585 586 |
}; static struct sensor_device_attribute fschmd_temp_attr[] = { |
22ed7883c 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 hwmon: Add new co... |
631 632 633 |
}; static struct sensor_device_attribute fschmd_fan_attr[] = { |
22ed7883c 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 hwmon: Add new co... |
669 670 671 672 |
}; /* |
97950c3d4 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 hwmon: (fschmd) A... |
704 705 |
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); |
97950c3d4 hwmon: (fschmd) A... |
706 |
/* Write new control register, do not trigger! */ |
c69ab2b78 hwmon: (fschmd) A... |
707 708 |
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL[data->kind], |
97950c3d4 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 hwmon: (fschmd) A... |
743 744 745 |
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL[data->kind], data->watchdog_control); |
97950c3d4 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 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 hwmon: (fschmd) A... |
766 767 |
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL[data->kind], |
97950c3d4 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 hwmon: (fschmd) F... |
777 |
int watchdog_is_open; |
97950c3d4 hwmon: (fschmd) A... |
778 |
|
525ad3731 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 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 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 hwmon: (fschmd) A... |
797 |
mutex_unlock(&watchdog_data_mutex); |
c453615f7 hwmon: (fschmd) F... |
798 |
if (watchdog_is_open) |
97950c3d4 hwmon: (fschmd) A... |
799 800 801 802 803 |
return -EBUSY; /* Start the watchdog */ watchdog_trigger(data); filp->private_data = data; |
c5bf68fe0 *: convert stream... |
804 |
return stream_open(inode, filp); |
97950c3d4 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 hwmon: (fschmd) F... |
833 |
int ret; |
97950c3d4 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 hwmon: (fschmd) F... |
857 858 |
static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
97950c3d4 hwmon: (fschmd) A... |
859 |
{ |
1b7243e8f hwmon: (fschmd) D... |
860 |
struct watchdog_info ident = { |
97950c3d4 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 hwmon: (fschmd) A... |
924 925 |
return ret; } |
828c09509 const: constify r... |
926 |
static const struct file_operations watchdog_fops = { |
97950c3d4 hwmon: (fschmd) A... |
927 928 929 930 931 |
.owner = THIS_MODULE, .llseek = no_llseek, .open = watchdog_open, .release = watchdog_release, .write = watchdog_write, |
55929332c drivers: Push dow... |
932 |
.unlocked_ioctl = watchdog_ioctl, |
b6dfb2477 compat_ioctl: mov... |
933 |
.compat_ioctl = compat_ptr_ioctl, |
97950c3d4 hwmon: (fschmd) A... |
934 935 936 937 938 |
}; /* * Detect, register, unregister and update device functions |
569ff1022 hwmon: Add new co... |
939 |
*/ |
525ad3731 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 dmi: Let dmi_walk... |
944 |
static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) |
7845cd791 hwmon: (fschmd) R... |
945 946 |
{ int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; |
525ad3731 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 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 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 hwmon: (fschmd) R... |
962 963 |
if (header->length < 5 || dmi_data[4] != 19) return; |
525ad3731 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 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 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 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 hwmon: (fschmd) R... |
1014 1015 1016 |
dmi_vref = vref; } } |
310ec7921 i2c: Drop the kin... |
1017 |
static int fschmd_detect(struct i2c_client *client, |
40ac1994b hwmon: (fschmd) C... |
1018 |
struct i2c_board_info *info) |
569ff1022 hwmon: Add new co... |
1019 |
{ |
52df6440a hwmon: Clean up d... |
1020 |
enum chips kind; |
40ac1994b hwmon: (fschmd) C... |
1021 |
struct i2c_adapter *adapter = client->adapter; |
52df6440a hwmon: Clean up d... |
1022 |
char id[4]; |
569ff1022 hwmon: Add new co... |
1023 1024 |
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
40ac1994b hwmon: (fschmd) C... |
1025 |
return -ENODEV; |
569ff1022 hwmon: Add new co... |
1026 1027 |
/* Detect & Identify the chip */ |
52df6440a 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 hwmon: Add new co... |
1049 |
|
dc71afe5a hwmon: Fix off-by... |
1050 |
strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE); |
40ac1994b hwmon: (fschmd) C... |
1051 1052 1053 |
return 0; } |
674870385 hwmon: use simple... |
1054 |
static int fschmd_probe(struct i2c_client *client) |
40ac1994b hwmon: (fschmd) C... |
1055 1056 |
{ struct fschmd_data *data; |
de15f093e hwmon: (fschmd) A... |
1057 1058 |
const char * const names[7] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall", "Hades", "Syleus" }; |
97950c3d4 hwmon: (fschmd) A... |
1059 |
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; |
40ac1994b hwmon: (fschmd) C... |
1060 |
int i, err; |
674870385 hwmon: use simple... |
1061 |
enum chips kind = i2c_match_id(fschmd_id, client)->driver_data; |
40ac1994b 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 hwmon: (fschmd) A... |
1069 1070 1071 |
mutex_init(&data->watchdog_lock); INIT_LIST_HEAD(&data->list); kref_init(&data->kref); |
525ad3731 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 hwmon: (fschmd) A... |
1077 |
data->client = client; |
dc71afe5a hwmon: Fix off-by... |
1078 |
data->kind = kind; |
40ac1994b hwmon: (fschmd) C... |
1079 |
|
569ff1022 hwmon: Add new co... |
1080 |
if (kind == fscpos) { |
525ad3731 hwmon: (fschmd) F... |
1081 1082 1083 1084 |
/* * The Poseidon has hardwired temp limits, fill these * in for the alarm resetting code */ |
569ff1022 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 hwmon: (fschmd) R... |
1089 |
/* Read the special DMI table for fscher and newer chips */ |
453e308d7 hwmon: (fschmd) C... |
1090 |
if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { |
e7a19c562 dmi: Let dmi_walk... |
1091 |
dmi_walk(fschmd_dmi_decode, NULL); |
7845cd791 hwmon: (fschmd) R... |
1092 |
if (dmi_vref == -1) { |
453e308d7 hwmon: (fschmd) C... |
1093 1094 |
dev_warn(&client->dev, "Couldn't get voltage scaling factors from " |
7845cd791 hwmon: (fschmd) R... |
1095 1096 1097 1098 1099 |
"BIOS DMI table, using builtin defaults "); dmi_vref = 33; } } |
97950c3d4 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 hwmon: (fschmd) A... |
1105 |
FSCHMD_REG_WDOG_CONTROL[data->kind]); |
97950c3d4 hwmon: (fschmd) A... |
1106 |
data->watchdog_state = i2c_smbus_read_byte_data(client, |
c69ab2b78 hwmon: (fschmd) A... |
1107 |
FSCHMD_REG_WDOG_STATE[data->kind]); |
97950c3d4 hwmon: (fschmd) A... |
1108 |
data->watchdog_preset = i2c_smbus_read_byte_data(client, |
c69ab2b78 hwmon: (fschmd) A... |
1109 |
FSCHMD_REG_WDOG_PRESET[data->kind]); |
97950c3d4 hwmon: (fschmd) A... |
1110 |
|
c69ab2b78 hwmon: (fschmd) A... |
1111 1112 1113 |
err = device_create_file(&client->dev, &dev_attr_alert_led); if (err) goto exit_detach; |
569ff1022 hwmon: Add new co... |
1114 |
|
c69ab2b78 hwmon: (fschmd) A... |
1115 |
for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { |
569ff1022 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 hwmon: (fschmd) U... |
1125 |
temp_max_show) |
569ff1022 hwmon: Add new co... |
1126 |
continue; |
c69ab2b78 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 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 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 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 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 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 hwmon: Fix checkp... |
1203 1204 1205 |
dev_warn(&client->dev, "Couldn't register watchdog chardev (due to no free minor) "); |
97950c3d4 hwmon: (fschmd) A... |
1206 1207 |
} mutex_unlock(&watchdog_data_mutex); |
453e308d7 hwmon: (fschmd) C... |
1208 1209 |
dev_info(&client->dev, "Detected FSC %s chip, revision: %d ", |
97950c3d4 hwmon: (fschmd) A... |
1210 |
names[data->kind], (int) data->revision); |
569ff1022 hwmon: Add new co... |
1211 1212 1213 1214 |
return 0; exit_detach: |
40ac1994b hwmon: (fschmd) C... |
1215 |
fschmd_remove(client); /* will also free data for us */ |
569ff1022 hwmon: Add new co... |
1216 1217 |
return err; } |
40ac1994b hwmon: (fschmd) C... |
1218 |
static int fschmd_remove(struct i2c_client *client) |
569ff1022 hwmon: Add new co... |
1219 1220 |
{ struct fschmd_data *data = i2c_get_clientdata(client); |
40ac1994b hwmon: (fschmd) C... |
1221 |
int i; |
569ff1022 hwmon: Add new co... |
1222 |
|
97950c3d4 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 hwmon: (fschmd) F... |
1241 1242 1243 1244 |
/* * Check if registered in case we're called from fschmd_detect * to cleanup after an error */ |
569ff1022 hwmon: Add new co... |
1245 1246 |
if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); |
c69ab2b78 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 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 hwmon: (fschmd) A... |
1256 1257 1258 |
mutex_lock(&watchdog_data_mutex); kref_put(&data->kref, fschmd_release_resources); mutex_unlock(&watchdog_data_mutex); |
569ff1022 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 hwmon: (fschmd) F... |
1283 1284 1285 1286 |
/* * reset alarm if the alarm condition is gone, * the chip doesn't do this itself */ |
569ff1022 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 hwmon: (fschmd) A... |
1292 |
data->temp_status[i]); |
569ff1022 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 hwmon: (fschmd) C... |
1310 |
if ((data->fan_status[i] & FSCHMD_FAN_ALARM) && |
569ff1022 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 hwmon: (fschmd) A... |
1314 |
data->fan_status[i]); |
569ff1022 hwmon: Add new co... |
1315 |
} |
c69ab2b78 hwmon: (fschmd) A... |
1316 |
for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) |
569ff1022 hwmon: Add new co... |
1317 |
data->volt[i] = i2c_smbus_read_byte_data(client, |
c69ab2b78 hwmon: (fschmd) A... |
1318 |
FSCHMD_REG_VOLT[data->kind][i]); |
569ff1022 hwmon: Add new co... |
1319 |
|
569ff1022 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 hwmon: convert dr... |
1328 |
module_i2c_driver(fschmd_driver); |
569ff1022 hwmon: Add new co... |
1329 |
|
453e308d7 hwmon: (fschmd) C... |
1330 |
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
de15f093e hwmon: (fschmd) A... |
1331 1332 |
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades " "and Syleus driver"); |
569ff1022 hwmon: Add new co... |
1333 |
MODULE_LICENSE("GPL"); |