mfd: rn5t618: Add IRQ support

This adds support for IRQ handling in the RC5T619 which is required
for properly implementing subdevices like RTC.
For now only definitions for the variant RC5T619 are included.

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
This commit is contained in:
Andreas Kemnade 2020-03-20 09:11:00 +01:00 committed by Lee Jones
parent 361dca7d97
commit 0c81604516
3 changed files with 93 additions and 1 deletions

View File

@ -1058,6 +1058,7 @@ config MFD_RN5T618
depends on OF depends on OF
select MFD_CORE select MFD_CORE
select REGMAP_I2C select REGMAP_I2C
select REGMAP_IRQ
help help
Say yes here to add support for the Ricoh RN5T567, Say yes here to add support for the Ricoh RN5T567,
RN5T618, RC5T619 PMIC. RN5T618, RC5T619 PMIC.

View File

@ -8,6 +8,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/rn5t618.h> #include <linux/mfd/rn5t618.h>
#include <linux/module.h> #include <linux/module.h>
@ -46,9 +48,56 @@ static const struct regmap_config rn5t618_regmap_config = {
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
}; };
static const struct regmap_irq rc5t619_irqs[] = {
REGMAP_IRQ_REG(RN5T618_IRQ_SYS, 0, BIT(0)),
REGMAP_IRQ_REG(RN5T618_IRQ_DCDC, 0, BIT(1)),
REGMAP_IRQ_REG(RN5T618_IRQ_RTC, 0, BIT(2)),
REGMAP_IRQ_REG(RN5T618_IRQ_ADC, 0, BIT(3)),
REGMAP_IRQ_REG(RN5T618_IRQ_GPIO, 0, BIT(4)),
REGMAP_IRQ_REG(RN5T618_IRQ_CHG, 0, BIT(6)),
};
static const struct regmap_irq_chip rc5t619_irq_chip = {
.name = "rc5t619",
.irqs = rc5t619_irqs,
.num_irqs = ARRAY_SIZE(rc5t619_irqs),
.num_regs = 1,
.status_base = RN5T618_INTMON,
.mask_base = RN5T618_INTEN,
.mask_invert = true,
};
static struct rn5t618 *rn5t618_pm_power_off; static struct rn5t618 *rn5t618_pm_power_off;
static struct notifier_block rn5t618_restart_handler; static struct notifier_block rn5t618_restart_handler;
static int rn5t618_irq_init(struct rn5t618 *rn5t618)
{
const struct regmap_irq_chip *irq_chip = NULL;
int ret;
if (!rn5t618->irq)
return 0;
switch (rn5t618->variant) {
case RC5T619:
irq_chip = &rc5t619_irq_chip;
break;
default:
dev_err(rn5t618->dev, "Currently no IRQ support for variant %d\n",
(int)rn5t618->variant);
return -ENOENT;
}
ret = devm_regmap_add_irq_chip(rn5t618->dev, rn5t618->regmap,
rn5t618->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0, irq_chip, &rn5t618->irq_data);
if (ret)
dev_err(rn5t618->dev, "Failed to register IRQ chip\n");
return ret;
}
static void rn5t618_trigger_poweroff_sequence(bool repower) static void rn5t618_trigger_poweroff_sequence(bool repower)
{ {
/* disable automatic repower-on */ /* disable automatic repower-on */
@ -106,6 +155,8 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, priv); i2c_set_clientdata(i2c, priv);
priv->variant = (long)of_id->data; priv->variant = (long)of_id->data;
priv->irq = i2c->irq;
priv->dev = &i2c->dev;
priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config); priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config);
if (IS_ERR(priv->regmap)) { if (IS_ERR(priv->regmap)) {
@ -138,7 +189,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
return ret; return ret;
} }
return 0; return rn5t618_irq_init(priv);
} }
static int rn5t618_i2c_remove(struct i2c_client *i2c) static int rn5t618_i2c_remove(struct i2c_client *i2c)
@ -155,15 +206,40 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c)
return 0; return 0;
} }
static int __maybe_unused rn5t618_i2c_suspend(struct device *dev)
{
struct rn5t618 *priv = dev_get_drvdata(dev);
if (priv->irq)
disable_irq(priv->irq);
return 0;
}
static int __maybe_unused rn5t618_i2c_resume(struct device *dev)
{
struct rn5t618 *priv = dev_get_drvdata(dev);
if (priv->irq)
enable_irq(priv->irq);
return 0;
}
static const struct i2c_device_id rn5t618_i2c_id[] = { static const struct i2c_device_id rn5t618_i2c_id[] = {
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, rn5t618_i2c_id); MODULE_DEVICE_TABLE(i2c, rn5t618_i2c_id);
static SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops,
rn5t618_i2c_suspend,
rn5t618_i2c_resume);
static struct i2c_driver rn5t618_i2c_driver = { static struct i2c_driver rn5t618_i2c_driver = {
.driver = { .driver = {
.name = "rn5t618", .name = "rn5t618",
.of_match_table = of_match_ptr(rn5t618_of_match), .of_match_table = of_match_ptr(rn5t618_of_match),
.pm = &rn5t618_i2c_dev_pm_ops,
}, },
.probe = rn5t618_i2c_probe, .probe = rn5t618_i2c_probe,
.remove = rn5t618_i2c_remove, .remove = rn5t618_i2c_remove,

View File

@ -242,9 +242,24 @@ enum {
RC5T619, RC5T619,
}; };
/* RN5T618 IRQ definitions */
enum {
RN5T618_IRQ_SYS = 0,
RN5T618_IRQ_DCDC,
RN5T618_IRQ_RTC,
RN5T618_IRQ_ADC,
RN5T618_IRQ_GPIO,
RN5T618_IRQ_CHG,
RN5T618_NR_IRQS,
};
struct rn5t618 { struct rn5t618 {
struct regmap *regmap; struct regmap *regmap;
struct device *dev;
long variant; long variant;
int irq;
struct regmap_irq_chip_data *irq_data;
}; };
#endif /* __LINUX_MFD_RN5T618_H */ #endif /* __LINUX_MFD_RN5T618_H */