コード例 #1
0
ファイル: rtc-imxdi.c プロジェクト: despierto/imx_233_linux
/*
 * Write a dryice register and wait until it completes.
 *
 * This function uses interrupts to determine when the
 * write has completed.
 */
static int di_write_wait(struct rtc_drv_data *pdata, u32 val, int reg)
{
	int ret;
	int rc = 0;

	/* serialize register writes */
	mutex_lock(&pdata->write_mutex);

	/* enable the write-complete interrupt */
	di_int_enable(pdata, DIER_WCIE);

	pdata->dsr = 0;

	/* do the register write */
	di_write(pdata, val, reg);

	/* wait for the write to finish */
	ret = wait_event_interruptible_timeout(pdata->write_wait,
					       pdata->dsr & (DSR_WCF | DSR_WEF),
					       1 * HZ);
	if (ret == 0)
		dev_warn(&pdata->pdev->dev, "Write-wait timeout\n");

	/* check for write error */
	if (pdata->dsr & DSR_WEF) {
		clear_write_error(pdata);
		rc = -EIO;
	}
	mutex_unlock(&pdata->write_mutex);
	return rc;
}
コード例 #2
0
/*
 * write a dryice register and loop, waiting for it
 * to complete. use only during driver initialization.
 * returns 0 on success or 1 on write failure.
 */
static int di_write_loop(uint32_t val, int reg)
{
	int rc = 0;
	int cnt;

	di_debug("FUNC: %s\n", __func__);
	di_write(val, reg);

	for (cnt = 0; cnt < DI_WRITE_LOOP_CNT; cnt++) {
		uint32_t dsr = di_read(DSR);
		if (dsr & DSR_WEF) {
			try_to_clear_wef();
			rc = 1;
		}
		if (dsr & DSR_WCF)
			break;
	}
	di_debug("wait_write_loop looped %d times\n", cnt);
	if (cnt == DI_WRITE_LOOP_CNT)
		rc = 1;

	if (rc)
		di_warn("DryIce wait_write_done: WRITE ERROR!\n");
	return rc;
}
コード例 #3
0
ファイル: rtc-imxdi.c プロジェクト: despierto/imx_233_linux
/*
 * disable a dryice interrupt
 */
static inline void di_int_disable(struct rtc_drv_data *pdata, u32 intr)
{
	unsigned long flags;

	spin_lock_irqsave(&pdata->irq_lock, flags);
	di_write(pdata, di_read(pdata, DIER) & ~intr, DIER);
	spin_unlock_irqrestore(&pdata->irq_lock, flags);
}
コード例 #4
0
/*
 * the write-error flag is something that shouldn't get set
 * during normal operation.  if it's set something is terribly
 * wrong.  the best we can do is try to clear the bit and hope
 * that dryice will recover.  this situation is similar to an
 * unexpected bus fault in terms of severity.
 */
static void try_to_clear_wef(void)
{
	int cnt;

	while (1) {
		di_write(DSR_WEF, DSR);
		for (cnt = 0; cnt < DI_WRITE_LOOP_CNT; cnt++) {
			if ((di_read(DSR) & DSR_WEF) == 0)
				break;
		}
		di_warn("WARNING: DryIce cannot clear DSR_WEF "
			"(Write Error Flag)!\n");
	}
}
コード例 #5
0
ファイル: rtc-imxdi.c プロジェクト: despierto/imx_233_linux
/*
 * This function attempts to clear the dryice write-error flag.
 *
 * A dryice write error is similar to a bus fault and should not occur in
 * normal operation.  Clearing the flag requires another write, so the root
 * cause of the problem may need to be fixed before the flag can be cleared.
 */
static void clear_write_error(struct rtc_drv_data *pdata)
{
	int cnt;

	dev_warn(&pdata->pdev->dev, "WARNING: Register write error!\n");

	for (;;) {
		/* clear the write error flag */
		di_write(pdata, DSR_WEF, DSR);

		/* wait for it to take effect */
		for (cnt = 0; cnt < 100; cnt++) {
			if ((di_read(pdata, DSR) & DSR_WEF) == 0)
				return;
			udelay(10);
		}
		dev_err(&pdata->pdev->dev,
			"ERROR: Cannot clear write-error flag!\n");
	}
}
コード例 #6
0
void todo_cur(void)
{
	di_debug("FUNC: %s[%d]\n", __func__, todo.cur);
	switch (TC.action) {
	case TODO_ACT_WRITE_VAL:
		di_debug("  TODO_ACT_WRITE_VAL\n");
		/* enable the write-completion interrupt */
		todo.status = TODO_ST_PEND_WCF;
		di_write(di_read(DIER) | DIER_WCIE, DIER);

		di_write(TC.src, TC.dst);
		break;

	case TODO_ACT_WRITE_PTR32:
		di_debug("  TODO_ACT_WRITE_PTR32\n");
		/* enable the write-completion interrupt */
		todo.status = TODO_ST_PEND_WCF;
		di_write(di_read(DIER) | DIER_WCIE, DIER);

		di_write(*(uint32_t *)TC.src, TC.dst);
		break;

	case TODO_ACT_WRITE_PTR:
		{
			uint8_t *p = (uint8_t *)TC.src;
			uint32_t val = 0;
			int num = TC.num;

			di_debug("  TODO_ACT_WRITE_PTR\n");
			while (num--)
				val = (val << 8) | *p++;

			/* enable the write-completion interrupt */
			todo.status = TODO_ST_PEND_WCF;
			di_write(di_read(DIER) | DIER_WCIE, DIER);

			di_write(val, TC.dst);
		}
		break;

	case TODO_ACT_ASSIGN:
		di_debug("  TODO_ACT_ASSIGN\n");
		switch (TC.num) {
		case 1:
			*(uint8_t *)TC.dst = TC.src;
			break;
		case 2:
			*(uint16_t *)TC.dst = TC.src;
			break;
		case 4:
			*(uint32_t *)TC.dst = TC.src;
			break;
		default:
			di_warn("Unexpected size in TODO_ACT_ASSIGN\n");
			break;
		}
		break;

	case TODO_ACT_WAIT_RKG:
		di_debug("  TODO_ACT_WAIT_RKG\n");
		/* enable the random-key interrupt */
		todo.status = TODO_ST_PEND_RKG;
		di_write(di_read(DIER) | DIER_RKIE, DIER);
		break;

	default:
		di_debug("  TODO_ACT_NOOP\n");
		break;
	}
}