【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\n");
        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)





posted @ 2014-06-22 15:29  Leo.cheng  阅读(1255)  评论(0编辑  收藏  举报