• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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