diff options
author | Michael Walle <michael@walle.cc> | 2016-07-25 05:12:06 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2016-09-09 00:34:14 -0400 |
commit | a95da110cd6f464e7ea413224add0700051fe9ac (patch) | |
tree | 08b0ddfc859c398fa5d179c9be2a363a27545baa /drivers/hwmon/adt7411.c | |
parent | 637ab157d4a94145a6c9b89113222b6c80fab54c (diff) |
hwmon: (adt7411) add external thermal diode support
If the EXT_TDM bit is set, the chip supports a second temperature sensor
instead of two voltage sensors.
Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/adt7411.c')
-rw-r--r-- | drivers/hwmon/adt7411.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index fc1e65a263a4..812fbc00f693 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c | |||
@@ -7,8 +7,7 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * TODO: SPI, support for external temperature sensor | 10 | * TODO: SPI, use power-down mode for suspend?, interrupt handling? |
11 | * use power-down mode for suspend?, interrupt handling? | ||
12 | */ | 11 | */ |
13 | 12 | ||
14 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -31,6 +30,7 @@ | |||
31 | #define ADT7411_REG_CFG1 0x18 | 30 | #define ADT7411_REG_CFG1 0x18 |
32 | #define ADT7411_CFG1_START_MONITOR (1 << 0) | 31 | #define ADT7411_CFG1_START_MONITOR (1 << 0) |
33 | #define ADT7411_CFG1_RESERVED_BIT1 (1 << 1) | 32 | #define ADT7411_CFG1_RESERVED_BIT1 (1 << 1) |
33 | #define ADT7411_CFG1_EXT_TDM (1 << 2) | ||
34 | #define ADT7411_CFG1_RESERVED_BIT3 (1 << 3) | 34 | #define ADT7411_CFG1_RESERVED_BIT3 (1 << 3) |
35 | 35 | ||
36 | #define ADT7411_REG_CFG2 0x19 | 36 | #define ADT7411_REG_CFG2 0x19 |
@@ -57,6 +57,7 @@ struct adt7411_data { | |||
57 | unsigned long next_update; | 57 | unsigned long next_update; |
58 | int vref_cached; | 58 | int vref_cached; |
59 | struct i2c_client *client; | 59 | struct i2c_client *client; |
60 | bool use_ext_temp; | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | /* | 63 | /* |
@@ -127,11 +128,20 @@ static ssize_t adt7411_show_vdd(struct device *dev, | |||
127 | static ssize_t adt7411_show_temp(struct device *dev, | 128 | static ssize_t adt7411_show_temp(struct device *dev, |
128 | struct device_attribute *attr, char *buf) | 129 | struct device_attribute *attr, char *buf) |
129 | { | 130 | { |
131 | int nr = to_sensor_dev_attr(attr)->index; | ||
130 | struct adt7411_data *data = dev_get_drvdata(dev); | 132 | struct adt7411_data *data = dev_get_drvdata(dev); |
131 | struct i2c_client *client = data->client; | 133 | struct i2c_client *client = data->client; |
132 | int val = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB, | 134 | int val; |
133 | ADT7411_REG_INT_TEMP_MSB, 0); | 135 | struct { |
134 | 136 | u8 low; | |
137 | u8 high; | ||
138 | } reg[2] = { | ||
139 | { ADT7411_REG_INT_TEMP_VDD_LSB, ADT7411_REG_INT_TEMP_MSB }, | ||
140 | { ADT7411_REG_EXT_TEMP_AIN14_LSB, | ||
141 | ADT7411_REG_EXT_TEMP_AIN1_MSB }, | ||
142 | }; | ||
143 | |||
144 | val = adt7411_read_10_bit(client, reg[nr].low, reg[nr].high, 0); | ||
135 | if (val < 0) | 145 | if (val < 0) |
136 | return val; | 146 | return val; |
137 | 147 | ||
@@ -218,11 +228,13 @@ static ssize_t adt7411_set_bit(struct device *dev, | |||
218 | return ret < 0 ? ret : count; | 228 | return ret < 0 ? ret : count; |
219 | } | 229 | } |
220 | 230 | ||
231 | |||
221 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ | 232 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ |
222 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ | 233 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ |
223 | adt7411_set_bit, __bit, __reg) | 234 | adt7411_set_bit, __bit, __reg) |
224 | 235 | ||
225 | static DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL); | 236 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL, 0); |
237 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, adt7411_show_temp, NULL, 1); | ||
226 | static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL); | 238 | static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL); |
227 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0); | 239 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0); |
228 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1); | 240 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1); |
@@ -237,7 +249,8 @@ static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_22 | |||
237 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); | 249 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); |
238 | 250 | ||
239 | static struct attribute *adt7411_attrs[] = { | 251 | static struct attribute *adt7411_attrs[] = { |
240 | &dev_attr_temp1_input.attr, | 252 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
253 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
241 | &dev_attr_in0_input.attr, | 254 | &dev_attr_in0_input.attr, |
242 | &sensor_dev_attr_in1_input.dev_attr.attr, | 255 | &sensor_dev_attr_in1_input.dev_attr.attr, |
243 | &sensor_dev_attr_in2_input.dev_attr.attr, | 256 | &sensor_dev_attr_in2_input.dev_attr.attr, |
@@ -253,7 +266,27 @@ static struct attribute *adt7411_attrs[] = { | |||
253 | NULL | 266 | NULL |
254 | }; | 267 | }; |
255 | 268 | ||
256 | ATTRIBUTE_GROUPS(adt7411); | 269 | static umode_t adt7411_attrs_visible(struct kobject *kobj, |
270 | struct attribute *attr, int index) | ||
271 | { | ||
272 | struct device *dev = container_of(kobj, struct device, kobj); | ||
273 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
274 | bool visible = true; | ||
275 | |||
276 | if (attr == &sensor_dev_attr_temp2_input.dev_attr.attr) | ||
277 | visible = data->use_ext_temp; | ||
278 | else if (attr == &sensor_dev_attr_in1_input.dev_attr.attr || | ||
279 | attr == &sensor_dev_attr_in2_input.dev_attr.attr) | ||
280 | visible = !data->use_ext_temp; | ||
281 | |||
282 | return visible ? attr->mode : 0; | ||
283 | } | ||
284 | |||
285 | static const struct attribute_group adt7411_group = { | ||
286 | .attrs = adt7411_attrs, | ||
287 | .is_visible = adt7411_attrs_visible, | ||
288 | }; | ||
289 | __ATTRIBUTE_GROUPS(adt7411); | ||
257 | 290 | ||
258 | static int adt7411_detect(struct i2c_client *client, | 291 | static int adt7411_detect(struct i2c_client *client, |
259 | struct i2c_board_info *info) | 292 | struct i2c_board_info *info) |
@@ -309,6 +342,8 @@ static int adt7411_init_device(struct adt7411_data *data) | |||
309 | if (ret < 0) | 342 | if (ret < 0) |
310 | return ret; | 343 | return ret; |
311 | 344 | ||
345 | data->use_ext_temp = ret & ADT7411_CFG1_EXT_TDM; | ||
346 | |||
312 | /* | 347 | /* |
313 | * We must only write zero to bit 1 and only one to bit 3 according to | 348 | * We must only write zero to bit 1 and only one to bit 3 according to |
314 | * the datasheet. | 349 | * the datasheet. |