18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/hwmon/wm831x-hwmon.c - Wolfson Microelectronics WM831x PMIC 48c2ecf20Sopenharmony_ci * hardware monitoring features. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Wolfson Microelectronics plc 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 148c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/mfd/wm831x/core.h> 188c2ecf20Sopenharmony_ci#include <linux/mfd/wm831x/auxadc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic const char * const input_names[] = { 218c2ecf20Sopenharmony_ci [WM831X_AUX_SYSVDD] = "SYSVDD", 228c2ecf20Sopenharmony_ci [WM831X_AUX_USB] = "USB", 238c2ecf20Sopenharmony_ci [WM831X_AUX_BKUP_BATT] = "Backup battery", 248c2ecf20Sopenharmony_ci [WM831X_AUX_BATT] = "Battery", 258c2ecf20Sopenharmony_ci [WM831X_AUX_WALL] = "WALL", 268c2ecf20Sopenharmony_ci [WM831X_AUX_CHIP_TEMP] = "PMIC", 278c2ecf20Sopenharmony_ci [WM831X_AUX_BATT_TEMP] = "Battery", 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic ssize_t show_voltage(struct device *dev, 318c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct wm831x *wm831x = dev_get_drvdata(dev); 348c2ecf20Sopenharmony_ci int channel = to_sensor_dev_attr(attr)->index; 358c2ecf20Sopenharmony_ci int ret; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci ret = wm831x_auxadc_read_uv(wm831x, channel); 388c2ecf20Sopenharmony_ci if (ret < 0) 398c2ecf20Sopenharmony_ci return ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret, 1000)); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic ssize_t show_chip_temp(struct device *dev, 458c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct wm831x *wm831x = dev_get_drvdata(dev); 488c2ecf20Sopenharmony_ci int channel = to_sensor_dev_attr(attr)->index; 498c2ecf20Sopenharmony_ci int ret; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci ret = wm831x_auxadc_read(wm831x, channel); 528c2ecf20Sopenharmony_ci if (ret < 0) 538c2ecf20Sopenharmony_ci return ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Degrees celsius = (512.18-ret) / 1.0983 */ 568c2ecf20Sopenharmony_ci ret = 512180 - (ret * 1000); 578c2ecf20Sopenharmony_ci ret = DIV_ROUND_CLOSEST(ret * 10000, 10983); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", ret); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic ssize_t show_label(struct device *dev, 638c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int channel = to_sensor_dev_attr(attr)->index; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", input_names[channel]); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define WM831X_VOLTAGE(id, name) \ 718c2ecf20Sopenharmony_ci static SENSOR_DEVICE_ATTR(in##id##_input, S_IRUGO, show_voltage, \ 728c2ecf20Sopenharmony_ci NULL, name) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define WM831X_NAMED_VOLTAGE(id, name) \ 758c2ecf20Sopenharmony_ci WM831X_VOLTAGE(id, name); \ 768c2ecf20Sopenharmony_ci static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \ 778c2ecf20Sopenharmony_ci NULL, name) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciWM831X_VOLTAGE(0, WM831X_AUX_AUX1); 808c2ecf20Sopenharmony_ciWM831X_VOLTAGE(1, WM831X_AUX_AUX2); 818c2ecf20Sopenharmony_ciWM831X_VOLTAGE(2, WM831X_AUX_AUX3); 828c2ecf20Sopenharmony_ciWM831X_VOLTAGE(3, WM831X_AUX_AUX4); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciWM831X_NAMED_VOLTAGE(4, WM831X_AUX_SYSVDD); 858c2ecf20Sopenharmony_ciWM831X_NAMED_VOLTAGE(5, WM831X_AUX_USB); 868c2ecf20Sopenharmony_ciWM831X_NAMED_VOLTAGE(6, WM831X_AUX_BATT); 878c2ecf20Sopenharmony_ciWM831X_NAMED_VOLTAGE(7, WM831X_AUX_WALL); 888c2ecf20Sopenharmony_ciWM831X_NAMED_VOLTAGE(8, WM831X_AUX_BKUP_BATT); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_chip_temp, NULL, 918c2ecf20Sopenharmony_ci WM831X_AUX_CHIP_TEMP); 928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 938c2ecf20Sopenharmony_ci WM831X_AUX_CHIP_TEMP); 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * Report as a voltage since conversion depends on external components 968c2ecf20Sopenharmony_ci * and that's what the ABI wants. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_voltage, NULL, 998c2ecf20Sopenharmony_ci WM831X_AUX_BATT_TEMP); 1008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 1018c2ecf20Sopenharmony_ci WM831X_AUX_BATT_TEMP); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic struct attribute *wm831x_attrs[] = { 1048c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_input.dev_attr.attr, 1058c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 1068c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 1078c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 1108c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_label.dev_attr.attr, 1118c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr.attr, 1128c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_label.dev_attr.attr, 1138c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_input.dev_attr.attr, 1148c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_label.dev_attr.attr, 1158c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_input.dev_attr.attr, 1168c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_label.dev_attr.attr, 1178c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_input.dev_attr.attr, 1188c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_label.dev_attr.attr, 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 1218c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_label.dev_attr.attr, 1228c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 1238c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_label.dev_attr.attr, 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci NULL 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(wm831x); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int wm831x_hwmon_probe(struct platform_device *pdev) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 1338c2ecf20Sopenharmony_ci struct device *hwmon_dev; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "wm831x", 1368c2ecf20Sopenharmony_ci wm831x, 1378c2ecf20Sopenharmony_ci wm831x_groups); 1388c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic struct platform_driver wm831x_hwmon_driver = { 1428c2ecf20Sopenharmony_ci .probe = wm831x_hwmon_probe, 1438c2ecf20Sopenharmony_ci .driver = { 1448c2ecf20Sopenharmony_ci .name = "wm831x-hwmon", 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cimodule_platform_driver(wm831x_hwmon_driver); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 1518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("WM831x Hardware Monitoring"); 1528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1538c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:wm831x-hwmon"); 154