@@ -98,6 +98,11 @@ enum pmic_arb_cmd_op_code {
struct pmic_arb_ver_ops;
+struct apid_data {
+ u16 ppid;
+ u8 owner;
+};
+
/**
* spmi_pmic_arb - SPMI PMIC Arbiter object
*
@@ -115,7 +120,6 @@ enum pmic_arb_cmd_op_code {
* @mapping_table: in-memory copy of PPID -> APID mapping table.
* @domain: irq domain object for PMIC IRQ domain
* @spmic: SPMI controller object
- * @apid_to_ppid: in-memory copy of APID -> PPID mapping table.
* @ver_ops: version dependent operations.
* @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping table.
* v2 only.
@@ -138,11 +142,10 @@ struct spmi_pmic_arb {
DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
struct irq_domain *domain;
struct spmi_controller *spmic;
- u16 *apid_to_ppid;
const struct pmic_arb_ver_ops *ver_ops;
u16 *ppid_to_apid;
u16 last_apid;
- u8 *apid_to_owner;
+ struct apid_data apid_data[PMIC_ARB_MAX_PERIPHS];
};
/**
@@ -482,6 +485,28 @@ static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
d->irq);
}
+static void cleanup_irq(struct spmi_pmic_arb *pa, u8 apid, int id)
+{
+ u16 ppid = pa->apid_data[apid].ppid;
+ u8 sid = ppid >> 8;
+ u8 per = ppid & 0xFF;
+ u8 irq_mask = BIT(id);
+
+ writel_relaxed(irq_mask, pa->intr + pa->ver_ops->irq_clear(apid));
+
+ if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+ (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1))
+ dev_err_ratelimited(&pa->spmic->dev,
+ "failed to ack irq_mask = 0x%x for ppid = %x\n",
+ irq_mask, ppid);
+
+ if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+ (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1))
+ dev_err_ratelimited(&pa->spmic->dev,
+ "failed to ack irq_mask = 0x%x for ppid = %x\n",
+ irq_mask, ppid);
+}
+
static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
{
unsigned int irq;
@@ -493,9 +518,13 @@ static void periph_interrupt(struct spmi_pmic_arb *pa, u8 apid)
id = ffs(status) - 1;
status &= ~BIT(id);
irq = irq_find_mapping(pa->domain,
- pa->apid_to_ppid[apid] << 16
+ pa->apid_data[apid].ppid << 16
| id << 8
| apid);
+ if (irq == 0) {
+ cleanup_irq(pa, apid, id);
+ continue;
+ }
generic_handle_irq(irq);
}
}
@@ -530,12 +559,9 @@ static void qpnpint_irq_ack(struct irq_data *d)
struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
u8 irq = d->hwirq >> 8;
u8 apid = d->hwirq;
- unsigned long flags;
u8 data;
- raw_spin_lock_irqsave(&pa->lock, flags);
writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid));
- raw_spin_unlock_irqrestore(&pa->lock, flags);
data = BIT(irq);
qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
@@ -543,23 +569,9 @@ static void qpnpint_irq_ack(struct irq_data *d)
static void qpnpint_irq_mask(struct irq_data *d)
{
- struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
u8 irq = d->hwirq >> 8;
- u8 apid = d->hwirq;
- unsigned long flags;
- u32 status;
- u8 data;
+ u8 data = BIT(irq);
- raw_spin_lock_irqsave(&pa->lock, flags);
- status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid));
- if (status & SPMI_PIC_ACC_ENABLE_BIT) {
- status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
- writel_relaxed(status, pa->intr +
- pa->ver_ops->acc_enable(apid));
- }
- raw_spin_unlock_irqrestore(&pa->lock, flags);
-
- data = BIT(irq);
qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
}
@@ -568,20 +580,12 @@ static void qpnpint_irq_unmask(struct irq_data *d)
struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d);
u8 irq = d->hwirq >> 8;
u8 apid = d->hwirq;
- unsigned long flags;
- u32 status;
- u8 data;
+ u8 data = BIT(irq);
- raw_spin_lock_irqsave(&pa->lock, flags);
- status = readl_relaxed(pa->intr + pa->ver_ops->acc_enable(apid));
- if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
- writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT,
- pa->intr + pa->ver_ops->acc_enable(apid));
- }
- raw_spin_unlock_irqrestore(&pa->lock, flags);
+ writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
+ pa->intr + pa->ver_ops->acc_enable(apid));
- data = BIT(irq);
- qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
+ qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
}
static void qpnpint_irq_enable(struct irq_data *d)
@@ -755,7 +759,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
pa->ppid_to_apid[ppid]
= *apid | PMIC_ARB_CHAN_VALID;
- pa->apid_to_ppid[*apid] = ppid;
+ pa->apid_data[*apid].ppid = ppid;
return 0;
}
} else {
@@ -765,7 +769,7 @@ static int qpnpint_irq_domain_map(struct irq_domain *d,
*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
pa->ppid_to_apid[ppid]
= *apid | PMIC_ARB_CHAN_VALID;
- pa->apid_to_ppid[*apid] = ppid;
+ pa->apid_data[*apid].ppid = ppid;
return 0;
}
}
@@ -802,7 +806,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
regval = readl_relaxed(pa->cnfg +
SPMI_OWNERSHIP_TABLE_REG(apid));
- pa->apid_to_owner[apid] = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
+ pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
offset = PMIC_ARB_REG_CHNL(apid);
if (offset >= pa->core_size)
@@ -814,7 +818,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
id = (regval >> 8) & PMIC_ARB_PPID_MASK;
pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID;
- pa->apid_to_ppid[apid] = id;
+ pa->apid_data[apid].ppid = id;
if (id == ppid) {
apid |= PMIC_ARB_CHAN_VALID;
break;
@@ -846,7 +850,6 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode)
{
u8 apid;
- u8 owner;
int rc;
rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid);
@@ -856,8 +859,7 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
*mode = 0;
*mode |= S_IRUSR;
- owner = pa->apid_to_owner[apid];
- if (owner == pa->ee)
+ if (pa->ee == pa->apid_data[apid].owner)
*mode |= S_IWUSR;
return 0;
}
@@ -1028,15 +1030,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
err = -ENOMEM;
goto err_put_ctrl;
}
-
- pa->apid_to_owner = devm_kcalloc(&ctrl->dev,
- pa->max_periph,
- sizeof(*pa->apid_to_owner),
- GFP_KERNEL);
- if (!pa->apid_to_owner) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
@@ -1088,14 +1081,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->ee = ee;
- pa->apid_to_ppid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
- sizeof(*pa->apid_to_ppid),
- GFP_KERNEL);
- if (!pa->apid_to_ppid) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
-
pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1,
sizeof(*pa->mapping_table), GFP_KERNEL);
if (!pa->mapping_table) {