1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <log.h>
11 #include <rtc.h>
12 
dm_rtc_get(struct udevice * dev,struct rtc_time * time)13 int dm_rtc_get(struct udevice *dev, struct rtc_time *time)
14 {
15 	struct rtc_ops *ops = rtc_get_ops(dev);
16 
17 	assert(ops);
18 	if (!ops->get)
19 		return -ENOSYS;
20 	return ops->get(dev, time);
21 }
22 
dm_rtc_set(struct udevice * dev,struct rtc_time * time)23 int dm_rtc_set(struct udevice *dev, struct rtc_time *time)
24 {
25 	struct rtc_ops *ops = rtc_get_ops(dev);
26 
27 	assert(ops);
28 	if (!ops->set)
29 		return -ENOSYS;
30 	return ops->set(dev, time);
31 }
32 
dm_rtc_reset(struct udevice * dev)33 int dm_rtc_reset(struct udevice *dev)
34 {
35 	struct rtc_ops *ops = rtc_get_ops(dev);
36 
37 	assert(ops);
38 	if (!ops->reset)
39 		return -ENOSYS;
40 	return ops->reset(dev);
41 }
42 
dm_rtc_read(struct udevice * dev,unsigned int reg,u8 * buf,unsigned int len)43 int dm_rtc_read(struct udevice *dev, unsigned int reg, u8 *buf, unsigned int len)
44 {
45 	struct rtc_ops *ops = rtc_get_ops(dev);
46 
47 	assert(ops);
48 	if (ops->read)
49 		return ops->read(dev, reg, buf, len);
50 	if (!ops->read8)
51 		return -ENOSYS;
52 	while (len--) {
53 		int ret = ops->read8(dev, reg++);
54 
55 		if (ret < 0)
56 			return ret;
57 		*buf++ = ret;
58 	}
59 	return 0;
60 }
61 
dm_rtc_write(struct udevice * dev,unsigned int reg,const u8 * buf,unsigned int len)62 int dm_rtc_write(struct udevice *dev, unsigned int reg,
63 		 const u8 *buf, unsigned int len)
64 {
65 	struct rtc_ops *ops = rtc_get_ops(dev);
66 
67 	assert(ops);
68 	if (ops->write)
69 		return ops->write(dev, reg, buf, len);
70 	if (!ops->write8)
71 		return -ENOSYS;
72 	while (len--) {
73 		int ret = ops->write8(dev, reg++, *buf++);
74 
75 		if (ret < 0)
76 			return ret;
77 	}
78 	return 0;
79 }
80 
rtc_read8(struct udevice * dev,unsigned int reg)81 int rtc_read8(struct udevice *dev, unsigned int reg)
82 {
83 	struct rtc_ops *ops = rtc_get_ops(dev);
84 
85 	assert(ops);
86 	if (ops->read8)
87 		return ops->read8(dev, reg);
88 	if (ops->read) {
89 		u8 buf[1];
90 		int ret = ops->read(dev, reg, buf, 1);
91 
92 		if (ret < 0)
93 			return ret;
94 		return buf[0];
95 	}
96 	return -ENOSYS;
97 }
98 
rtc_write8(struct udevice * dev,unsigned int reg,int val)99 int rtc_write8(struct udevice *dev, unsigned int reg, int val)
100 {
101 	struct rtc_ops *ops = rtc_get_ops(dev);
102 
103 	assert(ops);
104 	if (ops->write8)
105 		return ops->write8(dev, reg, val);
106 	if (ops->write) {
107 		u8 buf[1] = { val };
108 
109 		return ops->write(dev, reg, buf, 1);
110 	}
111 	return -ENOSYS;
112 }
113 
rtc_read16(struct udevice * dev,unsigned int reg,u16 * valuep)114 int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep)
115 {
116 	u16 value = 0;
117 	int ret;
118 	int i;
119 
120 	for (i = 0; i < sizeof(value); i++) {
121 		ret = rtc_read8(dev, reg + i);
122 		if (ret < 0)
123 			return ret;
124 		value |= ret << (i << 3);
125 	}
126 
127 	*valuep = value;
128 	return 0;
129 }
130 
rtc_write16(struct udevice * dev,unsigned int reg,u16 value)131 int rtc_write16(struct udevice *dev, unsigned int reg, u16 value)
132 {
133 	int i, ret;
134 
135 	for (i = 0; i < sizeof(value); i++) {
136 		ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
137 		if (ret)
138 			return ret;
139 	}
140 
141 	return 0;
142 }
143 
rtc_read32(struct udevice * dev,unsigned int reg,u32 * valuep)144 int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep)
145 {
146 	u32 value = 0;
147 	int ret;
148 	int i;
149 
150 	for (i = 0; i < sizeof(value); i++) {
151 		ret = rtc_read8(dev, reg + i);
152 		if (ret < 0)
153 			return ret;
154 		value |= ret << (i << 3);
155 	}
156 
157 	*valuep = value;
158 	return 0;
159 }
160 
rtc_write32(struct udevice * dev,unsigned int reg,u32 value)161 int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
162 {
163 	int i, ret;
164 
165 	for (i = 0; i < sizeof(value); i++) {
166 		ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
167 		if (ret)
168 			return ret;
169 	}
170 
171 	return 0;
172 }
173 
174 UCLASS_DRIVER(rtc) = {
175 	.name		= "rtc",
176 	.id		= UCLASS_RTC,
177 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
178 	.post_bind	= dm_scan_fdt_dev,
179 #endif
180 };
181