Twenty-one, RTC driver

A, RTC device driver analysis

Rtc kernel driver in the kernel drivers / rtc directory, which contains the RTC driver for each platform. Readers may choose a board driver file for analysis in this directory, I chose rtc-davinci.c file.

File link:

https://pan.baidu.com/s/1Yl5RyISOewi3_ZTZ-sY0Kw

Extraction code is: yp7d

 

First look at the init () function:

 1 static struct platform_driver davinci_rtc_driver = {
 2     .probe        = davinci_rtc_probe,
 3     .remove        = __devexit_p(davinci_rtc_remove),
 4     .driver        = {
 5         .name = "rtc_davinci",
 6         .owner = THIS_MODULE,
 7     },
 8 };
 9 
10 static int __init rtc_init(void)
11 {
12     return platform_driver_probe(&davinci_rtc_driver, davinci_rtc_probe);
13 }

It registers davinci_rtc_driver driver that corresponding device is defined in arch / arm / mach-davinci / dm365.c of:

 1 static struct resource dm365_rtc_resources[] = {
 2     {
 3         .start = DM365_RTC_BASE,
 4         .end = DM365_RTC_BASE + SZ_1K - 1,
 5         .flags = IORESOURCE_MEM,
 6     },
 7     {
 8         .start = IRQ_DM365_RTCINT,
 9         .flags = IORESOURCE_IRQ,
10     },
11 };
12 
13 static struct platform_device dm365_rtc_device = {
14     .name = "rtc_davinci",
15     .id = 0,
16     .num_resources = ARRAY_SIZE(dm365_rtc_resources),
17     .resource = dm365_rtc_resources,
18 };

 

probe () function call relationship is as follows:

davinci_rtc_probe
   -> davinci_rtc-> IRQ = platform_get_irq (PDEV, 0 );                 / * Get platform_device interrupt * / 
  -> = RES platform_get_resource (PDEV, IORESOURCE_MEM, 0 );         / * get memory address * / 
  -> MEM = request_mem_region (davinci_rtc- > pbase, davinci_rtc-> base_size, pdev-> name);
   -> davinci_rtc-> Base = ioremap (davinci_rtc-> pbase, davinci_rtc-> base_size);     / * register is mapped * / 
  / * Register RTC device * / 
  - > davinci_rtc-> RTC = rtc_device_register (pdev-> name, & pdev-> dev, & davinci_rtc_ops, THIS_MODULE);
     ->rtc = kzalloc(the sizeof ( struct rtc_device), GFP_KERNEL);
     -> RTC-> ID = ID;       / * set members rtc * / 
    -> RTC-> = OPS OPS;     / * this is the function of operating rtc * / 
    -> rtc_dev_prepare (rtc) ;
       -> cdev_init (& RTC-> char_dev, & rtc_dev_fops);      / * bind the file_operations * / 
    -> device_register (& RTC-> dev);
       -> device_add (dev);
     -> rtc_dev_add_device (RTC);     / * in / dev under Creating rtc file, add cdev to the system * / 
      -> cdev_add (rTC-&> char_dev, rTC-> dev.devt, 1 )
   -> rtcif_write (davinci_rtc,0, PRTCIF_INTEN);         / * Set Register * / 
  -> the request_irq (davinci_rtc-> IRQ, davinci_rtc_interrupt, 0 , " davinci_rtc " , davinci_rtc);     / * request interrupt * /

probe () function has made the following points:

1. Set the relevant register rtc

2. Assign, set up and register rtc_device

3. Assign, set up and register cdev

 

In rtc_device registration process, rtc_device bound struct rtc_class_ops davinci_rtc_ops

static  struct rtc_class_ops davinci_rtc_ops = { 
    .ioctl             = davinci_rtc_ioctl, 
    .read_time         = davinci_rtc_read_time,               / * read time * / 
    .set_time         = davinci_rtc_set_time,                 / * Set Time * / 
    .alarm_irq_enable     = davinci_rtc_alarm_irq_enable,     / * Interrupt Enable * / 
    .read_alarm         = davinci_rtc_read_alarm ,             / * read the alarm time * / 
    .set_alarm         = davinci_rtc_set_alarm,               / * set the alarm time*/
};

 

In cdev registration process, cdev bound struct file_operations rtc_dev_fops

static const struct file_operations rtc_dev_fops = {
    .owner        = THIS_MODULE,
    .llseek        = no_llseek,
    .read        = rtc_dev_read,
    .poll        = rtc_dev_poll,
    .unlocked_ioctl    = rtc_dev_ioctl,
    .open        = rtc_dev_open,
    .release    = rtc_dev_release,
    .fasync        = rtc_dev_fasync,
};

When we at the application layer open ( "/ dev / rtcx"), it calls rtc_dev_fops-> open ():

 1 static int rtc_dev_open(struct inode *inode, struct file *file)
 2 {
 3     int err;
 4     struct rtc_device *rtc = container_of(inode->i_cdev,
 5                     struct rtc_device, char_dev);
 6     const struct rtc_class_ops *ops = rtc->ops;
 7 ...
 8     err = ops->open ? ops->open(rtc->dev.parent) : 0;
 9 ...
10     return err;
11 }

open () function will eventually call struct rtc_class_ops davinci_rtc_ops the open () function, because the function davinci_rtc_ops not open, do not do this analysis ().

 

When we at the application layer open (after), the use of ioctl (int fd, unsigned long cmd, ...), it calls rtc_dev_fops-> ioctl ():

 1 static long rtc_dev_ioctl(struct file *file,
 2         unsigned int cmd, unsigned long arg)
 3 {
 4     int err = 0;
 5     struct rtc_device *rtc = file->private_data;
 6     const struct rtc_class_ops *ops = rtc->ops;        /* 获取rtc_class_ops */
 7     struct rtc_time tm;
 8     struct rtc_wkalrm alarm;
 9     void __user *uarg = (void __user *) arg;
10 
11     err = mutex_lock_interruptible(&rtc->ops_lock);
12 ...
13     switch (cmd) {
14 ...
15     case RTC_RD_TIME:
16         mutex_unlock(&rtc->ops_lock);
17 
18         err = rtc_read_time(rtc, &tm);
19         if (err < 0)
20             return err;
21 
22         if (copy_to_user(uarg, &tm, sizeof(tm)))
23             err = -EFAULT;
24         return err;
25 ...
26     }
27 
28 done:
29     mutex_unlock(&rtc->ops_lock);
30     return err;
31 }

In order to read this time (RTC_RD_TIME), for example, call the following relationship:

rtc_read_time(rtc, &tm);
  -> __rtc_read_time(rtc, tm);
    -> err = rtc->ops->read_time(rtc->dev.parent, tm)    /* davinci_rtc_read_time */
      -> tm->tm_sec = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_SEC));    /* 读数据 */
      -> day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY0);
      -> convertfromdays(days, tm)    /* 格式转换 */

 

Through two structure analysis, we can determine:

1. rtc_device-> cdev is an abstract rtc for interaction with the application layer

2. rtc_device-> ops is cdev-> ops underlying implementation, the operation completion time by write registers

 

 

Second, modify the kernel to support RTC

The implementation of the development board

# ls /dev/rtc*

There will be some development board can not find the character device, because the kernel only defines rtc platform device, but is not registered, so the platform and device driver does not match, so we need to modify the kernel of an array of registration or registration platform devices .

For itop4412, the kernel of its registered array in arch / arm / mach-exynos / Line 2740 mach-itop4412.c of.

1 static struct platform_device *smdk4x12_devices[] __initdata = {
2 ...
3     &s3c_device_rtc,
4 ...
5 };

We can see that it already contains the rtc device. If not, the reader needs to be added according to their own circumstances, and recompile the kernel programming.

 

For dm365.c previously used, it is directly registered () function register internet device init:

 1 static int __init dm365_init_devices(void)
 2 {
 3     if (!cpu_is_davinci_dm365())
 4         return 0;
 5 
 6     davinci_cfg_reg(DM365_INT_EDMA_CC);
 7     platform_device_register(&dm365_edma_device);
 8 
 9     platform_device_register(&dm365_mdio_device);
10     platform_device_register(&dm365_emac_device);
11     clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
12               NULL, &dm365_emac_device.dev);
13 
14     /* Add isif clock alias */
15     clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
16     platform_device_register(&dm365_vpss_device);
17     platform_device_register(&dm365_isif_dev);
18     platform_device_register(&vpfe_capture_dev);
19     return 0;
20 }

I can see he did not support rtc, so we can add the following code to make development board support rtc.

. 1 davinci_cfg_reg (DM365_INT_PRTCSS);               / * Configuration Pin Mux * / 
2 platform_device_register (& dm365_rtc_device);     / * registered internet device * /

Then recompile the kernel programming.

 

Next, we can operate the rtc.

There are two clocks in Linux: hardware clock (register clock) and a system clock (core clock)

Use hwclock can view the hardware clock, use the date command to view the system clock.

 

date command:

1. Check the system time

2. Check the system time format

% Y: Year, % m: month,% d: day,% H: when,% M: points,% S: seconds

3. Set the system time

Format:. Date month, day, hour in seconds

 

hwclock command:

Common Command parameters are as follows:

-r, - show: read and print the hardware clock

-s, - hctosys: the hardware clock is synchronized to the system clock

-w, - systohc: synchronize the system clock to hardware clock

FIG Use as follows:

 

Guess you like

Origin www.cnblogs.com/Lioker/p/11275621.html