1 /*
2  * Copyright (c) 2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 
9 #ifndef HPM_ESC_DRV_H
10 #define HPM_ESC_DRV_H
11 
12 #include "hpm_common.h"
13 #include "hpm_esc_regs.h"
14 
15 /**
16  *
17  * @brief ESC driver APIs
18  * @defgroup esc_interface ESC driver APIs
19  * @ingroup esc_interfaces
20  * @{
21  */
22 
23  /**
24  * @brief ESC error codes
25  */
26 enum {
27     status_esc_eeprom_ack_error      = MAKE_STATUS(status_group_esc, 0),           /**< ESC EEPROM ack error */
28     status_esc_eeprom_checksum_error = MAKE_STATUS(status_group_esc, 1),           /**< ESC EEPROM checksum error */
29 };
30 
31 
32 typedef enum {
33     latch_source_from_ntm = 0,
34     latch_source_from_trigger_mux = 1,
35 } esc_latch_source_t;
36 
37 typedef enum {
38     esc_eeprom_idle_cmd = 0, /* clear error bits */
39     esc_eeprom_read_cmd = 1,
40     esc_eeprom_write_cmd = 2,
41     esc_eeprom_reload_cmd = 4,
42 } esc_eeprom_cmd_t;
43 
44 typedef enum  {
45     esc_ctrl_signal_func_alt_nmii_link0 = 0,
46     esc_ctrl_signal_func_alt_nmii_link1 = 1,
47     esc_ctrl_signal_func_alt_nmii_link2 = 2,
48     esc_ctrl_signal_func_alt_link_act0  = 3,
49     esc_ctrl_signal_func_alt_link_act1  = 4,
50     esc_ctrl_signal_func_alt_link_act2  = 5,
51     esc_ctrl_signal_func_alt_led_run    = 6,
52     esc_ctrl_signal_func_alt_led_err    = 7,
53     esc_ctrl_signal_func_alt_reset_out  = 8,
54 } esc_ctrl_signal_function_t;
55 
56 
57 typedef struct {
58     bool eeprom_emulation;
59     bool eeprom_size_over_16kbit;
60     bool core_clock_en;
61     bool phy_refclk_en;
62 } esc_eeprom_clock_config_t;
63 
64 
65 #ifdef __cplusplus
66 extern "C" {
67 #endif
68 
69 /**
70  * @brief ESC peripheral clock
71  *
72  * @param[in] ptr ESC base address
73  * @param[in] enable Set true to enable or false to disable
74  */
esc_core_enable_clock(ESC_Type * ptr,bool enable)75 static inline void esc_core_enable_clock(ESC_Type *ptr, bool enable)
76 {
77     if (enable) {
78         ptr->GPR_CFG0 |= ESC_GPR_CFG0_CLK100_EN_MASK;
79     } else {
80         ptr->GPR_CFG0 &= ~ESC_GPR_CFG0_CLK100_EN_MASK;
81     }
82 }
83 
84 /**
85  * @brief ESC PHY clock
86  *
87  * @param[in] ptr ESC base address
88  * @param[in] enable Set true to enable or false to disable
89  */
esc_phy_enable_clock(ESC_Type * ptr,bool enable)90 static inline void esc_phy_enable_clock(ESC_Type *ptr, bool enable)
91 {
92     if (enable) {
93         ptr->PHY_CFG1 |= ESC_PHY_CFG1_REFCK_25M_OE_MASK;   /*!< enable PHY 25M refck */
94     } else {
95         ptr->PHY_CFG1 &= ~ESC_PHY_CFG1_REFCK_25M_OE_MASK;   /*!< disable PHY 25M refck */
96     }
97 }
98 
99 /**
100  * @brief ESC config eeprom attributes(emulation and size) and peripheral clock
101  *
102  * @param[in] ptr ESC base address
103  * @param[in] config esc_eeprom_clock_config_t
104  */
esc_config_eeprom_and_clock(ESC_Type * ptr,esc_eeprom_clock_config_t * config)105 static inline void esc_config_eeprom_and_clock(ESC_Type *ptr, esc_eeprom_clock_config_t *config)
106 {
107     uint32_t gpr_cfg0 = ptr->GPR_CFG0;
108 
109     if (config->eeprom_emulation) {
110         gpr_cfg0 |= ESC_GPR_CFG0_EEPROM_EMU_MASK;
111         gpr_cfg0 &= ~(ESC_GPR_CFG0_PROM_SIZE_MASK | ESC_GPR_CFG0_I2C_SCLK_EN_MASK);
112     } else {
113         gpr_cfg0 &= ~ESC_GPR_CFG0_EEPROM_EMU_MASK;
114         gpr_cfg0 |= ESC_GPR_CFG0_I2C_SCLK_EN_MASK;
115         if (config->eeprom_size_over_16kbit) {
116             gpr_cfg0 |= ESC_GPR_CFG0_PROM_SIZE_MASK;
117         } else {
118             gpr_cfg0 &= ~ESC_GPR_CFG0_PROM_SIZE_MASK;
119         }
120     }
121     ptr->GPR_CFG0 = gpr_cfg0;
122     esc_core_enable_clock(ptr, config->core_clock_en);
123     esc_phy_enable_clock(ptr, config->phy_refclk_en);
124 }
125 
126 /**
127  * @brief ESC assign specific function to CTRL signal
128  *
129  * @param[in] ptr ESC base address
130  * @param[in] index CTRL signal index(0-8)
131  * @param[in] func specific function
132  * @param[in] invert invert signal
133  */
esc_config_ctrl_signal_function(ESC_Type * ptr,uint8_t index,esc_ctrl_signal_function_t func,bool invert)134 static inline void esc_config_ctrl_signal_function(ESC_Type *ptr, uint8_t index, esc_ctrl_signal_function_t func, bool invert)
135 {
136     ptr->IO_CFG[index] = ESC_IO_CFG_FUNC_ALT_SET(func) | ESC_IO_CFG_INVERT_SET(invert);
137 }
138 
139 /**
140  * @brief ESC config nmii_link signal source
141  *
142  * @param[in] ptr ESC base address
143  * @param[in] link0_from_io true for signal from configured IO; false for signal from register(GPR_CFG2) value
144  * @param[in] link1_from_io true for signal from configured IO; false for signal from register(GPR_CFG2) value
145  * @param[in] link2_from_io true for signal from configured IO; false for signal from register(GPR_CFG2) value
146  */
esc_config_nmii_link_source(ESC_Type * ptr,bool link0_from_io,bool link1_from_io,bool link2_from_io)147 static inline void esc_config_nmii_link_source(ESC_Type *ptr, bool link0_from_io, bool link1_from_io, bool link2_from_io)
148 {
149     if (link0_from_io) {
150         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK0_FROM_IO_MASK;
151     } else {
152         ptr->GPR_CFG2 &= ~ESC_GPR_CFG2_NMII_LINK0_FROM_IO_MASK;
153         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK0_GPR_MASK; /* config GRP to indicate LINK0 is invalid by default */
154     }
155 
156     if (link1_from_io) {
157         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK1_FROM_IO_MASK;
158     } else {
159         ptr->GPR_CFG2 &= ~ESC_GPR_CFG2_NMII_LINK1_FROM_IO_MASK;
160         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK1_GPR_MASK; /* config GRP to indicate LINK1 is invalid by default */
161     }
162 
163     if (link2_from_io) {
164         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK2_FROM_IO_MASK;
165     } else {
166         ptr->GPR_CFG2 &= ~ESC_GPR_CFG2_NMII_LINK2_FROM_IO_MASK;
167         ptr->GPR_CFG2 |= ESC_GPR_CFG2_NMII_LINK2_GPR_MASK; /* config GRP to indicate LINK2 is invalid by default */
168     }
169 }
170 
171 /* config ESC reset request source: ESC core or GRP_REG value */
172 /**
173  * @brief ESC config reset signal source
174  *
175  * @param[in] ptr ESC base address
176  * @param[in] reset_from_ecat_core true for reset signal from ecat core; false for reset signal from register(GPR_CFG1) value
177  */
esc_config_reset_source(ESC_Type * ptr,bool reset_from_ecat_core)178 static inline void esc_config_reset_source(ESC_Type *ptr, bool reset_from_ecat_core)
179 {
180     if (reset_from_ecat_core) {
181         ptr->GPR_CFG1 |= ESC_GPR_CFG1_RSTO_OVRD_ENJ_MASK;
182     } else {
183         ptr->GPR_CFG1 &= ~ESC_GPR_CFG1_RSTO_OVRD_ENJ_MASK;
184     }
185 }
186 
187 /**
188  * @brief ESC generate reset signal to ESC_RESET interrupt and RESET_OUT pin
189  * @note the reset signal source should be configured in esc_config_reset_source before
190  *
191  * @param[in] ptr ESC base address
192  */
esc_pdi_reset(ESC_Type * ptr)193 static inline void esc_pdi_reset(ESC_Type *ptr)
194 {
195     ptr->ESC_RST_PDI = 0x52; /* R */
196     ptr->ESC_RST_PDI = 0x45; /* E */
197     ptr->ESC_RST_PDI = 0x53; /* S */
198 }
199 
200 /*!
201  * @brief ESC read PHY register via ESC MII Management Interface
202  *
203  * @param[in] ptr ESC base address
204  * @param[in] phy_addr PHY address.
205  * @param[in] reg_addr Register address.
206  * @param[in] data PHY data returned.
207  */
208 
209 hpm_stat_t esc_mdio_read(ESC_Type *ptr, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data);
210 
211 /*!
212  * @brief ESc write PHY register via ESC MII Management Interface
213  *
214  * @param[in] ptr ESC base address
215  * @param[in] phy_addr PHY address.
216  * @param[in] reg_addr Register address.
217  * @param[in] data Write to PHY register.
218  */
219 hpm_stat_t esc_mdio_write(ESC_Type *ptr, uint8_t phy_addr, uint8_t reg_addr, uint16_t data);
220 
221 /*!
222  * @brief ESC check eeprom loading data status
223  * @note EtherCAT communication is possible even if the EEPROM is blank
224  *
225  * @param[in] ptr ESC base address.
226  * @retval status_success: loding data successfully and correctlly.
227  * @retval status_esc_eeprom_ack_error: loding  data checksum error(eeprom blank).
228  * @retval status_esc_eeprom_checksum_error: no ack error.
229  * @retval status_timeout: loding data timeout.
230  */
231 hpm_stat_t esc_check_eeprom_loading(ESC_Type *ptr);
232 
233 /*!
234  * @brief ESC get eeprom cmd, this using in eeprom emulation function
235  *
236  * @param[in] ptr ESC base address
237  * @return uint8_t esc_eeprom_cmd_t.
238  */
esc_get_eeprom_cmd(ESC_Type * ptr)239 static inline uint8_t esc_get_eeprom_cmd(ESC_Type *ptr)
240 {
241     return ESC_EEPROM_CTRL_STAT_CMD_GET(ptr->EEPROM_CTRL_STAT);
242 }
243 
244 /*!
245  * @brief ESC ack eeprom cmd in eeprom emualtion function
246  *
247  * @param[in] ptr ESC base address
248  * @param[in] cmd esc_eeprom_cmd_t
249  * @param[in] ack_err eeprom ack error occurrred
250  * @param[in] crc_err eeprom checksum error occurrred
251  */
esc_eeprom_emulation_ack(ESC_Type * ptr,esc_eeprom_cmd_t cmd,bool ack_err,bool crc_err)252 static inline void esc_eeprom_emulation_ack(ESC_Type *ptr, esc_eeprom_cmd_t cmd, bool ack_err, bool crc_err)
253 {
254     uint16_t temp = ESC_EEPROM_CTRL_STAT_CMD_SET(cmd);
255     if (ack_err) {
256         temp |= ESC_EEPROM_CTRL_STAT_ERR_ACK_CMD_MASK;
257     }
258     if (crc_err) {
259         temp |= ESC_EEPROM_CTRL_STAT_CKSM_ERR_MASK;
260     }
261 
262     ptr->EEPROM_CTRL_STAT = temp;
263 }
264 
265 /*!
266  * @brief ESC get eeprom byte address
267  *
268  * @param[in] ptr ESC base address
269  * @return byte address
270  */
esc_get_eeprom_byte_address(ESC_Type * ptr)271 static inline uint32_t esc_get_eeprom_byte_address(ESC_Type *ptr)
272 {
273     return (ptr->EEPROM_ADDR) << 1U;
274 }
275 
276 /*!
277  * @brief ESC get eeprom word(2 bytes) address
278  *
279  * @param[in] ptr ESC base address
280  * @return word address
281  */
esc_get_eeprom_word_address(ESC_Type * ptr)282 static inline uint32_t esc_get_eeprom_word_address(ESC_Type *ptr)
283 {
284     return ptr->EEPROM_ADDR;
285 }
286 
287 /*!
288  * @brief ESC read eeprom data from register, this function is using in eeprom emulation function
289  *
290  * @param[in] ptr ESC base address
291  * @return eeprom data
292  */
esc_read_eeprom_data(ESC_Type * ptr)293 static inline uint64_t esc_read_eeprom_data(ESC_Type *ptr)
294 {
295     return ptr->EEPROM_DATA;
296 }
297 
298 /*!
299  * @brief ESC write eeprom data to register, this function is using in eeprom emulation function
300  *
301  * @param[in] ptr ESC base address
302  * @param[in] data eeprom data
303  */
esc_write_eeprom_data(ESC_Type * ptr,uint64_t data)304 static inline void esc_write_eeprom_data(ESC_Type *ptr, uint64_t data)
305 {
306     ptr->EEPROM_DATA = data;
307 }
308 
309 /*!
310  * @brief ESC config latch0 signal source
311  *
312  * @param[in] ptr ESC base address
313  * @param[in] latch0_from_ntm true for signal from ntm system, false for signal from IO
314  */
esc_config_latch0_source(ESC_Type * ptr,bool latch0_from_ntm)315 static inline void esc_config_latch0_source(ESC_Type *ptr, bool latch0_from_ntm)
316 {
317     if (latch0_from_ntm) {
318         ptr->GPR_CFG1 &= ~ESC_GPR_CFG1_LATCH0_FROM_IO_MASK;
319     } else {
320         ptr->GPR_CFG1 |= ESC_GPR_CFG1_LATCH0_FROM_IO_MASK;
321     }
322 }
323 
324 /*!
325  * @brief ESC config latch1 signal source
326  *
327  * @param[in] ptr ESC base address
328  * @param[in] latch0_from_trigmux true for signal from trigmux system, false for signal from IO
329  */
esc_config_latch1_source(ESC_Type * ptr,bool latch0_from_trigmux)330 static inline void esc_config_latch1_source(ESC_Type *ptr, bool latch0_from_trigmux)
331 {
332     if (latch0_from_trigmux) {
333         ptr->GPR_CFG1 &= ~ESC_GPR_CFG1_LATCH1_FROM_IO_MASK;
334     } else {
335         ptr->GPR_CFG1 |= ESC_GPR_CFG1_LATCH1_FROM_IO_MASK;
336     }
337 }
338 
339 
340 
341 #ifdef __cplusplus
342 }
343 #endif
344 /**
345  * @}
346  */
347 #endif /* HPM_ESC_DRV_H */
348