hwmon: (smsc47m1) Fix: do not use assignment in if condition
[deliverable/linux.git] / drivers / hwmon / smsc47m1.c
CommitLineData
1da177e4
LT
1/*
2 smsc47m1.c - Part of lm_sensors, Linux kernel modules
3 for hardware monitoring
4
6091780e 5 Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
8eccbb6f
JD
6 LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
7 Super-I/O chips.
1da177e4
LT
8
9 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
8eccbb6f 10 Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
1da177e4
LT
11 Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
12 and Jean Delvare
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27*/
28
512504e9
JP
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
1da177e4
LT
31#include <linux/module.h>
32#include <linux/slab.h>
33#include <linux/ioport.h>
34#include <linux/jiffies.h>
51f2cca1 35#include <linux/platform_device.h>
943b0830 36#include <linux/hwmon.h>
e84cfbcb 37#include <linux/hwmon-sysfs.h>
943b0830 38#include <linux/err.h>
1da177e4 39#include <linux/init.h>
9a61bf63 40#include <linux/mutex.h>
ce8c6ce1 41#include <linux/sysfs.h>
b9acb64a 42#include <linux/acpi.h>
6055fae8 43#include <linux/io.h>
1da177e4 44
67b671bc
JD
45static unsigned short force_id;
46module_param(force_id, ushort, 0);
47MODULE_PARM_DESC(force_id, "Override the detected device ID");
48
51f2cca1
JD
49static struct platform_device *pdev;
50
51#define DRVNAME "smsc47m1"
8eccbb6f 52enum chips { smsc47m1, smsc47m2 };
1da177e4
LT
53
54/* Super-I/0 registers and commands */
55
56#define REG 0x2e /* The register to read/write */
57#define VAL 0x2f /* The value to read/write */
58
59static inline void
60superio_outb(int reg, int val)
61{
62 outb(reg, REG);
63 outb(val, VAL);
64}
65
66static inline int
67superio_inb(int reg)
68{
69 outb(reg, REG);
70 return inb(VAL);
71}
72
73/* logical device for fans is 0x0A */
74#define superio_select() superio_outb(0x07, 0x0A)
75
76static inline void
77superio_enter(void)
78{
79 outb(0x55, REG);
80}
81
82static inline void
83superio_exit(void)
84{
85 outb(0xAA, REG);
86}
87
88#define SUPERIO_REG_ACT 0x30
89#define SUPERIO_REG_BASE 0x60
90#define SUPERIO_REG_DEVID 0x20
1b54ab45 91#define SUPERIO_REG_DEVREV 0x21
1da177e4
LT
92
93/* Logical device registers */
94
95#define SMSC_EXTENT 0x80
96
97/* nr is 0 or 1 in the macros below */
98#define SMSC47M1_REG_ALARM 0x04
99#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
100#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
1da177e4 101#define SMSC47M1_REG_FANDIV 0x58
8eccbb6f
JD
102
103static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
104static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c };
105static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
106
107#define SMSC47M2_REG_ALARM6 0x09
108#define SMSC47M2_REG_TPIN1 0x38
109#define SMSC47M2_REG_TPIN2 0x37
110#define SMSC47M2_REG_TPIN3 0x2d
111#define SMSC47M2_REG_PPIN3 0x2c
112#define SMSC47M2_REG_FANDIV3 0x6a
1da177e4
LT
113
114#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \
115 983040/((192-(reg))*(div)))
116#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \
117 983040/(((reg)-(preload))*(div)))
118#define DIV_FROM_REG(reg) (1 << (reg))
119#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1)
120#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01)
121#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E)
122
123struct smsc47m1_data {
51f2cca1
JD
124 unsigned short addr;
125 const char *name;
8eccbb6f 126 enum chips type;
1beeffe4 127 struct device *hwmon_dev;
1da177e4 128
9a61bf63 129 struct mutex update_lock;
1da177e4
LT
130 unsigned long last_updated; /* In jiffies */
131
8eccbb6f
JD
132 u8 fan[3]; /* Register value */
133 u8 fan_preload[3]; /* Register value */
134 u8 fan_div[3]; /* Register encoding, shifted right */
1da177e4 135 u8 alarms; /* Register encoding */
8eccbb6f 136 u8 pwm[3]; /* Register value (bit 0 is disable) */
1da177e4
LT
137};
138
51f2cca1
JD
139struct smsc47m1_sio_data {
140 enum chips type;
fa0bff02 141 u8 activate; /* Remember initial device state */
51f2cca1 142};
1da177e4 143
51f2cca1 144
3ecf44b3 145static int __exit smsc47m1_remove(struct platform_device *pdev);
1da177e4
LT
146static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
147 int init);
148
51f2cca1 149static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
94e183fd 150{
51f2cca1 151 return inb_p(data->addr + reg);
94e183fd
JD
152}
153
51f2cca1 154static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
94e183fd
JD
155 u8 value)
156{
51f2cca1 157 outb_p(value, data->addr + reg);
94e183fd 158}
1da177e4 159
51f2cca1 160static struct platform_driver smsc47m1_driver = {
cdaf7934 161 .driver = {
87218842 162 .owner = THIS_MODULE,
51f2cca1 163 .name = DRVNAME,
cdaf7934 164 },
3ecf44b3 165 .remove = __exit_p(smsc47m1_remove),
1da177e4
LT
166};
167
e84cfbcb
JD
168static ssize_t get_fan(struct device *dev, struct device_attribute
169 *devattr, char *buf)
1da177e4 170{
e84cfbcb 171 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4 172 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
e84cfbcb 173 int nr = attr->index;
1da177e4
LT
174 /* This chip (stupidly) stops monitoring fan speed if PWM is
175 enabled and duty cycle is 0%. This is fine if the monitoring
176 and control concern the same fan, but troublesome if they are
177 not (which could as well happen). */
178 int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
179 FAN_FROM_REG(data->fan[nr],
180 DIV_FROM_REG(data->fan_div[nr]),
181 data->fan_preload[nr]);
182 return sprintf(buf, "%d\n", rpm);
183}
184
e84cfbcb
JD
185static ssize_t get_fan_min(struct device *dev, struct device_attribute
186 *devattr, char *buf)
1da177e4 187{
e84cfbcb 188 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4 189 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
e84cfbcb 190 int nr = attr->index;
1da177e4
LT
191 int rpm = MIN_FROM_REG(data->fan_preload[nr],
192 DIV_FROM_REG(data->fan_div[nr]));
193 return sprintf(buf, "%d\n", rpm);
194}
195
e84cfbcb
JD
196static ssize_t get_fan_div(struct device *dev, struct device_attribute
197 *devattr, char *buf)
1da177e4 198{
e84cfbcb 199 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4 200 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
e84cfbcb 201 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
1da177e4
LT
202}
203
1f08af7e
JD
204static ssize_t get_fan_alarm(struct device *dev, struct device_attribute
205 *devattr, char *buf)
206{
207 int bitnr = to_sensor_dev_attr(devattr)->index;
208 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
209 return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
210}
211
e84cfbcb
JD
212static ssize_t get_pwm(struct device *dev, struct device_attribute
213 *devattr, char *buf)
1da177e4 214{
e84cfbcb 215 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4 216 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
e84cfbcb 217 return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
1da177e4
LT
218}
219
e84cfbcb
JD
220static ssize_t get_pwm_en(struct device *dev, struct device_attribute
221 *devattr, char *buf)
1da177e4 222{
e84cfbcb 223 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1da177e4 224 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
e84cfbcb 225 return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
1da177e4
LT
226}
227
e84cfbcb
JD
228static ssize_t get_alarms(struct device *dev, struct device_attribute
229 *devattr, char *buf)
1da177e4
LT
230{
231 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
232 return sprintf(buf, "%d\n", data->alarms);
233}
234
e84cfbcb
JD
235static ssize_t set_fan_min(struct device *dev, struct device_attribute
236 *devattr, const char *buf, size_t count)
1da177e4 237{
e84cfbcb 238 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
51f2cca1 239 struct smsc47m1_data *data = dev_get_drvdata(dev);
e84cfbcb 240 int nr = attr->index;
1da177e4
LT
241 long rpmdiv, val = simple_strtol(buf, NULL, 10);
242
9a61bf63 243 mutex_lock(&data->update_lock);
1da177e4
LT
244 rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
245
246 if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
9a61bf63 247 mutex_unlock(&data->update_lock);
1da177e4
LT
248 return -EINVAL;
249 }
250
251 data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
51f2cca1 252 smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
1da177e4 253 data->fan_preload[nr]);
9a61bf63 254 mutex_unlock(&data->update_lock);
1da177e4
LT
255
256 return count;
257}
258
259/* Note: we save and restore the fan minimum here, because its value is
260 determined in part by the fan clock divider. This follows the principle
d6e05edc 261 of least surprise; the user doesn't expect the fan minimum to change just
1da177e4 262 because the divider changed. */
e84cfbcb
JD
263static ssize_t set_fan_div(struct device *dev, struct device_attribute
264 *devattr, const char *buf, size_t count)
1da177e4 265{
e84cfbcb 266 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
51f2cca1 267 struct smsc47m1_data *data = dev_get_drvdata(dev);
e84cfbcb 268 int nr = attr->index;
1da177e4
LT
269 long new_div = simple_strtol(buf, NULL, 10), tmp;
270 u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
271
272 if (new_div == old_div) /* No change */
273 return count;
274
9a61bf63 275 mutex_lock(&data->update_lock);
1da177e4
LT
276 switch (new_div) {
277 case 1: data->fan_div[nr] = 0; break;
278 case 2: data->fan_div[nr] = 1; break;
279 case 4: data->fan_div[nr] = 2; break;
280 case 8: data->fan_div[nr] = 3; break;
281 default:
9a61bf63 282 mutex_unlock(&data->update_lock);
1da177e4
LT
283 return -EINVAL;
284 }
285
8eccbb6f
JD
286 switch (nr) {
287 case 0:
288 case 1:
51f2cca1 289 tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
8eccbb6f
JD
290 & ~(0x03 << (4 + 2 * nr));
291 tmp |= data->fan_div[nr] << (4 + 2 * nr);
51f2cca1 292 smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
8eccbb6f
JD
293 break;
294 case 2:
51f2cca1 295 tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
8eccbb6f 296 tmp |= data->fan_div[2] << 4;
51f2cca1 297 smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
8eccbb6f
JD
298 break;
299 }
1da177e4
LT
300
301 /* Preserve fan min */
302 tmp = 192 - (old_div * (192 - data->fan_preload[nr])
303 + new_div / 2) / new_div;
304 data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
51f2cca1 305 smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
1da177e4 306 data->fan_preload[nr]);
9a61bf63 307 mutex_unlock(&data->update_lock);
1da177e4
LT
308
309 return count;
310}
311
e84cfbcb
JD
312static ssize_t set_pwm(struct device *dev, struct device_attribute
313 *devattr, const char *buf, size_t count)
1da177e4 314{
e84cfbcb 315 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
51f2cca1 316 struct smsc47m1_data *data = dev_get_drvdata(dev);
e84cfbcb 317 int nr = attr->index;
1da177e4
LT
318 long val = simple_strtol(buf, NULL, 10);
319
320 if (val < 0 || val > 255)
321 return -EINVAL;
322
9a61bf63 323 mutex_lock(&data->update_lock);
1da177e4
LT
324 data->pwm[nr] &= 0x81; /* Preserve additional bits */
325 data->pwm[nr] |= PWM_TO_REG(val);
51f2cca1 326 smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
1da177e4 327 data->pwm[nr]);
9a61bf63 328 mutex_unlock(&data->update_lock);
1da177e4
LT
329
330 return count;
331}
332
e84cfbcb
JD
333static ssize_t set_pwm_en(struct device *dev, struct device_attribute
334 *devattr, const char *buf, size_t count)
1da177e4 335{
e84cfbcb 336 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
51f2cca1 337 struct smsc47m1_data *data = dev_get_drvdata(dev);
e84cfbcb 338 int nr = attr->index;
1da177e4
LT
339 long val = simple_strtol(buf, NULL, 10);
340
341 if (val != 0 && val != 1)
342 return -EINVAL;
343
9a61bf63 344 mutex_lock(&data->update_lock);
1da177e4
LT
345 data->pwm[nr] &= 0xFE; /* preserve the other bits */
346 data->pwm[nr] |= !val;
51f2cca1 347 smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
1da177e4 348 data->pwm[nr]);
9a61bf63 349 mutex_unlock(&data->update_lock);
1da177e4
LT
350
351 return count;
352}
353
354#define fan_present(offset) \
e84cfbcb
JD
355static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \
356 NULL, offset - 1); \
357static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
358 get_fan_min, set_fan_min, offset - 1); \
359static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
360 get_fan_div, set_fan_div, offset - 1); \
1f08af7e
JD
361static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm, \
362 NULL, offset - 1); \
e84cfbcb
JD
363static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
364 get_pwm, set_pwm, offset - 1); \
365static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
366 get_pwm_en, set_pwm_en, offset - 1)
1da177e4
LT
367
368fan_present(1);
369fan_present(2);
8eccbb6f 370fan_present(3);
1da177e4
LT
371
372static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
373
51f2cca1
JD
374static ssize_t show_name(struct device *dev, struct device_attribute
375 *devattr, char *buf)
376{
377 struct smsc47m1_data *data = dev_get_drvdata(dev);
378
379 return sprintf(buf, "%s\n", data->name);
380}
381static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
382
7e612685 383static struct attribute *smsc47m1_attributes_fan1[] = {
e84cfbcb
JD
384 &sensor_dev_attr_fan1_input.dev_attr.attr,
385 &sensor_dev_attr_fan1_min.dev_attr.attr,
386 &sensor_dev_attr_fan1_div.dev_attr.attr,
1f08af7e 387 &sensor_dev_attr_fan1_alarm.dev_attr.attr,
7e612685
GR
388 NULL
389};
390
391static const struct attribute_group smsc47m1_group_fan1 = {
392 .attrs = smsc47m1_attributes_fan1,
393};
394
395static struct attribute *smsc47m1_attributes_fan2[] = {
e84cfbcb
JD
396 &sensor_dev_attr_fan2_input.dev_attr.attr,
397 &sensor_dev_attr_fan2_min.dev_attr.attr,
398 &sensor_dev_attr_fan2_div.dev_attr.attr,
1f08af7e 399 &sensor_dev_attr_fan2_alarm.dev_attr.attr,
7e612685
GR
400 NULL
401};
402
403static const struct attribute_group smsc47m1_group_fan2 = {
404 .attrs = smsc47m1_attributes_fan2,
405};
406
407static struct attribute *smsc47m1_attributes_fan3[] = {
e84cfbcb
JD
408 &sensor_dev_attr_fan3_input.dev_attr.attr,
409 &sensor_dev_attr_fan3_min.dev_attr.attr,
410 &sensor_dev_attr_fan3_div.dev_attr.attr,
1f08af7e 411 &sensor_dev_attr_fan3_alarm.dev_attr.attr,
7e612685
GR
412 NULL
413};
e84cfbcb 414
7e612685
GR
415static const struct attribute_group smsc47m1_group_fan3 = {
416 .attrs = smsc47m1_attributes_fan3,
417};
418
419static struct attribute *smsc47m1_attributes_pwm1[] = {
e84cfbcb
JD
420 &sensor_dev_attr_pwm1.dev_attr.attr,
421 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
7e612685
GR
422 NULL
423};
424
425static const struct attribute_group smsc47m1_group_pwm1 = {
426 .attrs = smsc47m1_attributes_pwm1,
427};
428
429static struct attribute *smsc47m1_attributes_pwm2[] = {
e84cfbcb
JD
430 &sensor_dev_attr_pwm2.dev_attr.attr,
431 &sensor_dev_attr_pwm2_enable.dev_attr.attr,
7e612685
GR
432 NULL
433};
434
435static const struct attribute_group smsc47m1_group_pwm2 = {
436 .attrs = smsc47m1_attributes_pwm2,
437};
438
439static struct attribute *smsc47m1_attributes_pwm3[] = {
e84cfbcb
JD
440 &sensor_dev_attr_pwm3.dev_attr.attr,
441 &sensor_dev_attr_pwm3_enable.dev_attr.attr,
7e612685
GR
442 NULL
443};
ce8c6ce1 444
7e612685
GR
445static const struct attribute_group smsc47m1_group_pwm3 = {
446 .attrs = smsc47m1_attributes_pwm3,
447};
448
449static struct attribute *smsc47m1_attributes[] = {
ce8c6ce1 450 &dev_attr_alarms.attr,
51f2cca1 451 &dev_attr_name.attr,
ce8c6ce1
JD
452 NULL
453};
454
455static const struct attribute_group smsc47m1_group = {
456 .attrs = smsc47m1_attributes,
457};
458
51f2cca1
JD
459static int __init smsc47m1_find(unsigned short *addr,
460 struct smsc47m1_sio_data *sio_data)
1da177e4
LT
461{
462 u8 val;
463
464 superio_enter();
67b671bc 465 val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
1da177e4
LT
466
467 /*
6091780e
JD
468 * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
469 * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
1da177e4 470 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
ec5ce552 471 * can do much more besides (device id 0x60).
b890a07f
JD
472 * The LPC47M997 is undocumented, but seems to be compatible with
473 * the LPC47M192, and has the same device id.
8eccbb6f
JD
474 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
475 * supports a 3rd fan, and the pin configuration registers are
476 * unfortunately different.
1b54ab45
JD
477 * The LPC47M233 has the same device id (0x6B) but is not compatible.
478 * We check the high bit of the device revision register to
479 * differentiate them.
1da177e4 480 */
51f2cca1 481 switch (val) {
8eccbb6f 482 case 0x51:
512504e9 483 pr_info("Found SMSC LPC47B27x\n");
51f2cca1 484 sio_data->type = smsc47m1;
8eccbb6f
JD
485 break;
486 case 0x59:
512504e9 487 pr_info("Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
51f2cca1 488 sio_data->type = smsc47m1;
8eccbb6f
JD
489 break;
490 case 0x5F:
512504e9 491 pr_info("Found SMSC LPC47M14x\n");
51f2cca1 492 sio_data->type = smsc47m1;
8eccbb6f
JD
493 break;
494 case 0x60:
512504e9 495 pr_info("Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
51f2cca1 496 sio_data->type = smsc47m1;
8eccbb6f
JD
497 break;
498 case 0x6B:
1b54ab45 499 if (superio_inb(SUPERIO_REG_DEVREV) & 0x80) {
512504e9 500 pr_debug("Found SMSC LPC47M233, unsupported\n");
1b54ab45
JD
501 superio_exit();
502 return -ENODEV;
503 }
504
512504e9 505 pr_info("Found SMSC LPC47M292\n");
51f2cca1 506 sio_data->type = smsc47m2;
8eccbb6f
JD
507 break;
508 default:
1da177e4
LT
509 superio_exit();
510 return -ENODEV;
511 }
512
513 superio_select();
2d8672c5
JD
514 *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
515 | superio_inb(SUPERIO_REG_BASE + 1);
fa0bff02 516 if (*addr == 0) {
512504e9 517 pr_info("Device address not set, will not use\n");
1da177e4
LT
518 superio_exit();
519 return -ENODEV;
520 }
521
fa0bff02
JD
522 /* Enable only if address is set (needed at least on the
523 * Compaq Presario S4000NX) */
524 sio_data->activate = superio_inb(SUPERIO_REG_ACT);
525 if ((sio_data->activate & 0x01) == 0) {
512504e9 526 pr_info("Enabling device\n");
fa0bff02
JD
527 superio_outb(SUPERIO_REG_ACT, sio_data->activate | 0x01);
528 }
529
1da177e4
LT
530 superio_exit();
531 return 0;
532}
533
fa0bff02 534/* Restore device to its initial state */
a00d643a 535static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data)
fa0bff02
JD
536{
537 if ((sio_data->activate & 0x01) == 0) {
538 superio_enter();
539 superio_select();
540
512504e9 541 pr_info("Disabling device\n");
fa0bff02
JD
542 superio_outb(SUPERIO_REG_ACT, sio_data->activate);
543
544 superio_exit();
545 }
546}
547
a0e92d70
JD
548#define CHECK 1
549#define REQUEST 2
550#define RELEASE 3
551
552/*
553 * This function can be used to:
554 * - test for resource conflicts with ACPI
555 * - request the resources
556 * - release the resources
557 * We only allocate the I/O ports we really need, to minimize the risk of
558 * conflicts with ACPI or with other drivers.
559 */
560static int smsc47m1_handle_resources(unsigned short address, enum chips type,
561 int action, struct device *dev)
562{
563 static const u8 ports_m1[] = {
564 /* register, region length */
565 0x04, 1,
566 0x33, 4,
567 0x56, 7,
568 };
569
570 static const u8 ports_m2[] = {
571 /* register, region length */
572 0x04, 1,
573 0x09, 1,
574 0x2c, 2,
575 0x35, 4,
576 0x56, 7,
577 0x69, 4,
578 };
579
580 int i, ports_size, err;
581 const u8 *ports;
582
583 switch (type) {
584 case smsc47m1:
585 default:
586 ports = ports_m1;
587 ports_size = ARRAY_SIZE(ports_m1);
588 break;
589 case smsc47m2:
590 ports = ports_m2;
591 ports_size = ARRAY_SIZE(ports_m2);
592 break;
593 }
594
595 for (i = 0; i + 1 < ports_size; i += 2) {
596 unsigned short start = address + ports[i];
597 unsigned short len = ports[i + 1];
598
599 switch (action) {
600 case CHECK:
601 /* Only check for conflicts */
602 err = acpi_check_region(start, len, DRVNAME);
603 if (err)
604 return err;
605 break;
606 case REQUEST:
607 /* Request the resources */
608 if (!request_region(start, len, DRVNAME)) {
609 dev_err(dev, "Region 0x%hx-0x%hx already in "
610 "use!\n", start, start + len);
611
612 /* Undo all requests */
613 for (i -= 2; i >= 0; i -= 2)
614 release_region(address + ports[i],
615 ports[i + 1]);
616 return -EBUSY;
617 }
618 break;
619 case RELEASE:
620 /* Release the resources */
621 release_region(start, len);
622 break;
623 }
624 }
625
626 return 0;
627}
628
7e612685
GR
629static void smsc47m1_remove_files(struct device *dev)
630{
631 sysfs_remove_group(&dev->kobj, &smsc47m1_group);
632 sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan1);
633 sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan2);
634 sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan3);
635 sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm1);
636 sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm2);
637 sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm3);
638}
639
3ecf44b3 640static int __init smsc47m1_probe(struct platform_device *pdev)
1da177e4 641{
51f2cca1
JD
642 struct device *dev = &pdev->dev;
643 struct smsc47m1_sio_data *sio_data = dev->platform_data;
1da177e4 644 struct smsc47m1_data *data;
51f2cca1 645 struct resource *res;
a0e92d70 646 int err;
8eccbb6f 647 int fan1, fan2, fan3, pwm1, pwm2, pwm3;
1da177e4 648
51f2cca1
JD
649 static const char *names[] = {
650 "smsc47m1",
651 "smsc47m2",
652 };
653
654 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
a0e92d70
JD
655 err = smsc47m1_handle_resources(res->start, sio_data->type,
656 REQUEST, dev);
657 if (err < 0)
658 return err;
1da177e4 659
ba9c2e8d 660 if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
1da177e4
LT
661 err = -ENOMEM;
662 goto error_release;
663 }
1da177e4 664
51f2cca1
JD
665 data->addr = res->start;
666 data->type = sio_data->type;
667 data->name = names[sio_data->type];
9a61bf63 668 mutex_init(&data->update_lock);
51f2cca1 669 platform_set_drvdata(pdev, data);
1da177e4
LT
670
671 /* If no function is properly configured, there's no point in
672 actually registering the chip. */
51f2cca1 673 pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
1da177e4 674 == 0x04;
51f2cca1 675 pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
1da177e4 676 == 0x04;
8eccbb6f 677 if (data->type == smsc47m2) {
51f2cca1 678 fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
8eccbb6f 679 & 0x0d) == 0x09;
51f2cca1 680 fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
8eccbb6f 681 & 0x0d) == 0x09;
51f2cca1 682 fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
8eccbb6f 683 & 0x0d) == 0x0d;
51f2cca1 684 pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
8eccbb6f
JD
685 & 0x0d) == 0x08;
686 } else {
51f2cca1 687 fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
8eccbb6f 688 & 0x05) == 0x05;
51f2cca1 689 fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
8eccbb6f
JD
690 & 0x05) == 0x05;
691 fan3 = 0;
692 pwm3 = 0;
693 }
694 if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
51f2cca1 695 dev_warn(dev, "Device not configured, will not use\n");
1da177e4
LT
696 err = -ENODEV;
697 goto error_free;
698 }
699
1da177e4
LT
700 /* Some values (fan min, clock dividers, pwm registers) may be
701 needed before any update is triggered, so we better read them
702 at least once here. We don't usually do it that way, but in
703 this particular case, manually reading 5 registers out of 8
704 doesn't make much sense and we're better using the existing
705 function. */
51f2cca1 706 smsc47m1_update_device(dev, 1);
1da177e4 707
943b0830 708 /* Register sysfs hooks */
1da177e4 709 if (fan1) {
7e612685
GR
710 err = sysfs_create_group(&dev->kobj,
711 &smsc47m1_group_fan1);
712 if (err)
ce8c6ce1 713 goto error_remove_files;
1da177e4 714 } else
51f2cca1 715 dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
1da177e4
LT
716
717 if (fan2) {
7e612685
GR
718 err = sysfs_create_group(&dev->kobj,
719 &smsc47m1_group_fan2);
720 if (err)
ce8c6ce1 721 goto error_remove_files;
1da177e4 722 } else
51f2cca1 723 dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
1da177e4 724
8eccbb6f 725 if (fan3) {
7e612685
GR
726 err = sysfs_create_group(&dev->kobj,
727 &smsc47m1_group_fan3);
728 if (err)
8eccbb6f 729 goto error_remove_files;
8477d026 730 } else if (data->type == smsc47m2)
51f2cca1 731 dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
8eccbb6f 732
1da177e4 733 if (pwm1) {
7e612685
GR
734 err = sysfs_create_group(&dev->kobj,
735 &smsc47m1_group_pwm1);
736 if (err)
ce8c6ce1 737 goto error_remove_files;
1da177e4 738 } else
51f2cca1 739 dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
8eccbb6f 740
1da177e4 741 if (pwm2) {
7e612685
GR
742 err = sysfs_create_group(&dev->kobj,
743 &smsc47m1_group_pwm2);
744 if (err)
ce8c6ce1 745 goto error_remove_files;
1da177e4 746 } else
51f2cca1 747 dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
1da177e4 748
8eccbb6f 749 if (pwm3) {
7e612685
GR
750 err = sysfs_create_group(&dev->kobj,
751 &smsc47m1_group_pwm3);
752 if (err)
8eccbb6f 753 goto error_remove_files;
8477d026 754 } else if (data->type == smsc47m2)
51f2cca1 755 dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
8eccbb6f 756
7e612685
GR
757 err = sysfs_create_group(&dev->kobj, &smsc47m1_group);
758 if (err)
68a50b56 759 goto error_remove_files;
ce8c6ce1 760
1beeffe4
TJ
761 data->hwmon_dev = hwmon_device_register(dev);
762 if (IS_ERR(data->hwmon_dev)) {
763 err = PTR_ERR(data->hwmon_dev);
ce8c6ce1
JD
764 goto error_remove_files;
765 }
1da177e4
LT
766
767 return 0;
768
ce8c6ce1 769error_remove_files:
7e612685 770 smsc47m1_remove_files(dev);
1da177e4 771error_free:
04a6217d 772 platform_set_drvdata(pdev, NULL);
1f57ff89 773 kfree(data);
1da177e4 774error_release:
a0e92d70 775 smsc47m1_handle_resources(res->start, sio_data->type, RELEASE, dev);
1da177e4
LT
776 return err;
777}
778
3ecf44b3 779static int __exit smsc47m1_remove(struct platform_device *pdev)
1da177e4 780{
51f2cca1
JD
781 struct smsc47m1_data *data = platform_get_drvdata(pdev);
782 struct resource *res;
1da177e4 783
1beeffe4 784 hwmon_device_unregister(data->hwmon_dev);
7e612685 785 smsc47m1_remove_files(&pdev->dev);
1da177e4 786
51f2cca1 787 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
a0e92d70 788 smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev);
04a6217d 789 platform_set_drvdata(pdev, NULL);
943b0830 790 kfree(data);
1da177e4
LT
791
792 return 0;
793}
794
1da177e4
LT
795static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
796 int init)
797{
51f2cca1 798 struct smsc47m1_data *data = dev_get_drvdata(dev);
1da177e4 799
9a61bf63 800 mutex_lock(&data->update_lock);
1da177e4
LT
801
802 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
8eccbb6f
JD
803 int i, fan_nr;
804 fan_nr = data->type == smsc47m2 ? 3 : 2;
1da177e4 805
8eccbb6f 806 for (i = 0; i < fan_nr; i++) {
51f2cca1 807 data->fan[i] = smsc47m1_read_value(data,
8eccbb6f 808 SMSC47M1_REG_FAN[i]);
51f2cca1 809 data->fan_preload[i] = smsc47m1_read_value(data,
8eccbb6f 810 SMSC47M1_REG_FAN_PRELOAD[i]);
51f2cca1 811 data->pwm[i] = smsc47m1_read_value(data,
8eccbb6f 812 SMSC47M1_REG_PWM[i]);
1da177e4
LT
813 }
814
51f2cca1 815 i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
1da177e4
LT
816 data->fan_div[0] = (i >> 4) & 0x03;
817 data->fan_div[1] = i >> 6;
818
51f2cca1 819 data->alarms = smsc47m1_read_value(data,
1da177e4
LT
820 SMSC47M1_REG_ALARM) >> 6;
821 /* Clear alarms if needed */
822 if (data->alarms)
51f2cca1 823 smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
1da177e4 824
8eccbb6f 825 if (fan_nr >= 3) {
51f2cca1 826 data->fan_div[2] = (smsc47m1_read_value(data,
8eccbb6f 827 SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
51f2cca1 828 data->alarms |= (smsc47m1_read_value(data,
8eccbb6f
JD
829 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
830 /* Clear alarm if needed */
831 if (data->alarms & 0x04)
51f2cca1 832 smsc47m1_write_value(data,
8eccbb6f
JD
833 SMSC47M2_REG_ALARM6,
834 0x40);
835 }
836
1da177e4
LT
837 data->last_updated = jiffies;
838 }
839
9a61bf63 840 mutex_unlock(&data->update_lock);
1da177e4
LT
841 return data;
842}
843
51f2cca1
JD
844static int __init smsc47m1_device_add(unsigned short address,
845 const struct smsc47m1_sio_data *sio_data)
846{
847 struct resource res = {
848 .start = address,
849 .end = address + SMSC_EXTENT - 1,
850 .name = DRVNAME,
851 .flags = IORESOURCE_IO,
852 };
853 int err;
854
a0e92d70 855 err = smsc47m1_handle_resources(address, sio_data->type, CHECK, NULL);
b9acb64a
JD
856 if (err)
857 goto exit;
858
51f2cca1
JD
859 pdev = platform_device_alloc(DRVNAME, address);
860 if (!pdev) {
861 err = -ENOMEM;
512504e9 862 pr_err("Device allocation failed\n");
51f2cca1
JD
863 goto exit;
864 }
865
866 err = platform_device_add_resources(pdev, &res, 1);
867 if (err) {
512504e9 868 pr_err("Device resource addition failed (%d)\n", err);
51f2cca1
JD
869 goto exit_device_put;
870 }
871
2df6d811
JD
872 err = platform_device_add_data(pdev, sio_data,
873 sizeof(struct smsc47m1_sio_data));
874 if (err) {
512504e9 875 pr_err("Platform data allocation failed\n");
51f2cca1
JD
876 goto exit_device_put;
877 }
51f2cca1
JD
878
879 err = platform_device_add(pdev);
880 if (err) {
512504e9 881 pr_err("Device addition failed (%d)\n", err);
51f2cca1
JD
882 goto exit_device_put;
883 }
884
885 return 0;
886
887exit_device_put:
888 platform_device_put(pdev);
889exit:
890 return err;
891}
892
1da177e4
LT
893static int __init sm_smsc47m1_init(void)
894{
51f2cca1
JD
895 int err;
896 unsigned short address;
897 struct smsc47m1_sio_data sio_data;
898
899 if (smsc47m1_find(&address, &sio_data))
1da177e4 900 return -ENODEV;
1da177e4 901
3ecf44b3
JD
902 /* Sets global pdev as a side effect */
903 err = smsc47m1_device_add(address, &sio_data);
51f2cca1
JD
904 if (err)
905 goto exit;
906
3ecf44b3 907 err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe);
51f2cca1 908 if (err)
3ecf44b3 909 goto exit_device;
51f2cca1
JD
910
911 return 0;
912
3ecf44b3
JD
913exit_device:
914 platform_device_unregister(pdev);
fa0bff02 915 smsc47m1_restore(&sio_data);
51f2cca1
JD
916exit:
917 return err;
1da177e4
LT
918}
919
920static void __exit sm_smsc47m1_exit(void)
921{
51f2cca1 922 platform_driver_unregister(&smsc47m1_driver);
fa0bff02 923 smsc47m1_restore(pdev->dev.platform_data);
3ecf44b3 924 platform_device_unregister(pdev);
1da177e4
LT
925}
926
927MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
928MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
929MODULE_LICENSE("GPL");
930
931module_init(sm_smsc47m1_init);
932module_exit(sm_smsc47m1_exit);
This page took 0.936303 seconds and 5 git commands to generate.