S3C2440 rtc 平台设备驱动 卸载问题 oops


(1)rtc平台设备驱动源码如下,gzliu_2440_rtc.c:

相关的函数及结构体参见:

  1. #include <linux/module.h>   
  2. #include <linux/fs.h>   
  3. #include <linux/string.h>   
  4. #include <linux/init.h>   
  5. #include <linux/device.h>   
  6. #include <linux/interrupt.h>   
  7. #include <linux/rtc.h>   
  8. #include <linux/bcd.h>   
  9. #include <asm/hardware.h>   
  10. #include <asm/uaccess.h>   
  11. #include <asm/io.h>   
  12. #include <asm/irq.h>   
  13. #include <asm/rtc.h>   
  14. #include <asm/mach/time.h>   
  15. #include <asm/hardware/clock.h>   
  16. #include <asm/arch/regs-rtc.h>   
  17. // 包含RTC_AF的声明   
  18. #include <linux/mc146818rtc.h>   
  19.   
  20. #undef S3C24XX_VA_RTC   
  21. #define S3C24XX_VA_RTC s3c2440_rtc_base   
  22.   
  23. static struct resource *s3c2440_rtc_mem = NULL;  
  24.   
  25. static void __iomem *s3c2440_rtc_base = NULL;  
  26. static int s3c2440_rtc_alarm_irq = NO_IRQ;  
  27. static int s3c2440_rtc_tick_irq  = NO_IRQ;  
  28. static int s3c2440_rtc_freq    = 1;                     // rtc tick中断频率   
  29.   
  30. static DEFINE_SPINLOCK(s3c2440_rtc_pie_lock);  
  31.   
  32. static int s3c2440_rtc_proc(char *buf)  
  33. {  
  34.     unsigned int rtcalm = readb(S3C2410_RTCALM);  
  35.     unsigned int ticnt = readb (S3C2410_TICNT);  
  36.     char *p = buf;  
  37. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_proc()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  38.   
  39.     p += sprintf(p, "alarm_IRQ\t: %s\n", (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );  
  40.     p += sprintf(p, "periodic_IRQ\t: %s\n", (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );  
  41.     p += sprintf(p, "periodic_freq\t: %d\n", s3c2440_rtc_freq);  
  42.   
  43.     return p - buf;  
  44. }  
  45.   
  46. static int s3c2440_rtc_getalarm(struct rtc_wkalrm *alrm)  
  47. {  
  48.     struct rtc_time *alm_tm = &alrm->time;  
  49.     unsigned int alm_en;  
  50. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_getalarm()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  51.   
  52.     alm_tm->tm_sec  = readb(S3C2410_ALMSEC);  
  53.     alm_tm->tm_min  = readb(S3C2410_ALMMIN);  
  54.     alm_tm->tm_hour = readb(S3C2410_ALMHOUR);  
  55.     alm_tm->tm_mon  = readb(S3C2410_ALMMON);  
  56.     alm_tm->tm_mday = readb(S3C2410_ALMDATE);  
  57.     alm_tm->tm_year = readb(S3C2410_ALMYEAR);  
  58.   
  59.     alm_en = readb(S3C2410_RTCALM);  
  60.   
  61.     pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", alm_en, alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);  
  62.   
  63.   
  64.     /* decode the alarm enable field */  
  65.   
  66.     if (alm_en & S3C2410_RTCALM_SECEN)  
  67.     {  
  68.         BCD_TO_BIN(alm_tm->tm_sec);  
  69.     }  
  70.     else  
  71.     {  
  72.         alm_tm->tm_sec = 0xff;  
  73.     }  
  74.   
  75.     if (alm_en & S3C2410_RTCALM_MINEN)  
  76.     {  
  77.         BCD_TO_BIN(alm_tm->tm_min);  
  78.     }  
  79.     else  
  80.     {  
  81.         alm_tm->tm_min = 0xff;  
  82.     }  
  83.   
  84.     if (alm_en & S3C2410_RTCALM_HOUREN)  
  85.     {  
  86.         BCD_TO_BIN(alm_tm->tm_hour);  
  87.     }  
  88.     else  
  89.     {  
  90.         alm_tm->tm_hour = 0xff;  
  91.     }  
  92.   
  93.     if (alm_en & S3C2410_RTCALM_DAYEN)  
  94.     {  
  95.         BCD_TO_BIN(alm_tm->tm_mday);  
  96.     }  
  97.     else  
  98.     {  
  99.         alm_tm->tm_mday = 0xff;  
  100.     }  
  101.   
  102.     if (alm_en & S3C2410_RTCALM_MONEN)  
  103.     {  
  104.         BCD_TO_BIN(alm_tm->tm_mon);  
  105.         alm_tm->tm_mon -= 1;  
  106.     }  
  107.     else  
  108.     {  
  109.         alm_tm->tm_mon = 0xff;  
  110.     }  
  111.   
  112.     if (alm_en & S3C2410_RTCALM_YEAREN)  
  113.     {  
  114.         BCD_TO_BIN(alm_tm->tm_year);  
  115.     }  
  116.     else  
  117.     {  
  118.         alm_tm->tm_year = 0xffff;  
  119.     }  
  120.   
  121.     /* todo - set alrm->enabled ? */  
  122.   
  123.     return 0;  
  124.       
  125. }/* s3c2440_rtc_getalarm(struct rtc_wkalrm *alrm) */  
  126.   
  127. static int s3c2440_rtc_setalarm(struct rtc_wkalrm *alrm)  
  128. {  
  129.     struct rtc_time *tm = &alrm->time;  
  130.     unsigned int alrm_en;  
  131. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_setalarm()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  132.   
  133.     pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", alrm->enabled, tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);  
  134.   
  135.     if (alrm->enabled || 1)  
  136.     {  
  137.         alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;  
  138.         writeb(0x00, S3C2410_RTCALM);  
  139.   
  140.         if (tm->tm_sec < 60 && tm->tm_sec >= 0)  
  141.         {  
  142.             alrm_en |= S3C2410_RTCALM_SECEN;  
  143.             writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);  
  144.         }  
  145.   
  146.         if (tm->tm_min < 60 && tm->tm_min >= 0)  
  147.         {  
  148.             alrm_en |= S3C2410_RTCALM_MINEN;  
  149.             writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);  
  150.         }  
  151.   
  152.         if (tm->tm_hour < 24 && tm->tm_hour >= 0)  
  153.         {  
  154.             alrm_en |= S3C2410_RTCALM_HOUREN;  
  155.             writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);  
  156.         }  
  157.   
  158.         pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);  
  159.   
  160.         writeb(alrm_en, S3C2410_RTCALM);  
  161.         enable_irq_wake(s3c2440_rtc_alarm_irq);  
  162.     }  
  163.     else  
  164.     {  
  165.         alrm_en = readb(S3C2410_RTCALM);  
  166.         alrm_en &= ~S3C2410_RTCALM_ALMEN;  
  167.         writeb(alrm_en, S3C2410_RTCALM);  
  168.         disable_irq_wake(s3c2440_rtc_alarm_irq);  
  169.     }  
  170.   
  171.     return 0;  
  172.       
  173. }/* s3c2440_rtc_setalarm(struct rtc_wkalrm *alrm) */  
  174.   
  175. /* Time read/write */  
  176. static int s3c2440_rtc_gettime(struct rtc_time *rtc_tm)  
  177. {  
  178.     unsigned int have_retried = 0;  
  179. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_gettime()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  180.   
  181. retry_get_time:  
  182.     rtc_tm->tm_min  = readb(S3C2410_RTCMIN);  
  183.     rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);  
  184.     rtc_tm->tm_mday = readb(S3C2410_RTCDATE);  
  185.     rtc_tm->tm_mon  = readb(S3C2410_RTCMON);  
  186.     rtc_tm->tm_year = readb(S3C2410_RTCYEAR);  
  187.     rtc_tm->tm_sec  = readb(S3C2410_RTCSEC);  
  188.   
  189.     /* the only way to work out wether the system was mid-update 
  190.      * when we read it is to check the second counter, and if it 
  191.      * is zero, then we re-try the entire read 
  192.      */  
  193.   
  194.     if (rtc_tm->tm_sec == 0 && !have_retried)  
  195.     {  
  196.         have_retried = 1;  
  197.         goto retry_get_time;  
  198.     }  
  199.       
  200.     pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);  
  201.   
  202. printk("before BCD_TO_BIN: %d-%d-%d %d:%d:%d\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);  
  203.     BCD_TO_BIN(rtc_tm->tm_sec);  
  204.     BCD_TO_BIN(rtc_tm->tm_min);  
  205.     BCD_TO_BIN(rtc_tm->tm_hour);  
  206.     BCD_TO_BIN(rtc_tm->tm_mday);  
  207.     BCD_TO_BIN(rtc_tm->tm_mon);  
  208.     BCD_TO_BIN(rtc_tm->tm_year);  
  209. printk("after BCD_TO_BIN: %d-%d-%d %d:%d:%d\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);  
  210.   
  211.         // 要保证rtc_tm->tm_year + 1900 == 2011年,rtc_tm->tm_mon + 1 == 8月   
  212.     rtc_tm->tm_year += 100;  
  213.     rtc_tm->tm_mon -= 1;  
  214.   
  215.     return 0;  
  216.       
  217. }/* s3c2440_rtc_gettime(struct rtc_time *rtc_tm) */  
  218.   
  219. static int s3c2440_rtc_settime(struct rtc_time *tm)  
  220. {  
  221. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_settime()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  222.     /* the rtc gets round the y2k problem by just not supporting it */  
  223.   
  224.     if (tm->tm_year < 100)  
  225.         return -EINVAL;  
  226. printk("before BIN2BCD: %d-%d-%d %d:%d:%d\n"tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);  
  227.     writeb(BIN2BCD(tm->tm_sec),  S3C2410_RTCSEC);  
  228.     writeb(BIN2BCD(tm->tm_min),  S3C2410_RTCMIN);  
  229.     writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);  
  230.     writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);  
  231.     writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);  
  232.     writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);  
  233.   
  234.     return 0;  
  235. }  
  236.   
  237. /* Update control registers */  
  238. static void s3c2440_rtc_setaie(int to)  
  239. {  
  240.     unsigned int tmp;  
  241. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_setaie()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  242.   
  243.     pr_debug("%s: aie=%d\n", __FUNCTION__, to);  
  244.   
  245.     tmp = readb(S3C2410_RTCALM);  
  246.   
  247.     if (to)  
  248.     {  
  249.         tmp |= S3C2410_RTCALM_ALMEN;  
  250.     }  
  251.     else  
  252.     {  
  253.         tmp &= ~S3C2410_RTCALM_ALMEN;  
  254.     }  
  255.   
  256.   
  257.     writeb(tmp, S3C2410_RTCALM);  
  258. }  
  259.   
  260. static void s3c2440_rtc_setfreq(int freq)  
  261. {  
  262.     unsigned int tmp;  
  263. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_setfreq()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  264.   
  265.     spin_lock_irq(&s3c2440_rtc_pie_lock);  
  266.     tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;  
  267.   
  268.     s3c2440_rtc_freq = freq;  
  269.       
  270.     tmp |= (128 / freq)-1;  
  271.   
  272.     writeb(tmp, S3C2410_TICNT);  
  273.     spin_unlock_irq(&s3c2440_rtc_pie_lock);  
  274.       
  275. }/* s3c2440_rtc_setfreq(int freq) */  
  276.   
  277. static void s3c2440_rtc_setpie(int to)  
  278. {  
  279.     unsigned int tmp;  
  280. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_setpie()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  281.   
  282.     pr_debug("%s: pie=%d\n", __FUNCTION__, to);  
  283.   
  284.     spin_lock_irq(&s3c2440_rtc_pie_lock);  
  285.     tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;  
  286.   
  287.     if (to)  
  288.     {  
  289.         tmp |= S3C2410_TICNT_ENABLE;  
  290.     }  
  291.       
  292.     writeb(tmp, S3C2410_TICNT);  
  293.     spin_unlock_irq(&s3c2440_rtc_pie_lock);  
  294. }  
  295.   
  296. static int s3c2440_rtc_ioctl(unsigned int cmd, unsigned long arg)  
  297. {  
  298. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_ioctl()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  299.     switch (cmd)  
  300.     {  
  301.         case RTC_AIE_OFF:  
  302.         case RTC_AIE_ON:  
  303.             s3c2440_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);  
  304.             return 0;  
  305.   
  306.         case RTC_PIE_OFF:  
  307.         case RTC_PIE_ON:  
  308.             s3c2440_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);  
  309.             return 0;  
  310.   
  311.         case RTC_IRQP_READ:  
  312.             return put_user(s3c2440_rtc_freq, (unsigned long __user *)arg);  
  313.       
  314.         case RTC_IRQP_SET:  
  315.             if (arg < 1 || arg > 64)  
  316.                 return -EINVAL;  
  317.       
  318.             if (!capable(CAP_SYS_RESOURCE))  
  319.                 return -EACCES;  
  320.       
  321.             /* check for power of 2 */  
  322.   
  323.             if ((arg & (arg-1)) != 0)  
  324.                 return -EINVAL;  
  325.   
  326.             pr_debug("s3c2440_rtc: setting frequency %ld\n", arg);  
  327.       
  328.             s3c2440_rtc_setfreq(arg);  
  329.             return 0;  
  330.   
  331.         case RTC_UIE_ON:  
  332.         case RTC_UIE_OFF:  
  333.             return -EINVAL;  
  334.               
  335.     }/* switch (cmd) */  
  336.   
  337.     return -EINVAL;  
  338.       
  339. }/* s3c2440_rtc_ioctl(unsigned int cmd, unsigned long arg) */  
  340.   
  341. static irqreturn_t s3c2440_rtc_alarmirq(int irq, void *id, struct pt_regs *r)  
  342. {  
  343. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_alarmirq()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  344.     rtc_update(1, RTC_AF | RTC_IRQF);  
  345.     return IRQ_HANDLED;  
  346. }  
  347.   
  348. static irqreturn_t s3c2440_rtc_tickirq(int irq, void *id, struct pt_regs *r)  
  349. {  
  350. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_tickirq()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  351.     rtc_update(1, RTC_PF | RTC_IRQF);  
  352.     return IRQ_HANDLED;  
  353. }  
  354.   
  355. static int s3c2440_rtc_open(void)  
  356. {  
  357.     int ret;  
  358. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_open()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  359.   
  360.     ret = request_irq(s3c2440_rtc_alarm_irq, s3c2440_rtc_alarmirq, SA_INTERRUPT,  "s3c2440-rtc alarm", NULL);  
  361.     if (ret)  
  362.     {  
  363.         printk(KERN_ERR "IRQ%d already in use\n", s3c2440_rtc_alarm_irq);  
  364.     }  
  365.       
  366.     ret = request_irq(s3c2440_rtc_tick_irq, s3c2440_rtc_tickirq, SA_INTERRUPT,  "s3c2440-rtc tick", NULL);  
  367.     if (ret)  
  368.     {  
  369.         printk(KERN_ERR "IRQ%d already in use\n", s3c2440_rtc_tick_irq);  
  370.         goto tick_err;  
  371.     }  
  372.   
  373.     return ret;  
  374.   
  375. tick_err:  
  376.     free_irq(s3c2440_rtc_alarm_irq, NULL);  
  377.     return ret;  
  378.       
  379. }/* s3c2440_rtc_open(void) */  
  380.   
  381. static void s3c2440_rtc_release(void)  
  382. {  
  383. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_release()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  384.     /* do not clear AIE here, it may be needed for wake */  
  385.   
  386.     s3c2440_rtc_setpie(0);  
  387.     free_irq(s3c2440_rtc_alarm_irq, NULL);  
  388.     free_irq(s3c2440_rtc_tick_irq, NULL);  
  389. }  
  390.   
  391. static struct rtc_ops s3c2440_rtcops =   
  392. {  
  393.     .owner      = THIS_MODULE,  
  394.     .open       = s3c2440_rtc_open,  
  395.     .release    = s3c2440_rtc_release,  
  396.     .ioctl      = s3c2440_rtc_ioctl,  
  397.     .read_time  = s3c2440_rtc_gettime,  
  398.     .set_time   = s3c2440_rtc_settime,  
  399.     .read_alarm = s3c2440_rtc_getalarm,  
  400.     .set_alarm  = s3c2440_rtc_setalarm,  
  401.     .proc       = s3c2440_rtc_proc,  
  402. };  
  403.   
  404. static void s3c2440_rtc_enable(struct device *dev, int en)  
  405. {  
  406.     unsigned int tmp;  
  407. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_enable()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  408.   
  409.     if (s3c2440_rtc_base == NULL)  
  410.     {  
  411.         return;  
  412.     }  
  413.       
  414.     if (!en)  
  415.     {  
  416.         tmp = readb(S3C2410_RTCCON);  
  417.         writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);  
  418.   
  419.         tmp = readb(S3C2410_TICNT);  
  420.         writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);  
  421.     }  
  422.     else  
  423.     {  
  424.         /* re-enable the device, and check it is ok */  
  425.           
  426.         if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0)  
  427.         {  
  428.             dev_info(dev, "rtc disabled, re-enabling\n");  
  429.   
  430.             tmp = readb(S3C2410_RTCCON);  
  431.             writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);  
  432.         }  
  433.   
  434.         if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL))  
  435.         {  
  436.             dev_info(dev, "removing S3C2410_RTCCON_CNTSEL\n");  
  437.   
  438.             tmp = readb(S3C2410_RTCCON);  
  439.             writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);  
  440.         }  
  441.   
  442.         if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST))  
  443.         {  
  444.             dev_info(dev, "removing S3C2410_RTCCON_CLKRST\n");  
  445.   
  446.             tmp = readb(S3C2410_RTCCON);  
  447.             writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);  
  448.         }  
  449.     }  
  450.       
  451. }/* s3c2440_rtc_enable(struct device *dev, int en) */  
  452.   
  453. static int s3c2440_rtc_probe(struct device *dev)  
  454. {  
  455.     struct platform_device *pdev = to_platform_device(dev);  
  456.     struct resource *res;  
  457.     int ret;  
  458. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_probe()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  459.       
  460.     pr_debug("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);  
  461.       
  462.     /* find the IRQs */  
  463.     /*  
  464.     * platform_get_irq()原型: 
  465.     * 文件 drivers/base/platform.c 
  466.         * int platform_get_irq(struct platform_device *dev, unsigned int num) 
  467.         * { 
  468.      *     struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 
  469.         * 
  470.      *     return r ? r->start : 0; 
  471.         * } 
  472.          
  473.         * 其中platform_get_resource(dev, IORESOURCE_IRQ, num)获取第num个flags与IORESOURCE_IRQ匹配的资源, 
  474.         * rtc资源结构体如下,num为1与[2]对应,num为0与[1]对应。 
  475.          
  476.         * 文件 arch/arm/mach-s3c2410/devs.c 
  477.         * static struct resource s3c_rtc_resource[] = { 
  478.      * [0] = { 
  479.      *      .start = S3C2410_PA_RTC, 
  480.         *      .end   = S3C2410_PA_RTC + 0xff, 
  481.         *      .flags = IORESOURCE_MEM, 
  482.      *  }, 
  483.      *  [1] = { 
  484.      *      .start = IRQ_RTC, 
  485.              .end   = IRQ_RTC, 
  486.              .flags = IORESOURCE_IRQ, 
  487.         *  }, 
  488.         *  [2] = { 
  489.      *        .start = IRQ_TICK, 
  490.         *        .end   = IRQ_TICK, 
  491.         *        .flags = IORESOURCE_IRQ 
  492.         *   } 
  493.         * }; 
  494.          
  495.          * 也可直接使用IRQ_RTC,IRQ_TICK对s3c2440_rtc_alarm_irq和s3c2440_rtc_tick_irq赋值。 
  496.     */  
  497.     s3c2440_rtc_tick_irq = platform_get_irq(pdev, 1);  
  498.     if (s3c2440_rtc_tick_irq <= 0)  
  499.     {  
  500.         dev_err(dev, "no irq for rtc tick\n");  
  501.         return -ENOENT;  
  502.     }  
  503.   
  504.     s3c2440_rtc_alarm_irq = platform_get_irq(pdev, 0);  
  505.     if (s3c2440_rtc_alarm_irq <= 0)  
  506.     {  
  507.         dev_err(dev, "no irq for alarm\n");  
  508.         return -ENOENT;  
  509.     }  
  510.   
  511.     pr_debug("s3c2440_rtc: tick irq %d, alarm irq %d\n", s3c2440_rtc_tick_irq, s3c2440_rtc_alarm_irq);  
  512.   
  513.     /* get the memory region */  
  514.     /* 
  515.     * 文件 include/linux/ioport.h 
  516.     * resource结构体的定义: 
  517.         * struct resource { 
  518.         * const char *name; 
  519.         * unsigned long start, end; 
  520.         * unsigned long flags; 
  521.         * struct resource *parent, *sibling, *child; 
  522.         * }; 
  523.          
  524.         * platform_get_resource()函数原型: 
  525.         * 文件 drivers/base/platform.c 
  526.         * struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) 
  527.         * { 
  528.         *   int i; 
  529.  
  530.         *    for (i = 0; i < dev->num_resources; i++) { 
  531.         *    struct resource *r = &dev->resource[i]; 
  532.  
  533.         *    if ((r->flags & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_IRQ | IORESOURCE_DMA)) == type) 
  534.         *               if (num-- == 0) 
  535.         *                    return r; 
  536.         *    } 
  537.         *    return NULL; 
  538.         * } 
  539.     */  
  540.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  541.     if (res == NULL)  
  542.     {  
  543.         dev_err(dev, "failed to get memory region resource\n");  
  544.         return -ENOENT;  
  545.     }  
  546.   
  547.         /* 
  548.         * 文件 include/linux/ioport.h 
  549.         * #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) 
  550.          
  551.         * 其中的iomem_resource: 
  552.         * 文件 kernel/resource.c 
  553.         * struct resource iomem_resource = { 
  554.         *    .name  = "PCI mem", 
  555.         *    .start = 0UL, 
  556.         *    .end   = ~0UL, 
  557.         *    .flags = IORESOURCE_MEM, 
  558.         * }; 
  559.          
  560.          
  561.         */  
  562.     s3c2440_rtc_mem = request_mem_region(res->start, res->end-res->start+1, pdev->name);  
  563.   
  564.     if (s3c2440_rtc_mem == NULL)  
  565.     {  
  566.         dev_err(dev, "failed to reserve memory region\n");  
  567.         ret = -ENOENT;  
  568.         goto exit_err;  
  569.     }  
  570.       
  571.     s3c2440_rtc_base = ioremap(res->start, res->end - res->start + 1);  
  572.     if (s3c2440_rtc_base == NULL)  
  573.     {  
  574.         dev_err(dev, "failed ioremap()\n");  
  575.         ret = -EINVAL;  
  576.         goto exit_err;  
  577.     }  
  578.       
  579.     // 是用linux源码中的s3c2410-rtc.c移植的,不知道为什么要写这么一行,没看出有什么用。   
  580.         //s3c2440_rtc_mem = res;   
  581.         // 导致卸载时出现"Internal error: Oops: 13 [#1]"   
  582.           
  583.     pr_debug("s3c2440_rtc_base=%p\n", s3c2440_rtc_base);  
  584.   
  585.     pr_debug("s3c2440_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));  
  586.       
  587.     /* check to see if everything is setup correctly */  
  588.     s3c2440_rtc_enable(dev, 1);  
  589.       
  590.     pr_debug("s3c2440_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));  
  591.   
  592.        /* 
  593.         
  594.        * s3c2440a手册中描述: 
  595.        * TICK TIME INTERRUPT 
  596.        * The RTC tick time is used for interrupt request. The TICNT register has an interrupt enable bit and the count value for 
  597.        * the interrupt. The count value reaches '0' when the tick time interrupt occurs. Then the period of interrupt is as 
  598.        * follows: 
  599.        * — Period = ( n+1 ) / 128 second 
  600.        * — n: Tick time count value (1~127) 
  601.         
  602.        * 此函数将rtc的tick中断时间间隔设置为:(1/s3c2440_rtc_freq)second,即1s 
  603.        */  
  604.     s3c2440_rtc_setfreq(s3c2440_rtc_freq);  
  605.       
  606.     // 注册rtc设备,并且创建/proc中的节点,将s3c2440_rtc_proc与该节点绑定。   
  607.     register_rtc(&s3c2440_rtcops);  
  608.     return 0;  
  609.       
  610. exit_err:  
  611.     dev_err(dev, "error %d during initialisation\n", ret);  
  612.           
  613.     return ret;  
  614.       
  615. }/* s3c2440_rtc_probe(struct device *dev) */  
  616.   
  617. static int s3c2440_rtc_remove(struct device *dev)  
  618. {  
  619. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_remove()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  620.     unregister_rtc(&s3c2440_rtcops);  
  621.   
  622.        // 0 - disable tick time interrupt   
  623.     s3c2440_rtc_setpie(0);  
  624.       
  625.     // 0 - disable alarm   
  626.     s3c2440_rtc_setaie(0);  
  627.   
  628.     if (s3c2440_rtc_mem != NULL)  
  629.     {  
  630.         pr_debug("s3c2440_rtc: releasing s3c2440_rtc_mem\n");  
  631.         iounmap(s3c2440_rtc_base);  
  632.         release_resource(s3c2440_rtc_mem);  
  633.         kfree(s3c2440_rtc_mem);  
  634.     }  
  635.   
  636.     return 0;  
  637. }  
  638.   
  639. #ifdef CONFIG_PM   
  640.   
  641. /* S3C2440 RTC 电源管理控制 */  
  642.   
  643. static struct timespec s3c2440_rtc_delta;  
  644. static int ticnt_save;  
  645.   
  646. static int s3c2440_rtc_suspend(struct device *dev, pm_message_t state, u32 level)  
  647. {  
  648.     struct rtc_time tm;  
  649.     struct timespec time;  
  650. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_suspend()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  651.   
  652.     time.tv_nsec = 0;  
  653.   
  654.     if (level == SUSPEND_POWER_DOWN)  
  655.     {  
  656.         /* save TICNT for anyone using periodic interrupts */  
  657.   
  658.         ticnt_save = readb(S3C2410_TICNT);  
  659.   
  660.         /* calculate time delta for suspend */  
  661.   
  662.         s3c2440_rtc_gettime(&tm);  
  663.         rtc_tm_to_time(&tm, &time.tv_sec);  
  664.         save_time_delta(&s3c2440_rtc_delta, &time);  
  665.         s3c2440_rtc_enable(dev, 0);  
  666.     }  
  667.   
  668.     return 0;  
  669. }  
  670.   
  671. static int s3c2440_rtc_resume(struct device *dev, u32 level)  
  672. {  
  673.     struct rtc_time tm;  
  674.     struct timespec time;  
  675. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_resume()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  676.   
  677.     time.tv_nsec = 0;  
  678.   
  679.     s3c2440_rtc_enable(dev, 1);  
  680.     s3c2440_rtc_gettime(&tm);  
  681.     rtc_tm_to_time(&tm, &time.tv_sec);  
  682.     restore_time_delta(&s3c2440_rtc_delta, &time);  
  683.   
  684.     writeb(ticnt_save, S3C2410_TICNT);  
  685.     return 0;  
  686. }  
  687. #else   
  688. #define s3c2440_rtc_suspend NULL   
  689. #define s3c2440_rtc_resume  NULL   
  690. #endif   
  691.   
  692. static struct device_driver s3c2440_rtcdrv =   
  693. {  
  694.     .name       = "s3c2440-rtc",  
  695.     .bus        = &platform_bus_type,  
  696.     .probe      = s3c2440_rtc_probe,  
  697.     .remove     = s3c2440_rtc_remove,  
  698.     .suspend    = s3c2440_rtc_suspend,  
  699.     .resume     = s3c2440_rtc_resume,  
  700. };  
  701.   
  702. static int __init s3c2440_rtc_init(void)  
  703. {  
  704. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_init()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  705.     return driver_register(&s3c2440_rtcdrv);  
  706. }  
  707.   
  708. static void __exit s3c2440_rtc_exit(void)  
  709. {  
  710. printk("@@@@@@@@@@@@@@@@@@@@@@\ngzliu s3c2440_rtc_exit()\n@@@@@@@@@@@@@@@@@@@@@@@@\n");  
  711.     driver_unregister(&s3c2440_rtcdrv);  
  712. }  
  713.   
  714. module_init(s3c2440_rtc_init);  
  715. module_exit(s3c2440_rtc_exit);  
  716.   
  717. MODULE_DESCRIPTION("S3C2440 RTC Driver");  
  718. MODULE_AUTHOR("gzLiu, <gzliu_hit@qq.com>");  
  719. MODULE_LICENSE("GPL");  

(2)编译成模块形式,加载没问题,卸载时出现如下问题:


(3)经检查源码,发现问题处在上面源码中580行,注释掉就好了。

  • 1
  • 2
  • 下一页

相关内容