* [PATCH 0/3] thermal: add devm_ version of thermal_zone register and driver for max77620 @ 2016-03-04 13:40 Laxman Dewangan 2016-03-04 13:40 ` [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Laxman Dewangan ` (2 more replies) 0 siblings, 3 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-04 13:40 UTC (permalink / raw) To: edubezval, rui.zhang, corbet Cc: rklein, linux-doc, linux-kernel, linux-pm, Laxman Dewangan The series add the devm_ version of thermal_zone_of_sensor_register/unregister and use this in new thermal driver for max77620. The header file for max77620 is part of MFD patch https://lkml.org/lkml/2016/2/11/186 Laxman Dewangan (3): thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register thermal: Add devm_thermal_zone_of_sensor_register() in managed devices list thermal: max77620: Add thermal driver for reporting junction temp Documentation/driver-model/devres.txt | 4 + drivers/thermal/Kconfig | 9 ++ drivers/thermal/Makefile | 1 + drivers/thermal/of-thermal.c | 81 ++++++++++++++++++ drivers/thermal/thermal-max77620.c | 151 ++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 18 ++++ 6 files changed, 264 insertions(+) create mode 100644 drivers/thermal/thermal-max77620.c -- 2.1.4 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register 2016-03-04 13:40 [PATCH 0/3] thermal: add devm_ version of thermal_zone register and driver for max77620 Laxman Dewangan @ 2016-03-04 13:40 ` Laxman Dewangan 2016-03-08 21:29 ` Eduardo Valentin 2016-03-04 13:40 ` [PATCH 2/3] thermal: Add devm_thermal_zone_of_sensor_register() in managed devices list Laxman Dewangan 2016-03-04 13:40 ` [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp Laxman Dewangan 2 siblings, 1 reply; 9+ messages in thread From: Laxman Dewangan @ 2016-03-04 13:40 UTC (permalink / raw) To: edubezval, rui.zhang, corbet Cc: rklein, linux-doc, linux-kernel, linux-pm, Laxman Dewangan Add resource managed version of thermal_zone_of_sensor_register() and thermal_zone_of_sensor_unregister(). This helps in reducing the code size in error path, remove of driver remove callbacks and making proper sequence for deallocations. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> --- drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 18 ++++++++++ 2 files changed, 99 insertions(+) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 9043f8f..1d9f8dc 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -555,6 +555,87 @@ void thermal_zone_of_sensor_unregister(struct device *dev, } EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); +static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res) +{ + thermal_zone_of_sensor_unregister(dev, + *(struct thermal_zone_device **)res); +} + +static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res, + void *data) +{ + struct thermal_zone_device **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +/** + * devm_thermal_zone_of_sensor_register - Resource managed version of + * thermal_zone_of_sensor_register() + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @sensor_id: a sensor identifier, in case the sensor IP has more + * than one sensors + * @data: a private pointer (owned by the caller) that will be passed + * back, when a temperature reading is needed. + * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. + * + * Refer thermal_zone_of_sensor_register() for more details. + * + * Return: On success returns a valid struct thermal_zone_device, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + * Registered hermal_zone_device device will automatically be + * released when device is unbounded. + */ +struct thermal_zone_device * +devm_thermal_zone_of_sensor_register(struct device *dev, int sensor_id, + void *data, const struct thermal_zone_of_device_ops *ops) +{ + struct thermal_zone_device **ptr, *tzd; + + ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops); + if (IS_ERR(tzd)) { + devres_free(ptr); + return tzd; + } + + *ptr = tzd; + devres_add(dev, ptr); + + return tzd; +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register); + +/** + * devm_thermal_zone_of_sensor_unregister - Resource managed version of + * thermal_zone_of_sensor_unregister(). + * @dev: Device for which which resource was allocated. + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. + * + * This function removes the sensor callbacks and private data from the + * thermal zone device registered with devm_thermal_zone_of_sensor_register() + * API. It will also silent the zone by remove the .get_temp() and .get_trend() + * thermal zone device callbacks. + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tzd) +{ + WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release, + devm_thermal_zone_of_sensor_match, tzd)); +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister); + /*** functions parsing device tree nodes ***/ /** diff --git a/include/linux/thermal.h b/include/linux/thermal.h index e13a1ac..4c43b21 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -362,6 +362,11 @@ thermal_zone_of_sensor_register(struct device *dev, int id, void *data, const struct thermal_zone_of_device_ops *ops); void thermal_zone_of_sensor_unregister(struct device *dev, struct thermal_zone_device *tz); +struct thermal_zone_device * +devm_thermal_zone_of_sensor_register(struct device *dev, int id, void *data, + const struct thermal_zone_of_device_ops *ops); +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz); #else static inline struct thermal_zone_device * thermal_zone_of_sensor_register(struct device *dev, int id, void *data, @@ -376,6 +381,19 @@ void thermal_zone_of_sensor_unregister(struct device *dev, { } +static inline struct thermal_zone_device * +devm_thermal_zone_of_sensor_register(struct device *dev, int id, void *data, + const struct thermal_zone_of_device_ops *ops) +{ + return ERR_PTR(-ENODEV); +} + +static inline +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz) +{ +} + #endif #if IS_ENABLED(CONFIG_THERMAL) -- 2.1.4 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register 2016-03-04 13:40 ` [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Laxman Dewangan @ 2016-03-08 21:29 ` Eduardo Valentin 2016-03-09 12:10 ` Laxman Dewangan 0 siblings, 1 reply; 9+ messages in thread From: Eduardo Valentin @ 2016-03-08 21:29 UTC (permalink / raw) To: Laxman Dewangan Cc: rui.zhang, corbet, rklein, linux-doc, linux-kernel, linux-pm Hello Laxman, Minor as follows. Can you please run ./scripts/checkpatch.pl --strict on this and remove the warnings, errors, checks? On Fri, Mar 04, 2016 at 07:10:08PM +0530, Laxman Dewangan wrote: > Add resource managed version of thermal_zone_of_sensor_register() and > thermal_zone_of_sensor_unregister(). > > This helps in reducing the code size in error path, remove of > driver remove callbacks and making proper sequence for deallocations. > > Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> > --- > drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/thermal.h | 18 ++++++++++ Could you also please document these under Documentation/thermal/sysfs-api.txt? > 2 files changed, 99 insertions(+) > > diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c > index 9043f8f..1d9f8dc 100644 > --- a/drivers/thermal/of-thermal.c > +++ b/drivers/thermal/of-thermal.c > @@ -555,6 +555,87 @@ void thermal_zone_of_sensor_unregister(struct device *dev, > } > EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); > > +static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res) > +{ > + thermal_zone_of_sensor_unregister(dev, > + *(struct thermal_zone_device **)res); > +} > + > +static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res, > + void *data) > +{ > + struct thermal_zone_device **r = res; > + > + if (WARN_ON(!r || !*r)) > + return 0; > + > + return *r == data; > +} > + > +/** > + * devm_thermal_zone_of_sensor_register - Resource managed version of > + * thermal_zone_of_sensor_register() > + * @dev: a valid struct device pointer of a sensor device. Must contain > + * a valid .of_node, for the sensor node. > + * @sensor_id: a sensor identifier, in case the sensor IP has more > + * than one sensors > + * @data: a private pointer (owned by the caller) that will be passed > + * back, when a temperature reading is needed. > + * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. > + * > + * Refer thermal_zone_of_sensor_register() for more details. > + * > + * Return: On success returns a valid struct thermal_zone_device, > + * otherwise, it returns a corresponding ERR_PTR(). Caller must > + * check the return value with help of IS_ERR() helper. > + * Registered hermal_zone_device device will automatically be > + * released when device is unbounded. > + */ > +struct thermal_zone_device * > +devm_thermal_zone_of_sensor_register(struct device *dev, int sensor_id, > + void *data, const struct thermal_zone_of_device_ops *ops) > +{ > + struct thermal_zone_device **ptr, *tzd; > + > + ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr), > + GFP_KERNEL); > + if (!ptr) > + return ERR_PTR(-ENOMEM); > + > + tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops); > + if (IS_ERR(tzd)) { > + devres_free(ptr); > + return tzd; > + } > + > + *ptr = tzd; > + devres_add(dev, ptr); > + > + return tzd; > +} > +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register); > + > +/** > + * devm_thermal_zone_of_sensor_unregister - Resource managed version of > + * thermal_zone_of_sensor_unregister(). > + * @dev: Device for which which resource was allocated. > + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. > + * > + * This function removes the sensor callbacks and private data from the > + * thermal zone device registered with devm_thermal_zone_of_sensor_register() > + * API. It will also silent the zone by remove the .get_temp() and .get_trend() > + * thermal zone device callbacks. > + * Normally this function will not need to be called and the resource > + * management code will ensure that the resource is freed. > + */ > +void devm_thermal_zone_of_sensor_unregister(struct device *dev, > + struct thermal_zone_device *tzd) > +{ > + WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release, > + devm_thermal_zone_of_sensor_match, tzd)); > +} > +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister); > + > /*** functions parsing device tree nodes ***/ > > /** > diff --git a/include/linux/thermal.h b/include/linux/thermal.h > index e13a1ac..4c43b21 100644 > --- a/include/linux/thermal.h > +++ b/include/linux/thermal.h > @@ -362,6 +362,11 @@ thermal_zone_of_sensor_register(struct device *dev, int id, void *data, > const struct thermal_zone_of_device_ops *ops); > void thermal_zone_of_sensor_unregister(struct device *dev, > struct thermal_zone_device *tz); > +struct thermal_zone_device * > +devm_thermal_zone_of_sensor_register(struct device *dev, int id, void *data, > + const struct thermal_zone_of_device_ops *ops); > +void devm_thermal_zone_of_sensor_unregister(struct device *dev, > + struct thermal_zone_device *tz); > #else > static inline struct thermal_zone_device * > thermal_zone_of_sensor_register(struct device *dev, int id, void *data, > @@ -376,6 +381,19 @@ void thermal_zone_of_sensor_unregister(struct device *dev, > { > } > > +static inline struct thermal_zone_device * > +devm_thermal_zone_of_sensor_register(struct device *dev, int id, void *data, > + const struct thermal_zone_of_device_ops *ops) > +{ > + return ERR_PTR(-ENODEV); > +} > + > +static inline > +void devm_thermal_zone_of_sensor_unregister(struct device *dev, > + struct thermal_zone_device *tz) > +{ > +} > + > #endif > > #if IS_ENABLED(CONFIG_THERMAL) > -- > 2.1.4 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register 2016-03-08 21:29 ` Eduardo Valentin @ 2016-03-09 12:10 ` Laxman Dewangan 0 siblings, 0 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-09 12:10 UTC (permalink / raw) To: Eduardo Valentin Cc: rui.zhang, corbet, rklein, linux-doc, linux-kernel, linux-pm Hi Edurado, Thanks for review. On Wednesday 09 March 2016 02:59 AM, Eduardo Valentin wrote: > Hello Laxman, > > > Minor as follows. > > Can you please run ./scripts/checkpatch.pl --strict on this and remove > the warnings, errors, checks? Taken from existing function and so borrowed the error. Will fix in next revision. > > On Fri, Mar 04, 2016 at 07:10:08PM +0530, Laxman Dewangan wrote: >> Add resource managed version of thermal_zone_of_sensor_register() and >> thermal_zone_of_sensor_unregister(). >> >> This helps in reducing the code size in error path, remove of >> driver remove callbacks and making proper sequence for deallocations. >> >> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> >> --- >> drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ >> include/linux/thermal.h | 18 ++++++++++ > Could you also please document these under > Documentation/thermal/sysfs-api.txt? > > Sure, I saw that thermal_zone_of_sensor_register/unregister is also not documented. So I will add the details for this first and then add for newly added interfaces. Will take care in next series. ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/3] thermal: Add devm_thermal_zone_of_sensor_register() in managed devices list 2016-03-04 13:40 [PATCH 0/3] thermal: add devm_ version of thermal_zone register and driver for max77620 Laxman Dewangan 2016-03-04 13:40 ` [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Laxman Dewangan @ 2016-03-04 13:40 ` Laxman Dewangan 2016-03-04 13:40 ` [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp Laxman Dewangan 2 siblings, 0 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-04 13:40 UTC (permalink / raw) To: edubezval, rui.zhang, corbet Cc: rklein, linux-doc, linux-kernel, linux-pm, Laxman Dewangan thermal_zone_of_sensor_register() and thermal_zone_of_sensor_unregister() gained their devm_ wrappers. Add these APIs in the list of managed devices. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> --- Documentation/driver-model/devres.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 5930d9a..dd7ce58 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -342,6 +342,10 @@ SLAVE DMA ENGINE SPI devm_spi_register_master() +THERMAL + devm_thermal_zone_of_sensor_register() + devm_thermal_zone_of_sensor_unregister() + WATCHDOG devm_watchdog_register_device() devm_watchdog_unregister_device() -- 2.1.4 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp 2016-03-04 13:40 [PATCH 0/3] thermal: add devm_ version of thermal_zone register and driver for max77620 Laxman Dewangan 2016-03-04 13:40 ` [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Laxman Dewangan 2016-03-04 13:40 ` [PATCH 2/3] thermal: Add devm_thermal_zone_of_sensor_register() in managed devices list Laxman Dewangan @ 2016-03-04 13:40 ` Laxman Dewangan 2016-03-04 14:04 ` Laxman Dewangan 2016-03-08 21:24 ` Eduardo Valentin 2 siblings, 2 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-04 13:40 UTC (permalink / raw) To: edubezval, rui.zhang, corbet Cc: rklein, linux-doc, linux-kernel, linux-pm, Laxman Dewangan Maxim Semiconductor Max77620 supports alarm interrupts when its die temperature crosses 120C and 140C. These threshold temperatures are not configurable. Add thermal driver to register PMIC die temperature as thermal zone sensor and capture the die temperature warning interrupts to notifying the client. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> --- drivers/thermal/Kconfig | 9 +++ drivers/thermal/Makefile | 1 + drivers/thermal/thermal-max77620.c | 151 +++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 drivers/thermal/thermal-max77620.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5e7c97a..faba1a3 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -194,6 +194,15 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config MAX77620_THERMAL + tristate "Temperature sensor driver for Maxim MAX77620 PMIC" + depends on MFD_MAX77620 + depends on OF + help + Support for die junction temperature warning alarm for Maxim + Semiconductor PMIC MAX77620 device. Device generates alert + signal/interrupt when die temperature cross its threshold. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 8e9cbc3..c6bc2bd 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_MAX77620_THERMAL) += thermal-max77620.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o diff --git a/drivers/thermal/thermal-max77620.c b/drivers/thermal/thermal-max77620.c new file mode 100644 index 0000000..846da62 --- /dev/null +++ b/drivers/thermal/thermal-max77620.c @@ -0,0 +1,151 @@ +/* + * Junction temperature thermal driver for Maxim Max77620. + * + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * Mallikarjun Kasoju <mkasoju@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/max77620.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/thermal.h> + +#define MAX77620_NORMAL_OPERATING_TEMP 100000 +#define MAX77620_TJALARM1_TEMP 120000 +#define MAX77620_TJALARM1_TEMP 140000 + +struct max77620_therm_info { + struct device *dev; + struct regmap *rmap; + struct thermal_zone_device *tz_device; + int irq_tjalarm1; + int irq_tjalarm2; +}; + +static int max77620_thermal_read_temp(void *data, int *temp) +{ + struct max77620_therm_info *mtherm = data; + unsigned int val; + int ret; + + ret = regmap_read(mtherm->rmap, MAX77620_REG_STATLBT, &val); + if (ret < 0) { + dev_err(mtherm->dev, "Failed to read STATLBT, %d\n", ret); + return -EINVAL; + } + + if (val & MAX77620_IRQ_TJALRM2_MASK) + *temp = MAX77620_TJALARM2_TEMP; + else if (val & MAX77620_IRQ_TJALRM1_MASK) + *temp = MAX77620_TJALARM1_TEMP; + else + *temp = MAX77620_NORMAL_OPERATING_TEMP; + return 0; +} + +static const struct thermal_zone_of_device_ops max77620_thermal_ops = { + .get_temp = max77620_thermal_read_temp, +}; + +static irqreturn_t max77620_thermal_irq(int irq, void *data) +{ + struct max77620_therm_info *mtherm = data; + + if (irq == mtherm->irq_tjalarm1) + dev_warn(mtherm->dev, "Junction Temp Alarm1(120C) occurred\n"); + else if (irq == mtherm->irq_tjalarm2) + dev_warn(mtherm->dev, "Junction Temp Alarm2(140C) occurred\n"); + + thermal_zone_device_update(mtherm->tz_device); + + return IRQ_HANDLED; +} + +static int max77620_thermal_probe(struct platform_device *pdev) +{ + struct max77620_therm_info *mtherm; + int ret; + + if (!pdev->dev.of_node) + pdev->dev.of_node = pdev->dev.parent->of_node; + + mtherm = devm_kzalloc(&pdev->dev, sizeof(*mtherm), GFP_KERNEL); + if (!mtherm) + return -ENOMEM; + + mtherm->irq_tjalarm1 = platform_get_irq(pdev, 0); + mtherm->irq_tjalarm2 = platform_get_irq(pdev, 1); + if ((mtherm->irq_tjalarm1 < 0) || (mtherm->irq_tjalarm2 < 0)) { + dev_err(&pdev->dev, "Alarm irq number not available\n"); + return -EINVAL; + } + + mtherm->dev = &pdev->dev; + mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mtherm->rmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, + mtherm, &max77620_thermal_ops); + if (IS_ERR(mtherm->tz_device)) { + ret = PTR_ERR(mtherm->tz_device); + dev_err(&pdev->dev, "Failed to register thermal zone, %d\n", + ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL, + max77620_thermal_irq, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&pdev->dev), mtherm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq1, %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm2, NULL, + max77620_thermal_irq, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&pdev->dev), mtherm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq2, %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, mtherm); + return 0; +} + +static struct platform_device_id max77620_thermal_devtype[] = { + { .name = "max77620-thermal", }, + {}, +}; + +static struct platform_driver max77620_thermal_driver = { + .driver = { + .name = "max77620-thermal", + }, + .probe = max77620_thermal_probe, + .id_table = max77620_thermal_devtype, +}; + +module_platform_driver(max77620_thermal_driver); + +MODULE_DESCRIPTION("Max77620 Junction temperature Thermal driver"); +MODULE_ALIAS("platform:max77620-thermal"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>"); +MODULE_LICENSE("GPL v2"); -- 2.1.4 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp 2016-03-04 13:40 ` [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp Laxman Dewangan @ 2016-03-04 14:04 ` Laxman Dewangan 2016-03-08 21:24 ` Eduardo Valentin 1 sibling, 0 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-04 14:04 UTC (permalink / raw) To: edubezval, rui.zhang, corbet; +Cc: rklein, linux-doc, linux-kernel, linux-pm On Friday 04 March 2016 07:10 PM, Laxman Dewangan wrote: > > > +#include <linux/regmap.h> > +#include <linux/slab.h> > +#include <linux/thermal.h> > + > +#define MAX77620_NORMAL_OPERATING_TEMP 100000 > +#define MAX77620_TJALARM1_TEMP 120000 > +#define MAX77620_TJALARM1_TEMP 140000 > Oops, Second one is MAX77620_TJALARM2_TEMP. Will send other version once I will have some more feedback. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp 2016-03-04 13:40 ` [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp Laxman Dewangan 2016-03-04 14:04 ` Laxman Dewangan @ 2016-03-08 21:24 ` Eduardo Valentin 2016-03-09 12:34 ` Laxman Dewangan 1 sibling, 1 reply; 9+ messages in thread From: Eduardo Valentin @ 2016-03-08 21:24 UTC (permalink / raw) To: Laxman Dewangan Cc: rui.zhang, corbet, rklein, linux-doc, linux-kernel, linux-pm Hello Laxman, Thanks for working on this. Impressed how simplified these drivers are becoming. I really liked you added the so waited devm_ helpers. Very minor comments as follows (now that you will send a new version anyway). On Fri, Mar 04, 2016 at 07:10:10PM +0530, Laxman Dewangan wrote: > Maxim Semiconductor Max77620 supports alarm interrupts when > its die temperature crosses 120C and 140C. These threshold > temperatures are not configurable. > > Add thermal driver to register PMIC die temperature as thermal > zone sensor and capture the die temperature warning interrupts > to notifying the client. Are any of these critical? > > Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> > --- > drivers/thermal/Kconfig | 9 +++ > drivers/thermal/Makefile | 1 + > drivers/thermal/thermal-max77620.c | 151 +++++++++++++++++++++++++++++++++++++ Given that it is a DT based driver, please add also a binding entry under Documentation/devicetree/bindings/thermal/ > 3 files changed, 161 insertions(+) > create mode 100644 drivers/thermal/thermal-max77620.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > index 5e7c97a..faba1a3 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -194,6 +194,15 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs when the > passive trip is crossed. > > +config MAX77620_THERMAL > + tristate "Temperature sensor driver for Maxim MAX77620 PMIC" > + depends on MFD_MAX77620 Can this be COMPILE_TEST'ed? > + depends on OF > + help > + Support for die junction temperature warning alarm for Maxim > + Semiconductor PMIC MAX77620 device. Device generates alert > + signal/interrupt when die temperature cross its threshold. > + Somehow checkpatch.pl --strict is complaining about this entry. Can you please check? > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > index 8e9cbc3..c6bc2bd 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -36,6 +36,7 @@ obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o > obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_MAX77620_THERMAL) += thermal-max77620.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/thermal-max77620.c b/drivers/thermal/thermal-max77620.c > new file mode 100644 > index 0000000..846da62 > --- /dev/null > +++ b/drivers/thermal/thermal-max77620.c > @@ -0,0 +1,151 @@ > +/* > + * Junction temperature thermal driver for Maxim Max77620. > + * > + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. > + * > + * Author: Laxman Dewangan <ldewangan@nvidia.com> > + * Mallikarjun Kasoju <mkasoju@nvidia.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + */ > + > +#include <linux/irq.h> > +#include <linux/interrupt.h> > +#include <linux/mfd/max77620.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/slab.h> > +#include <linux/thermal.h> > + > +#define MAX77620_NORMAL_OPERATING_TEMP 100000 > +#define MAX77620_TJALARM1_TEMP 120000 > +#define MAX77620_TJALARM1_TEMP 140000 > + > +struct max77620_therm_info { > + struct device *dev; > + struct regmap *rmap; > + struct thermal_zone_device *tz_device; > + int irq_tjalarm1; > + int irq_tjalarm2; > +}; > + > +static int max77620_thermal_read_temp(void *data, int *temp) > +{ > + struct max77620_therm_info *mtherm = data; > + unsigned int val; > + int ret; > + > + ret = regmap_read(mtherm->rmap, MAX77620_REG_STATLBT, &val); > + if (ret < 0) { > + dev_err(mtherm->dev, "Failed to read STATLBT, %d\n", ret); > + return -EINVAL; > + } > + > + if (val & MAX77620_IRQ_TJALRM2_MASK) > + *temp = MAX77620_TJALARM2_TEMP; > + else if (val & MAX77620_IRQ_TJALRM1_MASK) > + *temp = MAX77620_TJALARM1_TEMP; > + else > + *temp = MAX77620_NORMAL_OPERATING_TEMP; So, no way at all to get a temp? > + return 0; > +} > + > +static const struct thermal_zone_of_device_ops max77620_thermal_ops = { > + .get_temp = max77620_thermal_read_temp, > +}; > + > +static irqreturn_t max77620_thermal_irq(int irq, void *data) > +{ > + struct max77620_therm_info *mtherm = data; > + > + if (irq == mtherm->irq_tjalarm1) > + dev_warn(mtherm->dev, "Junction Temp Alarm1(120C) occurred\n"); > + else if (irq == mtherm->irq_tjalarm2) > + dev_warn(mtherm->dev, "Junction Temp Alarm2(140C) occurred\n"); > + > + thermal_zone_device_update(mtherm->tz_device); > + > + return IRQ_HANDLED; > +} > + > +static int max77620_thermal_probe(struct platform_device *pdev) > +{ > + struct max77620_therm_info *mtherm; > + int ret; > + > + if (!pdev->dev.of_node) > + pdev->dev.of_node = pdev->dev.parent->of_node; Why is this needed? > + > + mtherm = devm_kzalloc(&pdev->dev, sizeof(*mtherm), GFP_KERNEL); > + if (!mtherm) > + return -ENOMEM; > + > + mtherm->irq_tjalarm1 = platform_get_irq(pdev, 0); > + mtherm->irq_tjalarm2 = platform_get_irq(pdev, 1); > + if ((mtherm->irq_tjalarm1 < 0) || (mtherm->irq_tjalarm2 < 0)) { > + dev_err(&pdev->dev, "Alarm irq number not available\n"); > + return -EINVAL; > + } > + > + mtherm->dev = &pdev->dev; > + mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL); > + if (!mtherm->rmap) { > + dev_err(&pdev->dev, "Failed to get parent regmap\n"); > + return -ENODEV; > + } > + > + mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, > + mtherm, &max77620_thermal_ops); > + if (IS_ERR(mtherm->tz_device)) { > + ret = PTR_ERR(mtherm->tz_device); > + dev_err(&pdev->dev, "Failed to register thermal zone, %d\n", > + ret); > + return ret; > + } > + > + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL, > + max77620_thermal_irq, > + IRQF_ONESHOT | IRQF_SHARED, > + dev_name(&pdev->dev), mtherm); > + if (ret < 0) { > + dev_err(&pdev->dev, "Failed to request irq1, %d\n", ret); > + return ret; > + } > + > + ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm2, NULL, > + max77620_thermal_irq, > + IRQF_ONESHOT | IRQF_SHARED, > + dev_name(&pdev->dev), mtherm); > + if (ret < 0) { > + dev_err(&pdev->dev, "Failed to request irq2, %d\n", ret); > + return ret; > + } > + > + platform_set_drvdata(pdev, mtherm); nit: empty line here. > + return 0; > +} > + > +static struct platform_device_id max77620_thermal_devtype[] = { > + { .name = "max77620-thermal", }, > + {}, > +}; > + > +static struct platform_driver max77620_thermal_driver = { > + .driver = { > + .name = "max77620-thermal", > + }, > + .probe = max77620_thermal_probe, > + .id_table = max77620_thermal_devtype, > +}; > + > +module_platform_driver(max77620_thermal_driver); > + > +MODULE_DESCRIPTION("Max77620 Junction temperature Thermal driver"); > +MODULE_ALIAS("platform:max77620-thermal"); > +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); > +MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.4 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp 2016-03-08 21:24 ` Eduardo Valentin @ 2016-03-09 12:34 ` Laxman Dewangan 0 siblings, 0 replies; 9+ messages in thread From: Laxman Dewangan @ 2016-03-09 12:34 UTC (permalink / raw) To: Eduardo Valentin Cc: rui.zhang, corbet, rklein, linux-doc, linux-kernel, linux-pm On Wednesday 09 March 2016 02:54 AM, Eduardo Valentin wrote: > > On Fri, Mar 04, 2016 at 07:10:10PM +0530, Laxman Dewangan wrote: >> Maxim Semiconductor Max77620 supports alarm interrupts when >> its die temperature crosses 120C and 140C. These threshold >> temperatures are not configurable. >> >> Add thermal driver to register PMIC die temperature as thermal >> zone sensor and capture the die temperature warning interrupts >> to notifying the client. > Are any of these critical? Datasheet says that two alarm interrupt at 120 and 140degC. 165 degC is shutdown temp on which PMIC get shutdown. So just says as the warning interrupt. > >> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> >> --- >> drivers/thermal/Kconfig | 9 +++ >> drivers/thermal/Makefile | 1 + >> drivers/thermal/thermal-max77620.c | 151 +++++++++++++++++++++++++++++++++++++ > Given that it is a DT based driver, please add also a binding entry > under Documentation/devicetree/bindings/thermal/ There is no new DT property and so did not added. But will add the doc saying the mandatory properties from thermal framework i.e. #thermal-sensor-cells > > + depends on MFD_MAX77620 > Can this be COMPILE_TEST'ed? Yes, I compile and tested . >> + depends on OF >> + help >> + Support for die junction temperature warning alarm for Maxim >> + Semiconductor PMIC MAX77620 device. Device generates alert >> + signal/interrupt when die temperature cross its threshold. >> + > Somehow checkpatch.pl --strict is complaining about this entry. Can you > please check? The help should be minimum 4 lines otherwise warning is generated. I made it for next patch. Second warning is: /** WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #57: new file mode 100644 total: 0 errors, 1 warnings, 0 checks, 174 lines checked 0001-thermal-max77620-Add-thermal-driver-for-reporting-ju.patch has style problems, please review. **/ This is because new file get added and I think we can ignore it. >> + if (val & MAX77620_IRQ_TJALRM2_MASK) >> + *temp = MAX77620_TJALARM2_TEMP; >> + else if (val & MAX77620_IRQ_TJALRM1_MASK) >> + *temp = MAX77620_TJALARM1_TEMP; >> + else >> + *temp = MAX77620_NORMAL_OPERATING_TEMP; > So, no way at all to get a temp? yaah, there is no way other than getting the bit for whether temp crossed threshold or not. > >> + >> + if (!pdev->dev.of_node) >> + pdev->dev.of_node = pdev->dev.parent->of_node; > Why is this needed? This driver is sub mfd devices and it is registered without device node pointer. The DT binding doc for the mfdmax77620 is flat, does not have thermal sub node. hence to get the of_node for sensor, I am making the device node as node pointer for thermal sensor. I can overwrite as pdev->dev.of_node = pdev->dev.parent->of_node also without check for simplification. ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2016-03-09 12:47 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-03-04 13:40 [PATCH 0/3] thermal: add devm_ version of thermal_zone register and driver for max77620 Laxman Dewangan 2016-03-04 13:40 ` [PATCH 1/3] thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Laxman Dewangan 2016-03-08 21:29 ` Eduardo Valentin 2016-03-09 12:10 ` Laxman Dewangan 2016-03-04 13:40 ` [PATCH 2/3] thermal: Add devm_thermal_zone_of_sensor_register() in managed devices list Laxman Dewangan 2016-03-04 13:40 ` [PATCH 3/3] thermal: max77620: Add thermal driver for reporting junction temp Laxman Dewangan 2016-03-04 14:04 ` Laxman Dewangan 2016-03-08 21:24 ` Eduardo Valentin 2016-03-09 12:34 ` Laxman Dewangan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).