Example #1
0
/*
 * set the seconds portion of dryice time counter and clear the
 * fractional part.
 */
static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs)
{
	struct imxdi_dev *imxdi = dev_get_drvdata(dev);
	int rc;

	/* zero the fractional part first */
	rc = di_write_wait(imxdi, 0, DTCLR);
	if (rc == 0)
		rc = di_write_wait(imxdi, secs, DTCMR);

	return rc;
}
Example #2
0
/*
 * set the seconds portion of dryice alarm register
 */
static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
	struct imxdi_dev *imxdi = dev_get_drvdata(dev);
	unsigned long now;
	unsigned long alarm_time;
	int rc;

	rc = rtc_tm_to_time(&alarm->time, &alarm_time);
	if (rc)
		return rc;

	/* don't allow setting alarm in the past */
	now = __raw_readl(imxdi->ioaddr + DTCMR);
	if (alarm_time < now)
		return -EINVAL;

	/* write the new alarm time */
	rc = di_write_wait(imxdi, (u32)alarm_time, DCAMR);
	if (rc)
		return rc;

	if (alarm->enabled)
		di_int_enable(imxdi, DIER_CAIE);  /* enable alarm intr */
	else
		di_int_disable(imxdi, DIER_CAIE); /* disable alarm intr */

	return 0;
}
Example #3
0
/*
 * post the alarm event from user context so it can sleep
 * on the write completion.
 */
static void dryice_work(struct work_struct *work)
{
	struct imxdi_dev *imxdi = container_of(work,
			struct imxdi_dev, work);

	/* dismiss the interrupt (ignore error) */
	di_write_wait(imxdi, DSR_CAF, DSR);

	/* pass the alarm event to the rtc framework. */
	rtc_update_irq(imxdi->rtc, 1, RTC_AF | RTC_IRQF);
}
static void dryice_work(struct work_struct *work)
{
	struct imxdi_dev *imxdi = container_of(work,
			struct imxdi_dev, work);

	
	di_write_wait(imxdi, DSR_CAF, DSR);

	
	rtc_update_irq(imxdi->rtc, 1, RTC_AF | RTC_IRQF);
}
Example #5
0
/*
 * probe for dryice rtc device
 */
static int dryice_rtc_probe(struct platform_device *pdev)
{
	struct resource *res;
	struct imxdi_dev *imxdi;
	int rc;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENODEV;

	imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL);
	if (!imxdi)
		return -ENOMEM;

	imxdi->pdev = pdev;

	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
				pdev->name))
		return -EBUSY;

	imxdi->ioaddr = devm_ioremap(&pdev->dev, res->start,
			resource_size(res));
	if (imxdi->ioaddr == NULL)
		return -ENOMEM;

	spin_lock_init(&imxdi->irq_lock);

	imxdi->irq = platform_get_irq(pdev, 0);
	if (imxdi->irq < 0)
		return imxdi->irq;

	init_waitqueue_head(&imxdi->write_wait);

	INIT_WORK(&imxdi->work, dryice_work);

	mutex_init(&imxdi->write_mutex);

	imxdi->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(imxdi->clk))
		return PTR_ERR(imxdi->clk);
	clk_prepare_enable(imxdi->clk);

	/*
	 * Initialize dryice hardware
	 */

	/* mask all interrupts */
	__raw_writel(0, imxdi->ioaddr + DIER);

	rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
			IRQF_SHARED, pdev->name, imxdi);
	if (rc) {
		dev_warn(&pdev->dev, "interrupt not available.\n");
		goto err;
	}

	/* put dryice into valid state */
	if (__raw_readl(imxdi->ioaddr + DSR) & DSR_NVF) {
		rc = di_write_wait(imxdi, DSR_NVF | DSR_SVF, DSR);
		if (rc)
			goto err;
	}

	/* initialize alarm */
	rc = di_write_wait(imxdi, DCAMR_UNSET, DCAMR);
	if (rc)
		goto err;
	rc = di_write_wait(imxdi, 0, DCALR);
	if (rc)
		goto err;

	/* clear alarm flag */
	if (__raw_readl(imxdi->ioaddr + DSR) & DSR_CAF) {
		rc = di_write_wait(imxdi, DSR_CAF, DSR);
		if (rc)
			goto err;
	}

	/* the timer won't count if it has never been written to */
	if (__raw_readl(imxdi->ioaddr + DTCMR) == 0) {
		rc = di_write_wait(imxdi, 0, DTCMR);
		if (rc)
			goto err;
	}

	/* start keeping time */
	if (!(__raw_readl(imxdi->ioaddr + DCR) & DCR_TCE)) {
		rc = di_write_wait(imxdi,
				__raw_readl(imxdi->ioaddr + DCR) | DCR_TCE,
				DCR);
		if (rc)
			goto err;
	}

	platform_set_drvdata(pdev, imxdi);
	imxdi->rtc = rtc_device_register(pdev->name, &pdev->dev,
				  &dryice_rtc_ops, THIS_MODULE);
	if (IS_ERR(imxdi->rtc)) {
		rc = PTR_ERR(imxdi->rtc);
		goto err;
	}

	return 0;

err:
	clk_disable_unprepare(imxdi->clk);

	return rc;
}