027-Add-RTC-driver-support-on-MCF5441x-platform.patch 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. From 6462d09dad154b69ea6180c0acb2d009627ff1be Mon Sep 17 00:00:00 2001
  2. From: Alison Wang <[email protected]>
  3. Date: Thu, 4 Aug 2011 09:59:46 +0800
  4. Subject: [PATCH 27/52] Add RTC driver support on MCF5441x platform
  5. Support on-chip robust-RTC module on MCF5441x platform.
  6. Signed-off-by: Alison Wang <[email protected]>
  7. ---
  8. drivers/rtc/Kconfig | 9 +
  9. drivers/rtc/Makefile | 1 +
  10. drivers/rtc/rtc-m5441x.c | 638 ++++++++++++++++++++++++++++++++++++++++++++++
  11. 3 files changed, 648 insertions(+), 0 deletions(-)
  12. create mode 100644 drivers/rtc/rtc-m5441x.c
  13. --- a/drivers/rtc/Kconfig
  14. +++ b/drivers/rtc/Kconfig
  15. @@ -928,6 +928,15 @@ config RTC_MCF
  16. If you build it as a module it will be call mcf-rtc.
  17. +config RTC_M5441X
  18. + tristate "Freescale Coldfire M5441X platform Real Time Clock"
  19. + depends on COLDFIRE
  20. + help
  21. + If you say yes here you will get support for the on-chip Coldfire
  22. + Real-Time Clock for mcf5441x platform.
  23. +
  24. + If you build it as a module it will be call rtc-m5441x.
  25. +
  26. config RTC_DRV_PS3
  27. tristate "PS3 RTC"
  28. depends on PPC_PS3
  29. --- a/drivers/rtc/Makefile
  30. +++ b/drivers/rtc/Makefile
  31. @@ -103,3 +103,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm83
  32. obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
  33. obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
  34. obj-$(CONFIG_RTC_MCF) += rtc-mcf.o
  35. +obj-$(CONFIG_RTC_M5441X) += rtc-m5441x.o
  36. --- /dev/null
  37. +++ b/drivers/rtc/rtc-m5441x.c
  38. @@ -0,0 +1,638 @@
  39. +/*
  40. + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
  41. + *
  42. + * [email protected]
  43. + *
  44. + * The code contained herein is licensed under the GNU General Public
  45. + * License. You may obtain a copy of the GNU General Public License
  46. + * Version 2 or later at the following locations:
  47. + *
  48. + * http://www.opensource.org/licenses/gpl-license.html
  49. + * http://www.gnu.org/copyleft/gpl.html
  50. + */
  51. +
  52. +/*
  53. + * Implementation based on rtc-mcf.c
  54. + */
  55. +
  56. +/*
  57. + * RTC Real Time Clock (RTC) Driver
  58. + *
  59. + * @file rtc-m5441x.c
  60. + * @brief Real Time Clock interface
  61. + *
  62. + * This file contains Real Time Clock interface for Linux.
  63. + *
  64. + */
  65. +#include <linux/rtc.h>
  66. +#include <linux/module.h>
  67. +#include <linux/fs.h>
  68. +#include <linux/init.h>
  69. +#include <linux/interrupt.h>
  70. +#include <linux/platform_device.h>
  71. +#include <linux/clk.h>
  72. +#include <linux/uaccess.h>
  73. +#include <asm/mcfsim.h>
  74. +#include <linux/slab.h>
  75. +#include <linux/io.h>
  76. +
  77. +#ifdef readw
  78. +#undef readw
  79. +#endif
  80. +
  81. +#ifdef writew
  82. +#undef writew
  83. +#endif
  84. +
  85. +#define readw(addr) in_be16(addr)
  86. +#define writew(val, addr) out_be16((addr), (val))
  87. +
  88. +
  89. +#define PIT_ALL_ON (MCF_RTC_ISR_2HZ | MCF_RTC_ISR_SAM0 | MCF_RTC_ISR_SAM1 | \
  90. + MCF_RTC_ISR_SAM2 | MCF_RTC_ISR_SAM3 | MCF_RTC_ISR_SAM4 | \
  91. + MCF_RTC_ISR_SAM5 | MCF_RTC_ISR_SAM6 | MCF_RTC_ISR_SAM7)
  92. +
  93. +#define MAX_PIE_NUM 9
  94. +#define MAX_PIE_FREQ 512
  95. +const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
  96. + {2, MCF_RTC_ISR_2HZ},
  97. + {4, MCF_RTC_ISR_SAM0},
  98. + {8, MCF_RTC_ISR_SAM1},
  99. + {16, MCF_RTC_ISR_SAM2},
  100. + {32, MCF_RTC_ISR_SAM3},
  101. + {64, MCF_RTC_ISR_SAM4},
  102. + {128, MCF_RTC_ISR_SAM5},
  103. + {256, MCF_RTC_ISR_SAM6},
  104. + {MAX_PIE_FREQ, MCF_RTC_ISR_SAM7},
  105. +};
  106. +
  107. +/* Those are the bits from a classic RTC we want to mimic */
  108. +#define RTC_IRQF 0x80 /* any of the following 3 is active */
  109. +#define RTC_PF 0x40 /* Periodic interrupt */
  110. +#define RTC_AF 0x20 /* Alarm interrupt */
  111. +#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
  112. +
  113. +#define MCF_RTC_TIME 0
  114. +#define MCF_RTC_ALARM 1
  115. +
  116. +struct rtc_plat_data {
  117. + struct rtc_device *rtc;
  118. + int irq;
  119. + unsigned int irqen;
  120. + int alrm_sec;
  121. + int alrm_min;
  122. + int alrm_hour;
  123. + int alrm_mday;
  124. +};
  125. +
  126. +static const int year_cal_basic = 2112;
  127. +
  128. +#define RTC_VERSION "0.1"
  129. +
  130. +static u32 rtc_freq = 2; /* minimun value for PIE */
  131. +static unsigned long rtc_status;
  132. +
  133. +static struct rtc_time g_rtc_alarm = {
  134. + .tm_year = 0,
  135. + .tm_mon = 0,
  136. + .tm_mday = 0,
  137. + .tm_hour = 0,
  138. + .tm_mon = 0,
  139. + .tm_sec = 0,
  140. +};
  141. +
  142. +static DEFINE_SPINLOCK(rtc_lock);
  143. +
  144. +
  145. +/*
  146. + * This funciton is used to disable RTC register write protection
  147. + */
  148. +static void disable_register_write_protection(void)
  149. +{
  150. + if (readw(MCF_RTC_SR) & MCF_RTC_SR_WPE) {
  151. + writew(0x0000, MCF_RTC_CR);
  152. + writew(0x0001, MCF_RTC_CR);
  153. + writew(0x0003, MCF_RTC_CR);
  154. + writew(0x0002, MCF_RTC_CR);
  155. + }
  156. +
  157. +}
  158. +
  159. +/*
  160. + * This function is used to obtain the RTC time or the alarm value in
  161. + * second.
  162. + *
  163. + * @param time_alarm use MCF_RTC_TIME for RTC time value;
  164. + * MCF_RTC_ALARM for alarm value
  165. + *
  166. + * @return The RTC time or alarm time in second.
  167. + */
  168. +static u32 get_alarm_or_time(struct device *dev, int time_alarm,
  169. + struct rtc_time *tm)
  170. +{
  171. + dev_dbg(dev, "debug function %s()!\n", __func__);
  172. +
  173. + if (time_alarm == MCF_RTC_TIME) {
  174. + /*check register information */
  175. + dev_dbg(dev, "RTC_YEARMON:0x%x,RTC_DAYS:0x%x,RTC_HOURMIN:0x%x,"
  176. + "RTC_SECONDS:0x%x\n", readw(MCF_RTC_YEARMON),
  177. + readw(MCF_RTC_DAYS), readw(MCF_RTC_HOURMIN),
  178. + readw(MCF_RTC_SECONDS));
  179. +
  180. + /* get year */
  181. + tm->tm_year = year_cal_basic +
  182. + (char)(MCF_RTC_YEARMON_YEAR_RD(readw(MCF_RTC_YEARMON)));
  183. + /* get month */
  184. + tm->tm_mon =
  185. + MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_YEARMON)) - 1;
  186. + /* get month day */
  187. + tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_DAYS));
  188. + /* get year day */
  189. + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
  190. + tm->tm_year);
  191. + /* year minus 1900 */
  192. + tm->tm_year = tm->tm_year - 1900;
  193. + /* get week day */
  194. + tm->tm_wday = MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_DAYS));
  195. + /* get hours */
  196. + tm->tm_hour =
  197. + MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_HOURMIN));
  198. + /* get minutes */
  199. + tm->tm_min =
  200. + MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_HOURMIN));
  201. + /* get seconds */
  202. + tm->tm_sec =
  203. + MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_SECONDS));
  204. + /* no day saving time */
  205. + tm->tm_isdst = -1;
  206. +
  207. + /* check rtc_tm fileds information */
  208. + dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d,"
  209. + "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
  210. + tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
  211. + tm->tm_hour, tm->tm_min, tm->tm_sec);
  212. +
  213. + } else if (time_alarm == MCF_RTC_ALARM) {
  214. + tm->tm_year = year_cal_basic +
  215. + (char)MCF_RTC_YEARMON_YEAR_RD
  216. + (readw(MCF_RTC_ALRM_YRMON));
  217. + tm->tm_mon =
  218. + MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_ALRM_YRMON)) - 1;
  219. + tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_ALRM_DAYS));
  220. + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon,
  221. + tm->tm_year);
  222. + tm->tm_year = tm->tm_year - 1900;
  223. + tm->tm_wday =
  224. + MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_ALRM_DAYS));
  225. + tm->tm_hour =
  226. + MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_ALRM_HM));
  227. + tm->tm_min =
  228. + MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_ALRM_HM));
  229. + tm->tm_sec =
  230. + MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_ALRM_SEC));
  231. + tm->tm_isdst = -1;
  232. +
  233. + /* debug information */
  234. + dev_dbg(dev, "RTC ALARM --> year:%d,yday:%d,mon:%d,mday:%d,"
  235. + "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
  236. + tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
  237. + tm->tm_hour, tm->tm_min, tm->tm_sec);
  238. +
  239. + } else {
  240. + panic("wrong value for time_alarm=%d\n", time_alarm);
  241. + }
  242. +
  243. + return 0;
  244. +}
  245. +
  246. +/*
  247. + * This function sets the RTC alarm value or the time value.
  248. + *
  249. + * @param time_alarm the new alarm value to be updated in the RTC
  250. + * @param time use MCF_RTC_TIME for RTC time value;
  251. + * MCF_RTC_ALARM for alarm value
  252. + */
  253. +static void set_alarm_or_time(struct device *dev, int time_alarm,
  254. + struct rtc_time *tm)
  255. +{
  256. + char year;
  257. +
  258. + dev_dbg(dev, "debug function %s()!\n", __func__);
  259. +
  260. + /* wirte enable setting */
  261. + disable_register_write_protection();
  262. +
  263. + if (time_alarm == MCF_RTC_TIME) {
  264. + /* check rtc_time fields information */
  265. + dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d,"
  266. + "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year,
  267. + tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday,
  268. + tm->tm_hour, tm->tm_min, tm->tm_sec);
  269. +
  270. + year = ((tm->tm_year + 1900) - year_cal_basic);
  271. + /* write RTC_YEARMON register */
  272. + writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_YEARMON);
  273. +
  274. + /* write RTC_DAYS register */
  275. + writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) |
  276. + MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_DAYS);
  277. +
  278. + /* write RTC_HOURMIN register */
  279. + writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) |
  280. + MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min),
  281. + MCF_RTC_HOURMIN);
  282. +
  283. + /* write RTC_SECONDS register */
  284. + writew(MCF_RTC_SECONDS_SECONDS_SET
  285. + (tm->tm_sec), MCF_RTC_SECONDS);
  286. +
  287. + /* debug information */
  288. + dev_dbg(dev, "RTC_YEARMON:0x%x, RTC_DAYS:0x%x, "
  289. + "RTC_HOURMIN:0x%x, RTC_SECONDS:0x%x\n",
  290. + readw(MCF_RTC_YEARMON), readw(MCF_RTC_DAYS),
  291. + readw(MCF_RTC_HOURMIN), readw(MCF_RTC_SECONDS));
  292. + } else if (time_alarm == MCF_RTC_ALARM) {
  293. +
  294. + year = ((tm->tm_year + 1900) - year_cal_basic);
  295. + /* write RTC_YEARMON register */
  296. + writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_ALRM_YRMON);
  297. +
  298. + /* write RTC_DAYS register */
  299. + writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) |
  300. + MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_ALRM_DAYS);
  301. +
  302. + /* write RTC_HOURMIN register */
  303. + writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) |
  304. + MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min),
  305. + MCF_RTC_ALRM_HM);
  306. +
  307. + /* write RTC_SECONDS register */
  308. + writew(MCF_RTC_SECONDS_SECONDS_SET
  309. + (tm->tm_sec), MCF_RTC_ALRM_SEC);
  310. +
  311. + /* debug information */
  312. + dev_dbg(dev, "ALRM_YRMON:0x%x,ALRM_DAYS:0x%x,ALRM_HM:0x%x,"
  313. + "ALRM_SEC:0x%x\n", readw(MCF_RTC_ALRM_YRMON),
  314. + readw(MCF_RTC_ALRM_DAYS), readw(MCF_RTC_ALRM_HM),
  315. + readw(MCF_RTC_ALRM_SEC));
  316. + } else {
  317. + panic("wrong value for time_alarm=%d\n", time_alarm);
  318. + }
  319. +}
  320. +
  321. +/*!
  322. + * This function updates the RTC alarm registers and then clears all the
  323. + * interrupt status bits.
  324. + *
  325. + * @param alrm the new alarm value to be updated in the RTC
  326. + *
  327. + * @return 0 if successful; non-zero otherwise.
  328. + */
  329. +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
  330. +{
  331. + /* clear all the interrupt status bits */
  332. + disable_register_write_protection();
  333. +
  334. + writew(readw(MCF_RTC_ISR), MCF_RTC_ISR);
  335. +
  336. + set_alarm_or_time(dev, MCF_RTC_ALARM, alrm);
  337. +
  338. + return 0;
  339. +}
  340. +
  341. +/*!
  342. + * This function is the RTC interrupt service routine.
  343. + *
  344. + * @param irq RTC IRQ number
  345. + * @param dev_id device ID which is not used
  346. + *
  347. + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
  348. + */
  349. +static irqreturn_t mcf_rtc_interrupt(int irq, void *dev_id)
  350. +{
  351. + struct platform_device *pdev = dev_id;
  352. + struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
  353. + u16 status = 0;
  354. + u32 events = 0;
  355. +
  356. + spin_lock(&rtc_lock);
  357. +
  358. + /* clear interrupt sources */
  359. + status = readw(MCF_RTC_ISR) & readw(MCF_RTC_IER);
  360. +
  361. + disable_register_write_protection();
  362. +
  363. + writew(status, MCF_RTC_ISR);
  364. +
  365. + /* clear alarm interrupt if it has occurred */
  366. + if (status & MCF_RTC_ISR_ALM)
  367. + status &= ~MCF_RTC_ISR_ALM;
  368. +
  369. + /* update irq data & counter */
  370. + if (status & MCF_RTC_ISR_ALM)
  371. + events |= (RTC_AF | RTC_IRQF);
  372. + if (status & MCF_RTC_ISR_1HZ)
  373. + events |= (RTC_UF | RTC_IRQF);
  374. + if (status & PIT_ALL_ON)
  375. + events |= (RTC_PF | RTC_IRQF);
  376. +
  377. + if ((status & MCF_RTC_ISR_ALM) && rtc_valid_tm(&g_rtc_alarm))
  378. + rtc_update_alarm(&pdev->dev, &g_rtc_alarm);
  379. +
  380. + spin_unlock(&rtc_lock);
  381. + rtc_update_irq(pdata->rtc, 1, events);
  382. + return IRQ_HANDLED;
  383. +}
  384. +
  385. +/*!
  386. + * clear all interrupts and release the IRQ
  387. + */
  388. +static void mcf_rtc_release(struct device *dev)
  389. +{
  390. + spin_lock_irq(&rtc_lock);
  391. +
  392. + disable_register_write_protection();
  393. +
  394. + writew(0, MCF_RTC_IER); /* Disable all rtc interrupts */
  395. + writew(readw(MCF_RTC_ISR), MCF_RTC_ISR);
  396. + spin_unlock_irq(&rtc_lock);
  397. + rtc_status = 0;
  398. +}
  399. +
  400. +/*!
  401. + * This function is used to support some ioctl calls directly.
  402. + * Other ioctl calls are supported indirectly through the
  403. + * arm/common/rtctime.c file.
  404. + *
  405. + * @param cmd ioctl command as defined in include/linux/rtc.h
  406. + * @param arg value for the ioctl command
  407. + *
  408. + * @return 0 if successful or negative value otherwise.
  409. + */
  410. +static int mcf_rtc_ioctl(struct device *dev, unsigned int cmd,
  411. + unsigned long arg)
  412. +{
  413. + int i;
  414. +
  415. + disable_register_write_protection();
  416. +
  417. + switch (cmd) {
  418. + case RTC_PIE_OFF:
  419. + writew((readw(MCF_RTC_IER) & ~PIT_ALL_ON), MCF_RTC_IER);
  420. + return 0;
  421. + case RTC_IRQP_SET:
  422. + if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0)
  423. + return -EINVAL; /* Also make sure a power of 2Hz */
  424. + if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
  425. + return -EACCES;
  426. + rtc_freq = arg;
  427. + return 0;
  428. + case RTC_IRQP_READ:
  429. + return put_user(rtc_freq, (u32 *) arg);
  430. + case RTC_PIE_ON:
  431. + for (i = 0; i < MAX_PIE_NUM; i++) {
  432. + if (PIE_BIT_DEF[i][0] == rtc_freq)
  433. + break;
  434. + }
  435. + if (i == MAX_PIE_NUM)
  436. + return -EACCES;
  437. + spin_lock_irq(&rtc_lock);
  438. + writew((readw(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
  439. + spin_unlock_irq(&rtc_lock);
  440. + return 0;
  441. + case RTC_AIE_OFF:
  442. + spin_lock_irq(&rtc_lock);
  443. + writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
  444. + spin_unlock_irq(&rtc_lock);
  445. + return 0;
  446. +
  447. + case RTC_AIE_ON:
  448. + spin_lock_irq(&rtc_lock);
  449. + writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
  450. + spin_unlock_irq(&rtc_lock);
  451. + return 0;
  452. +
  453. + case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
  454. + spin_lock_irq(&rtc_lock);
  455. + writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER);
  456. + spin_unlock_irq(&rtc_lock);
  457. + return 0;
  458. +
  459. + case RTC_UIE_ON:
  460. + spin_lock_irq(&rtc_lock);
  461. + writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_1HZ), MCF_RTC_IER);
  462. + spin_unlock_irq(&rtc_lock);
  463. + return 0;
  464. + }
  465. + return -ENOIOCTLCMD;
  466. +}
  467. +
  468. +/*!
  469. + * This function reads the current RTC time into tm in Gregorian date.
  470. + *
  471. + * @param tm contains the RTC time value upon return
  472. + *
  473. + * @return 0 if successful; non-zero otherwise.
  474. + */
  475. +static int mcf_rtc_read_time(struct device *dev, struct rtc_time *tm)
  476. +{
  477. + do {
  478. + get_alarm_or_time(dev, MCF_RTC_TIME, tm);
  479. + } while (0);
  480. +
  481. + return 0;
  482. +}
  483. +
  484. +/*!
  485. + * This function sets the internal RTC time based on tm in Gregorian date.
  486. + *
  487. + * @param tm the time value to be set in the RTC
  488. + *
  489. + * @return 0 if successful; non-zero otherwise.
  490. + */
  491. +static int mcf_rtc_set_time(struct device *dev, struct rtc_time *tm)
  492. +{
  493. + do {
  494. + set_alarm_or_time(dev, MCF_RTC_TIME, tm);
  495. + } while (0);
  496. +
  497. + return 0;
  498. +}
  499. +
  500. +/*!
  501. + * This function reads the current alarm value into the passed in \b alrm
  502. + * argument. It updates the \b alrm's pending field value based on the whether
  503. + * an alarm interrupt occurs or not.
  504. + *
  505. + * @param alrm contains the RTC alarm value upon return
  506. + *
  507. + * @return 0 if successful; non-zero otherwise.
  508. + */
  509. +static int mcf_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  510. +{
  511. + do {
  512. + get_alarm_or_time(dev, MCF_RTC_ALARM, &alrm->time);
  513. + } while (0);
  514. +
  515. + alrm->pending = ((readw(MCF_RTC_ISR) & MCF_RTC_ISR_ALM) != 0) ? 1 : 0;
  516. +
  517. + return 0;
  518. +}
  519. +
  520. +/*!
  521. + * This function sets the RTC alarm based on passed in alrm.
  522. + *
  523. + * @param alrm the alarm value to be set in the RTC
  524. + *
  525. + * @return 0 if successful; non-zero otherwise.
  526. + */
  527. +static int mcf_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  528. +{
  529. + int ret;
  530. +
  531. + spin_lock_irq(&rtc_lock);
  532. +
  533. + disable_register_write_protection();
  534. +
  535. + if (rtc_valid_tm(&alrm->time)) {
  536. + if (alrm->time.tm_sec > 59 ||
  537. + alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
  538. + ret = -EINVAL;
  539. + goto out;
  540. + }
  541. + ret = rtc_update_alarm(dev, &alrm->time);
  542. + } else {
  543. + ret = rtc_valid_tm(&alrm->time);
  544. + if (ret)
  545. + goto out;
  546. + ret = rtc_update_alarm(dev, &alrm->time);
  547. + }
  548. +
  549. + if (ret == 0) {
  550. + memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
  551. +
  552. + if (alrm->enabled) {
  553. + writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM),
  554. + MCF_RTC_IER);
  555. + } else {
  556. + writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM),
  557. + MCF_RTC_IER);
  558. + }
  559. + }
  560. +out:
  561. + spin_unlock_irq(&rtc_lock);
  562. +
  563. + return ret;
  564. +}
  565. +
  566. +/*!
  567. + * The RTC driver structure
  568. + */
  569. +static struct rtc_class_ops mcf_rtc_ops = {
  570. + .ioctl = mcf_rtc_ioctl,
  571. + .read_time = mcf_rtc_read_time,
  572. + .set_time = mcf_rtc_set_time,
  573. + .read_alarm = mcf_rtc_read_alarm,
  574. + .set_alarm = mcf_rtc_set_alarm,
  575. +};
  576. +
  577. +static int __devinit mcf_rtc_probe(struct platform_device *pdev)
  578. +{
  579. + struct rtc_device *rtc;
  580. + struct rtc_plat_data *pdata = NULL;
  581. + u32 ret = 0;
  582. +
  583. + disable_register_write_protection();
  584. + /* Clear interrupt before request irq */
  585. + writew(0x0100, MCF_RTC_CR);
  586. + writew(0x0001, MCF_RTC_IER);
  587. +
  588. + if (!(readw(MCF_RTC_CFG_DATA) & MCF_RTC_CFG_DATA_OSCEN))
  589. + writew(MCF_RTC_CFG_DATA_OSCEN, MCF_RTC_CFG_DATA);
  590. +
  591. + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
  592. + if (!pdata)
  593. + return -ENOMEM;
  594. +
  595. + pdata->irq = MCFINT_VECBASE + MCFINT_RTC;
  596. + if (request_irq(pdata->irq, mcf_rtc_interrupt, IRQF_DISABLED,
  597. + pdev->name, pdev) < 0) {
  598. + dev_warn(&pdev->dev, "interrupt not available.\n");
  599. + pdata->irq = -1;
  600. + }
  601. +
  602. + if (test_and_set_bit(1, &rtc_status))
  603. + return -EBUSY;
  604. +
  605. + rtc = rtc_device_register(pdev->name, &pdev->dev, &mcf_rtc_ops,
  606. + THIS_MODULE);
  607. + if (IS_ERR(rtc)) {
  608. + ret = PTR_ERR(rtc);
  609. + if (pdata->irq >= 0)
  610. + free_irq(pdata->irq, pdev);
  611. + kfree(pdata);
  612. + return ret;
  613. + }
  614. + pdata->rtc = rtc;
  615. + platform_set_drvdata(pdev, pdata);
  616. +
  617. + dev_dbg(&pdev->dev, "RTC_CR:0x%x, RTC_SR:0x%x\n", readw(MCF_RTC_CR),
  618. + readw(MCF_RTC_SR));
  619. +
  620. + printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
  621. + return ret;
  622. +}
  623. +
  624. +static int __devexit mcf_rtc_remove(struct platform_device *pdev)
  625. +{
  626. + struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
  627. +
  628. + rtc_device_unregister(pdata->rtc);
  629. + if (pdata->irq >= 0)
  630. + free_irq(pdata->irq, pdev);
  631. + kfree(pdata);
  632. + mcf_rtc_release(NULL);
  633. + return 0;
  634. +}
  635. +
  636. +/*!
  637. + * Contains pointers to the power management callback functions.
  638. + */
  639. +MODULE_ALIAS("rtc-m5441x");
  640. +static struct platform_driver mcf_rtc_driver = {
  641. + .driver = {
  642. + .name = "rtc-m5441x",
  643. + .owner = THIS_MODULE,
  644. + },
  645. + .probe = mcf_rtc_probe,
  646. + .remove = __devexit_p(mcf_rtc_remove),
  647. +};
  648. +
  649. +/*!
  650. + * This function creates the /proc/driver/rtc file and registers the device RTC
  651. + * in the /dev/misc directory. It also reads the RTC value from external source
  652. + * and setup the internal RTC properly.
  653. + *
  654. + * @return -1 if RTC is failed to initialize; 0 is successful.
  655. + */
  656. +static int __init mcf_rtc_init(void)
  657. +{
  658. + return platform_driver_register(&mcf_rtc_driver);
  659. +}
  660. +
  661. +/*!
  662. + * This function removes the /proc/driver/rtc file and un-registers the
  663. + * device RTC from the /dev/misc directory.
  664. + */
  665. +static void __exit mcf_rtc_exit(void)
  666. +{
  667. + platform_driver_unregister(&mcf_rtc_driver);
  668. +
  669. +}
  670. +
  671. +module_init(mcf_rtc_init);
  672. +module_exit(mcf_rtc_exit);
  673. +
  674. +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
  675. +MODULE_DESCRIPTION("Real Time Clock Driver (MCF)");
  676. +MODULE_LICENSE("GPL V2");