diff options
author | Rajagopala V <rajagopala.v@stericsson.com> | 2011-08-25 13:27:42 +0530 |
---|---|---|
committer | Robert Marklund <robert.marklund@stericsson.com> | 2011-10-05 12:52:59 +0200 |
commit | 678e3ff19b5ecb4bb721b483d2ac7d32fe96998a (patch) | |
tree | a13a74aee8aa4f78ddac0c4d945d66bd7f3fdaf1 | |
parent | 0c59264379c98030b33989d5846199159d89fd42 (diff) |
abx500: hwmon: temperature monitor support for AB5500
Includes support for xtal temp, pcb temp and die temp
monitoring
ST-Ericsson Linux next: NA
ST-Ericsson ID: WP257616 & WP351655
ST-Ericsson FOSS-OUT ID: NA
Change-Id: I7668fb36df957b66929bfd13a4b6ad0386036aa1
Signed-off-by: Rajagopala V <rajagopala.v@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/28139
Reviewed-by: QATEST
Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r-- | drivers/hwmon/Kconfig | 14 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/ab5500.c | 190 | ||||
-rw-r--r-- | drivers/hwmon/abx500.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/abx500.h | 6 | ||||
-rwxr-xr-x | drivers/mfd/ab5500-core.c | 13 | ||||
-rw-r--r-- | include/linux/mfd/abx500.h | 1 |
7 files changed, 226 insertions, 1 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index cba0d3ec649..45b00f5d589 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -50,7 +50,19 @@ config SENSORS_AB8500 used to access sensors outside the AB8500 chip. This driver can also be built as a module. If so, the module - will be called ab8500-temp. + will be called abx500-temp. + +config SENSORS_AB5500 + tristate "AB5500 thermal monitoring" + depends on AB5500_GPADC + default n + help + If you say yes here you get support for the thermal sensor part + of the AB5500 chip. The driver includes thermal management for + AB5500 die, pcb and RF XTAL temperature. + + This driver can also be built as a module. If so, the module + will be called abx500-temp. config SENSORS_DB8500 tristate "DB8500 thermal monitoring" diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 049b99a9192..2e09b4b9545 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o obj-$(CONFIG_SENSORS_W83791D) += w83791d.o obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o +obj-$(CONFIG_SENSORS_AB5500) += abx500.o ab5500.o obj-$(CONFIG_SENSORS_DB8500) += db8500.o obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o diff --git a/drivers/hwmon/ab5500.c b/drivers/hwmon/ab5500.c new file mode 100644 index 00000000000..f229d103ec1 --- /dev/null +++ b/drivers/hwmon/ab5500.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Martin Persson <martin.persson@stericsson.com> for + * ST-Ericsson. + * License terms: GNU Gereral Public License (GPL) version 2 + * + * Note: + * + * If/when the AB5500 thermal warning temperature is reached (threshold + * 125C cannot be changed by SW), an interrupt is set and the driver + * notifies user space via a sysfs event. If a shut down is not + * triggered by user space and temperature reaches beyond critical + * limit(130C) pm_power off is called. + * + * If/when AB5500 thermal shutdown temperature is reached a hardware + * shutdown of the AB5500 will occur. + */ + +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/sysfs.h> +#include <linux/hwmon-sysfs.h> +#include <linux/platform_device.h> +#include <linux/mfd/abx500/ab5500-gpadc.h> +#include "abx500.h" + +/* AB5500 driver monitors GPADC - XTAL_TEMP, PCB_TEMP, + * BTEMP_BALL, BAT_CTRL and DIE_TEMP + */ +#define NUM_MONITORED_SENSORS 5 + +#define SHUTDOWN_AUTO_MIN_LIMIT -25 +#define SHUTDOWN_AUTO_MAX_LIMIT 130 + +static int ab5500_output_convert(int val, u8 sensor) +{ + int res = val; + /* GPADC returns die temperature in Celsius + * convert it to millidegree celsius + */ + if (sensor == DIE_TEMP) + res = val * 1000; + + return res; +} + +static int ab5500_read_sensor(struct abx500_temp *data, u8 sensor) +{ + /* + * TODO: Add support for BAT_CTRL node, since this + * temperature measurement is more complex than just + * an ADC readout + */ + int val = ab5500_gpadc_convert(data->ab5500_gpadc, sensor); + if (val < 0) + return val; + else + return ab5500_output_convert(val, sensor); +} + +static ssize_t ab5500_show_name(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "ab5500\n"); +} + +static ssize_t ab5500_show_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + char *name; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int index = attr->index; + + /* + * Make sure these labels correspond to the attribute indexes + * used when calling SENSOR_DEVICE_ATRR. + * Temperature sensors outside ab8500 (read via GPADC) are marked + * with prefix ext_ + */ + switch (index) { + case 1: + name = "xtal_temp"; + break; + case 2: + name = "pcb_temp"; + break; + case 3: + name = "bat_temp"; + break; + case 4: + name = "bat_ctrl"; + break; + case 5: + name = "ab5500"; + break; + default: + return -EINVAL; + } + return sprintf(buf, "%s\n", name); +} + +static int temp_shutdown_trig(int mux) +{ + pm_power_off(); + return 0; +} + +static int ab5500_temp_shutdown_auto(struct abx500_temp *data) +{ + int ret; + struct adc_auto_input *auto_ip; + + auto_ip = kzalloc(sizeof(struct adc_auto_input), GFP_KERNEL); + if (!auto_ip) { + dev_err(&data->pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + auto_ip->mux = DIE_TEMP; + auto_ip->freq = MS500; + auto_ip->min = SHUTDOWN_AUTO_MIN_LIMIT; + auto_ip->max = SHUTDOWN_AUTO_MAX_LIMIT; + auto_ip->auto_adc_callback = temp_shutdown_trig; + data->gpadc_auto = auto_ip; + ret = ab5500_gpadc_convert_auto(data->ab5500_gpadc, + data->gpadc_auto); + if (ret < 0) + kfree(auto_ip); + + return ret; +} + +static int ab5500_temp_irq_handler(int irq, struct abx500_temp *data) +{ + /* + * Make sure the magic numbers below corresponds to the node + * used for AB5500 thermal warning from HW. + */ + mutex_lock(&data->lock); + data->crit_alarm[4] = 1; + mutex_unlock(&data->lock); + sysfs_notify(&data->pdev->dev.kobj, NULL, "temp5_crit_alarm"); + dev_info(&data->pdev->dev, "ABX500 thermal warning," + " power off system now!\n"); + return 0; +} + +int __init abx500_hwmon_init(struct abx500_temp *data) +{ + int err; + + data->ab5500_gpadc = ab5500_gpadc_get("ab5500-adc.0"); + if (IS_ERR(data->ab5500_gpadc)) + return PTR_ERR(data->ab5500_gpadc); + + err = ab5500_temp_shutdown_auto(data); + if (err < 0) { + dev_err(&data->pdev->dev, "Failed to register" + " auto trigger(%d)\n", err); + return err; + } + + /* + * Setup HW defined data. + * + * Reference hardware (HREF): + * + * XTAL_TEMP, PCB_TEMP, BTEMP_BALL refer to millivolts and + * BAT_CTRL and DIE_TEMP refer to millidegrees + * + * Make sure indexes correspond to the attribute indexes + * used when calling SENSOR_DEVICE_ATRR + */ + data->gpadc_addr[0] = XTAL_TEMP; + data->gpadc_addr[1] = PCB_TEMP; + data->gpadc_addr[2] = BTEMP_BALL; + data->gpadc_addr[3] = BAT_CTRL; + data->gpadc_addr[4] = DIE_TEMP; + data->monitored_sensors = NUM_MONITORED_SENSORS; + + data->ops.read_sensor = ab5500_read_sensor; + data->ops.irq_handler = ab5500_temp_irq_handler; + data->ops.show_name = ab5500_show_name; + data->ops.show_label = ab5500_show_label; + + return 0; +} diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c index 9d522ef6f62..6666dc27065 100644 --- a/drivers/hwmon/abx500.c +++ b/drivers/hwmon/abx500.c @@ -623,6 +623,7 @@ exit_platform_data: hwmon_device_unregister(data->hwmon_dev); platform_set_drvdata(pdev, NULL); exit: + kfree(data->gpadc_auto); kfree(data); return err; } @@ -635,6 +636,7 @@ static int __devexit abx500_temp_remove(struct platform_device *pdev) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group); platform_set_drvdata(pdev, NULL); + kfree(data->gpadc_auto); kfree(data); return 0; } diff --git a/drivers/hwmon/abx500.h b/drivers/hwmon/abx500.h index a089a63939d..1d41aa191fe 100644 --- a/drivers/hwmon/abx500.h +++ b/drivers/hwmon/abx500.h @@ -10,7 +10,9 @@ #define NUM_SENSORS 5 struct ab8500_gpadc; +struct ab5500_gpadc; struct ab8500_btemp; +struct adc_auto_input; struct abx500_temp; /** @@ -34,7 +36,9 @@ struct abx500_temp_ops { * @pdev: platform device * @hwmon_dev: hwmon device * @ab8500_gpadc: gpadc interface for ab8500 + * @ab5500_gpadc: gpadc interface for ab5500 * @btemp: battery temperature interface for ab8500 + * @adc_auto_input: gpadc auto trigger * @gpadc_addr: gpadc channel address * @temp: sensor temperature input value * @min: sensor temperature min value @@ -57,7 +61,9 @@ struct abx500_temp { struct platform_device *pdev; struct device *hwmon_dev; struct ab8500_gpadc *ab8500_gpadc; + struct ab5500_gpadc *ab5500_gpadc; struct ab8500_btemp *ab8500_btemp; + struct adc_auto_input *gpadc_auto; struct abx500_temp_ops ops; u8 gpadc_addr[NUM_SENSORS]; unsigned long temp[NUM_SENSORS]; diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index 189f4b66bfa..9c47f075962 100755 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -1389,6 +1389,19 @@ static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = { }, }, }, + [AB5500_DEVID_TEMPMON] = { + .name = "abx500-temp", + .id = AB5500_DEVID_TEMPMON, + .num_resources = 1, + .resources = (struct resource[]) { + { + .name = "ABX500_TEMP_WARM", + .flags = IORESOURCE_IRQ, + .start = AB5500_IRQ(2, 2), + .end = AB5500_IRQ(2, 2), + }, + }, + }, }; /* diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 7a1d3179f6a..e99a3d177ea 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -230,6 +230,7 @@ enum ab5500_devid { AB5500_DEVID_ONSWA, AB5500_DEVID_CHARGALG, AB5500_DEVID_BTEMP, + AB5500_DEVID_TEMPMON, AB5500_NUM_DEVICES, }; |