From 56f0b552fe41b80bcb558f1542b03d5f5af4f366 Mon Sep 17 00:00:00 2001 From: Leonid Lobachev Date: Fri, 26 Apr 2019 11:47:56 -0700 Subject: [PATCH] staging: gasket: Add thermal sysfs nodes. Add node to read current temperature and nodes to set and enable/disable thermal warnings. Change-Id: I8a12f6e33679573107686fe32be2e4a8bb0f9cc7 Signed-off-by: Leonid Lobachev --- apex_driver.c | 125 +++++++++++++++++++++++++++++++++++++++++++++---- gasket_sysfs.h | 7 +++ 2 files changed, 122 insertions(+), 10 deletions(-) diff --git a/apex_driver.c b/apex_driver.c index 1eff202..d1b823e 100644 --- a/apex_driver.c +++ b/apex_driver.c @@ -68,6 +68,10 @@ enum sysfs_attribute_type { ATTR_KERNEL_HIB_SIMPLE_PAGE_TABLE_SIZE, ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES, ATTR_TEMP, + ATTR_TEMP_WARN1, + ATTR_TEMP_WARN1_EN, + ATTR_TEMP_WARN2, + ATTR_TEMP_WARN2_EN, }; /* @@ -100,6 +104,7 @@ enum apex_bar2_regs { APEX_BAR2_REG_IDLEGENERATOR_IDLEGEN_IDLEREGISTER = 0x4A000, APEX_BAR2_REG_KERNEL_HIB_PAGE_TABLE = 0x50000, APEX_BAR2_REG_OMC0_D0 = 0x01a0d0, + APEX_BAR2_REG_OMC0_D4 = 0x01a0d4, APEX_BAR2_REG_OMC0_D8 = 0x01a0d8, APEX_BAR2_REG_OMC0_DC = 0x01a0dc, @@ -566,11 +571,23 @@ static long apex_ioctl(struct file *filp, uint cmd, void __user *argp) } } +/* Linear fit optimized for 25C-100C */ +static int adc_to_millic(int adc) +{ + return (662 - adc) * 250 + 550; +} + +static int millic_to_adc(int millic) +{ + return (550 - millic) / 250 + 662; +} + /* Display driver sysfs entries. */ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr, char *buf) { int ret; + unsigned value; struct gasket_dev *gasket_dev; struct gasket_sysfs_attribute *gasket_attr; enum sysfs_attribute_type type; @@ -606,13 +623,95 @@ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr, gasket_dev->page_table[0])); break; case ATTR_TEMP: - // Read temperature - ret = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_OMC0_DC); - ret = (ret >> 16) & ((1 << 10) - 1); - // Remap to millicelsius (rough calculation) - ret = (((662 - ret) * 1000 / 4 + 500) * 10 + 500) / 10; - ret = snprintf(buf, PAGE_SIZE, "%i\n", ret); + value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_DC); + value = (value >> 16) & ((1 << 10) - 1); + ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value)); + break; + case ATTR_TEMP_WARN1: + value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D4); + value = (value >> 16) & ((1 << 10) - 1); + ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value)); + break; + case ATTR_TEMP_WARN2: + value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D8); + value = (value >> 16) & ((1 << 10) - 1); + ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value)); + break; + case ATTR_TEMP_WARN1_EN: + value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D4); + ret = scnprintf(buf, PAGE_SIZE, "%i\n", value >> 31); + break; + case ATTR_TEMP_WARN2_EN: + value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D8); + ret = scnprintf(buf, PAGE_SIZE, "%i\n", value >> 31); + break; + default: + dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", + attr->attr.name); + ret = 0; + break; + } + + gasket_sysfs_put_attr(device, gasket_attr); + gasket_sysfs_put_device_data(device, gasket_dev); + return ret; +} + +/* Set driver sysfs entries. */ +static ssize_t sysfs_store(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = count, value; + struct gasket_dev *gasket_dev; + struct gasket_sysfs_attribute *gasket_attr; + enum sysfs_attribute_type type; + + if (kstrtoint(buf, 10, &value)) + return -EINVAL; + + gasket_dev = gasket_sysfs_get_device_data(device); + if (!gasket_dev) { + dev_err(device, "No Apex device sysfs mapping found\n"); + return -ENODEV; + } + + gasket_attr = gasket_sysfs_get_attr(device, attr); + if (!gasket_attr) { + dev_err(device, "No Apex device sysfs attr data found\n"); + gasket_sysfs_put_device_data(device, gasket_dev); + return -ENODEV; + } + + type = (enum sysfs_attribute_type)gasket_attr->data.attr_type; + switch (type) { + case ATTR_TEMP_WARN1: + value = millic_to_adc(value); + gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D4, value, 10, + 16); + break; + case ATTR_TEMP_WARN2: + value = millic_to_adc(value); + gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D8, value, 10, + 16); + break; + case ATTR_TEMP_WARN1_EN: + value = value > 0 ? 1 : 0; + gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D4, value, 1, + 31); + break; + case ATTR_TEMP_WARN2_EN: + value = value > 0 ? 1 : 0; + gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, + APEX_BAR2_REG_OMC0_D8, value, 1, + 31); break; default: dev_dbg(gasket_dev->dev, "Unknown attribute: %s\n", @@ -634,6 +733,12 @@ static struct gasket_sysfs_attribute apex_sysfs_attrs[] = { GASKET_SYSFS_RO(node_0_num_mapped_pages, sysfs_show, ATTR_KERNEL_HIB_NUM_ACTIVE_PAGES), GASKET_SYSFS_RO(temp, sysfs_show, ATTR_TEMP), + GASKET_SYSFS_RW(temp_warn1, sysfs_show, sysfs_store, ATTR_TEMP_WARN1), + GASKET_SYSFS_RW(temp_warn1_en, sysfs_show, sysfs_store, + ATTR_TEMP_WARN1_EN), + GASKET_SYSFS_RW(temp_warn2, sysfs_show, sysfs_store, ATTR_TEMP_WARN2), + GASKET_SYSFS_RW(temp_warn2_en, sysfs_show, sysfs_store, + ATTR_TEMP_WARN2_EN), GASKET_END_OF_ATTR_ARRAY }; @@ -711,17 +816,17 @@ static int apex_pci_probe(struct pci_dev *pci_dev, // Enable thermal sensor clocks gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_OMC0_D0, 0x1, 1, 7); + APEX_BAR2_REG_OMC0_D0, 0x1, 1, 7); // Enable thermal sensor (ENAD ENVR ENBG) gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_OMC0_D8, 0x7, 3, 0); + APEX_BAR2_REG_OMC0_D8, 0x7, 3, 0); // Enable OMC thermal sensor controller // This bit should be asserted 100 us after ENAD ENVR ENBG schedule_timeout(usecs_to_jiffies(100)); gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX, - APEX_BAR2_REG_OMC0_DC, 0x1, 1, 0); + APEX_BAR2_REG_OMC0_DC, 0x1, 1, 0); ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device, apex_sysfs_attrs); diff --git a/gasket_sysfs.h b/gasket_sysfs.h index 151e8ed..e8f29a3 100644 --- a/gasket_sysfs.h +++ b/gasket_sysfs.h @@ -79,6 +79,13 @@ struct gasket_sysfs_attribute { .data.attr_type = _attr_type \ } +#define GASKET_SYSFS_RW(_name, _show_function, _store_function, _attr_type) \ + { \ + .attr = __ATTR(_name, S_IWUSR | S_IWGRP | S_IRUGO, \ + _show_function, _store_function), \ + .data.attr_type = _attr_type \ + } + /* Initializes the Gasket sysfs subsystem. * * Description: Performs one-time initialization. Must be called before usage