diff options
author | Michael Walle <michael@walle.cc> | 2016-10-14 05:43:34 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2016-12-02 16:28:15 -0500 |
commit | 1b109c49b72dc3cb8392bbc22bad662f71b8fd80 (patch) | |
tree | 95ee985bdf0f911c8ad361710a9c7ebd11758d7a | |
parent | 3d7e0a24947c076a6cf6080c5f076c60ae8d9543 (diff) |
hwmon: (adt7411) update to new hwmon registration API
This is also a preparation for to support more properties like min, max and
alarm.
Signed-off-by: Michael Walle <michael@walle.cc>
[groeck: Minor alignment changes]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/adt7411.c | 301 |
1 files changed, 180 insertions, 121 deletions
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 812fbc00f693..bdeaece9641d 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c | |||
@@ -55,7 +55,7 @@ struct adt7411_data { | |||
55 | struct mutex device_lock; /* for "atomic" device accesses */ | 55 | struct mutex device_lock; /* for "atomic" device accesses */ |
56 | struct mutex update_lock; | 56 | struct mutex update_lock; |
57 | unsigned long next_update; | 57 | unsigned long next_update; |
58 | int vref_cached; | 58 | long vref_cached; |
59 | struct i2c_client *client; | 59 | struct i2c_client *client; |
60 | bool use_ext_temp; | 60 | bool use_ext_temp; |
61 | }; | 61 | }; |
@@ -114,85 +114,6 @@ static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit, | |||
114 | return ret; | 114 | return ret; |
115 | } | 115 | } |
116 | 116 | ||
117 | static ssize_t adt7411_show_vdd(struct device *dev, | ||
118 | struct device_attribute *attr, char *buf) | ||
119 | { | ||
120 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
121 | struct i2c_client *client = data->client; | ||
122 | int ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB, | ||
123 | ADT7411_REG_VDD_MSB, 2); | ||
124 | |||
125 | return ret < 0 ? ret : sprintf(buf, "%u\n", ret * 7000 / 1024); | ||
126 | } | ||
127 | |||
128 | static ssize_t adt7411_show_temp(struct device *dev, | ||
129 | struct device_attribute *attr, char *buf) | ||
130 | { | ||
131 | int nr = to_sensor_dev_attr(attr)->index; | ||
132 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
133 | struct i2c_client *client = data->client; | ||
134 | int val; | ||
135 | struct { | ||
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); | ||
145 | if (val < 0) | ||
146 | return val; | ||
147 | |||
148 | val = val & 0x200 ? val - 0x400 : val; /* 10 bit signed */ | ||
149 | |||
150 | return sprintf(buf, "%d\n", val * 250); | ||
151 | } | ||
152 | |||
153 | static ssize_t adt7411_show_input(struct device *dev, | ||
154 | struct device_attribute *attr, char *buf) | ||
155 | { | ||
156 | int nr = to_sensor_dev_attr(attr)->index; | ||
157 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
158 | struct i2c_client *client = data->client; | ||
159 | int val; | ||
160 | u8 lsb_reg, lsb_shift; | ||
161 | |||
162 | mutex_lock(&data->update_lock); | ||
163 | if (time_after_eq(jiffies, data->next_update)) { | ||
164 | val = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); | ||
165 | if (val < 0) | ||
166 | goto exit_unlock; | ||
167 | |||
168 | if (val & ADT7411_CFG3_REF_VDD) { | ||
169 | val = adt7411_read_10_bit(client, | ||
170 | ADT7411_REG_INT_TEMP_VDD_LSB, | ||
171 | ADT7411_REG_VDD_MSB, 2); | ||
172 | if (val < 0) | ||
173 | goto exit_unlock; | ||
174 | |||
175 | data->vref_cached = val * 7000 / 1024; | ||
176 | } else { | ||
177 | data->vref_cached = 2250; | ||
178 | } | ||
179 | |||
180 | data->next_update = jiffies + HZ; | ||
181 | } | ||
182 | |||
183 | lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2); | ||
184 | lsb_shift = 2 * (nr & 0x03); | ||
185 | val = adt7411_read_10_bit(client, lsb_reg, | ||
186 | ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, lsb_shift); | ||
187 | if (val < 0) | ||
188 | goto exit_unlock; | ||
189 | |||
190 | val = sprintf(buf, "%u\n", val * data->vref_cached / 1024); | ||
191 | exit_unlock: | ||
192 | mutex_unlock(&data->update_lock); | ||
193 | return val; | ||
194 | } | ||
195 | |||
196 | static ssize_t adt7411_show_bit(struct device *dev, | 117 | static ssize_t adt7411_show_bit(struct device *dev, |
197 | struct device_attribute *attr, char *buf) | 118 | struct device_attribute *attr, char *buf) |
198 | { | 119 | { |
@@ -228,65 +149,157 @@ static ssize_t adt7411_set_bit(struct device *dev, | |||
228 | return ret < 0 ? ret : count; | 149 | return ret < 0 ? ret : count; |
229 | } | 150 | } |
230 | 151 | ||
231 | |||
232 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ | 152 | #define ADT7411_BIT_ATTR(__name, __reg, __bit) \ |
233 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ | 153 | SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \ |
234 | adt7411_set_bit, __bit, __reg) | 154 | adt7411_set_bit, __bit, __reg) |
235 | 155 | ||
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); | ||
238 | static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL); | ||
239 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0); | ||
240 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1); | ||
241 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, adt7411_show_input, NULL, 2); | ||
242 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, adt7411_show_input, NULL, 3); | ||
243 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, adt7411_show_input, NULL, 4); | ||
244 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, adt7411_show_input, NULL, 5); | ||
245 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, adt7411_show_input, NULL, 6); | ||
246 | static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, adt7411_show_input, NULL, 7); | ||
247 | static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG); | 156 | static ADT7411_BIT_ATTR(no_average, ADT7411_REG_CFG2, ADT7411_CFG2_DISABLE_AVG); |
248 | static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225); | 157 | static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_225); |
249 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); | 158 | static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD); |
250 | 159 | ||
251 | static struct attribute *adt7411_attrs[] = { | 160 | static struct attribute *adt7411_attrs[] = { |
252 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
253 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
254 | &dev_attr_in0_input.attr, | ||
255 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
256 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
257 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
258 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
259 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
260 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
261 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
262 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
263 | &sensor_dev_attr_no_average.dev_attr.attr, | 161 | &sensor_dev_attr_no_average.dev_attr.attr, |
264 | &sensor_dev_attr_fast_sampling.dev_attr.attr, | 162 | &sensor_dev_attr_fast_sampling.dev_attr.attr, |
265 | &sensor_dev_attr_adc_ref_vdd.dev_attr.attr, | 163 | &sensor_dev_attr_adc_ref_vdd.dev_attr.attr, |
266 | NULL | 164 | NULL |
267 | }; | 165 | }; |
166 | ATTRIBUTE_GROUPS(adt7411); | ||
268 | 167 | ||
269 | static umode_t adt7411_attrs_visible(struct kobject *kobj, | 168 | static int adt7411_read_in_vdd(struct device *dev, u32 attr, long *val) |
270 | struct attribute *attr, int index) | ||
271 | { | 169 | { |
272 | struct device *dev = container_of(kobj, struct device, kobj); | ||
273 | struct adt7411_data *data = dev_get_drvdata(dev); | 170 | struct adt7411_data *data = dev_get_drvdata(dev); |
274 | bool visible = true; | 171 | struct i2c_client *client = data->client; |
172 | int ret; | ||
275 | 173 | ||
276 | if (attr == &sensor_dev_attr_temp2_input.dev_attr.attr) | 174 | switch (attr) { |
277 | visible = data->use_ext_temp; | 175 | case hwmon_in_input: |
278 | else if (attr == &sensor_dev_attr_in1_input.dev_attr.attr || | 176 | ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB, |
279 | attr == &sensor_dev_attr_in2_input.dev_attr.attr) | 177 | ADT7411_REG_VDD_MSB, 2); |
280 | visible = !data->use_ext_temp; | 178 | if (ret < 0) |
179 | return ret; | ||
180 | *val = ret * 7000 / 1024; | ||
181 | return 0; | ||
182 | default: | ||
183 | return -EOPNOTSUPP; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, | ||
188 | long *val) | ||
189 | { | ||
190 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
191 | struct i2c_client *client = data->client; | ||
281 | 192 | ||
282 | return visible ? attr->mode : 0; | 193 | int ret; |
194 | int lsb_reg, lsb_shift; | ||
195 | int nr = channel - 1; | ||
196 | |||
197 | mutex_lock(&data->update_lock); | ||
198 | if (time_after_eq(jiffies, data->next_update)) { | ||
199 | ret = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); | ||
200 | if (ret < 0) | ||
201 | goto exit_unlock; | ||
202 | |||
203 | if (ret & ADT7411_CFG3_REF_VDD) { | ||
204 | ret = adt7411_read_in_vdd(dev, hwmon_in_input, | ||
205 | &data->vref_cached); | ||
206 | if (ret < 0) | ||
207 | goto exit_unlock; | ||
208 | } else { | ||
209 | data->vref_cached = 2250; | ||
210 | } | ||
211 | |||
212 | data->next_update = jiffies + HZ; | ||
213 | } | ||
214 | |||
215 | switch (attr) { | ||
216 | case hwmon_in_input: | ||
217 | lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2); | ||
218 | lsb_shift = 2 * (nr & 0x03); | ||
219 | ret = adt7411_read_10_bit(client, lsb_reg, | ||
220 | ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, | ||
221 | lsb_shift); | ||
222 | if (ret < 0) | ||
223 | goto exit_unlock; | ||
224 | *val = ret * data->vref_cached / 1024; | ||
225 | ret = 0; | ||
226 | break; | ||
227 | default: | ||
228 | ret = -EOPNOTSUPP; | ||
229 | break; | ||
230 | } | ||
231 | exit_unlock: | ||
232 | mutex_unlock(&data->update_lock); | ||
233 | return ret; | ||
283 | } | 234 | } |
284 | 235 | ||
285 | static const struct attribute_group adt7411_group = { | 236 | static int adt7411_read_in(struct device *dev, u32 attr, int channel, |
286 | .attrs = adt7411_attrs, | 237 | long *val) |
287 | .is_visible = adt7411_attrs_visible, | 238 | { |
288 | }; | 239 | if (channel == 0) |
289 | __ATTRIBUTE_GROUPS(adt7411); | 240 | return adt7411_read_in_vdd(dev, attr, val); |
241 | else | ||
242 | return adt7411_read_in_chan(dev, attr, channel, val); | ||
243 | } | ||
244 | |||
245 | static int adt7411_read_temp(struct device *dev, u32 attr, int channel, | ||
246 | long *val) | ||
247 | { | ||
248 | struct adt7411_data *data = dev_get_drvdata(dev); | ||
249 | struct i2c_client *client = data->client; | ||
250 | int ret, regl, regh; | ||
251 | |||
252 | switch (attr) { | ||
253 | case hwmon_temp_input: | ||
254 | regl = channel ? ADT7411_REG_EXT_TEMP_AIN14_LSB : | ||
255 | ADT7411_REG_INT_TEMP_VDD_LSB; | ||
256 | regh = channel ? ADT7411_REG_EXT_TEMP_AIN1_MSB : | ||
257 | ADT7411_REG_INT_TEMP_MSB; | ||
258 | ret = adt7411_read_10_bit(client, regl, regh, 0); | ||
259 | if (ret < 0) | ||
260 | return ret; | ||
261 | ret = ret & 0x200 ? ret - 0x400 : ret; /* 10 bit signed */ | ||
262 | *val = ret * 250; | ||
263 | return 0; | ||
264 | default: | ||
265 | return -EOPNOTSUPP; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static int adt7411_read(struct device *dev, enum hwmon_sensor_types type, | ||
270 | u32 attr, int channel, long *val) | ||
271 | { | ||
272 | switch (type) { | ||
273 | case hwmon_in: | ||
274 | return adt7411_read_in(dev, attr, channel, val); | ||
275 | case hwmon_temp: | ||
276 | return adt7411_read_temp(dev, attr, channel, val); | ||
277 | default: | ||
278 | return -EOPNOTSUPP; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static umode_t adt7411_is_visible(const void *_data, | ||
283 | enum hwmon_sensor_types type, | ||
284 | u32 attr, int channel) | ||
285 | { | ||
286 | const struct adt7411_data *data = _data; | ||
287 | |||
288 | switch (type) { | ||
289 | case hwmon_in: | ||
290 | if (channel > 0 && channel < 3) | ||
291 | return data->use_ext_temp ? 0 : S_IRUGO; | ||
292 | else | ||
293 | return S_IRUGO; | ||
294 | case hwmon_temp: | ||
295 | if (channel == 1) | ||
296 | return data->use_ext_temp ? S_IRUGO : 0; | ||
297 | else | ||
298 | return S_IRUGO; | ||
299 | default: | ||
300 | return 0; | ||
301 | } | ||
302 | } | ||
290 | 303 | ||
291 | static int adt7411_detect(struct i2c_client *client, | 304 | static int adt7411_detect(struct i2c_client *client, |
292 | struct i2c_board_info *info) | 305 | struct i2c_board_info *info) |
@@ -358,6 +371,51 @@ static int adt7411_init_device(struct adt7411_data *data) | |||
358 | return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val); | 371 | return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val); |
359 | } | 372 | } |
360 | 373 | ||
374 | static const u32 adt7411_in_config[] = { | ||
375 | HWMON_I_INPUT, | ||
376 | HWMON_I_INPUT, | ||
377 | HWMON_I_INPUT, | ||
378 | HWMON_I_INPUT, | ||
379 | HWMON_I_INPUT, | ||
380 | HWMON_I_INPUT, | ||
381 | HWMON_I_INPUT, | ||
382 | HWMON_I_INPUT, | ||
383 | HWMON_I_INPUT, | ||
384 | 0 | ||
385 | }; | ||
386 | |||
387 | static const struct hwmon_channel_info adt7411_in = { | ||
388 | .type = hwmon_in, | ||
389 | .config = adt7411_in_config, | ||
390 | }; | ||
391 | |||
392 | static const u32 adt7411_temp_config[] = { | ||
393 | HWMON_T_INPUT, | ||
394 | HWMON_T_INPUT, | ||
395 | 0 | ||
396 | }; | ||
397 | |||
398 | static const struct hwmon_channel_info adt7411_temp = { | ||
399 | .type = hwmon_temp, | ||
400 | .config = adt7411_temp_config, | ||
401 | }; | ||
402 | |||
403 | static const struct hwmon_channel_info *adt7411_info[] = { | ||
404 | &adt7411_in, | ||
405 | &adt7411_temp, | ||
406 | NULL | ||
407 | }; | ||
408 | |||
409 | static const struct hwmon_ops adt7411_hwmon_ops = { | ||
410 | .is_visible = adt7411_is_visible, | ||
411 | .read = adt7411_read, | ||
412 | }; | ||
413 | |||
414 | static const struct hwmon_chip_info adt7411_chip_info = { | ||
415 | .ops = &adt7411_hwmon_ops, | ||
416 | .info = adt7411_info, | ||
417 | }; | ||
418 | |||
361 | static int adt7411_probe(struct i2c_client *client, | 419 | static int adt7411_probe(struct i2c_client *client, |
362 | const struct i2c_device_id *id) | 420 | const struct i2c_device_id *id) |
363 | { | 421 | { |
@@ -382,9 +440,10 @@ static int adt7411_probe(struct i2c_client *client, | |||
382 | /* force update on first occasion */ | 440 | /* force update on first occasion */ |
383 | data->next_update = jiffies; | 441 | data->next_update = jiffies; |
384 | 442 | ||
385 | hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, | 443 | hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, |
386 | data, | 444 | data, |
387 | adt7411_groups); | 445 | &adt7411_chip_info, |
446 | adt7411_groups); | ||
388 | return PTR_ERR_OR_ZERO(hwmon_dev); | 447 | return PTR_ERR_OR_ZERO(hwmon_dev); |
389 | } | 448 | } |
390 | 449 | ||