From: Tiberiu Breana <tiberiu.a.breana@intel.com>
To: lm-sensors@vger.kernel.org
Subject: [lm-sensors] [PATCH 2/2] hwmon: (max31722) Add alarm support
Date: Tue, 22 Mar 2016 11:41:05 +0000 [thread overview]
Message-ID: <1458646865-6416-3-git-send-email-tiberiu.a.breana@intel.com> (raw)
Add temperature threshold alarm support for the max31722
sensor driver.
Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
---
Documentation/hwmon/max31722 | 7 +++
drivers/hwmon/max31722.c | 130 +++++++++++++++++++++++++++++++++++++++++--
2 files changed, 131 insertions(+), 6 deletions(-)
diff --git a/Documentation/hwmon/max31722 b/Documentation/hwmon/max31722
index 090da845..e247963 100644
--- a/Documentation/hwmon/max31722
+++ b/Documentation/hwmon/max31722
@@ -25,6 +25,10 @@ Usage Notes
-----------
This driver uses ACPI to auto-detect devices. See ACPI IDs in the above section.
+The sensor supports a temperature alarm. This is set once the measured
+temperature goes above a user-set threshold (temp1_max) and will be cleared
+once the temperature goes below temp1_min. See the datasheet, page 9,
+"Comparator Mode" for details.
Sysfs entries
-------------
@@ -32,3 +36,6 @@ Sysfs entries
The following attribute is supported:
temp1_input Measured temperature. Read-only.
+temp1_alarm Temperature alarm. Read-only.
+temp1_min Minimum temperature threshold. Read-write.
+temp1_max Maximum temperature threshold. Read-write.
diff --git a/drivers/hwmon/max31722.c b/drivers/hwmon/max31722.c
index 13ba906..8e14eed 100644
--- a/drivers/hwmon/max31722.c
+++ b/drivers/hwmon/max31722.c
@@ -11,6 +11,8 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -20,13 +22,20 @@
#define MAX31722_REG_CFG 0x00
#define MAX31722_REG_TEMP_LSB 0x01
#define MAX31722_REG_TEMP_MSB 0x02
+#define MAX31722_REG_THIGH_LSB 0x03
+#define MAX31722_REG_TLOW_LSB 0x05
#define MAX31722_MAX_REG 0x86
#define MAX31722_MODE_CONTINUOUS 0x00
#define MAX31722_MODE_STANDBY 0x01
#define MAX31722_RESOLUTION_11BIT 0x02
+/* Minimum and maximum supported temperatures, in millidegrees */
+#define MAX31722_MIN_TEMP -55000
+#define MAX31722_MAX_TEMP 125000
+
#define MAX31722_REGMAP_NAME "max31722_regmap"
+#define MAX31722_GPIO "max31722_gpio"
#define MAX31722_REGFIELD(name) \
do { \
@@ -39,12 +48,27 @@
} \
} while (0)
+enum attr_index {
+ t_input,
+ t_min,
+ t_max,
+ t_alarm,
+ t_num_regs
+};
+
+static const u8 max31722_regs[t_num_regs] = {
+ [t_input] = MAX31722_REG_TEMP_LSB,
+ [t_min] = MAX31722_REG_TLOW_LSB,
+ [t_max] = MAX31722_REG_THIGH_LSB,
+};
+
struct max31722_data {
struct spi_device *spi_device;
struct device *hwmon_dev;
struct regmap *regmap;
struct regmap_field *reg_state;
struct regmap_field *reg_resolution;
+ bool alarm_active;
};
/*
@@ -117,9 +141,9 @@ static ssize_t max31722_show_name(struct device *dev,
return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
-static ssize_t max31722_show_temperature(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t max31722_show_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
{
int i;
int ret;
@@ -127,8 +151,10 @@ static ssize_t max31722_show_temperature(struct device *dev,
s16 val;
u16 temp;
struct max31722_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- ret = regmap_bulk_read(data->regmap, MAX31722_REG_TEMP_LSB, &temp, 2);
+ ret = regmap_bulk_read(data->regmap,
+ max31722_regs[attr->index], &temp, 2);
if (ret < 0) {
dev_err(&data->spi_device->dev,
"failed to read temperature register\n");
@@ -152,13 +178,79 @@ static ssize_t max31722_show_temperature(struct device *dev,
return sprintf(buf, "%d\n", val);
}
+static ssize_t max31722_set_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int i;
+ int ret;
+ int fract;
+ u16 thresh;
+ u8 lsb;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ long val;
+ struct max31722_data *data = dev_get_drvdata(dev);
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val < MAX31722_MIN_TEMP || val > MAX31722_MAX_TEMP)
+ return -EINVAL;
+ /*
+ * Convert input to a register value. First round down the value to one
+ * that can be represented in the 11 bit resolution.
+ */
+ val -= val % max31722_milli_table[2];
+
+ fract = val % 1000;
+
+ lsb = 0;
+ for (i = 0 ; i < ARRAY_SIZE(max31722_milli_table) && fract > 0; i++)
+ if (fract - max31722_milli_table[i] >= 0) {
+ fract -= max31722_milli_table[i];
+ lsb += 1 << (3 - i - 1);
+ }
+ lsb <<= 5;
+
+ thresh = (val / 1000) << 8 | lsb;
+ ret = regmap_bulk_write(data->regmap,
+ max31722_regs[attr->index], &thresh, 2);
+ if (ret < 0) {
+ dev_err(&data->spi_device->dev,
+ "failed to write threshold register\n");
+ return ret;
+ }
+
+ return count;
+}
+
+static ssize_t max31722_show_alarm(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct spi_device *spi_device = to_spi_device(dev);
+ struct max31722_data *data = spi_get_drvdata(spi_device);
+
+ return sprintf(buf, "%d\n", data->alarm_active ? 1 : 0);
+}
+
static DEVICE_ATTR(name, S_IRUGO, max31722_show_name, NULL);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
- max31722_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, max31722_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, max31722_show_temp,
+ max31722_set_temp, t_min);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, max31722_show_temp,
+ max31722_set_temp, t_max);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, max31722_show_alarm, NULL,
+ t_alarm);
+
static struct attribute *max31722_attributes[] = {
&dev_attr_name.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
NULL,
};
@@ -166,6 +258,18 @@ static const struct attribute_group max31722_group = {
.attrs = max31722_attributes,
};
+static irqreturn_t max31722_irq_handler(int irq, void *private)
+{
+ struct max31722_data *data = private;
+ /*
+ * The device will issue cyclical interrupts when the
+ * THIGH/TLOW thresholds are met.
+ */
+ data->alarm_active = !data->alarm_active;
+
+ return IRQ_HANDLED;
+}
+
static int max31722_init(struct max31722_data *data)
{
int ret = 0;
@@ -196,6 +300,8 @@ static int max31722_init(struct max31722_data *data)
if (ret < 0)
goto err;
+ data->alarm_active = false;
+
return 0;
err:
@@ -223,6 +329,18 @@ static int max31722_probe(struct spi_device *spi)
if (ret < 0)
goto err_standby;
+ if (spi->irq > 0) {
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq,
+ NULL,
+ max31722_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ dev_name(&spi->dev), data);
+ if (ret < 0) {
+ dev_err(&spi->dev, "request irq %d failed\n", spi->irq);
+ goto err_remove_group;
+ }
+ }
+
data->hwmon_dev = hwmon_device_register(&spi->dev);
if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
--
1.9.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
next reply other threads:[~2016-03-22 11:41 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-22 11:41 Tiberiu Breana [this message]
2016-03-22 14:56 ` [lm-sensors] [PATCH 2/2] hwmon: (max31722) Add alarm support Guenter Roeck
2016-03-29 15:35 ` Breana, Tiberiu A
2016-03-29 15:56 ` Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1458646865-6416-3-git-send-email-tiberiu.a.breana@intel.com \
--to=tiberiu.a.breana@intel.com \
--cc=lm-sensors@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.