This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

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

Other Parts Discussed in Thread: AM3352

首先感谢大家关注我的问题!
对于LINUX驱动编写来说,我是个新手,最近在编写AM3352 ADC驱动。公司产品用的是liunx 3.2内核:linux-3.2.0-psp04.06.00.08.sdk。
没有用到设备树。
通过参考TI Steven Liu 工程师写的驱动实例(www.deyisupport.com/.../75146.aspx
进行改编成最简单的字符驱动模型,能够进行驱动的加载和卸载,驱动的主节点设成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
之后一直没有打印信息输出,分析对比程序,推断是没有触发中断,一直在等待中断。这会是什么原因呢?希望能得到大家的帮助。
下面是程序(附件也是一样的程序):

  • #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");