[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