linux字符设备驱动-ADC

嵌入式系统版本:linux2.6.24

 

驱动程序:

#include <linux/kernel.h>

#include <linux/module.h>

#include <asm/uaccess.h>

#include <linux/mm.h>

#include <linux/ioport.h>

#include <asm/io.h>

#include <linux/ioport.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/device.h>

#include <linux/clk.h>

 

#define ADC_MAJOR 102   //主设备号

#define ADC_MINOR 0     //次设备号

#define DEVICE_NAME  "adc_dev"//设备名称   

#define SUCCESS   0

//=====================寄存器地址映射===========================

#define adc_con            (unsigned long)ioremap(0x58000000,4)

#define adc_dat0    (volatile unsigned long)ioremap(0x5800000c,4)

 

static int Device_Open = 0;

static struct clk *adc_clk;//定义adc时钟结构

 

int adc_init(void);

void adc_cleanup(void);

static int device_open(struct inode *,struct file *);

static int device_release(struct inode *,struct file *);

static ssize_t device_read(struct file *,char *,size_t,loff_t *);

int init_module(void);

void cleanup_module(void);

 

//=================================================================

//           填充file_operations

//================================================================

struct file_operations  adc_ops =  

{                                  

       .owner    = THIS_MODULE,

       .read   = device_read,

       .open      = device_open,

       .release=device_release,

};

 

//===========================================================

//        注册设备

//===========================================================

struct cdev *my_cdev; 

struct class *my_class;

int __init adc_init(void)       

{

#if 0

       Major = register_chrdev(ADC_MAJOR,DEVICE_NAME,&adc_ops);  //注册操作,返回主设备值

       if(Major <0)

       {

              printk("ADC init_module:failed with %d\n",Major);    //主设备号小于0,则注册失败

              return Major;

       }

      

       devfs_mk_cdev(MKDEV(ADC_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);

#endif

        int err, i;

        int devno = MKDEV(ADC_MAJOR, ADC_MINOR);//获取设备号 .

           //===========初始化cdev================

        my_cdev = cdev_alloc();

        cdev_init(my_cdev, &adc_ops);//初始化cdev

        my_cdev->owner = THIS_MODULE;

        err = cdev_add(my_cdev, devno, 1);//添加cdev

        if (err != 0)

               printk("adc register failed!\n");

        //============注册设备==================

        my_class = class_create(THIS_MODULE, "adc_class");

        if(IS_ERR(my_class)) {

            printk("Err: failed in creating class.\n");

            return -1;

        }

        /* register your own device in sysfs, and this will cause udevd to create corresponding device node */

        class_device_create(my_class, NULL, devno, NULL, DEVICE_NAME "%d", ADC_MINOR );

       //=============打开adc时钟=====================

       adc_clk = clk_get(NULL, "adc"); 

       if (!adc_clk) 

       { 

               printk(KERN_ERR "failed to get adc clock source\n"); 

            return -ENOENT; 

        } 

       clk_enable(adc_clk);

 

       printk(DEVICE_NAME " initialized\n");

       return 0;

}

//===========================================================

//            打开设备文件

//===========================================================

static int device_open(struct inode * inode,struct file *file)      

{

    if(Device_Open)

    {

        return -EBUSY;

    }

    Device_Open++;

    return SUCCESS;

}

 

//===========================================================

//            关闭设备文件

//===========================================================

static int device_release(struct inode * inode,struct file *file)

{

    Device_Open --;

    return 0;

}

 

//===========================================================

//        读取设备文件

//===========================================================

static ssize_t device_read(struct file *file,

                            char * buffer,

                            size_t length,

                            loff_t * offset)

{

       unsigned long buf;

printk("1\n");

       __raw_writel((1<<14)|(5<<6)|(0<<3), adc_con);     //选择ADC通道

       __raw_writel(__raw_readl(adc_con)|0x1, adc_con);  //启动ADC

printk("2\n");

       while(__raw_readl(adc_con) &0x1);                 //等待ADC启动完成

printk("3\n");

        while(!(__raw_readl(adc_con) & 0x8000));      //等待ADC完成

printk("4\n");

      buf=__raw_readl(adc_dat0) & 0x3ff;                //读取ADC

       *buffer=(unsigned char)buf;

       buffer++;

       *buffer=(unsigned char)(buf>>8);

       return 2;

}

 

//===========================================================

//        注销设备

//===========================================================

void adc_cleanup()    

{

              //========关闭ADC时钟========

        if(adc_clk) 

        { 

            clk_disable(adc_clk); 

            clk_put(adc_clk); 

            adc_clk = NULL; 

        } 

        //========注销设备========

        cdev_del(my_cdev);

        class_device_destroy(my_class, MKDEV(ADC_MAJOR, ADC_MINOR));

        class_destroy(my_class);

        printk("AdcDriver removed success!\r\n");

 

}

module_init(adc_init);        

module_exit(adc_cleanup);

MODULE_LICENSE("GPL");

 

注意:对于红色的部分,如果去掉会导致系统卡死在驱动中,最终崩溃,因为系统移植的时候adc时钟是默认关闭的,需要重新开启。见:./arch/arm/mach-s3c2410/clock.c

测试程序:

#include "stdio.h"

#include "sys/types.h"

#include "sys/ioctl.h"

#include "stdlib.h"

#include "termios.h"

#include "sys/stat.h"

#include "fcntl.h"

#include "sys/time.h"

int main(int argc, char **argv)

{

        int fd,ret,adcdat0;

        char buf[2];

        fd=open("/dev/adc_dev",0);//打开设备

        if(fd<0)

        {

                printf("open adc error\n");

                exit(1);

        }

        else

        {

                printf("success\n");

                while(1)   

                {

                        read(fd,buf,2);//读设备

                     adcdat0=buf[1];

                     adcdat0=adcdat0<<8|buf[0];

                        printf("adc_value = %d \n",adcdat0);

                        sleep(1);

                }

        }

        close(fd);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落西湘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值