zoukankan      html  css  js  c++  java
  • 【Linux高级驱动】rtc驱动开发

    【1.分层思想】

    1.1 rtc-dev.c   //设备接口层,功能:给用户提供接口

    subsys_initcall(rtc_init);   //module_init(rtc_init)  //rtc/class.c
    /*创建一个设备类*/
    rtc_class = class_create(THIS_MODULE, "rtc");
    /*初始化*/
    rtc_init  
     rtc_dev_init
      /*动态申请主设备号*/
      alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");

    1.2 rtc-s3c.c  //功能:操作硬件

    module_init(s3c_rtc_init);
    static struct platform_driver s3c_rtc_driver = {
     .probe  = s3c_rtc_probe,
     .remove  = __devexit_p(s3c_rtc_remove),
     .suspend = s3c_rtc_suspend,
     .resume  = s3c_rtc_resume,
     .id_table = s3c_rtc_driver_ids,
     .driver  = {
      .name = "s3c-rtc",
      .owner = THIS_MODULE,
     },
    };
    s3c_rtc_init
     platform_driver_register(&s3c_rtc_driver);
    s3c_rtc_probe
     /*1.获取中断资源*/
     /*2.获取io内存资源*/
     /*3.映射*/
     /*4.使能RTC*/
     /*5.注册*/
     rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,THIS_MODULE);
      //device_create(class,parent,MKDEV,drvdata,name)
      rtc->dev.parent = dev;
      rtc->dev.class = rtc_class;
      dev_set_name(&rtc->dev, "rtc%d", id);   //指定设备文件的名字  /dev/rtc0 /dev/rtc1 /dev/rtc2 .....
      rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
      cdev_init(&rtc->char_dev, &rtc_dev_fops);
      rtc_dev_add_device(rtc);
       cdev_add(&rtc->char_dev, rtc->dev.devt, 1)


     

    【为了能够读取到rtc的时间】

    【一/添加驱动(driver/rtc)】

    1.修改driver/rtc/目录下的Kconfig
        vi linux-2.6.35.5/driver/rtc/Kconfig

    config RTC_DRV_S3C
             tristate "Samsung S3C series SoC RTC"
             depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100(添加的东西)
             help
               RTC (Realtime Clock) driver for the clock inbuilt into the
               Samsung S3C24XX series of SoCs. This can provide periodic
               interrupt rates from 1Hz to 64Hz for user programs, and
               wakeup from Alarm.
               The driver currently supports the common features on all the
               S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440
               and S3C2442.
               This driver can also be build as a module. If so, the module
               will be called rtc-s3c.


     

    2.配置内核
        make menuconfig

    Device Drivers  --->
     <*> Real Time Clock  --->     //class.c rtc-dev.c
      <*>   Samsung S3C series SoC RTCs       //需要修改driver/rtc/Kconfig

    3.资源添加
        vi arch/arm/mach-s5pc100/Kconfig

    config MACH_SMDKC100
              bool "SMDKC100"
              select CPU_S5PC100
              select S3C_DEV_FB
              select S3C_DEV_I2C1
              select S3C_DEV_HSMMC
              select S3C_DEV_HSMMC1
              select S3C_DEV_HSMMC2
              select S5PC100_SETUP_FB_24BPP
              select S5PC100_SETUP_I2C1
              select S5PC100_SETUP_SDHCI
              select S3C_DEV_LED
              select S3C_DEV_RTC     //添加的代码

        vi arch/arm/mach-s5pc100/mach-smdkc100.c

    static struct platform_device *smdkc100_devices[] __initdata = {
             &s3c_device_i2c0,
             &s3c_device_i2c1,
             &s3c_device_fb,
             &s3c_device_hsmmc0,
             &s3c_device_hsmmc1,
             &s3c_device_hsmmc2,
             &smdkc100_lcd_powerdev,
             &s5pc100_device_iis0,
             &s5pc100_device_ac97,
     #ifdef  CONFIG_DM9000
             &s5pc100_device_dm9000,
     #endif
             &fsled_device,
             &s3c_device_rtc,
     };

    4.修改linux-2.6.35.5/arch/arm/mach-s5pc100/includ/mach/map.h
        vi linux-2.6.35.5/arch/arm/mach-s5pc100/includ/mach/map.h
        在其中添加

    #define S3C_PA_RTC  0xEA300000

    5.重新编译内核

    测试:


    1.编写测试程序,见rtc_test.c
    2.运行测试程序
    ./rtc_test

    Current RTC date/time is 0-0-2000, 00:00:00.
        说明时间没有成功读取到.猜测:没有成功初始化硬件,导致不能成功读取到时间

    <解决办法>
        使能rtc模块的时钟,在rtc-s3c.c文件的probe函数中,在使能RTC之前添加如下代码

    /*开始rtc时钟,使能rtc模块的时钟*/
    rtc_clk=clk_get(&pdev->dev, "rtc");
    clk_enable(rtc_clk);

    2.现象:一直读出来的数据位0,也设置不进去,
        原因:硬件问题.

    【代码跟踪】

    open

    app:  open("/dev/rtc0", O_RDONLY);
    ====================================
    vfs:  sys_open
       ...
       ...
    rtc-dev.c struct file_operations rtc_dev_fops
        .open  = rtc_dev_open,
         
         struct rtc_class_ops *ops = rtc->ops;
         err = ops->open ? ops->open(rtc->dev.parent) : 0;   //s3c_rtc_open
    rtc-s3c.c     s3c_rtc_open
             request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
              IRQF_DISABLED,  "s3c2410-rtc alarm", rtc_dev);
             request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
              IRQF_DISABLED,  "s3c2410-rtc tick", rtc_dev);

    RTC_SET_TIME

    app:ioctl(fd, RTC_SET_TIME, &time);
    ====================================
    vfs:  sys_ioctl
       ...
       ...
    rtc-dev.c struct file_operations rtc_dev_fops
        .unlocked_ioctl = rtc_dev_ioctl,
         struct rtc_class_ops *ops = rtc->ops;
          switch (cmd) {
           case RTC_SET_TIME:
            mutex_unlock(&rtc->ops_lock);
            /*从用户空间获取要设置的时间*/
            if (copy_from_user(&tm, uarg, sizeof(tm)))
             return -EFAULT;
            return rtc_set_time(rtc, &tm);
             if (rtc->ops->set_time)
               err = rtc->ops->set_time(rtc->dev.parent, tm);  //s3c_rtc_settime
          }
    rtc-s3c.c    s3c_rtc_settime
           int year = tm->tm_year - 100
           if (year < 0 || year >= 100) {
            dev_err(dev, "rtc only supports 100 years ");
            return -EINVAL;
           }
           writeb(bin2bcd(tm->tm_sec),  base + S3C2410_RTCSEC);
           writeb(bin2bcd(tm->tm_min),  base + S3C2410_RTCMIN);
           writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);
           writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
           writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
           writeb(bin2bcd(year), base + S3C2410_RTCYEAR);


    RTC_RD_TIME

    app:ioctl(fd, RTC_RD_TIME, &time);
    ====================================
    vfs:  sys_ioctl
       ...
       ...
    rtc-dev.c struct file_operations rtc_dev_fops
        .unlocked_ioctl = rtc_dev_ioctl,
         struct rtc_class_ops *ops = rtc->ops;
         switch (cmd) {
          case RTC_RD_TIME:
           mutex_unlock(&rtc->ops_lock);
           err = rtc_read_time(rtc, &tm);
             memset(tm, 0, sizeof(struct rtc_time));
              err = rtc->ops->read_time(rtc->dev.parent, tm);  //s3c_rtc_gettime
           if (err < 0)
            return err;
           if (copy_to_user(uarg, &tm, sizeof(tm)))
            err = -EFAULT;
           return err;
         }
    rtc-s3c.c   s3c_rtc_gettime
          rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);
          rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
          rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
          rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);
          rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
          rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);
          rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
          rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
          rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
          rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
          rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
          rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
          rtc_tm->tm_year += 100;
          rtc_tm->tm_mon -= 1;

    【linux设备驱动之rtc驱动开发】


      

    @成鹏致远(wwwlllll@126.com)





  • 相关阅读:
    eclipse 构建 jpa project 所需的用户库(vendor: EclipseLink)
    <mvc:resources mapping="/xxx/**" location="/xxx/"/>无效,可能和Controller的URL模式有关
    面向对象设计的基本原则
    MySql数据库时区异常,java.sql.SQLException: The server time zone value '?й???׼ʱ?' is unrecognized or represents more than one time zone.
    elasticsearch kibana + 分词器安装详细步骤
    neo4j企业版集群搭建
    Elasticsearchdump 数据导入/导出
    Hive环境搭建和SparkSql整合
    Hadoop 集群搭建和维护文档
    HBase 安装snappy压缩软件以及相关编码配置
  • 原文地址:https://www.cnblogs.com/lcw/p/3802597.html
Copyright © 2011-2022 走看看