1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * The Netronix embedded controller is a microcontroller found in some
4 * e-book readers designed by the original design manufacturer Netronix, Inc.
5 * It contains RTC, battery monitoring, system power management, and PWM
8 * This driver implements access to the RTC time and date.
10 * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
13 #include <linux/mfd/ntxec.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/rtc.h>
18 #include <linux/types.h>
25 #define NTXEC_REG_WRITE_YEAR 0x10
26 #define NTXEC_REG_WRITE_MONTH 0x11
27 #define NTXEC_REG_WRITE_DAY 0x12
28 #define NTXEC_REG_WRITE_HOUR 0x13
29 #define NTXEC_REG_WRITE_MINUTE 0x14
30 #define NTXEC_REG_WRITE_SECOND 0x15
32 #define NTXEC_REG_READ_YEAR_MONTH 0x20
33 #define NTXEC_REG_READ_MDAY_HOUR 0x21
34 #define NTXEC_REG_READ_MINUTE_SECOND 0x23
36 static int ntxec_read_time(struct device
*dev
, struct rtc_time
*tm
)
38 struct ntxec_rtc
*rtc
= dev_get_drvdata(dev
);
43 res
= regmap_read(rtc
->ec
->regmap
, NTXEC_REG_READ_MINUTE_SECOND
, &value
);
47 tm
->tm_min
= value
>> 8;
48 tm
->tm_sec
= value
& 0xff;
50 res
= regmap_read(rtc
->ec
->regmap
, NTXEC_REG_READ_MDAY_HOUR
, &value
);
54 tm
->tm_mday
= value
>> 8;
55 tm
->tm_hour
= value
& 0xff;
57 res
= regmap_read(rtc
->ec
->regmap
, NTXEC_REG_READ_YEAR_MONTH
, &value
);
61 tm
->tm_year
= (value
>> 8) + 100;
62 tm
->tm_mon
= (value
& 0xff) - 1;
65 * Read the minutes/seconds field again. If it changed since the first
66 * read, we can't assume that the values read so far are consistent,
67 * and should start from the beginning.
69 res
= regmap_read(rtc
->ec
->regmap
, NTXEC_REG_READ_MINUTE_SECOND
, &value
);
73 if (tm
->tm_min
!= value
>> 8 || tm
->tm_sec
!= (value
& 0xff))
79 static int ntxec_set_time(struct device
*dev
, struct rtc_time
*tm
)
81 struct ntxec_rtc
*rtc
= dev_get_drvdata(dev
);
84 * To avoid time overflows while we're writing the full date/time,
85 * set the seconds field to zero before doing anything else. For the
86 * next 59 seconds (plus however long it takes until the RTC's next
87 * update of the second field), the seconds field will not overflow
88 * into the other fields.
90 struct reg_sequence regs
[] = {
91 { NTXEC_REG_WRITE_SECOND
, ntxec_reg8(0) },
92 { NTXEC_REG_WRITE_YEAR
, ntxec_reg8(tm
->tm_year
- 100) },
93 { NTXEC_REG_WRITE_MONTH
, ntxec_reg8(tm
->tm_mon
+ 1) },
94 { NTXEC_REG_WRITE_DAY
, ntxec_reg8(tm
->tm_mday
) },
95 { NTXEC_REG_WRITE_HOUR
, ntxec_reg8(tm
->tm_hour
) },
96 { NTXEC_REG_WRITE_MINUTE
, ntxec_reg8(tm
->tm_min
) },
97 { NTXEC_REG_WRITE_SECOND
, ntxec_reg8(tm
->tm_sec
) },
100 return regmap_multi_reg_write(rtc
->ec
->regmap
, regs
, ARRAY_SIZE(regs
));
103 static const struct rtc_class_ops ntxec_rtc_ops
= {
104 .read_time
= ntxec_read_time
,
105 .set_time
= ntxec_set_time
,
108 static int ntxec_rtc_probe(struct platform_device
*pdev
)
110 struct rtc_device
*dev
;
111 struct ntxec_rtc
*rtc
;
113 pdev
->dev
.of_node
= pdev
->dev
.parent
->of_node
;
115 rtc
= devm_kzalloc(&pdev
->dev
, sizeof(*rtc
), GFP_KERNEL
);
119 rtc
->dev
= &pdev
->dev
;
120 rtc
->ec
= dev_get_drvdata(pdev
->dev
.parent
);
121 platform_set_drvdata(pdev
, rtc
);
123 dev
= devm_rtc_allocate_device(&pdev
->dev
);
127 dev
->ops
= &ntxec_rtc_ops
;
128 dev
->range_min
= RTC_TIMESTAMP_BEGIN_2000
;
129 dev
->range_max
= 9025257599LL; /* 2255-12-31 23:59:59 */
131 return devm_rtc_register_device(dev
);
134 static struct platform_driver ntxec_rtc_driver
= {
138 .probe
= ntxec_rtc_probe
,
140 module_platform_driver(ntxec_rtc_driver
);
142 MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
143 MODULE_DESCRIPTION("RTC driver for Netronix EC");
144 MODULE_LICENSE("GPL");
145 MODULE_ALIAS("platform:ntxec-rtc");