lkml.org 
[lkml]   [2021]   [Nov]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 1/5] regulator: irq_helpers: Allow omitting map_event for simple IRQs
    If the device has dedicated IRQ (or irq controller already splits the IRQ
    appropriately) for single error indication on a single regulator then the
    map-event callback has not much to do.

    Simplify the usage for such devices by using a common helper function to
    return the regulator and the reason when map_event is not populated.

    Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>

    ---
    drivers/regulator/irq_helpers.c | 52 ++++++++++++++++++++++++++++++--
    include/linux/regulator/driver.h | 36 ++++++++++++++++++++++
    2 files changed, 86 insertions(+), 2 deletions(-)

    diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
    index 522764435575..e06127006c1b 100644
    --- a/drivers/regulator/irq_helpers.c
    +++ b/drivers/regulator/irq_helpers.c
    @@ -153,6 +153,42 @@ static void regulator_notifier_isr_work(struct work_struct *work)
    msecs_to_jiffies(tmo));
    }

    +static bool single_bit_set(int val, int bits_to_check)
    +{
    + int bit;
    + const unsigned long bits = val;
    +
    + bit = find_first_bit(&bits, bits_to_check);
    + if (bit == bits_to_check)
    + return false;
    +
    + bit = find_next_bit(&bits, bits_to_check, bit + 1);
    +
    + return (bit == bits_to_check);
    +}
    +
    +static int map_event_simple(int irq, struct regulator_irq_data *rid,
    + unsigned long *dev_mask)
    +{
    + int err = rid->states[0].possible_errs;
    +
    + *dev_mask = 1;
    + /*
    + * This helper should only be used in a situation where the IRQ
    + * can indicate only one type of problem for one specific rdev.
    + * Something fishy is going on if we are having multiple rdevs or ERROR
    + * flags here.
    + */
    + if (WARN_ON(rid->num_states != 1 ||
    + !single_bit_set(err, sizeof(err) * 8)))
    + return 0;
    +
    + rid->states[0].errors = err;
    + rid->states[0].notifs = regulator_err2notif(err);
    +
    + return 0;
    +}
    +
    static irqreturn_t regulator_notifier_isr(int irq, void *data)
    {
    struct regulator_irq *h = data;
    @@ -320,7 +356,10 @@ static void init_rdev_errors(struct regulator_irq *h)
    * 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
    + * from all associated regulators. Use this instead of the
    + * per_rdev_errs if you have a simple device where the
    + * IRQ can indicate only one type of error for one specific
    + * regulator (and you omitted the map_event).
    * @per_rdev_errs: Optional error flag array describing errors specific
    * for only some of the regulators. These errors will be
    * or'ed with common errors. If this is given the array
    @@ -341,7 +380,7 @@ void *regulator_irq_helper(struct device *dev,
    struct regulator_irq *h;
    int ret;

    - if (!rdev_amount || !d || !d->map_event || !d->name)
    + if (!rdev_amount || !d || !d->name)
    return ERR_PTR(-EINVAL);

    h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
    @@ -351,6 +390,15 @@ void *regulator_irq_helper(struct device *dev,
    h->irq = irq;
    h->desc = *d;

    + if (!h->desc.map_event) {
    + if (rdev_amount != 1 ||
    + !single_bit_set(common_errs, sizeof(common_errs) * 8) ||
    + per_rdev_errs)
    + return ERR_PTR(-EINVAL);
    +
    + h->desc.map_event = map_event_simple;
    + }
    +
    ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs,
    rdev_amount);
    if (ret)
    diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
    index bd7a73db2e66..f9d1115627e5 100644
    --- a/include/linux/regulator/driver.h
    +++ b/include/linux/regulator/driver.h
    @@ -529,6 +529,8 @@ struct regulator_irq_data {
    * status reading from IC failed. If this is repeated for
    * fatal_cnt times the core will call die() callback or power-off
    * the system as a last resort to protect the HW.
    + * Simple devices where a particular IRQ can only indicate one
    + * type of error, for one regulator can omit this callback.
    * @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()
    @@ -644,6 +646,40 @@ struct regulator_dev {
    spinlock_t err_lock;
    };

    +/*
    + * Convert error flags to corresponding notifications.
    + *
    + * Can be used by drivers which use the notification helpers to
    + * find out correct notification flags based on the error flags. Drivers
    + * can avoid storing both supported notification and error flags which
    + * may save few bytes.
    + */
    +static inline int regulator_err2notif(int err)
    +{
    + switch (err) {
    + case REGULATOR_ERROR_UNDER_VOLTAGE:
    + return REGULATOR_EVENT_UNDER_VOLTAGE;
    + case REGULATOR_ERROR_OVER_CURRENT:
    + return REGULATOR_EVENT_OVER_CURRENT;
    + case REGULATOR_ERROR_REGULATION_OUT:
    + return REGULATOR_EVENT_REGULATION_OUT;
    + case REGULATOR_ERROR_FAIL:
    + return REGULATOR_EVENT_FAIL;
    + case REGULATOR_ERROR_OVER_TEMP:
    + return REGULATOR_EVENT_OVER_TEMP;
    + case REGULATOR_ERROR_UNDER_VOLTAGE_WARN:
    + return REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
    + case REGULATOR_ERROR_OVER_CURRENT_WARN:
    + return REGULATOR_EVENT_OVER_CURRENT_WARN;
    + case REGULATOR_ERROR_OVER_VOLTAGE_WARN:
    + return REGULATOR_EVENT_OVER_VOLTAGE_WARN;
    + case REGULATOR_ERROR_OVER_TEMP_WARN:
    + return REGULATOR_EVENT_OVER_TEMP_WARN;
    + }
    + return 0;
    +}
    +
    +
    struct regulator_dev *
    regulator_register(const struct regulator_desc *regulator_desc,
    const struct regulator_config *config);
    --
    2.31.1

    --
    Matti Vaittinen, Linux device drivers
    ROHM Semiconductors, Finland SWDC
    Kiviharjunlenkki 1E
    90220 OULU
    FINLAND

    ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
    Simon says - in Latin please.
    ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
    Thanks to Simon Glass for the translation =]
    [unhandled content-type:application/pgp-signature]
    \
     
     \ /
      Last update: 2021-11-18 12:50    [W:6.170 / U:1.160 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site