From patchwork Fri Feb 23 16:23:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 129436 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp789275lja; Fri, 23 Feb 2018 08:24:26 -0800 (PST) X-Google-Smtp-Source: AH8x225ICA0FggpCjdLs1aQyF/pXBvw2o90sFghzk6PpBeBek+3f1GfZ241M888+tom9BkOtXcO7 X-Received: by 2002:a17:902:b7c2:: with SMTP id v2-v6mr2175284plz.351.1519403066837; Fri, 23 Feb 2018 08:24:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519403066; cv=none; d=google.com; s=arc-20160816; b=FeHjWQ/dceHG5ZQj88N/8d+AIA0M7FRT/FbPmY3MfIDmv2jA0VLzqGS/mivG9ueiHP X9vQ5Cejc/11Rhy6dBm24L2Q7IgPPB8Ikp5RNBCf44kZK2wn0vZzsQ46QVm26sQHhvgw +TVnJJVqdbmNo9kpe9RGALDyBHkd7+xl7fcDB+YtElGP++C3ZjuBf+P9JjjqRkpbayrE hsBgUB2acHqJq4g6L4sn89RlAZAoGR90mnKfmPfLHj55A9PV4nWWINF8ydiD1OTi0Y/p 9eB3AaOd100q1ea4jhuOcDP1PyTI6oHcfsAuQChAAAEVk/uEER/vAGiS3bpIRnMGx6wj 1OMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=C5R9xw8ARYHZObto4zYusUHQ6n53kG2ftYFz+s3XDTE=; b=yZtq8W/0GawIYoWC23pLdFOgLWrXpUl0AzDsw4YEsV1VkbWV/DMZfsAx89VGYBiNDX RikA8J/C9ozLrLSo5feO5GQ2p/l4GgHLoFieCfWCeSTh98w++qkGnRHrKG0suKkWuokO NITJ3mhfdLOx12ljbQ711qz+BYaX0husNNmkv4s0aQ8Mznrkte5n5uPqyuJQySW+vQDi ORH+FgC0qBIfK8WisiKY2ZSwDwmR5k65jGN3govEqpodt+Bg7SENcZVmeC8bTc066Jy1 u4iA74opIkO/+nmrMkMYxUPNxPxn5i15AuUF9n4idX9PiVJru61eCgQJ77/H56tpqclf b9tA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t64si1692392pgb.294.2018.02.23.08.24.26; Fri, 23 Feb 2018 08:24:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751887AbeBWQYX (ORCPT + 6 others); Fri, 23 Feb 2018 11:24:23 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57288 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751841AbeBWQYV (ORCPT ); Fri, 23 Feb 2018 11:24:21 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0980F1529; Fri, 23 Feb 2018 08:24:21 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id A81523F25C; Fri, 23 Feb 2018 08:24:19 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Alexey Klimov , Arnd Bergmann , Greg Kroah-Hartman Subject: [PATCH v6 08/20] firmware: arm_scmi: add initial support for power protocol Date: Fri, 23 Feb 2018 16:23:38 +0000 Message-Id: <1519403030-21189-9-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> References: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The power protocol is intended for management of power states of various power domains. The power domain management protocol provides commands to describe the protocol version, discover the implementation specific attributes, set and get the power state of a domain. This patch adds support for the above mention features of the protocol. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla -- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 242 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 28 +++++ 3 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/power.c | 232 +++++++++++++++++++++++++++++++++++++ include/linux/scmi_protocol.h | 28 +++++ 3 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/power.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 2130ee9ac825..420c761ced94 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,4 +1,4 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-protocols-y = base.o clock.o perf.o +scmi-protocols-y = base.o clock.o perf.o power.o diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c new file mode 100644 index 000000000000..baf92a15b7e9 --- /dev/null +++ b/drivers/firmware/arm_scmi/power.c @@ -0,0 +1,232 @@ +/* + * System Control and Management Interface (SCMI) Power Protocol + * + * Copyright (C) 2017 ARM Ltd. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "common.h" + +enum scmi_power_protocol_cmd { + POWER_DOMAIN_ATTRIBUTES = 0x3, + POWER_STATE_SET = 0x4, + POWER_STATE_GET = 0x5, + POWER_STATE_NOTIFY = 0x6, +}; + +struct scmi_msg_resp_power_attributes { + __le16 num_domains; + __le16 reserved; + __le32 stats_addr_low; + __le32 stats_addr_high; + __le32 stats_size; +}; + +struct scmi_msg_resp_power_domain_attributes { + __le32 flags; +#define SUPPORTS_STATE_SET_NOTIFY(x) ((x) & BIT(31)) +#define SUPPORTS_STATE_SET_ASYNC(x) ((x) & BIT(30)) +#define SUPPORTS_STATE_SET_SYNC(x) ((x) & BIT(29)) + u8 name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_set_state { + __le32 flags; +#define STATE_SET_ASYNC BIT(0) + __le32 domain; + __le32 state; +}; + +struct scmi_power_state_notify { + __le32 domain; + __le32 notify_enable; +}; + +struct power_dom_info { + bool state_set_sync; + bool state_set_async; + bool state_set_notify; + char name[SCMI_MAX_STR_SIZE]; +}; + +struct scmi_power_info { + int num_domains; + u64 stats_addr; + u32 stats_size; + struct power_dom_info *dom_info; +}; + +static int scmi_power_attributes_get(const struct scmi_handle *handle, + struct scmi_power_info *pi) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_attributes *attr; + + ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + pi->num_domains = le16_to_cpu(attr->num_domains); + pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | + (u64)le32_to_cpu(attr->stats_addr_high) << 32; + pi->stats_size = le32_to_cpu(attr->stats_size); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, + struct power_dom_info *dom_info) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_power_domain_attributes *attr; + + ret = scmi_one_xfer_init(handle, POWER_DOMAIN_ATTRIBUTES, + SCMI_PROTOCOL_POWER, sizeof(domain), + sizeof(*attr), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + attr = t->rx.buf; + + ret = scmi_do_xfer(handle, t); + if (!ret) { + u32 flags = le32_to_cpu(attr->flags); + + dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags); + dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags); + dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags); + memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); + } + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) +{ + int ret; + struct scmi_xfer *t; + struct scmi_power_set_state *st; + + ret = scmi_one_xfer_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, + sizeof(*st), 0, &t); + if (ret) + return ret; + + st = t->tx.buf; + st->flags = cpu_to_le32(0); + st->domain = cpu_to_le32(domain); + st->state = cpu_to_le32(state); + + ret = scmi_do_xfer(handle, t); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int +scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_one_xfer_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, + sizeof(u32), sizeof(u32), &t); + if (ret) + return ret; + + *(__le32 *)t->tx.buf = cpu_to_le32(domain); + + ret = scmi_do_xfer(handle, t); + if (!ret) + *state = le32_to_cpu(*(__le32 *)t->rx.buf); + + scmi_one_xfer_put(handle, t); + return ret; +} + +static int scmi_power_num_domains_get(const struct scmi_handle *handle) +{ + struct scmi_power_info *pi = handle->power_priv; + + return pi->num_domains; +} + +static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain) +{ + struct scmi_power_info *pi = handle->power_priv; + struct power_dom_info *dom = pi->dom_info + domain; + + return dom->name; +} + +static struct scmi_power_ops power_ops = { + .num_domains_get = scmi_power_num_domains_get, + .name_get = scmi_power_name_get, + .state_set = scmi_power_state_set, + .state_get = scmi_power_state_get, +}; + +static int scmi_power_protocol_init(struct scmi_handle *handle) +{ + int domain; + u32 version; + struct scmi_power_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_POWER, &version); + + dev_dbg(handle->dev, "Power Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + scmi_power_attributes_get(handle, pinfo); + + pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains, + sizeof(*pinfo->dom_info), GFP_KERNEL); + if (!pinfo->dom_info) + return -ENOMEM; + + for (domain = 0; domain < pinfo->num_domains; domain++) { + struct power_dom_info *dom = pinfo->dom_info + domain; + + scmi_power_domain_attributes_get(handle, domain, dom); + } + + handle->power_ops = &power_ops; + handle->power_priv = pinfo; + + return 0; +} + +static int __init scmi_power_init(void) +{ + return scmi_protocol_register(SCMI_PROTOCOL_POWER, + &scmi_power_protocol_init); +} +subsys_initcall(scmi_power_init); diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index 981523620985..be5396537b91 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -124,10 +124,36 @@ struct scmi_perf_ops { }; /** + * struct scmi_power_ops - represents the various operations provided + * by SCMI Power Protocol + * + * @num_domains_get: get the count of power domains provided by SCMI + * @name_get: gets the name of a power domain + * @state_set: sets the power state of a power domain + * @state_get: gets the power state of a power domain + */ +struct scmi_power_ops { + int (*num_domains_get)(const struct scmi_handle *handle); + char *(*name_get)(const struct scmi_handle *handle, u32 domain); +#define SCMI_POWER_STATE_TYPE_SHIFT 30 +#define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1) +#define SCMI_POWER_STATE_PARAM(type, id) \ + ((((type) & BIT(0)) << SCMI_POWER_STATE_TYPE_SHIFT) | \ + ((id) & SCMI_POWER_STATE_ID_MASK)) +#define SCMI_POWER_STATE_GENERIC_ON SCMI_POWER_STATE_PARAM(0, 0) +#define SCMI_POWER_STATE_GENERIC_OFF SCMI_POWER_STATE_PARAM(1, 0) + int (*state_set)(const struct scmi_handle *handle, u32 domain, + u32 state); + int (*state_get)(const struct scmi_handle *handle, u32 domain, + u32 *state); +}; + +/** * struct scmi_handle - Handle returned to ARM SCMI clients for usage. * * @dev: pointer to the SCMI device * @version: pointer to the structure containing SCMI version information + * @power_ops: pointer to set of power protocol operations * @perf_ops: pointer to set of performance protocol operations * @clk_ops: pointer to set of clock protocol operations */ @@ -136,9 +162,11 @@ struct scmi_handle { struct scmi_revision_info *version; struct scmi_perf_ops *perf_ops; struct scmi_clk_ops *clk_ops; + struct scmi_power_ops *power_ops; /* for protocol internal use */ void *perf_priv; void *clk_priv; + void *power_priv; }; enum scmi_std_protocol { From patchwork Fri Feb 23 16:23:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 129437 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp789346lja; Fri, 23 Feb 2018 08:24:30 -0800 (PST) X-Google-Smtp-Source: AH8x226VJPexB85EfYYyVK7QU/L+GShWqFZCI3zj/UU4RURsNVY8wOIb/9kvqOsqDOvW6OqMXl8U X-Received: by 2002:a17:902:aa83:: with SMTP id d3-v6mr2208256plr.36.1519403070043; Fri, 23 Feb 2018 08:24:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519403070; cv=none; d=google.com; s=arc-20160816; b=Uo8Ux8FCEDUu9XPWz9YPkfuLldUJbEbxxALp0fmokOci8xOMo0SOSVe2YCmJlLFPyl 2V3hTCyBkIX4MUn0iXMJw/TW2Jd1GFjJt0fyajPWPVdpPtKfpfj+xn3wsO2Xa9xakRRf qPBPh0LxJD/Vl4OTiIDiVG5T+GaOnC339Dnrbya0/L5+Ey69hht8OJyVwZR1HmtLYWTP vg4vvTDqVysiFOYVkhJfBdTqjEcfsyyn3Jed1SHCxY/MyTEt9tJMwpPuZI+yKMMoul9e y0OHnguphwNtccOBIYyCO5utmAnglltVsw6G6RooSKGEFBF/gwZ9t0W3F8ODVygKy5rA zwTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=kSf5TsnBVkUyX8P1X1Vz0sWsof1us3ocZzmJZtkSWac=; b=cYuXRzYRatKoJOfWGX2EhZzch8jBRXFiNZYxCyCzOvlfCPPMB99+QOIl/K3Tfu0qav WpC4RhCV6sZPkBHnlOsd9hb2QVzNB4EU0rHKcaUUGVUAAj5smXS+BD4uEp34knBTYyeO lOg/FR8WZ+6/4Vm/pMph/n74W/rHJTavunKfdjSIqUWwGvbmMNFVpap0Pj/XIPEOfEJA 8BvUESbbBnbU0rigIF2Yx14mArRVykXWHy3Fuuolw4uWvdA0JDwverv0MIuo3gfIgFk/ EvJnulxuU9vRvZ9WTliVjY5/uAMRRmwp8JKbJuT0MxYkf+ULcIpr3kMFaFkyFqykb3xO KY2A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g9-v6si1970983plp.423.2018.02.23.08.24.29; Fri, 23 Feb 2018 08:24:30 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751920AbeBWQY2 (ORCPT + 6 others); Fri, 23 Feb 2018 11:24:28 -0500 Received: from foss.arm.com ([217.140.101.70]:57330 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751841AbeBWQY0 (ORCPT ); Fri, 23 Feb 2018 11:24:26 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D2DB51610; Fri, 23 Feb 2018 08:24:25 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7D6F73F25C; Fri, 23 Feb 2018 08:24:24 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Alexey Klimov , Arnd Bergmann , Greg Kroah-Hartman Subject: [PATCH v6 11/20] firmware: arm_scmi: add support for polling based SCMI transfers Date: Fri, 23 Feb 2018 16:23:41 +0000 Message-Id: <1519403030-21189-12-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> References: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org It would be useful to have options to perform some SCMI transfers atomically by polling for the completion flag instead of interrupt driven. The SCMI specification has option to disable the interrupt and poll for the completion flag in the shared memory. This patch adds support for polling based SCMI transfers using that option. This might be used for uninterrupted/atomic DVFS operations from the scheduler context. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 55 ++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 970c3a8c6e96..e6698629e15a 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -29,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -346,6 +348,30 @@ void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) spin_unlock_irqrestore(&minfo->xfer_lock, flags); } +static bool +scmi_xfer_poll_done(const struct scmi_info *info, struct scmi_xfer *xfer) +{ + struct scmi_shared_mem *mem = info->tx_payload; + u16 xfer_id = MSG_XTRACT_TOKEN(le32_to_cpu(mem->msg_header)); + + if (xfer->hdr.seq != xfer_id) + return false; + + return le32_to_cpu(mem->channel_status) & + (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); +} + +#define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC) + +static bool scmi_xfer_done_no_timeout(const struct scmi_info *info, + struct scmi_xfer *xfer, ktime_t stop) +{ + ktime_t __cur = ktime_get(); + + return scmi_xfer_poll_done(info, xfer) || ktime_after(__cur, stop); +} + /** * scmi_do_xfer() - Do one transfer * @@ -372,15 +398,28 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) /* mbox_send_message returns non-negative value on success, so reset */ ret = 0; - /* And we wait for the response. */ - timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); - if (!wait_for_completion_timeout(&xfer->done, timeout)) { - dev_err(dev, "mbox timed out in resp(caller: %pS)\n", - (void *)_RET_IP_); - ret = -ETIMEDOUT; - } else if (xfer->hdr.status) { - ret = scmi_to_linux_errno(xfer->hdr.status); + if (xfer->hdr.poll_completion) { + ktime_t stop = ktime_add_ns(ktime_get(), SCMI_MAX_POLL_TO_NS); + + spin_until_cond(scmi_xfer_done_no_timeout(info, xfer, stop)); + + if (ktime_before(ktime_get(), stop)) + scmi_fetch_response(xfer, info->tx_payload); + else + ret = -ETIMEDOUT; + } else { + /* And we wait for the response. */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); + if (!wait_for_completion_timeout(&xfer->done, timeout)) { + dev_err(dev, "mbox timed out in resp(caller: %pS)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; + } } + + if (!ret && xfer->hdr.status) + ret = scmi_to_linux_errno(xfer->hdr.status); + /* * NOTE: we might prefer not to need the mailbox ticker to manage the * transfer queueing since the protocol layer queues things by itself. From patchwork Fri Feb 23 16:23:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 129447 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp791061lja; Fri, 23 Feb 2018 08:26:20 -0800 (PST) X-Google-Smtp-Source: AH8x22783Q/LhBFZ3n0V4w1P6ewJo6nZ2ympRRqmv3OuDXBs7dag+Yp8pXXMSJQTr3yw5v8X36Hr X-Received: by 10.99.166.10 with SMTP id t10mr1873066pge.198.1519403179893; Fri, 23 Feb 2018 08:26:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519403179; cv=none; d=google.com; s=arc-20160816; b=IgOPr8kZjJHIOcuhiltClObHxspKlgxCIHLHfXbCdQ7+sApqzBGXy56yb0bZHIGX06 UFJgP5GVKzph62HXCOrUztmSBGRGIoURfV810aVDN69LgNpx/VyPw40EI3OuucINzs+Q iQdRoxRJ2FSIKpvElNkoAXKA0FRyaGKiMHci2/ETIj5OPDG7U7phLhqcfmRdI6QgO+L7 FtHdECNzWGaw7u6RRNvSSb37L6gaVZQq+1ZzOYcByQW/s1NSJpYuCx3HZJ5OK60L/IE/ fa2pDuwry5agDvgyCAf0OIs2g1HVXVwKbkIUQeavq99YEzmlpAw4oYhD6NlQY/sWqO5D W0eA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=ZhBe09h/6asjYp5imNYh+hB7zrgpDB+J82tOGJrTZA4=; b=ss085xdG0az7XvIwxel4J8d+WEyjJmEsYhmOf5qOfP1DLP6gCCdAtclYqiMRZYmaMU 0SfhHH7tjaQh6xbaq/pKcCFMZ0qf1gyssifguxktJHiuEUVWy4Ex6RltyswJo4DBflbq CCU2Z9xZvoKG3KhyiKc1/av4O5mUHegHx0uEczdrrbI2b0GAg07XKBEsmIdX0jAKrROJ aUQbexgj9mpIy8H9d1AQqSamRlFJXuORhQDFqO8Brwu+fnSoon3KKzHRq1eDpJEBNMUp iLKVV/f7CUyJekZOfZgNzE8rxH2Wc/PDZM6c/VkTEaZBvZWGFYPNlBt/n6jyJbQjBhX7 RUeQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r22si1710580pgn.104.2018.02.23.08.26.19; Fri, 23 Feb 2018 08:26:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751580AbeBWQ0S (ORCPT + 6 others); Fri, 23 Feb 2018 11:26:18 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57356 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751970AbeBWQYa (ORCPT ); Fri, 23 Feb 2018 11:24:30 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A839516A0; Fri, 23 Feb 2018 08:24:30 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 52E043F25C; Fri, 23 Feb 2018 08:24:29 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Alexey Klimov , Arnd Bergmann , Greg Kroah-Hartman Subject: [PATCH v6 14/20] firmware: arm_scmi: add per-protocol channels support using idr objects Date: Fri, 23 Feb 2018 16:23:44 +0000 Message-Id: <1519403030-21189-15-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> References: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In order to maintain the channel information per protocol, we need some sort of list or hashtable to hold all this information. IDR provides sparse array mapping of small integer ID numbers onto arbitrary pointers. In this case the arbitrary pointers can be pointers to the channel information. This patch adds support for per-protocol channels using those idr objects. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index a9e3f4c46b78..527157f55e27 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -115,6 +115,7 @@ struct scmi_chan_info { struct mbox_chan *chan; void __iomem *payload; struct device *dev; + struct scmi_handle *handle; }; /** @@ -126,7 +127,7 @@ struct scmi_chan_info { * @version: SCMI revision information containing protocol version, * implementation version and (sub-)vendor identification. * @minfo: Message info - * @tx_cinfo: Reference to SCMI channel information + * @tx_idr: IDR object to map protocol id to channel info pointer * @protocols_imp: list of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol * @node: list head @@ -138,7 +139,7 @@ struct scmi_info { struct scmi_revision_info version; struct scmi_handle handle; struct scmi_xfers_info minfo; - struct scmi_chan_info *tx_cinfo; + struct idr tx_idr; u8 *protocols_imp; struct list_head node; int users; @@ -229,7 +230,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) struct scmi_xfer *xfer; struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); struct device *dev = cinfo->dev; - struct scmi_info *info = dev_get_drvdata(dev); + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); struct scmi_xfers_info *minfo = &info->minfo; struct scmi_shared_mem __iomem *mem = cinfo->payload; @@ -401,7 +402,11 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) int timeout; struct scmi_info *info = handle_to_scmi_info(handle); struct device *dev = info->dev; - struct scmi_chan_info *cinfo = info->tx_cinfo; + struct scmi_chan_info *cinfo; + + cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id); + if (unlikely(!cinfo)) + return -EINVAL; ret = mbox_send_message(cinfo->chan, xfer); if (ret < 0) { @@ -668,13 +673,18 @@ static int scmi_mailbox_check(struct device_node *np) return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); } -static int scmi_mbox_free_channel(struct scmi_chan_info *cinfo) +static int scmi_mbox_free_channel(int id, void *p, void *data) { + struct scmi_chan_info *cinfo = p; + struct idr *idr = data; + if (!IS_ERR_OR_NULL(cinfo->chan)) { mbox_free_channel(cinfo->chan); cinfo->chan = NULL; } + idr_remove(idr, id); + return 0; } @@ -682,6 +692,7 @@ static int scmi_remove(struct platform_device *pdev) { int ret = 0; struct scmi_info *info = platform_get_drvdata(pdev); + struct idr *idr = &info->tx_idr; mutex_lock(&scmi_list_mutex); if (info->users) @@ -690,28 +701,34 @@ static int scmi_remove(struct platform_device *pdev) list_del(&info->node); mutex_unlock(&scmi_list_mutex); - if (!ret) + if (!ret) { /* Safe to free channels since no more users */ - return scmi_mbox_free_channel(info->tx_cinfo); + ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + idr_destroy(&info->tx_idr); + } return ret; } -static inline int scmi_mbox_chan_setup(struct scmi_info *info) +static inline int +scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id) { int ret; struct resource res; resource_size_t size; - struct device *dev = info->dev; struct device_node *shmem, *np = dev->of_node; struct scmi_chan_info *cinfo; struct mbox_client *cl; + if (scmi_mailbox_check(np)) { + cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE); + goto idr_alloc; + } + cinfo = devm_kzalloc(info->dev, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) return -ENOMEM; - info->tx_cinfo = cinfo; cinfo->dev = dev; cl = &cinfo->cl; @@ -745,6 +762,14 @@ static inline int scmi_mbox_chan_setup(struct scmi_info *info) return ret; } +idr_alloc: + ret = idr_alloc(&info->tx_idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); + if (ret != prot_id) { + dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret); + return ret; + } + + cinfo->handle = &info->handle; return 0; } @@ -761,6 +786,11 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, return; } + if (scmi_mbox_chan_setup(info, &sdev->dev, prot_id)) { + dev_err(&sdev->dev, "failed to setup transport\n"); + scmi_device_destroy(sdev); + } + /* setup handle now as the transport is ready */ scmi_set_handle(sdev); } @@ -795,19 +825,19 @@ static int scmi_probe(struct platform_device *pdev) return ret; platform_set_drvdata(pdev, info); + idr_init(&info->tx_idr); handle = &info->handle; handle->dev = info->dev; handle->version = &info->version; - ret = scmi_mbox_chan_setup(info); + ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE); if (ret) return ret; ret = scmi_base_protocol_init(handle); if (ret) { dev_err(dev, "unable to communicate with SCMI(%d)\n", ret); - scmi_mbox_free_channel(info->tx_cinfo); return ret; } From patchwork Fri Feb 23 16:23:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sudeep Holla X-Patchwork-Id: 129445 Delivered-To: patch@linaro.org Received: by 10.46.66.2 with SMTP id p2csp790437lja; Fri, 23 Feb 2018 08:25:39 -0800 (PST) X-Google-Smtp-Source: AH8x227+FSC3mWmWYyeKsdlswSlcVpoj+B3bvr/yjSwonZBBjGmX5/prTYLk+LWnY1oGwTjfb+3z X-Received: by 10.101.64.10 with SMTP id f10mr1809118pgp.171.1519403138882; Fri, 23 Feb 2018 08:25:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519403138; cv=none; d=google.com; s=arc-20160816; b=gvUpRnXVrZ8DxcLKzg8pHFzztnmYIf+2IkLNOgF6RkjzeTrG73LnSWMGur+ODinRoC HD93aT3bnCTEqgfmHDEj1ycxiAqCMRrnNMM37PThtyQQyiGveszM3iuwvxAXIBTmG+zh vTgVl++awjAMYRN9nb2NyzunOKM+i7h7Ka05snNH6FwgD6gwktECuH4qjPU2ep4CkMF0 6yJ2r8dhE7MtzdFB6/Tx9SViPWN3pv92pjv5W3Ng0U59a4npcK15Js8492zgq7K81bzZ G3onYP4FdyGgtmmMw6nCq75nT7Y3w1BPjpX1s+G37WsWOkiMPh150kpOa9Scm3XLBELM 0Lbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=55ZsGVSgvqEQn89iJIPYS0RKw0AUU+a3R/HP9rn4xRM=; b=qVTKWUxrF3zN/EQ5kGy9efQNKoROZmws9x9e9yXvRP8YJ4kWdVjT6IeSkf1DV746s/ Fvj5KvuHk8IWt8c5s2b3ACLn5o6S88QcAunXKIyW4JTk3oCQmyTaz9v7z06Sa88T/2rw xSfTsHjFWq6zKCkkroaVZWIVVa298OSu/ZdJ7Ae3MUacv+GmHw8IuviA5H5dwP78R4BB lzQwevO7GwpE/IwLEIefkBA+ogouIydDU+C8SNBvyKtjonHRhZlo/NV7UU/iVxa3JhUT +vP3cCy9kTZ0VQJUb2uaAGWsX+WKCGk/ZyJxxN1YPXcezGHobFZZztm7StHbC5lwaqso UeDA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 186si2019649pfe.411.2018.02.23.08.25.38; Fri, 23 Feb 2018 08:25:38 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751920AbeBWQZh (ORCPT + 6 others); Fri, 23 Feb 2018 11:25:37 -0500 Received: from foss.arm.com ([217.140.101.70]:57406 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751468AbeBWQYi (ORCPT ); Fri, 23 Feb 2018 11:24:38 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D7F251713; Fri, 23 Feb 2018 08:24:37 -0800 (PST) Received: from e107155-lin.cambridge.arm.com (unknown [10.1.210.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 5EFCC3F25C; Fri, 23 Feb 2018 08:24:36 -0800 (PST) From: Sudeep Holla To: ALKML , LKML , DTML Cc: Sudeep Holla , Alexey Klimov , Arnd Bergmann , Greg Kroah-Hartman , linux-hwmon@vger.kernel.org Subject: [PATCH v6 18/20] hwmon: add support for sensors exported via ARM SCMI Date: Fri, 23 Feb 2018 16:23:48 +0000 Message-Id: <1519403030-21189-19-git-send-email-sudeep.holla@arm.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> References: <1519403030-21189-1-git-send-email-sudeep.holla@arm.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Create a driver to add support for SoC sensors exported by the System Control Processor (SCP) via the System Control and Management Interface (SCMI). The supported sensor types is one of voltage, temperature, current, and power. The sensor labels and values provided by the SCP are exported via the hwmon sysfs interface. Cc: linux-hwmon@vger.kernel.org Acked-by: Guenter Roeck Signed-off-by: Sudeep Holla --- drivers/hwmon/Kconfig | 12 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/scmi-hwmon.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/hwmon/scmi-hwmon.c -- 2.7.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ef23553ff5cb..033e57366d56 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -317,6 +317,18 @@ config SENSORS_APPLESMC Say Y here if you have an applicable laptop and want to experience the awesome power of applesmc. +config SENSORS_ARM_SCMI + tristate "ARM SCMI Sensors" + depends on ARM_SCMI_PROTOCOL + depends on THERMAL || !THERMAL_OF + help + This driver provides support for temperature, voltage, current + and power sensors available on SCMI based platforms. The actual + number and type of sensors exported depend on the platform. + + This driver can also be built as a module. If so, the module + will be called scmi-hwmon. + config SENSORS_ARM_SCPI tristate "ARM SCPI Sensors" depends on ARM_SCPI_PROTOCOL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index f814b4ace138..e7d52a36e6c4 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o +obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c new file mode 100644 index 000000000000..7a0ab768d4b5 --- /dev/null +++ b/drivers/hwmon/scmi-hwmon.c @@ -0,0 +1,233 @@ +/* + * System Control and Management Interface(SCMI) based hwmon sensor driver + * + * Copyright (C) 2017 ARM Ltd. + * Sudeep Holla + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +struct scmi_sensors { + const struct scmi_handle *handle; + const struct scmi_sensor_info **info[hwmon_max]; +}; + +static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + int ret; + u64 value; + const struct scmi_sensor_info *sensor; + struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); + const struct scmi_handle *h = scmi_sensors->handle; + + sensor = *(scmi_sensors->info[type] + channel); + ret = h->sensor_ops->reading_get(h, sensor->id, false, &value); + if (!ret) + *val = value; + + return ret; +} + +static int +scmi_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + const struct scmi_sensor_info *sensor; + struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); + + sensor = *(scmi_sensors->info[type] + channel); + *str = sensor->name; + + return 0; +} + +static umode_t +scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct scmi_sensor_info *sensor; + const struct scmi_sensors *scmi_sensors = drvdata; + + sensor = *(scmi_sensors->info[type] + channel); + if (sensor && sensor->name) + return S_IRUGO; + + return 0; +} + +static const struct hwmon_ops scmi_hwmon_ops = { + .is_visible = scmi_hwmon_is_visible, + .read = scmi_hwmon_read, + .read_string = scmi_hwmon_read_string, +}; + +static struct hwmon_chip_info scmi_chip_info = { + .ops = &scmi_hwmon_ops, + .info = NULL, +}; + +static int scmi_hwmon_add_chan_info(struct hwmon_channel_info *scmi_hwmon_chan, + struct device *dev, int num, + enum hwmon_sensor_types type, u32 config) +{ + int i; + u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); + + if (!cfg) + return -ENOMEM; + + scmi_hwmon_chan->type = type; + scmi_hwmon_chan->config = cfg; + for (i = 0; i < num; i++, cfg++) + *cfg = config; + + return 0; +} + +static enum hwmon_sensor_types scmi_types[] = { + [TEMPERATURE_C] = hwmon_temp, + [VOLTAGE] = hwmon_in, + [CURRENT] = hwmon_curr, + [POWER] = hwmon_power, + [ENERGY] = hwmon_energy, +}; + +static u32 hwmon_attributes[] = { + [hwmon_chip] = HWMON_C_REGISTER_TZ, + [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL, + [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, + [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, + [hwmon_power] = HWMON_P_INPUT | HWMON_P_LABEL, + [hwmon_energy] = HWMON_E_INPUT | HWMON_E_LABEL, +}; + +static int scmi_hwmon_probe(struct scmi_device *sdev) +{ + int i, idx; + u16 nr_sensors; + enum hwmon_sensor_types type; + struct scmi_sensors *scmi_sensors; + const struct scmi_sensor_info *sensor; + int nr_count[hwmon_max] = {0}, nr_types = 0; + const struct hwmon_chip_info *chip_info; + struct device *hwdev, *dev = &sdev->dev; + struct hwmon_channel_info *scmi_hwmon_chan; + const struct hwmon_channel_info **ptr_scmi_ci; + const struct scmi_handle *handle = sdev->handle; + + if (!handle || !handle->sensor_ops) + return -ENODEV; + + nr_sensors = handle->sensor_ops->count_get(handle); + if (!nr_sensors) + return -EIO; + + scmi_sensors = devm_kzalloc(dev, sizeof(*scmi_sensors), GFP_KERNEL); + if (!scmi_sensors) + return -ENOMEM; + + scmi_sensors->handle = handle; + + for (i = 0; i < nr_sensors; i++) { + sensor = handle->sensor_ops->info_get(handle, i); + if (!sensor) + return PTR_ERR(sensor); + + switch (sensor->type) { + case TEMPERATURE_C: + case VOLTAGE: + case CURRENT: + case POWER: + case ENERGY: + type = scmi_types[sensor->type]; + if (!nr_count[type]) + nr_types++; + nr_count[type]++; + break; + } + } + + if (nr_count[hwmon_temp]) + nr_count[hwmon_chip]++, nr_types++; + + scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), + GFP_KERNEL); + if (!scmi_hwmon_chan) + return -ENOMEM; + + ptr_scmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*ptr_scmi_ci), + GFP_KERNEL); + if (!ptr_scmi_ci) + return -ENOMEM; + + scmi_chip_info.info = ptr_scmi_ci; + chip_info = &scmi_chip_info; + + for (type = 0; type < hwmon_max && nr_count[type]; type++) { + scmi_hwmon_add_chan_info(scmi_hwmon_chan, dev, nr_count[type], + type, hwmon_attributes[type]); + *ptr_scmi_ci++ = scmi_hwmon_chan++; + + scmi_sensors->info[type] = + devm_kcalloc(dev, nr_count[type], + sizeof(*scmi_sensors->info), GFP_KERNEL); + if (!scmi_sensors->info[type]) + return -ENOMEM; + } + + for (i = nr_sensors - 1; i >= 0 ; i--) { + sensor = handle->sensor_ops->info_get(handle, i); + if (!sensor) + continue; + + switch (sensor->type) { + case TEMPERATURE_C: + case VOLTAGE: + case CURRENT: + case POWER: + case ENERGY: + type = scmi_types[sensor->type]; + idx = --nr_count[type]; + *(scmi_sensors->info[type] + idx) = sensor; + break; + } + } + + hwdev = devm_hwmon_device_register_with_info(dev, "scmi_sensors", + scmi_sensors, chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwdev); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_SENSOR }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_hwmon_drv = { + .name = "scmi-hwmon", + .probe = scmi_hwmon_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_hwmon_drv); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("ARM SCMI HWMON interface driver"); +MODULE_LICENSE("GPL v2");