Thread (13 messages) 13 messages, 4 authors, 2013-06-28
STALE4765d

[PATCH 3/4] hwmon: Add a simple driver to read the MXS SoC temperature

From: Alexandre Belloni <hidden>
Date: 2013-06-26 08:52:31
Also in: linux-arm-kernel, lkml
Subsystem: documentation, hardware monitoring, open firmware and flattened device tree bindings, the rest · Maintainers: Jonathan Corbet, Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Torvalds

The low resolution ADC of the mxs is able to read an internal temperature
sensor, expose that using hwmon.

Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/hwmon/mxs-cputemp.txt      |  18 +++
 Documentation/hwmon/mxs-cputemp                    |  29 +++++
 drivers/hwmon/Kconfig                              |  10 ++
 drivers/hwmon/Makefile                             |   1 +
 drivers/hwmon/mxs-cputemp.c                        | 132 +++++++++++++++++++++
 5 files changed, 190 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/hwmon/mxs-cputemp.txt
 create mode 100644 Documentation/hwmon/mxs-cputemp
 create mode 100644 drivers/hwmon/mxs-cputemp.c
diff --git a/Documentation/devicetree/bindings/hwmon/mxs-cputemp.txt b/Documentation/devicetree/bindings/hwmon/mxs-cputemp.txt
new file mode 100644
index 0000000..7d3ae47
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/mxs-cputemp.txt
@@ -0,0 +1,18 @@
+mxs cputemp hwmon sensors
+-------------------------
+
+See: Documentation/hwmon/mxs-cputemp
+
+Required properties:
+- compatible: should be "fsl,mxs-internal-temp"
+- io-channels: should list the two adc channels needed to calculate the
+	       temperature
+- io-channel-names: should map the previously listed adc channels to the "min"
+		    and "max" value
+
+Example:
+	temp {
+		compatible = "fsl,mxs-internal-temp";
+		io-channels = <&lradc 8>, <&lradc 9>;
+		io-channel-names = "min", "max";
+	};
diff --git a/Documentation/hwmon/mxs-cputemp b/Documentation/hwmon/mxs-cputemp
new file mode 100644
index 0000000..6c6201f
--- /dev/null
+++ b/Documentation/hwmon/mxs-cputemp
@@ -0,0 +1,29 @@
+Kernel driver mxs-cputemp
+=========================
+
+Supported chips:
+  * Freescale i.mx28
+    Datasheet: i.MX28 Applications Processor Reference Manual, Rev. 1, 2010
+    	       http://cache.freescale.com/files/dsp/doc/ref_manual/MCIMX28RM.pdf
+
+Author: Alexandre Belloni
+
+Description
+-----------
+This driver permits reading the internal die temperature sensor embedded inside
+Freescale i.mx28 SoCs. This sensor is read through two channels of the on chip
+Low-Resolution ADC. After calculation, the three-sigma error of the temperature
+sensor should be within ± 1.5% in degrees Kelvin. Additionally, the temperature
+sampling has a three-sigma sample-to-sample variation of 2 degrees Kelvin. If
+desired, this error can be removed by oversampling and averaging the temperature
+result.
+
+The formula is:
+	(Channel9 – Channel8) * Gain_correction/4
+
+As recommended by the datasheet, Gain_correction is equal to 1.012.
+
+sysfs entries
+-------------
+temp1_input	Measured and corrected temperature in millidegrees Celsius
+
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0428e8a..2daf794 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -929,6 +929,16 @@ config SENSORS_MCP3021
 	  This driver can also be built as a module.  If so, the module
 	  will be called mcp3021.
 
+config SENSORS_MXS_CPU
+	tristate "MXS internal CPU temperature sensor"
+	depends on MXS_LRADC
+	help
+	  If you say yes here you get support for the i.mx28 internal
+	  temperature sensor.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called mxs-cputemp
+
 config SENSORS_NCT6775
 	tristate "Nuvoton NCT6775F and compatibles"
 	depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d17d3e6..366c92d 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
+obj-$(CONFIG_SENSORS_MXS_CPU)	+= mxs-cputemp.o
 obj-$(CONFIG_SENSORS_NCT6775)	+= nct6775.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
diff --git a/drivers/hwmon/mxs-cputemp.c b/drivers/hwmon/mxs-cputemp.c
new file mode 100644
index 0000000..a312fb5
--- /dev/null
+++ b/drivers/hwmon/mxs-cputemp.c
@@ -0,0 +1,132 @@
+/*
+ * Driver for the mxs internal temperature sensor
+ *
+ * Copyright 2013 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#define DRVNAME "mxs-hwmon"
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/iio/consumer.h>
+
+#define GAIN_CORRECTION 1012
+
+/* The value we calculate from the ADCs is in Kelvins, don't forget to convert
+ * it to Celsius */
+#define VALUES_TO_MILLIC(min, max) ((max - min) * GAIN_CORRECTION / 4 - 272150)
+
+struct mxs_hwmon_data {
+	struct device *hwmon_dev;
+	struct iio_channel *chan_min;
+	struct iio_channel *chan_max;
+};
+
+static int mxs_hwmon_show_temp(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	int err, val_min, val_max;
+
+	struct mxs_hwmon_data *data = dev_get_drvdata(dev);
+
+	err = iio_read_channel_raw(data->chan_min, &val_min);
+	if (err < 0)
+		return err;
+
+	err = iio_read_channel_raw(data->chan_max, &val_max);
+	if (err < 0)
+		return err;
+
+	return sprintf(buf, "%u\n", VALUES_TO_MILLIC(val_min, val_max));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, mxs_hwmon_show_temp, NULL);
+
+static int mxs_hwmon_probe(struct platform_device *pdev)
+{
+	int err;
+	struct mxs_hwmon_data *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, data);
+
+	err = device_create_file(&pdev->dev, &dev_attr_temp1_input);
+	if (err)
+		return err;
+
+	data->chan_min = iio_channel_get(&pdev->dev, "min");
+	if (IS_ERR(data->chan_min)) {
+		err = PTR_ERR(data->chan_min);
+		goto error_chan_min;
+	}
+
+	data->chan_max = iio_channel_get(&pdev->dev, "max");
+	if (IS_ERR(data->chan_max)) {
+		err = PTR_ERR(data->chan_max);
+		goto error_chan_max;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error_hwmon;
+	}
+
+	return 0;
+
+error_hwmon:
+	iio_channel_release(data->chan_max);
+error_chan_max:
+	iio_channel_release(data->chan_min);
+error_chan_min:
+	device_remove_file(&pdev->dev, &dev_attr_temp1_input);
+
+	return err;
+}
+
+static int mxs_hwmon_remove(struct platform_device *pdev)
+{
+	struct mxs_hwmon_data *data = platform_get_drvdata(pdev);
+
+	iio_channel_release(data->chan_min);
+	iio_channel_release(data->chan_max);
+	hwmon_device_unregister(data->hwmon_dev);
+
+	device_remove_file(&pdev->dev, &dev_attr_temp1_input);
+
+	return 0;
+}
+
+static struct of_device_id mxs_hwmon_of_match[] = {
+	{ .compatible = "fsl,mxs-internal-temp", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mxs_hwmon_of_match);
+
+static struct platform_driver mxs_hwmon_driver = {
+	.probe = mxs_hwmon_probe,
+	.remove = mxs_hwmon_remove,
+	.driver	= {
+		.name = DRVNAME,
+		.owner = THIS_MODULE,
+		.of_match_table = mxs_hwmon_of_match,
+	},
+};
+
+module_platform_driver(mxs_hwmon_driver);
+
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Freescale i.MX28 hwmon sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mxs-hwmon");
-- 
1.8.1.2
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help