I'm trying to use a DS3231 with a Beaglebone Black. I'm custom system I built with buildroot (BusyBox v1.31.1), I also wrote the driver I'm using, this is an university assignment, so I can't use prebuilt systems or any existing drivers.
I'm building with Linaro's linux cross compiler (v7.5.0 2019.12) and using kernel version 5.10.65-ti-r30.
The system detects the RTC and my driver probes successfully, it generates an RTC file in /dev/rtc2
and I can set the time in the RTC with hwclock --systohc -f /dev/rtc2
, but whenever I read it with hwclock -f /dev/rtc2
it says it's 1 second before the Unix epoch (1969/12/31 23:59:59). I've also written an userspace program that uses ioctl()
to read and set the RTC and it sets and reads the time with no problems, so I know my driver is working.
I've also modified the time in the internal RTC in /dev/rtc0
, and hwclock
outputs its time with no problems.
Here's the output of my rtc when using my program and hwclock
:
# ./a.out r /dev/rtc2
Time read: 2023/07/24 19:03:22
# hwclock -f /dev/rtc2
Wed Dec 31 23:59:59 1969 0.000000 seconds
The date shown on hwclock
should be the same as my program. If I put pr_info()
statements inside the driver to print the time they print the correct time.
Here's the read function from my driver:
static int ds3231_read_time(struct device* dev, struct rtc_time* tm){
struct i2c_client* client = to_i2c_client(dev);
s32 ret;
u8 reg;
ret = i2c_smbus_read_byte_data(client, DS3231_REG_SEC);
if(ret < 0){
pr_err("Error %d during seconds read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_sec = 10 * (reg >> 4) + (reg & DS3231_MSK_SEC);
ret = i2c_smbus_read_byte_data(client, DS3231_REG_MIN);
if(ret < 0){
pr_err("Error %d during minutes read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_min = 10 * (reg >> 4) + (reg & DS3231_MSK_MIN);
ret = i2c_smbus_read_byte_data(client, DS3231_REG_HRS);
if(ret < 0){
pr_err("Error %d during hours read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_hour = 20 * ((reg >> 5) & 1) + 10 * ((reg >> 4) & 1) + (reg & DS3231_MSK_HR);
ret = i2c_smbus_read_byte_data(client, DS3231_REG_MDAY);
if(ret < 0){
pr_err("Error %d during day read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_mday = 10 * (reg >> 4) + (reg & DS3231_MSK_DAY);
ret = i2c_smbus_read_byte_data(client, DS3231_REG_MON);
if(ret < 0){
pr_err("Error %d during month read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_mon = 10 * ((reg >> 4) & 1) + (reg & DS3231_MSK_MON);
ret = i2c_smbus_read_byte_data(client, DS3231_REG_YEAR);
if(ret < 0){
pr_err("Error %d during year read\n", ret);
return ret;
}
reg = (u8)(ret);
tm->tm_year = 2000 + 100 * (tm->tm_mon >> 7) + 10 * (reg >> 4) + (reg & DS3231_MSK_YEAR);
tm->tm_wday = calculate_wday(tm->tm_year, tm->tm_mon, tm->tm_mday);
tm->tm_yday = calculate_yday(tm->tm_year, tm->tm_mon, tm->tm_mday);
tm->tm_isdst = 0;
return 0;
}
I don't think this function is causing the problems, but I'm including it just in case.