blob: de12293da17315d513a5aeb41992c105a0fa5547 [file] [log] [blame]
/*
* Copyright (C) 2015, Google, Inc.
*
* The LM95071 is a three-pin SPI-enabled temperature sensor.
* Datasheet can be found here:
* http://www.ti.com/lit/gpn/lm95071
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/hwmon.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/hwmon-sysfs.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#define DEVNAME "lm95071"
#define DEVID 0x800f
#define LM95071_CC 0x0000
struct lm95071 {
struct device *hwmon_dev;
};
static ssize_t lm95071_show_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "%s\n", DEVNAME);
}
static DEVICE_ATTR(name, S_IRUGO, lm95071_show_name, NULL);
static ssize_t lm95071_show_temp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int ret;
s64 temp;
u16 sign;
u8 rx_buf[2];
u16 raw_temp = 0;
struct spi_device *spi = to_spi_device(dev);
ret = spi_write_then_read(spi, NULL, 0, rx_buf, ARRAY_SIZE(rx_buf));
if (ret < 0) {
return ret;
}
/* Temperature Conversion */
raw_temp = (rx_buf[0] << 8) | rx_buf[1];
sign = 0x8000 & raw_temp;
if (sign) {
raw_temp = ~raw_temp + 1;
}
/*
* LM90571 Temp register has two unused bits at the end. After these are
* removed, every number remaining corresponds to 0.03125 C of temperature.
* This is increased by three orders of five orders of magnitude to make math
* simple, then divided by 100 to convert to millidigrees.
*
* Official docs here: http://www.ti.com/lit/ds/symlink/lm95071.pdf
*/
temp = raw_temp >> 2;
temp = (temp * 1000) >> 5;
return sprintf(buf, "%lld\n", sign ? -temp : temp);
}
static DEVICE_ATTR(temp1_input, S_IRUGO, lm95071_show_temp, NULL);
/*
* Before continuous conversion mode is activated, the sensor will return its
* ID whenever 16 bits are read.
*/
static int lm95071_detect(struct spi_device *spi)
{
u16 id;
u8 rx_buf[2];
spi_write_then_read(spi, NULL, 0, rx_buf, ARRAY_SIZE(rx_buf));
id = (rx_buf[0] << 8) | rx_buf[1];
if (id != DEVID) {
return -ENODEV;
}
return 0;
}
static int lm95071_activate_cc(struct spi_device *spi)
{
u8 tx_buf[2];
u8 rx_buf[2];
tx_buf[0] = (LM95071_CC >> 8) & 0xff;
tx_buf[1] = LM95071_CC & 0xff;
return spi_write_then_read(spi, tx_buf, ARRAY_SIZE(tx_buf),
rx_buf, ARRAY_SIZE(rx_buf));
}
static int lm95071_probe(struct spi_device *spi)
{
struct lm95071 *lm_dev;
int err = 0;
printk(KERN_INFO "lm95071: Probing for device\n");
if ((err = lm95071_detect(spi)) || (err = lm95071_activate_cc(spi))) {
goto exit;
}
lm_dev = kzalloc(sizeof(*lm_dev), GFP_KERNEL);
if (!lm_dev) {
err = -ENOMEM;
goto exit;
}
lm_dev->hwmon_dev = hwmon_device_register(&spi->dev);
if (IS_ERR(lm_dev->hwmon_dev)) {
err = PTR_ERR(lm_dev->hwmon_dev);
goto hwmon_dev_reg_fail;
}
spi_set_drvdata(spi, lm_dev);
if ((err = device_create_file(&spi->dev, &dev_attr_temp1_input)) ||
(err = device_create_file(&spi->dev, &dev_attr_name))) {
goto sysfs_create_fail;
}
printk(KERN_INFO "lm95071: Found device\n");
return 0;
sysfs_create_fail:
device_remove_file(&spi->dev, &dev_attr_temp1_input);
hwmon_device_unregister(lm_dev->hwmon_dev);
hwmon_dev_reg_fail:
spi_set_drvdata(spi, NULL);
kfree(lm_dev);
exit:
if (err == -ENODEV) {
printk(KERN_ERR "lm95071: Device not found\n");
} else {
printk(KERN_ERR "lm95071: Probe failed (%d)\n", err);
}
return err;
}
static int lm95071_remove(struct spi_device *spi)
{
struct lm95071 *lm_dev = spi_get_drvdata(spi);
device_remove_file(&spi->dev, &dev_attr_temp1_input);
device_remove_file(&spi->dev, &dev_attr_name);
hwmon_device_unregister(lm_dev->hwmon_dev);
spi_set_drvdata(spi, NULL);
kfree(lm_dev);
return 0;
}
/* Driver data. */
static const struct spi_device_id lm95071_id[] = {
{ DEVNAME, 0 },
{ },
};
static struct spi_driver lm95071_driver = {
.driver = {
.name = DEVNAME,
.owner = THIS_MODULE,
},
.id_table = lm95071_id,
.probe = lm95071_probe,
.remove = lm95071_remove,
};
module_spi_driver(lm95071_driver);