text: /*
   * File      : rtc.c
   * This file is part of RT-Thread RTOS
   * COPYRIGHT (C) 2006, RT-Thread Development Team
   *
   * The license and distribution terms for this file may be
   * found in the file LICENSE in this distribution or at
   * http://openlab.rt-thread.com/license/LICENSE
   *
   * Change Logs:
   * Date           Author       Notes
   * 2009-04-26     yi.qiu       	first version
   * 2010-03-18     Gary Lee	add functions such as GregorianDay
   *                             		and rtc_time_to_tm
   * 2009-03-20     yi.qiu       	clean up
   */
  
  #include <rtthread.h>
  #include <time.h>
  #include <s3c24x0.h>
  
  // #define RTC_DEBUG
  
  #define RTC_ENABLE		RTCCON |=  0x01;	/*RTC read and write enable */
  #define RTC_DISABLE		RTCCON &= ~0x01;	/* RTC read and write disable */
  #define BCD2BIN(n)		(((((n) >> 4) & 0x0F) * 10) + ((n) & 0x0F))
  #define BIN2BCD(n)		((((n) / 10) << 4) | ((n) % 10))
  
  /**
   * This function get rtc time
   */
  void rt_hw_rtc_get(struct tm *ti)
  {
  	rt_uint8_t sec, min, hour, mday, wday, mon, year;
  
  	/* enable access to RTC registers */
  	RTCCON |= RTC_ENABLE;
  
  	/* read RTC registers */
  	do
  	{
  		sec 	= BCDSEC;
  		min 	= BCDMIN;
  		hour 	= BCDHOUR;
  		mday	= BCDDATE;
  		wday 	= BCDDAY;
  		mon 	= BCDMON;
  		year 	= BCDYEAR;
      } while (sec != BCDSEC);
  
  #ifdef RTC_DEBUG
  	rt_kprintf("sec:%x min:%x hour:%x mday:%x wday:%x mon:%x year:%x\n",
  		sec, min, hour, mday, wday, mon, year);
  #endif
  
  	/* disable access to RTC registers */
  	RTC_DISABLE
  
  	ti->tm_sec  	= BCD2BIN(sec  & 0x7F);
  	ti->tm_min  	= BCD2BIN(min  & 0x7F);
  	ti->tm_hour 	= BCD2BIN(hour & 0x3F);
  	ti->tm_mday 	= BCD2BIN(mday & 0x3F);
  	ti->tm_mon  	= BCD2BIN(mon & 0x1F);
  	ti->tm_year 	= BCD2BIN(year);
  	ti->tm_wday 	= BCD2BIN(wday & 0x07);
  	ti->tm_yday 	= 0;
  	ti->tm_isdst 	= 0;
  }
  
  /**
   * This function set rtc time
   */
  void rt_hw_rtc_set(struct tm *ti)
  {
  	rt_uint8_t sec, min, hour, mday, wday, mon, year;
  
  	year	= BIN2BCD(ti->tm_year);
  	mon 	= BIN2BCD(ti->tm_mon);
  	wday 	= BIN2BCD(ti->tm_wday);
  	mday 	= BIN2BCD(ti->tm_mday);
  	hour 	= BIN2BCD(ti->tm_hour);
  	min 	= BIN2BCD(ti->tm_min);
  	sec 	= BIN2BCD(ti->tm_sec);
  
  	/* enable access to RTC registers */
  	RTC_ENABLE
  
  	do{
  		/* write RTC registers */
  		BCDSEC 		= sec;
  		BCDMIN 		= min;
  		BCDHOUR 	= hour;
  		BCDDATE 	= mday;
  		BCDDAY 		= wday;
  		BCDMON 	= mon;
  		BCDYEAR 	= year;
  	}while (sec != BCDSEC);
  	
  	/* disable access to RTC registers */
  	RTC_DISABLE
  }
  
  /**
   * This function reset rtc
   */
  void rt_hw_rtc_reset (void)
  {
  	RTCCON = (RTCCON & ~0x06) | 0x08;
  	RTCCON &= ~(0x08|0x01);
  }
  
  static struct rt_device rtc;
  static rt_err_t rtc_open(rt_device_t dev, rt_uint16_t oflag)
  {
  	RTC_ENABLE
  	return RT_EOK;
  }
  
  static rt_err_t rtc_close(rt_device_t dev)
  {
  	RTC_DISABLE
  	return RT_EOK;
  }
  
  static rt_size_t rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
  {
  	return RT_EOK;
  }
  
  static rt_err_t rtc_control(rt_device_t dev, rt_uint8_t cmd, void *args)
  {
  	struct tm tm, *tm_ptr;
      time_t *time;
  	RT_ASSERT(dev != RT_NULL);
  
  	time = (time_t *)args;
  	switch (cmd)
  	{
  	case RT_DEVICE_CTRL_RTC_GET_TIME:
  		/* read device */
  		rt_hw_rtc_get(&tm);
  		*((rt_time_t *)args) = mktime(&tm);
  		break;
  
  	case RT_DEVICE_CTRL_RTC_SET_TIME:
  		tm_ptr = localtime(time);
  		/* write device */
  		rt_hw_rtc_set(tm_ptr);
  		break;
  	}
  
  	return RT_EOK;
  }
  
  void rt_hw_rtc_init(void)
  {
  	rtc.type	= RT_Device_Class_RTC;
  
  	/* register rtc device */
  	rtc.init 	= RT_NULL;
  	rtc.open 	= rtc_open;
  	rtc.close	= rtc_close;
  	rtc.read 	= rtc_read;
  	rtc.write	= RT_NULL;
  	rtc.control = rtc_control;
  	
  	/* no private */
  	rtc.user_data = RT_NULL;
  	
  	rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR);
  }
  
  #ifdef RT_USING_FINSH
  #include <finsh.h>
  void list_date()
  {
  	time_t time;
  	rt_device_t device;
  
  	device = rt_device_find("rtc");
  	if (device != RT_NULL)
  	{
  		rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time);
  
  		rt_kprintf("%d, %s\n", time, ctime(&time));
  	}
  }
  FINSH_FUNCTION_EXPORT(list_date, list date);
  #endif
  