summaryrefslogtreecommitdiff
path: root/avr/pcf8583.c
blob: bdb779f0c4f1bd5137c3f4f854fa262a0c077a48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

/*
 * Date & Time support for Philips PCF8583 RTC
 */

#include "common.h"
#include <stdlib.h>
#include "time.h"
#include "rtc.h"
#include "i2c.h"
#include "command.h"
#include "debug.h"

#define  DEBUG_RTC 0

#define debug_rtc(fmt, args...)			\
	debug_cond(DEBUG_RTC, fmt, ##args)

#define REG_CS		0x00	/* control/status */
#define REG_CSEC	0x01	/* hundredth of a second */
#define REG_SEC		0x02	/* seconds */
#define REG_MIN		0x03	/* minutes */
#define REG_HOUR	0x04	/* hours */
#define REG_YRDATE	0x05	/* year/date */
#define REG_WDMON	0x06	/* weekdays/months */
#define NR_OF_REGS	7


/* ------------------------------------------------------------------------- */

static uint_fast8_t bcd2bin(uint8_t val)
{
	return (val >> 4) * 10 + (val & 0x0f);
}

static uint8_t bin2bcd (uint_fast8_t val)
{
	div_t d = div(val, 10);

	return (d.quot << 4) | d.rem;
}


int rtc_get (struct tm *tmp)
{
	uint8_t rtcbuf[NR_OF_REGS];
	int16_t year;

	i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, NR_OF_REGS);
	i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);

	debug_rtc("Get RTC year: %u, wdays/month: %02x, year/date: %02x, "
		"hour: %02x, min: %02x, sec: %02x, (stat: %02x)\n", year,
		rtcbuf[6], rtcbuf[5], rtcbuf[4], rtcbuf[3], rtcbuf[2], rtcbuf[0]);

	tmp->tm_sec  = bcd2bin (rtcbuf[REG_SEC]    & 0x7F);
	tmp->tm_min  = bcd2bin (rtcbuf[REG_MIN]    & 0x7F);
	tmp->tm_hour = bcd2bin (rtcbuf[REG_HOUR]   & 0x3F);
	tmp->tm_mday = bcd2bin (rtcbuf[REG_YRDATE] & 0x3F);
	tmp->tm_mon  = bcd2bin (rtcbuf[REG_WDMON]  & 0x1F) - 1;
	while (year%4 != (rtcbuf[REG_YRDATE]>>6)) {
		year++;
		i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
	}
	tmp->tm_year  = year - 1900;
	tmp->tm_wday = rtcbuf[REG_WDMON] >> 5;
	tmp->tm_yday = 0;
	tmp->tm_isdst= 0;

	debug_rtc( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

	return rtcbuf[REG_CS] == 0x04 ? 0 : 1;
}

int rtc_set (struct tm *tmp)
{
	uint8_t rtcbuf[NR_OF_REGS];
	int16_t year = tmp->tm_year + 1900;

	debug_rtc("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

	rtcbuf[REG_CS] = 0x84;
	rtcbuf[REG_CSEC] = 0x00;
	rtcbuf[REG_WDMON ] = (bin2bcd(tmp->tm_mon) + 1) | ((tmp->tm_wday) << 5);
	rtcbuf[REG_YRDATE] = ((year % 4) << 6) | bin2bcd(tmp->tm_mday);
	rtcbuf[REG_HOUR  ] = bin2bcd(tmp->tm_hour);
	rtcbuf[REG_MIN   ] = bin2bcd(tmp->tm_min);
	rtcbuf[REG_SEC   ] = bin2bcd(tmp->tm_sec);

	i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0,    1, rtcbuf, NR_OF_REGS);
	i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
	rtcbuf[REG_CS] = 0x04;
	i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, 1);

	return 0;
}