* [PATCH 0/6] thermal: iio bindings
@ 2015-09-26 22:05 Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 1/6] thermal: core: enhance thermal_zone_device_update Srinivas Pandruvada
` (6 more replies)
0 siblings, 7 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
v0
Since this was discussed during LPC in Seattle and three versions of RFC are
published and reviwed, this is posted as non RFC version. This has
changes in iio interface file as suggested by Jonathan. We may add threshold
event direction flag later if required, without much impact by adding new
event type.
RFC v2
- Rebase to 4.3.rc1
- Additional parameter to thermal_zone_device_update for event type
- Moved the dummy IIO callbacks to local include file, in this
way "not used" warnings can be avoided
- Remove changes from user space governor, rather notify from core
- Validate the trigger, so that when thermal device supports async
notifications, this will be exclusive trigger
- Use new thermal core event type to differentiate events for iio
threshold notification
RFC v1
- Change commit message to be more clear
- Split in three patches (First for thermal_iio.c, second to integrate
to thermal_core and third for user space governor).
- Removed IIO defines in thermal.h
- Removed direct push to buffers
- Other comments from Jonathan except introduce validate_trigger
RFC v0
Base version for first review
Srinivas Pandruvada (6):
thermal: core: enhance thermal_zone_device_update
thermal: documentation update
thermal: iio device for thermal sensor
thermal: use iio binding calls
thermal: iio Documentation
thermal: x86_pkg_temp: Register threshold callbacks
Documentation/thermal/sysfs-api.txt | 10 +
Documentation/thermal/thermal_iio_binding | 88 +++++
drivers/acpi/thermal.c | 2 +-
drivers/platform/x86/acerhdf.c | 2 +-
drivers/thermal/Kconfig | 12 +
drivers/thermal/Makefile | 1 +
drivers/thermal/db8500_thermal.c | 2 +-
drivers/thermal/hisi_thermal.c | 3 +-
drivers/thermal/imx_thermal.c | 4 +-
.../thermal/int340x_thermal/int340x_thermal_zone.h | 2 +-
drivers/thermal/intel_soc_dts_iosf.c | 3 +-
drivers/thermal/of-thermal.c | 2 +-
drivers/thermal/qcom-spmi-temp-alarm.c | 2 +-
drivers/thermal/rcar_thermal.c | 3 +-
drivers/thermal/rockchip_thermal.c | 3 +-
drivers/thermal/samsung/exynos_tmu.c | 2 +-
drivers/thermal/st/st_thermal_memmap.c | 3 +-
drivers/thermal/thermal_core.c | 21 +-
drivers/thermal/thermal_iio.c | 383 +++++++++++++++++++++
drivers/thermal/thermal_iio.h | 45 +++
drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 4 +-
drivers/thermal/x86_pkg_temp_thermal.c | 11 +-
include/linux/thermal.h | 26 +-
23 files changed, 609 insertions(+), 25 deletions(-)
create mode 100644 Documentation/thermal/thermal_iio_binding
create mode 100644 drivers/thermal/thermal_iio.c
create mode 100644 drivers/thermal/thermal_iio.h
--
2.4.3
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/6] thermal: core: enhance thermal_zone_device_update
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 2/6] thermal: documentation update Srinivas Pandruvada
` (5 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
thermal_zone_device_update is called by thermal core and clients to
trigger reading of temperature, evaluation of trips and take governor
specified actions. There can be number of reasons this may be triggered,
for example when HW calculates new temperature sample or violation of a
threshold. Since this is the only interface available for client drivers
to trigger thermal core actions, it should also should have a way to
specify the trigger event type.
This change adds additional parameter to specify event. This is optional
for the driver to specify event type, in that case this can be just
THERMAL_DEVICE_EVENT_NONE. Alternately they can select
THERMAL_DEVICE_EVENT_THRESHOLD for temperature threshold event,
THERMAL_DEVICE_EVENT_TEMP_SAMPLE for new temperature sample notification,
THERMAL_DEVICE_TRIP_TEMP_CHANGE for a temperature trip change.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/acpi/thermal.c | 2 +-
drivers/platform/x86/acerhdf.c | 2 +-
drivers/thermal/db8500_thermal.c | 2 +-
drivers/thermal/hisi_thermal.c | 3 ++-
drivers/thermal/imx_thermal.c | 4 ++--
drivers/thermal/int340x_thermal/int340x_thermal_zone.h | 2 +-
drivers/thermal/intel_soc_dts_iosf.c | 3 ++-
drivers/thermal/of-thermal.c | 2 +-
drivers/thermal/qcom-spmi-temp-alarm.c | 2 +-
drivers/thermal/rcar_thermal.c | 3 ++-
drivers/thermal/rockchip_thermal.c | 3 ++-
drivers/thermal/samsung/exynos_tmu.c | 2 +-
drivers/thermal/st/st_thermal_memmap.c | 3 ++-
drivers/thermal/thermal_core.c | 11 ++++++-----
drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 4 ++--
drivers/thermal/x86_pkg_temp_thermal.c | 3 ++-
include/linux/thermal.h | 13 +++++++++++--
17 files changed, 40 insertions(+), 24 deletions(-)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 30d8518..e4f547b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -520,7 +520,7 @@ static void acpi_thermal_check(void *data)
if (!tz->tz_enabled)
return;
- thermal_zone_device_update(tz->thermal_zone);
+ thermal_zone_device_update(tz->thermal_zone, THERMAL_DEVICE_EVENT_NONE);
}
/* sys I/F for generic thermal sysfs support */
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 460fa67..6382d4e 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -405,7 +405,7 @@ static inline void acerhdf_enable_kernelmode(void)
kernelmode = 1;
thz_dev->polling_delay = interval*1000;
- thermal_zone_device_update(thz_dev);
+ thermal_zone_device_update(thz_dev, THERMAL_DEVICE_EVENT_NONE);
pr_notice("kernel mode fan control ON\n");
}
diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c
index 652acd8..e4cbbe6 100644
--- a/drivers/thermal/db8500_thermal.c
+++ b/drivers/thermal/db8500_thermal.c
@@ -306,7 +306,7 @@ static void db8500_thermal_work(struct work_struct *work)
if (cur_mode == THERMAL_DEVICE_DISABLED)
return;
- thermal_zone_device_update(pzone->therm_dev);
+ thermal_zone_device_update(pzone->therm_dev, THERMAL_DEVICE_EVENT_NONE);
dev_dbg(&pzone->therm_dev->device, "thermal work finished.\n");
}
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 36d0729..65f3432 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -227,7 +227,8 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
mutex_unlock(&data->thermal_lock);
for (i = 0; i < HISI_MAX_SENSORS; i++)
- thermal_zone_device_update(data->sensors[i].tzd);
+ thermal_zone_device_update(data->sensors[i].tzd,
+ THERMAL_DEVICE_EVENT_NONE);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 4bec1d3..24b3aa6 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -249,7 +249,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
}
data->mode = mode;
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
return 0;
}
@@ -436,7 +436,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
dev_dbg(&data->tz->device, "THERMAL ALARM: T > %d\n",
data->alarm_temp / 1000);
- thermal_zone_device_update(data->tz);
+ thermal_zone_device_update(data->tz, THERMAL_DEVICE_EVENT_NONE);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
index aaadf72..2f93b85 100644
--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -62,7 +62,7 @@ static inline void *int340x_thermal_zone_get_priv_data(
static inline void int340x_thermal_zone_device_update(
struct int34x_thermal_zone *tzone)
{
- thermal_zone_device_update(tzone->zone);
+ thermal_zone_device_update(tzone->zone, THERMAL_DEVICE_EVENT_THRESHOLD);
}
#endif
diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c
index 5841d1d..4402ab0 100644
--- a/drivers/thermal/intel_soc_dts_iosf.c
+++ b/drivers/thermal/intel_soc_dts_iosf.c
@@ -392,7 +392,8 @@ void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
pr_debug("TZD update for zone %d\n", i);
- thermal_zone_device_update(sensors->soc_dts[i].tzone);
+ thermal_zone_device_update(sensors->soc_dts[i].tzone,
+ THERMAL_DEVICE_EVENT_THRESHOLD);
}
} else
spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 42b7d42..4168bf9 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -292,7 +292,7 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
mutex_unlock(&tz->lock);
data->mode = mode;
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
return 0;
}
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c
index b677aad..bf3da3c 100644
--- a/drivers/thermal/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom-spmi-temp-alarm.c
@@ -150,7 +150,7 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
{
struct qpnp_tm_chip *chip = data;
- thermal_zone_device_update(chip->tz_dev);
+ thermal_zone_device_update(chip->tz_dev, THERMAL_DEVICE_EVENT_NONE);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 5d4ae7d..2eac44a 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -308,7 +308,8 @@ static void rcar_thermal_work(struct work_struct *work)
rcar_thermal_get_temp(priv->zone, &nctemp);
if (nctemp != cctemp)
- thermal_zone_device_update(priv->zone);
+ thermal_zone_device_update(priv->zone,
+ THERMAL_DEVICE_EVENT_NONE);
}
static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index c89ffb2..b3d7214 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -361,7 +361,8 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
thermal->chip->irq_ack(thermal->regs);
for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
- thermal_zone_device_update(thermal->sensors[i].tzd);
+ thermal_zone_device_update(thermal->sensors[i].tzd,
+ THERMAL_DEVICE_EVENT_NONE);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 0bae8cc..80ccc92 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -223,7 +223,7 @@ static void exynos_report_trigger(struct exynos_tmu_data *p)
return;
}
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
mutex_lock(&tz->lock);
/* Find the level for which trip happened */
diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c
index fc0c9e1..45b6b9f 100644
--- a/drivers/thermal/st/st_thermal_memmap.c
+++ b/drivers/thermal/st/st_thermal_memmap.c
@@ -42,7 +42,8 @@ static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata)
{
struct st_thermal_sensor *sensor = sdata;
- thermal_zone_device_update(sensor->thermal_dev);
+ thermal_zone_device_update(sensor->thermal_dev,
+ THERMAL_DEVICE_EVENT_NONE);
return IRQ_HANDLED;
}
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5e5fc70..18e7802 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -536,7 +536,8 @@ static void update_temperature(struct thermal_zone_device *tz)
tz->last_temperature, tz->temperature);
}
-void thermal_zone_device_update(struct thermal_zone_device *tz)
+void thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_device_event_type event)
{
int count;
@@ -555,7 +556,7 @@ static void thermal_zone_device_check(struct work_struct *work)
struct thermal_zone_device *tz = container_of(work, struct
thermal_zone_device,
poll_queue.work);
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
}
/* sys I/F for thermal zone */
@@ -794,7 +795,7 @@ passive_store(struct device *dev, struct device_attribute *attr,
tz->forced_passive = state;
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
return count;
}
@@ -885,7 +886,7 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
}
if (!ret)
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
return ret ? ret : count;
}
@@ -1872,7 +1873,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_DEVICE_EVENT_NONE);
return tz;
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index b213a12..ab2a011 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -52,7 +52,7 @@ static void ti_thermal_work(struct work_struct *work)
struct ti_thermal_data *data = container_of(work,
struct ti_thermal_data, thermal_wq);
- thermal_zone_device_update(data->ti_thermal);
+ thermal_zone_device_update(data->ti_thermal, THERMAL_DEVICE_EVENT_NONE);
dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
data->ti_thermal->type);
@@ -205,7 +205,7 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
data->mode = mode;
ti_bandgap_write_update_interval(bgp, data->sensor_id,
data->ti_thermal->polling_delay);
- thermal_zone_device_update(data->ti_thermal);
+ thermal_zone_device_update(data->ti_thermal, THERMAL_DEVICE_EVENT_NONE);
dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
data->ti_thermal->polling_delay);
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 7fc919f..849f682 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -348,7 +348,8 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
}
if (notify) {
pr_debug("thermal_zone_device_update\n");
- thermal_zone_device_update(phdev->tzone);
+ thermal_zone_device_update(phdev->tzone,
+ THERMAL_DEVICE_EVENT_THRESHOLD);
}
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 17292fe..c074f6a 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -87,6 +87,13 @@ enum thermal_trend {
THERMAL_TREND_DROP_FULL, /* apply lowest cooling action */
};
+enum thermal_device_event_type {
+ THERMAL_DEVICE_EVENT_NONE, /* No specific reason */
+ THERMAL_DEVICE_EVENT_THRESHOLD, /* temp thereshold event */
+ THERMAL_DEVICE_EVENT_TEMP_SAMPLE, /* New temp sample notify */
+ THERMAL_DEVICE_TRIP_TEMP_CHANGE, /* trip temp change */
+};
+
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
@@ -393,7 +400,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
unsigned int);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
-void thermal_zone_device_update(struct thermal_zone_device *);
+void thermal_zone_device_update(struct thermal_zone_device *,
+ enum thermal_device_event_type);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
const struct thermal_cooling_device_ops *);
@@ -436,7 +444,8 @@ static inline int thermal_zone_unbind_cooling_device(
struct thermal_zone_device *tz, int trip,
struct thermal_cooling_device *cdev)
{ return -ENODEV; }
-static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
+static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_device_event_type)
{ }
static inline struct thermal_cooling_device *
thermal_cooling_device_register(char *type, void *devdata,
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/6] thermal: documentation update
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 1/6] thermal: core: enhance thermal_zone_device_update Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 3/6] thermal: iio device for thermal sensor Srinivas Pandruvada
` (4 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
Added description for thermal_zone_device_update, which is
already used by thermal core and client drivers.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
Documentation/thermal/sysfs-api.txt | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 10f062e..16770f0 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -494,3 +494,13 @@ platform data is provided, this uses the step_wise throttling policy.
This function serves as an arbitrator to set the state of a cooling
device. It sets the cooling device to the deepest cooling state if
possible.
+
+5.5:thermal_zone_device_update:
+This function is used by thermal core and thermal client drivers to trigger
+temperature read and governor specific processing for thermal trip violation.
+Using event type parameter, the caller can specify the reason for this call.
+This reason can be
+THERMAL_DEVICE_EVENT_NONE for unspecified reason
+THERMAL_DEVICE_EVENT_THRESHOLD for temp threshold event
+THERMAL_DEVICE_EVENT_TEMP_SAMPLE for new temperature sample notification
+THERMAL_DEVICE_TRIP_TEMP_CHANGE for notifying trip point temperature change
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/6] thermal: iio device for thermal sensor
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 1/6] thermal: core: enhance thermal_zone_device_update Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 2/6] thermal: documentation update Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-27 18:18 ` Jonathan Cameron
2015-12-31 19:18 ` Eduardo Valentin
2015-09-26 22:05 ` [PATCH 4/6] thermal: use iio binding calls Srinivas Pandruvada
` (3 subsequent siblings)
6 siblings, 2 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
This change registers temperature sensor in a thermal zone as an IIO
temperature device. This allows user space thermal application to fully
utilize IIO capability to read temperature events and samples.
The primary motivation for this change to improve performance for user
space thermal controllers like Linux thermal daemon or Intel® Dynamic
Platform and Thermal Framework (DPTF) for Chromium OS.
The current sysfs has several limitations, which forces the current
user space to use polling as the safe way. This polling causes performance
bottlenecks as some devices requires extremely aggressive response to
changing temperature conditions.
These are some limitations, which this change tries to address:
- Temperature reading via sysfs attribute, which needs conversion from
string to int
- No way to set threshold settings to avoid polling for temperature change
without using a RW passive trip point.
- Event notifications via slow kobject uevents, which needs parsing to id
the zone and read temperature
- Only pull interface from user space, kernel drivers can't send samples
- One sample at a time read from user space
These limitations can be addressed by registering temperature sensor
as an IIO device. IIO provides
- buffered access via /dev/iio:deviceX node with select/poll capability
- temperature thresholds setting via iio event thresholds
- Wait and receive events
- Able to use different external trigger (data ready indications) and push
samples to buffers
Next set of patches uses the IIO binding introduced in this patchset.
The iio device created during call to thermal_zone_device_register. Samples
are pushed to iio buffers when thermal_zone_device_update is called from
client drivers.
New thermal zone device callbacks:
It introduces three new callbacks for thermal client drivers:
get_threshold_temp: Get the current threshold temperature
set_threshold_temp: Set the current threshold temperature
check_notification_support: Inform that the client driver has asynchronous
notification mechanism. If it is then polling can be avoided for the
temperature sensor.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/thermal/Kconfig | 12 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/thermal_iio.c | 383 ++++++++++++++++++++++++++++++++++++++++++
drivers/thermal/thermal_iio.h | 45 +++++
include/linux/thermal.h | 13 ++
5 files changed, 454 insertions(+)
create mode 100644 drivers/thermal/thermal_iio.c
create mode 100644 drivers/thermal/thermal_iio.h
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 0390044..bc7836e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -29,6 +29,18 @@ config THERMAL_HWMON
Say 'Y' here if you want all thermal sensors to
have hwmon sysfs interface too.
+config THERMAL_IIO
+ bool
+ prompt "Thermal sensor from a zone as IIO sensor device"
+ select IIO
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ This will register thermal sensor in a zone as an IIO temperature
+ sensor device.
+ This will help user space thermal controllers to use IIO ABI to
+ get events and buffered acces to temperature samples.
+
config THERMAL_OF
bool
prompt "APIs to parse thermal data out of device tree"
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 26f1608..b72a28d 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
+thermal_sys-$(CONFIG_THERMAL_IIO) += thermal_iio.o
thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o
# governors
diff --git a/drivers/thermal/thermal_iio.c b/drivers/thermal/thermal_iio.c
new file mode 100644
index 0000000..492eaff
--- /dev/null
+++ b/drivers/thermal/thermal_iio.c
@@ -0,0 +1,383 @@
+/*
+ * thermal iio interface driver
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope 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/thermal.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+struct thermal_iio_data {
+ struct thermal_zone_device *tz;
+ struct iio_trigger *interrupt_trig;
+ struct iio_chan_spec *channels;
+ bool enable_trigger;
+ int temp_thres;
+ bool ev_enable_state;
+ struct mutex mutex;
+};
+
+static const struct iio_event_spec thermal_event = {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE)
+};
+
+static const struct iio_chan_spec thermal_iio_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ }
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1)
+};
+
+static const struct iio_chan_spec thermal_iio_channels_with_events[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ .event_spec = &thermal_event,
+ .num_event_specs = 1,
+
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1)
+};
+
+static int thermal_iio_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ int temp;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = thermal_zone_get_temp(iio_data->tz, &temp);
+ if (!ret) {
+ *val = temp;
+ ret = IIO_VAL_INT;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static irqreturn_t thermal_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ u32 buffer[4];
+ int temp;
+ int ret;
+
+ ret = thermal_zone_get_temp(iio_data->tz, &temp);
+ if (ret)
+ goto err_read;
+
+ *(u32 *)buffer = temp;
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ iio_get_time_ns());
+err_read:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int thermal_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ int ret = 0;
+
+ mutex_lock(&iio_data->mutex);
+ if (iio_data->tz->ops->set_notification_status) {
+ ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
+ state);
+ if (!ret)
+ iio_data->enable_trigger = state;
+ } else
+ iio_data->enable_trigger = state;
+ mutex_unlock(&iio_data->mutex);
+
+ return ret;
+}
+
+static int thermal_iio_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+
+ if (iio_data->interrupt_trig && iio_data->interrupt_trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct iio_trigger_ops thermal_trigger_ops = {
+ .set_trigger_state = thermal_data_rdy_trigger_set_state,
+ .owner = THIS_MODULE,
+};
+
+static int thermal_iio_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&iio_data->mutex);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ *val = iio_data->temp_thres;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&iio_data->mutex);
+
+ return ret;
+}
+
+static int thermal_iio_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ int ret = 0;
+
+ mutex_lock(&iio_data->mutex);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ iio_data->temp_thres = val;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&iio_data->mutex);
+
+ return ret;
+}
+
+static int thermal_iio_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ bool state;
+
+ mutex_lock(&iio_data->mutex);
+ state = iio_data->ev_enable_state;
+ mutex_unlock(&iio_data->mutex);
+
+ return state;
+}
+
+static int thermal_iio_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct thermal_iio_data *iio_data = iio_priv(indio_dev);
+ int temp_thres;
+ int ret = 0;
+
+ mutex_lock(&iio_data->mutex);
+ if ((state && iio_data->ev_enable_state) ||
+ (!state && !iio_data->ev_enable_state))
+ goto done_write_event;
+
+ if (state && !iio_data->temp_thres) {
+ ret = -EINVAL;
+ goto done_write_event;
+ }
+
+ if (state)
+ temp_thres = iio_data->temp_thres;
+ else
+ temp_thres = 0;
+
+ ret = iio_data->tz->ops->set_threshold_temp(iio_data->tz, 0,
+ temp_thres);
+ if (ret)
+ goto done_write_event;
+
+ if (iio_data->tz->ops->set_notification_status) {
+ ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
+ state > 0);
+ if (!ret)
+ iio_data->ev_enable_state = state;
+ } else
+ iio_data->ev_enable_state = state;
+
+done_write_event:
+ mutex_unlock(&iio_data->mutex);
+
+ return ret;
+}
+
+static int thermal_iio_setup_trig(struct iio_trigger **iio_trig,
+ struct thermal_zone_device *tz,
+ const char *format)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = devm_iio_trigger_alloc(&tz->device, format, tz->type,
+ tz->indio_dev->id);
+ if (!trig) {
+ dev_err(&tz->device, "Trigger Allocate Failed\n");
+ return -ENOMEM;
+ }
+ trig->dev.parent = &tz->device;
+ trig->ops = &thermal_trigger_ops;
+ iio_trigger_set_drvdata(trig, tz->indio_dev);
+ ret = iio_trigger_register(trig);
+ if (ret) {
+ dev_err(&tz->device, "Trigger Allocate Failed\n");
+ return ret;
+ }
+ *iio_trig = trig;
+
+ return 0;
+}
+
+static const struct iio_info thermal_iio_info = {
+ .read_raw = thermal_iio_read_raw,
+ .read_event_value = thermal_iio_read_event,
+ .write_event_value = thermal_iio_write_event,
+ .write_event_config = thermal_iio_write_event_config,
+ .read_event_config = thermal_iio_read_event_config,
+ .validate_trigger = thermal_iio_validate_trigger,
+ .driver_module = THIS_MODULE,
+};
+
+int thermal_iio_sensor_register(struct thermal_zone_device *tz)
+{
+ struct thermal_iio_data *iio_data;
+ int ret;
+
+ tz->indio_dev = devm_iio_device_alloc(&tz->device, sizeof(*iio_data));
+ if (!tz->indio_dev)
+ return -ENOMEM;
+
+ iio_data = iio_priv(tz->indio_dev);
+ iio_data->tz = tz;
+ mutex_init(&iio_data->mutex);
+
+ tz->indio_dev->dev.parent = &tz->device;
+ if (tz->ops->set_threshold_temp)
+ tz->indio_dev->channels = thermal_iio_channels_with_events;
+ else
+ tz->indio_dev->channels = thermal_iio_channels;
+ tz->indio_dev->num_channels = ARRAY_SIZE(thermal_iio_channels);
+ tz->indio_dev->name = tz->type;
+ tz->indio_dev->info = &thermal_iio_info;
+ tz->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (tz->ops->check_notification_support &&
+ tz->ops->check_notification_support(tz)) {
+ ret = thermal_iio_setup_trig(&iio_data->interrupt_trig, tz,
+ "%s-dev%d");
+ if (ret)
+ return ret;
+
+ tz->indio_dev->trig = iio_trigger_get(iio_data->interrupt_trig);
+ }
+ ret = iio_triggered_buffer_setup(tz->indio_dev,
+ &iio_pollfunc_store_time,
+ thermal_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&tz->device, "failed to init trigger buffer\n");
+ goto err_unreg_int_trig;
+ }
+ ret = iio_device_register(tz->indio_dev);
+ if (ret < 0) {
+ dev_err(&tz->device, "unable to register iio device\n");
+ goto err_cleanup_trig;
+ }
+
+ return 0;
+
+err_cleanup_trig:
+ iio_triggered_buffer_cleanup(tz->indio_dev);
+err_unreg_int_trig:
+ if (iio_data->interrupt_trig)
+ iio_trigger_unregister(iio_data->interrupt_trig);
+
+ return ret;
+}
+
+int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
+{
+ struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
+
+ iio_device_unregister(tz->indio_dev);
+ iio_triggered_buffer_cleanup(tz->indio_dev);
+ if (iio_data->interrupt_trig)
+ iio_trigger_unregister(iio_data->interrupt_trig);
+
+ return 0;
+}
+
+int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
+ enum thermal_device_event_type event)
+{
+ struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
+
+ mutex_lock(&iio_data->mutex);
+ if (iio_data->ev_enable_state &&
+ event == THERMAL_DEVICE_EVENT_THRESHOLD)
+ iio_push_event(tz->indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+ if (iio_data->enable_trigger)
+ iio_trigger_poll(tz->indio_dev->trig);
+ mutex_unlock(&iio_data->mutex);
+
+ return 0;
+}
diff --git a/drivers/thermal/thermal_iio.h b/drivers/thermal/thermal_iio.h
new file mode 100644
index 0000000..850ea7d
--- /dev/null
+++ b/drivers/thermal/thermal_iio.h
@@ -0,0 +1,45 @@
+/*
+ * thermal iio interface driver interface file
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#ifndef __THERMAL_IIO_H__
+#define __THERMAL_IIO_H__
+
+#if defined(CONFIG_THERMAL_IIO)
+
+int thermal_iio_sensor_register(struct thermal_zone_device *tz);
+int thermal_iio_sensor_unregister(struct thermal_zone_device *tz);
+int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
+ enum thermal_device_event_type event);
+
+#else
+
+static int thermal_iio_sensor_register(struct thermal_zone_device *tz)
+{
+ return 0;
+}
+
+static int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
+{
+ return 0;
+}
+
+static int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
+ enum thermal_device_event_type event)
+
+{
+ return 0;
+}
+
+#endif
+#endif
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index c074f6a..925d1e5 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -114,6 +114,13 @@ struct thermal_zone_device_ops {
int (*set_emul_temp) (struct thermal_zone_device *, int);
int (*get_trend) (struct thermal_zone_device *, int,
enum thermal_trend *);
+ int (*get_threshold_temp)(struct thermal_zone_device *, int,
+ int *);
+ int (*set_threshold_temp)(struct thermal_zone_device *, int,
+ int);
+ int (*set_notification_status)(struct thermal_zone_device *,
+ bool status);
+ bool (*check_notification_support)(struct thermal_zone_device *);
int (*notify) (struct thermal_zone_device *, int,
enum thermal_trip_type);
};
@@ -148,6 +155,8 @@ struct thermal_attr {
char name[THERMAL_NAME_LENGTH];
};
+struct iio_dev;
+
/**
* struct thermal_zone_device - structure for a thermal zone
* @id: unique id number for each thermal zone
@@ -182,6 +191,7 @@ struct thermal_attr {
* @lock: lock to protect thermal_instances list
* @node: node in thermal_tz_list (in thermal_core.c)
* @poll_queue: delayed work for polling
+ * @indio_dev: pointer to instance of an IIO dev for this zone
*/
struct thermal_zone_device {
int id;
@@ -208,6 +218,9 @@ struct thermal_zone_device {
struct mutex lock;
struct list_head node;
struct delayed_work poll_queue;
+#if defined(CONFIG_THERMAL_IIO)
+ struct iio_dev *indio_dev;
+#endif
};
/**
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/6] thermal: use iio binding calls
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
` (2 preceding siblings ...)
2015-09-26 22:05 ` [PATCH 3/6] thermal: iio device for thermal sensor Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 5/6] thermal: iio Documentation Srinivas Pandruvada
` (2 subsequent siblings)
6 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
This change:
Register zone temperature sensor as IIO device during zone registration,
Remove iio device during zone removal,
Notify iio binding during thermal_device_update call.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/thermal/thermal_core.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 18e7802..dbde29f 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -43,6 +43,7 @@
#include "thermal_core.h"
#include "thermal_hwmon.h"
+#include "thermal_iio.h"
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -544,6 +545,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
if (!tz->ops->get_temp)
return;
+ thermal_iio_sensor_notify(tz, event);
update_temperature(tz);
for (count = 0; count < tz->trips; count++)
@@ -1858,10 +1860,15 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
mutex_unlock(&thermal_governor_lock);
+ if (thermal_iio_sensor_register(tz))
+ goto unregister;
+
if (!tz->tzp || !tz->tzp->no_hwmon) {
result = thermal_add_hwmon_sysfs(tz);
- if (result)
+ if (result) {
+ thermal_iio_sensor_unregister(tz);
goto unregister;
+ }
}
mutex_lock(&thermal_list_lock);
@@ -1943,6 +1950,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
remove_trip_attrs(tz);
thermal_set_governor(tz, NULL);
+ thermal_iio_sensor_unregister(tz);
thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 5/6] thermal: iio Documentation
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
` (3 preceding siblings ...)
2015-09-26 22:05 ` [PATCH 4/6] thermal: use iio binding calls Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-27 18:23 ` Jonathan Cameron
2015-09-26 22:05 ` [PATCH 6/6] thermal: x86_pkg_temp: Register threshold callbacks Srinivas Pandruvada
2015-09-27 11:24 ` [PATCH 0/6] thermal: iio bindings Daniel Lezcano
6 siblings, 1 reply; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=a, Size: 3777 bytes --]
An overview document about thermal iio binding.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
Documentation/thermal/thermal_iio_binding | 88 +++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100644 Documentation/thermal/thermal_iio_binding
diff --git a/Documentation/thermal/thermal_iio_binding b/Documentation/thermal/thermal_iio_binding
new file mode 100644
index 0000000..df501f1
--- /dev/null
+++ b/Documentation/thermal/thermal_iio_binding
@@ -0,0 +1,88 @@
+
+Thermal IIO Bindings
+
+When CONFIG_THERMAL_IIO is enabled, in addition to the regular thermal
+zone attributes, an additional entry for an IIO device is created.
+IIO sysfs ABI documents is available at Documentation/ABI/sysfs-bus-iio.
+
+The following example shows the contents of the IIO:device in a thermal
+zone.
+
+thermal_zoneX
+├── iio:device9
+│ ├── buffer
+│ │ ├── enable
+│ │ ├── length
+│ │ └── watermark
+│ ├── events
+│ │ ├── in_temp_thresh_either_en
+│ │ └── in_temp_thresh_either_value
+│ ├── in_temp_raw
+│ ├── name
+│ ├── scan_elements
+│ │ ├── in_temp_en
+│ │ ├── in_temp_index
+│ │ ├── in_temp_type
+│ │ ├── in_timestamp_en
+│ │ ├── in_timestamp_index
+│ │ └── in_timestamp_type
+│ ├── subsystem -> ../../../../../bus/iio
+│ ├── trigger0
+│ │ └── name
+│ ├── trigger
+│ │ └── current_trigger
+│ └── uevent
+├── integral_cutoff
+...
+... other thermal_zone attributes
+...
+
+
+IIO Attributes
+
+name: This shows iio device name, which will match thermal_zone/type attribute
+in_temp_raw: This will show raw temperature values same as thermal_zone/temp
+attribute.
+
+trigger/current_trigger: This is IIO way of specifying data ready indication.
+If the thermal client can provide asynchronous notifications, then a iio trigger
+device is created under trigger0. The name of this trigger will be thermal
+device name suffixed with devX. To enable iio buffer notifications,
+trigger/current_trigger cab be updated with this trigger. For example
+
+#echo "x86_pkg_temp-dev9" > trigger/current_trigger
+
+In addition of samples can be pushed to iio buffers with external standard IIO
+device triggers, E.g. sysfs trigger.
+
+How to enable events?
+To enable events a suitable threshold temperature can be written to
+in_temp_thresh_either_value
+and enable by writing 1 to in_temp_thresh_either_en.
+
+To monitor events a good user space program is here:
+tools/iio/iio_event_monitor.c
+
+For example
+# echo 50000 > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_temp_thresh_either_value
+# echo 1 > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_temp_thresh_either_en
+# ./iio_event_monitor x86_pkg_temp
+Found IIO device with name x86_pkg_temp with device number 9
+Event: time: 1443297126626859289, type: temp, channel: 0, evtype: thresh, direction: either
+
+How to read temperature samples?
+When thermal client or core driver calls thermal_zone_device_update, this will
+result in sample pushed to iio buffers. These samples can be read from
+/dev/iio:deviceX file.
+
+To enable buffer select scan_elements
+# echo 1 > scan_elements/in_temp_en
+
+Set buffer length to n samples and enable buffer.
+# echo 2 > buffer/length
+# echo 1 > buffer/enable
+
+Then user can poll/select or /dev/iio:deviceX (Here X correspond to iio device number),
+and read temperature samples. A good example is at tools/iio/generic_buffer.c.
+
+
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 6/6] thermal: x86_pkg_temp: Register threshold callbacks
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
` (4 preceding siblings ...)
2015-09-26 22:05 ` [PATCH 5/6] thermal: iio Documentation Srinivas Pandruvada
@ 2015-09-26 22:05 ` Srinivas Pandruvada
2015-09-27 11:24 ` [PATCH 0/6] thermal: iio bindings Daniel Lezcano
6 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-26 22:05 UTC (permalink / raw)
To: jic23, rui.zhang, edubezval, linux-pm, linux-iio; +Cc: Srinivas Pandruvada
Register callbacks to get/set temperature thresholds.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/thermal/x86_pkg_temp_thermal.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 849f682..58d0770 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -273,12 +273,20 @@ static int sys_get_trip_type(struct thermal_zone_device *thermal,
return 0;
}
+static bool sys_check_notify_support(struct thermal_zone_device *tz)
+{
+ return true;
+}
+
/* Thermal zone callback registry */
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.get_trip_temp = sys_get_trip_temp,
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
+ .get_threshold_temp = sys_get_trip_temp,
+ .set_threshold_temp = sys_set_trip_temp,
+ .check_notification_support = sys_check_notify_support,
};
static bool pkg_temp_thermal_platform_thermal_rate_control(void)
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 0/6] thermal: iio bindings
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
` (5 preceding siblings ...)
2015-09-26 22:05 ` [PATCH 6/6] thermal: x86_pkg_temp: Register threshold callbacks Srinivas Pandruvada
@ 2015-09-27 11:24 ` Daniel Lezcano
2015-09-27 14:29 ` Srinivas Pandruvada
6 siblings, 1 reply; 15+ messages in thread
From: Daniel Lezcano @ 2015-09-27 11:24 UTC (permalink / raw)
To: Srinivas Pandruvada, jic23, rui.zhang, edubezval, linux-pm,
linux-iio
On 09/26/2015 03:05 PM, Srinivas Pandruvada wrote:
> v0
> Since this was discussed during LPC in Seattle and three versions of RFC are
> published and reviwed, this is posted as non RFC version. This has
> changes in iio interface file as suggested by Jonathan. We may add threshold
> event direction flag later if required, without much impact by adding new
> event type.
Not everyone was at LPC.
You should fix the changelog(s) and explain what you are trying to solve
and why it is important.
> RFC v2
> - Rebase to 4.3.rc1
> - Additional parameter to thermal_zone_device_update for event type
> - Moved the dummy IIO callbacks to local include file, in this
> way "not used" warnings can be avoided
> - Remove changes from user space governor, rather notify from core
> - Validate the trigger, so that when thermal device supports async
> notifications, this will be exclusive trigger
> - Use new thermal core event type to differentiate events for iio
> threshold notification
>
> RFC v1
> - Change commit message to be more clear
> - Split in three patches (First for thermal_iio.c, second to integrate
> to thermal_core and third for user space governor).
> - Removed IIO defines in thermal.h
> - Removed direct push to buffers
> - Other comments from Jonathan except introduce validate_trigger
>
> RFC v0
> Base version for first review
>
> Srinivas Pandruvada (6):
> thermal: core: enhance thermal_zone_device_update
> thermal: documentation update
> thermal: iio device for thermal sensor
> thermal: use iio binding calls
> thermal: iio Documentation
> thermal: x86_pkg_temp: Register threshold callbacks
>
> Documentation/thermal/sysfs-api.txt | 10 +
> Documentation/thermal/thermal_iio_binding | 88 +++++
> drivers/acpi/thermal.c | 2 +-
> drivers/platform/x86/acerhdf.c | 2 +-
> drivers/thermal/Kconfig | 12 +
> drivers/thermal/Makefile | 1 +
> drivers/thermal/db8500_thermal.c | 2 +-
> drivers/thermal/hisi_thermal.c | 3 +-
> drivers/thermal/imx_thermal.c | 4 +-
> .../thermal/int340x_thermal/int340x_thermal_zone.h | 2 +-
> drivers/thermal/intel_soc_dts_iosf.c | 3 +-
> drivers/thermal/of-thermal.c | 2 +-
> drivers/thermal/qcom-spmi-temp-alarm.c | 2 +-
> drivers/thermal/rcar_thermal.c | 3 +-
> drivers/thermal/rockchip_thermal.c | 3 +-
> drivers/thermal/samsung/exynos_tmu.c | 2 +-
> drivers/thermal/st/st_thermal_memmap.c | 3 +-
> drivers/thermal/thermal_core.c | 21 +-
> drivers/thermal/thermal_iio.c | 383 +++++++++++++++++++++
> drivers/thermal/thermal_iio.h | 45 +++
> drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 4 +-
> drivers/thermal/x86_pkg_temp_thermal.c | 11 +-
> include/linux/thermal.h | 26 +-
> 23 files changed, 609 insertions(+), 25 deletions(-)
> create mode 100644 Documentation/thermal/thermal_iio_binding
> create mode 100644 drivers/thermal/thermal_iio.c
> create mode 100644 drivers/thermal/thermal_iio.h
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 0/6] thermal: iio bindings
2015-09-27 11:24 ` [PATCH 0/6] thermal: iio bindings Daniel Lezcano
@ 2015-09-27 14:29 ` Srinivas Pandruvada
0 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-09-27 14:29 UTC (permalink / raw)
To: Daniel Lezcano, jic23, rui.zhang, edubezval, linux-pm, linux-iio
On Sun, 2015-09-27 at 04:24 -0700, Daniel Lezcano wrote:
> On 09/26/2015 03:05 PM, Srinivas Pandruvada wrote:
> > v0
> > Since this was discussed during LPC in Seattle and three versions
> > of RFC are
> > published and reviwed, this is posted as non RFC version. This has
> > changes in iio interface file as suggested by Jonathan. We may add
> > threshold
> > event direction flag later if required, without much impact by
> > adding new
> > event type.
>
> Not everyone was at LPC.
>
> You should fix the changelog(s) and explain what you are trying to
> solve
> and why it is important.
Sure. The very first RFC had this. I hope you did get chance to look at
this.
>
>
> > RFC v2
> > - Rebase to 4.3.rc1
> > - Additional parameter to thermal_zone_device_update for event type
> > - Moved the dummy IIO callbacks to local include file, in this
> > way "not used" warnings can be avoided
> > - Remove changes from user space governor, rather notify from core
> > - Validate the trigger, so that when thermal device supports async
> > notifications, this will be exclusive trigger
> > - Use new thermal core event type to differentiate events for iio
> > threshold notification
> >
> > RFC v1
> > - Change commit message to be more clear
> > - Split in three patches (First for thermal_iio.c, second to
> > integrate
> > to thermal_core and third for user space governor).
> > - Removed IIO defines in thermal.h
> > - Removed direct push to buffers
> > - Other comments from Jonathan except introduce validate_trigger
> >
> > RFC v0
> > Base version for first review
> >
> > Srinivas Pandruvada (6):
> > thermal: core: enhance thermal_zone_device_update
> > thermal: documentation update
> > thermal: iio device for thermal sensor
> > thermal: use iio binding calls
> > thermal: iio Documentation
> > thermal: x86_pkg_temp: Register threshold callbacks
> >
> > Documentation/thermal/sysfs-api.txt | 10 +
> > Documentation/thermal/thermal_iio_binding | 88 +++++
> > drivers/acpi/thermal.c | 2 +-
> > drivers/platform/x86/acerhdf.c | 2 +-
> > drivers/thermal/Kconfig | 12 +
> > drivers/thermal/Makefile | 1 +
> > drivers/thermal/db8500_thermal.c | 2 +-
> > drivers/thermal/hisi_thermal.c | 3 +-
> > drivers/thermal/imx_thermal.c | 4 +-
> > .../thermal/int340x_thermal/int340x_thermal_zone.h | 2 +-
> > drivers/thermal/intel_soc_dts_iosf.c | 3 +-
> > drivers/thermal/of-thermal.c | 2 +-
> > drivers/thermal/qcom-spmi-temp-alarm.c | 2 +-
> > drivers/thermal/rcar_thermal.c | 3 +-
> > drivers/thermal/rockchip_thermal.c | 3 +-
> > drivers/thermal/samsung/exynos_tmu.c | 2 +-
> > drivers/thermal/st/st_thermal_memmap.c | 3 +-
> > drivers/thermal/thermal_core.c | 21 +-
> > drivers/thermal/thermal_iio.c | 383
> > +++++++++++++++++++++
> > drivers/thermal/thermal_iio.h | 45 +++
> > drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 4 +-
> > drivers/thermal/x86_pkg_temp_thermal.c | 11 +-
> > include/linux/thermal.h | 26 +-
> > 23 files changed, 609 insertions(+), 25 deletions(-)
> > create mode 100644 Documentation/thermal/thermal_iio_binding
> > create mode 100644 drivers/thermal/thermal_iio.c
> > create mode 100644 drivers/thermal/thermal_iio.h
> >
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/6] thermal: iio device for thermal sensor
2015-09-26 22:05 ` [PATCH 3/6] thermal: iio device for thermal sensor Srinivas Pandruvada
@ 2015-09-27 18:18 ` Jonathan Cameron
2015-12-31 19:18 ` Eduardo Valentin
1 sibling, 0 replies; 15+ messages in thread
From: Jonathan Cameron @ 2015-09-27 18:18 UTC (permalink / raw)
To: Srinivas Pandruvada, rui.zhang, edubezval, linux-pm, linux-iio
On 26/09/15 23:05, Srinivas Pandruvada wrote:
> This change registers temperature sensor in a thermal zone as an IIO
> temperature device. This allows user space thermal application to fully
> utilize IIO capability to read temperature events and samples.
> The primary motivation for this change to improve performance for user
> space thermal controllers like Linux thermal daemon or Intel® Dynamic
> Platform and Thermal Framework (DPTF) for Chromium OS.
> The current sysfs has several limitations, which forces the current
> user space to use polling as the safe way. This polling causes performance
> bottlenecks as some devices requires extremely aggressive response to
> changing temperature conditions.
> These are some limitations, which this change tries to address:
> - Temperature reading via sysfs attribute, which needs conversion from
> string to int
> - No way to set threshold settings to avoid polling for temperature change
> without using a RW passive trip point.
> - Event notifications via slow kobject uevents, which needs parsing to id
> the zone and read temperature
> - Only pull interface from user space, kernel drivers can't send samples
> - One sample at a time read from user space
> These limitations can be addressed by registering temperature sensor
> as an IIO device. IIO provides
> - buffered access via /dev/iio:deviceX node with select/poll capability
> - temperature thresholds setting via iio event thresholds
> - Wait and receive events
> - Able to use different external trigger (data ready indications) and push
> samples to buffers
>
> Next set of patches uses the IIO binding introduced in this patchset.
> The iio device created during call to thermal_zone_device_register. Samples
> are pushed to iio buffers when thermal_zone_device_update is called from
> client drivers.
>
> New thermal zone device callbacks:
> It introduces three new callbacks for thermal client drivers:
> get_threshold_temp: Get the current threshold temperature
> set_threshold_temp: Set the current threshold temperature
> check_notification_support: Inform that the client driver has asynchronous
> notification mechanism. If it is then polling can be avoided for the
> temperature sensor.
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
I think I confused you in a previous review.
To avoid complexity with a non interrupt trigger like this one you
need both the validate_trigger and validate_device callbacks (in the device
and trigger respectively). See below.
Fix that little bit up (which is really simple!) and you can add
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Thanks,
Jonathan
> ---
> drivers/thermal/Kconfig | 12 ++
> drivers/thermal/Makefile | 1 +
> drivers/thermal/thermal_iio.c | 383 ++++++++++++++++++++++++++++++++++++++++++
> drivers/thermal/thermal_iio.h | 45 +++++
> include/linux/thermal.h | 13 ++
> 5 files changed, 454 insertions(+)
> create mode 100644 drivers/thermal/thermal_iio.c
> create mode 100644 drivers/thermal/thermal_iio.h
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 0390044..bc7836e 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -29,6 +29,18 @@ config THERMAL_HWMON
> Say 'Y' here if you want all thermal sensors to
> have hwmon sysfs interface too.
>
> +config THERMAL_IIO
> + bool
> + prompt "Thermal sensor from a zone as IIO sensor device"
> + select IIO
> + select IIO_BUFFER
> + select IIO_TRIGGERED_BUFFER
> + help
> + This will register thermal sensor in a zone as an IIO temperature
> + sensor device.
> + This will help user space thermal controllers to use IIO ABI to
> + get events and buffered acces to temperature samples.
> +
> config THERMAL_OF
> bool
> prompt "APIs to parse thermal data out of device tree"
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..b72a28d 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o
>
> # interface to/from other layers providing sensors
> thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
> +thermal_sys-$(CONFIG_THERMAL_IIO) += thermal_iio.o
> thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o
>
> # governors
> diff --git a/drivers/thermal/thermal_iio.c b/drivers/thermal/thermal_iio.c
> new file mode 100644
> index 0000000..492eaff
> --- /dev/null
> +++ b/drivers/thermal/thermal_iio.c
> @@ -0,0 +1,383 @@
> +/*
> + * thermal iio interface driver
> + * Copyright (c) 2015, Intel Corporation.
> + *
> + * 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.
> + *
> + * This program is distributed in the hope 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/thermal.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
> +
> +struct thermal_iio_data {
> + struct thermal_zone_device *tz;
> + struct iio_trigger *interrupt_trig;
> + struct iio_chan_spec *channels;
> + bool enable_trigger;
> + int temp_thres;
> + bool ev_enable_state;
> + struct mutex mutex;
> +};
> +
> +static const struct iio_event_spec thermal_event = {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_EITHER,
> + .mask_separate = BIT(IIO_EV_INFO_VALUE) |
> + BIT(IIO_EV_INFO_ENABLE)
> +};
> +
> +static const struct iio_chan_spec thermal_iio_channels[] = {
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + .scan_index = 0,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 32,
> + .storagebits = 32,
> + .endianness = IIO_CPU,
> + }
> + },
> + IIO_CHAN_SOFT_TIMESTAMP(1)
> +};
> +
> +static const struct iio_chan_spec thermal_iio_channels_with_events[] = {
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + .scan_index = 0,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 32,
> + .storagebits = 32,
> + .endianness = IIO_CPU,
> + },
> + .event_spec = &thermal_event,
> + .num_event_specs = 1,
> +
> + },
> + IIO_CHAN_SOFT_TIMESTAMP(1)
> +};
> +
> +static int thermal_iio_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int temp;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = thermal_zone_get_temp(iio_data->tz, &temp);
> + if (!ret) {
> + *val = temp;
> + ret = IIO_VAL_INT;
> + }
> + break;
> + default:
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +static irqreturn_t thermal_trigger_handler(int irq, void *p)
> +{
> + struct iio_poll_func *pf = p;
> + struct iio_dev *indio_dev = pf->indio_dev;
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + u32 buffer[4];
> + int temp;
> + int ret;
> +
> + ret = thermal_zone_get_temp(iio_data->tz, &temp);
> + if (ret)
> + goto err_read;
> +
> + *(u32 *)buffer = temp;
Umm. I'm confused by the above. buffer is a u32 array, so you are
casting it to a u32 pointer then dereferencing that. Doesn't that
just give you buffer[0] = temp?
(might be too late on a Sunday!) Given temp is signed, wby not use
s32 buffer[4] and be done with it?
> + iio_push_to_buffers_with_timestamp(indio_dev, buffer,
> + iio_get_time_ns());
> +err_read:
> + iio_trigger_notify_done(indio_dev->trig);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int thermal_data_rdy_trigger_set_state(struct iio_trigger *trig,
> + bool state)
> +{
> + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + if (iio_data->tz->ops->set_notification_status) {
> + ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
> + state);
> + if (!ret)
> + iio_data->enable_trigger = state;
> + } else
> + iio_data->enable_trigger = state;
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_validate_trigger(struct iio_dev *indio_dev,
> + struct iio_trigger *trig)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> +
> + if (iio_data->interrupt_trig && iio_data->interrupt_trig != trig)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static const struct iio_trigger_ops thermal_trigger_ops = {
> + .set_trigger_state = thermal_data_rdy_trigger_set_state,
For reasons explained later, you want validate_device to be defined
as well.
> + .owner = THIS_MODULE,
> +};
> +
> +static int thermal_iio_read_event(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int *val, int *val2)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret;
> +
> + mutex_lock(&iio_data->mutex);
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + *val = iio_data->temp_thres;
> + ret = IIO_VAL_INT;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_write_event(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int val, int val2)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + iio_data->temp_thres = val;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_read_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + bool state;
> +
> + mutex_lock(&iio_data->mutex);
> + state = iio_data->ev_enable_state;
> + mutex_unlock(&iio_data->mutex);
> +
> + return state;
> +}
> +
> +static int thermal_iio_write_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + int state)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int temp_thres;
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + if ((state && iio_data->ev_enable_state) ||
> + (!state && !iio_data->ev_enable_state))
> + goto done_write_event;
> +
> + if (state && !iio_data->temp_thres) {
> + ret = -EINVAL;
> + goto done_write_event;
> + }
> +
> + if (state)
> + temp_thres = iio_data->temp_thres;
> + else
> + temp_thres = 0;
> +
> + ret = iio_data->tz->ops->set_threshold_temp(iio_data->tz, 0,
> + temp_thres);
> + if (ret)
> + goto done_write_event;
> +
> + if (iio_data->tz->ops->set_notification_status) {
> + ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
> + state > 0);
> + if (!ret)
> + iio_data->ev_enable_state = state;
> + } else
> + iio_data->ev_enable_state = state;
> +
> +done_write_event:
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_setup_trig(struct iio_trigger **iio_trig,
> + struct thermal_zone_device *tz,
> + const char *format)
> +{
> + struct iio_trigger *trig;
> + int ret;
> +
> + trig = devm_iio_trigger_alloc(&tz->device, format, tz->type,
> + tz->indio_dev->id);
> + if (!trig) {
> + dev_err(&tz->device, "Trigger Allocate Failed\n");
> + return -ENOMEM;
> + }
> + trig->dev.parent = &tz->device;
> + trig->ops = &thermal_trigger_ops;
> + iio_trigger_set_drvdata(trig, tz->indio_dev);
> + ret = iio_trigger_register(trig);
> + if (ret) {
> + dev_err(&tz->device, "Trigger Allocate Failed\n");
> + return ret;
> + }
> + *iio_trig = trig;
> +
> + return 0;
> +}
> +
> +static const struct iio_info thermal_iio_info = {
> + .read_raw = thermal_iio_read_raw,
> + .read_event_value = thermal_iio_read_event,
> + .write_event_value = thermal_iio_write_event,
> + .write_event_config = thermal_iio_write_event_config,
> + .read_event_config = thermal_iio_read_event_config,
> + .validate_trigger = thermal_iio_validate_trigger,
> + .driver_module = THIS_MODULE,
> +};
> +
> +int thermal_iio_sensor_register(struct thermal_zone_device *tz)
> +{
> + struct thermal_iio_data *iio_data;
> + int ret;
> +
> + tz->indio_dev = devm_iio_device_alloc(&tz->device, sizeof(*iio_data));
> + if (!tz->indio_dev)
> + return -ENOMEM;
> +
> + iio_data = iio_priv(tz->indio_dev);
> + iio_data->tz = tz;
> + mutex_init(&iio_data->mutex);
> +
> + tz->indio_dev->dev.parent = &tz->device;
> + if (tz->ops->set_threshold_temp)
> + tz->indio_dev->channels = thermal_iio_channels_with_events;
> + else
> + tz->indio_dev->channels = thermal_iio_channels;
> + tz->indio_dev->num_channels = ARRAY_SIZE(thermal_iio_channels);
> + tz->indio_dev->name = tz->type;
> + tz->indio_dev->info = &thermal_iio_info;
> + tz->indio_dev->modes = INDIO_DIRECT_MODE;
> +
> + if (tz->ops->check_notification_support &&
> + tz->ops->check_notification_support(tz)) {
> + ret = thermal_iio_setup_trig(&iio_data->interrupt_trig, tz,
> + "%s-dev%d");
> + if (ret)
> + return ret;
> +
> + tz->indio_dev->trig = iio_trigger_get(iio_data->interrupt_trig);
> + }
> + ret = iio_triggered_buffer_setup(tz->indio_dev,
> + &iio_pollfunc_store_time,
> + thermal_trigger_handler, NULL);
> + if (ret) {
> + dev_err(&tz->device, "failed to init trigger buffer\n");
> + goto err_unreg_int_trig;
> + }
> + ret = iio_device_register(tz->indio_dev);
> + if (ret < 0) {
> + dev_err(&tz->device, "unable to register iio device\n");
> + goto err_cleanup_trig;
> + }
> +
> + return 0;
> +
> +err_cleanup_trig:
> + iio_triggered_buffer_cleanup(tz->indio_dev);
> +err_unreg_int_trig:
> + if (iio_data->interrupt_trig)
> + iio_trigger_unregister(iio_data->interrupt_trig);
> +
> + return ret;
> +}
> +
> +int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
> +
> + iio_device_unregister(tz->indio_dev);
> + iio_triggered_buffer_cleanup(tz->indio_dev);
> + if (iio_data->interrupt_trig)
> + iio_trigger_unregister(iio_data->interrupt_trig);
> +
> + return 0;
> +}
> +
> +int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
> +
> + mutex_lock(&iio_data->mutex);
> + if (iio_data->ev_enable_state &&
> + event == THERMAL_DEVICE_EVENT_THRESHOLD)
> + iio_push_event(tz->indio_dev,
> + IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
> + IIO_EV_TYPE_THRESH,
> + IIO_EV_DIR_EITHER),
> + iio_get_time_ns());
> + if (iio_data->enable_trigger)
I didn't pick up on this earlier, but is this running in interrupt context
or not? iio_trigger_poll is generally assumed to do so and I suspect this
is not guaranteed to be given the mutex!
Validating the trigger means that only the right trigger can drive the
thermal buffer, but unless you validate the other way as well there is nothing
stopping something else registering to use this trigger. If it's not
a true interrupt, all sorts of mess can occur.
What you need is the validate_device callback for the trigger to check the
device is the one providing the trigger.
Once you've validated both ways, using iio_trigger_poll_chained is fine and
makes it clear we are calling a bottom half (these days normally an interrupt
thread, but not one here).
The alternative is to go through the irq_work dance, but I doubt there is
any reason to do that here.
> + iio_trigger_poll(tz->indio_dev->trig);
> + mutex_unlock(&iio_data->mutex);
> +
> + return 0;
> +}
> diff --git a/drivers/thermal/thermal_iio.h b/drivers/thermal/thermal_iio.h
> new file mode 100644
> index 0000000..850ea7d
> --- /dev/null
> +++ b/drivers/thermal/thermal_iio.h
> @@ -0,0 +1,45 @@
> +/*
> + * thermal iio interface driver interface file
> + * Copyright (c) 2015, Intel Corporation.
> + *
> + * 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.
> + *
> + * This program is distributed in the hope 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.
> + */
> +
> +#ifndef __THERMAL_IIO_H__
> +#define __THERMAL_IIO_H__
> +
> +#if defined(CONFIG_THERMAL_IIO)
> +
> +int thermal_iio_sensor_register(struct thermal_zone_device *tz);
> +int thermal_iio_sensor_unregister(struct thermal_zone_device *tz);
> +int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event);
> +
> +#else
> +
> +static int thermal_iio_sensor_register(struct thermal_zone_device *tz)
> +{
> + return 0;
> +}
> +
> +static int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
> +{
> + return 0;
> +}
> +
> +static int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event)
> +
> +{
> + return 0;
> +}
> +
> +#endif
> +#endif
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index c074f6a..925d1e5 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -114,6 +114,13 @@ struct thermal_zone_device_ops {
> int (*set_emul_temp) (struct thermal_zone_device *, int);
> int (*get_trend) (struct thermal_zone_device *, int,
> enum thermal_trend *);
> + int (*get_threshold_temp)(struct thermal_zone_device *, int,
> + int *);
> + int (*set_threshold_temp)(struct thermal_zone_device *, int,
> + int);
> + int (*set_notification_status)(struct thermal_zone_device *,
> + bool status);
> + bool (*check_notification_support)(struct thermal_zone_device *);
> int (*notify) (struct thermal_zone_device *, int,
> enum thermal_trip_type);
> };
> @@ -148,6 +155,8 @@ struct thermal_attr {
> char name[THERMAL_NAME_LENGTH];
> };
>
> +struct iio_dev;
> +
> /**
> * struct thermal_zone_device - structure for a thermal zone
> * @id: unique id number for each thermal zone
> @@ -182,6 +191,7 @@ struct thermal_attr {
> * @lock: lock to protect thermal_instances list
> * @node: node in thermal_tz_list (in thermal_core.c)
> * @poll_queue: delayed work for polling
> + * @indio_dev: pointer to instance of an IIO dev for this zone
> */
> struct thermal_zone_device {
> int id;
> @@ -208,6 +218,9 @@ struct thermal_zone_device {
> struct mutex lock;
> struct list_head node;
> struct delayed_work poll_queue;
> +#if defined(CONFIG_THERMAL_IIO)
> + struct iio_dev *indio_dev;
> +#endif
> };
>
> /**
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/6] thermal: iio Documentation
2015-09-26 22:05 ` [PATCH 5/6] thermal: iio Documentation Srinivas Pandruvada
@ 2015-09-27 18:23 ` Jonathan Cameron
2015-10-02 17:01 ` Srinivas Pandruvada
0 siblings, 1 reply; 15+ messages in thread
From: Jonathan Cameron @ 2015-09-27 18:23 UTC (permalink / raw)
To: Srinivas Pandruvada, rui.zhang, edubezval, linux-pm, linux-iio
On 26/09/15 23:05, Srinivas Pandruvada wrote:
> An overview document about thermal iio binding.
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> ---
> Documentation/thermal/thermal_iio_binding | 88 +++++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
> create mode 100644 Documentation/thermal/thermal_iio_binding
>
> diff --git a/Documentation/thermal/thermal_iio_binding b/Documentation/thermal/thermal_iio_binding
> new file mode 100644
> index 0000000..df501f1
> --- /dev/null
> +++ b/Documentation/thermal/thermal_iio_binding
> @@ -0,0 +1,88 @@
> +
> +Thermal IIO Bindings
> +
> +When CONFIG_THERMAL_IIO is enabled, in addition to the regular thermal
> +zone attributes, an additional entry for an IIO device is created.
> +IIO sysfs ABI documents is available at Documentation/ABI/sysfs-bus-iio.
> +
> +The following example shows the contents of the IIO:device in a thermal
> +zone.
> +
> +thermal_zoneX
> +├── iio:device9
> +│ ├── buffer
> +│ │ ├── enable
> +│ │ ├── length
> +│ │ └── watermark
> +│ ├── events
> +│ │ ├── in_temp_thresh_either_en
> +│ │ └── in_temp_thresh_either_value
> +│ ├── in_temp_raw
> +│ ├── name
> +│ ├── scan_elements
> +│ │ ├── in_temp_en
> +│ │ ├── in_temp_index
> +│ │ ├── in_temp_type
> +│ │ ├── in_timestamp_en
> +│ │ ├── in_timestamp_index
> +│ │ └── in_timestamp_type
> +│ ├── subsystem -> ../../../../../bus/iio
> +│ ├── trigger0
> +│ │ └── name
> +│ ├── trigger
> +│ │ └── current_trigger
> +│ └── uevent
> +├── integral_cutoff
> +...
> +... other thermal_zone attributes
> +...
> +
> +
> +IIO Attributes
> +
> +name: This shows iio device name, which will match thermal_zone/type attribute
> +in_temp_raw: This will show raw temperature values same as thermal_zone/temp
> +attribute.
> +
> +trigger/current_trigger: This is IIO way of specifying data ready indication.
Kind of, given it's not exposed to userspace to read, but rather hooked directly
to the filling of the buffer. You might want to reword to not imply userspace can
discover that it has fired directly.
> +If the thermal client can provide asynchronous notifications, then a iio trigger
> +device is created under trigger0. The name of this trigger will be thermal
> +device name suffixed with devX. To enable iio buffer notifications,
> +trigger/current_trigger cab be updated with this trigger. For example
> +
> +#echo "x86_pkg_temp-dev9" > trigger/current_trigger
> +
> +In addition of samples can be pushed to iio buffers with external standard IIO
> +device triggers, E.g. sysfs trigger.
> +
> +How to enable events?
> +To enable events a suitable threshold temperature can be written to
> +in_temp_thresh_either_value
> +and enable by writing 1 to in_temp_thresh_either_en.
> +
> +To monitor events a good user space program is here:
> +tools/iio/iio_event_monitor.c
> +
> +For example
> +# echo 50000 > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_temp_thresh_either_value
> +# echo 1 > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_temp_thresh_either_en
> +# ./iio_event_monitor x86_pkg_temp
> +Found IIO device with name x86_pkg_temp with device number 9
> +Event: time: 1443297126626859289, type: temp, channel: 0, evtype: thresh, direction: either
> +
> +How to read temperature samples?
> +When thermal client or core driver calls thermal_zone_device_update, this will
> +result in sample pushed to iio buffers. These samples can be read from
> +/dev/iio:deviceX file.
> +
> +To enable buffer select scan_elements
> +# echo 1 > scan_elements/in_temp_en
> +
> +Set buffer length to n samples and enable buffer.
> +# echo 2 > buffer/length
> +# echo 1 > buffer/enable
> +
> +Then user can poll/select or /dev/iio:deviceX (Here X correspond to iio device number),
> +and read temperature samples. A good example is at tools/iio/generic_buffer.c.
> +
One too many blank lines at the end.
> +
Reasonable docs to get people started I think, but whether they are detailed enough is
going to be a question for the thermal guys!
Also, perhaps a cross reference to Daniel's doc book on IIO?
Documentation/DocBook/iio/
As that expands in detail it might include lots of stuff that isn't relevant
to thermal, but it might also fill in details that we don't want to explicitly
layout here.
Jonathan
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/6] thermal: iio Documentation
2015-09-27 18:23 ` Jonathan Cameron
@ 2015-10-02 17:01 ` Srinivas Pandruvada
0 siblings, 0 replies; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-10-02 17:01 UTC (permalink / raw)
To: Jonathan Cameron, rui.zhang, edubezval, linux-pm, linux-iio
On Sun, 2015-09-27 at 19:23 +0100, Jonathan Cameron wrote:
> On 26/09/15 23:05, Srinivas Pandruvada wrote:
> > An overview document about thermal iio binding.
> >
> > Signed-off-by: Srinivas Pandruvada <
> > srinivas.pandruvada@linux.intel.com>
> > ---
> > Documentation/thermal/thermal_iio_binding | 88
> > +++++++++++++++++++++++++++++++
> > 1 file changed, 88 insertions(+)
> > create mode 100644 Documentation/thermal/thermal_iio_binding
> >
> > diff --git a/Documentation/thermal/thermal_iio_binding
> > b/Documentation/thermal/thermal_iio_binding
> > new file mode 100644
> > index 0000000..df501f1
> > --- /dev/null
> > +++ b/Documentation/thermal/thermal_iio_binding
> > @@ -0,0 +1,88 @@
> > +
> > +Thermal IIO Bindings
> > +
> > +When CONFIG_THERMAL_IIO is enabled, in addition to the regular
> > thermal
> > +zone attributes, an additional entry for an IIO device is created.
> > +IIO sysfs ABI documents is available at Documentation/ABI/sysfs
> > -bus-iio.
> > +
> > +The following example shows the contents of the IIO:device in a
> > thermal
> > +zone.
> > +
> > +thermal_zoneX
> > +├── iio:device9
> > +│ ├── buffer
> > +│ │ ├── enable
> > +│ │ ├── length
> > +│ │ └── watermark
> > +│ ├── events
> > +│ │ ├── in_temp_thresh_either_en
> > +│ │ └── in_temp_thresh_either_value
> > +│ ├── in_temp_raw
> > +│ ├── name
> > +│ ├── scan_elements
> > +│ │ ├── in_temp_en
> > +│ │ ├── in_temp_index
> > +│ │ ├── in_temp_type
> > +│ │ ├── in_timestamp_en
> > +│ │ ├── in_timestamp_index
> > +│ │ └── in_timestamp_type
> > +│ ├── subsystem -> ../../../../../bus/iio
> > +│ ├── trigger0
> > +│ │ └── name
> > +│ ├── trigger
> > +│ │ └── current_trigger
> > +│ └── uevent
> > +├── integral_cutoff
> > +...
> > +... other thermal_zone attributes
> > +...
> > +
> > +
> > +IIO Attributes
> > +
> > +name: This shows iio device name, which will match
> > thermal_zone/type attribute
> > +in_temp_raw: This will show raw temperature values same as
> > thermal_zone/temp
> > +attribute.
> > +
> > +trigger/current_trigger: This is IIO way of specifying data ready
> > indication.
> Kind of, given it's not exposed to userspace to read, but rather
> hooked directly
> to the filling of the buffer. You might want to reword to not imply
> userspace can
> discover that it has fired directly.
OK
> > +If the thermal client can provide asynchronous notifications, then
> > a iio trigger
> > +device is created under trigger0. The name of this trigger will be
> > thermal
> > +device name suffixed with devX. To enable iio buffer
> > notifications,
> > +trigger/current_trigger cab be updated with this trigger. For
> > example
> > +
> > +#echo "x86_pkg_temp-dev9" > trigger/current_trigger
> > +
> > +In addition of samples can be pushed to iio buffers with external
> > standard IIO
> > +device triggers, E.g. sysfs trigger.
> > +
> > +How to enable events?
> > +To enable events a suitable threshold temperature can be written
> > to
> > +in_temp_thresh_either_value
> > +and enable by writing 1 to in_temp_thresh_either_en.
> > +
> > +To monitor events a good user space program is here:
> > +tools/iio/iio_event_monitor.c
> > +
> > +For example
> > +# echo 50000 >
> > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_te
> > mp_thresh_either_value
> > +# echo 1 >
> > /sys/devices/virtual/thermal/thermal_zone9/iio:device9/events/in_te
> > mp_thresh_either_en
> > +# ./iio_event_monitor x86_pkg_temp
> > +Found IIO device with name x86_pkg_temp with device number 9
> > +Event: time: 1443297126626859289, type: temp, channel: 0, evtype:
> > thresh, direction: either
> > +
> > +How to read temperature samples?
> > +When thermal client or core driver calls
> > thermal_zone_device_update, this will
> > +result in sample pushed to iio buffers. These samples can be read
> > from
> > +/dev/iio:deviceX file.
> > +
> > +To enable buffer select scan_elements
> > +# echo 1 > scan_elements/in_temp_en
> > +
> > +Set buffer length to n samples and enable buffer.
> > +# echo 2 > buffer/length
> > +# echo 1 > buffer/enable
> > +
> > +Then user can poll/select or /dev/iio:deviceX (Here X correspond
> > to iio device number),
> > +and read temperature samples. A good example is at
> > tools/iio/generic_buffer.c.
> > +
> One too many blank lines at the end.
> > +
> Reasonable docs to get people started I think, but whether they are
> detailed enough is
> going to be a question for the thermal guys!
>
Idea here is to just give pointers to the IIO documentation and
examples to get developers to explore if they want to use this I/F.
> Also, perhaps a cross reference to Daniel's doc book on IIO?
> Documentation/DocBook/iio/
>
> As that expands in detail it might include lots of stuff that isn't
> relevant
> to thermal, but it might also fill in details that we don't want to
> explicitly
> layout here.
>
Thanks for your reviews.
-Srinivas
> Jonathan
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/6] thermal: iio device for thermal sensor
2015-09-26 22:05 ` [PATCH 3/6] thermal: iio device for thermal sensor Srinivas Pandruvada
2015-09-27 18:18 ` Jonathan Cameron
@ 2015-12-31 19:18 ` Eduardo Valentin
2015-12-31 23:18 ` Srinivas Pandruvada
1 sibling, 1 reply; 15+ messages in thread
From: Eduardo Valentin @ 2015-12-31 19:18 UTC (permalink / raw)
To: Srinivas Pandruvada; +Cc: jic23, rui.zhang, linux-pm, linux-iio
On Sat, Sep 26, 2015 at 03:05:08PM -0700, Srinivas Pandruvada wrote:
> This change registers temperature sensor in a thermal zone as an IIO
> temperature device. This allows user space thermal application to fully
> utilize IIO capability to read temperature events and samples.
> The primary motivation for this change to improve performance for user
> space thermal controllers like Linux thermal daemon or Intel® Dynamic
> Platform and Thermal Framework (DPTF) for Chromium OS.
> The current sysfs has several limitations, which forces the current
> user space to use polling as the safe way. This polling causes performance
> bottlenecks as some devices requires extremely aggressive response to
> changing temperature conditions.
> These are some limitations, which this change tries to address:
> - Temperature reading via sysfs attribute, which needs conversion from
> string to int
> - No way to set threshold settings to avoid polling for temperature change
> without using a RW passive trip point.
> - Event notifications via slow kobject uevents, which needs parsing to id
> the zone and read temperature
> - Only pull interface from user space, kernel drivers can't send samples
> - One sample at a time read from user space
> These limitations can be addressed by registering temperature sensor
> as an IIO device. IIO provides
> - buffered access via /dev/iio:deviceX node with select/poll capability
> - temperature thresholds setting via iio event thresholds
> - Wait and receive events
> - Able to use different external trigger (data ready indications) and push
> samples to buffers
>
> Next set of patches uses the IIO binding introduced in this patchset.
> The iio device created during call to thermal_zone_device_register. Samples
> are pushed to iio buffers when thermal_zone_device_update is called from
> client drivers.
>
> New thermal zone device callbacks:
> It introduces three new callbacks for thermal client drivers:
> get_threshold_temp: Get the current threshold temperature
> set_threshold_temp: Set the current threshold temperature
> check_notification_support: Inform that the client driver has asynchronous
> notification mechanism. If it is then polling can be avoided for the
> temperature sensor.
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> ---
> drivers/thermal/Kconfig | 12 ++
> drivers/thermal/Makefile | 1 +
> drivers/thermal/thermal_iio.c | 383 ++++++++++++++++++++++++++++++++++++++++++
> drivers/thermal/thermal_iio.h | 45 +++++
> include/linux/thermal.h | 13 ++
> 5 files changed, 454 insertions(+)
> create mode 100644 drivers/thermal/thermal_iio.c
> create mode 100644 drivers/thermal/thermal_iio.h
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 0390044..bc7836e 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -29,6 +29,18 @@ config THERMAL_HWMON
> Say 'Y' here if you want all thermal sensors to
> have hwmon sysfs interface too.
>
> +config THERMAL_IIO
> + bool
> + prompt "Thermal sensor from a zone as IIO sensor device"
> + select IIO
> + select IIO_BUFFER
> + select IIO_TRIGGERED_BUFFER
> + help
> + This will register thermal sensor in a zone as an IIO temperature
> + sensor device.
> + This will help user space thermal controllers to use IIO ABI to
> + get events and buffered acces to temperature samples.
> +
> config THERMAL_OF
> bool
> prompt "APIs to parse thermal data out of device tree"
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..b72a28d 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o
>
> # interface to/from other layers providing sensors
> thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
> +thermal_sys-$(CONFIG_THERMAL_IIO) += thermal_iio.o
> thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o
>
> # governors
> diff --git a/drivers/thermal/thermal_iio.c b/drivers/thermal/thermal_iio.c
> new file mode 100644
> index 0000000..492eaff
> --- /dev/null
> +++ b/drivers/thermal/thermal_iio.c
> @@ -0,0 +1,383 @@
> +/*
> + * thermal iio interface driver
> + * Copyright (c) 2015, Intel Corporation.
> + *
> + * 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.
> + *
> + * This program is distributed in the hope 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/thermal.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
> +
> +struct thermal_iio_data {
> + struct thermal_zone_device *tz;
> + struct iio_trigger *interrupt_trig;
> + struct iio_chan_spec *channels;
> + bool enable_trigger;
> + int temp_thres;
> + bool ev_enable_state;
> + struct mutex mutex;
> +};
> +
> +static const struct iio_event_spec thermal_event = {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_EITHER,
> + .mask_separate = BIT(IIO_EV_INFO_VALUE) |
> + BIT(IIO_EV_INFO_ENABLE)
> +};
> +
> +static const struct iio_chan_spec thermal_iio_channels[] = {
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + .scan_index = 0,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 32,
> + .storagebits = 32,
> + .endianness = IIO_CPU,
> + }
> + },
> + IIO_CHAN_SOFT_TIMESTAMP(1)
> +};
> +
> +static const struct iio_chan_spec thermal_iio_channels_with_events[] = {
> + {
> + .type = IIO_TEMP,
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> + .scan_index = 0,
> + .scan_type = {
> + .sign = 'u',
> + .realbits = 32,
> + .storagebits = 32,
> + .endianness = IIO_CPU,
> + },
> + .event_spec = &thermal_event,
> + .num_event_specs = 1,
> +
> + },
> + IIO_CHAN_SOFT_TIMESTAMP(1)
> +};
> +
> +static int thermal_iio_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int temp;
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + ret = thermal_zone_get_temp(iio_data->tz, &temp);
> + if (!ret) {
> + *val = temp;
> + ret = IIO_VAL_INT;
> + }
> + break;
> + default:
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +static irqreturn_t thermal_trigger_handler(int irq, void *p)
> +{
> + struct iio_poll_func *pf = p;
> + struct iio_dev *indio_dev = pf->indio_dev;
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + u32 buffer[4];
> + int temp;
> + int ret;
> +
> + ret = thermal_zone_get_temp(iio_data->tz, &temp);
> + if (ret)
> + goto err_read;
> +
> + *(u32 *)buffer = temp;
> + iio_push_to_buffers_with_timestamp(indio_dev, buffer,
> + iio_get_time_ns());
> +err_read:
> + iio_trigger_notify_done(indio_dev->trig);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int thermal_data_rdy_trigger_set_state(struct iio_trigger *trig,
> + bool state)
> +{
> + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + if (iio_data->tz->ops->set_notification_status) {
> + ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
> + state);
> + if (!ret)
> + iio_data->enable_trigger = state;
> + } else
> + iio_data->enable_trigger = state;
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_validate_trigger(struct iio_dev *indio_dev,
> + struct iio_trigger *trig)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> +
> + if (iio_data->interrupt_trig && iio_data->interrupt_trig != trig)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static const struct iio_trigger_ops thermal_trigger_ops = {
> + .set_trigger_state = thermal_data_rdy_trigger_set_state,
> + .owner = THIS_MODULE,
> +};
> +
> +static int thermal_iio_read_event(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int *val, int *val2)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret;
> +
> + mutex_lock(&iio_data->mutex);
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + *val = iio_data->temp_thres;
> + ret = IIO_VAL_INT;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_write_event(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int val, int val2)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + iio_data->temp_thres = val;
> + break;
> + default:
> + ret = -EINVAL;
> + }
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_read_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + bool state;
> +
> + mutex_lock(&iio_data->mutex);
> + state = iio_data->ev_enable_state;
> + mutex_unlock(&iio_data->mutex);
> +
> + return state;
> +}
> +
> +static int thermal_iio_write_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + int state)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(indio_dev);
> + int temp_thres;
> + int ret = 0;
> +
> + mutex_lock(&iio_data->mutex);
> + if ((state && iio_data->ev_enable_state) ||
> + (!state && !iio_data->ev_enable_state))
> + goto done_write_event;
> +
> + if (state && !iio_data->temp_thres) {
> + ret = -EINVAL;
> + goto done_write_event;
> + }
> +
> + if (state)
> + temp_thres = iio_data->temp_thres;
> + else
> + temp_thres = 0;
> +
> + ret = iio_data->tz->ops->set_threshold_temp(iio_data->tz, 0,
> + temp_thres);
> + if (ret)
> + goto done_write_event;
> +
> + if (iio_data->tz->ops->set_notification_status) {
> + ret = iio_data->tz->ops->set_notification_status(iio_data->tz,
> + state > 0);
> + if (!ret)
> + iio_data->ev_enable_state = state;
> + } else
> + iio_data->ev_enable_state = state;
> +
> +done_write_event:
> + mutex_unlock(&iio_data->mutex);
> +
> + return ret;
> +}
> +
> +static int thermal_iio_setup_trig(struct iio_trigger **iio_trig,
> + struct thermal_zone_device *tz,
> + const char *format)
> +{
> + struct iio_trigger *trig;
> + int ret;
> +
> + trig = devm_iio_trigger_alloc(&tz->device, format, tz->type,
> + tz->indio_dev->id);
> + if (!trig) {
> + dev_err(&tz->device, "Trigger Allocate Failed\n");
> + return -ENOMEM;
> + }
> + trig->dev.parent = &tz->device;
> + trig->ops = &thermal_trigger_ops;
> + iio_trigger_set_drvdata(trig, tz->indio_dev);
> + ret = iio_trigger_register(trig);
> + if (ret) {
> + dev_err(&tz->device, "Trigger Allocate Failed\n");
> + return ret;
> + }
> + *iio_trig = trig;
> +
> + return 0;
> +}
> +
> +static const struct iio_info thermal_iio_info = {
> + .read_raw = thermal_iio_read_raw,
> + .read_event_value = thermal_iio_read_event,
> + .write_event_value = thermal_iio_write_event,
> + .write_event_config = thermal_iio_write_event_config,
> + .read_event_config = thermal_iio_read_event_config,
> + .validate_trigger = thermal_iio_validate_trigger,
> + .driver_module = THIS_MODULE,
> +};
> +
> +int thermal_iio_sensor_register(struct thermal_zone_device *tz)
> +{
> + struct thermal_iio_data *iio_data;
> + int ret;
> +
> + tz->indio_dev = devm_iio_device_alloc(&tz->device, sizeof(*iio_data));
> + if (!tz->indio_dev)
> + return -ENOMEM;
> +
> + iio_data = iio_priv(tz->indio_dev);
> + iio_data->tz = tz;
> + mutex_init(&iio_data->mutex);
> +
> + tz->indio_dev->dev.parent = &tz->device;
> + if (tz->ops->set_threshold_temp)
> + tz->indio_dev->channels = thermal_iio_channels_with_events;
> + else
> + tz->indio_dev->channels = thermal_iio_channels;
> + tz->indio_dev->num_channels = ARRAY_SIZE(thermal_iio_channels);
> + tz->indio_dev->name = tz->type;
> + tz->indio_dev->info = &thermal_iio_info;
> + tz->indio_dev->modes = INDIO_DIRECT_MODE;
> +
> + if (tz->ops->check_notification_support &&
> + tz->ops->check_notification_support(tz)) {
> + ret = thermal_iio_setup_trig(&iio_data->interrupt_trig, tz,
> + "%s-dev%d");
> + if (ret)
> + return ret;
> +
> + tz->indio_dev->trig = iio_trigger_get(iio_data->interrupt_trig);
> + }
> + ret = iio_triggered_buffer_setup(tz->indio_dev,
> + &iio_pollfunc_store_time,
> + thermal_trigger_handler, NULL);
> + if (ret) {
> + dev_err(&tz->device, "failed to init trigger buffer\n");
> + goto err_unreg_int_trig;
> + }
> + ret = iio_device_register(tz->indio_dev);
> + if (ret < 0) {
> + dev_err(&tz->device, "unable to register iio device\n");
> + goto err_cleanup_trig;
> + }
> +
> + return 0;
> +
> +err_cleanup_trig:
> + iio_triggered_buffer_cleanup(tz->indio_dev);
> +err_unreg_int_trig:
> + if (iio_data->interrupt_trig)
> + iio_trigger_unregister(iio_data->interrupt_trig);
> +
> + return ret;
> +}
> +
> +int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
> +
> + iio_device_unregister(tz->indio_dev);
> + iio_triggered_buffer_cleanup(tz->indio_dev);
> + if (iio_data->interrupt_trig)
> + iio_trigger_unregister(iio_data->interrupt_trig);
> +
> + return 0;
> +}
> +
> +int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event)
> +{
> + struct thermal_iio_data *iio_data = iio_priv(tz->indio_dev);
> +
> + mutex_lock(&iio_data->mutex);
> + if (iio_data->ev_enable_state &&
> + event == THERMAL_DEVICE_EVENT_THRESHOLD)
> + iio_push_event(tz->indio_dev,
> + IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
> + IIO_EV_TYPE_THRESH,
> + IIO_EV_DIR_EITHER),
> + iio_get_time_ns());
> + if (iio_data->enable_trigger)
> + iio_trigger_poll(tz->indio_dev->trig);
> + mutex_unlock(&iio_data->mutex);
> +
> + return 0;
> +}
> diff --git a/drivers/thermal/thermal_iio.h b/drivers/thermal/thermal_iio.h
> new file mode 100644
> index 0000000..850ea7d
> --- /dev/null
> +++ b/drivers/thermal/thermal_iio.h
> @@ -0,0 +1,45 @@
> +/*
> + * thermal iio interface driver interface file
> + * Copyright (c) 2015, Intel Corporation.
> + *
> + * 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.
> + *
> + * This program is distributed in the hope 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.
> + */
> +
> +#ifndef __THERMAL_IIO_H__
> +#define __THERMAL_IIO_H__
> +
> +#if defined(CONFIG_THERMAL_IIO)
> +
> +int thermal_iio_sensor_register(struct thermal_zone_device *tz);
> +int thermal_iio_sensor_unregister(struct thermal_zone_device *tz);
> +int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event);
> +
> +#else
> +
> +static int thermal_iio_sensor_register(struct thermal_zone_device *tz)
> +{
> + return 0;
> +}
> +
> +static int thermal_iio_sensor_unregister(struct thermal_zone_device *tz)
> +{
> + return 0;
> +}
> +
> +static int thermal_iio_sensor_notify(struct thermal_zone_device *tz,
> + enum thermal_device_event_type event)
> +
> +{
> + return 0;
> +}
> +
> +#endif
> +#endif
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index c074f6a..925d1e5 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -114,6 +114,13 @@ struct thermal_zone_device_ops {
> int (*set_emul_temp) (struct thermal_zone_device *, int);
> int (*get_trend) (struct thermal_zone_device *, int,
> enum thermal_trend *);
> + int (*get_threshold_temp)(struct thermal_zone_device *, int,
> + int *);
> + int (*set_threshold_temp)(struct thermal_zone_device *, int,
> + int);
> + int (*set_notification_status)(struct thermal_zone_device *,
> + bool status);
> + bool (*check_notification_support)(struct thermal_zone_device *);
Can an existing thermal sensor benefit of the new functionality? If yes,
that is the correct path for it, which code changes are required?
The problem I have with the above is the fact that they add callbacks
and behavior eligible only for a subset of thermal zones.
If we are moving to IIO integrated mode, the existing drivers need to be
converted, to avoid diversification of behavior. For example, there is
existing notification callbacks. Also, hot trip points are described as
notification points.
I believe the patch set needs to document also the next steps on this
move.
> int (*notify) (struct thermal_zone_device *, int,
> enum thermal_trip_type);
> };
> @@ -148,6 +155,8 @@ struct thermal_attr {
> char name[THERMAL_NAME_LENGTH];
> };
>
> +struct iio_dev;
> +
> /**
> * struct thermal_zone_device - structure for a thermal zone
> * @id: unique id number for each thermal zone
> @@ -182,6 +191,7 @@ struct thermal_attr {
> * @lock: lock to protect thermal_instances list
> * @node: node in thermal_tz_list (in thermal_core.c)
> * @poll_queue: delayed work for polling
> + * @indio_dev: pointer to instance of an IIO dev for this zone
> */
> struct thermal_zone_device {
> int id;
> @@ -208,6 +218,9 @@ struct thermal_zone_device {
> struct mutex lock;
> struct list_head node;
> struct delayed_work poll_queue;
> +#if defined(CONFIG_THERMAL_IIO)
> + struct iio_dev *indio_dev;
> +#endif
> };
>
> /**
> --
> 2.4.3
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/6] thermal: iio device for thermal sensor
2015-12-31 19:18 ` Eduardo Valentin
@ 2015-12-31 23:18 ` Srinivas Pandruvada
2015-12-31 23:31 ` Pandruvada, Srinivas
0 siblings, 1 reply; 15+ messages in thread
From: Srinivas Pandruvada @ 2015-12-31 23:18 UTC (permalink / raw)
To: Eduardo Valentin; +Cc: jic23, rui.zhang, linux-pm, linux-iio
On Thu, 2015-12-31 at 11:18 -0800, Eduardo Valentin wrote:
> On Sat, Sep 26, 2015 at 03:05:08PM -0700, Srinivas Pandruvada wrote:
> > This change registers temperature sensor in a thermal zone as an
> > IIO
> > temperature device. This allows user space thermal application to
> > fully
> > utilize IIO capability to read temperature events and samples.
> > The primary motivation for this change to improve performance for
> > user
> > space thermal controllers like Linux thermal daemon or Intel®
> > Dynamic
> > Platform and Thermal Framework (DPTF) for Chromium OS.
> > The current sysfs has several limitations, which forces the current
> > user space to use polling as the safe way. This polling causes
> > performance
> > bottlenecks as some devices requires extremely aggressive response
> > to
> > changing temperature conditions.
> > These are some limitations, which this change tries to address:
> > - Temperature reading via sysfs attribute, which needs conversion
> > from
> > string to int
> > - No way to set threshold settings to avoid polling for temperature
> > change
> > without using a RW passive trip point.
> > - Event notifications via slow kobject uevents, which needs parsing
> > to id
> > the zone and read temperature
> > - Only pull interface from user space, kernel drivers can't send
> > samples
> > - One sample at a time read from user space
> > These limitations can be addressed by registering temperature
> > sensor
> > as an IIO device. IIO provides
> > - buffered access via /dev/iio:deviceX node with select/poll
> > capability
> > - temperature thresholds setting via iio event thresholds
> > - Wait and receive events
> > - Able to use different external trigger (data ready indications)
> > and push
> > samples to buffers
> >
> > Next set of patches uses the IIO binding introduced in this
> > patchset.
> > The iio device created during call to thermal_zone_device_register.
> > Samples
> > are pushed to iio buffers when thermal_zone_device_update is called
> > from
> > client drivers.
> >
> > New thermal zone device callbacks:
> > It introduces three new callbacks for thermal client drivers:
> > get_threshold_temp: Get the current threshold temperature
> > set_threshold_temp: Set the current threshold temperature
> > check_notification_support: Inform that the client driver has
> > asynchronous
> > notification mechanism. If it is then polling can be avoided for
> > the
> > temperature sensor.
> >
> > Signed-off-by: Srinivas Pandruvada <
> > srinivas.pandruvada@linux.intel.com>
> > ---
[Cut]
> >
> > + int (*get_threshold_temp)(struct thermal_zone_device *, > >
> > int,
> > + int *);
> > + int (*set_threshold_temp)(struct thermal_zone_device *,
> > int,
> > + int);
> > + int (*set_notification_status)(struct thermal_zone_device
> > *,
> > + bool status);
> > + bool (*check_notification_support)(struct
> > thermal_zone_device *);
>
>
> Can an existing thermal sensor benefit of the new functionality? If
> yes,
Yes. The existing driver will be using the trips instead of thresholds.
As we discussed during LPC,
trips (pasive/active/..): These are temperature points to which a
cooling action can be performed by binding a cooling device. The
existing drivers who support RW trips, user space still can update
those and get sample notifications. Existing drivers either have
polling or interrupt suport to evaluate trips and call
thermal_zone_device_update(), which will result in sample pushed to
user space.
Thresholds: These are sensor temperature points which user space wants
to get notification of temperature change. They will not be presented
as passive/active/hot trips. User space can decide what to do with the
notifications. If existing drivers don't want to present as fake trips,
then they need to add the callback support.
> The problem I have with the above is the fact that they add callbacks
> and behavior eligible only for a subset of thermal zones.
>
> If we are moving to IIO integrated mode, the existing drivers need to
> be
> converted, to avoid diversification of behavior. For example, there
> is
> existing notification callbacks. Also, hot trip points are described
> as
> notification points.
>
> I believe the patch set needs to document also the next steps on this
> move.
>
If we decide to merge this functionality, I will push a documentation
and IIO sample program to use these features.
Thanks,
Srinivas
>
> > int (*notify) (struct thermal_zone_device *, int,
> > enum thermal_trip_type);
> > };
> > @@ -148,6 +155,8 @@ struct thermal_attr {
> > char name[THERMAL_NAME_LENGTH];
> > };
> >
> > +struct iio_dev;
> > +
> > /**
> > * struct thermal_zone_device - structure for a thermal zone
> > * @id: unique id number for each thermal zone
> > @@ -182,6 +191,7 @@ struct thermal_attr {
> > * @lock: lock to protect thermal_instances list
> > * @node: node in thermal_tz_list (in thermal_core.c)
> > * @poll_queue: delayed work for polling
> > + * @indio_dev: pointer to instance of an IIO dev for this
> > zone
> > */
> > struct thermal_zone_device {
> > int id;
> > @@ -208,6 +218,9 @@ struct thermal_zone_device {
> > struct mutex lock;
> > struct list_head node;
> > struct delayed_work poll_queue;
> > +#if defined(CONFIG_THERMAL_IIO)
> > + struct iio_dev *indio_dev;
> > +#endif
> > };
> >
> > /**
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/6] thermal: iio device for thermal sensor
2015-12-31 23:18 ` Srinivas Pandruvada
@ 2015-12-31 23:31 ` Pandruvada, Srinivas
0 siblings, 0 replies; 15+ messages in thread
From: Pandruvada, Srinivas @ 2015-12-31 23:31 UTC (permalink / raw)
To: edubezval@gmail.com
Cc: Zhang, Rui, linux-iio@vger.kernel.org, jic23@kernel.org,
linux-pm@vger.kernel.org
T24gVGh1LCAyMDE1LTEyLTMxIGF0IDE1OjE4IC0wODAwLCBTcmluaXZhcyBQYW5kcnV2YWRhIHdy
b3RlOg0KPiBPbiBUaHUsIDIwMTUtMTItMzEgYXQgMTE6MTggLTA4MDAsIEVkdWFyZG8gVmFsZW50
aW4gd3JvdGU6DQo+ID4gT24gU2F0LCBTZXAgMjYsIDIwMTUgYXQgMDM6MDU6MDhQTSAtMDcwMCwg
U3Jpbml2YXMgUGFuZHJ1dmFkYQ0KPiA+IHdyb3RlOg0KPiA+ID4gVGhpcyBjaGFuZ2UgcmVnaXN0
ZXJzIHRlbXBlcmF0dXJlIHNlbnNvciBpbiBhIHRoZXJtYWwgem9uZSBhcyBhbg0KPiA+ID4gSUlP
DQo+ID4gPiB0ZW1wZXJhdHVyZSBkZXZpY2UuIFRoaXMgYWxsb3dzIHVzZXIgc3BhY2UgdGhlcm1h
bCBhcHBsaWNhdGlvbiB0bw0KPiA+ID4gZnVsbHkNCj4gPiA+IHV0aWxpemUgSUlPIGNhcGFiaWxp
dHkgdG8gcmVhZCB0ZW1wZXJhdHVyZSBldmVudHMgYW5kIHNhbXBsZXMuDQo+ID4gPiBUaGUgcHJp
bWFyeSBtb3RpdmF0aW9uIGZvciB0aGlzIGNoYW5nZSB0byBpbXByb3ZlIHBlcmZvcm1hbmNlIGZv
cg0KPiA+ID4gdXNlcg0KPiA+ID4gc3BhY2UgdGhlcm1hbCBjb250cm9sbGVycyBsaWtlIExpbnV4
IHRoZXJtYWwgZGFlbW9uIG9yIEludGVswq4NCj4gPiA+IER5bmFtaWMNCj4gPiA+IFBsYXRmb3Jt
IGFuZCBUaGVybWFsIEZyYW1ld29yayAoRFBURikgZm9yIENocm9taXVtIE9TLg0KPiA+ID4gVGhl
IGN1cnJlbnQgc3lzZnMgaGFzIHNldmVyYWwgbGltaXRhdGlvbnMsIHdoaWNoIGZvcmNlcyB0aGUN
Cj4gPiA+IGN1cnJlbnQNCj4gPiA+IHVzZXIgc3BhY2UgdG8gdXNlIHBvbGxpbmcgYXMgdGhlIHNh
ZmUgd2F5LiBUaGlzIHBvbGxpbmcgY2F1c2VzDQo+ID4gPiBwZXJmb3JtYW5jZQ0KPiA+ID4gYm90
dGxlbmVja3MgYXMgc29tZSBkZXZpY2VzIHJlcXVpcmVzIGV4dHJlbWVseSBhZ2dyZXNzaXZlDQo+
ID4gPiByZXNwb25zZQ0KPiA+ID4gdG8NCj4gPiA+IGNoYW5naW5nIHRlbXBlcmF0dXJlIGNvbmRp
dGlvbnMuDQo+ID4gPiBUaGVzZSBhcmUgc29tZSBsaW1pdGF0aW9ucywgd2hpY2ggdGhpcyBjaGFu
Z2UgdHJpZXMgdG8gYWRkcmVzczoNCj4gPiA+IC0gVGVtcGVyYXR1cmUgcmVhZGluZyB2aWEgc3lz
ZnMgYXR0cmlidXRlLCB3aGljaCBuZWVkcyBjb252ZXJzaW9uDQo+ID4gPiBmcm9tDQo+ID4gPiBz
dHJpbmcgdG8gaW50DQo+ID4gPiAtIE5vIHdheSB0byBzZXQgdGhyZXNob2xkIHNldHRpbmdzIHRv
IGF2b2lkIHBvbGxpbmcgZm9yDQo+ID4gPiB0ZW1wZXJhdHVyZQ0KPiA+ID4gY2hhbmdlDQo+ID4g
PiB3aXRob3V0IHVzaW5nIGEgUlcgcGFzc2l2ZSB0cmlwIHBvaW50Lg0KPiA+ID4gLSBFdmVudCBu
b3RpZmljYXRpb25zIHZpYSBzbG93IGtvYmplY3QgdWV2ZW50cywgd2hpY2ggbmVlZHMNCj4gPiA+
IHBhcnNpbmcNCj4gPiA+IHRvIGlkDQo+ID4gPiB0aGUgem9uZSBhbmQgcmVhZCB0ZW1wZXJhdHVy
ZQ0KPiA+ID4gLSBPbmx5IHB1bGwgaW50ZXJmYWNlIGZyb20gdXNlciBzcGFjZSwga2VybmVsIGRy
aXZlcnMgY2FuJ3Qgc2VuZA0KPiA+ID4gc2FtcGxlcw0KPiA+ID4gLSBPbmUgc2FtcGxlIGF0IGEg
dGltZSByZWFkIGZyb20gdXNlciBzcGFjZQ0KPiA+ID4gVGhlc2UgbGltaXRhdGlvbnMgY2FuIGJl
IGFkZHJlc3NlZCBieSByZWdpc3RlcmluZyB0ZW1wZXJhdHVyZQ0KPiA+ID4gc2Vuc29yDQo+ID4g
PiBhcyBhbiBJSU8gZGV2aWNlLiBJSU8gcHJvdmlkZXMNCj4gPiA+IC0gYnVmZmVyZWQgYWNjZXNz
IHZpYSAvZGV2L2lpbzpkZXZpY2VYIG5vZGUgd2l0aCBzZWxlY3QvcG9sbA0KPiA+ID4gY2FwYWJp
bGl0eQ0KPiA+ID4gLSB0ZW1wZXJhdHVyZSB0aHJlc2hvbGRzIHNldHRpbmcgdmlhIGlpbyBldmVu
dCB0aHJlc2hvbGRzDQo+ID4gPiAtIFdhaXQgYW5kIHJlY2VpdmUgZXZlbnRzDQo+ID4gPiAtIEFi
bGUgdG8gdXNlIGRpZmZlcmVudCBleHRlcm5hbCB0cmlnZ2VyIChkYXRhIHJlYWR5IGluZGljYXRp
b25zKQ0KPiA+ID4gYW5kIHB1c2gNCj4gPiA+IHNhbXBsZXMgdG8gYnVmZmVycw0KPiA+ID4gDQo+
ID4gPiBOZXh0IHNldCBvZiBwYXRjaGVzIHVzZXMgdGhlIElJTyBiaW5kaW5nIGludHJvZHVjZWQg
aW4gdGhpcw0KPiA+ID4gcGF0Y2hzZXQuDQo+ID4gPiBUaGUgaWlvIGRldmljZSBjcmVhdGVkIGR1
cmluZyBjYWxsIHRvDQo+ID4gPiB0aGVybWFsX3pvbmVfZGV2aWNlX3JlZ2lzdGVyLg0KPiA+ID4g
U2FtcGxlcw0KPiA+ID4gYXJlIHB1c2hlZCB0byBpaW8gYnVmZmVycyB3aGVuIHRoZXJtYWxfem9u
ZV9kZXZpY2VfdXBkYXRlIGlzDQo+ID4gPiBjYWxsZWQNCj4gPiA+IGZyb20NCj4gPiA+IGNsaWVu
dCBkcml2ZXJzLg0KPiA+ID4gDQo+ID4gPiBOZXcgdGhlcm1hbCB6b25lIGRldmljZSBjYWxsYmFj
a3M6DQo+ID4gPiBJdCBpbnRyb2R1Y2VzIHRocmVlIG5ldyBjYWxsYmFja3MgZm9yIHRoZXJtYWwg
Y2xpZW50IGRyaXZlcnM6DQo+ID4gPiBnZXRfdGhyZXNob2xkX3RlbXA6IEdldCB0aGUgY3VycmVu
dCB0aHJlc2hvbGQgdGVtcGVyYXR1cmUNCj4gPiA+IHNldF90aHJlc2hvbGRfdGVtcDogU2V0IHRo
ZSBjdXJyZW50IHRocmVzaG9sZCB0ZW1wZXJhdHVyZQ0KPiA+ID4gY2hlY2tfbm90aWZpY2F0aW9u
X3N1cHBvcnQ6IEluZm9ybSB0aGF0IHRoZSBjbGllbnQgZHJpdmVyIGhhcw0KPiA+ID4gYXN5bmNo
cm9ub3VzDQo+ID4gPiBub3RpZmljYXRpb24gbWVjaGFuaXNtLiBJZiBpdCBpcyB0aGVuIHBvbGxp
bmcgY2FuIGJlIGF2b2lkZWQgZm9yDQo+ID4gPiB0aGUNCj4gPiA+IHRlbXBlcmF0dXJlIHNlbnNv
ci4NCj4gPiA+IA0KPiA+ID4gU2lnbmVkLW9mZi1ieTogU3Jpbml2YXMgUGFuZHJ1dmFkYSA8DQo+
ID4gPiBzcmluaXZhcy5wYW5kcnV2YWRhQGxpbnV4LmludGVsLmNvbT4NCj4gPiA+IC0tLQ0KPiAN
Cj4gW0N1dF0NCj4gDQo+ID4gPiANCj4gPiA+ICsJaW50ICgqZ2V0X3RocmVzaG9sZF90ZW1wKShz
dHJ1Y3QgdGhlcm1hbF96b25lX2RldmljZSAqLA0KPiA+ID4gPiA+IA0KPiA+ID4gaW50LA0KPiA+
ID4gKwkJCQkgIGludCAqKTsNCj4gPiA+ICsJaW50ICgqc2V0X3RocmVzaG9sZF90ZW1wKShzdHJ1
Y3QgdGhlcm1hbF96b25lX2RldmljZSAqLA0KPiA+ID4gaW50LA0KPiA+ID4gKwkJCQkgIGludCk7
DQo+ID4gPiArCWludCAoKnNldF9ub3RpZmljYXRpb25fc3RhdHVzKShzdHJ1Y3QNCj4gPiA+IHRo
ZXJtYWxfem9uZV9kZXZpY2UNCj4gPiA+ICosDQo+ID4gPiArCQkJCSAgICAgICBib29sIHN0YXR1
cyk7DQo+ID4gPiArCWJvb2wgKCpjaGVja19ub3RpZmljYXRpb25fc3VwcG9ydCkoc3RydWN0DQo+
ID4gPiB0aGVybWFsX3pvbmVfZGV2aWNlICopOw0KPiA+IA0KPiA+IA0KPiA+IENhbiBhbiBleGlz
dGluZyB0aGVybWFsIHNlbnNvciBiZW5lZml0IG9mIHRoZSBuZXcgZnVuY3Rpb25hbGl0eT8gSWYN
Cj4gPiB5ZXMsDQo+IA0KPiBZZXMuIFRoZSBleGlzdGluZyBkcml2ZXIgd2lsbCBiZSB1c2luZyB0
aGUgdHJpcHMgaW5zdGVhZCBvZg0KPiB0aHJlc2hvbGRzLg0KPiBBcyB3ZSBkaXNjdXNzZWQgZHVy
aW5nIExQQywNCj4gdHJpcHMgKHBhc2l2ZS9hY3RpdmUvLi4pOiBUaGVzZSBhcmUgdGVtcGVyYXR1
cmUgcG9pbnRzIHRvIHdoaWNoIGENCj4gY29vbGluZyBhY3Rpb24gY2FuIGJlIHBlcmZvcm1lZCBi
eSBiaW5kaW5nIGEgY29vbGluZyBkZXZpY2UuIFRoZQ0KPiBleGlzdGluZyBkcml2ZXJzIHdobyBz
dXBwb3J0IFJXIHRyaXBzLCB1c2VyIHNwYWNlIHN0aWxsIGNhbiB1cGRhdGUNCj4gdGhvc2UgYW5k
IGdldCBzYW1wbGUgbm90aWZpY2F0aW9ucy4gRXhpc3RpbmcgZHJpdmVycyBlaXRoZXIgaGF2ZQ0K
PiBwb2xsaW5nIG9yIGludGVycnVwdCBzdXBvcnQgdG8gZXZhbHVhdGUgdHJpcHMgYW5kIGNhbGwN
Cj4gdGhlcm1hbF96b25lX2RldmljZV91cGRhdGUoKSwgd2hpY2ggd2lsbCByZXN1bHQgaW4gc2Ft
cGxlIHB1c2hlZCB0bw0KPiB1c2VyIHNwYWNlLg0KPiAgDQo+IFRocmVzaG9sZHM6IFRoZXNlIGFy
ZSBzZW5zb3IgdGVtcGVyYXR1cmUgcG9pbnRzIHdoaWNoIHVzZXIgc3BhY2UNCj4gd2FudHMNCj4g
dG8gZ2V0IG5vdGlmaWNhdGlvbiBvZiB0ZW1wZXJhdHVyZSBjaGFuZ2UuIFRoZXkgd2lsbCBub3Qg
YmUgcHJlc2VudGVkDQo+IGFzIHBhc3NpdmUvYWN0aXZlL2hvdCB0cmlwcy4gVXNlciBzcGFjZSBj
YW4gZGVjaWRlIHdoYXQgdG8gZG8gd2l0aA0KPiB0aGUNCj4gbm90aWZpY2F0aW9ucy4gSWYgZXhp
c3RpbmcgZHJpdmVycyBkb24ndCB3YW50IHRvIHByZXNlbnQgYXMgZmFrZQ0KPiB0cmlwcywNCj4g
dGhlbiB0aGV5IG5lZWQgdG8gYWRkIHRoZSBjYWxsYmFjayBzdXBwb3J0Lg0KPiANCj4gPiBUaGUg
cHJvYmxlbSBJIGhhdmUgd2l0aCB0aGUgYWJvdmUgaXMgdGhlIGZhY3QgdGhhdCB0aGV5IGFkZA0K
PiA+IGNhbGxiYWNrcw0KPiA+IGFuZCBiZWhhdmlvciBlbGlnaWJsZSBvbmx5IGZvciBhIHN1YnNl
dCBvZiB0aGVybWFsIHpvbmVzLg0KPiA+IA0KPiA+IElmIHdlIGFyZSBtb3ZpbmcgdG8gSUlPIGlu
dGVncmF0ZWQgbW9kZSwgdGhlIGV4aXN0aW5nIGRyaXZlcnMgbmVlZA0KPiA+IHRvDQo+ID4gYmUN
Cj4gPiBjb252ZXJ0ZWQsIHRvIGF2b2lkIGRpdmVyc2lmaWNhdGlvbiBvZiBiZWhhdmlvci4gRm9y
IGV4YW1wbGUsIHRoZXJlDQo+ID4gaXMNCj4gPiBleGlzdGluZyBub3RpZmljYXRpb24gY2FsbGJh
Y2tzLiBBbHNvLCBob3QgdHJpcCBwb2ludHMgYXJlDQo+ID4gZGVzY3JpYmVkDQo+ID4gYXMNCj4g
PiBub3RpZmljYXRpb24gcG9pbnRzLg0KPiA+IA0KPiA+IEkgYmVsaWV2ZSB0aGUgcGF0Y2ggc2V0
IG5lZWRzIHRvIGRvY3VtZW50IGFsc28gdGhlIG5leHQgc3RlcHMgb24NCj4gPiB0aGlzDQo+ID4g
bW92ZS4NCj4gPiANCj4gDQo+IElmIHdlIGRlY2lkZSB0byBtZXJnZSB0aGlzIGZ1bmN0aW9uYWxp
dHksIEkgd2lsbCBwdXNoIGEgZG9jdW1lbnRhdGlvbg0KPiBhbmQgSUlPIHNhbXBsZSBwcm9ncmFt
IHRvIHVzZSB0aGVzZSBmZWF0dXJlcy4NCj4gDQpUaGUgc2VyaXMgaXMgb2xkIGVub3VnaCwgSSBm
b3Jnb3QuIFRoZSBwYXRjaCBhZGRzIGRvY3VtZW50YXRpb24NCltQQVRDSCA1LzZdIHRoZXJtYWw6
IGlpbyBEb2N1bWVudGF0aW9uDQpUaGVyZSBpcyBhbHdheXMgc2NvcGUgdG8gYWRkIG1vcmUuDQoN
ClRoYW5rcywNClNyaW5pdmFzDQoNCg0KPiBUaGFua3MsDQo+IFNyaW5pdmFzDQo+IA0KPiA+IA0K
PiA+ID4gIAlpbnQgKCpub3RpZnkpIChzdHJ1Y3QgdGhlcm1hbF96b25lX2RldmljZSAqLCBpbnQs
DQo+ID4gPiAgCQkgICAgICAgZW51bSB0aGVybWFsX3RyaXBfdHlwZSk7DQo+ID4gPiAgfTsNCj4g
PiA+IEBAIC0xNDgsNiArMTU1LDggQEAgc3RydWN0IHRoZXJtYWxfYXR0ciB7DQo+ID4gPiAgCWNo
YXIgbmFtZVtUSEVSTUFMX05BTUVfTEVOR1RIXTsNCj4gPiA+ICB9Ow0KPiA+ID4gIA0KPiA+ID4g
K3N0cnVjdCBpaW9fZGV2Ow0KPiA+ID4gKw0KPiA+ID4gIC8qKg0KPiA+ID4gICAqIHN0cnVjdCB0
aGVybWFsX3pvbmVfZGV2aWNlIC0gc3RydWN0dXJlIGZvciBhIHRoZXJtYWwgem9uZQ0KPiA+ID4g
ICAqIEBpZDoJCXVuaXF1ZSBpZCBudW1iZXIgZm9yIGVhY2ggdGhlcm1hbCB6b25lDQo+ID4gPiBA
QCAtMTgyLDYgKzE5MSw3IEBAIHN0cnVjdCB0aGVybWFsX2F0dHIgew0KPiA+ID4gICAqIEBsb2Nr
Oglsb2NrIHRvIHByb3RlY3QgdGhlcm1hbF9pbnN0YW5jZXMgbGlzdA0KPiA+ID4gICAqIEBub2Rl
Oglub2RlIGluIHRoZXJtYWxfdHpfbGlzdCAoaW4gdGhlcm1hbF9jb3JlLmMpDQo+ID4gPiAgICog
QHBvbGxfcXVldWU6CWRlbGF5ZWQgd29yayBmb3IgcG9sbGluZw0KPiA+ID4gKyAqIEBpbmRpb19k
ZXY6CXBvaW50ZXIgdG8gaW5zdGFuY2Ugb2YgYW4gSUlPIGRldiBmb3IgdGhpcw0KPiA+ID4gem9u
ZQ0KPiA+ID4gICAqLw0KPiA+ID4gIHN0cnVjdCB0aGVybWFsX3pvbmVfZGV2aWNlIHsNCj4gPiA+
ICAJaW50IGlkOw0KPiA+ID4gQEAgLTIwOCw2ICsyMTgsOSBAQCBzdHJ1Y3QgdGhlcm1hbF96b25l
X2RldmljZSB7DQo+ID4gPiAgCXN0cnVjdCBtdXRleCBsb2NrOw0KPiA+ID4gIAlzdHJ1Y3QgbGlz
dF9oZWFkIG5vZGU7DQo+ID4gPiAgCXN0cnVjdCBkZWxheWVkX3dvcmsgcG9sbF9xdWV1ZTsNCj4g
PiA+ICsjaWYgZGVmaW5lZChDT05GSUdfVEhFUk1BTF9JSU8pDQo+ID4gPiArCXN0cnVjdCBpaW9f
ZGV2ICppbmRpb19kZXY7DQo+ID4gPiArI2VuZGlmDQo+ID4gPiAgfTsNCj4gPiA+ICA=
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2015-12-31 23:31 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-26 22:05 [PATCH 0/6] thermal: iio bindings Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 1/6] thermal: core: enhance thermal_zone_device_update Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 2/6] thermal: documentation update Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 3/6] thermal: iio device for thermal sensor Srinivas Pandruvada
2015-09-27 18:18 ` Jonathan Cameron
2015-12-31 19:18 ` Eduardo Valentin
2015-12-31 23:18 ` Srinivas Pandruvada
2015-12-31 23:31 ` Pandruvada, Srinivas
2015-09-26 22:05 ` [PATCH 4/6] thermal: use iio binding calls Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 5/6] thermal: iio Documentation Srinivas Pandruvada
2015-09-27 18:23 ` Jonathan Cameron
2015-10-02 17:01 ` Srinivas Pandruvada
2015-09-26 22:05 ` [PATCH 6/6] thermal: x86_pkg_temp: Register threshold callbacks Srinivas Pandruvada
2015-09-27 11:24 ` [PATCH 0/6] thermal: iio bindings Daniel Lezcano
2015-09-27 14:29 ` Srinivas Pandruvada
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).