diff options
author | Jean Delvare <khali@linux-fr.org> | 2010-10-28 14:31:46 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2010-10-28 14:31:46 -0400 |
commit | 0e256018b0f35d1b22ca37e1d0e207f7ba3d0076 (patch) | |
tree | 029db8e2bd87afb27c9d4211ff724958bade47b4 /drivers/hwmon/w83795.c | |
parent | 6c82b2f3fb31e43a9b898769afd2151ca64986a4 (diff) |
hwmon: (w83795) Add support for dynamic in0-2 limits
The W83795G can be configured to set the in0, in1 and/or in2 voltage
limits dynamically based on VID input pins. Switch the respective
sysfs attributes to read-only.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/w83795.c')
-rw-r--r-- | drivers/hwmon/w83795.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 24e44245e548..458fb297f696 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c | |||
@@ -316,6 +316,7 @@ struct w83795_data { | |||
316 | u8 bank; | 316 | u8 bank; |
317 | 317 | ||
318 | u32 has_in; /* Enable monitor VIN or not */ | 318 | u32 has_in; /* Enable monitor VIN or not */ |
319 | u8 has_dyn_in; /* Only in2-0 can have this */ | ||
319 | u16 in[21][3]; /* Register value, read/high/low */ | 320 | u16 in[21][3]; /* Register value, read/high/low */ |
320 | u8 in_lsb[10][3]; /* LSB Register value, high/low */ | 321 | u8 in_lsb[10][3]; /* LSB Register value, high/low */ |
321 | u8 has_gain; /* has gain: in17-20 * 8 */ | 322 | u8 has_gain; /* has gain: in17-20 * 8 */ |
@@ -450,6 +451,23 @@ static struct w83795_data *w83795_update_device(struct device *dev) | |||
450 | data->in[i][IN_READ] = tmp; | 451 | data->in[i][IN_READ] = tmp; |
451 | } | 452 | } |
452 | 453 | ||
454 | /* in0-2 can have dynamic limits (W83795G only) */ | ||
455 | if (data->has_dyn_in) { | ||
456 | u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); | ||
457 | u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); | ||
458 | |||
459 | for (i = 0; i < 3; i++) { | ||
460 | if (!(data->has_dyn_in & (1 << i))) | ||
461 | continue; | ||
462 | data->in[i][IN_MAX] = | ||
463 | w83795_read(client, W83795_REG_IN[i][IN_MAX]); | ||
464 | data->in[i][IN_LOW] = | ||
465 | w83795_read(client, W83795_REG_IN[i][IN_LOW]); | ||
466 | data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; | ||
467 | data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; | ||
468 | } | ||
469 | } | ||
470 | |||
453 | /* Update fan */ | 471 | /* Update fan */ |
454 | for (i = 0; i < ARRAY_SIZE(data->fan); i++) { | 472 | for (i = 0; i < ARRAY_SIZE(data->fan); i++) { |
455 | if (!(data->has_fan & (1 << i))) | 473 | if (!(data->has_fan & (1 << i))) |
@@ -1450,6 +1468,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, | |||
1450 | 1468 | ||
1451 | #define NOT_USED -1 | 1469 | #define NOT_USED -1 |
1452 | 1470 | ||
1471 | /* Don't change the attribute order, _max and _min are accessed by index | ||
1472 | * somewhere else in the code */ | ||
1453 | #define SENSOR_ATTR_IN(index) { \ | 1473 | #define SENSOR_ATTR_IN(index) { \ |
1454 | SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ | 1474 | SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ |
1455 | IN_READ, index), \ | 1475 | IN_READ, index), \ |
@@ -1844,6 +1864,39 @@ static int device_remove_file_wrapper(struct device *dev, | |||
1844 | return 0; | 1864 | return 0; |
1845 | } | 1865 | } |
1846 | 1866 | ||
1867 | static void w83795_check_dynamic_in_limits(struct i2c_client *client) | ||
1868 | { | ||
1869 | struct w83795_data *data = i2c_get_clientdata(client); | ||
1870 | u8 vid_ctl; | ||
1871 | int i, err_max, err_min; | ||
1872 | |||
1873 | vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); | ||
1874 | |||
1875 | /* Return immediately if VRM isn't configured */ | ||
1876 | if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) | ||
1877 | return; | ||
1878 | |||
1879 | data->has_dyn_in = (vid_ctl >> 3) & 0x07; | ||
1880 | for (i = 0; i < 2; i++) { | ||
1881 | if (!(data->has_dyn_in & (1 << i))) | ||
1882 | continue; | ||
1883 | |||
1884 | /* Voltage limits in dynamic mode, switch to read-only */ | ||
1885 | err_max = sysfs_chmod_file(&client->dev.kobj, | ||
1886 | &w83795_in[i][2].dev_attr.attr, | ||
1887 | S_IRUGO); | ||
1888 | err_min = sysfs_chmod_file(&client->dev.kobj, | ||
1889 | &w83795_in[i][3].dev_attr.attr, | ||
1890 | S_IRUGO); | ||
1891 | if (err_max || err_min) | ||
1892 | dev_warn(&client->dev, "Failed to set in%d limits " | ||
1893 | "read-only (%d, %d)\n", i, err_max, err_min); | ||
1894 | else | ||
1895 | dev_info(&client->dev, "in%d limits set dynamically " | ||
1896 | "from VID\n", i); | ||
1897 | } | ||
1898 | } | ||
1899 | |||
1847 | /* Check pins that can be used for either temperature or voltage monitoring */ | 1900 | /* Check pins that can be used for either temperature or voltage monitoring */ |
1848 | static void w83795_apply_temp_config(struct w83795_data *data, u8 config, | 1901 | static void w83795_apply_temp_config(struct w83795_data *data, u8 config, |
1849 | int temp_chan, int in_chan) | 1902 | int temp_chan, int in_chan) |
@@ -2049,6 +2102,9 @@ static int w83795_probe(struct i2c_client *client, | |||
2049 | if (err) | 2102 | if (err) |
2050 | goto exit_remove; | 2103 | goto exit_remove; |
2051 | 2104 | ||
2105 | if (data->chip_type == w83795g) | ||
2106 | w83795_check_dynamic_in_limits(client); | ||
2107 | |||
2052 | data->hwmon_dev = hwmon_device_register(dev); | 2108 | data->hwmon_dev = hwmon_device_register(dev); |
2053 | if (IS_ERR(data->hwmon_dev)) { | 2109 | if (IS_ERR(data->hwmon_dev)) { |
2054 | err = PTR_ERR(data->hwmon_dev); | 2110 | err = PTR_ERR(data->hwmon_dev); |