From patchwork Thu Feb 11 12:34:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 381234 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F311C433E6 for ; Thu, 11 Feb 2021 12:38:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D2C1264E79 for ; Thu, 11 Feb 2021 12:38:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231519AbhBKMha (ORCPT ); Thu, 11 Feb 2021 07:37:30 -0500 Received: from mail-lj1-f172.google.com ([209.85.208.172]:44681 "EHLO mail-lj1-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230029AbhBKMfL (ORCPT ); Thu, 11 Feb 2021 07:35:11 -0500 Received: by mail-lj1-f172.google.com with SMTP id x1so501465ljj.11; Thu, 11 Feb 2021 04:34:53 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=5v/cjtTmJg2RpKpRvNRPqO2XLjvgCacL1WtUm8zOfnA=; b=UszOAmYKZ5M+wc0ZH88yls+5ED/Lb7ECyP5yCpbtfzXq7hdNAC3VN7KEehd1Q5dBla Dp16yxUQ2TK63mrO0imH9kZpxfp95l/C5CmzY+3eIMQIzBlNs4su7uKrRYLcgjfU3kW3 tt1q/ZyhP1Y0mk73qSIWNIxkEtXl7jUpvEg6fshxOhZkhQI5iHCZ5KOCrQu2eSqtzW+4 +LOaAetLhMJyrGxOb9CWCtHYzX0pLKv6JkQ60ysSmTWIODUNYD24nv3mKyTN72gLOUJs Xlr9xqctpacDoBoSWerB5qvU4ixGJCSFr5Sg4/d2+po96crFLGToPMOF4KX/ixnSYcm5 p7GQ== X-Gm-Message-State: AOAM533zz2IVn5Mm+Pt6N/IdB/W+M0bCnj5lfLlDlVTzsXUrclpH9Fs4 I3powc/qQ7CODTwyaeEfiko= X-Google-Smtp-Source: ABdhPJxK/dYwsv+pjD2kxn36Gy9gjk0wC4yYlHAcf8kh0rRFFMI5TwptCAlairhIMcHQR8XshVvNaQ== X-Received: by 2002:a2e:2c0d:: with SMTP id s13mr89345ljs.298.1613046868233; Thu, 11 Feb 2021 04:34:28 -0800 (PST) Received: from localhost.localdomain (62-78-225-252.bb.dnainternet.fi. [62.78.225.252]) by smtp.gmail.com with ESMTPSA id j137sm636583lfj.55.2021.02.11.04.34.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 04:34:27 -0800 (PST) Date: Thu, 11 Feb 2021 14:34:17 +0200 From: Matti Vaittinen To: mazziesaccount@gmail.com, matti.vaittinen@fi.rohmeurope.com Cc: Liam Girdwood , Mark Brown , Rob Herring , Matti Vaittinen , Andy Gross , Bjorn Andersson , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-power@fi.rohmeurope.com, linux-arm-msm@vger.kernel.org, linux-renesas-soc@vger.kernel.org Subject: [RFC PATCH 1/7] dt_bindings: Add protection limit properties Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Support specifying protection/error/warning limits for regulator over current, over temperature and over/under voltage. Most of the PMICs support only "protection" feature but few setups do also support error/warning level indications. On many ICs most of the protection limits can't actually be set. But for example the ampere limit for over-current protection on ROHM BD9576 can be configured - or feature can be completely disabled. Provide limit setting for all protections/errors for the sake of the completeness and do that using own properties for all so that not all users would need to set all levels when only one or few are supported. Signed-off-by: Matti Vaittinen --- .../bindings/regulator/regulator.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index 6d0bc9cd4040..47fff75f0554 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -117,6 +117,88 @@ properties: description: Enable over current protection. type: boolean + regulator-over-current-protection-microamp: + description: Set over current protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. + + regulator-over-current-error-microamp: + description: Set over current error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested. + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. + + regulator-over-current-warn-microamp: + description: Set over current warning limit. This is a limit where hardware + is assumed still to be functional but approaching limit where it gets + damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. + + regulator-over-voltage-protection-microvolt: + description: Set over voltage protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. Limit is given as microvolt offset from + voltage set to regulator. + + regulator-over-voltage-error-microvolt: + description: Set over voltage error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. Limit + is given as microvolt offset from voltage set to regulator. + + regulator-over-voltage-warn-microvolt: + description: Set over voltage warning limit. This is a limit where hardware + is assumed still to be functional but approaching limit where it gets + damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. Limit is given as microvolt + offset from voltage set to regulator. + + regulator-under-voltage-protection-microvolt: + description: Set over under voltage protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. Limit is given as microvolt offset from + voltage set to regulator. + + regulator-under-voltage-error-microvolt: + description: Set under voltage error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. Limit + is given as microvolt offset from voltage set to regulator. + + regulator-under-voltage-warn-microvolt: + description: Set over under voltage warning limit. This is a limit where + hardware is assumed still to be functional but approaching limit where + it gets damaged. Recovery actions should be initiated. Zero can be passed + to disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. Limit is given as microvolt + offset from voltage set to regulator. + + regulator-over-temperature-protection-kelvin: + description: Set over temperature protection limit. This is a limit where + hardware performs emergency shutdown. Zero can be passed to disable + protection and value '1' indicates that protection should be enabled but + limit setting can be omitted. + + regulator-over-temperature-error-kelvin: + description: Set over temperature error limit. This is a limit where part of + the hardware propably is malfunctional and damage prevention is requested + Zero can be passed to disable error detection and value '1' indicates + that detection should be enabled but limit setting can be omitted. + + regulator-over-temperature-warn-kelvin: + description: Set over temperature warning limit. This is a limit where + hardware is assumed still to be functional but approaching limit where it + gets damaged. Recovery actions should be initiated. Zero can be passed to + disable detection and value '1' indicates that detection should + be enabled but limit setting can be omitted. + regulator-active-discharge: description: | tristate, enable/disable active discharge of regulators. The values are: From patchwork Thu Feb 11 12:35:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 381233 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 34B4BC433E6 for ; Thu, 11 Feb 2021 12:38:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 02A3864DD8 for ; Thu, 11 Feb 2021 12:38:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230221AbhBKMi0 (ORCPT ); Thu, 11 Feb 2021 07:38:26 -0500 Received: from mail-lf1-f43.google.com ([209.85.167.43]:34189 "EHLO mail-lf1-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230381AbhBKMfy (ORCPT ); Thu, 11 Feb 2021 07:35:54 -0500 Received: by mail-lf1-f43.google.com with SMTP id h26so7873123lfm.1; Thu, 11 Feb 2021 04:35:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=60oa+ZnuxS7FMsT+TgYgwtdTMpKdHL7fHJyqcV2Jlvw=; b=m7kiCtac6fEEcWp3N5RNXDcQXrvge+pSKL+LMOFGCX+/xbaU6s2PBCXlcNewJhTis5 Mbz952sob8VWQ7eEllyOP4y2DvuDIQF2tweH+PDlSxvdC9K/iLPU2kjsQki7e+2PkA27 IOJZxyXYAn+QK8UhM/Lh+gue7hk0CsFPNYEi5JNE6Kn6SJmJ+jMW7th96B4Fxn6lTyr3 QjdmyNSS8ngfoHVMBChkSENWnkU625LWgSHnQHTECox34DhJWDsUpEvGVdsUpu0bbr7t D4tiVYnxXDc5W9cPeLTgKWFTRtmz6x73FzsGrkct0AovM+55fSB444IWE/An0v2xJqYX gNxA== X-Gm-Message-State: AOAM532Wn0LDYLVkn5VLc8UNd0eZhI+8Zmj3IWrJs7MmwOG//NDCUyCs 6O5IJ4TFZajgtMaBhIdeVIg= X-Google-Smtp-Source: ABdhPJxTEslsZHSckTPWGdK1A808VNoaPP/FhTfLvv26pXwgHDCDv+0x6cUKJttCR7oFy7sruhpV/A== X-Received: by 2002:a05:6512:3743:: with SMTP id a3mr4277514lfs.8.1613046906971; Thu, 11 Feb 2021 04:35:06 -0800 (PST) Received: from localhost.localdomain (62-78-225-252.bb.dnainternet.fi. [62.78.225.252]) by smtp.gmail.com with ESMTPSA id b7sm892795ljk.52.2021.02.11.04.35.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 04:35:06 -0800 (PST) Date: Thu, 11 Feb 2021 14:35:00 +0200 From: Matti Vaittinen To: mazziesaccount@gmail.com, matti.vaittinen@fi.rohmeurope.com Cc: Liam Girdwood , Mark Brown , Rob Herring , Matti Vaittinen , Andy Gross , Bjorn Andersson , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-power@fi.rohmeurope.com, linux-arm-msm@vger.kernel.org, linux-renesas-soc@vger.kernel.org Subject: [RFC PATCH 3/7] regulator: IRQ based event/error notification helpers Message-ID: <3daf0531910c25d8b0da3964778ae2a6c9049d43.1613042245.git.matti.vaittinen@fi.rohmeurope.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Provide helper function for IC's implementing regulator notifications when an IRQ fires. The helper also works for IRQs which can not be acked. Helper can be set to disable the IRQ at handler and then re-enabling it on delayed work later. The helper also adds regulator_get_error_flags() errors in cache for the duration of IRQ disabling. Signed-off-by: Matti Vaittinen --- This patch has gone through only a very limited amount of testing. All reviews / suggestions / testing is highly appreciated. drivers/regulator/Makefile | 2 +- drivers/regulator/core.c | 24 +- drivers/regulator/irq_helpers.c | 396 +++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 129 ++++++++++ 4 files changed, 547 insertions(+), 4 deletions(-) create mode 100644 drivers/regulator/irq_helpers.c diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 44d2f8bf4b74..e25f1c2d6c9b 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -4,7 +4,7 @@ # -obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8f35a3dd4c30..9f06b33ff1e2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4366,20 +4366,37 @@ unsigned int regulator_get_mode(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_get_mode); +static int rdev_get_cached_err_flags(struct regulator_dev *rdev) +{ + int ret = 0; + + if (rdev->use_cached_err) { + spin_lock(&rdev->err_lock); + ret = rdev->cached_err; + spin_unlock(&rdev->err_lock); + } + return ret; +} + static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) { - int ret; + int ret, tmpret; regulator_lock(rdev); + ret = rdev_get_cached_err_flags(rdev); + /* sanity check */ - if (!rdev->desc->ops->get_error_flags) { + if (rdev->desc->ops->get_error_flags) { + tmpret = rdev->desc->ops->get_error_flags(rdev, flags); + if (tmpret > 0) + ret |= tmpret; + } else if (!rdev->use_cached_err) { ret = -EINVAL; goto out; } - ret = rdev->desc->ops->get_error_flags(rdev, flags); out: regulator_unlock(rdev); return ret; @@ -5214,6 +5231,7 @@ regulator_register(const struct regulator_desc *regulator_desc, goto rinse; } device_initialize(&rdev->dev); + spin_lock_init(&rdev->err_lock); /* * Duplicate the config so the driver could override it after diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c new file mode 100644 index 000000000000..57121554de8e --- /dev/null +++ b/drivers/regulator/irq_helpers.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 ROHM Semiconductors + * regulator IRQ based event notification helpers + * + * Logic has been partially adapted from qcom-labibb driver. + * + * Author: Matti Vaittinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct regulator_irq { + struct regulator_irq_data rdata; + struct regulator_irq_desc desc; + int irq; + int retry_cnt; + struct delayed_work isr_work; +}; + +/* + * Should only be called from threaded handler to prevent potential deadlock + */ +static void rdev_flag_err(struct regulator_dev *rdev, int err) +{ + spin_lock(&rdev->err_lock); + rdev->cached_err |= err; + spin_unlock(&rdev->err_lock); +} + +static void rdev_clear_err(struct regulator_dev *rdev, int err) +{ + spin_lock(&rdev->err_lock); + rdev->cached_err &= ~err; + spin_unlock(&rdev->err_lock); +} + +static void regulator_notifier_isr_work(struct work_struct *work) +{ + struct regulator_irq *h; + struct regulator_irq_desc *d; + struct regulator_irq_data *rid; + int ret = 0; + int tmo, i; + int num_rdevs; + + h = container_of(work, struct regulator_irq, + isr_work.work); + + + d = &h->desc; + rid = &h->rdata; + num_rdevs = rid->num_states; + +reread: + if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) { + if (d->die) + ret = d->die(rid); + else + BUG(); + + /* + * If the 'last resort' IC recovery failed we will have + * nothing else left to do... + */ + BUG_ON(ret); + + /* + * If h->die() was implemented we assume recovery has been + * attempted (probably regulator was shut down) + * and we just enable IRQ and bail-out. + */ + goto enable_out; + } + if (d->renable) { + ret = d->renable(rid); + + if (ret == REGULATOR_FAILED_RETRY) { + h->retry_cnt++; + if (!d->reread_ms) + goto reread; + /* + * driver indicated problem is still on - let's not enable IRQ + * but just wait a little more + */ + tmo = d->reread_ms; + goto reschedule; + } + + if (ret) { + /* + * IC status reading succeeded. update error info + * just in case the renable changed it. + */ + for (i = 0; i < num_rdevs; i++) { + struct regulator_err_state *stat; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + rdev = stat->rdev; + rdev_clear_err(rdev, (~stat->errors) & + stat->possible_errs); + } + h->retry_cnt++; + /* + * The IC indicated problem is still ON - no point in + * re-enabling the IRQ. Retry later. + */ + tmo = d->irq_off_ms; + goto reschedule; + } + } + + /* + * Either IC reported problem cleared or no status checker was provided. + * If problems are gone - good. If not - then the IRQ will fire again + * and we'll have new nice loop. In any case we should clear error flags + * here and re-enable IRQs. + */ + for (i = 0; i < num_rdevs; i++) { + struct regulator_err_state *stat; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + rdev = stat->rdev; + rdev_clear_err(rdev, stat->possible_errs); + } + + /* + * Things have been seemingly successful => zero retry-counter. + */ + h->retry_cnt = 0; + +enable_out: + enable_irq(h->irq); + + return; + +reschedule: + if (!d->high_prio) + mod_delayed_work(system_wq, &h->isr_work, + msecs_to_jiffies(tmo)); + else + mod_delayed_work(system_highpri_wq, &h->isr_work, + msecs_to_jiffies(tmo)); +} + +static irqreturn_t regulator_notifier_isr(int irq, void *data) +{ + struct regulator_irq *h = data; + struct regulator_irq_desc *d; + struct regulator_irq_data *rid; + unsigned long rdev_map = 0; + int num_rdevs; + int ret, i, j; + + d = &h->desc; + rid = &h->rdata; + num_rdevs = rid->num_states; + + if (d->fatal_cnt) + h->retry_cnt++; + + /* + * we spare few cycles by not clearing statuses prior this call. + * The IC driver must initialize the status buffers for rdevs + * which it indicates having active events via rdev_map. + * + * Maybe we should just to be on a safer side(?) + */ + if (d->map_event) + ret = d->map_event(irq, rid, &rdev_map); + + /* + * If status reading fails (which is unlikely) we don't ack/disable + * IRQ but just increase fail count and retry when IRQ fires again. + * If retry_count exceeds given safety limit we call IC specific die + * handler which can try disabling regulator(s). + * + * If no die handler is given we will just bug() as a last resort. + * + * We could try disabling all associated rdevs - but we might shoot + * ourself in the head and leave problematic regulator enabled. So + * if IC has no die-handler populated we just assume the regulator + * can't be disabled. + */ + if (unlikely(ret == REGULATOR_FAILED_RETRY)) + goto fail_out; + + h->retry_cnt = 0; + /* + * Let's not disable IRQ if there was no status bits for us. We'd + * better leave spurious IRQ handling to genirq + */ + if (ret || !rdev_map) + return IRQ_NONE; + + /* + * Some events are bogus if regulator is disabled. Skip such events + * if all relevant regulators are disabled + */ + if (d->skip_off) { + int skip = 1; + + for_each_set_bit(i, &rdev_map, num_rdevs) { + struct regulator_dev *rdev; + const struct regulator_ops *ops; + + rdev = rid->states[i].rdev; + ops = rdev->desc->ops; + + /* + * If any of the flagged regulators is enabled we do + * handle this + */ + if (ops->is_enabled(rdev)) { + skip = 0; + break; + } + } + if (skip) + return IRQ_NONE; + } + + /* Disable IRQ if HW keeps line asserted */ + if (d->irq_off_ms) + disable_irq_nosync(irq); + + /* + * IRQ seems to be for us. Let's fire correct notifiers / store error + * flags + */ + for_each_set_bit(i, &rdev_map, num_rdevs) { + struct regulator_err_state *stat; + int len; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + len = sizeof(stat->notifs); + + rdev = stat->rdev; + for_each_set_bit(j, &stat->notifs, 8 * len) + regulator_notifier_call_chain(rdev, 1 << (j - 1), NULL); + + rdev_flag_err(rdev, stat->errors); + } + + if (d->irq_off_ms) { + if (!d->high_prio) + schedule_delayed_work(&h->isr_work, + msecs_to_jiffies(d->irq_off_ms)); + else + mod_delayed_work(system_highpri_wq, + &h->isr_work, + msecs_to_jiffies(d->irq_off_ms)); + } + + return IRQ_HANDLED; + +fail_out: + if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) { + if (d->die) + ret = d->die(rid); + + /* + * If die() failed or was not implemented just BUG() as last + * attemt to save HW. + */ + BUG_ON(ret); + } + return IRQ_NONE; +} + +static void dev_delayed_work_drop(struct device *dev, void *res) +{ + cancel_delayed_work_sync(*(struct delayed_work **)res); +} + +int dev_delayed_work_autocancel(struct device *dev, struct delayed_work *w, + void (*worker)(struct work_struct *work)) +{ + struct delayed_work **ptr; + + ptr = devres_alloc(dev_delayed_work_drop, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + INIT_DELAYED_WORK(w, worker); + *ptr = w; + devres_add(dev, ptr); + + return 0; +} + +static int init_rdev_state(struct device *dev, struct regulator_irq *h, + struct regulator_dev **rdev, int common_err, + int *rdev_err, int rdev_amount) +{ + int i; + + h->rdata.states = devm_kzalloc(dev, sizeof(*h->rdata.states) * + rdev_amount, GFP_KERNEL); + if (!h->rdata.states) + return -ENOMEM; + + h->rdata.num_states = rdev_amount; + h->rdata.data = h->desc.data; + + for (i = 0; i < rdev_amount; i++) { + h->rdata.states[i].possible_errs = common_err; + if (rdev_err) + h->rdata.states[i].possible_errs |= *rdev_err++; + h->rdata.states[i].rdev = *rdev++; + } + + return 0; +} + +static void init_rdev_errors(struct regulator_irq *h) +{ + int i; + + for (i = 0; i < h->rdata.num_states; i++) { + if (h->rdata.states[i].possible_errs) + /* Can we trust writing this boolean is atomic? */ + h->rdata.states[i].rdev->use_cached_err = true; + } +} + +/** + * regulator_irq_helper - register IRQ based regulator event/error notifier + * + * @dev: device to which lifetime the helper's lifetime is + * bound. + * @d: IRQ helper descriptor. + * @irq: IRQ used to inform events/errors to be notified. + * @irq_flags: Extra IRQ flags to be OR's with the default IRQF_ONESHOT + * when requesting the (threaded) irq. + * @common_errs: Errors which can be flagged by this IRQ for all rdevs. + * When IRQ is re-enabled these errors will be cleared + * from all associated regulators + * @per_rdev_errs: Optional error flag array describing errors specific + * for only some of the regulators. These errors will be + * or'ed with common erros. If this is given the array + * should contain rdev_amount flags. Can be set to NULL + * if there is no regulator specific error flags for this + * IRQ. + * @rdev: Array of regulators associated with this IRQ. + * @rdev_amount: Amount of regulators associated wit this IRQ. + */ +int regulator_irq_helper(struct device *dev, const struct regulator_irq_desc *d, + int irq, int irq_flags, int common_errs, + int *per_rdev_errs, struct regulator_dev **rdev, + int rdev_amount) +{ + struct regulator_irq *h; + int ret; + + if (!rdev_amount || !d) + return -EINVAL; + + h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL); + if (!h) + return -ENOMEM; + + if (irq <= 0) { + dev_err(dev, "No IRQ\n"); + return -EINVAL; + } + + h->irq = irq; + h->desc = *d; + + ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs, + rdev_amount); + if (ret) + return ret; + + init_rdev_errors(h); + + if (h->desc.irq_off_ms) + dev_delayed_work_autocancel(dev, &h->isr_work, + regulator_notifier_isr_work); + + return devm_request_threaded_irq(dev, h->irq, NULL, + regulator_notifier_isr, IRQF_ONESHOT | + irq_flags, h->desc.name, h); +} +EXPORT_SYMBOL_GPL(regulator_irq_helper); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d7c77ee370f3..9a9bc0f5dcea 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -409,6 +409,128 @@ struct regulator_config { struct gpio_desc *ena_gpiod; }; +/** + * struct regulator_err_state - regulator error/notification status + * + * @rdev: Regulator which status the struct indicates. + * @notifs: Events which have occurred on regulator. + * @errors: Errors which are active on regulator. + * @possible_errs: Errors which can be signaled (by given IRQ). + */ +struct regulator_err_state { + struct regulator_dev *rdev; + unsigned long notifs; + unsigned long errors; + int possible_errs; +}; + +/** + * struct regulator_irq_data - regulator error/notification status date + * + * @states: Status structs for each of the associated regulators. + * @num_states: Amount of associated regulators. + * @data: Driver data pointer given at regulator_irq_desc. + * @opaque: Value storage for IC driver. Core does not update this. ICs + * may want to store status register value here at map_event and + * compare contents at renable to see if new problems have been + * added to status. If that is the case it may be desirable to + * return REGULATOR_ERROR_CLEARED and not REGULATOR_ERROR_ON to + * allow IRQ fire again and to generate notifications also for + * the new issues. + * + * This structure is passed to map_event and renable for reporting reulator + * status to core. + */ +struct regulator_irq_data { + struct regulator_err_state *states; + int num_states; + void *data; + long opaque; +}; + +/** + * struct regulator_irq_desc - notification sender for IRQ based events. + * + * @name: The visible name for the IRQ + * @fatal_cnt: If this IRQ is used to signal HW damaging condition it may be + * best to shut-down regulator(s) or reboot the SOC if error + * handling is repeteadly failing. If fatal_cnt is given the IRQ + * handling is aborted if it fails for fatal_cnt times and die() + * callback (if populated) or BUG() is called to try to prevent + * further damage. + * @reread_ms: The time which is waited before attempting to re-read status + * at the worker if IC reading fails. Immediate re-read is done + * if time is not specified. + * @irq_off_ms: The time which IRQ is kept disabled before re-evaluating the + * status for devices which keep IRQ disabled for duration of the + * error. If this is not given the IRQ is left enabled and renable + * is not called. + * @skip_off: If set to true the IRQ handler will attempt to check if any of + * the associated regulators are enabled prior to taking other + * actions. If no regulators are enabled and this is set to true + * a spurious IRQ is assumed and IRQ_NONE is returned. + * @high_prio: Boolean to indicate that high priority WQ should be used. + * @data: Driver private data pointer which will be passed as such to + * the renable, map_event and die callbacks in regulator_irq_data. + * @die: Protection callback. If IC status reading or recovery actions + * fail fatal_cnt times this callback or BUG() is called. This + * callback should implement final protection attempt like + * disabling the regulator. If protection succeeded this may + * return 0. If anything else is returned the core assumes final + * protection failed and calls BUG() as a last resort. + * @map_event: Driver callback to map IRQ status into regulator devices with + * events / errors. NOTE: callback MUST initialize both the + * errors and notifs for all rdevs which it signals having + * active events as core does not clean the map data. + * REGULATOR_FAILED_RETRY can be returned to indicate that the + * status reading from IC failed. If this is repeated for + * fatal_cnt times the core will call die() callback or BUG() + * as a last resort to protect the HW. + * @renable: Optional callback to check status (if HW supports that) before + * re-enabling IRQ. If implemented this should clear the error + * flags so that errors fetched by regulator_get_error_flags() + * are updated. If callback is not impelemted then errors are + * assumed to be cleared and IRQ is re-enabled. + * REGULATOR_FAILED_RETRY can be returned to + * indicate that the status reading from IC failed. If this is + * repeated for 'fatal_cnt' times the core will call die() + * callback or BUG() as a last resort to protect the HW. + * Returning zero indicates that the problem in HW has been solved + * and IRQ will be re-enabled. Returning REGULATOR_ERROR_ON + * indicates the error condition is still active and keeps IRQ + * disabled. Please note that returning REGULATOR_ERROR_ON does + * not retrigger evaluating what events are active or resending + * notifications. If this is needed you probably want to return + * zero and allow IRQ to retrigger causing events to be + * re-evaluated and re-sent. + * + * This structure is used for registering regulator IRQ notification helper. + */ +struct regulator_irq_desc { + const char *name; + int irq_flags; + int fatal_cnt; + int reread_ms; + int irq_off_ms; + bool skip_off; + bool high_prio; + void *data; + + int (*die)(struct regulator_irq_data *rid); + int (*map_event)(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask); + int (*renable)(struct regulator_irq_data *rid); +}; + +/* + * Return values for regulator IRQ helpers. + */ +enum { + REGULATOR_ERROR_CLEARED, + REGULATOR_FAILED_RETRY, + REGULATOR_ERROR_ON, +}; + /* * struct coupling_desc * @@ -473,6 +595,9 @@ struct regulator_dev { /* time when this regulator was disabled last time */ unsigned long last_off_jiffy; + int cached_err; + bool use_cached_err; + spinlock_t err_lock; }; struct regulator_dev * @@ -487,6 +612,10 @@ void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev); int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); +int regulator_irq_helper(struct device *dev, const struct regulator_irq_desc *d, + int irq, int irq_flags, int common_errs, + int *per_rdev_errs, struct regulator_dev **rdev, + int rdev_amount); void *rdev_get_drvdata(struct regulator_dev *rdev); struct device *rdev_get_dev(struct regulator_dev *rdev); From patchwork Thu Feb 11 12:35:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 381231 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1701C433E6 for ; Thu, 11 Feb 2021 12:41:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9838264DE7 for ; Thu, 11 Feb 2021 12:41:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230439AbhBKMky (ORCPT ); Thu, 11 Feb 2021 07:40:54 -0500 Received: from mail-lf1-f42.google.com ([209.85.167.42]:43524 "EHLO mail-lf1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229845AbhBKMge (ORCPT ); Thu, 11 Feb 2021 07:36:34 -0500 Received: by mail-lf1-f42.google.com with SMTP id d3so7811776lfg.10; Thu, 11 Feb 2021 04:36:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=NPjb16F/Enmos5BdXGztjXZs5CJCxN0wXp5AiXsE5FM=; b=LzCWrBu9qKDT9oP5u0Ie+I/kjjHSYbZy/kH69OcFuEasyWp6sqmGsZQLtOfYVZlfJZ Kxf9bLiFz+/+sqgP/069dEzl2cK0ncpyAj34dHNBUcHIEl0TAp0ZD/6EUdD6pAzDTAIz YNx1Kc5+DIjALiO3Ynj6kq18zEM0I7GiDXBeM/pVZSalD/x0+g7Ai7OIcoX44dSGQkkp iLZLVcIbdtuEDlVljRotceLUlemTagWcpDuaLvQxmJCy7zI19gGBmiOgcWYVIpPKDHNM nTrNiiUSjJXxevKrNs7RXw0M4L1pnYKyBIO4AbppSrdupAfspIGZM+r662m9EeolBWbG c+HA== X-Gm-Message-State: AOAM532dMZPQswrG9gQXCA67UmKFbuOlnXMpBRnQw1DVbV1hZzLLKWxG 7Aadl6NDRKl3NYcTJkAtolk= X-Google-Smtp-Source: ABdhPJxVGoucB8e6O/MTgeLno0yiF8jwESSuhPBRk1yyBvH/FQ2fgNm+QBMHaXjHOGowJ3UNODC7vA== X-Received: by 2002:ac2:5df1:: with SMTP id z17mr4107208lfq.124.1613046948259; Thu, 11 Feb 2021 04:35:48 -0800 (PST) Received: from localhost.localdomain (62-78-225-252.bb.dnainternet.fi. [62.78.225.252]) by smtp.gmail.com with ESMTPSA id n7sm631989lfu.123.2021.02.11.04.35.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 04:35:47 -0800 (PST) Date: Thu, 11 Feb 2021 14:35:41 +0200 From: Matti Vaittinen To: mazziesaccount@gmail.com, matti.vaittinen@fi.rohmeurope.com Cc: Liam Girdwood , Mark Brown , Rob Herring , Matti Vaittinen , Andy Gross , Bjorn Andersson , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-power@fi.rohmeurope.com, linux-arm-msm@vger.kernel.org, linux-renesas-soc@vger.kernel.org Subject: [RFC PATCH 5/7] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org BD9576MUF provides over-current protection and detection. Current is measured as voltage loss over external FET. Allow specifying FET's on resistance so current monitoring limits can be converted to voltages. Signed-off-by: Matti Vaittinen --- .../devicetree/bindings/regulator/rohm,bd9576-regulator.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml index b6515a0cee62..ad3f57e9cd9b 100644 --- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml @@ -27,6 +27,11 @@ patternProperties: Properties for single regulator. $ref: "regulator.yaml#" + properties: + rohm,ocw-fet-ron-milliohms: + description: External FET's ON-resistance. Required if VoutS1 OCP/OCW is + to be set. + required: - regulator-name From patchwork Thu Feb 11 12:36:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 381232 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7539CC433E9 for ; Thu, 11 Feb 2021 12:40:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3B64164E79 for ; Thu, 11 Feb 2021 12:40:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230285AbhBKMjv (ORCPT ); Thu, 11 Feb 2021 07:39:51 -0500 Received: from mail-lf1-f47.google.com ([209.85.167.47]:37550 "EHLO mail-lf1-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231610AbhBKMhT (ORCPT ); Thu, 11 Feb 2021 07:37:19 -0500 Received: by mail-lf1-f47.google.com with SMTP id w36so7860324lfu.4; Thu, 11 Feb 2021 04:37:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=BEYc1KpLEzvo5kSYZfGrwQM3KRwm1b2lfZYyXexWZu4=; b=VH4vA5eaDmGzUOYGHm3IOI/bJ70N4gSz0UgY50lfz8vQPzZDpYB2bWFKRSt9AWEVct 48618//wLka3kGjw94skvUURS0DjRaLJUKy5EtoM4z9zrmgoA5e7sMp6pTae9r5CNwq9 Tz1ZqCr0ZbFjPL7iR0vFtGwo6UpDfMXPlrINKV2g1BBYCx4OE+/Sthy4arnvuSAaOrOK NsI0iCB44dPvaAvt7iymI4/MN9v2tly+pBQtrb0KBqbtT8hfZ3veKqtxIIrCO+HuzUsJ bm+z3Wr+p4eIkecaftCiiGYQVHcz/Cx4qQQ9PP6XJcwpXGjFe3Ylsdobr/4c1zbm7r26 mwfA== X-Gm-Message-State: AOAM533ABYHxSFAXAadjoCyOdRUCVhFbeNXb4i3HIcamjBiXMWwZeFc/ QMRzZjks6yo4ZQosXae/bY0= X-Google-Smtp-Source: ABdhPJxdyVid28mVAXjh+nRn+59q3xrQHr7U1Cor2gQrpo6Nb6/fQrsOCfzYErmyn2sPLz9lNKsymA== X-Received: by 2002:a19:810c:: with SMTP id c12mr4351687lfd.244.1613046996016; Thu, 11 Feb 2021 04:36:36 -0800 (PST) Received: from localhost.localdomain (62-78-225-252.bb.dnainternet.fi. [62.78.225.252]) by smtp.gmail.com with ESMTPSA id n12sm896522lji.99.2021.02.11.04.36.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Feb 2021 04:36:35 -0800 (PST) Date: Thu, 11 Feb 2021 14:36:29 +0200 From: Matti Vaittinen To: mazziesaccount@gmail.com, matti.vaittinen@fi.rohmeurope.com Cc: Liam Girdwood , Mark Brown , Rob Herring , Matti Vaittinen , Andy Gross , Bjorn Andersson , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-power@fi.rohmeurope.com, linux-arm-msm@vger.kernel.org, linux-renesas-soc@vger.kernel.org Subject: [RFC PATCH 7/7] regulator: bd9576: Fix the driver name in id table Message-ID: <074dbbeef9ee2d5440d8c9ed1424ff4e99bdc048.1613042245.git.matti.vaittinen@fi.rohmeurope.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Driver name was changed in MFD cell: https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaittinen@fi.rohmeurope.com/ Fix the ID table to match this. Signed-off-by: Matti Vaittinen --- drivers/regulator/bd9576-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index 8768f6145ec4..39d4cb04ac34 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -1087,8 +1087,8 @@ static int bd957x_probe(struct platform_device *pdev) } static const struct platform_device_id bd957x_pmic_id[] = { - { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 }, - { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 }, + { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 }, + { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 }, { }, }; MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);