17111c6d1SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0
27111c6d1SMatti Vaittinen //
37111c6d1SMatti Vaittinen // Copyright (C) 2021 ROHM Semiconductors
47111c6d1SMatti Vaittinen // regulator IRQ based event notification helpers
57111c6d1SMatti Vaittinen //
67111c6d1SMatti Vaittinen // Logic has been partially adapted from qcom-labibb driver.
77111c6d1SMatti Vaittinen //
87111c6d1SMatti Vaittinen // Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
97111c6d1SMatti Vaittinen
107111c6d1SMatti Vaittinen #include <linux/device.h>
117111c6d1SMatti Vaittinen #include <linux/err.h>
127111c6d1SMatti Vaittinen #include <linux/interrupt.h>
137111c6d1SMatti Vaittinen #include <linux/kernel.h>
147111c6d1SMatti Vaittinen #include <linux/reboot.h>
157111c6d1SMatti Vaittinen #include <linux/regmap.h>
167111c6d1SMatti Vaittinen #include <linux/slab.h>
177111c6d1SMatti Vaittinen #include <linux/spinlock.h>
187111c6d1SMatti Vaittinen #include <linux/regulator/driver.h>
197111c6d1SMatti Vaittinen
207111c6d1SMatti Vaittinen #include "internal.h"
217111c6d1SMatti Vaittinen
227111c6d1SMatti Vaittinen #define REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS 10000
237111c6d1SMatti Vaittinen
247111c6d1SMatti Vaittinen struct regulator_irq {
257111c6d1SMatti Vaittinen struct regulator_irq_data rdata;
267111c6d1SMatti Vaittinen struct regulator_irq_desc desc;
277111c6d1SMatti Vaittinen int irq;
287111c6d1SMatti Vaittinen int retry_cnt;
297111c6d1SMatti Vaittinen struct delayed_work isr_work;
307111c6d1SMatti Vaittinen };
317111c6d1SMatti Vaittinen
327111c6d1SMatti Vaittinen /*
337111c6d1SMatti Vaittinen * Should only be called from threaded handler to prevent potential deadlock
347111c6d1SMatti Vaittinen */
rdev_flag_err(struct regulator_dev * rdev,int err)357111c6d1SMatti Vaittinen static void rdev_flag_err(struct regulator_dev *rdev, int err)
367111c6d1SMatti Vaittinen {
377111c6d1SMatti Vaittinen spin_lock(&rdev->err_lock);
387111c6d1SMatti Vaittinen rdev->cached_err |= err;
397111c6d1SMatti Vaittinen spin_unlock(&rdev->err_lock);
407111c6d1SMatti Vaittinen }
417111c6d1SMatti Vaittinen
rdev_clear_err(struct regulator_dev * rdev,int err)427111c6d1SMatti Vaittinen static void rdev_clear_err(struct regulator_dev *rdev, int err)
437111c6d1SMatti Vaittinen {
447111c6d1SMatti Vaittinen spin_lock(&rdev->err_lock);
457111c6d1SMatti Vaittinen rdev->cached_err &= ~err;
467111c6d1SMatti Vaittinen spin_unlock(&rdev->err_lock);
477111c6d1SMatti Vaittinen }
487111c6d1SMatti Vaittinen
regulator_notifier_isr_work(struct work_struct * work)497111c6d1SMatti Vaittinen static void regulator_notifier_isr_work(struct work_struct *work)
507111c6d1SMatti Vaittinen {
517111c6d1SMatti Vaittinen struct regulator_irq *h;
527111c6d1SMatti Vaittinen struct regulator_irq_desc *d;
537111c6d1SMatti Vaittinen struct regulator_irq_data *rid;
547111c6d1SMatti Vaittinen int ret = 0;
557111c6d1SMatti Vaittinen int tmo, i;
567111c6d1SMatti Vaittinen int num_rdevs;
577111c6d1SMatti Vaittinen
587111c6d1SMatti Vaittinen h = container_of(work, struct regulator_irq,
597111c6d1SMatti Vaittinen isr_work.work);
607111c6d1SMatti Vaittinen d = &h->desc;
617111c6d1SMatti Vaittinen rid = &h->rdata;
627111c6d1SMatti Vaittinen num_rdevs = rid->num_states;
637111c6d1SMatti Vaittinen
647111c6d1SMatti Vaittinen reread:
657111c6d1SMatti Vaittinen if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
667111c6d1SMatti Vaittinen if (!d->die)
677111c6d1SMatti Vaittinen return hw_protection_shutdown("Regulator HW failure? - no IC recovery",
687111c6d1SMatti Vaittinen REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
697111c6d1SMatti Vaittinen ret = d->die(rid);
707111c6d1SMatti Vaittinen /*
717111c6d1SMatti Vaittinen * If the 'last resort' IC recovery failed we will have
727111c6d1SMatti Vaittinen * nothing else left to do...
737111c6d1SMatti Vaittinen */
747111c6d1SMatti Vaittinen if (ret)
757111c6d1SMatti Vaittinen return hw_protection_shutdown("Regulator HW failure. IC recovery failed",
767111c6d1SMatti Vaittinen REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
777111c6d1SMatti Vaittinen
787111c6d1SMatti Vaittinen /*
797111c6d1SMatti Vaittinen * If h->die() was implemented we assume recovery has been
807111c6d1SMatti Vaittinen * attempted (probably regulator was shut down) and we
817111c6d1SMatti Vaittinen * just enable IRQ and bail-out.
827111c6d1SMatti Vaittinen */
837111c6d1SMatti Vaittinen goto enable_out;
847111c6d1SMatti Vaittinen }
857111c6d1SMatti Vaittinen if (d->renable) {
867111c6d1SMatti Vaittinen ret = d->renable(rid);
877111c6d1SMatti Vaittinen
887111c6d1SMatti Vaittinen if (ret == REGULATOR_FAILED_RETRY) {
897111c6d1SMatti Vaittinen /* Driver could not get current status */
907111c6d1SMatti Vaittinen h->retry_cnt++;
917111c6d1SMatti Vaittinen if (!d->reread_ms)
927111c6d1SMatti Vaittinen goto reread;
937111c6d1SMatti Vaittinen
947111c6d1SMatti Vaittinen tmo = d->reread_ms;
957111c6d1SMatti Vaittinen goto reschedule;
967111c6d1SMatti Vaittinen }
977111c6d1SMatti Vaittinen
987111c6d1SMatti Vaittinen if (ret) {
997111c6d1SMatti Vaittinen /*
1007111c6d1SMatti Vaittinen * IC status reading succeeded. update error info
1017111c6d1SMatti Vaittinen * just in case the renable changed it.
1027111c6d1SMatti Vaittinen */
1037111c6d1SMatti Vaittinen for (i = 0; i < num_rdevs; i++) {
1047111c6d1SMatti Vaittinen struct regulator_err_state *stat;
1057111c6d1SMatti Vaittinen struct regulator_dev *rdev;
1067111c6d1SMatti Vaittinen
1077111c6d1SMatti Vaittinen stat = &rid->states[i];
1087111c6d1SMatti Vaittinen rdev = stat->rdev;
1097111c6d1SMatti Vaittinen rdev_clear_err(rdev, (~stat->errors) &
1107111c6d1SMatti Vaittinen stat->possible_errs);
1117111c6d1SMatti Vaittinen }
1127111c6d1SMatti Vaittinen h->retry_cnt++;
1137111c6d1SMatti Vaittinen /*
1147111c6d1SMatti Vaittinen * The IC indicated problem is still ON - no point in
1157111c6d1SMatti Vaittinen * re-enabling the IRQ. Retry later.
1167111c6d1SMatti Vaittinen */
1177111c6d1SMatti Vaittinen tmo = d->irq_off_ms;
1187111c6d1SMatti Vaittinen goto reschedule;
1197111c6d1SMatti Vaittinen }
1207111c6d1SMatti Vaittinen }
1217111c6d1SMatti Vaittinen
1227111c6d1SMatti Vaittinen /*
1237111c6d1SMatti Vaittinen * Either IC reported problem cleared or no status checker was provided.
1247111c6d1SMatti Vaittinen * If problems are gone - good. If not - then the IRQ will fire again
1257111c6d1SMatti Vaittinen * and we'll have a new nice loop. In any case we should clear error
1267111c6d1SMatti Vaittinen * flags here and re-enable IRQs.
1277111c6d1SMatti Vaittinen */
1287111c6d1SMatti Vaittinen for (i = 0; i < num_rdevs; i++) {
1297111c6d1SMatti Vaittinen struct regulator_err_state *stat;
1307111c6d1SMatti Vaittinen struct regulator_dev *rdev;
1317111c6d1SMatti Vaittinen
1327111c6d1SMatti Vaittinen stat = &rid->states[i];
1337111c6d1SMatti Vaittinen rdev = stat->rdev;
1347111c6d1SMatti Vaittinen rdev_clear_err(rdev, stat->possible_errs);
1357111c6d1SMatti Vaittinen }
1367111c6d1SMatti Vaittinen
1377111c6d1SMatti Vaittinen /*
1387111c6d1SMatti Vaittinen * Things have been seemingly successful => zero retry-counter.
1397111c6d1SMatti Vaittinen */
1407111c6d1SMatti Vaittinen h->retry_cnt = 0;
1417111c6d1SMatti Vaittinen
1427111c6d1SMatti Vaittinen enable_out:
1437111c6d1SMatti Vaittinen enable_irq(h->irq);
1447111c6d1SMatti Vaittinen
1457111c6d1SMatti Vaittinen return;
1467111c6d1SMatti Vaittinen
1477111c6d1SMatti Vaittinen reschedule:
1487111c6d1SMatti Vaittinen if (!d->high_prio)
1497111c6d1SMatti Vaittinen mod_delayed_work(system_wq, &h->isr_work,
1507111c6d1SMatti Vaittinen msecs_to_jiffies(tmo));
1517111c6d1SMatti Vaittinen else
1527111c6d1SMatti Vaittinen mod_delayed_work(system_highpri_wq, &h->isr_work,
1537111c6d1SMatti Vaittinen msecs_to_jiffies(tmo));
1547111c6d1SMatti Vaittinen }
1557111c6d1SMatti Vaittinen
regulator_notifier_isr(int irq,void * data)1567111c6d1SMatti Vaittinen static irqreturn_t regulator_notifier_isr(int irq, void *data)
1577111c6d1SMatti Vaittinen {
1587111c6d1SMatti Vaittinen struct regulator_irq *h = data;
1597111c6d1SMatti Vaittinen struct regulator_irq_desc *d;
1607111c6d1SMatti Vaittinen struct regulator_irq_data *rid;
1617111c6d1SMatti Vaittinen unsigned long rdev_map = 0;
1627111c6d1SMatti Vaittinen int num_rdevs;
1637111c6d1SMatti Vaittinen int ret, i;
1647111c6d1SMatti Vaittinen
1657111c6d1SMatti Vaittinen d = &h->desc;
1667111c6d1SMatti Vaittinen rid = &h->rdata;
1677111c6d1SMatti Vaittinen num_rdevs = rid->num_states;
1687111c6d1SMatti Vaittinen
1697111c6d1SMatti Vaittinen if (d->fatal_cnt)
1707111c6d1SMatti Vaittinen h->retry_cnt++;
1717111c6d1SMatti Vaittinen
1727111c6d1SMatti Vaittinen /*
1737111c6d1SMatti Vaittinen * we spare a few cycles by not clearing statuses prior to this call.
1747111c6d1SMatti Vaittinen * The IC driver must initialize the status buffers for rdevs
1757111c6d1SMatti Vaittinen * which it indicates having active events via rdev_map.
1767111c6d1SMatti Vaittinen *
1777111c6d1SMatti Vaittinen * Maybe we should just to be on a safer side(?)
1787111c6d1SMatti Vaittinen */
1797111c6d1SMatti Vaittinen ret = d->map_event(irq, rid, &rdev_map);
1807111c6d1SMatti Vaittinen
1817111c6d1SMatti Vaittinen /*
1827111c6d1SMatti Vaittinen * If status reading fails (which is unlikely) we don't ack/disable
1837111c6d1SMatti Vaittinen * IRQ but just increase fail count and retry when IRQ fires again.
1847111c6d1SMatti Vaittinen * If retry_count exceeds the given safety limit we call IC specific die
1857111c6d1SMatti Vaittinen * handler which can try disabling regulator(s).
1867111c6d1SMatti Vaittinen *
187ad3ead1eSMatti Vaittinen * If no die handler is given we will just power-off as a last resort.
1887111c6d1SMatti Vaittinen *
1897111c6d1SMatti Vaittinen * We could try disabling all associated rdevs - but we might shoot
1907111c6d1SMatti Vaittinen * ourselves in the head and leave the problematic regulator enabled. So
1917111c6d1SMatti Vaittinen * if IC has no die-handler populated we just assume the regulator
1927111c6d1SMatti Vaittinen * can't be disabled.
1937111c6d1SMatti Vaittinen */
1947111c6d1SMatti Vaittinen if (unlikely(ret == REGULATOR_FAILED_RETRY))
1957111c6d1SMatti Vaittinen goto fail_out;
1967111c6d1SMatti Vaittinen
1977111c6d1SMatti Vaittinen h->retry_cnt = 0;
1987111c6d1SMatti Vaittinen /*
1997111c6d1SMatti Vaittinen * Let's not disable IRQ if there were no status bits for us. We'd
2007111c6d1SMatti Vaittinen * better leave spurious IRQ handling to genirq
2017111c6d1SMatti Vaittinen */
2027111c6d1SMatti Vaittinen if (ret || !rdev_map)
2037111c6d1SMatti Vaittinen return IRQ_NONE;
2047111c6d1SMatti Vaittinen
2057111c6d1SMatti Vaittinen /*
2067111c6d1SMatti Vaittinen * Some events are bogus if the regulator is disabled. Skip such events
2077111c6d1SMatti Vaittinen * if all relevant regulators are disabled
2087111c6d1SMatti Vaittinen */
2097111c6d1SMatti Vaittinen if (d->skip_off) {
2107111c6d1SMatti Vaittinen for_each_set_bit(i, &rdev_map, num_rdevs) {
2117111c6d1SMatti Vaittinen struct regulator_dev *rdev;
2127111c6d1SMatti Vaittinen const struct regulator_ops *ops;
2137111c6d1SMatti Vaittinen
2147111c6d1SMatti Vaittinen rdev = rid->states[i].rdev;
2157111c6d1SMatti Vaittinen ops = rdev->desc->ops;
2167111c6d1SMatti Vaittinen
2177111c6d1SMatti Vaittinen /*
2187111c6d1SMatti Vaittinen * If any of the flagged regulators is enabled we do
2197111c6d1SMatti Vaittinen * handle this
2207111c6d1SMatti Vaittinen */
2217111c6d1SMatti Vaittinen if (ops->is_enabled(rdev))
2227111c6d1SMatti Vaittinen break;
2237111c6d1SMatti Vaittinen }
2247111c6d1SMatti Vaittinen if (i == num_rdevs)
2257111c6d1SMatti Vaittinen return IRQ_NONE;
2267111c6d1SMatti Vaittinen }
2277111c6d1SMatti Vaittinen
2287111c6d1SMatti Vaittinen /* Disable IRQ if HW keeps line asserted */
2297111c6d1SMatti Vaittinen if (d->irq_off_ms)
2307111c6d1SMatti Vaittinen disable_irq_nosync(irq);
2317111c6d1SMatti Vaittinen
2327111c6d1SMatti Vaittinen /*
2337111c6d1SMatti Vaittinen * IRQ seems to be for us. Let's fire correct notifiers / store error
2347111c6d1SMatti Vaittinen * flags
2357111c6d1SMatti Vaittinen */
2367111c6d1SMatti Vaittinen for_each_set_bit(i, &rdev_map, num_rdevs) {
2377111c6d1SMatti Vaittinen struct regulator_err_state *stat;
2387111c6d1SMatti Vaittinen struct regulator_dev *rdev;
2397111c6d1SMatti Vaittinen
2407111c6d1SMatti Vaittinen stat = &rid->states[i];
2417111c6d1SMatti Vaittinen rdev = stat->rdev;
2427111c6d1SMatti Vaittinen
2437111c6d1SMatti Vaittinen rdev_dbg(rdev, "Sending regulator notification EVT 0x%lx\n",
2447111c6d1SMatti Vaittinen stat->notifs);
2457111c6d1SMatti Vaittinen
2467111c6d1SMatti Vaittinen regulator_notifier_call_chain(rdev, stat->notifs, NULL);
2477111c6d1SMatti Vaittinen rdev_flag_err(rdev, stat->errors);
2487111c6d1SMatti Vaittinen }
2497111c6d1SMatti Vaittinen
2507111c6d1SMatti Vaittinen if (d->irq_off_ms) {
2517111c6d1SMatti Vaittinen if (!d->high_prio)
2527111c6d1SMatti Vaittinen schedule_delayed_work(&h->isr_work,
2537111c6d1SMatti Vaittinen msecs_to_jiffies(d->irq_off_ms));
2547111c6d1SMatti Vaittinen else
2557111c6d1SMatti Vaittinen mod_delayed_work(system_highpri_wq,
2567111c6d1SMatti Vaittinen &h->isr_work,
2577111c6d1SMatti Vaittinen msecs_to_jiffies(d->irq_off_ms));
2587111c6d1SMatti Vaittinen }
2597111c6d1SMatti Vaittinen
2607111c6d1SMatti Vaittinen return IRQ_HANDLED;
2617111c6d1SMatti Vaittinen
2627111c6d1SMatti Vaittinen fail_out:
2637111c6d1SMatti Vaittinen if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
2647111c6d1SMatti Vaittinen /* If we have no recovery, just try shut down straight away */
2657111c6d1SMatti Vaittinen if (!d->die) {
2667111c6d1SMatti Vaittinen hw_protection_shutdown("Regulator failure. Retry count exceeded",
2677111c6d1SMatti Vaittinen REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
2687111c6d1SMatti Vaittinen } else {
2697111c6d1SMatti Vaittinen ret = d->die(rid);
2707111c6d1SMatti Vaittinen /* If die() failed shut down as a last attempt to save the HW */
2717111c6d1SMatti Vaittinen if (ret)
2727111c6d1SMatti Vaittinen hw_protection_shutdown("Regulator failure. Recovery failed",
2737111c6d1SMatti Vaittinen REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
2747111c6d1SMatti Vaittinen }
2757111c6d1SMatti Vaittinen }
2767111c6d1SMatti Vaittinen
2777111c6d1SMatti Vaittinen return IRQ_NONE;
2787111c6d1SMatti Vaittinen }
2797111c6d1SMatti Vaittinen
init_rdev_state(struct device * dev,struct regulator_irq * h,struct regulator_dev ** rdev,int common_err,int * rdev_err,int rdev_amount)2807111c6d1SMatti Vaittinen static int init_rdev_state(struct device *dev, struct regulator_irq *h,
2817111c6d1SMatti Vaittinen struct regulator_dev **rdev, int common_err,
2827111c6d1SMatti Vaittinen int *rdev_err, int rdev_amount)
2837111c6d1SMatti Vaittinen {
2847111c6d1SMatti Vaittinen int i;
2857111c6d1SMatti Vaittinen
2867111c6d1SMatti Vaittinen h->rdata.states = devm_kzalloc(dev, sizeof(*h->rdata.states) *
2877111c6d1SMatti Vaittinen rdev_amount, GFP_KERNEL);
2887111c6d1SMatti Vaittinen if (!h->rdata.states)
2897111c6d1SMatti Vaittinen return -ENOMEM;
2907111c6d1SMatti Vaittinen
2917111c6d1SMatti Vaittinen h->rdata.num_states = rdev_amount;
2927111c6d1SMatti Vaittinen h->rdata.data = h->desc.data;
2937111c6d1SMatti Vaittinen
2947111c6d1SMatti Vaittinen for (i = 0; i < rdev_amount; i++) {
2957111c6d1SMatti Vaittinen h->rdata.states[i].possible_errs = common_err;
2967111c6d1SMatti Vaittinen if (rdev_err)
2977111c6d1SMatti Vaittinen h->rdata.states[i].possible_errs |= *rdev_err++;
2987111c6d1SMatti Vaittinen h->rdata.states[i].rdev = *rdev++;
2997111c6d1SMatti Vaittinen }
3007111c6d1SMatti Vaittinen
3017111c6d1SMatti Vaittinen return 0;
3027111c6d1SMatti Vaittinen }
3037111c6d1SMatti Vaittinen
init_rdev_errors(struct regulator_irq * h)3047111c6d1SMatti Vaittinen static void init_rdev_errors(struct regulator_irq *h)
3057111c6d1SMatti Vaittinen {
3067111c6d1SMatti Vaittinen int i;
3077111c6d1SMatti Vaittinen
3087111c6d1SMatti Vaittinen for (i = 0; i < h->rdata.num_states; i++)
3097111c6d1SMatti Vaittinen if (h->rdata.states[i].possible_errs)
3107111c6d1SMatti Vaittinen h->rdata.states[i].rdev->use_cached_err = true;
3117111c6d1SMatti Vaittinen }
3127111c6d1SMatti Vaittinen
3137111c6d1SMatti Vaittinen /**
3147111c6d1SMatti Vaittinen * regulator_irq_helper - register IRQ based regulator event/error notifier
3157111c6d1SMatti Vaittinen *
3167111c6d1SMatti Vaittinen * @dev: device providing the IRQs
3177111c6d1SMatti Vaittinen * @d: IRQ helper descriptor.
3187111c6d1SMatti Vaittinen * @irq: IRQ used to inform events/errors to be notified.
3197111c6d1SMatti Vaittinen * @irq_flags: Extra IRQ flags to be OR'ed with the default
3207111c6d1SMatti Vaittinen * IRQF_ONESHOT when requesting the (threaded) irq.
3217111c6d1SMatti Vaittinen * @common_errs: Errors which can be flagged by this IRQ for all rdevs.
3227111c6d1SMatti Vaittinen * When IRQ is re-enabled these errors will be cleared
323a764ff77SMatti Vaittinen * from all associated regulators. Use this instead of the
324a764ff77SMatti Vaittinen * per_rdev_errs if you use
325a764ff77SMatti Vaittinen * regulator_irq_map_event_simple() for event mapping.
3267111c6d1SMatti Vaittinen * @per_rdev_errs: Optional error flag array describing errors specific
3277111c6d1SMatti Vaittinen * for only some of the regulators. These errors will be
3287111c6d1SMatti Vaittinen * or'ed with common errors. If this is given the array
3297111c6d1SMatti Vaittinen * should contain rdev_amount flags. Can be set to NULL
3307111c6d1SMatti Vaittinen * if there is no regulator specific error flags for this
3317111c6d1SMatti Vaittinen * IRQ.
3327111c6d1SMatti Vaittinen * @rdev: Array of pointers to regulators associated with this
3337111c6d1SMatti Vaittinen * IRQ.
3347111c6d1SMatti Vaittinen * @rdev_amount: Amount of regulators associated with this IRQ.
3357111c6d1SMatti Vaittinen *
3367111c6d1SMatti Vaittinen * Return: handle to irq_helper or an ERR_PTR() encoded error code.
3377111c6d1SMatti Vaittinen */
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)3387111c6d1SMatti Vaittinen void *regulator_irq_helper(struct device *dev,
3397111c6d1SMatti Vaittinen const struct regulator_irq_desc *d, int irq,
3407111c6d1SMatti Vaittinen int irq_flags, int common_errs, int *per_rdev_errs,
3417111c6d1SMatti Vaittinen struct regulator_dev **rdev, int rdev_amount)
3427111c6d1SMatti Vaittinen {
3437111c6d1SMatti Vaittinen struct regulator_irq *h;
3447111c6d1SMatti Vaittinen int ret;
3457111c6d1SMatti Vaittinen
3467111c6d1SMatti Vaittinen if (!rdev_amount || !d || !d->map_event || !d->name)
3477111c6d1SMatti Vaittinen return ERR_PTR(-EINVAL);
3487111c6d1SMatti Vaittinen
3497111c6d1SMatti Vaittinen h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
3507111c6d1SMatti Vaittinen if (!h)
3517111c6d1SMatti Vaittinen return ERR_PTR(-ENOMEM);
3527111c6d1SMatti Vaittinen
3537111c6d1SMatti Vaittinen h->irq = irq;
3547111c6d1SMatti Vaittinen h->desc = *d;
355*3ad4d29bSMatti Vaittinen h->desc.name = devm_kstrdup(dev, d->name, GFP_KERNEL);
356*3ad4d29bSMatti Vaittinen if (!h->desc.name)
357*3ad4d29bSMatti Vaittinen return ERR_PTR(-ENOMEM);
3587111c6d1SMatti Vaittinen
3597111c6d1SMatti Vaittinen ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs,
3607111c6d1SMatti Vaittinen rdev_amount);
3617111c6d1SMatti Vaittinen if (ret)
3627111c6d1SMatti Vaittinen return ERR_PTR(ret);
3637111c6d1SMatti Vaittinen
3647111c6d1SMatti Vaittinen init_rdev_errors(h);
3657111c6d1SMatti Vaittinen
3667111c6d1SMatti Vaittinen if (h->desc.irq_off_ms)
3677111c6d1SMatti Vaittinen INIT_DELAYED_WORK(&h->isr_work, regulator_notifier_isr_work);
3687111c6d1SMatti Vaittinen
3697111c6d1SMatti Vaittinen ret = request_threaded_irq(h->irq, NULL, regulator_notifier_isr,
3707111c6d1SMatti Vaittinen IRQF_ONESHOT | irq_flags, h->desc.name, h);
3717111c6d1SMatti Vaittinen if (ret) {
3727111c6d1SMatti Vaittinen dev_err(dev, "Failed to request IRQ %d\n", irq);
3737111c6d1SMatti Vaittinen
3747111c6d1SMatti Vaittinen return ERR_PTR(ret);
3757111c6d1SMatti Vaittinen }
3767111c6d1SMatti Vaittinen
3777111c6d1SMatti Vaittinen return h;
3787111c6d1SMatti Vaittinen }
3797111c6d1SMatti Vaittinen EXPORT_SYMBOL_GPL(regulator_irq_helper);
3807111c6d1SMatti Vaittinen
3817111c6d1SMatti Vaittinen /**
3827111c6d1SMatti Vaittinen * regulator_irq_helper_cancel - drop IRQ based regulator event/error notifier
3837111c6d1SMatti Vaittinen *
3847111c6d1SMatti Vaittinen * @handle: Pointer to handle returned by a successful call to
3857111c6d1SMatti Vaittinen * regulator_irq_helper(). Will be NULLed upon return.
3867111c6d1SMatti Vaittinen *
3877111c6d1SMatti Vaittinen * The associated IRQ is released and work is cancelled when the function
3887111c6d1SMatti Vaittinen * returns.
3897111c6d1SMatti Vaittinen */
regulator_irq_helper_cancel(void ** handle)3907111c6d1SMatti Vaittinen void regulator_irq_helper_cancel(void **handle)
3917111c6d1SMatti Vaittinen {
3927111c6d1SMatti Vaittinen if (handle && *handle) {
3937111c6d1SMatti Vaittinen struct regulator_irq *h = *handle;
3947111c6d1SMatti Vaittinen
3957111c6d1SMatti Vaittinen free_irq(h->irq, h);
3967111c6d1SMatti Vaittinen if (h->desc.irq_off_ms)
3977111c6d1SMatti Vaittinen cancel_delayed_work_sync(&h->isr_work);
3987111c6d1SMatti Vaittinen
3997111c6d1SMatti Vaittinen h = NULL;
4007111c6d1SMatti Vaittinen }
4017111c6d1SMatti Vaittinen }
4027111c6d1SMatti Vaittinen EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel);
403a764ff77SMatti Vaittinen
404a764ff77SMatti Vaittinen /**
405a764ff77SMatti Vaittinen * regulator_irq_map_event_simple - regulator IRQ notification for trivial IRQs
406a764ff77SMatti Vaittinen *
407a764ff77SMatti Vaittinen * @irq: Number of IRQ that occurred
408a764ff77SMatti Vaittinen * @rid: Information about the event IRQ indicates
409a764ff77SMatti Vaittinen * @dev_mask: mask indicating the regulator originating the IRQ
410a764ff77SMatti Vaittinen *
411a764ff77SMatti Vaittinen * Regulators whose IRQ has single, well defined purpose (always indicate
412a764ff77SMatti Vaittinen * exactly one event, and are relevant to exactly one regulator device) can
413a764ff77SMatti Vaittinen * use this function as their map_event callbac for their regulator IRQ
414a764ff77SMatti Vaittinen * notification helperk. Exactly one rdev and exactly one error (in
415a764ff77SMatti Vaittinen * "common_errs"-field) can be given at IRQ helper registration for
416a764ff77SMatti Vaittinen * regulator_irq_map_event_simple() to be viable.
417a764ff77SMatti Vaittinen */
regulator_irq_map_event_simple(int irq,struct regulator_irq_data * rid,unsigned long * dev_mask)418a764ff77SMatti Vaittinen int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid,
419a764ff77SMatti Vaittinen unsigned long *dev_mask)
420a764ff77SMatti Vaittinen {
421a764ff77SMatti Vaittinen int err = rid->states[0].possible_errs;
422a764ff77SMatti Vaittinen
423a764ff77SMatti Vaittinen *dev_mask = 1;
424a764ff77SMatti Vaittinen /*
425a764ff77SMatti Vaittinen * This helper should only be used in a situation where the IRQ
426a764ff77SMatti Vaittinen * can indicate only one type of problem for one specific rdev.
427a764ff77SMatti Vaittinen * Something fishy is going on if we are having multiple rdevs or ERROR
428a764ff77SMatti Vaittinen * flags here.
429a764ff77SMatti Vaittinen */
430a764ff77SMatti Vaittinen if (WARN_ON(rid->num_states != 1 || hweight32(err) != 1))
431a764ff77SMatti Vaittinen return 0;
432a764ff77SMatti Vaittinen
433a764ff77SMatti Vaittinen rid->states[0].errors = err;
434a764ff77SMatti Vaittinen rid->states[0].notifs = regulator_err2notif(err);
435a764ff77SMatti Vaittinen
436a764ff77SMatti Vaittinen return 0;
437a764ff77SMatti Vaittinen }
438a764ff77SMatti Vaittinen EXPORT_SYMBOL_GPL(regulator_irq_map_event_simple);
439a764ff77SMatti Vaittinen
440