From 081804a132de6802f64daf8af6704b21abeb86eb Mon Sep 17 00:00:00 2001 From: Jan Luebbe <jlu@pengutronix.de> Date: Sun, 21 Jul 2013 00:27:27 +0200 Subject: [PATCH 21/23] hwmon: add driver for the AM335x bandgap temperature sensor Signed-off-by: Jan Luebbe <jlu@pengutronix.de> --- Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt | 12 arch/arm/boot/dts/am33xx.dtsi | 5 drivers/hwmon/Kconfig | 7 drivers/hwmon/Makefile | 1 drivers/hwmon/am335x-bandgap.c | 164 +++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt create mode 100644 drivers/hwmon/am335x-bandgap.c Index: linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt =================================================================== @ linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt:4 @ +TI AM335x bandgap temperature sensor +------------------------------------ + +Requires node properties: +- compatible: Should be "ti,am335x-bandgap" +- reg: Should contain registers location and length + +Example: + bandgap@44e10448 { + compatible = "ti,am335x-bandgap"; + reg = <0x44e10448 0x8>; + }; Index: linux-3.12.24-rt38-r8s8/arch/arm/boot/dts/am33xx.dtsi =================================================================== --- linux-3.12.24-rt38-r8s8.orig/arch/arm/boot/dts/am33xx.dtsi +++ linux-3.12.24-rt38-r8s8/arch/arm/boot/dts/am33xx.dtsi @ linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt:759 @ interrupts = <37>; resets = <&prcm 0>; }; + + bandgap@44e10448 { + compatible = "ti,am335x-bandgap"; + reg = <0x44e10448 0x8>; + }; }; }; Index: linux-3.12.24-rt38-r8s8/drivers/hwmon/Kconfig =================================================================== --- linux-3.12.24-rt38-r8s8.orig/drivers/hwmon/Kconfig +++ linux-3.12.24-rt38-r8s8/drivers/hwmon/Kconfig @ linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt:267 @ config SENSORS_ADT7475 This driver can also be build as a module. If so, the module will be called adt7475. +config SENSORS_AM335X_BANDGAP + tristate "Texas Instruments AM335x SoC temperature sensor" + depends on SOC_AM33XX + help + If you say yes here you get support for the temperature + sensor found on the AM335x line of SoCs from Texas Instruments. + config SENSORS_ASC7621 tristate "Andigilog aSC7621" depends on I2C Index: linux-3.12.24-rt38-r8s8/drivers/hwmon/Makefile =================================================================== --- linux-3.12.24-rt38-r8s8.orig/drivers/hwmon/Makefile +++ linux-3.12.24-rt38-r8s8/drivers/hwmon/Makefile @ linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt:45 @ obj-$(CONFIG_SENSORS_ADT7411) += adt7411 obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o +obj-$(CONFIG_SENSORS_AM335X_BANDGAP) += am335x-bandgap.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o Index: linux-3.12.24-rt38-r8s8/drivers/hwmon/am335x-bandgap.c =================================================================== --- /dev/null +++ linux-3.12.24-rt38-r8s8/drivers/hwmon/am335x-bandgap.c @ linux-3.12.24-rt38-r8s8/Documentation/devicetree/bindings/hwmon/am335x-bandgap.txt:4 @ +/* + * Copyright (c) 2013 Jan Luebbe <j.luebbe@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/sysfs.h> + +#define DRV_NAME "am335x-bandgap" + +#define BANDGAP_CTRL 0x0 +#define BANDGAP_CTRL_DTEMP_MASK 0x0000FF00 +#define BANDGAP_CTRL_DTEMP_OFF 8 +#define BANDGAP_CTRL_BGROFF BIT(6) +#define BANDGAP_CTRL_SOC BIT(4) +#define BANDGAP_CTRL_CLRZ BIT(3) /* 0 = clear */ +#define BANDGAP_CTRL_CONTCONV BIT(2) +#define BANDGAP_CTRL_ECOZ BIT(1) +#define BANDGAP_CTRL_TSHUT BIT(0) + +#define BANDGAP_TRIM 0x4 +#define BANDGAP_TRIM_DTRBGAPC_MASK 0xFF000000 +#define BANDGAP_TRIM_DTRBGAPC_OFF 24 +#define BANDGAP_TRIM_DTRBGAPV_MASK 0x00FF0000 +#define BANDGAP_TRIM_DTRBGAPV_OFF 16 +#define BANDGAP_TRIM_DTRTEMPS_MASK 0x0000FF00 +#define BANDGAP_TRIM_DTRTEMPS_OFF 8 +#define BANDGAP_TRIM_DTRTEMPSC_MASK 0x000000FF +#define BANDGAP_TRIM_DTRTEMPSC_OFF 0 + +struct am335x_bandgap { + u32 __iomem *regs; + struct device *hwmon_dev; +}; + +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + return sprintf(buf, "%s\n", DRV_NAME); +} + +static ssize_t show_input(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct am335x_bandgap *data = dev_get_drvdata(dev); + u32 val, temp; + + /* read measurement */ + val = readl(data->regs + BANDGAP_CTRL); + + /* compute temperature */ + val = (val & BANDGAP_CTRL_DTEMP_MASK) >> BANDGAP_CTRL_DTEMP_OFF; + temp = val * 1000; + + return sprintf(buf, "%d\n", temp); +} + +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0); + +struct attribute *am335x_bandgap_attributes[] = { + &sensor_dev_attr_name.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group am335x_bandgap_group = { + .attrs = am335x_bandgap_attributes, +}; + +static int am335x_bandgap_probe(struct platform_device *pdev) +{ + struct am335x_bandgap *data; + struct resource *res; + int err; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + data->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!data->regs) + return -ENODEV; + + platform_set_drvdata(pdev, data); + + err = sysfs_create_group(&pdev->dev.kobj, &am335x_bandgap_group); + if (err < 0) { + dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err); + return err; + } + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + dev_err(&pdev->dev, "Class registration failed (%d)\n", err); + goto exit_sysfs_group; + } + + /* enable HW sensor */ + writel(BANDGAP_CTRL_SOC | BANDGAP_CTRL_CLRZ | BANDGAP_CTRL_CONTCONV, + data->regs + BANDGAP_CTRL); + + return 0; + +exit_sysfs_group: + sysfs_remove_group(&pdev->dev.kobj, &am335x_bandgap_group); + return err; +} + +static int am335x_bandgap_remove(struct platform_device *pdev) +{ + struct am335x_bandgap *data = platform_get_drvdata(pdev); + + /* disable HW sensor */ + writel(0x0, data->regs + BANDGAP_CTRL); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&pdev->dev.kobj, &am335x_bandgap_group); + + return 0; +} + +static const struct of_device_id am335x_bandgap_match[] = { + { .compatible = "ti,am335x-bandgap" }, + {}, +}; + +static struct platform_driver am335x_bandgap_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = of_match_ptr(am335x_bandgap_match), + }, + .probe = am335x_bandgap_probe, + .remove = am335x_bandgap_remove, +}; + +module_platform_driver(am335x_bandgap_driver); + +MODULE_AUTHOR("Jan Luebbe <j.luebbe@pengutronix.de>"); +MODULE_DESCRIPTION("AM335x temperature sensor driver"); +MODULE_LICENSE("GPL");