1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017-12-04 Haley the first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "am_mcu_apollo.h"
14
15 #ifdef RT_USING_SMBUS
16
17 #define SMBUS_GPIO_SDA 5
18 #define SMBUS_GPIO_SCL 6
19
20 #define mSDA_LOW() am_hal_gpio_out_bit_clear(SMBUS_GPIO_SDA) /* Clear SDA line */
21 #define mSDA_HIGH() am_hal_gpio_out_bit_set(SMBUS_GPIO_SDA) /* Set SDA line */
22 #define mSCL_LOW() am_hal_gpio_out_bit_clear(SMBUS_GPIO_SCL) /* Clear SCL line */
23 #define mSCL_HIGH() am_hal_gpio_out_bit_set(SMBUS_GPIO_SCL) /* Set SCL line */
24
25 #define mSDA_READ() am_hal_gpio_input_bit_read(SMBUS_GPIO_SDA) /* Read SDA line */
26
27 #define mSDA_IN() am_hal_gpio_pin_config(SMBUS_GPIO_SDA, AM_HAL_GPIO_INPUT | AM_HAL_GPIO_PULL6K) /* Set SDA as Input */
28 #define mSDA_OUT() am_hal_gpio_pin_config(SMBUS_GPIO_SDA, AM_HAL_GPIO_OUTPUT) /* Set SDA as Output */
29 #define mSCL_OUT() am_hal_gpio_pin_config(SMBUS_GPIO_SCL, AM_HAL_GPIO_OUTPUT) /* Set SCL as Output */
30
31 #define ACK 0
32 #define NACK 1
33
34 /* SCL keep time */
keep_delay(void)35 static void keep_delay(void)
36 {
37 int i;
38 for(i = 0; i < 30; i++)
39 __nop();
40 }
41
few_delay(void)42 static void few_delay(void)
43 {
44 __nop();
45 __nop();
46 }
47
am_smbus_send_bit(rt_uint8_t send_bit)48 static rt_uint8_t am_smbus_send_bit(rt_uint8_t send_bit)
49 {
50 mSDA_OUT();
51 few_delay();
52
53 if(send_bit) /* Send a bit */
54 mSDA_HIGH();
55 else
56 mSDA_LOW();
57
58 mSCL_HIGH(); /* High Level of Clock Pulse */
59 keep_delay();
60
61 mSCL_LOW();
62 keep_delay();
63
64 return 0;
65 }
66
am_smbus_read_bit(void)67 static rt_uint8_t am_smbus_read_bit(void)
68 {
69 rt_uint8_t read_bit;
70
71 mSDA_IN();
72 few_delay();
73
74 mSCL_HIGH(); /* High Level of Clock Pulse */
75 keep_delay();
76
77 read_bit = mSDA_READ(); /* Read a bit, save it in Read_bit */
78
79 mSCL_LOW();
80 keep_delay();
81
82 return read_bit;
83 }
84
am_smbus_start_bit(void)85 static void am_smbus_start_bit(void)
86 {
87 mSDA_OUT();
88 mSDA_HIGH(); /* Generate bus free time between Stop */
89 keep_delay();
90 mSCL_HIGH();
91 keep_delay();
92
93 mSDA_LOW(); /* Hold time after (Repeated) Start */
94 keep_delay();
95
96 mSCL_LOW();
97 keep_delay();
98 }
99
am_smbus_stop_bit(void)100 static void am_smbus_stop_bit(void)
101 {
102 mSDA_OUT();
103 mSDA_HIGH(); /* Generate bus free time between Stop */
104 keep_delay();
105 mSCL_LOW();
106 keep_delay();
107
108 mSDA_LOW(); /* Hold time after Stop */
109 keep_delay();
110
111 mSCL_HIGH(); /* For sleep mode(SCL needs to be high during Sleep.) */
112 keep_delay();
113 }
114
am_smbus_tx_byte(rt_uint8_t tx_byte)115 static rt_uint8_t am_smbus_tx_byte(rt_uint8_t tx_byte)
116 {
117 int i;
118 rt_uint8_t ack_bit;
119 rt_uint8_t bit_out;
120
121 for(i = 0; i < 8; i++)
122 {
123 if(tx_byte&0x80)
124 bit_out = 1; /* If the current bit of Tx_buffer is 1 set bit_out */
125 else
126 bit_out = 0; /* else clear bit_out */
127
128 am_smbus_send_bit(bit_out); /* Send the current bit on SDA */
129 tx_byte <<= 1; /* Get next bit for checking */
130 }
131
132 ack_bit = am_smbus_read_bit(); /* Get acknowledgment bit */
133
134 return ack_bit;
135 }
136
am_smbus_rx_byte(rt_uint8_t ack_nack)137 static rt_uint8_t am_smbus_rx_byte(rt_uint8_t ack_nack)
138 {
139 int i;
140 rt_uint8_t rx_byte;
141
142 for(i = 0; i < 8; i++)
143 {
144 if(am_smbus_read_bit()) /* Get a bit from the SDA line */
145 {
146 rx_byte <<= 1; /* If the bit is HIGH save 1 in RX_buffer */
147 rx_byte |=0x01;
148 }
149 else
150 {
151 rx_byte <<= 1; /* If the bit is LOW save 0 in RX_buffer */
152 rx_byte &=0xfe;
153 }
154 }
155 am_smbus_send_bit(ack_nack); /* Sends acknowledgment bit */
156
157 return rx_byte;
158 }
159
am_smbus_tx_then_tx(rt_uint8_t SlaveAddress,rt_uint8_t command,rt_uint8_t * pBuffer,rt_uint16_t bytesNumber)160 rt_uint8_t am_smbus_tx_then_tx(rt_uint8_t SlaveAddress, rt_uint8_t command, rt_uint8_t* pBuffer, rt_uint16_t bytesNumber)
161 {
162 int i;
163
164 am_smbus_start_bit(); /* Start condition */
165
166 if(am_smbus_tx_byte(SlaveAddress)) /* Send SlaveAddress and write */
167 return 1;
168
169 if(am_smbus_tx_byte(command)) /* Send command */
170 return 1;
171
172 for(i = 0; i < bytesNumber; i++)
173 {
174 am_smbus_tx_byte(pBuffer[i]); /* Write data, slave must send ACK */
175 }
176
177 am_smbus_stop_bit(); /* Stop condition */
178
179 return 0;
180 }
181
am_smbus_tx_then_rx(rt_uint8_t SlaveAddress,rt_uint8_t command,rt_uint8_t * pBuffer,rt_uint16_t bytesNumber)182 rt_uint8_t am_smbus_tx_then_rx(rt_uint8_t SlaveAddress, rt_uint8_t command, rt_uint8_t* pBuffer, rt_uint16_t bytesNumber)
183 {
184 int i;
185
186 am_smbus_start_bit(); /* Start condition */
187
188 if(am_smbus_tx_byte(SlaveAddress)) /* Send SlaveAddress and write */
189 return 1;
190
191 if(am_smbus_tx_byte(command)) /* Send command */
192 return 1;
193
194 am_smbus_start_bit(); /* Repeated Start condition */
195
196 if(am_smbus_tx_byte(SlaveAddress | 0x01)) /* Send SlaveAddress and read */
197 return 1;
198
199 for(i = 0; i < bytesNumber; i++)
200 {
201 pBuffer[i] = am_smbus_rx_byte(ACK); /* Read data, master must send ACK */
202 }
203
204 am_smbus_stop_bit(); /* Stop condition */
205
206 return 0;
207 }
208
am_smbus_scl_high(void)209 void am_smbus_scl_high(void)
210 {
211 mSCL_HIGH(); /* For sleep mode(SCL needs to be high during Sleep.) */
212 keep_delay();
213 }
214
am_smbus_scl_low(void)215 void am_smbus_scl_low(void)
216 {
217 mSCL_LOW(); /* For sleep mode(SCL needs to be high during Sleep.) */
218 keep_delay();
219 }
220
rt_hw_smbus_init(void)221 int rt_hw_smbus_init(void)
222 {
223 mSDA_OUT();
224 mSCL_OUT();
225 mSDA_HIGH(); /* bus free */
226 mSCL_HIGH();
227
228 return 0;
229 }
230 #ifdef RT_USING_COMPONENTS_INIT
231 INIT_BOARD_EXPORT(rt_hw_smbus_init);
232 #endif
233
234 #endif
235
236 /*@}*/
237