示例#1
0
static irqreturn_t pcf50633_irq(int irq, void *data)
{
    struct pcf50633 *pcf = data;
    int ret, i, j;
    u8 pcf_int[5], chgstat;

    /* Read the 5 INT regs in one transaction */
    ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
                              ARRAY_SIZE(pcf_int), pcf_int);
    if (ret != ARRAY_SIZE(pcf_int)) {
        dev_err(pcf->dev, "Error reading INT registers\n");

        /*
         * If this doesn't ACK the interrupt to the chip, we'll be
         * called once again as we're level triggered.
         */
        goto out;
    }

    /* defeat 8s death from lowsys on A5 */
    pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN,  0x04);

    /* We immediately read the usb and adapter status. We thus make sure
     * only of USBINS/USBREM IRQ handlers are called */
    if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
        chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
        if (chgstat & (0x3 << 4))
            pcf_int[0] &= ~PCF50633_INT1_USBREM;
        else
            pcf_int[0] &= ~PCF50633_INT1_USBINS;
    }

    /* Make sure only one of ADPINS or ADPREM is set */
    if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
        chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
        if (chgstat & (0x3 << 4))
            pcf_int[0] &= ~PCF50633_INT1_ADPREM;
        else
            pcf_int[0] &= ~PCF50633_INT1_ADPINS;
    }

    dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
            "INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
            pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);

    /* Some revisions of the chip don't have a 8s standby mode on
     * ONKEY1S press. We try to manually do it in such cases. */
    if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
        dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
                 pcf->onkey1s_held);
        if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
            if (pcf->pdata->force_shutdown)
                pcf->pdata->force_shutdown(pcf);
    }

    if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
        dev_info(pcf->dev, "ONKEY1S held\n");
        pcf->onkey1s_held = 1 ;

        /* Unmask IRQ_SECOND */
        pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
                                PCF50633_INT1_SECOND);

        /* Unmask IRQ_ONKEYR */
        pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
                                PCF50633_INT2_ONKEYR);
    }

    if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
        pcf->onkey1s_held = 0;

        /* Mask SECOND and ONKEYR interrupts */
        if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
            pcf50633_reg_set_bit_mask(pcf,
                                      PCF50633_REG_INT1M,
                                      PCF50633_INT1_SECOND,
                                      PCF50633_INT1_SECOND);

        if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
            pcf50633_reg_set_bit_mask(pcf,
                                      PCF50633_REG_INT2M,
                                      PCF50633_INT2_ONKEYR,
                                      PCF50633_INT2_ONKEYR);
    }

    /* Have we just resumed ? */
    if (pcf->is_suspended) {
        pcf->is_suspended = 0;

        /* Set the resume reason filtering out non resumers */
        for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
            pcf->resume_reason[i] = pcf_int[i] &
                                    pcf->pdata->resumers[i];

        /* Make sure we don't pass on any ONKEY events to
         * userspace now */
        pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
    }

    for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
        /* Unset masked interrupts */
        pcf_int[i] &= ~pcf->mask_regs[i];

        for (j = 0; j < 8 ; j++)
            if (pcf_int[i] & (1 << j))
                pcf50633_irq_call_handler(pcf, (i * 8) + j);
    }

out:
    return IRQ_HANDLED;
}
示例#2
0
int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
{
	struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
	int ret = 0;
	u8 bits;
	u8 mbcs2, chgmod;
	unsigned int mbcc5;

	if (ma >= 1000) {
		bits = PCF50633_MBCC7_USB_1000mA;
		ma = 1000;
	} else if (ma >= 500) {
		bits = PCF50633_MBCC7_USB_500mA;
		ma = 500;
	} else if (ma >= 100) {
		bits = PCF50633_MBCC7_USB_100mA;
		ma = 100;
	} else {
		bits = PCF50633_MBCC7_USB_SUSPEND;
		ma = 0;
	}

	ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
					PCF50633_MBCC7_USB_MASK, bits);
	if (ret)
		dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
	else
		dev_info(pcf->dev, "usb curlim to %d mA\n", ma);

	/*
	 * We limit the charging current to be the USB current limit.
	 * The reason is that on pcf50633, when it enters PMU Standby mode,
	 * which it does when the device goes "off", the USB current limit
	 * reverts to the variant default.  In at least one common case, that
	 * default is 500mA.  By setting the charging current to be the same
	 * as the USB limit we set here before PMU standby, we enforce it only
	 * using the correct amount of current even when the USB current limit
	 * gets reset to the wrong thing
	 */

	if (mbc->pcf->pdata->charger_reference_current_ma) {
		mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
		if (mbcc5 > 255)
			mbcc5 = 255;
		pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
	}

	mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
	chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	/* If chgmod == BATFULL, setting chgena has no effect.
	 * Datasheet says we need to set resume instead but when autoresume is
	 * used resume doesn't work. Clear and set chgena instead.
	 */
	if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	else {
		pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA);
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	}

	power_supply_changed(mbc->usb);

	return ret;
}