Re: [PATCH 5/6] hwmon: (pc87427) Add temperature monitoring support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2010-08-11 at 11:13 -0400, Jean Delvare wrote:
> Add support for the 6 temperature monitoring channels of the PC87427.
> Note that the sensors resolution can vary, and I couldn't find a way
> to figure it out, so we might have to compensate in user-space.
> 
> Signed-off-by: Jean Delvare <khali@xxxxxxxxxxxx>

Acked-by: Guenter Roeck <guenter.roeck@xxxxxxxxxxxx>

One question: You don't sign extend the 16 bit sensor data. Does that
mean negative values will be reported as large positive values, or does
the chip sign extend internally from 8/9 to 16 bit ?

> ---
>  Documentation/hwmon/pc87427 |   14 +
>  drivers/hwmon/Kconfig       |    4
>  drivers/hwmon/pc87427.c     |  368 ++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 379 insertions(+), 7 deletions(-)
> 
> --- linux-2.6.36-rc0.orig/drivers/hwmon/pc87427.c       2010-08-11 16:35:46.000000000 +0200
> +++ linux-2.6.36-rc0/drivers/hwmon/pc87427.c    2010-08-11 16:39:37.000000000 +0200
> @@ -1,7 +1,7 @@
>  /*
>   *  pc87427.c - hardware monitoring driver for the
>   *              National Semiconductor PC87427 Super-I/O chip
> - *  Copyright (C) 2006, 2008  Jean Delvare <khali@xxxxxxxxxxxx>
> + *  Copyright (C) 2006, 2008, 2010  Jean Delvare <khali@xxxxxxxxxxxx>
>   *
>   *  This program is free software; you can redistribute it and/or modify
>   *  it under the terms of the GNU General Public License version 2 as
> @@ -15,10 +15,11 @@
>   *  Supports the following chips:
>   *
>   *  Chip        #vin    #fan    #pwm    #temp   devid
> - *  PC87427     -       8       4       -       0xF2
> + *  PC87427     -       8       4       6       0xF2
>   *
>   *  This driver assumes that no more than one chip is present.
> - *  Only fans are supported so far, although the chip can do much more.
> + *  Only fans are fully supported so far. Temperatures are in read-only
> + *  mode, and voltages aren't supported at all.
>   */
> 
>  #include <linux/module.h>
> @@ -62,6 +63,14 @@ struct pc87427_data {
>         u8 pwm_auto_ok;                 /* bit vector */
>         u8 pwm_enable[4];               /* register values */
>         u8 pwm[4];                      /* register values */
> +
> +       u8 temp_enabled;                /* bit vector */
> +       s16 temp[6];                    /* register values */
> +       s8 temp_min[6];                 /* register values */
> +       s8 temp_max[6];                 /* register values */
> +       s8 temp_crit[6];                /* register values */
> +       u8 temp_status[6];              /* register values */
> +       u8 temp_type[6];                /* register values */
>  };
> 
>  struct pc87427_sio_data {
> @@ -120,6 +129,8 @@ static inline void superio_exit(int sioa
>  #define BANK_FM(nr)            (nr)
>  #define BANK_FT(nr)            (0x08 + (nr))
>  #define BANK_FC(nr)            (0x10 + (nr) * 2)
> +#define BANK_TM(nr)            (nr)
> +#define BANK_VM(nr)            (0x08 + (nr))
> 
>  /*
>   * I/O access functions
> @@ -252,6 +263,72 @@ static inline u8 pwm_enable_to_reg(unsig
>  }
> 
>  /*
> + * Temperature registers and conversions
> + */
> +
> +#define PC87427_REG_TEMP_STATUS                0x10
> +#define PC87427_REG_TEMP               0x14
> +#define PC87427_REG_TEMP_MAX           0x18
> +#define PC87427_REG_TEMP_MIN           0x19
> +#define PC87427_REG_TEMP_CRIT          0x1a
> +#define PC87427_REG_TEMP_TYPE          0x1d
> +
> +#define TEMP_STATUS_CHANEN             (1 << 0)
> +#define TEMP_STATUS_LOWFLG             (1 << 1)
> +#define TEMP_STATUS_HIGHFLG            (1 << 2)
> +#define TEMP_STATUS_CRITFLG            (1 << 3)
> +#define TEMP_STATUS_SENSERR            (1 << 5)
> +#define TEMP_TYPE_MASK                 (3 << 5)
> +
> +#define TEMP_TYPE_THERMISTOR           (1 << 5)
> +#define TEMP_TYPE_REMOTE_DIODE         (2 << 5)
> +#define TEMP_TYPE_LOCAL_DIODE          (3 << 5)
> +
> +/* Dedicated function to read all registers related to a given temperature
> +   input. This saves us quite a few locks and bank selections.
> +   Must be called with data->lock held.
> +   nr is from 0 to 5 */
> +static void pc87427_readall_temp(struct pc87427_data *data, u8 nr)
> +{
> +       int iobase = data->address[LD_TEMP];
> +
> +       outb(BANK_TM(nr), iobase + PC87427_REG_BANK);
> +       data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP));
> +       data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX);
> +       data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN);
> +       data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT);
> +       data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE);
> +       data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS);
> +       /* Clear fan alarm bits */
> +       outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS);
> +}
> +
> +static inline unsigned int temp_type_from_reg(u8 reg)
> +{
> +       switch (reg & TEMP_TYPE_MASK) {
> +       case TEMP_TYPE_THERMISTOR:
> +               return 4;
> +       case TEMP_TYPE_REMOTE_DIODE:
> +       case TEMP_TYPE_LOCAL_DIODE:
> +               return 3;
> +       default:
> +               return 0;
> +       }
> +}
> +
> +/* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible
> +   too, but I have no idea how to figure out when they are used. */
> +static inline long temp_from_reg(s16 reg)
> +{
> +       return reg * 1000 / 256;
> +}
> +
> +static inline long temp_from_reg8(s8 reg)
> +{
> +       return reg * 1000;
> +}
> +
> +/*
>   * Data interface
>   */
> 
> @@ -279,6 +356,13 @@ static struct pc87427_data *pc87427_upda
>                 pc87427_readall_pwm(data, i);
>         }
> 
> +       /* Temperature channels */
> +       for (i = 0; i < 6; i++) {
> +               if (!(data->temp_enabled & (1 << i)))
> +                       continue;
> +               pc87427_readall_temp(data, i);
> +       }
> +
>         data->last_updated = jiffies;
> 
>  done:
> @@ -595,6 +679,251 @@ static const struct attribute_group pc87
>         { .attrs = pc87427_attributes_pwm[3] },
>  };
> 
> +static ssize_t show_temp_input(struct device *dev, struct device_attribute
> +                              *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr]));
> +}
> +
> +static ssize_t show_temp_min(struct device *dev, struct device_attribute
> +                            *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr]));
> +}
> +
> +static ssize_t show_temp_max(struct device *dev, struct device_attribute
> +                            *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr]));
> +}
> +
> +static ssize_t show_temp_crit(struct device *dev, struct device_attribute
> +                             *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr]));
> +}
> +
> +static ssize_t show_temp_type(struct device *dev, struct device_attribute
> +                             *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr]));
> +}
> +
> +static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute
> +                                  *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%d\n", !!(data->temp_status[nr]
> +                                      & TEMP_STATUS_LOWFLG));
> +}
> +
> +static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute
> +                                  *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%d\n", !!(data->temp_status[nr]
> +                                      & TEMP_STATUS_HIGHFLG));
> +}
> +
> +static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute
> +                                  *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%d\n", !!(data->temp_status[nr]
> +                                      & TEMP_STATUS_CRITFLG));
> +}
> +
> +static ssize_t show_temp_fault(struct device *dev, struct device_attribute
> +                              *devattr, char *buf)
> +{
> +       struct pc87427_data *data = pc87427_update_device(dev);
> +       int nr = to_sensor_dev_attr(devattr)->index;
> +
> +       return sprintf(buf, "%d\n", !!(data->temp_status[nr]
> +                                      & TEMP_STATUS_SENSERR));
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO,
> +                         show_temp_min_alarm, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO,
> +                         show_temp_max_alarm, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO,
> +                         show_temp_crit_alarm, NULL, 5);
> +
> +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
> +
> +static struct attribute *pc87427_attributes_temp[6][10] = {
> +       {
> +               &sensor_dev_attr_temp1_input.dev_attr.attr,
> +               &sensor_dev_attr_temp1_min.dev_attr.attr,
> +               &sensor_dev_attr_temp1_max.dev_attr.attr,
> +               &sensor_dev_attr_temp1_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp1_type.dev_attr.attr,
> +               &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp1_fault.dev_attr.attr,
> +               NULL
> +       }, {
> +               &sensor_dev_attr_temp2_input.dev_attr.attr,
> +               &sensor_dev_attr_temp2_min.dev_attr.attr,
> +               &sensor_dev_attr_temp2_max.dev_attr.attr,
> +               &sensor_dev_attr_temp2_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp2_type.dev_attr.attr,
> +               &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp2_fault.dev_attr.attr,
> +               NULL
> +       }, {
> +               &sensor_dev_attr_temp3_input.dev_attr.attr,
> +               &sensor_dev_attr_temp3_min.dev_attr.attr,
> +               &sensor_dev_attr_temp3_max.dev_attr.attr,
> +               &sensor_dev_attr_temp3_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp3_type.dev_attr.attr,
> +               &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp3_fault.dev_attr.attr,
> +               NULL
> +       }, {
> +               &sensor_dev_attr_temp4_input.dev_attr.attr,
> +               &sensor_dev_attr_temp4_min.dev_attr.attr,
> +               &sensor_dev_attr_temp4_max.dev_attr.attr,
> +               &sensor_dev_attr_temp4_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp4_type.dev_attr.attr,
> +               &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp4_fault.dev_attr.attr,
> +               NULL
> +       }, {
> +               &sensor_dev_attr_temp5_input.dev_attr.attr,
> +               &sensor_dev_attr_temp5_min.dev_attr.attr,
> +               &sensor_dev_attr_temp5_max.dev_attr.attr,
> +               &sensor_dev_attr_temp5_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp5_type.dev_attr.attr,
> +               &sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp5_fault.dev_attr.attr,
> +               NULL
> +       }, {
> +               &sensor_dev_attr_temp6_input.dev_attr.attr,
> +               &sensor_dev_attr_temp6_min.dev_attr.attr,
> +               &sensor_dev_attr_temp6_max.dev_attr.attr,
> +               &sensor_dev_attr_temp6_crit.dev_attr.attr,
> +               &sensor_dev_attr_temp6_type.dev_attr.attr,
> +               &sensor_dev_attr_temp6_min_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
> +               &sensor_dev_attr_temp6_fault.dev_attr.attr,
> +               NULL
> +       }
> +};
> +
> +static const struct attribute_group pc87427_group_temp[6] = {
> +       { .attrs = pc87427_attributes_temp[0] },
> +       { .attrs = pc87427_attributes_temp[1] },
> +       { .attrs = pc87427_attributes_temp[2] },
> +       { .attrs = pc87427_attributes_temp[3] },
> +       { .attrs = pc87427_attributes_temp[4] },
> +       { .attrs = pc87427_attributes_temp[5] },
> +};
> +
>  static ssize_t show_name(struct device *dev, struct device_attribute
>                          *devattr, char *buf)
>  {
> @@ -659,7 +988,7 @@ static void __devinit pc87427_init_devic
>         /* The FMC module should be ready */
>         reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);
>         if (!(reg & 0x80))
> -               dev_warn(dev, "FMC module not ready!\n");
> +               dev_warn(dev, "%s module not ready!\n", "FMC");
> 
>         /* Check which fans are enabled */
>         for (i = 0; i < 8; i++) {
> @@ -701,6 +1030,19 @@ static void __devinit pc87427_init_devic
>                         data->pwm_auto_ok |= (1 << i);
>                 }
>         }
> +
> +       /* The HMC module should be ready */
> +       reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK);
> +       if (!(reg & 0x80))
> +               dev_warn(dev, "%s module not ready!\n", "HMC");
> +
> +       /* Check which temperature channels are enabled */
> +       for (i = 0; i < 6; i++) {
> +               reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i),
> +                                        PC87427_REG_TEMP_STATUS);
> +               if (reg & TEMP_STATUS_CHANEN)
> +                       data->temp_enabled |= (1 << i);
> +       }
>  }
> 
>  static int __devinit pc87427_probe(struct platform_device *pdev)
> @@ -749,6 +1091,14 @@ static int __devinit pc87427_probe(struc
>                 if (err)
>                         goto exit_remove_files;
>         }
> +       for (i = 0; i < 6; i++) {
> +               if (!(data->temp_enabled & (1 << i)))
> +                       continue;
> +               err = sysfs_create_group(&pdev->dev.kobj,
> +                                        &pc87427_group_temp[i]);
> +               if (err)
> +                       goto exit_remove_files;
> +       }
> 
>         data->hwmon_dev = hwmon_device_register(&pdev->dev);
>         if (IS_ERR(data->hwmon_dev)) {
> @@ -770,6 +1120,11 @@ exit_remove_files:
>                         continue;
>                 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
>         }
> +       for (i = 0; i < 6; i++) {
> +               if (!(data->temp_enabled & (1 << i)))
> +                       continue;
> +               sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]);
> +       }
>  exit_release_region:
>         pc87427_release_regions(pdev, res_count);
>  exit_kfree:
> @@ -798,6 +1153,11 @@ static int __devexit pc87427_remove(stru
>                         continue;
>                 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
>         }
> +       for (i = 0; i < 6; i++) {
> +               if (!(data->temp_enabled & (1 << i)))
> +                       continue;
> +               sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]);
> +       }
>         platform_set_drvdata(pdev, NULL);
>         kfree(data);
> 
> --- linux-2.6.36-rc0.orig/drivers/hwmon/Kconfig 2010-08-11 16:27:12.000000000 +0200
> +++ linux-2.6.36-rc0/drivers/hwmon/Kconfig      2010-08-11 16:39:37.000000000 +0200
> @@ -711,8 +711,8 @@ config SENSORS_PC87427
>           functions of the National Semiconductor PC87427 Super-I/O chip.
>           The chip has two distinct logical devices, one for fan speed
>           monitoring and control, and one for voltage and temperature
> -         monitoring. Only fan speed monitoring and control is supported
> -         right now.
> +         monitoring. Fan speed monitoring and control are supported, as
> +         well as temperature monitoring. Voltages aren't supported yet.
> 
>           This driver can also be built as a module.  If so, the module
>           will be called pc87427.
> --- linux-2.6.36-rc0.orig/Documentation/hwmon/pc87427   2010-08-11 16:27:12.000000000 +0200
> +++ linux-2.6.36-rc0/Documentation/hwmon/pc87427        2010-08-11 16:39:37.000000000 +0200
> @@ -18,7 +18,8 @@ Description
> 
>  The National Semiconductor Super I/O chip includes complete hardware
>  monitoring capabilities. It can monitor up to 18 voltages, 8 fans and
> -6 temperature sensors. Only the fans are supported at the moment.
> +6 temperature sensors. Only the fans and temperatures are supported at
> +the moment, voltages aren't.
> 
>  This chip also has fan controlling features (up to 4 PWM outputs),
>  which are partly supported by this driver.
> @@ -45,3 +46,14 @@ Fan speed can be controlled by PWM outpu
>  always off, always on, manual and automatic. The latter isn't supported
>  by the driver: you can only return to that mode if it was the original
>  setting, and the configuration interface is missing.
> +
> +
> +Temperature Monitoring
> +----------------------
> +
> +The PC87427 relies on external sensors (following the SensorPath
> +standard), so the resolution and range depend on the type of sensor
> +connected. The integer part can be 8-bit or 9-bit, and can be signed or
> +not. I couldn't find a way to figure out the external sensor data
> +temperature format, so user-space adjustment (typically by a factor 2)
> +may be required.
> 
> --
> Jean Delvare
> 
> _______________________________________________
> lm-sensors mailing list
> lm-sensors@xxxxxxxxxxxxxx
> http://lists.lm-sensors.org/mailman/listinfo/lm-sensors



_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux