2 * Simulate an I2C real time clock
4 * Copyright (c) 2015 Google, Inc
5 * Written by Simon Glass <sjg@chromium.org>
7 * SPDX-License-Identifier: GPL-2.0+
11 * This is a test driver. It starts off with the current time of the machine,
12 * but also supports setting the time, using an offset from the current
13 * clock. This driver is only intended for testing, not accurate
14 * time-keeping. It does not change the system time.
26 #define debug_buffer print_buffer
28 #define debug_buffer(x, ...)
31 DECLARE_GLOBAL_DATA_PTR
;
34 * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
36 * @base_time: Base system time when RTC device was bound
37 * @offset: RTC offset from current system time
38 * @use_system_time: true to use system time, false to use @base_time
39 * @reg: Register values
41 struct sandbox_i2c_rtc_plat_data
{
48 struct sandbox_i2c_rtc
{
49 unsigned int offset_secs
;
52 long sandbox_i2c_rtc_set_offset(struct udevice
*dev
, bool use_system_time
,
55 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
58 old_offset
= plat
->offset
;
59 plat
->use_system_time
= use_system_time
;
61 plat
->offset
= offset
;
66 long sandbox_i2c_rtc_get_set_base_time(struct udevice
*dev
, long base_time
)
68 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
71 old_base_time
= plat
->base_time
;
73 plat
->base_time
= base_time
;
78 static void reset_time(struct udevice
*dev
)
80 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
84 plat
->base_time
= rtc_mktime(&now
);
86 plat
->use_system_time
= true;
89 static int sandbox_i2c_rtc_get(struct udevice
*dev
, struct rtc_time
*time
)
91 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
92 struct rtc_time tm_now
;
95 if (plat
->use_system_time
) {
96 os_localtime(&tm_now
);
97 now
= rtc_mktime(&tm_now
);
99 now
= plat
->base_time
;
102 return rtc_to_tm(now
+ plat
->offset
, time
);
105 static int sandbox_i2c_rtc_set(struct udevice
*dev
, const struct rtc_time
*time
)
107 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
108 struct rtc_time tm_now
;
111 if (plat
->use_system_time
) {
112 os_localtime(&tm_now
);
113 now
= rtc_mktime(&tm_now
);
115 now
= plat
->base_time
;
117 plat
->offset
= rtc_mktime(time
) - now
;
122 /* Update the current time in the registers */
123 static int sandbox_i2c_rtc_prepare_read(struct udevice
*emul
)
125 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
126 struct rtc_time time
;
129 ret
= sandbox_i2c_rtc_get(emul
, &time
);
133 plat
->reg
[REG_SEC
] = time
.tm_sec
;
134 plat
->reg
[REG_MIN
] = time
.tm_min
;
135 plat
->reg
[REG_HOUR
] = time
.tm_hour
;
136 plat
->reg
[REG_MDAY
] = time
.tm_mday
;
137 plat
->reg
[REG_MON
] = time
.tm_mon
;
138 plat
->reg
[REG_YEAR
] = time
.tm_year
- 1900;
139 plat
->reg
[REG_WDAY
] = time
.tm_wday
;
144 static int sandbox_i2c_rtc_complete_write(struct udevice
*emul
)
146 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
147 struct rtc_time time
;
150 time
.tm_sec
= plat
->reg
[REG_SEC
];
151 time
.tm_min
= plat
->reg
[REG_MIN
];
152 time
.tm_hour
= plat
->reg
[REG_HOUR
];
153 time
.tm_mday
= plat
->reg
[REG_MDAY
];
154 time
.tm_mon
= plat
->reg
[REG_MON
];
155 time
.tm_year
= plat
->reg
[REG_YEAR
] + 1900;
156 time
.tm_wday
= plat
->reg
[REG_WDAY
];
158 ret
= sandbox_i2c_rtc_set(emul
, &time
);
165 static int sandbox_i2c_rtc_xfer(struct udevice
*emul
, struct i2c_msg
*msg
,
168 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
172 debug("\n%s\n", __func__
);
173 ret
= sandbox_i2c_rtc_prepare_read(emul
);
176 for (; nmsgs
> 0; nmsgs
--, msg
++) {
181 debug(" %s: msg->len=%d",
182 msg
->flags
& I2C_M_RD
? "read" : "write",
184 if (msg
->flags
& I2C_M_RD
) {
185 debug(", offset %x, len %x: ", offset
, len
);
187 /* Read the register */
188 memcpy(msg
->buf
, plat
->reg
+ offset
, len
);
189 memset(msg
->buf
+ len
, '\xff', msg
->len
- len
);
190 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
191 } else if (len
>= 1) {
193 offset
= *ptr
++ & (REG_COUNT
- 1);
195 debug(", set offset %x: ", offset
);
196 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
198 /* Write the register */
199 memcpy(plat
->reg
+ offset
, ptr
, len
);
200 if (offset
== REG_RESET
)
204 ret
= sandbox_i2c_rtc_complete_write(emul
);
211 struct dm_i2c_ops sandbox_i2c_rtc_emul_ops
= {
212 .xfer
= sandbox_i2c_rtc_xfer
,
215 static int sandbox_i2c_rtc_bind(struct udevice
*dev
)
222 static const struct udevice_id sandbox_i2c_rtc_ids
[] = {
223 { .compatible
= "sandbox,i2c-rtc" },
227 U_BOOT_DRIVER(sandbox_i2c_rtc_emul
) = {
228 .name
= "sandbox_i2c_rtc_emul",
229 .id
= UCLASS_I2C_EMUL
,
230 .of_match
= sandbox_i2c_rtc_ids
,
231 .bind
= sandbox_i2c_rtc_bind
,
232 .priv_auto_alloc_size
= sizeof(struct sandbox_i2c_rtc
),
233 .platdata_auto_alloc_size
= sizeof(struct sandbox_i2c_rtc_plat_data
),
234 .ops
= &sandbox_i2c_rtc_emul_ops
,