aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/chips/smsc47m1.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/i2c/chips/smsc47m1.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/i2c/chips/smsc47m1.c')
-rw-r--r--drivers/i2c/chips/smsc47m1.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c
new file mode 100644
index 000000000000..0e12ca369413
--- /dev/null
+++ b/drivers/i2c/chips/smsc47m1.c
@@ -0,0 +1,591 @@
1/*
2 smsc47m1.c - Part of lm_sensors, Linux kernel modules
3 for hardware monitoring
4
5 Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x
6 Super-I/O chips.
7
8 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
9 Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
10 Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
11 and Jean Delvare
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
27
28#include <linux/module.h>
29#include <linux/slab.h>
30#include <linux/ioport.h>
31#include <linux/jiffies.h>
32#include <linux/i2c.h>
33#include <linux/i2c-sensor.h>
34#include <linux/init.h>
35#include <asm/io.h>
36
37static unsigned short normal_i2c[] = { I2C_CLIENT_END };
38/* Address is autodetected, there is no default value */
39static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
40static struct i2c_force_data forces[] = {{NULL}};
41
42enum chips { any_chip, smsc47m1 };
43static struct i2c_address_data addr_data = {
44 .normal_i2c = normal_i2c,
45 .normal_isa = normal_isa,
46 .forces = forces,
47};
48
49/* Super-I/0 registers and commands */
50
51#define REG 0x2e /* The register to read/write */
52#define VAL 0x2f /* The value to read/write */
53
54static inline void
55superio_outb(int reg, int val)
56{
57 outb(reg, REG);
58 outb(val, VAL);
59}
60
61static inline int
62superio_inb(int reg)
63{
64 outb(reg, REG);
65 return inb(VAL);
66}
67
68/* logical device for fans is 0x0A */
69#define superio_select() superio_outb(0x07, 0x0A)
70
71static inline void
72superio_enter(void)
73{
74 outb(0x55, REG);
75}
76
77static inline void
78superio_exit(void)
79{
80 outb(0xAA, REG);
81}
82
83#define SUPERIO_REG_ACT 0x30
84#define SUPERIO_REG_BASE 0x60
85#define SUPERIO_REG_DEVID 0x20
86
87/* Logical device registers */
88
89#define SMSC_EXTENT 0x80
90
91/* nr is 0 or 1 in the macros below */
92#define SMSC47M1_REG_ALARM 0x04
93#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
94#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
95#define SMSC47M1_REG_PWM(nr) (0x56 + (nr))
96#define SMSC47M1_REG_FANDIV 0x58
97#define SMSC47M1_REG_FAN(nr) (0x59 + (nr))
98#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr))
99
100#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \
101 983040/((192-(reg))*(div)))
102#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \
103 983040/(((reg)-(preload))*(div)))
104#define DIV_FROM_REG(reg) (1 << (reg))
105#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1)
106#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01)
107#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E)
108
109struct smsc47m1_data {
110 struct i2c_client client;
111 struct semaphore lock;
112
113 struct semaphore update_lock;
114 unsigned long last_updated; /* In jiffies */
115
116 u8 fan[2]; /* Register value */
117 u8 fan_preload[2]; /* Register value */
118 u8 fan_div[2]; /* Register encoding, shifted right */
119 u8 alarms; /* Register encoding */
120 u8 pwm[2]; /* Register value (bit 7 is enable) */
121};
122
123
124static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
125static int smsc47m1_find(int *address);
126static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind);
127static int smsc47m1_detach_client(struct i2c_client *client);
128
129static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
130static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value);
131
132static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
133 int init);
134
135
136static struct i2c_driver smsc47m1_driver = {
137 .owner = THIS_MODULE,
138 .name = "smsc47m1",
139 .id = I2C_DRIVERID_SMSC47M1,
140 .flags = I2C_DF_NOTIFY,
141 .attach_adapter = smsc47m1_attach_adapter,
142 .detach_client = smsc47m1_detach_client,
143};
144
145/* nr is 0 or 1 in the callback functions below */
146
147static ssize_t get_fan(struct device *dev, char *buf, int nr)
148{
149 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
150 /* This chip (stupidly) stops monitoring fan speed if PWM is
151 enabled and duty cycle is 0%. This is fine if the monitoring
152 and control concern the same fan, but troublesome if they are
153 not (which could as well happen). */
154 int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
155 FAN_FROM_REG(data->fan[nr],
156 DIV_FROM_REG(data->fan_div[nr]),
157 data->fan_preload[nr]);
158 return sprintf(buf, "%d\n", rpm);
159}
160
161static ssize_t get_fan_min(struct device *dev, char *buf, int nr)
162{
163 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
164 int rpm = MIN_FROM_REG(data->fan_preload[nr],
165 DIV_FROM_REG(data->fan_div[nr]));
166 return sprintf(buf, "%d\n", rpm);
167}
168
169static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
170{
171 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
172 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
173}
174
175static ssize_t get_pwm(struct device *dev, char *buf, int nr)
176{
177 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
178 return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
179}
180
181static ssize_t get_pwm_en(struct device *dev, char *buf, int nr)
182{
183 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
184 return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
185}
186
187static ssize_t get_alarms(struct device *dev, char *buf)
188{
189 struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
190 return sprintf(buf, "%d\n", data->alarms);
191}
192
193static ssize_t set_fan_min(struct device *dev, const char *buf,
194 size_t count, int nr)
195{
196 struct i2c_client *client = to_i2c_client(dev);
197 struct smsc47m1_data *data = i2c_get_clientdata(client);
198 long rpmdiv, val = simple_strtol(buf, NULL, 10);
199
200 down(&data->update_lock);
201 rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]);
202
203 if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) {
204 up(&data->update_lock);
205 return -EINVAL;
206 }
207
208 data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
209 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
210 data->fan_preload[nr]);
211 up(&data->update_lock);
212
213 return count;
214}
215
216/* Note: we save and restore the fan minimum here, because its value is
217 determined in part by the fan clock divider. This follows the principle
218 of least suprise; the user doesn't expect the fan minimum to change just
219 because the divider changed. */
220static ssize_t set_fan_div(struct device *dev, const char *buf,
221 size_t count, int nr)
222{
223 struct i2c_client *client = to_i2c_client(dev);
224 struct smsc47m1_data *data = i2c_get_clientdata(client);
225
226 long new_div = simple_strtol(buf, NULL, 10), tmp;
227 u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
228
229 if (new_div == old_div) /* No change */
230 return count;
231
232 down(&data->update_lock);
233 switch (new_div) {
234 case 1: data->fan_div[nr] = 0; break;
235 case 2: data->fan_div[nr] = 1; break;
236 case 4: data->fan_div[nr] = 2; break;
237 case 8: data->fan_div[nr] = 3; break;
238 default:
239 up(&data->update_lock);
240 return -EINVAL;
241 }
242
243 tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F;
244 tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6);
245 smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
246
247 /* Preserve fan min */
248 tmp = 192 - (old_div * (192 - data->fan_preload[nr])
249 + new_div / 2) / new_div;
250 data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
251 smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
252 data->fan_preload[nr]);
253 up(&data->update_lock);
254
255 return count;
256}
257
258static ssize_t set_pwm(struct device *dev, const char *buf,
259 size_t count, int nr)
260{
261 struct i2c_client *client = to_i2c_client(dev);
262 struct smsc47m1_data *data = i2c_get_clientdata(client);
263
264 long val = simple_strtol(buf, NULL, 10);
265
266 if (val < 0 || val > 255)
267 return -EINVAL;
268
269 down(&data->update_lock);
270 data->pwm[nr] &= 0x81; /* Preserve additional bits */
271 data->pwm[nr] |= PWM_TO_REG(val);
272 smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
273 data->pwm[nr]);
274 up(&data->update_lock);
275
276 return count;
277}
278
279static ssize_t set_pwm_en(struct device *dev, const char *buf,
280 size_t count, int nr)
281{
282 struct i2c_client *client = to_i2c_client(dev);
283 struct smsc47m1_data *data = i2c_get_clientdata(client);
284
285 long val = simple_strtol(buf, NULL, 10);
286
287 if (val != 0 && val != 1)
288 return -EINVAL;
289
290 down(&data->update_lock);
291 data->pwm[nr] &= 0xFE; /* preserve the other bits */
292 data->pwm[nr] |= !val;
293 smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
294 data->pwm[nr]);
295 up(&data->update_lock);
296
297 return count;
298}
299
300#define fan_present(offset) \
301static ssize_t get_fan##offset (struct device *dev, char *buf) \
302{ \
303 return get_fan(dev, buf, offset - 1); \
304} \
305static ssize_t get_fan##offset##_min (struct device *dev, char *buf) \
306{ \
307 return get_fan_min(dev, buf, offset - 1); \
308} \
309static ssize_t set_fan##offset##_min (struct device *dev, \
310 const char *buf, size_t count) \
311{ \
312 return set_fan_min(dev, buf, count, offset - 1); \
313} \
314static ssize_t get_fan##offset##_div (struct device *dev, char *buf) \
315{ \
316 return get_fan_div(dev, buf, offset - 1); \
317} \
318static ssize_t set_fan##offset##_div (struct device *dev, \
319 const char *buf, size_t count) \
320{ \
321 return set_fan_div(dev, buf, count, offset - 1); \
322} \
323static ssize_t get_pwm##offset (struct device *dev, char *buf) \
324{ \
325 return get_pwm(dev, buf, offset - 1); \
326} \
327static ssize_t set_pwm##offset (struct device *dev, \
328 const char *buf, size_t count) \
329{ \
330 return set_pwm(dev, buf, count, offset - 1); \
331} \
332static ssize_t get_pwm##offset##_en (struct device *dev, char *buf) \
333{ \
334 return get_pwm_en(dev, buf, offset - 1); \
335} \
336static ssize_t set_pwm##offset##_en (struct device *dev, \
337 const char *buf, size_t count) \
338{ \
339 return set_pwm_en(dev, buf, count, offset - 1); \
340} \
341static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \
342 NULL); \
343static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
344 get_fan##offset##_min, set_fan##offset##_min); \
345static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
346 get_fan##offset##_div, set_fan##offset##_div); \
347static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
348 get_pwm##offset, set_pwm##offset); \
349static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
350 get_pwm##offset##_en, set_pwm##offset##_en);
351
352fan_present(1);
353fan_present(2);
354
355static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
356
357static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
358{
359 if (!(adapter->class & I2C_CLASS_HWMON))
360 return 0;
361 return i2c_detect(adapter, &addr_data, smsc47m1_detect);
362}
363
364static int smsc47m1_find(int *address)
365{
366 u8 val;
367
368 superio_enter();
369 val = superio_inb(SUPERIO_REG_DEVID);
370
371 /*
372 * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
373 * 0x5F) and LPC47B27x (device id 0x51) have fan control.
374 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
375 * can do much more besides (device id 0x60, unsupported).
376 */
377 if (val == 0x51)
378 printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n");
379 else if (val == 0x59)
380 printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n");
381 else if (val == 0x5F)
382 printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n");
383 else {
384 superio_exit();
385 return -ENODEV;
386 }
387
388 superio_select();
389 *address = (superio_inb(SUPERIO_REG_BASE) << 8)
390 | superio_inb(SUPERIO_REG_BASE + 1);
391 val = superio_inb(SUPERIO_REG_ACT);
392 if (*address == 0 || (val & 0x01) == 0) {
393 printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
394 superio_exit();
395 return -ENODEV;
396 }
397
398 superio_exit();
399 return 0;
400}
401
402static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
403{
404 struct i2c_client *new_client;
405 struct smsc47m1_data *data;
406 int err = 0;
407 int fan1, fan2, pwm1, pwm2;
408
409 if (!i2c_is_isa_adapter(adapter)) {
410 return 0;
411 }
412
413 if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {
414 dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
415 return -EBUSY;
416 }
417
418 if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
419 err = -ENOMEM;
420 goto error_release;
421 }
422 memset(data, 0x00, sizeof(struct smsc47m1_data));
423
424 new_client = &data->client;
425 i2c_set_clientdata(new_client, data);
426 new_client->addr = address;
427 init_MUTEX(&data->lock);
428 new_client->adapter = adapter;
429 new_client->driver = &smsc47m1_driver;
430 new_client->flags = 0;
431
432 strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
433 init_MUTEX(&data->update_lock);
434
435 /* If no function is properly configured, there's no point in
436 actually registering the chip. */
437 fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
438 == 0x05;
439 fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
440 == 0x05;
441 pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
442 == 0x04;
443 pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
444 == 0x04;
445 if (!(fan1 || fan2 || pwm1 || pwm2)) {
446 dev_warn(&new_client->dev, "Device is not configured, will not use\n");
447 err = -ENODEV;
448 goto error_free;
449 }
450
451 if ((err = i2c_attach_client(new_client)))
452 goto error_free;
453
454 /* Some values (fan min, clock dividers, pwm registers) may be
455 needed before any update is triggered, so we better read them
456 at least once here. We don't usually do it that way, but in
457 this particular case, manually reading 5 registers out of 8
458 doesn't make much sense and we're better using the existing
459 function. */
460 smsc47m1_update_device(&new_client->dev, 1);
461
462 if (fan1) {
463 device_create_file(&new_client->dev, &dev_attr_fan1_input);
464 device_create_file(&new_client->dev, &dev_attr_fan1_min);
465 device_create_file(&new_client->dev, &dev_attr_fan1_div);
466 } else
467 dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
468 "skipping\n");
469
470 if (fan2) {
471 device_create_file(&new_client->dev, &dev_attr_fan2_input);
472 device_create_file(&new_client->dev, &dev_attr_fan2_min);
473 device_create_file(&new_client->dev, &dev_attr_fan2_div);
474 } else
475 dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
476 "skipping\n");
477
478 if (pwm1) {
479 device_create_file(&new_client->dev, &dev_attr_pwm1);
480 device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
481 } else
482 dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
483 "skipping\n");
484 if (pwm2) {
485 device_create_file(&new_client->dev, &dev_attr_pwm2);
486 device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
487 } else
488 dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
489 "skipping\n");
490
491 device_create_file(&new_client->dev, &dev_attr_alarms);
492
493 return 0;
494
495error_free:
496 kfree(new_client);
497error_release:
498 release_region(address, SMSC_EXTENT);
499 return err;
500}
501
502static int smsc47m1_detach_client(struct i2c_client *client)
503{
504 int err;
505
506 if ((err = i2c_detach_client(client))) {
507 dev_err(&client->dev, "Client deregistration failed, "
508 "client not detached.\n");
509 return err;
510 }
511
512 release_region(client->addr, SMSC_EXTENT);
513 kfree(i2c_get_clientdata(client));
514
515 return 0;
516}
517
518static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
519{
520 int res;
521
522 down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
523 res = inb_p(client->addr + reg);
524 up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
525 return res;
526}
527
528static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
529{
530 down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
531 outb_p(value, client->addr + reg);
532 up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
533}
534
535static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
536 int init)
537{
538 struct i2c_client *client = to_i2c_client(dev);
539 struct smsc47m1_data *data = i2c_get_clientdata(client);
540
541 down(&data->update_lock);
542
543 if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
544 int i;
545
546 for (i = 0; i < 2; i++) {
547 data->fan[i] = smsc47m1_read_value(client,
548 SMSC47M1_REG_FAN(i));
549 data->fan_preload[i] = smsc47m1_read_value(client,
550 SMSC47M1_REG_FAN_PRELOAD(i));
551 data->pwm[i] = smsc47m1_read_value(client,
552 SMSC47M1_REG_PWM(i));
553 }
554
555 i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
556 data->fan_div[0] = (i >> 4) & 0x03;
557 data->fan_div[1] = i >> 6;
558
559 data->alarms = smsc47m1_read_value(client,
560 SMSC47M1_REG_ALARM) >> 6;
561 /* Clear alarms if needed */
562 if (data->alarms)
563 smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);
564
565 data->last_updated = jiffies;
566 }
567
568 up(&data->update_lock);
569 return data;
570}
571
572static int __init sm_smsc47m1_init(void)
573{
574 if (smsc47m1_find(normal_isa)) {
575 return -ENODEV;
576 }
577
578 return i2c_add_driver(&smsc47m1_driver);
579}
580
581static void __exit sm_smsc47m1_exit(void)
582{
583 i2c_del_driver(&smsc47m1_driver);
584}
585
586MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
587MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
588MODULE_LICENSE("GPL");
589
590module_init(sm_smsc47m1_init);
591module_exit(sm_smsc47m1_exit);