Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: ds3232: add temperature support

DS3232/DS3234 has the temperature registers with a resolution of 0.25
degree celsius. This enables to get the value through hwmon.

# cat /sys/class/hwmon/hwmon0/temp1_input
37250

Signed-off-by: Kirill Esipov <yesipov@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>

authored by

Kirill Esipov and committed by
Alexandre Belloni
c35c4195 d0a67c37

+127
+8
drivers/rtc/Kconfig
··· 802 802 This driver can also be built as a module. If so, the module 803 803 will be called rtc-ds3232. 804 804 805 + config RTC_DRV_DS3232_HWMON 806 + bool "HWMON support for Dallas/Maxim DS3232/DS3234" 807 + depends on RTC_DRV_DS3232 && HWMON && !(RTC_DRV_DS3232=y && HWMON=m) 808 + default y 809 + help 810 + Say Y here if you want to expose temperature sensor data on 811 + rtc-ds3232 812 + 805 813 config RTC_DRV_PCF2127 806 814 tristate "NXP PCF2127" 807 815 depends on RTC_I2C_AND_SPI
+119
drivers/rtc/rtc-ds3232.c
··· 22 22 #include <linux/bcd.h> 23 23 #include <linux/slab.h> 24 24 #include <linux/regmap.h> 25 + #include <linux/hwmon.h> 25 26 26 27 #define DS3232_REG_SECONDS 0x00 27 28 #define DS3232_REG_MINUTES 0x01 ··· 46 45 # define DS3232_REG_SR_BSY 0x04 47 46 # define DS3232_REG_SR_A2F 0x02 48 47 # define DS3232_REG_SR_A1F 0x01 48 + 49 + #define DS3232_REG_TEMPERATURE 0x11 49 50 50 51 struct ds3232 { 51 52 struct device *dev; ··· 278 275 return ret; 279 276 } 280 277 278 + /* 279 + * Temperature sensor support for ds3232/ds3234 devices. 280 + * A user-initiated temperature conversion is not started by this function, 281 + * so the temperature is updated once every 64 seconds. 282 + */ 283 + static int ds3232_hwmon_read_temp(struct device *dev, long int *mC) 284 + { 285 + struct ds3232 *ds3232 = dev_get_drvdata(dev); 286 + u8 temp_buf[2]; 287 + s16 temp; 288 + int ret; 289 + 290 + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf, 291 + sizeof(temp_buf)); 292 + if (ret < 0) 293 + return ret; 294 + 295 + /* 296 + * Temperature is represented as a 10-bit code with a resolution of 297 + * 0.25 degree celsius and encoded in two's complement format. 298 + */ 299 + temp = (temp_buf[0] << 8) | temp_buf[1]; 300 + temp >>= 6; 301 + *mC = temp * 250; 302 + 303 + return 0; 304 + } 305 + 306 + static umode_t ds3232_hwmon_is_visible(const void *data, 307 + enum hwmon_sensor_types type, 308 + u32 attr, int channel) 309 + { 310 + if (type != hwmon_temp) 311 + return 0; 312 + 313 + switch (attr) { 314 + case hwmon_temp_input: 315 + return 0444; 316 + default: 317 + return 0; 318 + } 319 + } 320 + 321 + static int ds3232_hwmon_read(struct device *dev, 322 + enum hwmon_sensor_types type, 323 + u32 attr, int channel, long *temp) 324 + { 325 + int err; 326 + 327 + switch (attr) { 328 + case hwmon_temp_input: 329 + err = ds3232_hwmon_read_temp(dev, temp); 330 + break; 331 + default: 332 + err = -EOPNOTSUPP; 333 + break; 334 + } 335 + 336 + return err; 337 + } 338 + 339 + static u32 ds3232_hwmon_chip_config[] = { 340 + HWMON_C_REGISTER_TZ, 341 + 0 342 + }; 343 + 344 + static const struct hwmon_channel_info ds3232_hwmon_chip = { 345 + .type = hwmon_chip, 346 + .config = ds3232_hwmon_chip_config, 347 + }; 348 + 349 + static u32 ds3232_hwmon_temp_config[] = { 350 + HWMON_T_INPUT, 351 + 0 352 + }; 353 + 354 + static const struct hwmon_channel_info ds3232_hwmon_temp = { 355 + .type = hwmon_temp, 356 + .config = ds3232_hwmon_temp_config, 357 + }; 358 + 359 + static const struct hwmon_channel_info *ds3232_hwmon_info[] = { 360 + &ds3232_hwmon_chip, 361 + &ds3232_hwmon_temp, 362 + NULL 363 + }; 364 + 365 + static const struct hwmon_ops ds3232_hwmon_hwmon_ops = { 366 + .is_visible = ds3232_hwmon_is_visible, 367 + .read = ds3232_hwmon_read, 368 + }; 369 + 370 + static const struct hwmon_chip_info ds3232_hwmon_chip_info = { 371 + .ops = &ds3232_hwmon_hwmon_ops, 372 + .info = ds3232_hwmon_info, 373 + }; 374 + 375 + static void ds3232_hwmon_register(struct device *dev, const char *name) 376 + { 377 + struct ds3232 *ds3232 = dev_get_drvdata(dev); 378 + struct device *hwmon_dev; 379 + 380 + if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON)) 381 + return; 382 + 383 + hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232, 384 + &ds3232_hwmon_chip_info, 385 + NULL); 386 + if (IS_ERR(hwmon_dev)) { 387 + dev_err(dev, "unable to register hwmon device %ld\n", 388 + PTR_ERR(hwmon_dev)); 389 + } 390 + } 391 + 281 392 static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) 282 393 { 283 394 struct ds3232 *ds3232 = dev_get_drvdata(dev); ··· 482 365 483 366 if (ds3232->irq > 0) 484 367 device_init_wakeup(dev, 1); 368 + 369 + ds3232_hwmon_register(dev, name); 485 370 486 371 ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops, 487 372 THIS_MODULE);