Пример #1
0
static int __exit dryice_rtc_remove(struct platform_device *pdev)
{
	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);

	flush_scheduled_work();

	if (pdata->rtc)
		rtc_device_unregister(pdata->rtc);

	/* mask alarm interrupt */
	di_int_disable(pdata, DIER_CAIE);

	if (pdata->irq >= 0)
		free_irq(pdata->irq, pdata);

	if (pdata->clk) {
		clk_disable(pdata->clk);
		clk_put(pdata->clk);
	}

	if (pdata->ioaddr)
		iounmap(pdata->ioaddr);

	if (pdata->baseaddr)
		release_mem_region(pdata->baseaddr, pdata->size);

	kfree(pdata);

	return 0;
}
Пример #2
0
/*
 * set the seconds portion of dryice alarm register
 */
static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
	unsigned long now;
	unsigned long alarm_time;
	int rc;

	dev_dbg(dev, "%s\n", __func__);
	rc = rtc_tm_to_time(&alarm->time, &alarm_time);
	if (rc)
		return rc;

	/* don't allow setting alarm in the past */
	now = di_read(pdata, DTCMR);
	if (alarm_time < now)
		return -EINVAL;

	/* write the new alarm time */
	di_write_wait_err(pdata, (u32)alarm_time, DCAMR, rc, err);

	if (alarm->enabled)
		di_int_enable(pdata, DIER_CAIE);  /* enable alarm intr */
	else
		di_int_disable(pdata, DIER_CAIE); /* disable alarm intr */
err:
	return rc;
}
Пример #3
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;
}
Пример #4
0
/*
 * dryice "normal" interrupt handler
 */
static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
{
	struct rtc_drv_data *pdata = dev_id;
	u32 dsr, dier;
	irqreturn_t rc = IRQ_NONE;

	dier = di_read(pdata, DIER);

	/* handle write complete and write error cases */
	if ((dier & DIER_WCIE)) {
		/*If the write wait queue is empty then there is no pending
		   operations. It means the interrupt is for DryIce -Security.
		   IRQ must be returned as none.*/
		if (list_empty_careful(&pdata->write_wait.task_list))
			return rc;

		/* DSR_WCF clears itself on DSR read */
	    dsr = di_read(pdata, DSR);
		if ((dsr & (DSR_WCF | DSR_WEF))) {
			/* mask the interrupt */
			di_int_disable(pdata, DIER_WCIE);

			/* save the dsr value for the wait queue */
			pdata->dsr |= dsr;

			wake_up_interruptible(&pdata->write_wait);
			rc = IRQ_HANDLED;
		}
	}

	/* handle the alarm case */
	if ((dier & DIER_CAIE)) {
		/* DSR_WCF clears itself on DSR read */
	    dsr = di_read(pdata, DSR);
		if (dsr & DSR_CAF) {
			/* mask the interrupt */
			di_int_disable(pdata, DIER_CAIE);

			/* finish alarm in user context */
			schedule_work(&pdata->work);
			rc = IRQ_HANDLED;
		}
	}
	return rc;
}
static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
{
	struct imxdi_dev *imxdi = dev_id;
	u32 dsr, dier;
	irqreturn_t rc = IRQ_NONE;

	dier = __raw_readl(imxdi->ioaddr + DIER);

	
	if ((dier & DIER_WCIE)) {
		if (list_empty_careful(&imxdi->write_wait.task_list))
			return rc;

		
		dsr = __raw_readl(imxdi->ioaddr + DSR);
		if ((dsr & (DSR_WCF | DSR_WEF))) {
			
			di_int_disable(imxdi, DIER_WCIE);

			
			imxdi->dsr |= dsr;

			wake_up_interruptible(&imxdi->write_wait);
			rc = IRQ_HANDLED;
		}
	}

	
	if ((dier & DIER_CAIE)) {
		
		dsr = __raw_readl(imxdi->ioaddr + DSR);
		if (dsr & DSR_CAF) {
			
			di_int_disable(imxdi, DIER_CAIE);

			
			schedule_work(&imxdi->work);
			rc = IRQ_HANDLED;
		}
	}
	return rc;
}
Пример #6
0
static int dryice_rtc_alarm_irq_enable(struct device *dev,
		unsigned int enabled)
{
	struct imxdi_dev *imxdi = dev_get_drvdata(dev);

	if (enabled)
		di_int_enable(imxdi, DIER_CAIE);
	else
		di_int_disable(imxdi, DIER_CAIE);

	return 0;
}
Пример #7
0
/*
 * rtc device ioctl
 *
 * The rtc framework handles the basic rtc ioctls on behalf
 * of the driver by calling the functions registered in the
 * rtc_ops structure.
 */
static int dryice_rtc_ioctl(struct device *dev, unsigned int cmd,
			    unsigned long arg)
{
	struct rtc_drv_data *pdata = dev_get_drvdata(dev);

	dev_dbg(dev, "%s(0x%x)\n", __func__, cmd);
	switch (cmd) {
	case RTC_AIE_OFF:  /* alarm disable */
		di_int_disable(pdata, DIER_CAIE);
		return 0;

	case RTC_AIE_ON:  /* alarm enable */
		di_int_enable(pdata, DIER_CAIE);
		return 0;
	}
	return -ENOIOCTLCMD;
}
Пример #8
0
/*
 * probe for dryice rtc device
 */
static int dryice_rtc_probe(struct platform_device *pdev)
{
	struct rtc_device *rtc;
	struct resource *res;
	struct rtc_drv_data *pdata = NULL;
	void __iomem *ioaddr = NULL;
	int rc = 0;

	dev_dbg(&pdev->dev, "%s\n", __func__);

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

	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	pdata->pdev = pdev;
	pdata->irq = -1;
	pdata->size = res->end - res->start + 1;

	if (!request_mem_region(res->start, pdata->size, pdev->name)) {
		rc = -EBUSY;
		goto err;
	}
	pdata->baseaddr = res->start;
	ioaddr = ioremap(pdata->baseaddr, pdata->size);
	if (!ioaddr) {
		rc = -ENOMEM;
		goto err;
	}
	pdata->ioaddr = ioaddr;
	pdata->irq = platform_get_irq(pdev, 0);

	init_waitqueue_head(&pdata->write_wait);

	INIT_WORK(&pdata->work, dryice_work);

	mutex_init(&pdata->write_mutex);

	pdata->clk = clk_get(NULL, "dryice_clk");
	clk_enable(pdata->clk);

	if (pdata->irq >= 0) {
		if (request_irq(pdata->irq, dryice_norm_irq, IRQF_SHARED,
				pdev->name, pdata) < 0) {
			dev_warn(&pdev->dev, "interrupt not available.\n");
			pdata->irq = -1;
			goto err;
		}
	}

	/*
	 * Initialize dryice hardware
	 */

	/* put dryice into valid state */
	if (di_read(pdata, DSR) & DSR_NVF)
		di_write_wait_err(pdata, DSR_NVF | DSR_SVF, DSR, rc, err);

	/* mask alarm interrupt */
	di_int_disable(pdata, DIER_CAIE);

	/* initialize alarm */
	di_write_wait_err(pdata, DCAMR_UNSET, DCAMR, rc, err);
	di_write_wait_err(pdata, 0, DCALR, rc, err);

	/* clear alarm flag */
	if (di_read(pdata, DSR) & DSR_CAF)
		di_write_wait_err(pdata, DSR_CAF, DSR, rc, err);

	/* the timer won't count if it has never been written to */
	if (!di_read(pdata, DTCMR))
		di_write_wait_err(pdata, 0, DTCMR, rc, err);

	/* start keeping time */
	if (!(di_read(pdata, DCR) & DCR_TCE))
		di_write_wait_err(pdata, di_read(pdata, DCR) | DCR_TCE, DCR,
				  rc, err);

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

	return 0;
err:
	if (pdata->rtc)
		rtc_device_unregister(pdata->rtc);

	if (pdata->irq >= 0)
		free_irq(pdata->irq, pdata);

	if (pdata->clk) {
		clk_disable(pdata->clk);
		clk_put(pdata->clk);
	}

	if (pdata->ioaddr)
		iounmap(pdata->ioaddr);

	if (pdata->baseaddr)
		release_mem_region(pdata->baseaddr, pdata->size);

	kfree(pdata);

	return rc;
}