.. | .. |
---|
19 | 19 | #include <linux/err.h> |
---|
20 | 20 | #include <linux/mutex.h> |
---|
21 | 21 | #include <linux/of.h> |
---|
| 22 | +#include <linux/regmap.h> |
---|
22 | 23 | |
---|
23 | 24 | /* Addresses to scan */ |
---|
24 | 25 | static const unsigned short normal_i2c[] = { |
---|
.. | .. |
---|
189 | 190 | { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK }, |
---|
190 | 191 | }; |
---|
191 | 192 | |
---|
192 | | -enum temp_index { |
---|
193 | | - t_input = 0, |
---|
194 | | - t_crit, |
---|
195 | | - t_min, |
---|
196 | | - t_max, |
---|
197 | | - t_num_temp |
---|
198 | | -}; |
---|
199 | | - |
---|
200 | | -static const u8 temp_regs[t_num_temp] = { |
---|
201 | | - [t_input] = JC42_REG_TEMP, |
---|
202 | | - [t_crit] = JC42_REG_TEMP_CRITICAL, |
---|
203 | | - [t_min] = JC42_REG_TEMP_LOWER, |
---|
204 | | - [t_max] = JC42_REG_TEMP_UPPER, |
---|
205 | | -}; |
---|
206 | | - |
---|
207 | 193 | /* Each client has this additional data */ |
---|
208 | 194 | struct jc42_data { |
---|
209 | | - struct i2c_client *client; |
---|
210 | 195 | struct mutex update_lock; /* protect register access */ |
---|
| 196 | + struct regmap *regmap; |
---|
211 | 197 | bool extended; /* true if extended range supported */ |
---|
212 | 198 | bool valid; |
---|
213 | | - unsigned long last_updated; /* In jiffies */ |
---|
214 | 199 | u16 orig_config; /* original configuration */ |
---|
215 | 200 | u16 config; /* current configuration */ |
---|
216 | | - u16 temp[t_num_temp];/* Temperatures */ |
---|
217 | 201 | }; |
---|
218 | 202 | |
---|
219 | 203 | #define JC42_TEMP_MIN_EXTENDED (-40000) |
---|
.. | .. |
---|
238 | 222 | return reg * 125 / 2; |
---|
239 | 223 | } |
---|
240 | 224 | |
---|
241 | | -static struct jc42_data *jc42_update_device(struct device *dev) |
---|
242 | | -{ |
---|
243 | | - struct jc42_data *data = dev_get_drvdata(dev); |
---|
244 | | - struct i2c_client *client = data->client; |
---|
245 | | - struct jc42_data *ret = data; |
---|
246 | | - int i, val; |
---|
247 | | - |
---|
248 | | - mutex_lock(&data->update_lock); |
---|
249 | | - |
---|
250 | | - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
---|
251 | | - for (i = 0; i < t_num_temp; i++) { |
---|
252 | | - val = i2c_smbus_read_word_swapped(client, temp_regs[i]); |
---|
253 | | - if (val < 0) { |
---|
254 | | - ret = ERR_PTR(val); |
---|
255 | | - goto abort; |
---|
256 | | - } |
---|
257 | | - data->temp[i] = val; |
---|
258 | | - } |
---|
259 | | - data->last_updated = jiffies; |
---|
260 | | - data->valid = true; |
---|
261 | | - } |
---|
262 | | -abort: |
---|
263 | | - mutex_unlock(&data->update_lock); |
---|
264 | | - return ret; |
---|
265 | | -} |
---|
266 | | - |
---|
267 | 225 | static int jc42_read(struct device *dev, enum hwmon_sensor_types type, |
---|
268 | 226 | u32 attr, int channel, long *val) |
---|
269 | 227 | { |
---|
270 | | - struct jc42_data *data = jc42_update_device(dev); |
---|
271 | | - int temp, hyst; |
---|
| 228 | + struct jc42_data *data = dev_get_drvdata(dev); |
---|
| 229 | + unsigned int regval; |
---|
| 230 | + int ret, temp, hyst; |
---|
272 | 231 | |
---|
273 | | - if (IS_ERR(data)) |
---|
274 | | - return PTR_ERR(data); |
---|
| 232 | + mutex_lock(&data->update_lock); |
---|
275 | 233 | |
---|
276 | 234 | switch (attr) { |
---|
277 | 235 | case hwmon_temp_input: |
---|
278 | | - *val = jc42_temp_from_reg(data->temp[t_input]); |
---|
279 | | - return 0; |
---|
| 236 | + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); |
---|
| 237 | + if (ret) |
---|
| 238 | + break; |
---|
| 239 | + |
---|
| 240 | + *val = jc42_temp_from_reg(regval); |
---|
| 241 | + break; |
---|
280 | 242 | case hwmon_temp_min: |
---|
281 | | - *val = jc42_temp_from_reg(data->temp[t_min]); |
---|
282 | | - return 0; |
---|
| 243 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_LOWER, ®val); |
---|
| 244 | + if (ret) |
---|
| 245 | + break; |
---|
| 246 | + |
---|
| 247 | + *val = jc42_temp_from_reg(regval); |
---|
| 248 | + break; |
---|
283 | 249 | case hwmon_temp_max: |
---|
284 | | - *val = jc42_temp_from_reg(data->temp[t_max]); |
---|
285 | | - return 0; |
---|
| 250 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val); |
---|
| 251 | + if (ret) |
---|
| 252 | + break; |
---|
| 253 | + |
---|
| 254 | + *val = jc42_temp_from_reg(regval); |
---|
| 255 | + break; |
---|
286 | 256 | case hwmon_temp_crit: |
---|
287 | | - *val = jc42_temp_from_reg(data->temp[t_crit]); |
---|
288 | | - return 0; |
---|
| 257 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, |
---|
| 258 | + ®val); |
---|
| 259 | + if (ret) |
---|
| 260 | + break; |
---|
| 261 | + |
---|
| 262 | + *val = jc42_temp_from_reg(regval); |
---|
| 263 | + break; |
---|
289 | 264 | case hwmon_temp_max_hyst: |
---|
290 | | - temp = jc42_temp_from_reg(data->temp[t_max]); |
---|
| 265 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val); |
---|
| 266 | + if (ret) |
---|
| 267 | + break; |
---|
| 268 | + |
---|
| 269 | + temp = jc42_temp_from_reg(regval); |
---|
291 | 270 | hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) |
---|
292 | 271 | >> JC42_CFG_HYST_SHIFT]; |
---|
293 | 272 | *val = temp - hyst; |
---|
294 | | - return 0; |
---|
| 273 | + break; |
---|
295 | 274 | case hwmon_temp_crit_hyst: |
---|
296 | | - temp = jc42_temp_from_reg(data->temp[t_crit]); |
---|
| 275 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, |
---|
| 276 | + ®val); |
---|
| 277 | + if (ret) |
---|
| 278 | + break; |
---|
| 279 | + |
---|
| 280 | + temp = jc42_temp_from_reg(regval); |
---|
297 | 281 | hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) |
---|
298 | 282 | >> JC42_CFG_HYST_SHIFT]; |
---|
299 | 283 | *val = temp - hyst; |
---|
300 | | - return 0; |
---|
| 284 | + break; |
---|
301 | 285 | case hwmon_temp_min_alarm: |
---|
302 | | - *val = (data->temp[t_input] >> JC42_ALARM_MIN_BIT) & 1; |
---|
303 | | - return 0; |
---|
| 286 | + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); |
---|
| 287 | + if (ret) |
---|
| 288 | + break; |
---|
| 289 | + |
---|
| 290 | + *val = (regval >> JC42_ALARM_MIN_BIT) & 1; |
---|
| 291 | + break; |
---|
304 | 292 | case hwmon_temp_max_alarm: |
---|
305 | | - *val = (data->temp[t_input] >> JC42_ALARM_MAX_BIT) & 1; |
---|
306 | | - return 0; |
---|
| 293 | + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); |
---|
| 294 | + if (ret) |
---|
| 295 | + break; |
---|
| 296 | + |
---|
| 297 | + *val = (regval >> JC42_ALARM_MAX_BIT) & 1; |
---|
| 298 | + break; |
---|
307 | 299 | case hwmon_temp_crit_alarm: |
---|
308 | | - *val = (data->temp[t_input] >> JC42_ALARM_CRIT_BIT) & 1; |
---|
309 | | - return 0; |
---|
| 300 | + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); |
---|
| 301 | + if (ret) |
---|
| 302 | + break; |
---|
| 303 | + |
---|
| 304 | + *val = (regval >> JC42_ALARM_CRIT_BIT) & 1; |
---|
| 305 | + break; |
---|
310 | 306 | default: |
---|
311 | | - return -EOPNOTSUPP; |
---|
| 307 | + ret = -EOPNOTSUPP; |
---|
| 308 | + break; |
---|
312 | 309 | } |
---|
| 310 | + |
---|
| 311 | + mutex_unlock(&data->update_lock); |
---|
| 312 | + |
---|
| 313 | + return ret; |
---|
313 | 314 | } |
---|
314 | 315 | |
---|
315 | 316 | static int jc42_write(struct device *dev, enum hwmon_sensor_types type, |
---|
316 | 317 | u32 attr, int channel, long val) |
---|
317 | 318 | { |
---|
318 | 319 | struct jc42_data *data = dev_get_drvdata(dev); |
---|
319 | | - struct i2c_client *client = data->client; |
---|
| 320 | + unsigned int regval; |
---|
320 | 321 | int diff, hyst; |
---|
321 | 322 | int ret; |
---|
322 | 323 | |
---|
.. | .. |
---|
324 | 325 | |
---|
325 | 326 | switch (attr) { |
---|
326 | 327 | case hwmon_temp_min: |
---|
327 | | - data->temp[t_min] = jc42_temp_to_reg(val, data->extended); |
---|
328 | | - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_min], |
---|
329 | | - data->temp[t_min]); |
---|
| 328 | + ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER, |
---|
| 329 | + jc42_temp_to_reg(val, data->extended)); |
---|
330 | 330 | break; |
---|
331 | 331 | case hwmon_temp_max: |
---|
332 | | - data->temp[t_max] = jc42_temp_to_reg(val, data->extended); |
---|
333 | | - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_max], |
---|
334 | | - data->temp[t_max]); |
---|
| 332 | + ret = regmap_write(data->regmap, JC42_REG_TEMP_UPPER, |
---|
| 333 | + jc42_temp_to_reg(val, data->extended)); |
---|
335 | 334 | break; |
---|
336 | 335 | case hwmon_temp_crit: |
---|
337 | | - data->temp[t_crit] = jc42_temp_to_reg(val, data->extended); |
---|
338 | | - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_crit], |
---|
339 | | - data->temp[t_crit]); |
---|
| 336 | + ret = regmap_write(data->regmap, JC42_REG_TEMP_CRITICAL, |
---|
| 337 | + jc42_temp_to_reg(val, data->extended)); |
---|
340 | 338 | break; |
---|
341 | 339 | case hwmon_temp_crit_hyst: |
---|
| 340 | + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, |
---|
| 341 | + ®val); |
---|
| 342 | + if (ret) |
---|
| 343 | + break; |
---|
| 344 | + |
---|
342 | 345 | /* |
---|
343 | 346 | * JC42.4 compliant chips only support four hysteresis values. |
---|
344 | 347 | * Pick best choice and go from there. |
---|
.. | .. |
---|
346 | 349 | val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED |
---|
347 | 350 | : JC42_TEMP_MIN) - 6000, |
---|
348 | 351 | JC42_TEMP_MAX); |
---|
349 | | - diff = jc42_temp_from_reg(data->temp[t_crit]) - val; |
---|
| 352 | + diff = jc42_temp_from_reg(regval) - val; |
---|
350 | 353 | hyst = 0; |
---|
351 | 354 | if (diff > 0) { |
---|
352 | 355 | if (diff < 2250) |
---|
.. | .. |
---|
358 | 361 | } |
---|
359 | 362 | data->config = (data->config & ~JC42_CFG_HYST_MASK) | |
---|
360 | 363 | (hyst << JC42_CFG_HYST_SHIFT); |
---|
361 | | - ret = i2c_smbus_write_word_swapped(data->client, |
---|
362 | | - JC42_REG_CONFIG, |
---|
363 | | - data->config); |
---|
| 364 | + ret = regmap_write(data->regmap, JC42_REG_CONFIG, |
---|
| 365 | + data->config); |
---|
364 | 366 | break; |
---|
365 | 367 | default: |
---|
366 | 368 | ret = -EOPNOTSUPP; |
---|
.. | .. |
---|
458 | 460 | .info = jc42_info, |
---|
459 | 461 | }; |
---|
460 | 462 | |
---|
| 463 | +static bool jc42_readable_reg(struct device *dev, unsigned int reg) |
---|
| 464 | +{ |
---|
| 465 | + return (reg >= JC42_REG_CAP && reg <= JC42_REG_DEVICEID) || |
---|
| 466 | + reg == JC42_REG_SMBUS; |
---|
| 467 | +} |
---|
| 468 | + |
---|
| 469 | +static bool jc42_writable_reg(struct device *dev, unsigned int reg) |
---|
| 470 | +{ |
---|
| 471 | + return (reg >= JC42_REG_CONFIG && reg <= JC42_REG_TEMP_CRITICAL) || |
---|
| 472 | + reg == JC42_REG_SMBUS; |
---|
| 473 | +} |
---|
| 474 | + |
---|
| 475 | +static bool jc42_volatile_reg(struct device *dev, unsigned int reg) |
---|
| 476 | +{ |
---|
| 477 | + return reg == JC42_REG_CONFIG || reg == JC42_REG_TEMP; |
---|
| 478 | +} |
---|
| 479 | + |
---|
| 480 | +static const struct regmap_config jc42_regmap_config = { |
---|
| 481 | + .reg_bits = 8, |
---|
| 482 | + .val_bits = 16, |
---|
| 483 | + .val_format_endian = REGMAP_ENDIAN_BIG, |
---|
| 484 | + .max_register = JC42_REG_SMBUS, |
---|
| 485 | + .writeable_reg = jc42_writable_reg, |
---|
| 486 | + .readable_reg = jc42_readable_reg, |
---|
| 487 | + .volatile_reg = jc42_volatile_reg, |
---|
| 488 | + .cache_type = REGCACHE_RBTREE, |
---|
| 489 | +}; |
---|
| 490 | + |
---|
461 | 491 | static int jc42_probe(struct i2c_client *client) |
---|
462 | 492 | { |
---|
463 | 493 | struct device *dev = &client->dev; |
---|
464 | 494 | struct device *hwmon_dev; |
---|
| 495 | + unsigned int config, cap; |
---|
465 | 496 | struct jc42_data *data; |
---|
466 | | - int config, cap; |
---|
| 497 | + int ret; |
---|
467 | 498 | |
---|
468 | 499 | data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL); |
---|
469 | 500 | if (!data) |
---|
470 | 501 | return -ENOMEM; |
---|
471 | 502 | |
---|
472 | | - data->client = client; |
---|
| 503 | + data->regmap = devm_regmap_init_i2c(client, &jc42_regmap_config); |
---|
| 504 | + if (IS_ERR(data->regmap)) |
---|
| 505 | + return PTR_ERR(data->regmap); |
---|
| 506 | + |
---|
473 | 507 | i2c_set_clientdata(client, data); |
---|
474 | 508 | mutex_init(&data->update_lock); |
---|
475 | 509 | |
---|
476 | | - cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP); |
---|
477 | | - if (cap < 0) |
---|
478 | | - return cap; |
---|
| 510 | + ret = regmap_read(data->regmap, JC42_REG_CAP, &cap); |
---|
| 511 | + if (ret) |
---|
| 512 | + return ret; |
---|
479 | 513 | |
---|
480 | 514 | data->extended = !!(cap & JC42_CAP_RANGE); |
---|
481 | 515 | |
---|
482 | 516 | if (device_property_read_bool(dev, "smbus-timeout-disable")) { |
---|
483 | | - int smbus; |
---|
484 | | - |
---|
485 | 517 | /* |
---|
486 | 518 | * Not all chips support this register, but from a |
---|
487 | 519 | * quick read of various datasheets no chip appears |
---|
488 | 520 | * incompatible with the below attempt to disable |
---|
489 | 521 | * the timeout. And the whole thing is opt-in... |
---|
490 | 522 | */ |
---|
491 | | - smbus = i2c_smbus_read_word_swapped(client, JC42_REG_SMBUS); |
---|
492 | | - if (smbus < 0) |
---|
493 | | - return smbus; |
---|
494 | | - i2c_smbus_write_word_swapped(client, JC42_REG_SMBUS, |
---|
495 | | - smbus | SMBUS_STMOUT); |
---|
| 523 | + ret = regmap_set_bits(data->regmap, JC42_REG_SMBUS, |
---|
| 524 | + SMBUS_STMOUT); |
---|
| 525 | + if (ret) |
---|
| 526 | + return ret; |
---|
496 | 527 | } |
---|
497 | 528 | |
---|
498 | | - config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG); |
---|
499 | | - if (config < 0) |
---|
500 | | - return config; |
---|
| 529 | + ret = regmap_read(data->regmap, JC42_REG_CONFIG, &config); |
---|
| 530 | + if (ret) |
---|
| 531 | + return ret; |
---|
501 | 532 | |
---|
502 | 533 | data->orig_config = config; |
---|
503 | 534 | if (config & JC42_CFG_SHUTDOWN) { |
---|
504 | 535 | config &= ~JC42_CFG_SHUTDOWN; |
---|
505 | | - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config); |
---|
| 536 | + regmap_write(data->regmap, JC42_REG_CONFIG, config); |
---|
506 | 537 | } |
---|
507 | 538 | data->config = config; |
---|
508 | 539 | |
---|
.. | .. |
---|
523 | 554 | |
---|
524 | 555 | config = (data->orig_config & ~JC42_CFG_HYST_MASK) |
---|
525 | 556 | | (data->config & JC42_CFG_HYST_MASK); |
---|
526 | | - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config); |
---|
| 557 | + regmap_write(data->regmap, JC42_REG_CONFIG, config); |
---|
527 | 558 | } |
---|
528 | 559 | return 0; |
---|
529 | 560 | } |
---|
.. | .. |
---|
535 | 566 | struct jc42_data *data = dev_get_drvdata(dev); |
---|
536 | 567 | |
---|
537 | 568 | data->config |= JC42_CFG_SHUTDOWN; |
---|
538 | | - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, |
---|
539 | | - data->config); |
---|
| 569 | + regmap_write(data->regmap, JC42_REG_CONFIG, data->config); |
---|
| 570 | + |
---|
| 571 | + regcache_cache_only(data->regmap, true); |
---|
| 572 | + regcache_mark_dirty(data->regmap); |
---|
| 573 | + |
---|
540 | 574 | return 0; |
---|
541 | 575 | } |
---|
542 | 576 | |
---|
.. | .. |
---|
544 | 578 | { |
---|
545 | 579 | struct jc42_data *data = dev_get_drvdata(dev); |
---|
546 | 580 | |
---|
| 581 | + regcache_cache_only(data->regmap, false); |
---|
| 582 | + |
---|
547 | 583 | data->config &= ~JC42_CFG_SHUTDOWN; |
---|
548 | | - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, |
---|
549 | | - data->config); |
---|
550 | | - return 0; |
---|
| 584 | + regmap_write(data->regmap, JC42_REG_CONFIG, data->config); |
---|
| 585 | + |
---|
| 586 | + /* Restore cached register values to hardware */ |
---|
| 587 | + return regcache_sync(data->regmap); |
---|
551 | 588 | } |
---|
552 | 589 | |
---|
553 | 590 | static const struct dev_pm_ops jc42_dev_pm_ops = { |
---|