295 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Copyright (c) 2020 MediaTek Inc.4 5#include <linux/interrupt.h>6#include <linux/irq.h>7#include <linux/irqdomain.h>8#include <linux/mfd/mt6357/core.h>9#include <linux/mfd/mt6357/registers.h>10#include <linux/mfd/mt6358/core.h>11#include <linux/mfd/mt6358/registers.h>12#include <linux/mfd/mt6359/core.h>13#include <linux/mfd/mt6359/registers.h>14#include <linux/mfd/mt6397/core.h>15#include <linux/module.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18 19#define MTK_PMIC_REG_WIDTH 1620 21static const struct irq_top_t mt6357_ints[] = {22 MT6357_TOP_GEN(BUCK),23 MT6357_TOP_GEN(LDO),24 MT6357_TOP_GEN(PSC),25 MT6357_TOP_GEN(SCK),26 MT6357_TOP_GEN(BM),27 MT6357_TOP_GEN(HK),28 MT6357_TOP_GEN(AUD),29 MT6357_TOP_GEN(MISC),30};31 32static const struct irq_top_t mt6358_ints[] = {33 MT6358_TOP_GEN(BUCK),34 MT6358_TOP_GEN(LDO),35 MT6358_TOP_GEN(PSC),36 MT6358_TOP_GEN(SCK),37 MT6358_TOP_GEN(BM),38 MT6358_TOP_GEN(HK),39 MT6358_TOP_GEN(AUD),40 MT6358_TOP_GEN(MISC),41};42 43static const struct irq_top_t mt6359_ints[] = {44 MT6359_TOP_GEN(BUCK),45 MT6359_TOP_GEN(LDO),46 MT6359_TOP_GEN(PSC),47 MT6359_TOP_GEN(SCK),48 MT6359_TOP_GEN(BM),49 MT6359_TOP_GEN(HK),50 MT6359_TOP_GEN(AUD),51 MT6359_TOP_GEN(MISC),52};53 54static struct pmic_irq_data mt6357_irqd = {55 .num_top = ARRAY_SIZE(mt6357_ints),56 .num_pmic_irqs = MT6357_IRQ_NR,57 .top_int_status_reg = MT6357_TOP_INT_STATUS0,58 .pmic_ints = mt6357_ints,59};60 61static struct pmic_irq_data mt6358_irqd = {62 .num_top = ARRAY_SIZE(mt6358_ints),63 .num_pmic_irqs = MT6358_IRQ_NR,64 .top_int_status_reg = MT6358_TOP_INT_STATUS0,65 .pmic_ints = mt6358_ints,66};67 68static struct pmic_irq_data mt6359_irqd = {69 .num_top = ARRAY_SIZE(mt6359_ints),70 .num_pmic_irqs = MT6359_IRQ_NR,71 .top_int_status_reg = MT6359_TOP_INT_STATUS0,72 .pmic_ints = mt6359_ints,73};74 75static void pmic_irq_enable(struct irq_data *data)76{77 unsigned int hwirq = irqd_to_hwirq(data);78 struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);79 struct pmic_irq_data *irqd = chip->irq_data;80 81 irqd->enable_hwirq[hwirq] = true;82}83 84static void pmic_irq_disable(struct irq_data *data)85{86 unsigned int hwirq = irqd_to_hwirq(data);87 struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);88 struct pmic_irq_data *irqd = chip->irq_data;89 90 irqd->enable_hwirq[hwirq] = false;91}92 93static void pmic_irq_lock(struct irq_data *data)94{95 struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);96 97 mutex_lock(&chip->irqlock);98}99 100static void pmic_irq_sync_unlock(struct irq_data *data)101{102 unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift;103 struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);104 struct pmic_irq_data *irqd = chip->irq_data;105 106 for (i = 0; i < irqd->num_pmic_irqs; i++) {107 if (irqd->enable_hwirq[i] == irqd->cache_hwirq[i])108 continue;109 110 /* Find out the IRQ group */111 top_gp = 0;112 while ((top_gp + 1) < irqd->num_top &&113 i >= irqd->pmic_ints[top_gp + 1].hwirq_base)114 top_gp++;115 116 /* Find the IRQ registers */117 gp_offset = i - irqd->pmic_ints[top_gp].hwirq_base;118 int_regs = gp_offset / MTK_PMIC_REG_WIDTH;119 shift = gp_offset % MTK_PMIC_REG_WIDTH;120 en_reg = irqd->pmic_ints[top_gp].en_reg +121 (irqd->pmic_ints[top_gp].en_reg_shift * int_regs);122 123 regmap_update_bits(chip->regmap, en_reg, BIT(shift),124 irqd->enable_hwirq[i] << shift);125 126 irqd->cache_hwirq[i] = irqd->enable_hwirq[i];127 }128 mutex_unlock(&chip->irqlock);129}130 131static struct irq_chip mt6358_irq_chip = {132 .name = "mt6358-irq",133 .flags = IRQCHIP_SKIP_SET_WAKE,134 .irq_enable = pmic_irq_enable,135 .irq_disable = pmic_irq_disable,136 .irq_bus_lock = pmic_irq_lock,137 .irq_bus_sync_unlock = pmic_irq_sync_unlock,138};139 140static void mt6358_irq_sp_handler(struct mt6397_chip *chip,141 unsigned int top_gp)142{143 unsigned int irq_status, sta_reg, status;144 unsigned int hwirq, virq;145 int i, j, ret;146 struct pmic_irq_data *irqd = chip->irq_data;147 148 for (i = 0; i < irqd->pmic_ints[top_gp].num_int_regs; i++) {149 sta_reg = irqd->pmic_ints[top_gp].sta_reg +150 irqd->pmic_ints[top_gp].sta_reg_shift * i;151 152 ret = regmap_read(chip->regmap, sta_reg, &irq_status);153 if (ret) {154 dev_err(chip->dev,155 "Failed to read IRQ status, ret=%d\n", ret);156 return;157 }158 159 if (!irq_status)160 continue;161 162 status = irq_status;163 do {164 j = __ffs(status);165 166 hwirq = irqd->pmic_ints[top_gp].hwirq_base +167 MTK_PMIC_REG_WIDTH * i + j;168 169 virq = irq_find_mapping(chip->irq_domain, hwirq);170 if (virq)171 handle_nested_irq(virq);172 173 status &= ~BIT(j);174 } while (status);175 176 regmap_write(chip->regmap, sta_reg, irq_status);177 }178}179 180static irqreturn_t mt6358_irq_handler(int irq, void *data)181{182 struct mt6397_chip *chip = data;183 struct pmic_irq_data *irqd = chip->irq_data;184 unsigned int bit, i, top_irq_status = 0;185 int ret;186 187 ret = regmap_read(chip->regmap,188 irqd->top_int_status_reg,189 &top_irq_status);190 if (ret) {191 dev_err(chip->dev,192 "Failed to read status from the device, ret=%d\n", ret);193 return IRQ_NONE;194 }195 196 for (i = 0; i < irqd->num_top; i++) {197 bit = BIT(irqd->pmic_ints[i].top_offset);198 if (top_irq_status & bit) {199 mt6358_irq_sp_handler(chip, i);200 top_irq_status &= ~bit;201 if (!top_irq_status)202 break;203 }204 }205 206 return IRQ_HANDLED;207}208 209static int pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,210 irq_hw_number_t hw)211{212 struct mt6397_chip *mt6397 = d->host_data;213 214 irq_set_chip_data(irq, mt6397);215 irq_set_chip_and_handler(irq, &mt6358_irq_chip, handle_level_irq);216 irq_set_nested_thread(irq, 1);217 irq_set_noprobe(irq);218 219 return 0;220}221 222static const struct irq_domain_ops mt6358_irq_domain_ops = {223 .map = pmic_irq_domain_map,224 .xlate = irq_domain_xlate_twocell,225};226 227int mt6358_irq_init(struct mt6397_chip *chip)228{229 int i, j, ret;230 struct pmic_irq_data *irqd;231 232 switch (chip->chip_id) {233 case MT6357_CHIP_ID:234 chip->irq_data = &mt6357_irqd;235 break;236 237 case MT6358_CHIP_ID:238 case MT6366_CHIP_ID:239 chip->irq_data = &mt6358_irqd;240 break;241 242 case MT6359_CHIP_ID:243 chip->irq_data = &mt6359_irqd;244 break;245 246 default:247 dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);248 return -ENODEV;249 }250 251 mutex_init(&chip->irqlock);252 irqd = chip->irq_data;253 irqd->enable_hwirq = devm_kcalloc(chip->dev,254 irqd->num_pmic_irqs,255 sizeof(*irqd->enable_hwirq),256 GFP_KERNEL);257 if (!irqd->enable_hwirq)258 return -ENOMEM;259 260 irqd->cache_hwirq = devm_kcalloc(chip->dev,261 irqd->num_pmic_irqs,262 sizeof(*irqd->cache_hwirq),263 GFP_KERNEL);264 if (!irqd->cache_hwirq)265 return -ENOMEM;266 267 /* Disable all interrupts for initializing */268 for (i = 0; i < irqd->num_top; i++) {269 for (j = 0; j < irqd->pmic_ints[i].num_int_regs; j++)270 regmap_write(chip->regmap,271 irqd->pmic_ints[i].en_reg +272 irqd->pmic_ints[i].en_reg_shift * j, 0);273 }274 275 chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,276 irqd->num_pmic_irqs,277 &mt6358_irq_domain_ops, chip);278 if (!chip->irq_domain) {279 dev_err(chip->dev, "Could not create IRQ domain\n");280 return -ENODEV;281 }282 283 ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,284 mt6358_irq_handler, IRQF_ONESHOT,285 mt6358_irq_chip.name, chip);286 if (ret) {287 dev_err(chip->dev, "Failed to register IRQ=%d, ret=%d\n",288 chip->irq, ret);289 return ret;290 }291 292 enable_irq_wake(chip->irq);293 return ret;294}295