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.
27 #define debug_buffer print_buffer
29 #define debug_buffer(x, ...)
32 DECLARE_GLOBAL_DATA_PTR
;
35 * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
37 * @base_time: Base system time when RTC device was bound
38 * @offset: RTC offset from current system time
39 * @use_system_time: true to use system time, false to use @base_time
40 * @reg: Register values
42 struct sandbox_i2c_rtc_plat_data
{
49 struct sandbox_i2c_rtc
{
50 unsigned int offset_secs
;
53 long sandbox_i2c_rtc_set_offset(struct udevice
*dev
, bool use_system_time
,
56 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
59 old_offset
= plat
->offset
;
60 plat
->use_system_time
= use_system_time
;
62 plat
->offset
= offset
;
67 long sandbox_i2c_rtc_get_set_base_time(struct udevice
*dev
, long base_time
)
69 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
72 old_base_time
= plat
->base_time
;
74 plat
->base_time
= base_time
;
79 static void reset_time(struct udevice
*dev
)
81 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
85 plat
->base_time
= rtc_mktime(&now
);
87 plat
->use_system_time
= true;
90 static int sandbox_i2c_rtc_get(struct udevice
*dev
, struct rtc_time
*time
)
92 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
93 struct rtc_time tm_now
;
96 if (plat
->use_system_time
) {
97 os_localtime(&tm_now
);
98 now
= rtc_mktime(&tm_now
);
100 now
= plat
->base_time
;
103 return rtc_to_tm(now
+ plat
->offset
, time
);
106 static int sandbox_i2c_rtc_set(struct udevice
*dev
, const struct rtc_time
*time
)
108 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(dev
);
109 struct rtc_time tm_now
;
112 if (plat
->use_system_time
) {
113 os_localtime(&tm_now
);
114 now
= rtc_mktime(&tm_now
);
116 now
= plat
->base_time
;
118 plat
->offset
= rtc_mktime(time
) - now
;
123 /* Update the current time in the registers */
124 static int sandbox_i2c_rtc_prepare_read(struct udevice
*emul
)
126 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
127 struct rtc_time time
;
130 ret
= sandbox_i2c_rtc_get(emul
, &time
);
134 plat
->reg
[REG_SEC
] = time
.tm_sec
;
135 plat
->reg
[REG_MIN
] = time
.tm_min
;
136 plat
->reg
[REG_HOUR
] = time
.tm_hour
;
137 plat
->reg
[REG_MDAY
] = time
.tm_mday
;
138 plat
->reg
[REG_MON
] = time
.tm_mon
;
139 plat
->reg
[REG_YEAR
] = time
.tm_year
- 1900;
140 plat
->reg
[REG_WDAY
] = time
.tm_wday
;
145 static int sandbox_i2c_rtc_complete_write(struct udevice
*emul
)
147 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
148 struct rtc_time time
;
151 time
.tm_sec
= plat
->reg
[REG_SEC
];
152 time
.tm_min
= plat
->reg
[REG_MIN
];
153 time
.tm_hour
= plat
->reg
[REG_HOUR
];
154 time
.tm_mday
= plat
->reg
[REG_MDAY
];
155 time
.tm_mon
= plat
->reg
[REG_MON
];
156 time
.tm_year
= plat
->reg
[REG_YEAR
] + 1900;
157 time
.tm_wday
= plat
->reg
[REG_WDAY
];
159 ret
= sandbox_i2c_rtc_set(emul
, &time
);
166 static int sandbox_i2c_rtc_xfer(struct udevice
*emul
, struct i2c_msg
*msg
,
169 struct sandbox_i2c_rtc_plat_data
*plat
= dev_get_platdata(emul
);
173 debug("\n%s\n", __func__
);
174 ret
= sandbox_i2c_rtc_prepare_read(emul
);
177 for (; nmsgs
> 0; nmsgs
--, msg
++) {
182 debug(" %s: msg->len=%d",
183 msg
->flags
& I2C_M_RD
? "read" : "write",
185 if (msg
->flags
& I2C_M_RD
) {
186 debug(", offset %x, len %x: ", offset
, len
);
188 /* Read the register */
189 memcpy(msg
->buf
, plat
->reg
+ offset
, len
);
190 memset(msg
->buf
+ len
, '\xff', msg
->len
- len
);
191 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
192 } else if (len
>= 1) {
194 offset
= *ptr
++ & (REG_COUNT
- 1);
196 debug(", set offset %x: ", offset
);
197 debug_buffer(0, msg
->buf
, 1, msg
->len
, 0);
199 /* Write the register */
200 memcpy(plat
->reg
+ offset
, ptr
, len
);
201 if (offset
== REG_RESET
)
205 ret
= sandbox_i2c_rtc_complete_write(emul
);
212 struct dm_i2c_ops sandbox_i2c_rtc_emul_ops
= {
213 .xfer
= sandbox_i2c_rtc_xfer
,
216 static int sandbox_i2c_rtc_bind(struct udevice
*dev
)
223 static const struct udevice_id sandbox_i2c_rtc_ids
[] = {
224 { .compatible
= "sandbox,i2c-rtc" },
228 U_BOOT_DRIVER(sandbox_i2c_rtc_emul
) = {
229 .name
= "sandbox_i2c_rtc_emul",
230 .id
= UCLASS_I2C_EMUL
,
231 .of_match
= sandbox_i2c_rtc_ids
,
232 .bind
= sandbox_i2c_rtc_bind
,
233 .priv_auto_alloc_size
= sizeof(struct sandbox_i2c_rtc
),
234 .platdata_auto_alloc_size
= sizeof(struct sandbox_i2c_rtc_plat_data
),
235 .ops
= &sandbox_i2c_rtc_emul_ops
,