From patchwork Mon Apr 18 03:35:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Caesar Wang X-Patchwork-Id: 8867291 Return-Path: X-Original-To: patchwork-linux-rockchip@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 961169F36E for ; Mon, 18 Apr 2016 03:38:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 63E6C20204 for ; Mon, 18 Apr 2016 03:38:46 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CEDF7201DD for ; Mon, 18 Apr 2016 03:38:44 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1as01M-0001Fc-Eu; Mon, 18 Apr 2016 03:38:44 +0000 Received: from mail-pa0-f66.google.com ([209.85.220.66]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1as01E-0000hp-BR for linux-rockchip@lists.infradead.org; Mon, 18 Apr 2016 03:38:38 +0000 Received: by mail-pa0-f66.google.com with SMTP id hb4so15077412pac.1 for ; Sun, 17 Apr 2016 20:38:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RdK873cprWPMadVADXTFfjOrfkhHNYea3UhTdW13O30=; b=GiTLCJot73stNliIsUC/2C7L0vc2ggfD/JyaEOhZFyuduMTG5kDjg3aPdGX4vwSQn0 pcg+2SXLvmpUFI6i126JFv3oRSRRUdLqzQUk9ycpJ/XNl6Q0R39ll6WjpShFbbk1WHs/ LIKaXCY6LI+vF0YbDdK/MSOhE9crH2VgmPmLJUYDX+q4GfG6GlI8moBXmjZOBtXsiUHv FW/ejH2OFL7j7nWM0DqBrnCeg5Vzh8OuvNDYBA0sehRfP8k3alPB247toZcDntdJ/Kbs vaM9gJlgKBq8QyCDaxDyFEFt2BKxgZKtMjQF4plpr/M8HOrQLyUUZCSGuL1cVP4YK4fT mjAw== X-Gm-Message-State: AOPr4FX1c/0+S+3OOPQOfIJ14nKir9QMSqM+fCoWrMSLDx2czTP3HGNKHVj+vaf0q4y+9Q== X-Received: by 10.66.124.198 with SMTP id mk6mr46135120pab.25.1460950695892; Sun, 17 Apr 2016 20:38:15 -0700 (PDT) Received: from localhost.localdomain ([104.37.5.139]) by smtp.gmail.com with ESMTPSA id tp9sm79756867pab.14.2016.04.17.20.38.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 17 Apr 2016 20:38:15 -0700 (PDT) From: Caesar Wang To: edubezval@gmail.com Subject: [PATCH 7/9] thermal: of: Add support for hardware-tracked trip points Date: Mon, 18 Apr 2016 11:35:59 +0800 Message-Id: <1460950562-20652-8-git-send-email-wxt@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1460950562-20652-1-git-send-email-wxt@rock-chips.com> References: <1460950562-20652-1-git-send-email-wxt@rock-chips.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160417_203836_692766_37D06DE5 X-CRM114-Status: GOOD ( 20.24 ) X-Spam-Score: -2.4 (--) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Wei Ni , Heiko Stuebner , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, dianders@chromium.org, Mikko Perttunen , linux-rockchip@lists.infradead.org, smbarber@google.com, Paul Walmsley , briannorris@google.com, Zhang Rui , Caesar Wang MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Mikko Perttunen This adds support for hardware-tracked trip points to the device tree thermal sensor framework. The framework supports an arbitrary number of trip points. Whenever the current temperature is updated, the trip points immediately below and above the current temperature are found. A sensor driver callback `set_trips' is then called with the temperatures. If there is no trip point above or below the current temperature, the passed trip temperature will be LONG_MAX or LONG_MIN respectively. In this callback, the driver should program the hardware such that it is notified when either of these trip points are triggered. When a trip point is triggered, the driver should call `thermal_zone_device_update' for the respective thermal zone. This will cause the trip points to be updated again. If the `set_trips' callback is not implemented (is NULL), the framework behaves as before. CQ-DEPEND=CL:*210768 Signed-off-by: Mikko Perttunen Signed-off-by: Paul Walmsley Signed-off-by: Wei Ni https://chromium-review.googlesource.com/212425 Reviewed-by: Olof Johansson Tested-by: Olof Johansson Reviewed-by: Dylan Reid Tested-by: Dylan Reid Tested-by: David Riley Reviewed-by: David Riley (cherry-picked from https://chromium.googlesource.com/chromiumos/ third_party/kernel/+/v3.18 commit 397befabb2a52fc16586509a970f8c98268b8040) Signed-off-by: Caesar Wang Cc: Zhang Rui Cc: Eduardo Valentin Cc: Heiko Stuebner --- drivers/thermal/of-thermal.c | 82 +++++++++++++++++++++++++++++++++++++++++++- include/linux/thermal.h | 2 ++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 8528802..cffa2a2 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -60,6 +60,8 @@ struct __thermal_bind_params { * @polling_delay: zone polling interval * @slope: slope of the temperature adjustment curve * @offset: offset of the temperature adjustment curve + * @prev_low_trip: previous low trip point temperature + * @prev_high_trip: previous high trip point temperature * @ntrips: number of trip points * @trips: an array of trip points (0..ntrips - 1) * @num_tbps: number of thermal bind params @@ -74,6 +76,7 @@ struct __thermal_zone { int polling_delay; int slope; int offset; + int prev_low_trip, prev_high_trip; /* trip data */ int ntrips; @@ -88,17 +91,63 @@ struct __thermal_zone { const struct thermal_zone_of_device_ops *ops; }; +/*** Automatic trip handling ***/ + +static int of_thermal_set_trips(struct thermal_zone_device *tz, int temp) +{ + struct __thermal_zone *data = tz->devdata; + int low = INT_MIN, high = INT_MAX; + int i; + + /* Hardware trip points not supported */ + if (!data->ops->set_trips) + return 0; + + /* No need to change trip points */ + if (temp > data->prev_low_trip && temp < data->prev_high_trip) + return 0; + + for (i = 0; i < data->ntrips; ++i) { + struct thermal_trip *trip = data->trips + i; + int trip_low = trip->temperature - trip->hysteresis; + + if (trip_low < temp && trip_low > low) + low = trip_low; + + if (trip->temperature > temp && trip->temperature < high) + high = trip->temperature; + } + + dev_dbg(&tz->device, + "temperature %d, updating trip points to %d, %d\n", + temp, low, high); + + data->prev_low_trip = low; + data->prev_high_trip = high; + + return data->ops->set_trips(data->sensor_data, low, high); +} + /*** DT thermal zone device callbacks ***/ static int of_thermal_get_temp(struct thermal_zone_device *tz, int *temp) { struct __thermal_zone *data = tz->devdata; + int err; if (!data->ops->get_temp) return -EINVAL; - return data->ops->get_temp(data->sensor_data, temp); + err = data->ops->get_temp(data->sensor_data, temp); + if (err) + return err; + + err = of_thermal_set_trips(tz, *temp); + if (err) + return err; + + return 0; } /** @@ -297,6 +346,22 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz, return 0; } +static int of_thermal_update_trips(struct thermal_zone_device *tz) +{ + int temp; + int err; + + err = of_thermal_get_temp(tz, &temp); + if (err) + return err; + + err = of_thermal_set_trips(tz, temp); + if (err) + return err; + + return 0; +} + static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, enum thermal_trip_type *type) { @@ -327,6 +392,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, int temp) { struct __thermal_zone *data = tz->devdata; + int err; if (trip >= data->ntrips || trip < 0) return -EDOM; @@ -342,6 +408,10 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, /* thermal framework should take care of data->mask & (1 << trip) */ data->trips[trip].temperature = temp; + err = of_thermal_update_trips(tz); + if (err) + return err; + return 0; } @@ -362,6 +432,7 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, int hyst) { struct __thermal_zone *data = tz->devdata; + int err; if (trip >= data->ntrips || trip < 0) return -EDOM; @@ -369,6 +440,10 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, /* thermal framework should take care of data->mask & (1 << trip) */ data->trips[trip].hysteresis = hyst; + err = of_thermal_update_trips(tz); + if (err) + return err; + return 0; } @@ -425,6 +500,8 @@ thermal_zone_of_add_sensor(struct device_node *zone, tz->ops = ops; tz->sensor_data = data; + of_thermal_update_trips(tzd); + tzd->ops->get_temp = of_thermal_get_temp; tzd->ops->get_trend = of_thermal_get_trend; tzd->ops->set_emul_temp = of_thermal_set_emul_temp; @@ -859,6 +936,9 @@ thermal_of_build_thermal_zone(struct device_node *np) /* trips */ child = of_get_child_by_name(np, "trips"); + tz->prev_high_trip = INT_MIN; + tz->prev_low_trip = INT_MAX; + /* No trips provided */ if (!child) goto finish; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 97b86c5..6ef932a 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -335,12 +335,14 @@ struct thermal_genl_event { * @get_trend: a pointer to a function that reads the sensor temperature trend. * @set_emul_temp: a pointer to a function that sets sensor emulated * temperature. + * @set_trips: a pointer to a function that set low/high trip temperature. */ struct thermal_zone_of_device_ops { int (*get_temp)(void *, int *); int (*get_trend)(void *, long *); int (*set_emul_temp)(void *, int); int (*set_trip_temp)(void *, int, int); + int (*set_trips)(void *, int, int); }; /**