All of lore.kernel.org
 help / color / mirror / Atom feed
From: Adam Ward <adam.ward@diasemi.com>
To: Mark Brown <broonie@kernel.org>, Rob Herring <robh+dt@kernel.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>,
	Vincent Whitchurch <vincent.whitchurch@axis.com>,
	<linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>
Subject: [PATCH 9/9] regulator: da9121: add interrupt support
Date: Fri, 20 Nov 2020 12:14:59 +0000	[thread overview]
Message-ID: <ef98a01f6281ae6c925f283b51804f7f5194d230.1605868780.git.Adam.Ward.opensource@diasemi.com> (raw)
In-Reply-To: <cover.1605868780.git.Adam.Ward.opensource@diasemi.com>

Adds interrupt handler for variants, and notifications for events; over
temperature/voltage/current.
Also handling of persistent events and respective timing configuration.

Signed-off-by: Adam Ward <Adam.Ward.opensource@diasemi.com>
---
 drivers/regulator/da9121-regulator.c | 548 +++++++++++++++++++++++++++++++++++
 1 file changed, 548 insertions(+)

diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index 3addbd2..37a767e 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -24,15 +24,22 @@
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/regulator/da9121.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
 
 #include "da9121-regulator.h"
 
 /* Chip data */
 struct da9121 {
 	struct device *dev;
+	struct delayed_work work;
+	struct regmap *regmap;
 	struct da9121_pdata *pdata;
 	struct regmap *regmap;
 	struct regulator_dev *rdev[DA9121_IDX_MAX];
+	unsigned int persistent[2];
+	unsigned int passive_delay;
+	int chip_irq;
 	int variant_id;
 };
 
@@ -92,6 +99,104 @@ struct da9121_variant_info {
 	{ 1, 2, &da9121_6A_2phase_current  },	//DA9121_TYPE_DA9217
 };
 
+static void da9121_status_poll_on(struct work_struct *work)
+{
+	struct da9121 *chip = container_of(work, struct da9121, work.work);
+	enum { R0 = 0, R1, R2, REG_MAX_NUM };
+	int status[REG_MAX_NUM] = {0};
+	int clear[REG_MAX_NUM] = {0};
+	unsigned long delay;
+	int i;
+	int ret;
+
+	/* If persistent-notification, status will be true
+	 * If not persistent-notification any longer, status will be false
+	 */
+	ret = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_STATUS_0,
+			(void *)status, (size_t)REG_MAX_NUM);
+	if (ret < 0) {
+		dev_err(chip->dev,
+			"Failed to read STATUS registers: %d\n", ret);
+		goto error;
+	}
+
+	/* 0 TEMP_CRIT */
+	if ((chip->persistent[R0] & DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT) &&
+	    !(status[R0] & DA9121_MASK_SYS_STATUS_0_TEMP_CRIT)) {
+		clear[R0] |= DA9121_MASK_SYS_MASK_0_M_TEMP_CRIT;
+		chip->persistent[R0] &= ~DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT;
+	}
+	/* 0 TEMP_WARN */
+	if ((chip->persistent[R0] & DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN) &&
+	    !(status[R0] & DA9121_MASK_SYS_STATUS_0_TEMP_WARN)) {
+		clear[R0] |= DA9121_MASK_SYS_MASK_0_M_TEMP_WARN;
+		chip->persistent[R0] &= ~DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN;
+	}
+
+	/* 1 OV1 */
+	if ((chip->persistent[R1] & DA9121_MASK_SYS_EVENT_1_E_OV1) &&
+	    !(status[R1] & DA9121_MASK_SYS_STATUS_1_OV1)) {
+		clear[R1] |= DA9121_MASK_SYS_MASK_1_M_OV1;
+		chip->persistent[R1] &= ~DA9121_MASK_SYS_EVENT_1_E_OV1;
+	}
+	/* 1 UV1 */
+	if ((chip->persistent[R1] & DA9121_MASK_SYS_EVENT_1_E_UV1) &&
+	    !(status[R1] & DA9121_MASK_SYS_STATUS_1_UV1)) {
+		clear[R1] |= DA9121_MASK_SYS_MASK_1_M_UV1;
+		chip->persistent[R1] &= ~DA9121_MASK_SYS_EVENT_1_E_UV1;
+	}
+	/* 1 OC1 */
+	if ((chip->persistent[R1] & DA9121_MASK_SYS_EVENT_1_E_OC1) &&
+	    !(status[R1] & DA9121_MASK_SYS_STATUS_1_OC1)) {
+		clear[R1] |= DA9121_MASK_SYS_MASK_1_M_OC1;
+		chip->persistent[R1] &= ~DA9121_MASK_SYS_EVENT_1_E_OC1;
+	}
+
+	if (variant_parameters[chip->variant_id].num_bucks == 2) {
+		/* 1 OV2 */
+		if ((chip->persistent[R1] & DA9xxx_MASK_SYS_EVENT_1_E_OV2) &&
+		    !(status[R1] & DA9xxx_MASK_SYS_STATUS_1_OV2)) {
+			clear[R1] |= DA9xxx_MASK_SYS_MASK_1_M_OV2;
+			chip->persistent[R1] &= ~DA9xxx_MASK_SYS_EVENT_1_E_OV2;
+		}
+		/* 1 UV2 */
+		if ((chip->persistent[R1] & DA9xxx_MASK_SYS_EVENT_1_E_UV2) &&
+		    !(status[R1] & DA9xxx_MASK_SYS_STATUS_1_UV2)) {
+			clear[R1] |= DA9xxx_MASK_SYS_MASK_1_M_UV2;
+			chip->persistent[R1] &= ~DA9xxx_MASK_SYS_EVENT_1_E_UV2;
+		}
+		/* 1 OC2 */
+		if ((chip->persistent[R1] & DA9xxx_MASK_SYS_EVENT_1_E_OC2) &&
+		    !(status[R1] & DA9xxx_MASK_SYS_STATUS_1_OC2)) {
+			clear[R1] |= DA9xxx_MASK_SYS_MASK_1_M_OC2;
+			chip->persistent[R1] &= ~DA9xxx_MASK_SYS_EVENT_1_E_OC2;
+		}
+	}
+
+	for (i = R0; i < REG_MAX_NUM-1; i++) {
+		if (clear[i]) {
+			unsigned int reg = DA9121_REG_SYS_MASK_0 + i;
+			unsigned int mbit = clear[i];
+
+			ret = regmap_update_bits(chip->regmap, reg, mbit, 0);
+			if (ret < 0) {
+				dev_err(chip->dev,
+					"Failed to unmask 0x%02x %d\n",
+					reg, ret);
+				goto error;
+			}
+		}
+	}
+
+	if (chip->persistent[R0] | chip->persistent[R1]) {
+		delay = msecs_to_jiffies(chip->passive_delay);
+		queue_delayed_work(system_freezable_wq, &chip->work, delay);
+	}
+
+error:
+	return;
+}
+
 static bool da9121_rdev_to_buck_reg_mask(struct regulator_dev *rdev, bool mode,
 					 unsigned int *reg, unsigned int *msk)
 {
@@ -528,6 +633,311 @@ static struct da9121_pdata *da9121_parse_regulators_dt(struct da9121 *chip)
 }
 #endif
 
+static inline int da9121_handle_notifier(
+		struct da9121 *chip, struct regulator_dev *rdev,
+		unsigned int event_bank, unsigned int event, unsigned int ebit)
+{
+	enum { R0 = 0, R1, R2, REG_MAX_NUM };
+	unsigned long notification = 0;
+	int ret = 0;
+
+	if (event & ebit) {
+		switch (event_bank) {
+		case DA9121_REG_SYS_EVENT_0:
+			switch (event & ebit) {
+			case DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT:
+				chip->persistent[R0] |= DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT;
+				notification |= REGULATOR_EVENT_OVER_TEMP |
+						REGULATOR_EVENT_DISABLE;
+				break;
+			case DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN:
+				chip->persistent[R0] |= DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN;
+				notification |= REGULATOR_EVENT_OVER_TEMP;
+				break;
+			default:
+				dev_warn(chip->dev,
+					 "Unhandled event in bank0 0x%02x\n",
+					 event & ebit);
+				ret = -EINVAL;
+				break;
+			}
+			break;
+		case DA9121_REG_SYS_EVENT_1:
+			switch (event & ebit) {
+			case DA9121_MASK_SYS_EVENT_1_E_OV1:
+				chip->persistent[R1] |= DA9121_MASK_SYS_EVENT_1_E_OV1;
+				notification |= REGULATOR_EVENT_REGULATION_OUT;
+				break;
+			case DA9121_MASK_SYS_EVENT_1_E_UV1:
+				chip->persistent[R1] |= DA9121_MASK_SYS_EVENT_1_E_UV1;
+				notification |= REGULATOR_EVENT_UNDER_VOLTAGE;
+				break;
+			case DA9121_MASK_SYS_EVENT_1_E_OC1:
+				chip->persistent[R1] |= DA9121_MASK_SYS_EVENT_1_E_OC1;
+				notification |= REGULATOR_EVENT_OVER_CURRENT;
+				break;
+			case DA9xxx_MASK_SYS_EVENT_1_E_OV2:
+				chip->persistent[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_OV2;
+				notification |= REGULATOR_EVENT_REGULATION_OUT;
+				break;
+			case DA9xxx_MASK_SYS_EVENT_1_E_UV2:
+				chip->persistent[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_UV2;
+				notification |= REGULATOR_EVENT_UNDER_VOLTAGE;
+				break;
+			case DA9xxx_MASK_SYS_EVENT_1_E_OC2:
+				chip->persistent[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_OC2;
+				notification |= REGULATOR_EVENT_OVER_CURRENT;
+				break;
+			default:
+				dev_warn(chip->dev,
+					 "Unhandled event in bank1 0x%02x\n",
+					 event & ebit);
+				ret = -EINVAL;
+				break;
+			}
+			break;
+		default:
+			dev_warn(chip->dev,
+				 "Unhandled event bank 0x%02x\n", event_bank);
+			ret = -EINVAL;
+			goto error;
+		}
+
+		regulator_notifier_call_chain(rdev, notification, NULL);
+	}
+
+error:
+	return ret;
+}
+
+static irqreturn_t da9121_irq_handler(int irq, void *data)
+{
+	struct da9121 *chip = data;
+	struct regulator_dev *rdev;
+	enum { R0 = 0, R1, R2, REG_MAX_NUM };
+	int event[REG_MAX_NUM] = {0};
+	int handled[REG_MAX_NUM] = {0};
+	int mask[REG_MAX_NUM] = {0};
+	int ret = IRQ_NONE;
+	int i;
+	int err;
+
+	err = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_EVENT_0,
+			(void *)event, (size_t)REG_MAX_NUM);
+	if (err < 0) {
+		dev_err(chip->dev, "Failed to read EVENT registers %d\n", err);
+		ret = IRQ_NONE;
+		goto error;
+	}
+
+	err = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_MASK_0,
+			(void *)mask, (size_t)REG_MAX_NUM);
+	if (err < 0) {
+		dev_err(chip->dev,
+			"Failed to read MASK registers: %d\n", ret);
+		ret = IRQ_NONE;
+		goto error;
+	}
+
+	rdev = chip->rdev[DA9121_IDX_BUCK1];
+
+	/* 0 SYSTEM_GOOD */
+	if (!(mask[R0] & DA9xxx_MASK_SYS_MASK_0_M_SG) &&
+	    (event[R0] & DA9xxx_MASK_SYS_EVENT_0_E_SG)) {
+		dev_warn(chip->dev, "Handled E_SG\n");
+		handled[R0] |= DA9xxx_MASK_SYS_EVENT_0_E_SG;
+		ret = IRQ_HANDLED;
+	}
+
+	/* 0 TEMP_CRIT */
+	if (!(mask[R0] & DA9121_MASK_SYS_MASK_0_M_TEMP_CRIT) &&
+	    (event[R0] & DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT)) {
+		err = da9121_handle_notifier(chip, rdev,
+			DA9121_REG_SYS_EVENT_0,	event[R0],
+			DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT);
+		if (!err) {
+			handled[R0] |= DA9121_MASK_SYS_EVENT_0_E_TEMP_CRIT;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	/* 0 TEMP_WARN */
+	if (!(mask[R0] & DA9121_MASK_SYS_MASK_0_M_TEMP_WARN) &&
+	    (event[R0] & DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN)) {
+		err = da9121_handle_notifier(chip, rdev,
+			DA9121_REG_SYS_EVENT_0, event[R0],
+			DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN);
+		if (!err) {
+			handled[R0] |= DA9121_MASK_SYS_EVENT_0_E_TEMP_WARN;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	if (event[R0] != handled[R0]) {
+		dev_warn(chip->dev,
+			 "Unhandled event in bank0 0x%02x\n",
+			 event[R0] ^ handled[R0]);
+	}
+
+	/* 1 PG1 */
+	if (!(mask[R1] & DA9121_MASK_SYS_MASK_1_M_PG1) &&
+	    (event[R1] & DA9121_MASK_SYS_EVENT_1_E_PG1)) {
+		dev_warn(chip->dev, "Handled E_PG1\n");
+		handled[R1] |= DA9121_MASK_SYS_EVENT_1_E_PG1;
+		ret = IRQ_HANDLED;
+	}
+
+	/* 1 OV1 */
+	if (!(mask[R1] & DA9121_MASK_SYS_MASK_1_M_OV1) &&
+	    (event[R1] & DA9121_MASK_SYS_EVENT_1_E_OV1)) {
+		err = da9121_handle_notifier(chip, rdev,
+			DA9121_REG_SYS_EVENT_1,	event[R1],
+			DA9121_MASK_SYS_EVENT_1_E_OV1);
+		if (!err) {
+			handled[R1] |= DA9121_MASK_SYS_EVENT_1_E_OV1;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	/* 1 UV1 */
+	if (!(mask[R1] & DA9121_MASK_SYS_MASK_1_M_UV1) &&
+	    (event[R1] & DA9121_MASK_SYS_EVENT_1_E_UV1)) {
+		err = da9121_handle_notifier(chip, rdev,
+			DA9121_REG_SYS_EVENT_1,	event[R1],
+			DA9121_MASK_SYS_EVENT_1_E_UV1);
+		if (!err) {
+			handled[R1] |= DA9121_MASK_SYS_EVENT_1_E_UV1;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	/* 1 OC1 */
+	if (!(mask[R1] & DA9121_MASK_SYS_MASK_1_M_OC1) &&
+	    (event[R1] & DA9121_MASK_SYS_EVENT_1_E_OC1)) {
+		err = da9121_handle_notifier(chip, rdev,
+			DA9121_REG_SYS_EVENT_1,	event[R1],
+			DA9121_MASK_SYS_EVENT_1_E_OC1);
+		if (!err) {
+			handled[R1] |= DA9121_MASK_SYS_EVENT_1_E_OC1;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	if (variant_parameters[chip->variant_id].num_bucks == 2) {
+		struct regulator_dev *rdev2 = chip->rdev[DA9121_IDX_BUCK2];
+
+		/* 1 PG2 */
+		if (!(mask[R1] & DA9xxx_MASK_SYS_MASK_1_M_PG2) &&
+		    (event[R1] & DA9xxx_MASK_SYS_EVENT_1_E_PG2)) {
+			dev_warn(chip->dev, "Handled E_PG2\n");
+			handled[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_PG2;
+			ret = IRQ_HANDLED;
+		}
+
+		/* 1 OV2 */
+		if (!(mask[R1] & DA9xxx_MASK_SYS_MASK_1_M_OV2) &&
+		    (event[R1] & DA9xxx_MASK_SYS_EVENT_1_E_OV2)) {
+			err = da9121_handle_notifier(chip, rdev2,
+				DA9121_REG_SYS_EVENT_1,	event[R1],
+				DA9xxx_MASK_SYS_EVENT_1_E_OV2);
+			if (!err) {
+				handled[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_OV2;
+				ret = IRQ_HANDLED;
+			}
+		}
+
+		/* 1 UV2 */
+		if (!(mask[R1] & DA9xxx_MASK_SYS_MASK_1_M_UV2) &&
+		    (event[R1] & DA9xxx_MASK_SYS_EVENT_1_E_UV2)) {
+			err = da9121_handle_notifier(chip, rdev2,
+				DA9121_REG_SYS_EVENT_1,	event[R1],
+				DA9xxx_MASK_SYS_EVENT_1_E_UV2);
+			if (!err) {
+				handled[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_UV2;
+				ret = IRQ_HANDLED;
+			}
+		}
+
+		/* 1 OC2 */
+		if (!(mask[R1] & DA9xxx_MASK_SYS_MASK_1_M_OC2) &&
+		    (event[R1] & DA9xxx_MASK_SYS_EVENT_1_E_OC2)) {
+			err = da9121_handle_notifier(chip, rdev2,
+				DA9121_REG_SYS_EVENT_1,	event[R1],
+				DA9xxx_MASK_SYS_EVENT_1_E_OC2);
+			if (!err) {
+				handled[R1] |= DA9xxx_MASK_SYS_EVENT_1_E_OC2;
+				ret = IRQ_HANDLED;
+			}
+		}
+	}
+
+	if (event[R1] != handled[R1]) {
+		dev_warn(chip->dev,
+			 "Unhandled event in bank1 0x%02x\n",
+			 event[R1] ^ handled[R1]);
+	}
+
+	/* DA9121_REG_SYS_EVENT_2 */
+	if (!(mask[R2] & DA9121_MASK_SYS_MASK_2_M_GPIO2) &&
+	    (event[R2] & DA9121_MASK_SYS_EVENT_2_E_GPIO2)) {
+		dev_warn(chip->dev, "Handled E_GPIO2\n");
+		handled[R2] |= DA9121_MASK_SYS_EVENT_2_E_GPIO2;
+		ret = IRQ_HANDLED;
+	}
+
+	if (!(mask[R2] & DA9121_MASK_SYS_MASK_2_M_GPIO1) &&
+	    (event[R2] & DA9121_MASK_SYS_EVENT_2_E_GPIO1)) {
+		dev_warn(chip->dev, "Handled E_GPIO1\n");
+		handled[R2] |= DA9121_MASK_SYS_EVENT_2_E_GPIO1;
+		ret = IRQ_HANDLED;
+	}
+
+	if (!(mask[R2] & DA9121_MASK_SYS_MASK_2_M_GPIO0) &&
+	    (event[R2] & DA9121_MASK_SYS_EVENT_2_E_GPIO0)) {
+		dev_warn(chip->dev, "Handled E_GPIO0\n");
+		handled[R2] |= DA9121_MASK_SYS_EVENT_2_E_GPIO0;
+		ret = IRQ_HANDLED;
+	}
+
+	if (event[R2] != handled[R2]) {
+		dev_warn(chip->dev,
+			 "Unhandled event in bank2 0x%02x\n",
+			 event[R2] ^ handled[R2]);
+	}
+
+	/* Mask the interrupts for persistent events OV, OC, UV, WARN, CRIT */
+	for (i = R0; i < REG_MAX_NUM-1; i++) {
+		if (handled[i]) {
+			unsigned int reg = DA9121_REG_SYS_MASK_0 + i;
+			unsigned int mbit = handled[i];
+
+			err = regmap_update_bits(chip->regmap, reg, mbit, mbit);
+			if (err < 0) {
+				dev_err(chip->dev,
+					"Failed to mask 0x%02x interrupt %d\n",
+					reg, err);
+				ret = IRQ_NONE;
+				goto error;
+			}
+		}
+	}
+
+	/* clear the events */
+	if (handled[R0] | handled[R1] | handled[R2]) {
+		err = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_EVENT_0,
+				(const void *)handled, (size_t)REG_MAX_NUM);
+		if (err < 0) {
+			dev_err(chip->dev, "Fail to write EVENTs %d\n", err);
+			ret = IRQ_NONE;
+			goto error;
+		}
+	}
+
+	queue_delayed_work(system_freezable_wq, &chip->work, 0);
+error:
+	return ret;
+}
+
 static int da9121_set_regulator_config(struct da9121 *chip)
 {
 	struct regulator_config config = { };
@@ -835,6 +1245,117 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
 	return ret;
 }
 
+static int da9121_set_irq_masks(struct da9121 *chip, bool mask_irqs)
+{
+	unsigned int mask0, update0;
+	unsigned int mask1, update1;
+	unsigned int mask3;
+	int ret = 0;
+
+	if (chip->chip_irq != 0) {
+		mask0 = DA9121_MASK_SYS_MASK_0_M_TEMP_CRIT |
+			DA9121_MASK_SYS_MASK_0_M_TEMP_WARN;
+
+		mask1 = DA9121_MASK_SYS_MASK_1_M_OV1 |
+			DA9121_MASK_SYS_MASK_1_M_UV1 |
+			DA9121_MASK_SYS_MASK_1_M_OC1;
+
+		if (mask_irqs) {
+			update0 = mask0;
+			update1 = mask1;
+		} else {
+			update0 = 0;
+			update1 = 0;
+		}
+
+		ret = regmap_update_bits(chip->regmap,
+				DA9121_REG_SYS_MASK_0,
+				mask0,
+				update0);
+		if (ret < 0) {
+			dev_err(chip->dev, "Failed to write MASK 0 reg %d\n",
+				ret);
+			goto error;
+		}
+
+		ret = regmap_update_bits(chip->regmap,
+				DA9121_REG_SYS_MASK_1,
+				mask1,
+				update1);
+		if (ret < 0) {
+			dev_err(chip->dev, "Failed to write MASK 1 reg %d\n",
+				ret);
+			goto error;
+		}
+
+		/* permanently disable IRQs for VR_HOT and PG1_STAT */
+		mask3 = DA9121_MASK_SYS_MASK_3_M_VR_HOT |
+			DA9121_MASK_SYS_MASK_3_M_PG1_STAT;
+
+		ret = regmap_update_bits(chip->regmap,
+				DA9121_REG_SYS_MASK_3,
+				mask3,
+				mask3);
+		if (ret < 0) {
+			dev_err(chip->dev, "Failed to write MASK 3 reg %d\n",
+			ret);
+			goto error;
+		}
+	}
+
+error:
+	return ret;
+}
+
+static int da9121_config_irq(struct i2c_client *i2c,
+			struct da9121 *chip)
+{
+	unsigned int p_delay = DA9121_DEFAULT_POLLING_PERIOD_MS;
+	int ret = 0;
+
+	chip->chip_irq = i2c->irq;
+
+	if (chip->chip_irq != 0) {
+		if (!of_property_read_u32(chip->dev->of_node,
+					  "dlg,irq-polling-delay-passive",
+					  &p_delay)) {
+			if (p_delay < DA9121_MIN_POLLING_PERIOD_MS ||
+			    p_delay > DA9121_MAX_POLLING_PERIOD_MS) {
+				dev_warn(chip->dev,
+					 "Out-of-range polling period %d ms\n",
+					 p_delay);
+				p_delay = DA9121_DEFAULT_POLLING_PERIOD_MS;
+			}
+		}
+
+		chip->passive_delay = p_delay;
+
+		ret = devm_request_threaded_irq(chip->dev,
+					chip->chip_irq, NULL,
+					da9121_irq_handler,
+					IRQF_TRIGGER_LOW|IRQF_ONESHOT,
+					"da9121", chip);
+		if (ret != 0) {
+			dev_err(chip->dev, "Failed IRQ request: %d\n",
+				chip->chip_irq);
+			goto error;
+		}
+
+		ret = da9121_set_irq_masks(chip, false);
+		if (ret != 0) {
+			dev_err(chip->dev, "Failed to set IRQ masks: %d\n",
+				ret);
+			goto error;
+		}
+
+		INIT_DELAYED_WORK(&chip->work, da9121_status_poll_on);
+		dev_info(chip->dev, "Interrupt polling period set at %d ms\n",
+			 chip->passive_delay);
+	}
+error:
+	return ret;
+}
+
 static const struct of_device_id da9121_dt_ids[] = {
 	{ .compatible = "dlg,da9121", .data = (void *) DA9121_TYPE_DA9121_DA9130 },
 	{ .compatible = "dlg,da9130", .data = (void *) DA9121_TYPE_DA9121_DA9130 },
@@ -877,6 +1398,12 @@ static int da9121_i2c_probe(struct i2c_client *i2c,
 	if (ret < 0)
 		goto error;
 
+	ret = da9121_set_irq_masks(chip, true);
+	if (ret != 0) {
+		dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret);
+		goto error;
+	}
+
 	if (!chip->pdata)
 		chip->pdata = da9121_parse_regulators_dt(chip);
 
@@ -889,6 +1416,26 @@ static int da9121_i2c_probe(struct i2c_client *i2c,
 	if (ret < 0)
 		goto error;
 
+	ret = da9121_config_irq(i2c, chip);
+	if (ret < 0)
+		goto error;
+
+error:
+	return ret;
+}
+
+static int da9121_i2c_remove(struct i2c_client *i2c)
+{
+	struct da9121 *chip = i2c_get_clientdata(i2c);
+	int ret = 0;
+
+	ret = da9121_set_irq_masks(chip, true);
+	if (ret != 0) {
+		dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret);
+		goto error;
+	}
+
+	cancel_delayed_work(&chip->work);
 error:
 	return ret;
 }
@@ -911,6 +1458,7 @@ static int da9121_i2c_probe(struct i2c_client *i2c,
 		.of_match_table = of_match_ptr(da9121_dt_ids),
 	},
 	.probe = da9121_i2c_probe,
+	.remove = da9121_i2c_remove,
 	.id_table = da9121_i2c_id,
 };
 
-- 
1.9.1


  parent reply	other threads:[~2020-11-20 12:15 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-20 12:14 [PATCH 0/9] regulator: da9121: extend support to variants, add features Adam Ward
2020-11-20 12:14 ` [PATCH 1/9] regulator: Update DA9121 dt-bindings Adam Ward
2020-11-20 13:47   ` Vincent Whitchurch
2020-11-25  9:21     ` Vincent Whitchurch
2020-11-27 13:01       ` Adam Ward
2020-11-27 14:59         ` Mark Brown
2020-11-20 12:14 ` [PATCH 2/9] regulator: da9121: Add header file Adam Ward
2020-11-20 12:14 ` [PATCH 3/9] regulator: da9121: Add device variants Adam Ward
2020-11-20 12:14 ` [PATCH 4/9] regulator: da9121: Add device variant details and respective regmaps Adam Ward
2020-11-20 12:45   ` Mark Brown
2020-11-20 12:14 ` [PATCH 5/9] regulator: da9121: Add support for device variants via devicetree Adam Ward
2020-11-20 12:51   ` Mark Brown
2020-11-20 12:14 ` [PATCH 6/9] regulator: da9121: Update registration to support multiple buck variants Adam Ward
2020-11-20 13:06   ` Mark Brown
2020-11-20 12:14 ` [PATCH 7/9] regulator: da9121: add current support Adam Ward
2020-11-20 13:17   ` Mark Brown
2020-11-20 12:14 ` [PATCH 8/9] regulator: da9121: add mode support Adam Ward
2020-11-20 12:14 ` Adam Ward [this message]
2020-11-20 13:45   ` [PATCH 9/9] regulator: da9121: add interrupt support Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ef98a01f6281ae6c925f283b51804f7f5194d230.1605868780.git.Adam.Ward.opensource@diasemi.com \
    --to=adam.ward@diasemi.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=vincent.whitchurch@axis.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.