TI中文支持网
TI专业的中文技术问题搜集分享网站

AM335X ADC LINUX 驱动无法进中断问题

首先感谢大家关注我的问题!
对于LINUX驱动编写来说,我是个新手,最近在编写AM3352 ADC驱动。公司产品用的是liunx 3.2内核:linux-3.2.0-psp04.06.00.08.sdk。
没有用到设备树。
通过参考TI Steven Liu 工程师写的驱动实例(http://www.deyisupport.com/question_answer/dsp_arm/sitara_arm/f/25/t/75146.aspx?pi2132219853=3)
进行改编成最简单的字符驱动模型,能够进行驱动的加载和卸载,驱动的主节点设成101,驱动名为drvADC,生成的驱动文件为drvADC.ko。驱动测试程序名为
drvADC_test.o编译好后,进行如下操作。
1、将drvADC.ko 和测试程序drvADC_test.o上传到核心板工作目录,并更改文件权限;
2、insmod drvADC.ko, 提示驱动安装成功, 检查在devices里面drvADC的主节点号的确为101;
3、mknod /dev/drvADC c 101 0, 检查在/dev目录下有drvADC;
4、在工作目录中运行测试程序./drvADC_test.o,输出信息如下:
[  810.407348] Going to open ADC
st start…
[  810.411773] map register memery
[  810.416229] irq request success, err = 0
[  810.420379] get clk success
[  810.423278] get clock_rate success, clock_rate = 24000000
[  810.428924] get clk_value success, clk_value = 8
[  810.433715] Choose ADC channel 4
[  810.437103] adc initialized!
[  810.440582] ADC channel:4 working, reading adc data
[  810.445678] Start adc channel 4
之后一直没有打印信息输出,分析对比程序,推断是没有触发中断,一直在等待中断。这会是什么原因呢?希望能得到大家的帮助。
下面是程序(附件也是一样的程序):

Eric Lia:

#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/types.h>
//#include <linux/irqs-33xx.h>
#include <linux/moduleparam.h>
#define TSCADC_REG_IRQEOI 0x020
#define TSCADC_REG_RAWIRQSTATUS 0x024
#define TSCADC_REG_IRQSTATUS 0x028
#define TSCADC_REG_IRQENABLE 0x02C
#define TSCADC_REG_IRQCLR 0x030
#define TSCADC_REG_IRQWAKEUP 0x034
#define TSCADC_REG_CTRL 0x040
#define TSCADC_REG_ADCFSM 0x044
#define TSCADC_REG_CLKDIV 0x04C
#define TSCADC_REG_SE 0x054
#define TSCADC_REG_IDLECONFIG 0x058
#define TSCADC_REG_CHARGECONFIG 0x05C
#define TSCADC_REG_CHARGEDELAY 0x060
#define TSCADC_REG_STEPCONFIG(n) (0x64 + ((n-1) * 8))
#define TSCADC_REG_STEPDELAY(n) (0x68 + ((n-1) * 8))
#define TSCADC_REG_STEPCONFIG13 0x0C4
#define TSCADC_REG_STEPDELAY13 0x0C8
#define TSCADC_REG_STEPCONFIG14 0x0CC
#define TSCADC_REG_STEPDELAY14 0x0D0
#define TSCADC_REG_FIFO0CNT 0xE4
#define TSCADC_REG_FIFO0THR 0xE8
#define TSCADC_REG_FIFO1CNT 0xF0
#define TSCADC_REG_FIFO1THR 0xF4
#define TSCADC_REG_FIFO0 0x100
#define TSCADC_REG_FIFO1 0x200/* Register Bitfields */
#define TSCADC_IRQWKUP_ENB BIT(0)
#define TSCADC_IRQWKUP_DISABLE 0x00
#define TSCADC_STPENB_STEPENB 0x7FFF
#define TSCADC_IRQENB_FIFO0THRES BIT(2)#define ADC_STPENB_STEPENB 0x1FE
#define TSCADC_IRQENB_STEPEND BIT(1)
#define TSCADC_IRQENB_FIFO1THRES BIT(5)
#define TSCADC_IRQENB_PENUP BIT(9)
#define TSCADC_IRQENB_HW_PEN BIT(0)
#define TSCADC_STEPCONFIG_MODE_HWSYNC 0x2
#define TSCADC_STEPCONFIG_2SAMPLES_AVG (1 << 4)
#define TSCADC_STEPCONFIG_XPP BIT(5)
#define TSCADC_STEPCONFIG_XNN BIT(6)
#define TSCADC_STEPCONFIG_YPP BIT(7)
#define TSCADC_STEPCONFIG_YNN BIT(8)
#define TSCADC_STEPCONFIG_XNP BIT(9)
#define TSCADC_STEPCONFIG_YPN BIT(10)#define TSCADC_STEPCONFIG_1_NEGATIVE_INP (0)
#define TSCADC_STEPCONFIG_1_INP (0)
#define TSCADC_STEPCONFIG_2_INP BIT(19)
#define TSCADC_STEPCONFIG_3_INP BIT(20)
#define TSCADC_STEPCONFIG_4_INP (BIT(19)|BIT(20))
#define TSCADC_STEPCONFIG_5_INP BIT(21)
#define TSCADC_STEPCONFIG_6_INP (BIT(19)|BIT(21))
#define TSCADC_STEPCONFIG_7_INP (BIT(21)|BIT(20))
#define TSCADC_STEPCONFIG_8_INP (BIT(19)|BIT(20)|BIT(21))
#define TSCADC_STEPCONFIG_REFP (BIT(12)|BIT(13))#define TSCADC_STEPCONFIG_RFM ((1 << 23)|(1 << 24))
#define TSCADC_STEPCONFIG_SINGLE_ENDED_OPER_MODE (0 <<25)
#define TSCADC_STEPCONFIG_MODE (0)
#define TSCADC_STEPCONFIG_RFP (1 << 12)
#define TSCADC_STEPCONFIG_INM (1 << 18)
#define TSCADC_STEPCONFIG_INP_4 (1 << 19)
#define TSCADC_STEPCONFIG_INP (1 << 20)
#define TSCADC_STEPCONFIG_INP_5 (1 << 21)
#define TSCADC_STEPCONFIG_FIFO1 (1 << 26)
#define TSCADC_STEPCONFIG_IDLE_INP (1 << 22)
#define TSCADC_STEPCONFIG_OPENDLY 0x0
#define TSCADC_STEPCONFIG_SAMPLEDLY 0x0#define TSCADC_STEPCONFIG_Z1 (3 << 19)#define TSCADC_CNTRLREG_TSCSSENB BIT(0)
#define TSCADC_CNTRLREG_STEPID BIT(1)
#define TSCADC_CNTRLREG_STEPCONFIGWRT BIT(2)
#define TSCADC_CNTRLREG_TSCENB BIT(7)
#define TSCADC_CNTRLREG_4WIRE (0x1 << 5)
#define TSCADC_CNTRLREG_5WIRE (0x1 << 6)
#define TSCADC_CNTRLREG_8WIRE (0x3 << 5)
#define TSCADC_ADCFSM_STEPID 0x10
#define TSCADC_ADCFSM_FSM BIT(5)#define ADC_CLK 3000000#define MAX_12BIT ((1 << 12) - 1)#define ADC_MAJOR_NUMBER 101
#define ADC_MOUDLE_NAME "drvADC"#define AM335X_ADC_BASE_ADDR 0X44E0D000 static volatile int ev_adc = 0;static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);
static int adc_data = 0;struct adc_st
{
 struct cdev adc;
 int irq;
 void __iomem *adc_base;};static int adc_major = 0;struct adc_st *adc_dev = NULL;static int channel = 4;module_param(channel, int, S_IRUGO);static unsigned int am335x_adc_readl(struct adc_st *adc, unsigned int reg);
static void am335x_adc_writel(struct adc_st *adc, unsigned int reg, unsigned int val);
static void am335x_start_adc(struct adc_st *dev);
static void am335x_stop_adc(struct adc_st *dev);
static void am335x_adc_step_config(struct adc_st *adc_dev);
static void am335x_adc_idle_config(struct adc_st *adc_config);
static int am335x_adc_open(struct inode *inode, struct file *file);
static ssize_t am335x_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos);
static int am335x_adc_release(struct inode *inode, struct file *filp);
long am335x_adc_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param);
static int am335x_adc_setup_cdev(struct adc_st *dev, int index);
static irqreturn_t adc_interrupt(int irq, void *dev)
{
 unsigned int status, irqclr = 0;
 int i;
 int fifo0count = 0;
 unsigned int readx1 = 0; printk("adc_interrupt enter, ev_adc %d...\n", ev_adc); if (!ev_adc)
 {
 status = am335x_adc_readl(adc_dev, TSCADC_REG_IRQSTATUS); printk("adc_interrupt status %d...\n", status); if (status & TSCADC_IRQENB_FIFO0THRES)
 {
 fifo0count = am335x_adc_readl(adc_dev, TSCADC_REG_FIFO0CNT);
 printk("ADC_Interrupt FIFO0_Count %d...\n", fifo0count); for (i = 0; i < fifo0count; i++)
 {
 readx1 = am335x_adc_readl(adc_dev, TSCADC_REG_FIFO0);
 printk("FIFO0_count %d : %d\n", i, readx1);
 adc_data += readx1; } if (fifo0count) 
 {
 adc_data = adc_data / fifo0count;
 }
 printk("ADC_DATA: %d \n", adc_data); irqclr |= TSCADC_IRQENB_FIFO0THRES;
 } am335x_stop_adc(adc_dev);
 am335x_adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, irqclr); //clear TSCADC_IRQENB_FIFO0THRES irq
 am335x_adc_writel(adc_dev, TSCADC_REG_IRQEOI, 0x0); // check pending interrupts
 am335x_adc_writel(adc_dev, TSCADC_REG_SE, ADC_STPENB_STEPENB);
 ev_adc = 1;
 wake_up_interruptible(&adc_waitq);
 } return IRQ_HANDLED;}static unsigned int am335x_adc_readl(struct adc_st *adc, unsigned int reg)
{
 return readl(adc->adc_base + reg);
}static void am335x_adc_writel(struct adc_st *adc, unsigned int reg, unsigned int val)
{
 writel(val, adc->adc_base + reg);
}static void am335x_start_adc(struct adc_st *dev)
{
 int ctrl = 0; printk("Start adc channel %d\n", channel);
 //TSC_ADC_SS module enable bit.
 //After programming all the steps and configuration registers, write a
 //1 to this bit to turn on TSC_ADC_SS.
 //Writing a 0 will disable the module (after the current conversion)
 ctrl |= TSCADC_CNTRLREG_STEPCONFIGWRT | TSCADC_CNTRLREG_TSCSSENB; am335x_adc_writel(dev, TSCADC_REG_CTRL, ctrl);
}static void am335x_stop_adc(struct adc_st *dev)
{
 int ctrl = 0; printk("Stop adc channel %d\n", channel);
 //TSC_ADC_SS module enable bit.
 //After programming all the steps and configuration registers, write a
 //1 to this bit to turn on TSC_ADC_SS.
 //Writing a 0 will disable the module (after the current conversion)
 ctrl |= TSCADC_CNTRLREG_STEPCONFIGWRT; am335x_adc_writel(dev, TSCADC_REG_CTRL, ctrl);}static void am335x_adc_step_config(struct adc_st *adc_dev)
{
 unsigned int step_config = 0;
 unsigned int delay = 0;
 int i; /* Configure the Step registers */
 step_config = TSCADC_STEPCONFIG_REFP | TSCADC_STEPCONFIG_RFM | TSCADC_STEPCONFIG_SINGLE_ENDED_OPER_MODE | TSCADC_STEPCONFIG_MODE; switch (channel)
 {
 case 0:
 step_config |= TSCADC_STEPCONFIG_1_INP;
 break;
 case 1:
 step_config |= TSCADC_STEPCONFIG_2_INP;
 break;
 case 2:
 step_config |= TSCADC_STEPCONFIG_3_INP;
 break;
 case 3:
 step_config |= TSCADC_STEPCONFIG_4_INP;
 break;
 case 4:
 step_config |= TSCADC_STEPCONFIG_5_INP;
 break;
 case 5:
 step_config |= TSCADC_STEPCONFIG_6_INP;
 break;
 case 6:
 step_config |= TSCADC_STEPCONFIG_7_INP;
 break;
 case 7:
 step_config |= TSCADC_STEPCONFIG_8_INP;
 break;
 default:
 channel = 4;
 step_config |= TSCADC_STEPCONFIG_5_INP; //default for channel 4
 printk("Input wrong! Channel number should be [0..7]\n");
 break; } printk("Choose ADC channel %d\n", channel); for (i = 1; i < 9; i++)
 {
 am335x_adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), step_config);
 } delay = TSCADC_STEPCONFIG_SAMPLEDLY | TSCADC_STEPCONFIG_OPENDLY; for (i = 1; i < 9; i++)
 {
 am335x_adc_writel(adc_dev, TSCADC_REG_STEPDELAY(i), delay);
 } am335x_adc_writel(adc_dev, TSCADC_REG_SE, ADC_STPENB_STEPENB); // steven:this affect which step configs can be used!!! Important!!!
}static void am335x_adc_idle_config(struct adc_st *adc_config)
{
 /* Idle mode adc screen config */
 unsigned int idle_config = 0; am335x_adc_writel(adc_config, TSCADC_REG_IDLECONFIG, idle_config);
}static int am335x_adc_open(struct inode *inode, struct file *file)
{
 int err;
 int clk_value;
 int clock_rate, ctrl;
// struct resource *res;
 struct clk *clk;
 dev_t devno;
// int ret; printk("Going to open ADC\n"); /* Allocate memory for device */
 adc_dev = kzalloc(sizeof(struct adc_st), GFP_KERNEL);
 if (!adc_dev)
 {
 printk("failed to allocate memory.\n");
 return -ENOMEM;
 } adc_dev->adc_base = ioremap(AM335X_ADC_BASE_ADDR, 0x1000); if (!adc_dev->adc_base)
 {
 printk("failed to map register memery.\n");
 err = -ENOMEM;
 goto err_release_mem;
 }
 printk("map register memery\n");
 //AM33XX_IRQ_ADC_GEN
 err = request_irq(16, adc_interrupt, IRQF_DISABLED, ADC_MOUDLE_NAME, adc_dev); if (err)
 {
 printk("Request adc irq failed\n");
 return err;
 }
 printk("irq request success, err = %x\n", err); clk = clk_get(NULL, "adc_tsc_fck"); if (IS_ERR(clk))
 {
 printk("failed to get TSC fck\n");
 err = PTR_ERR(clk);
 goto err_free_irq;
 }
 printk("get clk success\n");
 clock_rate = clk_get_rate(clk);
 printk("get clock_rate success, clock_rate = %d\n", clock_rate);
 clk_value = clock_rate / ADC_CLK;
 if (clk_value < 7)
 {
 printk("clock input less than min clock requirement\n");
 err = -EINVAL;
 goto err_fail;
 }
 printk("get clk_value success, clk_value = %d\n", clk_value);
 /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
 clk_value = clk_value - 1;
 am335x_adc_writel(adc_dev, TSCADC_REG_CLKDIV, clk_value); /* Set the control register bits */
 ctrl = TSCADC_CNTRLREG_STEPCONFIGWRT | TSCADC_CNTRLREG_TSCENB; am335x_adc_writel(adc_dev, TSCADC_REG_CTRL, ctrl); /* Set register bits for Idel Config Mode */
 am335x_adc_idle_config(adc_dev);
 am335x_adc_step_config(adc_dev); /* IRQ Enable */
 am335x_adc_writel(adc_dev, TSCADC_REG_IRQENABLE, TSCADC_IRQENB_FIFO0THRES);
 am335x_adc_writel(adc_dev, TSCADC_REG_FIFO0THR, 7); //FIFO THRESHOLD SET 0-7// device_init_wakeup(&pdev->dev, true);
 printk("adc initialized!\n");err_release_mem:
iounmap(adc_dev->adc_base);
err_free_irq:
free_irq(16, adc_dev); 
err_fail: return 0;
}//standard read function
static ssize_t am335x_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
 printk("ADC channel:%d working, reading adc data\n", channel); if (!ev_adc)
 {
 if (filp->f_flags & O_NONBLOCK)
 {
 return -EAGAIN;
 } else
 {
 am335x_start_adc(adc_dev); wait_event_interruptible(adc_waitq, ev_adc);
 }
 } ev_adc = 0; copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data)); adc_data = 0; return sizeof(adc_data);
}static int am335x_adc_close (struct inode *inode, struct file *file)
{
 printk("close adc \n\r"); free_irq(16, adc_dev);
 iounmap(adc_dev->adc_base); kfifo_free(ptrFifoMsgTx);
 kfifo_free(ptrFifoMsgRx); MOD_DEC_USE_COUNT; return 0;
}static int am335x_adc_release(struct inode *inode, struct file *filp)
{ return 0;
}long am335x_adc_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
 return 0;
}static struct file_operations am335x_adc_fops =
{
 .owner = THIS_MODULE,
 .open = am335x_adc_open,
 .close = am335x_adc_close,
 .read = am335x_adc_read,
 .release = am335x_adc_release,
 .unlocked_ioctl = am335x_adc_ioctl,
};static int am335x_adc_setup_cdev(struct adc_st *dev, int index)
{
 int err, devno = MKDEV(adc_major, index);
 cdev_init(&dev->adc, &am335x_adc_fops);
 dev->adc.owner = THIS_MODULE;
 err = cdev_add(&dev->adc, devno, 1);
 if (err)
 {
 printk("no memory resource defined.\n");
 return err;
 }
}static int __init am335x_adc_init(void)
{
 int ret; /* Fill in date and time into the module info. */
 if ((ret = register_chrdev(ADC_MAJOR_NUMBER, ADC_MOUDLE_NAME, &am335x_adc_fops)) < 0)
 {
 printk("am335x adc dirver register failed!\r\n");
 return ret;
 } printk("am335x adc dirver registed!\r\n"); return 0;
}module_init(am335x_adc_init);static void __exit am335x_adc_exit(void)
{
 unregister_chrdev(ADC_MAJOR_NUMBER, ADC_MOUDLE_NAME);
 printk("am335x adc dirver unregister\r\n");
}module_exit(am335x_adc_exit);MODULE_DESCRIPTION("TOK ADC controller driver");
MODULE_AUTHOR("TOK");
MODULE_LICENSE("GPL"); 

赞(0)
未经允许不得转载:TI中文支持网 » AM335X ADC LINUX 驱动无法进中断问题
分享到: 更多 (0)