18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson 2010 - 2013 48c2ecf20Sopenharmony_ci * Author: Martin Persson <martin.persson@stericsson.com> 58c2ecf20Sopenharmony_ci * Hongbo Zhang <hongbo.zhang@linaro.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * ABX500 does not provide auto ADC, so to monitor the required temperatures, 88c2ecf20Sopenharmony_ci * a periodic work is used. It is more important to not wake up the CPU than 98c2ecf20Sopenharmony_ci * to perform this job, hence the use of a deferred delay. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * A deferred delay for thermal monitor is considered safe because: 128c2ecf20Sopenharmony_ci * If the chip gets too hot during a sleep state it's most likely due to 138c2ecf20Sopenharmony_ci * external factors, such as the surrounding temperature. I.e. no SW decisions 148c2ecf20Sopenharmony_ci * will make any difference. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 198c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/mutex.h> 248c2ecf20Sopenharmony_ci#include <linux/of.h> 258c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 268c2ecf20Sopenharmony_ci#include <linux/pm.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 298c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 308c2ecf20Sopenharmony_ci#include "abx500.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DEFAULT_MONITOR_DELAY HZ 338c2ecf20Sopenharmony_ci#define DEFAULT_MAX_TEMP 130 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline void schedule_monitor(struct abx500_temp *data) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci data->work_active = true; 388c2ecf20Sopenharmony_ci schedule_delayed_work(&data->work, DEFAULT_MONITOR_DELAY); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void threshold_updated(struct abx500_temp *data) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int i; 448c2ecf20Sopenharmony_ci for (i = 0; i < data->monitored_sensors; i++) 458c2ecf20Sopenharmony_ci if (data->max[i] != 0 || data->min[i] != 0) { 468c2ecf20Sopenharmony_ci schedule_monitor(data); 478c2ecf20Sopenharmony_ci return; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci dev_dbg(&data->pdev->dev, "No active thresholds.\n"); 518c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&data->work); 528c2ecf20Sopenharmony_ci data->work_active = false; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void gpadc_monitor(struct work_struct *work) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci int temp, i, ret; 588c2ecf20Sopenharmony_ci char alarm_node[30]; 598c2ecf20Sopenharmony_ci bool updated_min_alarm, updated_max_alarm; 608c2ecf20Sopenharmony_ci struct abx500_temp *data; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci data = container_of(work, struct abx500_temp, work.work); 638c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (i = 0; i < data->monitored_sensors; i++) { 668c2ecf20Sopenharmony_ci /* Thresholds are considered inactive if set to 0 */ 678c2ecf20Sopenharmony_ci if (data->max[i] == 0 && data->min[i] == 0) 688c2ecf20Sopenharmony_ci continue; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (data->max[i] < data->min[i]) 718c2ecf20Sopenharmony_ci continue; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ret = data->ops.read_sensor(data, data->gpadc_addr[i], &temp); 748c2ecf20Sopenharmony_ci if (ret < 0) { 758c2ecf20Sopenharmony_ci dev_err(&data->pdev->dev, "GPADC read failed\n"); 768c2ecf20Sopenharmony_ci continue; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci updated_min_alarm = false; 808c2ecf20Sopenharmony_ci updated_max_alarm = false; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (data->min[i] != 0) { 838c2ecf20Sopenharmony_ci if (temp < data->min[i]) { 848c2ecf20Sopenharmony_ci if (data->min_alarm[i] == false) { 858c2ecf20Sopenharmony_ci data->min_alarm[i] = true; 868c2ecf20Sopenharmony_ci updated_min_alarm = true; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci if (data->min_alarm[i] == true) { 908c2ecf20Sopenharmony_ci data->min_alarm[i] = false; 918c2ecf20Sopenharmony_ci updated_min_alarm = true; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci if (data->max[i] != 0) { 968c2ecf20Sopenharmony_ci if (temp > data->max[i]) { 978c2ecf20Sopenharmony_ci if (data->max_alarm[i] == false) { 988c2ecf20Sopenharmony_ci data->max_alarm[i] = true; 998c2ecf20Sopenharmony_ci updated_max_alarm = true; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } else if (temp < data->max[i] - data->max_hyst[i]) { 1028c2ecf20Sopenharmony_ci if (data->max_alarm[i] == true) { 1038c2ecf20Sopenharmony_ci data->max_alarm[i] = false; 1048c2ecf20Sopenharmony_ci updated_max_alarm = true; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (updated_min_alarm) { 1108c2ecf20Sopenharmony_ci ret = sprintf(alarm_node, "temp%d_min_alarm", i + 1); 1118c2ecf20Sopenharmony_ci sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci if (updated_max_alarm) { 1148c2ecf20Sopenharmony_ci ret = sprintf(alarm_node, "temp%d_max_alarm", i + 1); 1158c2ecf20Sopenharmony_ci sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci schedule_monitor(data); 1208c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* HWMON sysfs interfaces */ 1248c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *devattr, 1258c2ecf20Sopenharmony_ci char *buf) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 1288c2ecf20Sopenharmony_ci /* Show chip name */ 1298c2ecf20Sopenharmony_ci return data->ops.show_name(dev, devattr, buf); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic ssize_t label_show(struct device *dev, 1338c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 1368c2ecf20Sopenharmony_ci /* Show each sensor label */ 1378c2ecf20Sopenharmony_ci return data->ops.show_label(dev, devattr, buf); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic ssize_t input_show(struct device *dev, 1418c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci int ret, temp; 1448c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 1458c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1468c2ecf20Sopenharmony_ci u8 gpadc_addr = data->gpadc_addr[attr->index]; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ret = data->ops.read_sensor(data, gpadc_addr, &temp); 1498c2ecf20Sopenharmony_ci if (ret < 0) 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", temp); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* Set functions (RW nodes) */ 1568c2ecf20Sopenharmony_cistatic ssize_t min_store(struct device *dev, struct device_attribute *devattr, 1578c2ecf20Sopenharmony_ci const char *buf, size_t count) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci unsigned long val; 1608c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 1618c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1628c2ecf20Sopenharmony_ci int res = kstrtol(buf, 10, &val); 1638c2ecf20Sopenharmony_ci if (res < 0) 1648c2ecf20Sopenharmony_ci return res; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci val = clamp_val(val, 0, DEFAULT_MAX_TEMP); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1698c2ecf20Sopenharmony_ci data->min[attr->index] = val; 1708c2ecf20Sopenharmony_ci threshold_updated(data); 1718c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return count; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic ssize_t max_store(struct device *dev, struct device_attribute *devattr, 1778c2ecf20Sopenharmony_ci const char *buf, size_t count) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci unsigned long val; 1808c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 1818c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 1828c2ecf20Sopenharmony_ci int res = kstrtol(buf, 10, &val); 1838c2ecf20Sopenharmony_ci if (res < 0) 1848c2ecf20Sopenharmony_ci return res; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci val = clamp_val(val, 0, DEFAULT_MAX_TEMP); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1898c2ecf20Sopenharmony_ci data->max[attr->index] = val; 1908c2ecf20Sopenharmony_ci threshold_updated(data); 1918c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return count; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic ssize_t max_hyst_store(struct device *dev, 1978c2ecf20Sopenharmony_ci struct device_attribute *devattr, 1988c2ecf20Sopenharmony_ci const char *buf, size_t count) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci unsigned long val; 2018c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2028c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2038c2ecf20Sopenharmony_ci int res = kstrtoul(buf, 10, &val); 2048c2ecf20Sopenharmony_ci if (res < 0) 2058c2ecf20Sopenharmony_ci return res; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci val = clamp_val(val, 0, DEFAULT_MAX_TEMP); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 2108c2ecf20Sopenharmony_ci data->max_hyst[attr->index] = val; 2118c2ecf20Sopenharmony_ci threshold_updated(data); 2128c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return count; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* Show functions (RO nodes) */ 2188c2ecf20Sopenharmony_cistatic ssize_t min_show(struct device *dev, struct device_attribute *devattr, 2198c2ecf20Sopenharmony_ci char *buf) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2228c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return sprintf(buf, "%lu\n", data->min[attr->index]); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic ssize_t max_show(struct device *dev, struct device_attribute *devattr, 2288c2ecf20Sopenharmony_ci char *buf) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2318c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return sprintf(buf, "%lu\n", data->max[attr->index]); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic ssize_t max_hyst_show(struct device *dev, 2378c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2408c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return sprintf(buf, "%lu\n", data->max_hyst[attr->index]); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic ssize_t min_alarm_show(struct device *dev, 2468c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2498c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->min_alarm[attr->index]); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic ssize_t max_alarm_show(struct device *dev, 2558c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2588c2ecf20Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->max_alarm[attr->index]); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic umode_t abx500_attrs_visible(struct kobject *kobj, 2648c2ecf20Sopenharmony_ci struct attribute *attr, int n) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 2678c2ecf20Sopenharmony_ci struct abx500_temp *data = dev_get_drvdata(dev); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (data->ops.is_visible) 2708c2ecf20Sopenharmony_ci return data->ops.is_visible(attr, n); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return attr->mode; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* Chip name, required by hwmon */ 2768c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(name, name, 0); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* GPADC - SENSOR1 */ 2798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_label, label, 0); 2808c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, input, 0); 2818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, min, 0); 2828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, max, 0); 2838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, max_hyst, 0); 2848c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, min_alarm, 0); 2858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, max_alarm, 0); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* GPADC - SENSOR2 */ 2888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_label, label, 1); 2898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, input, 1); 2908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_min, min, 1); 2918c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, max, 1); 2928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max_hyst, max_hyst, 1); 2938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, min_alarm, 1); 2948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, max_alarm, 1); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* GPADC - SENSOR3 */ 2978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_label, label, 2); 2988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, input, 2); 2998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_min, min, 2); 3008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, max, 2); 3018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max_hyst, max_hyst, 2); 3028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, min_alarm, 2); 3038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, max_alarm, 2); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* GPADC - SENSOR4 */ 3068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_label, label, 3); 3078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_input, input, 3); 3088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_min, min, 3); 3098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_max, max, 3); 3108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp4_max_hyst, max_hyst, 3); 3118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_min_alarm, min_alarm, 3); 3128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp4_max_alarm, max_alarm, 3); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic struct attribute *abx500_temp_attributes[] = { 3158c2ecf20Sopenharmony_ci &sensor_dev_attr_name.dev_attr.attr, 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_label.dev_attr.attr, 3188c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 3198c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 3208c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 3218c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, 3228c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 3238c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_label.dev_attr.attr, 3268c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 3278c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 3288c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 3298c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, 3308c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 3318c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_label.dev_attr.attr, 3348c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, 3358c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 3368c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 3378c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, 3388c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, 3398c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_label.dev_attr.attr, 3428c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_input.dev_attr.attr, 3438c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_min.dev_attr.attr, 3448c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_max.dev_attr.attr, 3458c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, 3468c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, 3478c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, 3488c2ecf20Sopenharmony_ci NULL 3498c2ecf20Sopenharmony_ci}; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic const struct attribute_group abx500_temp_group = { 3528c2ecf20Sopenharmony_ci .attrs = abx500_temp_attributes, 3538c2ecf20Sopenharmony_ci .is_visible = abx500_attrs_visible, 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic irqreturn_t abx500_temp_irq_handler(int irq, void *irq_data) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct platform_device *pdev = irq_data; 3598c2ecf20Sopenharmony_ci struct abx500_temp *data = platform_get_drvdata(pdev); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci data->ops.irq_handler(irq, data); 3628c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int setup_irqs(struct platform_device *pdev) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int ret; 3688c2ecf20Sopenharmony_ci int irq = platform_get_irq_byname(pdev, "ABX500_TEMP_WARM"); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (irq < 0) { 3718c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Get irq by name failed\n"); 3728c2ecf20Sopenharmony_ci return irq; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 3768c2ecf20Sopenharmony_ci abx500_temp_irq_handler, 0, "abx500-temp", pdev); 3778c2ecf20Sopenharmony_ci if (ret < 0) 3788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return ret; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int abx500_temp_probe(struct platform_device *pdev) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct abx500_temp *data; 3868c2ecf20Sopenharmony_ci int err; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 3898c2ecf20Sopenharmony_ci if (!data) 3908c2ecf20Sopenharmony_ci return -ENOMEM; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci data->pdev = pdev; 3938c2ecf20Sopenharmony_ci mutex_init(&data->lock); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Chip specific initialization */ 3968c2ecf20Sopenharmony_ci err = abx500_hwmon_init(data); 3978c2ecf20Sopenharmony_ci if (err < 0 || !data->ops.read_sensor || !data->ops.show_name || 3988c2ecf20Sopenharmony_ci !data->ops.show_label) 3998c2ecf20Sopenharmony_ci return err; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci INIT_DEFERRABLE_WORK(&data->work, gpadc_monitor); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci err = sysfs_create_group(&pdev->dev.kobj, &abx500_temp_group); 4068c2ecf20Sopenharmony_ci if (err < 0) { 4078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err); 4088c2ecf20Sopenharmony_ci return err; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci data->hwmon_dev = hwmon_device_register(&pdev->dev); 4128c2ecf20Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 4138c2ecf20Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 4148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Class registration failed (%d)\n", err); 4158c2ecf20Sopenharmony_ci goto exit_sysfs_group; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (data->ops.irq_handler) { 4198c2ecf20Sopenharmony_ci err = setup_irqs(pdev); 4208c2ecf20Sopenharmony_ci if (err < 0) 4218c2ecf20Sopenharmony_ci goto exit_hwmon_reg; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ciexit_hwmon_reg: 4268c2ecf20Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 4278c2ecf20Sopenharmony_ciexit_sysfs_group: 4288c2ecf20Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group); 4298c2ecf20Sopenharmony_ci return err; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int abx500_temp_remove(struct platform_device *pdev) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct abx500_temp *data = platform_get_drvdata(pdev); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&data->work); 4378c2ecf20Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 4388c2ecf20Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int abx500_temp_suspend(struct platform_device *pdev, 4448c2ecf20Sopenharmony_ci pm_message_t state) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct abx500_temp *data = platform_get_drvdata(pdev); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (data->work_active) 4498c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&data->work); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int abx500_temp_resume(struct platform_device *pdev) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct abx500_temp *data = platform_get_drvdata(pdev); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (data->work_active) 4598c2ecf20Sopenharmony_ci schedule_monitor(data); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 4658c2ecf20Sopenharmony_cistatic const struct of_device_id abx500_temp_match[] = { 4668c2ecf20Sopenharmony_ci { .compatible = "stericsson,abx500-temp" }, 4678c2ecf20Sopenharmony_ci {}, 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, abx500_temp_match); 4708c2ecf20Sopenharmony_ci#endif 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic struct platform_driver abx500_temp_driver = { 4738c2ecf20Sopenharmony_ci .driver = { 4748c2ecf20Sopenharmony_ci .name = "abx500-temp", 4758c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(abx500_temp_match), 4768c2ecf20Sopenharmony_ci }, 4778c2ecf20Sopenharmony_ci .suspend = abx500_temp_suspend, 4788c2ecf20Sopenharmony_ci .resume = abx500_temp_resume, 4798c2ecf20Sopenharmony_ci .probe = abx500_temp_probe, 4808c2ecf20Sopenharmony_ci .remove = abx500_temp_remove, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cimodule_platform_driver(abx500_temp_driver); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ciMODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>"); 4868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ABX500 temperature driver"); 4878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 488