2 * Copyright (c) 2012 Maurizio Lombardi
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * @defgroup CMOS RTC driver.
31 * @brief HelenOS RTC driver.
40 #include <libarch/ddi.h>
42 #include <ddf/driver.h>
44 #include <ops/clock_dev.h>
45 #include <fibril_synch.h>
46 #include <device/hw_res.h>
48 #include <ipc/clock_ctl.h>
50 #include "cmos-regs.h"
52 #define NAME "cmos-rtc"
56 #define RTC_FROM_FNODE(fnode) ((rtc_t *) ((fnode)->dev->driver_data))
57 #define RTC_FROM_DEV(devnode) ((rtc_t *) ((devnode)->driver_data))
60 /** DDF device node */
62 /** DDF function node */
64 /** The fibril mutex for synchronizing the access to the device */
66 /** The base I/O address of the device registers */
68 /** The I/O port used to access the CMOS registers */
70 /** true if a client is connected to the device */
71 bool client_connected
;
72 /** true if device is removed */
77 static int rtc_time_get(ddf_fun_t
*fun
, struct tm
*t
);
78 static int rtc_time_set(ddf_fun_t
*fun
, struct tm
*t
);
79 static int rtc_dev_add(ddf_dev_t
*dev
);
80 static int rtc_dev_initialize(rtc_t
*rtc
);
81 static bool rtc_pio_enable(rtc_t
*rtc
);
82 static void rtc_dev_cleanup(rtc_t
*rtc
);
83 static int rtc_open(ddf_fun_t
*fun
);
84 static void rtc_close(ddf_fun_t
*fun
);
85 static bool rtc_update_in_progress(rtc_t
*rtc
);
86 static int rtc_register_read(rtc_t
*rtc
, int reg
);
87 static unsigned bcd2bin(unsigned bcd
);
88 static unsigned bin2bcd(unsigned binary
);
89 static void rtc_default_handler(ddf_fun_t
*fun
,
90 ipc_callid_t callid
, ipc_call_t
*call
);
91 static int rtc_dev_remove(ddf_dev_t
*dev
);
92 static int rtc_tm_sanity_check(struct tm
*t
);
93 static void rtc_register_write(rtc_t
*rtc
, int reg
, int data
);
94 static bool is_leap_year(int year
);
96 static int days_month
[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
98 static ddf_dev_ops_t rtc_dev_ops
;
100 /** The RTC device driver's standard operations */
101 static driver_ops_t rtc_ops
= {
102 .dev_add
= rtc_dev_add
,
103 .dev_remove
= rtc_dev_remove
,
106 /** The RTC device driver structure */
107 static driver_t rtc_driver
= {
109 .driver_ops
= &rtc_ops
,
112 /** Clock interface */
113 static clock_dev_ops_t rtc_clock_dev_ops
= {
114 .time_get
= rtc_time_get
,
115 .time_set
= rtc_time_set
,
118 /** Initialize the RTC driver */
122 ddf_log_init(NAME
, LVL_ERROR
);
124 rtc_dev_ops
.open
= rtc_open
;
125 rtc_dev_ops
.close
= rtc_close
;
127 rtc_dev_ops
.interfaces
[CLOCK_DEV_IFACE
] = &rtc_clock_dev_ops
;
128 rtc_dev_ops
.default_handler
= &rtc_default_handler
;
131 /** Clean up the RTC soft state
133 * @param rtc The RTC device
136 rtc_dev_cleanup(rtc_t
*rtc
)
138 if (rtc
->dev
->parent_sess
) {
139 async_hangup(rtc
->dev
->parent_sess
);
140 rtc
->dev
->parent_sess
= NULL
;
144 /** Enable the I/O ports of the device
146 * @param rtc The real time clock device
148 * @return true in case of success, false otherwise
151 rtc_pio_enable(rtc_t
*rtc
)
153 if (pio_enable((void *)(uintptr_t) rtc
->io_addr
, REG_COUNT
,
154 (void **) &rtc
->port
)) {
156 ddf_msg(LVL_ERROR
, "Cannot map the port %#" PRIx32
157 " for device %s", rtc
->io_addr
, rtc
->dev
->name
);
164 /** Initialize the RTC device
166 * @param rtc Pointer to the RTC device
168 * @return EOK on success or a negative error code
171 rtc_dev_initialize(rtc_t
*rtc
)
178 ddf_msg(LVL_DEBUG
, "rtc_dev_initialize %s", rtc
->dev
->name
);
180 hw_resource_list_t hw_resources
;
181 memset(&hw_resources
, 0, sizeof(hw_resource_list_t
));
183 /* Connect to the parent's driver */
185 rtc
->dev
->parent_sess
= devman_parent_device_connect(EXCHANGE_SERIALIZE
,
186 rtc
->dev
->handle
, IPC_FLAG_BLOCKING
);
187 if (!rtc
->dev
->parent_sess
) {
188 ddf_msg(LVL_ERROR
, "Failed to connect to parent driver\
189 of device %s.", rtc
->dev
->name
);
194 /* Get the HW resources */
195 rc
= hw_res_get_resource_list(rtc
->dev
->parent_sess
, &hw_resources
);
197 ddf_msg(LVL_ERROR
, "Failed to get HW resources\
198 for device %s", rtc
->dev
->name
);
202 for (i
= 0; i
< hw_resources
.count
; ++i
) {
203 res
= &hw_resources
.resources
[i
];
205 if (res
->type
== IO_RANGE
) {
206 if (res
->res
.io_range
.size
< REG_COUNT
) {
207 ddf_msg(LVL_ERROR
, "I/O range assigned to \
208 device %s is too small", rtc
->dev
->name
);
212 rtc
->io_addr
= res
->res
.io_range
.address
;
214 ddf_msg(LVL_NOTE
, "Device %s was assigned I/O address \
215 0x%x", rtc
->dev
->name
, rtc
->io_addr
);
220 /* No I/O address assigned to this device */
221 ddf_msg(LVL_ERROR
, "Missing HW resource for device %s",
227 hw_res_clean_resource_list(&hw_resources
);
232 rtc_dev_cleanup(rtc
);
233 hw_res_clean_resource_list(&hw_resources
);
238 /** Read a register from the CMOS memory
240 * @param rtc The rtc device
241 * @param reg The index of the register to read
243 * @return The value of the register
246 rtc_register_read(rtc_t
*rtc
, int reg
)
248 pio_write_8(rtc
->port
, reg
);
249 return pio_read_8(rtc
->port
+ 1);
252 /** Write a register to the CMOS memory
254 * @param rtc The rtc device
255 * @param reg The index of the register to write
256 * @param data The data to write
259 rtc_register_write(rtc_t
*rtc
, int reg
, int data
)
261 pio_write_8(rtc
->port
, reg
);
262 pio_write_8(rtc
->port
+ 1, data
);
265 /** Check if an update is in progress
267 * @param rtc The rtc device
269 * @return true if an update is in progress, false otherwise
272 rtc_update_in_progress(rtc_t
*rtc
)
274 return rtc_register_read(rtc
, RTC_STATUS_A
) & RTC_MASK_UPDATE
;
277 /** Read the current time from the CMOS
279 * @param fun The RTC function
280 * @param t Pointer to the time variable
282 * @return EOK on success or a negative error code
285 rtc_time_get(ddf_fun_t
*fun
, struct tm
*t
)
288 bool pm_mode
= false;
289 rtc_t
*rtc
= RTC_FROM_FNODE(fun
);
291 fibril_mutex_lock(&rtc
->mutex
);
293 /* now read the registers */
295 /* Suspend until the update process has finished */
296 while (rtc_update_in_progress(rtc
));
298 t
->tm_sec
= rtc_register_read(rtc
, RTC_SEC
);
299 t
->tm_min
= rtc_register_read(rtc
, RTC_MIN
);
300 t
->tm_hour
= rtc_register_read(rtc
, RTC_HOUR
);
301 t
->tm_mday
= rtc_register_read(rtc
, RTC_DAY
);
302 t
->tm_mon
= rtc_register_read(rtc
, RTC_MON
);
303 t
->tm_year
= rtc_register_read(rtc
, RTC_YEAR
);
305 /* Now check if it is stable */
306 } while( t
->tm_sec
!= rtc_register_read(rtc
, RTC_SEC
) ||
307 t
->tm_min
!= rtc_register_read(rtc
, RTC_MIN
) ||
308 t
->tm_mday
!= rtc_register_read(rtc
, RTC_DAY
) ||
309 t
->tm_mon
!= rtc_register_read(rtc
, RTC_MON
) ||
310 t
->tm_year
!= rtc_register_read(rtc
, RTC_YEAR
));
312 /* Check if the RTC is working in 12h mode */
313 bool _12h_mode
= !(rtc_register_read(rtc
, RTC_STATUS_B
) &
317 /* The RTC is working in 12h mode, check if it is AM or PM */
318 if (t
->tm_hour
& 0x80) {
319 /* PM flag is active, it must to be cleared
320 * or the BCD conversion will fail.
327 /* Check if the RTC is working in BCD mode */
328 bcd_mode
= !(rtc_register_read(rtc
, RTC_STATUS_B
) & RTC_MASK_BCD
);
331 t
->tm_sec
= bcd2bin(t
->tm_sec
);
332 t
->tm_min
= bcd2bin(t
->tm_min
);
333 t
->tm_hour
= bcd2bin(t
->tm_hour
);
334 t
->tm_mday
= bcd2bin(t
->tm_mday
);
335 t
->tm_mon
= bcd2bin(t
->tm_mon
);
336 t
->tm_year
= bcd2bin(t
->tm_year
);
340 /* Convert to 24h mode */
344 } else if (t
->tm_hour
== 12)
348 /* Count the months starting from 0, not from 1 */
351 if (t
->tm_year
< 100) {
352 /* tm_year is the number of years since 1900, it is not
353 * possible it is < 100.
358 fibril_mutex_unlock(&rtc
->mutex
);
362 /** Set the time in the RTC
364 * @param fun The RTC function
365 * @param t The time value to set
367 * @return EOK or a negative error code
370 rtc_time_set(ddf_fun_t
*fun
, struct tm
*t
)
376 rtc_t
*rtc
= RTC_FROM_FNODE(fun
);
378 rc
= rtc_tm_sanity_check(t
);
382 t
->tm_mon
++; /* counts from 1, not from 0 */
384 fibril_mutex_lock(&rtc
->mutex
);
386 reg_b
= rtc_register_read(rtc
, RTC_STATUS_B
);
388 /* Force 24h mode of operation */
389 rtc_register_write(rtc
, RTC_STATUS_B
, reg_b
| RTC_MASK_24H
);
391 /* Check if the rtc is working in bcd mode */
392 bcd_mode
= !(reg_b
& RTC_MASK_BCD
);
394 /* Convert the tm struct fields in BCD mode */
395 t
->tm_sec
= bin2bcd(t
->tm_sec
);
396 t
->tm_min
= bin2bcd(t
->tm_min
);
397 t
->tm_hour
= bin2bcd(t
->tm_hour
);
398 t
->tm_mday
= bin2bcd(t
->tm_mday
);
399 t
->tm_mon
= bin2bcd(t
->tm_mon
+ 1);
400 t
->tm_year
= bin2bcd(t
->tm_year
);
403 /* Inhibit updates */
404 rtc_register_write(rtc
, RTC_STATUS_B
, reg_b
| RTC_MASK_INH
);
406 /* Write current time to RTC */
407 rtc_register_write(rtc
, RTC_SEC
, t
->tm_sec
);
408 rtc_register_write(rtc
, RTC_MIN
, t
->tm_min
);
409 rtc_register_write(rtc
, RTC_HOUR
, t
->tm_hour
);
410 rtc_register_write(rtc
, RTC_DAY
, t
->tm_mday
);
411 rtc_register_write(rtc
, RTC_MON
, t
->tm_mon
);
412 rtc_register_write(rtc
, RTC_YEAR
, t
->tm_year
);
415 reg_a
= rtc_register_read(rtc
, RTC_STATUS_A
);
416 rtc_register_write(rtc
, RTC_STATUS_A
, RTC_MASK_CLK_STOP
| reg_a
);
419 rtc_register_write(rtc
, RTC_STATUS_B
, reg_b
);
420 rtc_register_write(rtc
, RTC_STATUS_A
, reg_a
);
422 fibril_mutex_unlock(&rtc
->mutex
);
427 /** Check if the tm structure contains valid values
429 * @param t The tm structure to check
431 * @return EOK on success or EINVAL
434 rtc_tm_sanity_check(struct tm
*t
)
438 if (t
->tm_sec
< 0 || t
->tm_sec
> 59)
440 else if (t
->tm_min
< 0 || t
->tm_min
> 59)
442 else if (t
->tm_hour
< 0 || t
->tm_hour
> 23)
444 else if (t
->tm_mday
< 1 || t
->tm_mday
> 31)
446 else if (t
->tm_mon
< 0 || t
->tm_mon
> 11)
448 else if (t
->tm_year
< 0)
451 if (t
->tm_mon
== 1/* FEB */ && is_leap_year(t
->tm_year
))
454 ndays
= days_month
[t
->tm_mon
];
456 if (t
->tm_mday
> ndays
)
462 /** Check if a year is a leap year
464 * @param year The year to check
466 * @return true if it is a leap year, false otherwise
469 is_leap_year(int year
)
483 /** The dev_add callback of the rtc driver
485 * @param dev The RTC device
487 * @return EOK on success or a negative error code
490 rtc_dev_add(ddf_dev_t
*dev
)
493 ddf_fun_t
*fun
= NULL
;
495 bool need_cleanup
= false;
497 ddf_msg(LVL_DEBUG
, "rtc_dev_add %s (handle = %d)",
498 dev
->name
, (int) dev
->handle
);
500 rtc
= ddf_dev_data_alloc(dev
, sizeof(rtc_t
));
505 fibril_mutex_initialize(&rtc
->mutex
);
507 rc
= rtc_dev_initialize(rtc
);
513 if (!rtc_pio_enable(rtc
)) {
518 fun
= ddf_fun_create(dev
, fun_exposed
, "a");
520 ddf_msg(LVL_ERROR
, "Failed creating function");
525 fun
->ops
= &rtc_dev_ops
;
526 rc
= ddf_fun_bind(fun
);
528 ddf_msg(LVL_ERROR
, "Failed binding function");
534 ddf_fun_add_to_category(fun
, "clock");
536 rtc
->client_connected
= false;
538 ddf_msg(LVL_NOTE
, "Device %s successfully initialized",
545 ddf_fun_destroy(fun
);
547 rtc_dev_cleanup(rtc
);
551 /** The dev_remove callback for the rtc driver
553 * @param dev The RTC device
555 * @return EOK on success or a negative error code
558 rtc_dev_remove(ddf_dev_t
*dev
)
560 rtc_t
*rtc
= RTC_FROM_DEV(dev
);
563 fibril_mutex_lock(&rtc
->mutex
);
564 if (rtc
->client_connected
) {
565 fibril_mutex_unlock(&rtc
->mutex
);
570 fibril_mutex_unlock(&rtc
->mutex
);
572 rc
= ddf_fun_unbind(rtc
->fun
);
574 ddf_msg(LVL_ERROR
, "Failed to unbind function");
578 ddf_fun_destroy(rtc
->fun
);
579 rtc_dev_cleanup(rtc
);
584 /** Default handler for client requests not handled
585 * by the standard interface
588 rtc_default_handler(ddf_fun_t
*fun
, ipc_callid_t callid
, ipc_call_t
*call
)
590 sysarg_t method
= IPC_GET_IMETHOD(*call
);
591 rtc_t
*rtc
= RTC_FROM_FNODE(fun
);
595 case CLOCK_GET_BATTERY_STATUS
:
596 batt_ok
= rtc_register_read(rtc
, RTC_STATUS_D
) &
598 async_answer_1(callid
, EOK
, batt_ok
);
601 async_answer_0(callid
, ENOTSUP
);
607 * @param fun The function node
609 * @return EOK on success or a negative error code
612 rtc_open(ddf_fun_t
*fun
)
615 rtc_t
*rtc
= RTC_FROM_FNODE(fun
);
617 fibril_mutex_lock(&rtc
->mutex
);
619 if (rtc
->client_connected
)
621 else if (rtc
->removed
)
625 rtc
->client_connected
= true;
628 fibril_mutex_unlock(&rtc
->mutex
);
634 * @param fun The function node
637 rtc_close(ddf_fun_t
*fun
)
639 rtc_t
*rtc
= RTC_FROM_FNODE(fun
);
641 fibril_mutex_lock(&rtc
->mutex
);
643 assert(rtc
->client_connected
);
644 rtc
->client_connected
= false;
646 fibril_mutex_unlock(&rtc
->mutex
);
649 /** Convert from BCD mode to binary mode
651 * @param bcd The number in BCD format to convert
653 * @return The converted value
656 bcd2bin(unsigned bcd
)
658 return ((bcd
& 0xF0) >> 1) + ((bcd
& 0xF0) >> 3) + (bcd
& 0xf);
661 /** Convert from binary mode to BCD mode
663 * @param bcd The number in binary mode to convert
665 * @return The converted value
668 bin2bcd(unsigned binary
)
670 return ((binary
/ 10) << 4) + (binary
% 10);
674 main(int argc
, char **argv
)
676 printf(NAME
": HelenOS RTC driver\n");
678 return ddf_driver_main(&rtc_driver
);