Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / drivers / hwmon / f71882fg.c
index ca07a32..a4a94a0 100644 (file)
@@ -48,6 +48,7 @@
 
 #define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
 #define SIO_F71808E_ID         0x0901  /* Chipset ID */
+#define SIO_F71808A_ID         0x1001  /* Chipset ID */
 #define SIO_F71858_ID          0x0507  /* Chipset ID */
 #define SIO_F71862_ID          0x0601  /* Chipset ID */
 #define SIO_F71869_ID          0x0814  /* Chipset ID */
@@ -107,11 +108,12 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
             f71889ed, f71889a, f8000, f81865f };
 
 static const char *f71882fg_names[] = {
        "f71808e",
+       "f71808a",
        "f71858fg",
        "f71862fg",
        "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
@@ -125,6 +127,7 @@ static const char *f71882fg_names[] = {
 
 static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
        [f71808e]       = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+       [f71808a]       = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
        [f71858fg]      = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
        [f71862fg]      = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        [f71869]        = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@@ -138,6 +141,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
 
 static const char f71882fg_has_in1_alarm[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 0,
        [f71869]        = 0,
@@ -149,8 +153,9 @@ static const char f71882fg_has_in1_alarm[] = {
        [f81865f]       = 1,
 };
 
-static const char f71882fg_has_beep[] = {
+static const char f71882fg_fan_has_beep[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 1,
        [f71869]        = 1,
@@ -164,6 +169,7 @@ static const char f71882fg_has_beep[] = {
 
 static const char f71882fg_nr_fans[] = {
        [f71808e]       = 3,
+       [f71808a]       = 2, /* +1 fan which is monitor + simple pwm only */
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -171,12 +177,27 @@ static const char f71882fg_nr_fans[] = {
        [f71889fg]      = 3,
        [f71889ed]      = 3,
        [f71889a]       = 3,
-       [f8000]         = 3,
+       [f8000]         = 3, /* +1 fan which is monitor only */
        [f81865f]       = 2,
 };
 
+static const char f71882fg_temp_has_beep[] = {
+       [f71808e]       = 0,
+       [f71808a]       = 1,
+       [f71858fg]      = 0,
+       [f71862fg]      = 1,
+       [f71869]        = 1,
+       [f71882fg]      = 1,
+       [f71889fg]      = 1,
+       [f71889ed]      = 1,
+       [f71889a]       = 1,
+       [f8000]         = 0,
+       [f81865f]       = 1,
+};
+
 static const char f71882fg_nr_temps[] = {
        [f71808e]       = 2,
+       [f71808a]       = 2,
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -301,6 +322,10 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
        char *buf);
 static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
        const char *buf, size_t count);
+static ssize_t show_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, char *buf);
+static ssize_t store_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count);
 static ssize_t show_pwm_enable(struct device *dev,
        struct device_attribute *devattr, char *buf);
 static ssize_t store_pwm_enable(struct device *dev,
@@ -550,6 +575,14 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
                      show_pwm_interpolate, store_pwm_interpolate, 0, 3),
 } };
 
+/* Attr for the third fan of the f71808a, which only has manual pwm */
+static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
+       SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+       SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
+                     show_simple_pwm, store_simple_pwm, 0, 2),
+};
+
 /* Attr for models which can beep on Fan alarm */
 static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
        SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
@@ -1146,12 +1179,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->temp_type[3] = (reg & 0x08) ? 2 : 4;
                }
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type])
                        data->fan_beep = f71882fg_read8(data,
                                                F71882FG_REG_FAN_BEEP);
+
+               if (f71882fg_temp_has_beep[data->type])
                        data->temp_beep = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_BEEP);
-               }
 
                data->pwm_enable = f71882fg_read8(data,
                                                  F71882FG_REG_PWM_ENABLE);
@@ -1232,7 +1266,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->pwm[nr] =
                            f71882fg_read8(data, F71882FG_REG_PWM(nr));
                }
-               /* The f8000 can monitor 1 more fan, but has no pwm for it */
+               /* Some models have 1 more fan with limited capabilities */
+               if (data->type == f71808a) {
+                       data->fan[2] = f71882fg_read16(data,
+                                               F71882FG_REG_FAN(2));
+                       data->pwm[2] = f71882fg_read8(data,
+                                                       F71882FG_REG_PWM(2));
+               }
                if (data->type == f8000)
                        data->fan[3] = f71882fg_read16(data,
                                                F71882FG_REG_FAN(3));
@@ -1722,6 +1762,38 @@ leave:
        return count;
 }
 
+static ssize_t show_simple_pwm(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int val, nr = to_sensor_dev_attr_2(devattr)->index;
+
+       val = data->pwm[nr];
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_simple_pwm(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val = SENSORS_LIMIT(val, 0, 255);
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+       data->pwm[nr] = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static ssize_t show_pwm_enable(struct device *dev,
                               struct device_attribute *devattr, char *buf)
 {
@@ -2140,7 +2212,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        &fxxxx_temp_beep_attr[0][0],
                                        ARRAY_SIZE(fxxxx_temp_beep_attr[0])
@@ -2169,6 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        if (start_reg & 0x02) {
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                        /* These always have signed auto point temps */
                        data->auto_point_temp_signed = 1;
@@ -2221,7 +2294,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                        if (err)
@@ -2230,6 +2303,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                case f71889fg:
                case f71889ed:
@@ -2255,6 +2329,16 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                }
 
                switch (data->type) {
+               case f71808a:
+                       err = f71882fg_create_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       if (err)
+                               goto exit_unregister_sysfs;
+                       err = f71882fg_create_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2343,7 +2427,7 @@ static int f71882fg_remove(struct platform_device *pdev)
                                &fxxxx_temp_attr[0][0],
                                ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
                }
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                               &fxxxx_temp_beep_attr[0][0],
                               ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
@@ -2366,12 +2450,20 @@ static int f71882fg_remove(struct platform_device *pdev)
                f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
                                ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                }
 
                switch (data->type) {
+               case f71808a:
+                       f71882fg_remove_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       f71882fg_remove_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        f71882fg_remove_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2424,6 +2516,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        case SIO_F71808E_ID:
                sio_data->type = f71808e;
                break;
+       case SIO_F71808A_ID:
+               sio_data->type = f71808a;
+               break;
        case SIO_F71858_ID:
                sio_data->type = f71858fg;
                break;