• 【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)





  • 相关阅读:
    lintcode:数字三角形
    lintcode:Search Insert Position 搜索插入位置
    lintcode:搜索二维矩阵II
    lintcode :搜索二维矩阵
    Linux du命令详解
    Linux df命令详解
    Linux date命令详解
    Linux tcpdump命令详解
    Linux挂载共享命令
    Linux scp命令详解
  • 原文地址:https://www.cnblogs.com/lcw/p/3802597.html
Copyright © 2020-2023  润新知