[PATCH 9/9] regulator: da9121: add interrupt support

From: Adam Ward
Date: Fri Nov 20 2020 - 07:15:29 EST


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@xxxxxxxxxxx>
---
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