forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.7 KiB
151 lines
3.7 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* max31722 - hwmon driver for Maxim Integrated MAX31722/MAX31723 SPI |
|
* digital thermometer and thermostats. |
|
* |
|
* Copyright (c) 2016, Intel Corporation. |
|
*/ |
|
|
|
#include <linux/hwmon.h> |
|
#include <linux/hwmon-sysfs.h> |
|
#include <linux/kernel.h> |
|
#include <linux/module.h> |
|
#include <linux/spi/spi.h> |
|
|
|
#define MAX31722_REG_CFG 0x00 |
|
#define MAX31722_REG_TEMP_LSB 0x01 |
|
|
|
#define MAX31722_MODE_CONTINUOUS 0x00 |
|
#define MAX31722_MODE_STANDBY 0x01 |
|
#define MAX31722_MODE_MASK 0xFE |
|
#define MAX31722_RESOLUTION_12BIT 0x06 |
|
#define MAX31722_WRITE_MASK 0x80 |
|
|
|
struct max31722_data { |
|
struct device *hwmon_dev; |
|
struct spi_device *spi_device; |
|
u8 mode; |
|
}; |
|
|
|
static int max31722_set_mode(struct max31722_data *data, u8 mode) |
|
{ |
|
int ret; |
|
struct spi_device *spi = data->spi_device; |
|
u8 buf[2] = { |
|
MAX31722_REG_CFG | MAX31722_WRITE_MASK, |
|
(data->mode & MAX31722_MODE_MASK) | mode |
|
}; |
|
|
|
ret = spi_write(spi, &buf, sizeof(buf)); |
|
if (ret < 0) { |
|
dev_err(&spi->dev, "failed to set sensor mode.\n"); |
|
return ret; |
|
} |
|
data->mode = (data->mode & MAX31722_MODE_MASK) | mode; |
|
|
|
return 0; |
|
} |
|
|
|
static ssize_t max31722_temp_show(struct device *dev, |
|
struct device_attribute *attr, char *buf) |
|
{ |
|
ssize_t ret; |
|
struct max31722_data *data = dev_get_drvdata(dev); |
|
|
|
ret = spi_w8r16(data->spi_device, MAX31722_REG_TEMP_LSB); |
|
if (ret < 0) |
|
return ret; |
|
/* Keep 12 bits and multiply by the scale of 62.5 millidegrees/bit. */ |
|
return sprintf(buf, "%d\n", (s16)le16_to_cpu(ret) * 125 / 32); |
|
} |
|
|
|
static SENSOR_DEVICE_ATTR_RO(temp1_input, max31722_temp, 0); |
|
|
|
static struct attribute *max31722_attrs[] = { |
|
&sensor_dev_attr_temp1_input.dev_attr.attr, |
|
NULL, |
|
}; |
|
|
|
ATTRIBUTE_GROUPS(max31722); |
|
|
|
static int max31722_probe(struct spi_device *spi) |
|
{ |
|
int ret; |
|
struct max31722_data *data; |
|
|
|
data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); |
|
if (!data) |
|
return -ENOMEM; |
|
|
|
spi_set_drvdata(spi, data); |
|
data->spi_device = spi; |
|
/* |
|
* Set SD bit to 0 so we can have continuous measurements. |
|
* Set resolution to 12 bits for maximum precision. |
|
*/ |
|
data->mode = MAX31722_MODE_CONTINUOUS | MAX31722_RESOLUTION_12BIT; |
|
ret = max31722_set_mode(data, MAX31722_MODE_CONTINUOUS); |
|
if (ret < 0) |
|
return ret; |
|
|
|
data->hwmon_dev = hwmon_device_register_with_groups(&spi->dev, |
|
spi->modalias, |
|
data, |
|
max31722_groups); |
|
if (IS_ERR(data->hwmon_dev)) { |
|
max31722_set_mode(data, MAX31722_MODE_STANDBY); |
|
return PTR_ERR(data->hwmon_dev); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int max31722_remove(struct spi_device *spi) |
|
{ |
|
struct max31722_data *data = spi_get_drvdata(spi); |
|
|
|
hwmon_device_unregister(data->hwmon_dev); |
|
|
|
return max31722_set_mode(data, MAX31722_MODE_STANDBY); |
|
} |
|
|
|
static int __maybe_unused max31722_suspend(struct device *dev) |
|
{ |
|
struct spi_device *spi_device = to_spi_device(dev); |
|
struct max31722_data *data = spi_get_drvdata(spi_device); |
|
|
|
return max31722_set_mode(data, MAX31722_MODE_STANDBY); |
|
} |
|
|
|
static int __maybe_unused max31722_resume(struct device *dev) |
|
{ |
|
struct spi_device *spi_device = to_spi_device(dev); |
|
struct max31722_data *data = spi_get_drvdata(spi_device); |
|
|
|
return max31722_set_mode(data, MAX31722_MODE_CONTINUOUS); |
|
} |
|
|
|
static SIMPLE_DEV_PM_OPS(max31722_pm_ops, max31722_suspend, max31722_resume); |
|
|
|
static const struct spi_device_id max31722_spi_id[] = { |
|
{"max31722", 0}, |
|
{"max31723", 0}, |
|
{} |
|
}; |
|
MODULE_DEVICE_TABLE(spi, max31722_spi_id); |
|
|
|
static struct spi_driver max31722_driver = { |
|
.driver = { |
|
.name = "max31722", |
|
.pm = &max31722_pm_ops, |
|
}, |
|
.probe = max31722_probe, |
|
.remove = max31722_remove, |
|
.id_table = max31722_spi_id, |
|
}; |
|
|
|
module_spi_driver(max31722_driver); |
|
|
|
MODULE_AUTHOR("Tiberiu Breana <[email protected]>"); |
|
MODULE_DESCRIPTION("max31722 sensor driver"); |
|
MODULE_LICENSE("GPL v2");
|
|
|