1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_smbus.h"
9
10 static uint8_t hpm_smbus_pec_crc8(uint8_t *data, uint32_t len);
11
12
hpm_smbus_master_write_byte(I2C_Type * ptr,uint8_t slave_address,uint8_t data)13 hpm_stat_t hpm_smbus_master_write_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t data)
14 {
15 hpm_stat_t stat;
16 uint8_t buf[3];
17 /* addr + rw bit*/
18 buf[0] = slave_address << 1;
19 buf[1] = data;
20 buf[2] = hpm_smbus_pec_crc8(buf, 2);
21 stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
22 return stat;
23 }
24
hpm_smbus_master_read_byte(I2C_Type * ptr,uint8_t slave_address,uint8_t * data)25 hpm_stat_t hpm_smbus_master_read_byte(I2C_Type *ptr, uint8_t slave_address, uint8_t *data)
26 {
27 uint8_t buf[3];
28 hpm_stat_t stat;
29 uint8_t pec;
30 /* addr + rw bit*/
31 buf[0] = (slave_address << 1);
32 stat = i2c_master_read(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
33 if (stat == status_success) {
34 pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
35 if (pec == buf[2]) {
36 *data = buf[1];
37 } else {
38 stat = status_fail;
39 }
40 }
41 return stat;
42 }
43
hpm_smbus_master_write_byte_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint8_t data)44 hpm_stat_t hpm_smbus_master_write_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t data)
45 {
46 hpm_stat_t stat;
47 uint8_t buf[4];
48 /* addr + rw bit*/
49 buf[0] = slave_address << 1;
50 buf[1] = command;
51 buf[2] = data;
52 buf[3] = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
53 stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
54 return stat;
55 }
56
hpm_smbus_master_write_word_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint16_t data)57 hpm_stat_t hpm_smbus_master_write_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t data)
58 {
59 hpm_stat_t stat;
60 uint8_t buf[5];
61 /* addr + rw bit*/
62 buf[0] = slave_address << 1;
63 buf[1] = command;
64 *(uint16_t *)(&buf[2]) = data;
65 buf[4] = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
66 stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], sizeof(buf) - 1);
67 return stat;
68 }
69
hpm_smbus_master_read_byte_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint8_t * data)70 hpm_stat_t hpm_smbus_master_read_byte_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data)
71 {
72 hpm_stat_t stat;
73 uint8_t pec;
74 uint8_t buf[5];
75 /* addr + rw bit*/
76 buf[0] = (slave_address << 1);
77 buf[1] = command;
78 /* write command code in smbus spec*/
79 stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
80 if (stat == status_success) {
81 /* read */
82 buf[2] = (slave_address << 1) | 0x01;
83 /* now change dir,restart, read the byte */
84 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 1, i2c_frist_frame);
85 /* read the pec */
86 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[4], 1, i2c_last_frame);
87 if (stat == status_success) {
88 pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
89 if (pec == buf[4]) {
90 *data = buf[3];
91 } else {
92 stat = status_fail;
93 }
94 }
95 }
96 return stat;
97 }
98
hpm_smbus_master_read_word_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint16_t * data)99 hpm_stat_t hpm_smbus_master_read_word_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint16_t *data)
100 {
101 hpm_stat_t stat;
102 uint8_t pec;
103 uint8_t buf[6];
104 /* addr + rw bit*/
105 buf[0] = (slave_address << 1);
106 buf[1] = command;
107 /* write command code in smbus spec*/
108 stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
109 if (stat == status_success) {
110 /* read */
111 buf[2] = (slave_address << 1) | 0x01;
112 /* now change dir,restart, read the word (16 bits)*/
113 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 2, i2c_frist_frame);
114 /* read the pec */
115 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[5], 1, i2c_last_frame);
116 if (stat == status_success) {
117 pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
118 if (pec == buf[5]) {
119 *data = *(uint16_t *)(&buf[3]);
120 } else {
121 stat = status_fail;
122 }
123 }
124 }
125 return stat;
126 }
127
hpm_smbus_master_write_block_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint8_t * data,uint32_t size)128 hpm_stat_t hpm_smbus_master_write_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size)
129 {
130 hpm_stat_t stat;
131 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
132 uint16_t buf_size;
133 /* frame included addr, command, data, and pec */
134 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 3));
135 /* addr + rw bit*/
136 buf[0] = slave_address << 1;
137 buf[1] = command;
138 buf[2] = size;
139 memcpy(&buf[3], data, size);
140 buf[size + 3] = hpm_smbus_pec_crc8(buf, size + 3);
141 buf_size = size + 4;
142 stat = i2c_master_write(ptr, (const uint16_t)slave_address, buf, buf_size);
143 return stat;
144 }
145
hpm_smbus_master_read_block_in_command(I2C_Type * ptr,uint8_t slave_address,uint8_t command,uint8_t * data,uint32_t size)146 hpm_stat_t hpm_smbus_master_read_block_in_command(I2C_Type *ptr, uint8_t slave_address, uint8_t command, uint8_t *data, uint32_t size)
147 {
148 hpm_stat_t stat;
149 uint8_t pec;
150 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
151 /* frame included addr, command, data, and pec */
152 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 3));
153 /* addr + rw bit*/
154 buf[0] = (slave_address << 1);
155 buf[1] = command;
156 /* write command code in smbus spec*/
157 stat = i2c_master_seq_transmit(ptr, (const uint16_t)slave_address, &command, sizeof(uint8_t), i2c_frist_frame);
158 /* read */
159 buf[2] = (slave_address << 1) | 0x01;
160 if (stat == status_success) {
161 /* now change dir,restart, read the block count*/
162 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[3], 1, i2c_frist_frame);
163 /* read data*/
164 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[4], size, i2c_next_frame);
165 /* read pec */
166 stat = i2c_master_seq_receive(ptr, (const uint16_t)slave_address, &buf[size + 4], 1, i2c_last_frame);
167 if (stat == status_success) {
168 pec = hpm_smbus_pec_crc8(buf, sizeof(buf) - 1);
169 if (pec == buf[size + 4]) {
170 memcpy(data, &buf[4], size);
171 } else {
172 stat = status_fail;
173 }
174 }
175 }
176 return stat;
177 }
178
hpm_smbus_master_write(I2C_Type * ptr,uint8_t slave_address,uint8_t * data,uint32_t size)179 hpm_stat_t hpm_smbus_master_write(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size)
180 {
181 hpm_stat_t stat;
182 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
183 uint16_t buf_size;
184 /* frame included addr, data, and pec */
185 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 1));
186 /* addr + rw bit*/
187 buf[0] = (slave_address << 1) | 0x01;
188 memcpy(&buf[1], data, size);
189 buf[size + 1] = hpm_smbus_pec_crc8(buf, size + 1);
190 buf_size = size + 1;
191 stat = i2c_master_write(ptr, (const uint16_t)slave_address, &buf[1], buf_size);
192 return stat;
193 }
194
hpm_smbus_master_read(I2C_Type * ptr,uint8_t slave_address,uint8_t * data,uint32_t size)195 hpm_stat_t hpm_smbus_master_read(I2C_Type *ptr, uint8_t slave_address, uint8_t *data, uint32_t size)
196 {
197 hpm_stat_t stat;
198 uint8_t pec;
199 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
200 /* frame included addr, data, and pec */
201 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 2));
202 buf[0] = (slave_address << 1);
203 stat = i2c_master_read(ptr, slave_address, &buf[1], size + 1);
204 if (stat == status_success) {
205 pec = hpm_smbus_pec_crc8(buf, size + 1);
206 if (pec == buf[size + 1]) {
207 memcpy(data, &buf[1], size);
208 } else {
209 stat = status_fail;
210 }
211 }
212 return stat;
213 }
214
hpm_smbus_slave_write(I2C_Type * ptr,uint8_t * data,uint32_t size)215 hpm_stat_t hpm_smbus_slave_write(I2C_Type *ptr, uint8_t *data, uint32_t size)
216 {
217 hpm_stat_t stat;
218 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
219 uint16_t buf_size;
220 uint8_t slave_address;
221 /* frame included addr, data, and pec */
222 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 1));
223 slave_address = ptr->ADDR;
224 /* addr + rw bit*/
225 buf[0] = (slave_address << 1);
226 memcpy(&buf[1], data, size);
227 buf[size + 1] = hpm_smbus_pec_crc8(buf, size + 1);
228 buf_size = size + 1;
229 stat = i2c_slave_write(ptr, &buf[1], buf_size);
230 return stat;
231 }
232
hpm_smbus_slave_read(I2C_Type * ptr,uint8_t * data,uint32_t size)233 hpm_stat_t hpm_smbus_slave_read(I2C_Type *ptr, uint8_t *data, uint32_t size)
234 {
235 hpm_stat_t stat;
236 uint8_t pec;
237 uint8_t buf[I2C_SOC_TRANSFER_COUNT_MAX];
238 uint8_t slave_address;
239 /* frame included addr, data, and pec */
240 assert(size > 0 && size <= (I2C_SOC_TRANSFER_COUNT_MAX - 2));
241 /* addr + rw bit*/
242 slave_address = ptr->ADDR;
243 buf[0] = (slave_address << 1) | 0x01;
244 stat = i2c_slave_read(ptr, &buf[1], size + 1);
245 if (stat == status_success) {
246 pec = hpm_smbus_pec_crc8(buf, size + 1);
247 if (pec == buf[size + 1]) {
248 memcpy(data, &buf[1], size);
249 } else {
250 stat = status_fail;
251 }
252 }
253 return stat;
254 }
255
hpm_smbus_pec_crc8(uint8_t * data,uint32_t len)256 static uint8_t hpm_smbus_pec_crc8(uint8_t *data, uint32_t len)
257 {
258 /* The PEC is a CRC-8 error-checking byte, calculated on all the message bytes (including addresses and read/write bits) */
259 uint32_t i;
260 uint8_t crc = 0x00;
261 while (len--) {
262 crc ^= *data++;
263 for (i = 0; i < 8; i++) {
264 if (crc & 0x80) {
265 crc = (crc << 1) ^ 0x07;
266 } else {
267 crc <<= 1;
268 }
269 }
270 }
271 return crc;
272 }
273
274