[Letux-kernel] [PATCH 2/5] [WIP] irqchip/ingenic: Add support for TCU of JZ4730

Lubomir Rintel lkundrak at v3.sk
Fri Nov 27 04:15:41 CET 2020


Before JZ4740 the register layout was quite different. There were not
separate set/clear registers and the registers pertaining to a
particular channel were grouped together.

Signed-off-by: Lubomir Rintel <lkundrak at v3.sk>
---
 drivers/irqchip/irq-ingenic-tcu.c | 62 +++++++++++++++++++++++++++----
 1 file changed, 54 insertions(+), 8 deletions(-)

diff --git a/drivers/irqchip/irq-ingenic-tcu.c b/drivers/irqchip/irq-ingenic-tcu.c
index 4cb759ebf0346..44cf06f9cdc51 100644
--- a/drivers/irqchip/irq-ingenic-tcu.c
+++ b/drivers/irqchip/irq-ingenic-tcu.c
@@ -19,6 +19,7 @@ struct ingenic_tcu {
 	struct irq_domain *domain;
 	unsigned int nb_parent_irqs;
 	u32 parent_irqs[3];
+	bool jz4740_regs;
 };
 
 static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
@@ -29,9 +30,20 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
 	struct ingenic_tcu *tcu = gc->private;
 	uint32_t irq_reg, irq_mask;
 	unsigned int i;
+	uint32_t val;
 
-	regmap_read(tcu->map, TCU_REG_TFR, &irq_reg);
-	regmap_read(tcu->map, TCU_REG_TMR, &irq_mask);
+	if (tcu->jz4740_regs) {
+		regmap_read(tcu->map, TCU_REG_TFR, &irq_reg);
+		regmap_read(tcu->map, TCU_REG_TMR, &irq_mask);
+	} else {
+		irq_reg = 0;
+		irq_mask = 0;
+		for (i = 0; i < 3; i++) {
+			regmap_read(tcu->map, TCU_JZ4730_REG_TCSRc(i), &val);
+			irq_reg |= (val & TCU_JZ4730_TCSR_FLAG) ?  BIT(i) : 0;
+			irq_mask |= (val & TCU_JZ4730_TCSR_EN) ? 0 : BIT(i);
+		}
+	}
 
 	chained_irq_enter(irq_chip, desc);
 
@@ -49,10 +61,19 @@ static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d)
 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
 	struct ingenic_tcu *tcu = gc->private;
 	u32 mask = d->mask;
+	unsigned int i;
 
 	irq_gc_lock(gc);
-	regmap_write(tcu->map, ct->regs.ack, mask);
-	regmap_write(tcu->map, ct->regs.enable, mask);
+	if (tcu->jz4740_regs) {
+		regmap_write(tcu->map, ct->regs.ack, mask);
+		regmap_write(tcu->map, ct->regs.enable, mask);
+	} else {
+		for_each_set_bit(i, (unsigned long *)&mask, 3) {
+			regmap_update_bits(tcu->map, TCU_JZ4730_REG_TCSRc(i),
+					   TCU_JZ4730_TCSR_FLAG | TCU_JZ4730_TCSR_EN,
+					   TCU_JZ4730_TCSR_EN);
+		}
+	}
 	*ct->mask_cache |= mask;
 	irq_gc_unlock(gc);
 }
@@ -63,9 +84,17 @@ static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
 	struct ingenic_tcu *tcu = gc->private;
 	u32 mask = d->mask;
+	unsigned int i;
 
 	irq_gc_lock(gc);
-	regmap_write(tcu->map, ct->regs.disable, mask);
+	if (tcu->jz4740_regs) {
+		regmap_write(tcu->map, ct->regs.disable, mask);
+	} else {
+		for_each_set_bit(i, (unsigned long *)&mask, 3) {
+			regmap_update_bits(tcu->map, TCU_JZ4730_REG_TCSRc(i),
+					   TCU_JZ4730_TCSR_EN, 0);
+		}
+	}
 	*ct->mask_cache &= ~mask;
 	irq_gc_unlock(gc);
 }
@@ -76,10 +105,18 @@ static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
 	struct irq_chip_type *ct = irq_data_get_chip_type(d);
 	struct ingenic_tcu *tcu = gc->private;
 	u32 mask = d->mask;
+	unsigned int i;
 
 	irq_gc_lock(gc);
-	regmap_write(tcu->map, ct->regs.ack, mask);
-	regmap_write(tcu->map, ct->regs.disable, mask);
+	if (tcu->jz4740_regs) {
+		regmap_write(tcu->map, ct->regs.ack, mask);
+		regmap_write(tcu->map, ct->regs.disable, mask);
+	} else {
+		for_each_set_bit(i, (unsigned long *)&mask, 3) {
+			regmap_update_bits(tcu->map, TCU_JZ4730_REG_TCSRc(i),
+					   TCU_JZ4730_TCSR_FLAG | TCU_JZ4730_TCSR_EN, 0);
+		}
+	}
 	irq_gc_unlock(gc);
 }
 
@@ -101,6 +138,8 @@ static int __init ingenic_tcu_irq_init(struct device_node *np,
 	if (!tcu)
 		return -ENOMEM;
 
+	tcu->jz4740_regs = !of_device_is_compatible(np, "ingenic,jz4730-tcu");
+
 	tcu->map = map;
 
 	irqs = of_property_count_elems_of_size(np, "interrupts", sizeof(u32));
@@ -142,7 +181,14 @@ static int __init ingenic_tcu_irq_init(struct device_node *np,
 	ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
 
 	/* Mask all IRQs by default */
-	regmap_write(tcu->map, TCU_REG_TMSR, IRQ_MSK(32));
+	if (tcu->jz4740_regs) {
+		regmap_write(tcu->map, TCU_REG_TMSR, IRQ_MSK(32));
+	} else {
+		for (i = 0; i < 3; i++) {
+			regmap_update_bits(tcu->map, TCU_JZ4730_REG_TCSRc(i),
+					   TCU_JZ4730_TCSR_EN, 0);
+		}
+	}
 
 	/*
 	 * On JZ4740, timer 0 and timer 1 have their own interrupt line;
-- 
2.28.0



More information about the Letux-kernel mailing list