static void pm8058_irq_unmask(unsigned int irq) { int master, irq_bit; struct pm8058_chip *chip = get_irq_data(irq); u8 block, config, old_irqs_allowed, old_blocks_allowed; irq -= chip->pdata.irq_base; block = irq / 8; master = block / 8; irq_bit = irq % 8; old_irqs_allowed = chip->irqs_allowed[block]; chip->irqs_allowed[block] |= 1 << irq_bit; if (!old_irqs_allowed) { master = block / 8; old_blocks_allowed = chip->blocks_allowed[master]; chip->blocks_allowed[master] |= 1 << (block % 8); if (!old_blocks_allowed) chip->masters_allowed |= 1 << master; } config = PM8058_IRQF_WRITE | chip->config[irq]; pm8058_config_irq(chip, &block, &config); }
static void pm8058_irq_ack(unsigned int irq) { struct pm8058_chip *chip = get_irq_data(irq); u8 block, config; irq -= chip->pdata.irq_base; block = irq / 8; config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_CLR; pm8058_config_irq(chip, &block, &config); }
static void pm8058_irq_bus_sync_unlock(unsigned int irq) { u8 block, config; struct pm8058_chip *chip = get_irq_data(irq); irq -= chip->pdata.irq_base; block = irq / 8; config = chip->bus_unlock_config[irq]; /* dont waste cpu cycles if we dont have data to write */ if (config) pm8058_config_irq(chip, &block, &config); mutex_unlock(&chip->pm_lock); }
static void pm8058_irq_ack(unsigned int irq) { struct pm8058_chip *chip = get_irq_data(irq); u8 block, config; irq -= chip->pdata.irq_base; block = irq / 8; config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_CLR; /* Keep the mask */ if (!(chip->irqs_allowed[block] & (1 << (irq % 8)))) config |= PM8058_IRQF_MASK_FE | PM8058_IRQF_MASK_RE; pm8058_config_irq(chip, &block, &config); }
static void pm8058_irq_mask(unsigned int irq) { int master, irq_bit; struct pm8058_chip *chip = get_irq_data(irq); u8 block, config; irq -= chip->pdata.irq_base; block = irq / 8; master = block / 8; irq_bit = irq % 8; chip->irqs_allowed[block] &= ~(1 << irq_bit); if (!chip->irqs_allowed[block]) { chip->blocks_allowed[master] &= ~(1 << (block % 8)); if (!chip->blocks_allowed[master]) chip->masters_allowed &= ~(1 << master); } config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_MASK_FE | PM8058_IRQF_MASK_RE; pm8058_config_irq(chip, &block, &config); }
static int pm8058_irq_set_type(unsigned int irq, unsigned int flow_type) { int master, irq_bit; struct pm8058_chip *chip = get_irq_data(irq); u8 block, config; irq -= chip->pdata.irq_base; if (irq > chip->pm_max_irq) { chip->pm_max_irq = irq; chip->pm_max_blocks = chip->pm_max_irq / 8 + 1; chip->pm_max_masters = chip->pm_max_blocks / 8 + 1; } block = irq / 8; master = block / 8; irq_bit = irq % 8; chip->config[irq] = (irq_bit << PM8058_IRQF_BITS_SHIFT) | PM8058_IRQF_MASK_RE | PM8058_IRQF_MASK_FE; if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { if (flow_type & IRQF_TRIGGER_RISING) chip->config[irq] &= ~PM8058_IRQF_MASK_RE; if (flow_type & IRQF_TRIGGER_FALLING) chip->config[irq] &= ~PM8058_IRQF_MASK_FE; } else { chip->config[irq] |= PM8058_IRQF_LVL_SEL; if (flow_type & IRQF_TRIGGER_HIGH) chip->config[irq] &= ~PM8058_IRQF_MASK_RE; else chip->config[irq] &= ~PM8058_IRQF_MASK_FE; } config = PM8058_IRQF_WRITE | chip->config[irq] | PM8058_IRQF_CLR; return pm8058_config_irq(chip, &block, &config); }
static irqreturn_t pm8058_isr_thread(int irq_requested, void *data) { struct pm8058_chip *chip = data; int i, j, k; u8 root, block, config, bits; u8 blocks[MAX_PM_MASTERS]; int masters = 0, irq, handled = 0, spurious = 0; u16 irqs_to_handle[MAX_PM_IRQ]; mutex_lock(&chip->pm_lock); /* Read root for masters */ if (pm8058_read_root(chip, &root)) goto bail_out; masters = root >> 1; if (!(masters & chip->masters_allowed) || (masters & ~chip->masters_allowed)) { spurious = 1000000; } /* Read allowed masters for blocks. */ for (i = 0; i < chip->pm_max_masters; i++) { if (masters & (1 << i)) { if (pm8058_read_master(chip, i, &blocks[i])) goto bail_out; if (!blocks[i]) { if (pm8058_can_print()) pr_err("%s: Spurious master: %d " "(blocks=0)", __func__, i); spurious += 10000; } } else blocks[i] = 0; } /* Select block, read status and call isr */ for (i = 0; i < chip->pm_max_masters; i++) { if (!blocks[i]) continue; for (j = 0; j < 8; j++) { if (!(blocks[i] & (1 << j))) continue; block = i * 8 + j; /* block # */ if (pm8058_read_block(chip, &block, &bits)) goto bail_out; if (!bits) { if (pm8058_can_print()) pr_err("%s: Spurious block: " "[master, block]=[%d, %d] " "(bits=0)\n", __func__, i, j); spurious += 100; continue; } /* Check IRQ bits */ for (k = 0; k < 8; k++) { if (!(bits & (1 << k))) continue; /* Check spurious interrupts */ if (((1 << i) & chip->masters_allowed) && (blocks[i] & chip->blocks_allowed[i]) && (bits & chip->irqs_allowed[block])) { /* Found one */ irq = block * 8 + k; irqs_to_handle[handled] = irq + chip->pdata.irq_base; handled++; } else { /* Clear and mask wrong one */ config = PM8058_IRQF_W_C_M | (k << PM8058_IRQF_BITS_SHIFT); pm8058_config_irq(chip, &block, &config); if (pm8058_can_print()) pr_err("%s: Spurious IRQ: " "[master, block, bit]=" "[%d, %d (%d), %d]\n", __func__, i, j, block, k); spurious++; } } } } bail_out: mutex_unlock(&chip->pm_lock); for (i = 0; i < handled; i++) handle_nested_irq(irqs_to_handle[i]); for (i = 0; i < handled; i++) { irqs_to_handle[i] -= chip->pdata.irq_base; block = irqs_to_handle[i] / 8 ; config = PM8058_IRQF_WRITE | chip->config[irqs_to_handle[i]] | PM8058_IRQF_CLR; pm8058_config_irq(chip, &block, &config); } if (spurious) { if (!pm8058_can_print()) return IRQ_HANDLED; pr_err("%s: spurious = %d (handled = %d)\n", __func__, spurious, handled); pr_err(" root = 0x%x (masters_allowed<<1 = 0x%x)\n", root, chip->masters_allowed << 1); for (i = 0; i < chip->pm_max_masters; i++) { if (masters & (1 << i)) pr_err(" blocks[%d]=0x%x, " "allowed[%d]=0x%x\n", i, blocks[i], i, chip->blocks_allowed[i]); } } return IRQ_HANDLED; }
static irqreturn_t pm8058_isr_thread(int irq_requested, void *data) { struct pm8058_chip *chip = data; int i, j, k; u8 root, block, config, bits; u8 blocks[MAX_PM_MASTERS]; int masters = 0, irq, handled = 0, spurious = 0; u16 irqs_to_handle[MAX_PM_IRQ]; unsigned long irqsave; spin_lock_irqsave(&chip->pm_lock, irqsave); if (pm8058_read_root(chip, &root)) goto bail_out; masters = root >> 1; if (!(masters & chip->masters_allowed) || (masters & ~chip->masters_allowed)) { spurious = 1000000; } for (i = 0; i < chip->pm_max_masters; i++) { if (masters & (1 << i)) { if (pm8058_read_master(chip, i, &blocks[i])) goto bail_out; if (!blocks[i]) { if (pm8058_can_print()) pr_err("%s: Spurious master: %d " "(blocks=0)", __func__, i); spurious += 10000; } } else blocks[i] = 0; } for (i = 0; i < chip->pm_max_masters; i++) { if (!blocks[i]) continue; for (j = 0; j < 8; j++) { if (!(blocks[i] & (1 << j))) continue; block = i * 8 + j; if (pm8058_read_block(chip, &block, &bits)) goto bail_out; if (!bits) { if (pm8058_can_print()) pr_err("%s: Spurious block: " "[master, block]=[%d, %d] " "(bits=0)\n", __func__, i, j); spurious += 100; continue; } for (k = 0; k < 8; k++) { if (!(bits & (1 << k))) continue; if (((1 << i) & chip->masters_allowed) && (blocks[i] & chip->blocks_allowed[i]) && (bits & chip->irqs_allowed[block])) { irq = block * 8 + k; irqs_to_handle[handled] = irq + chip->pdata.irq_base; handled++; } else { config = PM8058_IRQF_W_C_M | (k < PM8058_IRQF_BITS_SHIFT); pm8058_config_irq(chip, &block, &config); if (pm8058_can_print()) pr_err("%s: Spurious IRQ: " "[master, block, bit]=" "[%d, %d (%d), %d]\n", __func__, i, j, block, k); spurious++; } } } } bail_out: spin_unlock_irqrestore(&chip->pm_lock, irqsave); for (i = 0; i < handled; i++) generic_handle_irq(irqs_to_handle[i]); if (spurious) { if (!pm8058_can_print()) return IRQ_HANDLED; pr_err("%s: spurious = %d (handled = %d)\n", __func__, spurious, handled); pr_err(" root = 0x%x (masters_allowed<<1 = 0x%x)\n", root, chip->masters_allowed << 1); for (i = 0; i < chip->pm_max_masters; i++) { if (masters & (1 << i)) pr_err(" blocks[%d]=0x%x, " "allowed[%d]=0x%x\n", i, blocks[i], i, chip->blocks_allowed[i]); } } return IRQ_HANDLED; }