Пример #1
0
int pcf50633_irq_suspend(struct pcf50633 *pcf)
{
    int ret;
    int i;
    u8 res[5];

    /* Make sure our interrupt handlers are not called
     * henceforth */
    disable_irq(pcf->irq);

    /* Save the masks */
    ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
                              ARRAY_SIZE(pcf->suspend_irq_masks),
                              pcf->suspend_irq_masks);
    if (ret < 0) {
        dev_err(pcf->dev, "error saving irq masks\n");
        goto out;
    }

    /* Write wakeup irq masks */
    for (i = 0; i < ARRAY_SIZE(res); i++)
        res[i] = ~pcf->pdata->resumers[i];

    ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
                               ARRAY_SIZE(res), &res[0]);
    if (ret < 0) {
        dev_err(pcf->dev, "error writing wakeup irq masks\n");
        goto out;
    }

    pcf->is_suspended = 1;

out:
    return ret;
}
Пример #2
0
static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct pcf50633_rtc *rtc;
	struct pcf50633_time pcf_tm;
	int ret;

	rtc = dev_get_drvdata(dev);

	ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
					    PCF50633_TI_EXTENT,
					    &pcf_tm.time[0]);
	if (ret != PCF50633_TI_EXTENT) {
		dev_err(dev, "Failed to read time\n");
		return -EIO;
	}

	dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
		pcf_tm.time[PCF50633_TI_DAY],
		pcf_tm.time[PCF50633_TI_MONTH],
		pcf_tm.time[PCF50633_TI_YEAR],
		pcf_tm.time[PCF50633_TI_HOUR],
		pcf_tm.time[PCF50633_TI_MIN],
		pcf_tm.time[PCF50633_TI_SEC]);

	pcf2rtc_time(tm, &pcf_tm);

	dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n",
		tm->tm_mday, tm->tm_mon, tm->tm_year,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	return rtc_valid_tm(tm);
}
static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct pcf50633_rtc *rtc;
	struct pcf50633_time pcf_tm;
	int ret = 0;

	rtc = dev_get_drvdata(dev);

	alrm->enabled = rtc->alarm_enabled;

	ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
				PCF50633_TI_EXTENT, &pcf_tm.time[0]);
	if (ret != PCF50633_TI_EXTENT) {
		dev_err(dev, "Failed to read time\n");
		return -EIO;
	}

	pcf2rtc_time(&alrm->time, &pcf_tm);

	return rtc_valid_tm(&alrm->time);
}
Пример #4
0
static int pcf50633_suspend(struct device *dev, pm_message_t state)
{
	struct pcf50633 *pcf;
	int ret = 0, i;
	u8 res[5];

	pcf = dev_get_drvdata(dev);

	/* Make sure our interrupt handlers are not called
	 * henceforth */
	disable_irq(pcf->irq);

	/* Make sure that any running IRQ worker has quit */
	cancel_work_sync(&pcf->irq_work);

	/* Save the masks */
	ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
				ARRAY_SIZE(pcf->suspend_irq_masks),
					pcf->suspend_irq_masks);
	if (ret < 0) {
		dev_err(pcf->dev, "error saving irq masks\n");
		goto out;
	}

	/* Write wakeup irq masks */
	for (i = 0; i < ARRAY_SIZE(res); i++)
		res[i] = ~pcf->pdata->resumers[i];

	ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
					ARRAY_SIZE(res), &res[0]);
	if (ret < 0) {
		dev_err(pcf->dev, "error writing wakeup irq masks\n");
		goto out;
	}

	pcf->is_suspended = 1;

out:
	return ret;
}
Пример #5
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;
}