firmware/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_mfd_rn5t567-i...

150 lines
3.9 KiB
Diff

diff -drupN a/drivers/mfd/rn5t567-irq.c b/drivers/mfd/rn5t567-irq.c
--- a/drivers/mfd/rn5t567-irq.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/mfd/rn5t567-irq.c 2022-06-09 05:02:30.000000000 +0300
@@ -0,0 +1,145 @@
+/*
+ * Interrupt driver for RICOH567 power management chip.
+ *
+ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd.
+ *
+ * Author: cli <chen.li@ingenic.com>
+ *
+ * Based on code
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rn5t567.h>
+#include <linux/regmap.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+
+struct rn5t567_irq_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex irq_lock;
+ struct irq_domain *irq_domain;
+};
+
+static struct rn5t567_irq_data *rn5t567 = NULL;
+
+static irqreturn_t rn5t567_irq_thread_handler(int virq, void *data)
+{
+ struct rn5t567_irq_data *pdata = data;
+ int enable, pending = 0, ret;
+
+ might_sleep();
+
+ mutex_lock(&pdata->irq_lock);
+
+ ret = regmap_read(pdata->regmap, RN5T567_INTMON, &pending);
+ ret |=regmap_read(pdata->regmap, RN5T567_INTEN, &enable);
+ if (!ret) {
+ dev_warn(pdata->dev, "irq read i2c reg faild: %d\n", ret);
+ mutex_unlock(&pdata->irq_lock);
+ return IRQ_HANDLED;
+ }
+ pending = (pending & enable);
+ mutex_unlock(&pdata->irq_lock);
+
+ while (pending) {
+ int cur_irq , i;
+ i = fls(pending) - 1;
+ cur_irq = irq_find_mapping(pdata->irq_domain, i);
+ handle_nested_irq(cur_irq);
+ pending &= ~BIT(i);
+ };
+
+ return IRQ_HANDLED;
+}
+
+static int rn5t567_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq, unsigned int *out_type)
+{
+ struct regmap *regmap = (struct regmap *)d->host_data;
+ int ret;
+
+ if (!regmap)
+ return -EINVAL;
+
+ ret = irq_domain_xlate_onecell(d, ctrlr, intspec, intsize,
+ out_hwirq, out_type);
+ if (ret)
+ return ret;
+
+ switch (*out_hwirq) {
+ case RN5T567_IRQ_WDG:
+ break;
+ case RN5T567_IRQ_SYSTEM:
+ case RN5T567_IRQ_DCDC:
+ case RN5T567_IRQ_GPIO:
+ regmap_update_bits(regmap, RN5T567_INTEN, BIT(*out_hwirq), BIT(*out_hwirq));
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops rn5t567_irq_domain_ops = {
+ .xlate = rn5t567_domain_xlate_onecell,
+};
+
+int rn5t567_irq_init(struct i2c_client *i2c, struct regmap *regmap)
+{
+ int ret;
+
+ i2c->irq = irq_of_parse_and_map(i2c->dev.of_node, 0);
+ if (!i2c->irq)
+ return 0;
+
+ rn5t567 = devm_kzalloc(&i2c->dev, sizeof(struct rn5t567_irq_data), GFP_KERNEL);
+ if (!rn5t567)
+ return -ENOMEM;
+
+ mutex_init(&rn5t567->irq_lock);
+ rn5t567->regmap = regmap;
+
+ regmap_write(rn5t567->regmap, RN5T567_INTEN, 0);
+ regmap_write(rn5t567->regmap, RN5T567_INTPOL, 0);
+
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, rn5t567_irq_thread_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT, i2c->name, rn5t567);
+ if (ret) {
+ dev_err(&i2c->dev, "irq request failed: %d\n", ret);
+ return ret;
+ }
+
+ rn5t567->irq_domain = irq_domain_add_linear(i2c->dev.of_node, RN5T567_IRQ_NUM,
+ &rn5t567_irq_domain_ops, regmap);
+ if (IS_ERR(rn5t567->irq_domain)) {
+ ret = PTR_ERR(rn5t567->irq_domain);
+ dev_err(&i2c->dev, "irq domain add failed: %d\n", ret);
+ return ret;
+ }
+
+ rn5t567->dev = &i2c->dev;
+
+ return 0;
+}
+
+void rn5t567_irq_deinit(void)
+{
+ if (rn5t567->irq_domain)
+ irq_domain_remove(rn5t567->irq_domain);
+
+ regmap_write(rn5t567->regmap, RN5T567_INTEN, 0);
+}