⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_tc.c

📁 AT91RM9200的定时器驱动(linux2.4内核)
💻 C
字号:
/* *	Timer Counter interface for Linux on Atmel AT91RM9200 * *	Copyright (c) 2002 Rick Bronson *  *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the License, or (at your option) any later version. *Timer/Counter driver.  This enables you to opena Timer/Counter channel and wait on a specific time.  Also allows youto output a specific frequency on a pin. */#include <linux/module.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/string.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <asm/bitops.h>#include <asm/hardware.h>#include <asm/irq.h>#include <linux/rtc.h>#include <asm/arch/tc.h>  /* get ioctl stuff for tc */#include "at91_tc.h"#define	DRIVER_VERSION	"1.00"static AT91PS_TC p_tc_lut[TC_NUM] = {  /* TC address lookup table */  AT91C_BASE_TC0, AT91C_BASE_TC1, AT91C_BASE_TC2,   AT91C_BASE_TC3, AT91C_BASE_TC4, AT91C_BASE_TC5, };static AT91PS_TCB p_tcb_lut[TC_NUM] = {  /* TC block address lookup table */  AT91C_BASE_TCB0, AT91C_BASE_TCB0, AT91C_BASE_TCB0,   AT91C_BASE_TCB1, AT91C_BASE_TCB1, AT91C_BASE_TCB1, };static void at91_tc_interrupt(int irq, void *dev_id, struct pt_regs *regs)  {  struct tc_private *priv = dev_id;  /* pointer to the priv */  AT91PS_TC p_tc = priv->p_tc;  unsigned int rtsr = p_tc->TC_SR & p_tc->TC_IMR;  if (rtsr & AT91C_TC_CPAS)    wake_up_interruptible(&priv->tc_wait);   /* wake up waiting process */  }static int at91_tc_open(struct inode *inode, struct file *file){	struct tc_private *priv;	int minor = MINOR(inode->i_rdev);	if (minor > AT91_TC_MINOR_LAST)		return -EINVAL;	priv = (struct tc_private *)kmalloc(sizeof(struct tc_private), 					      GFP_KERNEL);	if (!priv)		return -ENOMEM;	priv->minor = minor;	priv->p_tc = p_tc_lut[minor];  /* save TC pointer */	priv->p_tcb = p_tcb_lut[minor];  /* save TC Block pointer */	file->private_data = (void *)priv;	spin_lock_init(&priv->lock1);        priv->first_time_flag = 0;	priv->irq = AT91C_ID_TC0 + minor;        *AT91C_PMC_PCER = 1 << priv->irq;  // turn clock on        init_waitqueue_head(&priv->tc_wait);	if (request_irq (priv->irq, at91_tc_interrupt,                           0, "at91_tc", priv))          {          kfree(priv);          printk("at91_tc: unable to get IRQ %d\n", priv->irq);          return -EAGAIN;          }        return 0;}static int at91_tc_release(struct inode *inode, struct file *file){	struct tc_private *priv = (struct tc_private *)file->private_data;        AT91PS_TC p_tc = priv->p_tc;        p_tc->TC_IDR = -1;  /* disable the interrupt */        p_tc->TC_CCR = AT91C_TC_CLKDIS;  /* disable the clock */        *AT91C_PMC_PCDR = 1 << priv->irq;  /* turn clock off */        wake_up_interruptible(&priv->tc_wait);   /* wake up waiting process if any */	free_irq(priv->irq, priv);  /* get rid of this int */	kfree(priv);	return 0;}ssize_t at91_tc_read(struct file * file, char *buf, size_t count, loff_t * ppos){	struct tc_private *priv = (struct tc_private *)file->private_data;        AT91PS_TC p_tc = priv->p_tc;	if (count < sizeof(unsigned long))		return -EINVAL;	return put_user(p_tc->TC_CV, (unsigned long *) buf);}/* * Handle commands from user-space */static int at91_tc_ioctl(struct inode *inode, struct file *file,			  unsigned int cmd, unsigned long arg)  {  int ret = 0;  unsigned long flags, val;  struct tc_private *priv = (struct tc_private *)file->private_data;  struct at91_tc_ioctl_clock tc_clock;  struct at91_pck_ioctl pmc_pck;  AT91PS_TC p_tc = priv->p_tc;  AT91PS_TCB p_tcb = priv->p_tcb;  AT91PS_PIO p_pio; /* pio init if any for this Timer */  switch (cmd)    {    case AT91_TC_WAIT:  /* set up periodict interrupt */      if (copy_from_user (&val, (void *)arg, sizeof (val)))        ret = -EFAULT;      spin_lock_irqsave(&priv->lock1, flags);  /* stop int's else we wakeup b4 we sleep */      p_tc->TC_CMR = AT91C_TC_WAVE | AT91C_TC_TIMER_DIV5_CLOCK;  /* 32768 Hz clock */      if (priv->first_time_flag == 0)        {        p_tc->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;  //Channel Control Register        p_tc->TC_RA = val;        p_tc->TC_IER = AT91C_TC_CPAS;  /* enable the interrupt */        priv->first_time_flag = 1;        }      else        p_tc->TC_RA += val;      interruptible_sleep_on(&priv->tc_wait);      spin_unlock_irqrestore(&priv->lock1, flags);      ret = copy_to_user ((void *)arg, &val, sizeof (val)) ? -EFAULT : 0;      break;    case AT91_TC_SET_CLOCK:  /* set up timer modes, and possible output on a pin */      if (copy_from_user (&tc_clock, (void *)arg, sizeof (tc_clock)))        return -EFAULT;      if ((p_pio = tc_clock.p_pio) != NULL)        {  /* configure port pin for peripheral */	p_pio->PIO_ASR = tc_clock.pio_asr;	p_pio->PIO_BSR = tc_clock.pio_bsr;	p_pio->PIO_PDR = tc_clock.pio_asr | tc_clock.pio_bsr;        }      p_tcb->TCB_BCR = tc_clock.tcb_bcr;  /* TC Block Control Register */      p_tcb->TCB_BMR = tc_clock.tcb_bmr;  /* TC Block Mode Register */      p_tc->TC_CMR = tc_clock.tc_cmr;  /* Channel Mode Register, must write 1st */      p_tc->TC_CCR = tc_clock.tc_ccr;  /* Channel Control Register */      p_tc->TC_RA = tc_clock.tc_ra;  /* RA Register */      p_tc->TC_RC = tc_clock.tc_rc;  /* RA Register */      break;    case AT91_TC_ENABLE_PCK:  /* set up timer modes, and possible output on a pin */      if (copy_from_user (&pmc_pck, (void *)arg, sizeof (pmc_pck)))        return -EFAULT;      if ((p_pio = pmc_pck.p_pio) != NULL)        {  /* configure port pin for peripheral */	p_pio->PIO_ASR = pmc_pck.pio_asr;	p_pio->PIO_BSR = pmc_pck.pio_bsr;	p_pio->PIO_PDR = pmc_pck.pio_asr | pmc_pck.pio_bsr;        }      AT91C_BASE_SYS->PMC_PCKR[pmc_pck.pck_no] = pmc_pck.pmc_pck;  /* program it */      AT91C_BASE_SYS->PMC_SCER = AT91C_PMC_PCK0 << pmc_pck.pck_no;  /* enable it */      break;    case AT91_TC_DISABLE_PCK:  /* set up timer modes, and possible output on a pin */      if (copy_from_user (&pmc_pck, (void *)arg, sizeof (pmc_pck)))        return -EFAULT;      AT91C_BASE_SYS->PMC_SCDR = AT91C_PMC_PCK0 << pmc_pck.pck_no;  /* disable it */      if ((p_pio = pmc_pck.p_pio) != NULL)        {  /* configure port pin for peripheral */	p_pio->PIO_PER = pmc_pck.pio_asr | pmc_pck.pio_bsr;        }      break;    default:      ret = -EINVAL;      break;    }  return ret;  }static struct file_operations at91_tc_fops = {	owner:THIS_MODULE,	read:at91_tc_read,	ioctl:at91_tc_ioctl,	open:at91_tc_open,	release:at91_tc_release,};/* * Initialize and install TC driver */static int __init at91_tc_init(void)  {  int res;   res = register_chrdev(TC_MAJOR, "at91 tc", &at91_tc_fops);  if (res < 0)    {    printk(KERN_ERR "at91_tc: couldn't get a major number.\n");    return res;    }  printk(KERN_INFO "AT91 Timer/Counter driver v" DRIVER_VERSION "\n");  return 0;  }module_init(at91_tc_init);MODULE_AUTHOR("Rick Bronson");MODULE_DESCRIPTION("AT91 Timer Counter Driver (AT91_TC)");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -