brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 886745b Raw
217 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Copyright (c) 2019 MediaTek Inc.4 5#include <linux/interrupt.h>6#include <linux/irq.h>7#include <linux/irqdomain.h>8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/regmap.h>11#include <linux/suspend.h>12#include <linux/mfd/mt6323/core.h>13#include <linux/mfd/mt6323/registers.h>14#include <linux/mfd/mt6331/core.h>15#include <linux/mfd/mt6331/registers.h>16#include <linux/mfd/mt6397/core.h>17#include <linux/mfd/mt6397/registers.h>18 19static void mt6397_irq_lock(struct irq_data *data)20{21	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);22 23	mutex_lock(&mt6397->irqlock);24}25 26static void mt6397_irq_sync_unlock(struct irq_data *data)27{28	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);29 30	regmap_write(mt6397->regmap, mt6397->int_con[0],31		     mt6397->irq_masks_cur[0]);32	regmap_write(mt6397->regmap, mt6397->int_con[1],33		     mt6397->irq_masks_cur[1]);34 35	mutex_unlock(&mt6397->irqlock);36}37 38static void mt6397_irq_disable(struct irq_data *data)39{40	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);41	int shift = data->hwirq & 0xf;42	int reg = data->hwirq >> 4;43 44	mt6397->irq_masks_cur[reg] &= ~BIT(shift);45}46 47static void mt6397_irq_enable(struct irq_data *data)48{49	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);50	int shift = data->hwirq & 0xf;51	int reg = data->hwirq >> 4;52 53	mt6397->irq_masks_cur[reg] |= BIT(shift);54}55 56static int mt6397_irq_set_wake(struct irq_data *irq_data, unsigned int on)57{58	struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(irq_data);59	int shift = irq_data->hwirq & 0xf;60	int reg = irq_data->hwirq >> 4;61 62	if (on)63		mt6397->wake_mask[reg] |= BIT(shift);64	else65		mt6397->wake_mask[reg] &= ~BIT(shift);66 67	return 0;68}69 70static struct irq_chip mt6397_irq_chip = {71	.name = "mt6397-irq",72	.irq_bus_lock = mt6397_irq_lock,73	.irq_bus_sync_unlock = mt6397_irq_sync_unlock,74	.irq_enable = mt6397_irq_enable,75	.irq_disable = mt6397_irq_disable,76	.irq_set_wake = pm_sleep_ptr(mt6397_irq_set_wake),77};78 79static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,80				  int irqbase)81{82	unsigned int status = 0;83	int i, irq, ret;84 85	ret = regmap_read(mt6397->regmap, reg, &status);86	if (ret) {87		dev_err(mt6397->dev, "Failed to read irq status: %d\n", ret);88		return;89	}90 91	for (i = 0; i < 16; i++) {92		if (status & BIT(i)) {93			irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);94			if (irq)95				handle_nested_irq(irq);96		}97	}98 99	regmap_write(mt6397->regmap, reg, status);100}101 102static irqreturn_t mt6397_irq_thread(int irq, void *data)103{104	struct mt6397_chip *mt6397 = data;105 106	mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0);107	mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16);108 109	return IRQ_HANDLED;110}111 112static int mt6397_irq_domain_map(struct irq_domain *d, unsigned int irq,113				 irq_hw_number_t hw)114{115	struct mt6397_chip *mt6397 = d->host_data;116 117	irq_set_chip_data(irq, mt6397);118	irq_set_chip_and_handler(irq, &mt6397_irq_chip, handle_level_irq);119	irq_set_nested_thread(irq, 1);120	irq_set_noprobe(irq);121 122	return 0;123}124 125static const struct irq_domain_ops mt6397_irq_domain_ops = {126	.map = mt6397_irq_domain_map,127};128 129static int mt6397_irq_pm_notifier(struct notifier_block *notifier,130				  unsigned long pm_event, void *unused)131{132	struct mt6397_chip *chip =133		container_of(notifier, struct mt6397_chip, pm_nb);134 135	switch (pm_event) {136	case PM_SUSPEND_PREPARE:137		regmap_write(chip->regmap,138			     chip->int_con[0], chip->wake_mask[0]);139		regmap_write(chip->regmap,140			     chip->int_con[1], chip->wake_mask[1]);141		enable_irq_wake(chip->irq);142		break;143 144	case PM_POST_SUSPEND:145		regmap_write(chip->regmap,146			     chip->int_con[0], chip->irq_masks_cur[0]);147		regmap_write(chip->regmap,148			     chip->int_con[1], chip->irq_masks_cur[1]);149		disable_irq_wake(chip->irq);150		break;151 152	default:153		break;154	}155 156	return NOTIFY_DONE;157}158 159int mt6397_irq_init(struct mt6397_chip *chip)160{161	int ret;162 163	mutex_init(&chip->irqlock);164 165	switch (chip->chip_id) {166	case MT6323_CHIP_ID:167		chip->int_con[0] = MT6323_INT_CON0;168		chip->int_con[1] = MT6323_INT_CON1;169		chip->int_status[0] = MT6323_INT_STATUS0;170		chip->int_status[1] = MT6323_INT_STATUS1;171		break;172	case MT6331_CHIP_ID:173		chip->int_con[0] = MT6331_INT_CON0;174		chip->int_con[1] = MT6331_INT_CON1;175		chip->int_status[0] = MT6331_INT_STATUS_CON0;176		chip->int_status[1] = MT6331_INT_STATUS_CON1;177		break;178	case MT6391_CHIP_ID:179	case MT6397_CHIP_ID:180		chip->int_con[0] = MT6397_INT_CON0;181		chip->int_con[1] = MT6397_INT_CON1;182		chip->int_status[0] = MT6397_INT_STATUS0;183		chip->int_status[1] = MT6397_INT_STATUS1;184		break;185 186	default:187		dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);188		return -ENODEV;189	}190 191	/* Mask all interrupt sources */192	regmap_write(chip->regmap, chip->int_con[0], 0x0);193	regmap_write(chip->regmap, chip->int_con[1], 0x0);194 195	chip->pm_nb.notifier_call = mt6397_irq_pm_notifier;196	chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,197						 MT6397_IRQ_NR,198						 &mt6397_irq_domain_ops,199						 chip);200	if (!chip->irq_domain) {201		dev_err(chip->dev, "could not create irq domain\n");202		return -ENOMEM;203	}204 205	ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,206					mt6397_irq_thread, IRQF_ONESHOT,207					"mt6397-pmic", chip);208	if (ret) {209		dev_err(chip->dev, "failed to register irq=%d; err: %d\n",210			chip->irq, ret);211		return ret;212	}213 214	register_pm_notifier(&chip->pm_nb);215	return 0;216}217