WindCharger: Added temp sensor for lm95071 device.
Change-Id: I5481381e3669a651736c25fa1ef6cf157ea91e97
diff --git a/arch/mips/configs/gfwc100_defconfig b/arch/mips/configs/gfwc100_defconfig
index 5599129..a72fbc3 100644
--- a/arch/mips/configs/gfwc100_defconfig
+++ b/arch/mips/configs/gfwc100_defconfig
@@ -190,7 +190,8 @@
CONFIG_SPI=y
CONFIG_SPI_ATH79=y
CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+CONFIG_SENSORS_LM95071=y
CONFIG_WATCHDOG=y
CONFIG_ATH79_WDT=m
# CONFIG_HID_SUPPORT is not set
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index dad895f..018fc29 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -674,6 +674,16 @@
This driver can also be built as a module. If so, the module
will be called lm93.
+config SENSORS_LM95071
+ tristate "National Semiconductor LM95071"
+ depends on HWMON && EXPERIMENTAL
+ help
+ If you say yes here you get support for National Semiconductor LM95071
+ sensor chip. This is a coldplug device, and as such it is assumed that the
+ board implementation will handle setup.
+
+ This driver can also be built as a module and will be called lm95071.
+
config SENSORS_LTC4151
tristate "Linear Technology LTC4151"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8..aa38e2a 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -81,6 +81,7 @@
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
+obj-$(CONFIG_SENSORS_LM95071) += lm95071.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
diff --git a/drivers/hwmon/lm95071.c b/drivers/hwmon/lm95071.c
new file mode 100644
index 0000000..301cdf2
--- /dev/null
+++ b/drivers/hwmon/lm95071.c
@@ -0,0 +1,160 @@
+/*
+ * 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;
+ 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;
+ }
+ 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:
+ 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);