diff options
Diffstat (limited to 'drivers/spmi')
-rw-r--r-- | drivers/spmi/spmi-pmic-arb.c | 144 |
1 files changed, 88 insertions, 56 deletions
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 72016116d861..6320f1f0ea5a 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -164,6 +164,8 @@ struct spmi_pmic_arb { * on v2 offset of SPMI_PIC_IRQ_CLEARn. */ struct pmic_arb_ver_ops { + int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, + u8 *apid); int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, mode_t *mode); /* spmi commands (read_cmd, write_cmd, cmd) functionality */ @@ -657,42 +659,6 @@ struct spmi_pmic_arb_irq_spec { unsigned irq:3; }; -static int search_mapping_table(struct spmi_pmic_arb *pa, - struct spmi_pmic_arb_irq_spec *spec, - u8 *apid) -{ - u16 ppid = spec->slave << 8 | spec->per; - u32 *mapping_table = pa->mapping_table; - int index = 0, i; - u32 data; - - for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { - if (!test_and_set_bit(index, pa->mapping_table_valid)) - mapping_table[index] = readl_relaxed(pa->cnfg + - SPMI_MAPPING_TABLE_REG(index)); - - data = mapping_table[index]; - - if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) { - if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { - index = SPMI_MAPPING_BIT_IS_1_RESULT(data); - } else { - *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); - return 0; - } - } else { - if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { - index = SPMI_MAPPING_BIT_IS_0_RESULT(data); - } else { - *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); - return 0; - } - } - } - - return -ENODEV; -} - static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, @@ -702,7 +668,7 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, { struct spmi_pmic_arb *pa = d->host_data; struct spmi_pmic_arb_irq_spec spec; - int err; + int rc; u8 apid; dev_dbg(&pa->spmic->dev, @@ -720,11 +686,14 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, spec.per = intspec[1]; spec.irq = intspec[2]; - err = search_mapping_table(pa, &spec, &apid); - if (err) - return err; - - pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per; + rc = pa->ver_ops->ppid_to_apid(pa, intspec[0], + (intspec[1] << 8), &apid); + if (rc < 0) { + dev_err(&pa->spmic->dev, + "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n", + intspec[0], intspec[1], intspec[2], rc); + return rc; + } /* Keep track of {max,min}_apid for bounding search during interrupt */ if (apid > pa->max_apid) @@ -758,6 +727,54 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, } static int +pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid) +{ + u16 ppid = sid << 8 | ((addr >> 8) & 0xFF); + u32 *mapping_table = pa->mapping_table; + int index = 0, i; + u16 apid_valid; + u32 data; + + apid_valid = pa->ppid_to_apid[ppid]; + if (apid_valid & PMIC_ARB_CHAN_VALID) { + *apid = (apid_valid & ~PMIC_ARB_CHAN_VALID); + return 0; + } + + for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { + if (!test_and_set_bit(index, pa->mapping_table_valid)) + mapping_table[index] = readl_relaxed(pa->cnfg + + SPMI_MAPPING_TABLE_REG(index)); + + data = mapping_table[index]; + + if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) { + if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { + index = SPMI_MAPPING_BIT_IS_1_RESULT(data); + } else { + *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); + pa->ppid_to_apid[ppid] + = *apid | PMIC_ARB_CHAN_VALID; + pa->apid_to_ppid[*apid] = ppid; + return 0; + } + } else { + if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { + index = SPMI_MAPPING_BIT_IS_0_RESULT(data); + } else { + *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); + pa->ppid_to_apid[ppid] + = *apid | PMIC_ARB_CHAN_VALID; + pa->apid_to_ppid[*apid] = ppid; + return 0; + } + } + } + + return -ENODEV; +} + +static int pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) { *mode = S_IRUSR | S_IWUSR; @@ -797,6 +814,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; if (id == ppid) { apid |= PMIC_ARB_CHAN_VALID; break; @@ -809,20 +827,35 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) static int -pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) +pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid) { u16 ppid = (sid << 8) | (addr >> 8); - u16 apid; - u8 owner; + u16 apid_valid; - apid = pa->ppid_to_apid[ppid]; - if (!(apid & PMIC_ARB_CHAN_VALID)) + apid_valid = pa->ppid_to_apid[ppid]; + if (!(apid_valid & PMIC_ARB_CHAN_VALID)) + apid_valid = pmic_arb_find_apid(pa, ppid); + if (!(apid_valid & PMIC_ARB_CHAN_VALID)) return -ENODEV; + *apid = (apid_valid & ~PMIC_ARB_CHAN_VALID); + return 0; +} + +static int +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); + if (rc < 0) + return rc; + *mode = 0; *mode |= S_IRUSR; - apid &= ~PMIC_ARB_CHAN_VALID; owner = pa->apid_to_owner[apid]; if (owner == pa->ee) *mode |= S_IWUSR; @@ -833,15 +866,12 @@ pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) static int pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) { - u16 ppid = (sid << 8) | (addr >> 8); - u16 apid; + u8 apid; + int rc; - apid = pa->ppid_to_apid[ppid]; - if (!(apid & PMIC_ARB_CHAN_VALID)) - apid = pmic_arb_find_apid(pa, ppid); - if (!(apid & PMIC_ARB_CHAN_VALID)) - return -ENODEV; - apid &= ~PMIC_ARB_CHAN_VALID; + rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid); + if (rc < 0) + return rc; *offset = 0x1000 * pa->ee + 0x8000 * apid; return 0; @@ -898,6 +928,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n) } static const struct pmic_arb_ver_ops pmic_arb_v1 = { + .ppid_to_apid = pmic_arb_ppid_to_apid_v1, .mode = pmic_arb_mode_v1, .non_data_cmd = pmic_arb_non_data_cmd_v1, .offset = pmic_arb_offset_v1, @@ -909,6 +940,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = { }; static const struct pmic_arb_ver_ops pmic_arb_v2 = { + .ppid_to_apid = pmic_arb_ppid_to_apid_v2, .mode = pmic_arb_mode_v2, .non_data_cmd = pmic_arb_non_data_cmd_v2, .offset = pmic_arb_offset_v2, |