aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pc87427.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/pc87427.c')
-rw-r--r--drivers/hwmon/pc87427.c271
1 files changed, 269 insertions, 2 deletions
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 0ac55ba6c6b8..869822785b4f 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -15,10 +15,10 @@
15 * Supports the following chips: 15 * Supports the following chips:
16 * 16 *
17 * Chip #vin #fan #pwm #temp devid 17 * Chip #vin #fan #pwm #temp devid
18 * PC87427 - 8 - - 0xF2 18 * PC87427 - 8 4 - 0xF2
19 * 19 *
20 * This driver assumes that no more than one chip is present. 20 * This driver assumes that no more than one chip is present.
21 * Only fan inputs are supported so far, although the chip can do much more. 21 * Only fans are supported so far, although the chip can do much more.
22 */ 22 */
23 23
24#include <linux/module.h> 24#include <linux/module.h>
@@ -57,10 +57,16 @@ struct pc87427_data {
57 u16 fan[8]; /* register values */ 57 u16 fan[8]; /* register values */
58 u16 fan_min[8]; /* register values */ 58 u16 fan_min[8]; /* register values */
59 u8 fan_status[8]; /* register values */ 59 u8 fan_status[8]; /* register values */
60
61 u8 pwm_enabled; /* bit vector */
62 u8 pwm_auto_ok; /* bit vector */
63 u8 pwm_enable[4]; /* register values */
64 u8 pwm[4]; /* register values */
60}; 65};
61 66
62struct pc87427_sio_data { 67struct pc87427_sio_data {
63 u8 has_fanin; 68 u8 has_fanin;
69 u8 has_fanout;
64}; 70};
65 71
66/* 72/*
@@ -72,7 +78,9 @@ struct pc87427_sio_data {
72#define SIOREG_CF2 0x22 /* Configuration 2 */ 78#define SIOREG_CF2 0x22 /* Configuration 2 */
73#define SIOREG_CF3 0x23 /* Configuration 3 */ 79#define SIOREG_CF3 0x23 /* Configuration 3 */
74#define SIOREG_CF4 0x24 /* Configuration 4 */ 80#define SIOREG_CF4 0x24 /* Configuration 4 */
81#define SIOREG_CF5 0x25 /* Configuration 5 */
75#define SIOREG_CFB 0x2B /* Configuration B */ 82#define SIOREG_CFB 0x2B /* Configuration B */
83#define SIOREG_CFC 0x2C /* Configuration C */
76#define SIOREG_CFD 0x2D /* Configuration D */ 84#define SIOREG_CFD 0x2D /* Configuration D */
77#define SIOREG_ACT 0x30 /* Device activation */ 85#define SIOREG_ACT 0x30 /* Device activation */
78#define SIOREG_MAP 0x50 /* I/O or memory mapping */ 86#define SIOREG_MAP 0x50 /* I/O or memory mapping */
@@ -188,6 +196,61 @@ static inline u16 fan_to_reg(unsigned long val)
188} 196}
189 197
190/* 198/*
199 * PWM registers and conversions
200 */
201
202#define PC87427_REG_PWM_ENABLE 0x10
203#define PC87427_REG_PWM_DUTY 0x12
204
205#define PWM_ENABLE_MODE_MASK (7 << 4)
206#define PWM_ENABLE_CTLEN (1 << 0)
207
208#define PWM_MODE_MANUAL (0 << 4)
209#define PWM_MODE_AUTO (1 << 4)
210#define PWM_MODE_OFF (2 << 4)
211#define PWM_MODE_ON (7 << 4)
212
213/* Dedicated function to read all registers related to a given PWM output.
214 This saves us quite a few locks and bank selections.
215 Must be called with data->lock held.
216 nr is from 0 to 3 */
217static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr)
218{
219 int iobase = data->address[LD_FAN];
220
221 outb(BANK_FC(nr), iobase + PC87427_REG_BANK);
222 data->pwm_enable[nr] = inb(iobase + PC87427_REG_PWM_ENABLE);
223 data->pwm[nr] = inb(iobase + PC87427_REG_PWM_DUTY);
224}
225
226static inline int pwm_enable_from_reg(u8 reg)
227{
228 switch (reg & PWM_ENABLE_MODE_MASK) {
229 case PWM_MODE_ON:
230 return 0;
231 case PWM_MODE_MANUAL:
232 case PWM_MODE_OFF:
233 return 1;
234 case PWM_MODE_AUTO:
235 return 2;
236 default:
237 return -EPROTO;
238 }
239}
240
241static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval)
242{
243 switch (val) {
244 default:
245 return PWM_MODE_ON;
246 case 1:
247 return pwmval ? PWM_MODE_MANUAL : PWM_MODE_OFF;
248 case 2:
249 return PWM_MODE_AUTO;
250 }
251}
252
253/*
191 * Data interface 254 * Data interface
192 */ 255 */
193 256
@@ -207,6 +270,14 @@ static struct pc87427_data *pc87427_update_device(struct device *dev)
207 continue; 270 continue;
208 pc87427_readall_fan(data, i); 271 pc87427_readall_fan(data, i);
209 } 272 }
273
274 /* PWM outputs */
275 for (i = 0; i < 4; i++) {
276 if (!(data->pwm_enabled & (1 << i)))
277 continue;
278 pc87427_readall_pwm(data, i);
279 }
280
210 data->last_updated = jiffies; 281 data->last_updated = jiffies;
211 282
212done: 283done:
@@ -384,6 +455,145 @@ static const struct attribute_group pc87427_group_fan[8] = {
384 { .attrs = pc87427_attributes_fan[7] }, 455 { .attrs = pc87427_attributes_fan[7] },
385}; 456};
386 457
458/* Must be called with data->lock held and pc87427_readall_pwm() freshly
459 called */
460static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode)
461{
462 int iobase = data->address[LD_FAN];
463 data->pwm_enable[nr] &= ~PWM_ENABLE_MODE_MASK;
464 data->pwm_enable[nr] |= mode;
465 outb(data->pwm_enable[nr], iobase + PC87427_REG_PWM_ENABLE);
466}
467
468static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
469 *devattr, char *buf)
470{
471 struct pc87427_data *data = pc87427_update_device(dev);
472 int nr = to_sensor_dev_attr(devattr)->index;
473 int pwm_enable;
474
475 pwm_enable = pwm_enable_from_reg(data->pwm_enable[nr]);
476 if (pwm_enable < 0)
477 return pwm_enable;
478 return sprintf(buf, "%d\n", pwm_enable);
479}
480
481static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
482 *devattr, const char *buf, size_t count)
483{
484 struct pc87427_data *data = dev_get_drvdata(dev);
485 int nr = to_sensor_dev_attr(devattr)->index;
486 unsigned long val;
487
488 if (strict_strtoul(buf, 10, &val) < 0 || val > 2)
489 return -EINVAL;
490 /* Can't go to automatic mode if it isn't configured */
491 if (val == 2 && !(data->pwm_auto_ok & (1 << nr)))
492 return -EINVAL;
493
494 mutex_lock(&data->lock);
495 pc87427_readall_pwm(data, nr);
496 update_pwm_enable(data, nr, pwm_enable_to_reg(val, data->pwm[nr]));
497 mutex_unlock(&data->lock);
498
499 return count;
500}
501
502static ssize_t show_pwm(struct device *dev, struct device_attribute
503 *devattr, char *buf)
504{
505 struct pc87427_data *data = pc87427_update_device(dev);
506 int nr = to_sensor_dev_attr(devattr)->index;
507
508 return sprintf(buf, "%d\n", (int)data->pwm[nr]);
509}
510
511static ssize_t set_pwm(struct device *dev, struct device_attribute
512 *devattr, const char *buf, size_t count)
513{
514 struct pc87427_data *data = dev_get_drvdata(dev);
515 int nr = to_sensor_dev_attr(devattr)->index;
516 unsigned long val;
517 int iobase = data->address[LD_FAN];
518 u8 mode;
519
520 if (strict_strtoul(buf, 10, &val) < 0 || val > 0xff)
521 return -EINVAL;
522
523 mutex_lock(&data->lock);
524 pc87427_readall_pwm(data, nr);
525 mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
526 if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
527 dev_notice(dev, "Can't set PWM%d duty cycle while not in "
528 "manual mode\n", nr + 1);
529 mutex_unlock(&data->lock);
530 return -EPERM;
531 }
532
533 /* We may have to change the mode */
534 if (mode == PWM_MODE_MANUAL && val == 0) {
535 /* Transition from Manual to Off */
536 update_pwm_enable(data, nr, PWM_MODE_OFF);
537 mode = PWM_MODE_OFF;
538 dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1,
539 "manual", "off");
540 } else if (mode == PWM_MODE_OFF && val != 0) {
541 /* Transition from Off to Manual */
542 update_pwm_enable(data, nr, PWM_MODE_MANUAL);
543 mode = PWM_MODE_MANUAL;
544 dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1,
545 "off", "manual");
546 }
547
548 data->pwm[nr] = val;
549 if (mode == PWM_MODE_MANUAL)
550 outb(val, iobase + PC87427_REG_PWM_DUTY);
551 mutex_unlock(&data->lock);
552
553 return count;
554}
555
556static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
557 show_pwm_enable, set_pwm_enable, 0);
558static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
559 show_pwm_enable, set_pwm_enable, 1);
560static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
561 show_pwm_enable, set_pwm_enable, 2);
562static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO,
563 show_pwm_enable, set_pwm_enable, 3);
564
565static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
566static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
567static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
568static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
569
570static struct attribute *pc87427_attributes_pwm[4][3] = {
571 {
572 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
573 &sensor_dev_attr_pwm1.dev_attr.attr,
574 NULL
575 }, {
576 &sensor_dev_attr_pwm2_enable.dev_attr.attr,
577 &sensor_dev_attr_pwm2.dev_attr.attr,
578 NULL
579 }, {
580 &sensor_dev_attr_pwm3_enable.dev_attr.attr,
581 &sensor_dev_attr_pwm3.dev_attr.attr,
582 NULL
583 }, {
584 &sensor_dev_attr_pwm4_enable.dev_attr.attr,
585 &sensor_dev_attr_pwm4.dev_attr.attr,
586 NULL
587 }
588};
589
590static const struct attribute_group pc87427_group_pwm[4] = {
591 { .attrs = pc87427_attributes_pwm[0] },
592 { .attrs = pc87427_attributes_pwm[1] },
593 { .attrs = pc87427_attributes_pwm[2] },
594 { .attrs = pc87427_attributes_pwm[3] },
595};
596
387static ssize_t show_name(struct device *dev, struct device_attribute 597static ssize_t show_name(struct device *dev, struct device_attribute
388 *devattr, char *buf) 598 *devattr, char *buf)
389{ 599{
@@ -431,6 +641,25 @@ static void __devinit pc87427_init_device(struct device *dev)
431 } 641 }
432 data->fan_enabled = sio_data->has_fanin; 642 data->fan_enabled = sio_data->has_fanin;
433 } 643 }
644
645 /* Check which PWM outputs are enabled */
646 for (i = 0; i < 4; i++) {
647 if (!(sio_data->has_fanout & (1 << i))) /* Not wired */
648 continue;
649 reg = pc87427_read8_bank(data, LD_FAN, BANK_FC(i),
650 PC87427_REG_PWM_ENABLE);
651 if (reg & PWM_ENABLE_CTLEN)
652 data->pwm_enabled |= (1 << i);
653
654 /* We don't expose an interface to reconfigure the automatic
655 fan control mode, so only allow to return to this mode if
656 it was originally set. */
657 if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) {
658 dev_dbg(dev, "PWM%d is in automatic control mode\n",
659 i + 1);
660 data->pwm_auto_ok |= (1 << i);
661 }
662 }
434} 663}
435 664
436static int __devinit pc87427_probe(struct platform_device *pdev) 665static int __devinit pc87427_probe(struct platform_device *pdev)
@@ -474,6 +703,14 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
474 if (err) 703 if (err)
475 goto exit_remove_files; 704 goto exit_remove_files;
476 } 705 }
706 for (i = 0; i < 4; i++) {
707 if (!(data->pwm_enabled & (1 << i)))
708 continue;
709 err = sysfs_create_group(&pdev->dev.kobj,
710 &pc87427_group_pwm[i]);
711 if (err)
712 goto exit_remove_files;
713 }
477 714
478 data->hwmon_dev = hwmon_device_register(&pdev->dev); 715 data->hwmon_dev = hwmon_device_register(&pdev->dev);
479 if (IS_ERR(data->hwmon_dev)) { 716 if (IS_ERR(data->hwmon_dev)) {
@@ -490,6 +727,11 @@ exit_remove_files:
490 continue; 727 continue;
491 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); 728 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
492 } 729 }
730 for (i = 0; i < 4; i++) {
731 if (!(data->pwm_enabled & (1 << i)))
732 continue;
733 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
734 }
493exit_release_region: 735exit_release_region:
494 release_region(res->start, resource_size(res)); 736 release_region(res->start, resource_size(res));
495exit_kfree: 737exit_kfree:
@@ -512,6 +754,11 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
512 continue; 754 continue;
513 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); 755 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
514 } 756 }
757 for (i = 0; i < 4; i++) {
758 if (!(data->pwm_enabled & (1 << i)))
759 continue;
760 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
761 }
515 platform_set_drvdata(pdev, NULL); 762 platform_set_drvdata(pdev, NULL);
516 kfree(data); 763 kfree(data);
517 764
@@ -648,6 +895,26 @@ static int __init pc87427_find(int sioaddr, unsigned short *address,
648 if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5))) 895 if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5)))
649 sio_data->has_fanin |= (1 << 6); /* FANIN6 */ 896 sio_data->has_fanin |= (1 << 6); /* FANIN6 */
650 897
898 /* Check which fan outputs are wired */
899 sio_data->has_fanout = (1 << 0); /* FANOUT0 */
900 if (cfg_b & (1 << 0))
901 sio_data->has_fanout |= (1 << 3); /* FANOUT3 */
902
903 cfg = superio_inb(sioaddr, SIOREG_CFC);
904 if (!(cfg & (1 << 4))) {
905 if (cfg_b & (1 << 1))
906 sio_data->has_fanout |= (1 << 1); /* FANOUT1 */
907 if (cfg_b & (1 << 2))
908 sio_data->has_fanout |= (1 << 2); /* FANOUT2 */
909 }
910
911 /* FANOUT1 and FANOUT2 can each be routed to 2 different pins */
912 cfg = superio_inb(sioaddr, SIOREG_CF5);
913 if (cfg & (1 << 6))
914 sio_data->has_fanout |= (1 << 1); /* FANOUT1 */
915 if (cfg & (1 << 5))
916 sio_data->has_fanout |= (1 << 2); /* FANOUT2 */
917
651exit: 918exit:
652 superio_exit(sioaddr); 919 superio_exit(sioaddr);
653 return err; 920 return err;