1 /*
2 * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include <device_mec5.h>
10 #include "mec_pcfg.h"
11 #include "mec_defs.h"
12 #include "mec_ecia_api.h"
13 #include "mec_i2c_api.h"
14 #include "mec_pcr_api.h"
15 #include "mec_retval.h"
16
17 /* MEC5 I2C controller notes:
18 * The I2C byte mode Control(WO) and Status(RO) register are both located at offset 0.
19 * I2C.STATUS register is an 8-bit read-only status register:
20 * bit[0] = Not Bus Busy(NBB) 0 indicates the bus is owned by this controller.
21 * bit[1] = Lost Arbitration(LAB) 1 indicates controller lost arbitration to another
22 * controller on the bus. LAB detection is performed during data transfer,
23 * ackowledgement, START, and Repeated-START phases of the transfer. LAB
24 * is not checked during a STOP phase. If LAB occurs this controller will tri-state
25 * its pins and continue to clock in the address/data from the external controller.
26 * On the 9th clock NIPEND and LAB will both assert.
27 * I2C-NL CM FSM will transition to IDLE state after 9th clock (n)ACK bit and
28 * clear the PIN bit to 1(de-asserted).
29 * bit[2] = AAS = 1 indicates an external Controller issued (RPT)-START + target address
30 * the target address matches one of the two target addresses in this controller's
31 * own address register or the I2C generate call address(0x00). NOTE: general
32 * call address detction can be enabled/disabled in the Configuration register.
33 * bit[3] = LRB_AD0 value interpretation depends upon the AAS status bit.
34 * AAS==0: LRB is the last received bit on the bus. Usually this is the value
35 * of SDA on the 9th I2C clock (0=ACK, 1=NACK).
36 * AAS==1: AD0=1 if received target address was the I2C GC(0x00) address else
37 * 0 if the target address matched one of the controller's own addresses.
38 * bit[4] = BER 1 = Controller detected a bus error. Assertion of BER cause the controller
39 * to de-assert NBB and NPIPEND: NBB=1 and NIPEND=1.
40 * bit[5] = STS 1 = externally generated STOP was detected. BROKEN in MEC520x. A HW fix
41 * implemented in MEC540x.
42 * bit[6] = SAD 1 = SMBus address decode asserted if enabled in the Configuration register.
43 * bit[7] = NIPEND 1 = No Interrupt Pending(de-asserted). 1 = Interrupt is Pending(asserted).
44 * NIPEND is asserted(0) after the 9th I2C clock or on detection of a bus error.
45 * TX direction: NIPEND de-asserted when I2C.Data register is written.
46 * RX direction: NIPEND de-asserted when I2C.Data is read.
47 * NOTE: In Controller Mode reading I2C.Data when direction is RX and I2C.CTRL.STO=0
48 * returns current data byte and generates clocks for the next byte (read-ahead).
49 * HW determines direction based on the W/nR bit which is bit[0] of the I2C target
50 * address.
51 *
52 * I2C.CTRL register is an 8-bit write-only control register:
53 * bit[0] = ACK = 1 HW will generate an ACK on the 9th after receiving a
54 * data byte from an external Controller.
55 * bit[1] = STO = 1 generate a STOP
56 * bit[2] = STA = 1 generate a START and transmit the address in the I2C.DATA register.
57 * bit[3] = ENI = 1 Assert the I2C controller's interrupt active signal to the corresponding
58 * GIRQ Source bit. Interrupt signal asserted when I2C.STATUS.NIPEND -> 0.
59 * bits[5:4] = reserved
60 * bit[6] = ESO = 1 Enable SDA outout. 0 = SDA disabled.
61 * bit[7] = NIPEND_RST = Not Pending Interrupt. A software reset de-asserting all status
62 * except the Not Bus Busy status bit. WARNING: Behaviour of this bit
63 * depends upon the I2C FSM state.
64 *
65 * Controller clears I2C.CTRL.STA write-only bit after 7th clock of I2C address.
66 * Controller clears I2C.CTRL.STO write-only bit when it drives SDA low at
67 * the beginning of generating the STOP sequence on the bus. This occurs
68 * a minimum 1/2 I2C clock period after the 9th clock pulse of the previous
69 * data on the bus.
70 */
71 #define MEC_I2C_SMB_COMPL_STS_RW1C_MSK 0xe1397f00u
72 #define MEC_I2C_SMB_COMPL_STS_RO_MSK 0x02020040u
73 #define MEC_I2C_SMB_COMPL_EN_RW_MSK 0x3cu
74
75 #define MEC_I2C_SMB0_ECIA_INFO MEC5_ECIA_INFO(13, 0, 5, 20)
76 #define MEC_I2C_SMB1_ECIA_INFO MEC5_ECIA_INFO(13, 1, 5, 21)
77 #define MEC_I2C_SMB2_ECIA_INFO MEC5_ECIA_INFO(13, 2, 5, 22)
78 #define MEC_I2C_SMB3_ECIA_INFO MEC5_ECIA_INFO(13, 3, 5, 23)
79 #define MEC_I2C_SMB4_ECIA_INFO MEC5_ECIA_INFO(13, 4, 5, 158)
80
81 /* #define MEC_I2C_NL_DEBUG_SAVE_CM_CMD */
82
83 struct mec_i2c_info {
84 uintptr_t base_addr;
85 uint32_t devi;
86 uint16_t pcr_id;
87 };
88
89 static const struct mec_i2c_freq_cfg freq_cfg_dflt[MEC_I2C_STD_FREQ_MAX] = {
90 [MEC_I2C_STD_FREQ_100K] = {
91 .freqhz = 100000u,
92 .idle_scaling = 0x01fc01edu,
93 .timeout_scaling = 0x4b9cc2c7u,
94 .data_timing = 0x0c4d5006u,
95 .bus_clk = 0x4f4fu,
96 .rpt_start_hold_time = 0x4du,
97 },
98 [MEC_I2C_STD_FREQ_400K] = {
99 .freqhz = 400000u,
100 .idle_scaling = 0x01000050u,
101 .timeout_scaling = 0x159cc2c7u,
102 .data_timing = 0x040a0a06u,
103 .bus_clk = 0xf17u,
104 .rpt_start_hold_time = 0x0au,
105 },
106 [MEC_I2C_STD_FREQ_1M] = {
107 .freqhz = 1000000u,
108 .idle_scaling = 0x10000050u,
109 .timeout_scaling = 0x089cc2c7u,
110 .data_timing = 0x04060601u,
111 .bus_clk = 0x509u,
112 .rpt_start_hold_time = 0x06u,
113 },
114 };
115
116 static const struct mec_i2c_info i2c_instances[MEC5_I2C_SMB_INSTANCES] = {
117 {MEC_I2C_SMB0_BASE, MEC_I2C_SMB0_ECIA_INFO, MEC_PCR_I2C_SMB0 },
118 {MEC_I2C_SMB1_BASE, MEC_I2C_SMB1_ECIA_INFO, MEC_PCR_I2C_SMB1 },
119 {MEC_I2C_SMB2_BASE, MEC_I2C_SMB2_ECIA_INFO, MEC_PCR_I2C_SMB2 },
120 {MEC_I2C_SMB3_BASE, MEC_I2C_SMB3_ECIA_INFO, MEC_PCR_I2C_SMB3 },
121 {MEC_I2C_SMB4_BASE, MEC_I2C_SMB4_ECIA_INFO, MEC_PCR_I2C_SMB4 },
122 };
123
get_i2c_smb_info(struct mec_i2c_smb_regs * base)124 static struct mec_i2c_info const *get_i2c_smb_info(struct mec_i2c_smb_regs *base)
125 {
126 for (int i = 0; i < MEC5_I2C_SMB_INSTANCES; i++) {
127 const struct mec_i2c_info *p = &i2c_instances[i];
128
129 if (p->base_addr == (uintptr_t)base) {
130 return p;
131 }
132 }
133
134 return NULL;
135 }
136
mec_hal_i2c_smb_reset(struct mec_i2c_smb_ctx * ctx)137 int mec_hal_i2c_smb_reset(struct mec_i2c_smb_ctx *ctx)
138 {
139 if (!ctx) {
140 return MEC_RET_ERR_INVAL;
141 }
142
143 const struct mec_i2c_info *info = get_i2c_smb_info(ctx->base);
144
145 if (!info) {
146 return MEC_RET_ERR_INVAL;
147 }
148
149 mec_hal_pcr_blk_reset(info->pcr_id);
150
151 return MEC_RET_OK;
152 }
153
i2c_timing(struct mec_i2c_smb_regs * base,const struct mec_i2c_freq_cfg * freq_cfg)154 static void i2c_timing(struct mec_i2c_smb_regs *base, const struct mec_i2c_freq_cfg *freq_cfg)
155 {
156 base->BUSCLK = freq_cfg->bus_clk;
157 base->RSHT = freq_cfg->rpt_start_hold_time;
158 base->DATATM = freq_cfg->data_timing;
159 base->IDLESC = freq_cfg->idle_scaling;
160 base->TMOUTSC = freq_cfg->timeout_scaling;
161 }
162
i2c_config(struct mec_i2c_smb_ctx * ctx,struct mec_i2c_smb_cfg * config,struct mec_i2c_freq_cfg * custom_freq_cfg)163 static void i2c_config(struct mec_i2c_smb_ctx *ctx, struct mec_i2c_smb_cfg *config,
164 struct mec_i2c_freq_cfg *custom_freq_cfg)
165 {
166 struct mec_i2c_smb_regs *base = ctx->base;
167 uint8_t control = MEC_BIT(MEC_I2C_SMB_CTRL_PIN_Pos); /* clear low level HW status */
168
169 /* disable and set port MUX */
170 base->CONFIG = (((uint32_t)config->port << MEC_I2C_SMB_CONFIG_PORT_SEL_Pos)
171 & MEC_I2C_SMB_CONFIG_PORT_SEL_Msk);
172 base->CONFIG |= MEC_BIT(MEC_I2C_SMB_CONFIG_FEN_Pos); /* enable digital filter */
173
174 base->CTRL = control;
175 ctx->i2c_ctrl_cached = control;
176
177 /* GCC 12 is generating a 16-bit load from an odd aligned address!
178 * base->OWN_ADDR = (uint32_t)config->target_addr1 | ((uint32_t)config->target_addr2 << 8);
179 * Try forcing it not to do that.
180 */
181 base->OWN_ADDR = config->target_addr2;
182 base->OWN_ADDR = (base->OWN_ADDR << 8) | config->target_addr1;
183
184 if (config->cfg_flags & MEC_I2C_SMB_CFG_CUST_FREQ) {
185 i2c_timing(base, custom_freq_cfg);
186 } else {
187 i2c_timing(base, &freq_cfg_dflt[config->std_freq]);
188 }
189
190 base->COMPL = MEC_I2C_SMB_COMPL_STS_RW1C_MSK;
191
192 /* Enable output drive and HW ACK generation */
193 control = (MEC_BIT(MEC_I2C_SMB_CTRL_PIN_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos)
194 | MEC_BIT(MEC_I2C_SMB_CTRL_ACK_Pos));
195 ctx->i2c_ctrl_cached = control;
196 base->CTRL = control;
197
198 base->CONFIG |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENAB_Pos);
199 for (int i = 0; i < 8; i++) {
200 base->EXTLEN = 0;
201 }
202 base->COMPL |= MEC_I2C_SMB_COMPL_STS_RW1C_MSK;
203 }
204
mec_hal_i2c_smb_init(struct mec_i2c_smb_ctx * ctx,struct mec_i2c_smb_cfg * config,struct mec_i2c_freq_cfg * custom_freq_cfg)205 int mec_hal_i2c_smb_init(struct mec_i2c_smb_ctx *ctx, struct mec_i2c_smb_cfg *config,
206 struct mec_i2c_freq_cfg *custom_freq_cfg)
207 {
208 if (!ctx) {
209 return MEC_RET_ERR_INVAL;
210 }
211
212 const struct mec_i2c_info *info = get_i2c_smb_info(ctx->base);
213
214 if (!info || !config) {
215 return MEC_RET_ERR_INVAL;
216 }
217
218 ctx->devi = info->devi;
219
220 mec_hal_pcr_clr_blk_slp_en(info->pcr_id);
221 mec_hal_pcr_blk_reset(info->pcr_id);
222
223 if (!(MEC_BIT(config->port) & MEC5_I2C_SMB_PORT_MAP)) {
224 return MEC_RET_ERR_INVAL;
225 }
226
227 if ((config->cfg_flags & MEC_I2C_SMB_CFG_CUST_FREQ) && !custom_freq_cfg) {
228 return MEC_RET_ERR_INVAL;
229 } else if (config->std_freq >= MEC_I2C_STD_FREQ_MAX) {
230 return MEC_RET_ERR_INVAL;
231 }
232
233 /* configure controller and cache last value written to write-only control register */
234 i2c_config(ctx, config, custom_freq_cfg);
235
236 /* clear GIRQ latched status */
237 mec_hal_girq_clr_src(ctx->devi);
238
239 return MEC_RET_OK;
240 }
241
mec_hal_i2c_smb_girq_status_clr(struct mec_i2c_smb_ctx * ctx)242 int mec_hal_i2c_smb_girq_status_clr(struct mec_i2c_smb_ctx *ctx)
243 {
244 if (!ctx) {
245 return MEC_RET_ERR_INVAL;
246 }
247
248 mec_hal_girq_clr_src(ctx->devi);
249
250 return MEC_RET_OK;
251 }
252
253 /* Enable/disable I2C controller interrupt signal from propagating to NVIC */
mec_hal_i2c_smb_girq_ctrl(struct mec_i2c_smb_ctx * ctx,int flags)254 int mec_hal_i2c_smb_girq_ctrl(struct mec_i2c_smb_ctx *ctx, int flags)
255 {
256 if (!ctx) {
257 return MEC_RET_ERR_INVAL;
258 }
259
260 if (flags & MEC_I2C_SMB_GIRQ_DIS) {
261 mec_hal_girq_ctrl(ctx->devi, 0);
262 }
263
264 if (flags & MEC_I2C_SMB_GIRQ_CLR_STS) {
265 mec_hal_girq_clr_src(ctx->devi);
266 }
267
268 if (flags & MEC_I2C_SMB_GIRQ_EN) {
269 mec_hal_girq_ctrl(ctx->devi, 1);
270 }
271
272 return MEC_RET_OK;
273 }
274
mec_hal_i2c_smb_girq_status(struct mec_i2c_smb_ctx * ctx)275 int mec_hal_i2c_smb_girq_status(struct mec_i2c_smb_ctx *ctx)
276 {
277 if (!ctx) {
278 return 0;
279 }
280
281 return (int)mec_hal_girq_src(ctx->devi);
282 }
283
mec_hal_i2c_smb_girq_result(struct mec_i2c_smb_ctx * ctx)284 int mec_hal_i2c_smb_girq_result(struct mec_i2c_smb_ctx *ctx)
285 {
286 if (!ctx) {
287 return 0;
288 }
289
290 return (int)mec_hal_girq_result(ctx->devi);
291 }
292
293 /* check I2C.Status Not Busy bit. If set the bus is NOT owned by this controller.
294 * Returns 0 if not owned or the parameter check fails.
295 * 1 if bus is owned by this controller.
296 */
mec_hal_i2c_smb_is_bus_owned(struct mec_i2c_smb_ctx * ctx)297 int mec_hal_i2c_smb_is_bus_owned(struct mec_i2c_smb_ctx *ctx)
298 {
299 #ifdef MEC_I2C_BASE_CHECK
300 if (!ctx || !ctx->base) {
301 return 0;
302 }
303 #endif
304 struct mec_i2c_smb_regs *base = ctx->base;
305
306 if (base->STATUS & MEC_BIT(MEC_I2C_SMB_STATUS_NBB_Pos)) {
307 return 0;
308 }
309
310 return 1;
311 }
312
mec_hal_i2c_smb_ctrl_set(struct mec_i2c_smb_ctx * ctx,uint8_t ctrl)313 int mec_hal_i2c_smb_ctrl_set(struct mec_i2c_smb_ctx * ctx, uint8_t ctrl)
314 {
315 #ifdef MEC_I2C_BASE_CHECK
316 if (!ctx || !ctx->base) {
317 return MEC_RET_ERR_INVAL;
318 }
319 #endif
320 struct mec_i2c_smb_regs *base = ctx->base;
321
322 ctx->i2c_ctrl_cached = ctrl;
323 base->CTRL = ctrl;
324
325 return MEC_RET_OK;
326 }
327
mec_hal_i2c_smb_ctrl_get(struct mec_i2c_smb_ctx * ctx)328 uint8_t mec_hal_i2c_smb_ctrl_get(struct mec_i2c_smb_ctx *ctx)
329 {
330 if (!ctx) {
331 return 0u;
332 }
333
334 return ctx->i2c_ctrl_cached;
335 }
336
337 /* Re-arm Target mode receive after an external STOP. */
mec_hal_i2c_smb_rearm_target_rx(struct mec_i2c_smb_ctx * ctx)338 int mec_hal_i2c_smb_rearm_target_rx(struct mec_i2c_smb_ctx *ctx)
339 {
340 uint8_t ctr = (MEC_BIT(MEC_I2C_SMB_CTRL_PIN_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos)
341 | MEC_BIT(MEC_I2C_SMB_CTRL_ACK_Pos));
342
343 return mec_hal_i2c_smb_ctrl_set(ctx, ctr);
344 }
345
mec_hal_i2c_smb_auto_ack_enable(struct mec_i2c_smb_ctx * ctx,uint8_t ien)346 int mec_hal_i2c_smb_auto_ack_enable(struct mec_i2c_smb_ctx *ctx, uint8_t ien)
347 {
348 #ifdef MEC_I2C_BASE_CHECK
349 if (!ctx || !ctx->base) {
350 return MEC_RET_ERR_INVAL;
351 }
352 #endif
353 struct mec_i2c_smb_regs *base = ctx->base;
354 uint8_t ctr = MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_ACK_Pos);
355
356 if (ien) {
357 ctr |= MEC_BIT(MEC_I2C_SMB_CTRL_ENI_Pos);
358 }
359
360 ctx->i2c_ctrl_cached = ctr;
361 base->CTRL = ctr;
362 return MEC_RET_OK;
363 }
364
mec_hal_i2c_smb_auto_ack_disable(struct mec_i2c_smb_ctx * ctx,uint8_t ien)365 int mec_hal_i2c_smb_auto_ack_disable(struct mec_i2c_smb_ctx *ctx, uint8_t ien)
366 {
367 #ifdef MEC_I2C_BASE_CHECK
368 if (!ctx || !ctx->base) {
369 return MEC_RET_ERR_INVAL;
370 }
371 #endif
372 struct mec_i2c_smb_regs *base = ctx->base;
373 uint8_t ctr = MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos);
374
375 if (ien) {
376 ctr |= MEC_BIT(MEC_I2C_SMB_CTRL_ENI_Pos);
377 }
378
379 ctx->i2c_ctrl_cached = ctr;
380 base->CTRL = ctr;
381 return MEC_RET_OK;
382 }
383
mec_hal_i2c_smb_idle_intr_enable(struct mec_i2c_smb_ctx * ctx,uint8_t enable)384 int mec_hal_i2c_smb_idle_intr_enable(struct mec_i2c_smb_ctx *ctx, uint8_t enable)
385 {
386 #ifdef MEC_I2C_BASE_CHECK
387 if (!ctx || !ctx->base) {
388 return MEC_RET_ERR_INVAL;
389 }
390 #endif
391
392 struct mec_i2c_smb_regs *base = ctx->base;
393
394 if (enable) {
395 base->CONFIG |= MEC_BIT(MEC_I2C_SMB_COMPL_IDLE_Pos);
396 } else {
397 base->CONFIG &= (uint32_t)~MEC_BIT(MEC_I2C_SMB_COMPL_IDLE_Pos);
398 }
399
400 return MEC_RET_OK;
401 }
402
mec_hal_i2c_smb_intr_ctrl(struct mec_i2c_smb_ctx * ctx,uint32_t mask,uint8_t enable)403 int mec_hal_i2c_smb_intr_ctrl(struct mec_i2c_smb_ctx *ctx, uint32_t mask, uint8_t enable)
404 {
405 uint32_t cfg = 0;
406
407 #ifdef MEC_I2C_BASE_CHECK
408 if (!ctx || !ctx->base) {
409 return MEC_RET_ERR_INVAL;
410 }
411 #endif
412
413 struct mec_i2c_smb_regs *regs = ctx->base;
414
415 if (mask & MEC_BIT(MEC_I2C_IEN_BYTE_MODE_POS)) {
416 if (enable) {
417 ctx->i2c_ctrl_cached |= MEC_BIT(MEC_I2C_SMB_CTRL_ENI_Pos);
418 } else {
419 ctx->i2c_ctrl_cached &= (uint8_t)~MEC_BIT(MEC_I2C_SMB_CTRL_ENI_Pos);
420 }
421 regs->CTRL = ctx->i2c_ctrl_cached;
422 }
423
424 if (mask & MEC_BIT(MEC_I2C_IEN_IDLE_POS)) {
425 cfg |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENI_IDLE_Pos);
426 }
427 if (mask & MEC_BIT(MEC_I2C_NL_IEN_CM_DONE_POS)) {
428 cfg |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENMI_Pos);
429 }
430 if (mask & MEC_BIT(MEC_I2C_NL_IEN_TM_DONE_POS)) {
431 cfg |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENSI_Pos);
432 }
433 if (mask & MEC_BIT(MEC_I2C_NL_IEN_AAT_POS)) {
434 cfg |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENI_AAS_Pos);
435 }
436
437 if (enable) {
438 regs->CONFIG |= cfg;
439 } else {
440 regs->CONFIG &= ~cfg;
441 }
442
443 return MEC_RET_OK;
444 }
445
446 /* Returns 32-bit unsigned containing combined I2C status
447 * b[7:0] = I2C.Status read-only register (byte status)
448 * b[31:8] = I2C.Completion status bits.
449 * We lose I2C.Completion bit[6] = TIMERR but this bit is
450 * a logical OR of bits[12:8].
451 * If parameter clear != 0 this routine will clear the R/W1C
452 * bits in I2C.Completion after reading them.
453 */
mec_hal_i2c_smb_status(struct mec_i2c_smb_ctx * ctx,uint8_t clear)454 uint32_t mec_hal_i2c_smb_status(struct mec_i2c_smb_ctx *ctx, uint8_t clear)
455 {
456 #ifdef MEC_I2C_BASE_CHECK
457 if (!ctx || !ctx->base) {
458 return 0;
459 }
460 #endif
461 struct mec_i2c_smb_regs *base = ctx->base;
462 uint32_t status = base->STATUS;
463 uint32_t compl = base->COMPL;
464
465 if (clear) {
466 base->COMPL = compl;
467 }
468
469 return (status | (compl & 0xffffff00u));
470 }
471
mec_hal_i2c_smb_wake_status(struct mec_i2c_smb_ctx * ctx)472 uint32_t mec_hal_i2c_smb_wake_status(struct mec_i2c_smb_ctx *ctx)
473 {
474 if (!ctx) {
475 return 0;
476 }
477
478 struct mec_i2c_smb_regs *base = ctx->base;
479
480 return base->WAKE_STS;
481 }
482
mec_hal_i2c_smb_wake_status_clr(struct mec_i2c_smb_ctx * ctx)483 void mec_hal_i2c_smb_wake_status_clr(struct mec_i2c_smb_ctx *ctx)
484 {
485 #ifdef MEC_I2C_BASE_CHECK
486 if (!ctx || !ctx->base) {
487 return;
488 }
489 #endif
490
491 struct mec_i2c_smb_regs *base = ctx->base;
492
493 base->WAKE_STS = MEC_BIT(MEC_I2C_SMB_WAKE_STS_START_DET_Pos);
494 }
495
mec_hal_i2c_smb_is_idle_intr(struct mec_i2c_smb_ctx * ctx)496 int mec_hal_i2c_smb_is_idle_intr(struct mec_i2c_smb_ctx *ctx)
497 {
498 #ifdef MEC_I2C_BASE_CHECK
499 if (!ctx || !ctx->base) {
500 return 0;
501 }
502 #endif
503 struct mec_i2c_smb_regs *base = ctx->base;
504 uint32_t cfg = base->CONFIG & MEC_BIT(MEC_I2C_SMB_CONFIG_ENI_IDLE_Pos);
505 uint32_t compl = base->COMPL & MEC_BIT(MEC_I2C_SMB_COMPL_IDLE_Pos);
506
507 if (cfg && compl) {
508 return 1;
509 }
510
511 return 0;
512 }
513
mec_hal_i2c_smb_idle_status_clr(struct mec_i2c_smb_ctx * ctx)514 int mec_hal_i2c_smb_idle_status_clr(struct mec_i2c_smb_ctx *ctx)
515 {
516 #ifdef MEC_I2C_BASE_CHECK
517 if (!ctx || !ctx->base) {
518 return 0;
519 }
520 #endif
521 struct mec_i2c_smb_regs *base = ctx->base;
522
523 base->COMPL |= MEC_BIT(MEC_I2C_SMB_COMPL_IDLE_Pos);
524
525 return 0;
526 }
527
528 /* Controller specification sequence:
529 * START + addr. Bus is idle (I2C.STATUS.NBB == 1)
530 * write addr to I2C.Data
531 * write 0xC5 to I2C.Control or 0xCb if interrupts are enabled
532 * RPT-START + addr. Bus must we owned by this controller (I2C.STATUS.NBB == 0)
533 * write 0x45 or 0x4b to I2C.Control
534 * write addr I2C.Data
535 */
mec_hal_i2c_smb_start_gen(struct mec_i2c_smb_ctx * ctx,uint8_t target_addr,int flags)536 int mec_hal_i2c_smb_start_gen(struct mec_i2c_smb_ctx *ctx, uint8_t target_addr, int flags)
537 {
538 #ifdef MEC_I2C_BASE_CHECK
539 if (!ctx || !ctx->base) {
540 return MEC_RET_ERR_INVAL;
541 }
542 #endif
543 struct mec_i2c_smb_regs *base = ctx->base;
544 uint8_t ctr = (MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_STA_Pos)
545 | MEC_BIT(MEC_I2C_SMB_CTRL_ACK_Pos));
546
547 if (flags & MEC_I2C_SMB_BYTE_ENI) {
548 ctr |= MEC_BIT(MEC_I2C_SMB_CTRL_ENI_Pos);
549 }
550
551 if (base->STATUS & MEC_BIT(MEC_I2C_SMB_STATUS_NBB_Pos)) {
552 ctr |= MEC_BIT(MEC_I2C_SMB_CTRL_PIN_Pos);
553 ctx->i2c_ctrl_cached = ctr;
554 base->DATA = target_addr;
555 base->CTRL = ctr;
556 } else {
557 ctx->i2c_ctrl_cached = ctr;
558 base->CTRL = ctr;
559 base->DATA = target_addr;
560 }
561
562 return MEC_RET_OK;
563 }
564
mec_hal_i2c_smb_stop_gen(struct mec_i2c_smb_ctx * ctx)565 int mec_hal_i2c_smb_stop_gen(struct mec_i2c_smb_ctx *ctx)
566 {
567 #ifdef MEC_I2C_BASE_CHECK
568 if (!ctx || !ctx->base) {
569 return MEC_RET_ERR_INVAL;
570 }
571 #endif
572 struct mec_i2c_smb_regs *base = ctx->base;
573 uint8_t control = (MEC_BIT(MEC_I2C_SMB_CTRL_PIN_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_ESO_Pos)
574 | MEC_BIT(MEC_I2C_SMB_CTRL_ACK_Pos) | MEC_BIT(MEC_I2C_SMB_CTRL_STO_Pos));
575
576 /* Nothing to do. Controller does not own the bus at this time */
577 if (base->STATUS & MEC_BIT(MEC_I2C_SMB_STATUS_NBB_Pos)) {
578 return MEC_RET_ERR_NOP;
579 }
580
581 ctx->i2c_ctrl_cached = control;
582 base->CTRL = control;
583
584 return MEC_RET_OK;
585 }
586
587 /* Write byte to I2C.DATA for transmit
588 * Prerequisites: Bus is owned by this controller and a START or Rpt-START plus
589 * target write address has been sent by the controller.
590 * If byte mode interrupts are required they should be enabled in the (Rpt)START
591 * generation API.
592 */
mec_hal_i2c_smb_xmit_byte(struct mec_i2c_smb_ctx * ctx,uint8_t msg_byte)593 int mec_hal_i2c_smb_xmit_byte(struct mec_i2c_smb_ctx *ctx, uint8_t msg_byte)
594 {
595 #ifdef MEC_I2C_BASE_CHECK
596 if (!ctx || !ctx->base) {
597 return MEC_RET_ERR_INVAL;
598 }
599 #endif
600 struct mec_i2c_smb_regs *base = ctx->base;
601
602 /* TODO should we check for NBB==1 and return error?
603 * Only for data bytes. In the case of START we write target
604 * address to I2C.DATA before writing I2C.Control.
605 * If this function is only used for data then we can add the
606 * check of NBB.
607 */
608
609 base->DATA = msg_byte;
610
611 return MEC_RET_OK;
612 }
613
614 /* Read byte currently in receive buffer and generate clocks for next
615 * byte if CTRL.STO == 0.
616 */
mec_hal_i2c_smb_read_byte(struct mec_i2c_smb_ctx * ctx,uint8_t * msg_byte)617 int mec_hal_i2c_smb_read_byte(struct mec_i2c_smb_ctx *ctx, uint8_t *msg_byte)
618 {
619 #ifdef MEC_I2C_BASE_CHECK
620 if (!ctx || !ctx->base) {
621 return MEC_RET_ERR_INVAL;
622 }
623 #endif
624 struct mec_i2c_smb_regs *base = ctx->base;
625 uint8_t b = base->DATA;
626
627 if (msg_byte) {
628 *msg_byte = b;
629 }
630
631 return MEC_RET_OK;
632 }
633
mec_hal_i2c_smb_bbctrl(struct mec_i2c_smb_ctx * ctx,uint8_t enable,uint8_t pin_drive)634 int mec_hal_i2c_smb_bbctrl(struct mec_i2c_smb_ctx *ctx, uint8_t enable, uint8_t pin_drive)
635 {
636 #ifdef MEC_I2C_BASE_CHECK
637 if (!ctx || !ctx->base) {
638 return MEC_RET_ERR_INVAL;
639 }
640 #endif
641 struct mec_i2c_smb_regs *base = ctx->base;
642 uint8_t bbctr = 0u;
643
644 if (enable) {
645 bbctr |= MEC_BIT(MEC_I2C_SMB_BBCTRL_BBEN_Pos);
646 if (!(pin_drive & MEC_BIT(MEC_I2C_BB_SCL_POS))) { /* drive low? */
647 bbctr |= MEC_BIT(MEC_I2C_SMB_BBCTRL_CLDIR_Pos);
648 }
649 if (!(pin_drive & MEC_BIT(MEC_I2C_BB_SDA_POS))) { /* drive low? */
650 bbctr |= MEC_BIT(MEC_I2C_SMB_BBCTRL_DADIR_Pos);
651 }
652 }
653
654 base->BBCTRL = bbctr;
655
656 return MEC_RET_OK;
657 }
658
659 /* Read SCL and SDA pin states using bit-bang control register.
660 * NOTE 1: Bit-bang mode must be enabled otherwise HW will return
661 * both pin states as high.
662 * NOTE 2: Enabling bit-bang switches the SCL and SDA lines away from
663 * I2C logic to BB logic. When bit-bang is is disabled one must allow
664 * time for I2C logic to resync to pins.
665 */
mec_hal_i2c_smb_bbctrl_pin_states(struct mec_i2c_smb_ctx * ctx)666 uint8_t mec_hal_i2c_smb_bbctrl_pin_states(struct mec_i2c_smb_ctx *ctx)
667 {
668 #ifdef MEC_I2C_BASE_CHECK
669 if (!ctx || !ctx->base) {
670 return 0x3u;
671 }
672 #endif
673 struct mec_i2c_smb_regs *base = ctx->base;
674
675 return (base->BBCTRL >> MEC_I2C_SMB_BBCTRL_BBCLKI_Pos) & 0x3u;
676 }
677
678 /* -------- I2C-NL -------- */
679
680 #ifdef MEC_I2C_NL_DEBUG_SAVE_CM_CMD
681 static volatile uint32_t mec_i2c_nl_dbg_save[4];
682 #endif
683
mec_hal_i2c_nl_cm_cfg_start(struct mec_i2c_smb_ctx * ctx,uint16_t ntx,uint16_t nrx,uint32_t flags)684 int mec_hal_i2c_nl_cm_cfg_start(struct mec_i2c_smb_ctx *ctx, uint16_t ntx, uint16_t nrx,
685 uint32_t flags)
686 {
687 #ifdef MEC_I2C_BASE_CHECK
688 if (!ctx || !ctx->base) {
689 return MEC_RET_ERR_INVAL;
690 }
691 #endif
692 struct mec_i2c_smb_regs *regs = ctx->base;
693 uint32_t cmd = 0;
694
695 if (!ntx) { /* Any I2C transaction requires transmit of target address! */
696 return MEC_RET_ERR_INVAL;
697 }
698
699 regs->CONFIG &= (uint32_t)~MEC_BIT(MEC_I2C_SMB_CONFIG_ENMI_Pos);
700 regs->CONFIG |= (MEC_BIT(MEC_I2C_SMB_CONFIG_FLUSH_CTXB_Pos)
701 | MEC_BIT(MEC_I2C_SMB_CONFIG_FLUSH_CRXB_Pos));
702 regs->COMPL |= MEC_BIT(MEC_I2C_SMB_COMPL_MDONE_Pos);
703
704 regs->EXTLEN = ((ntx >> 8) & 0xffu) | (nrx & 0xff00u);
705
706 cmd = (uint32_t)(ntx & 0xffu) << MEC_I2C_SMB_CM_CMD_WRCNT_LSB_Pos;
707 cmd |= ((uint32_t)(nrx & 0xffu) << MEC_I2C_SMB_CM_CMD_RDCNT_LSB_Pos);
708 cmd |= (MEC_BIT(MEC_I2C_SMB_CM_CMD_MRUN_Pos) | MEC_BIT(MEC_I2C_SMB_CM_CMD_MPROCEED_Pos));
709
710 if (flags & MEC_I2C_NL_FLAG_START) {
711 cmd |= MEC_BIT(MEC_I2C_SMB_CM_CMD_START0_Pos);
712 }
713
714 if (flags & MEC_I2C_NL_FLAG_RPT_START) {
715 cmd |= MEC_BIT(MEC_I2C_SMB_CM_CMD_STARTN_Pos);
716 }
717
718 if (flags & MEC_I2C_NL_FLAG_STOP) {
719 cmd |= MEC_BIT(MEC_I2C_SMB_CM_CMD_STOP_Pos);
720 }
721
722 if (flags & MEC_I2C_NL_FLAG_CM_DONE_IEN) {
723 regs->CONFIG |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENMI_Pos);
724 }
725
726 #ifdef MEC_I2C_NL_DEBUG_SAVE_CM_CMD
727 mec_i2c_nl_dbg_save[0] = cmd;
728 mec_i2c_nl_dbg_save[1] = regs->CONFIG;
729 mec_i2c_nl_dbg_save[2] = regs->COMPL;
730 mec_i2c_nl_dbg_save[3] = regs->EXTLEN;
731 #endif
732
733 regs->CM_CMD = cmd;
734
735 return MEC_RET_OK;
736 }
737
738 /* I2C-NL FSM clears MRUN and MPROCEED when both wrCnt and rdCnt transition to 0.
739 * MRUN==1 and MPROCEED is cleared to 0 when FSM requires software to reconfigure
740 * DMA for the direction change from write to read. After the Rpt-Start and rdAddr
741 * are transmitted and (n)ACK'd the FSM clears MPROCEED only.
742 * NOTE: any error should clear MRUN and MPROCEED.
743 */
mec_hal_i2c_nl_cm_event(struct mec_i2c_smb_regs * regs)744 uint32_t mec_hal_i2c_nl_cm_event(struct mec_i2c_smb_regs *regs)
745 {
746 #ifdef MEC_I2C_BASE_CHECK
747 if (!regs) {
748 return MEC_I2C_NL_CM_EVENT_NONE;
749 }
750 #endif
751
752 uint32_t cm_cmd = regs->CM_CMD & 0x03u;
753
754 if (cm_cmd == 0) {
755 return MEC_I2C_NL_CM_EVENT_ALL_DONE;
756 } else if (cm_cmd == 0x01) {
757 return MEC_I2C_NL_CM_EVENT_W2R;
758 } else {
759 return MEC_I2C_NL_CM_EVENT_NONE;
760 }
761 }
762
763 /* ---- Power Management ----
764 * Each controller has a wake enable interrupt on detection of an
765 * external I2C START. This is only required if the controller is
766 * being used in target mode.
767 */
768
769 static uint8_t i2c_pm_save_buf[MEC5_I2C_SMB_INSTANCES];
770
771 /* Save and disable the controller */
mec_hal_i2c_pm_save_disable(void)772 void mec_hal_i2c_pm_save_disable(void)
773 {
774 for (int i = 0; i < MEC5_I2C_SMB_INSTANCES; i++) {
775 struct mec_i2c_smb_regs *regs = (struct mec_i2c_smb_regs *)i2c_instances[i].base_addr;
776
777 if (regs->CONFIG & MEC_BIT(MEC_I2C_SMB_CONFIG_ENAB_Pos)) {
778 regs->CONFIG &= (uint32_t)~MEC_BIT(MEC_I2C_SMB_CONFIG_ENAB_Pos);
779 i2c_pm_save_buf[i] = 1;
780 } else {
781 i2c_pm_save_buf[i] = 0;
782 }
783 }
784 }
785
mec_hal_i2c_pm_restore(void)786 void mec_hal_i2c_pm_restore(void)
787 {
788 for (int i = 0; i < MEC5_I2C_SMB_INSTANCES; i++) {
789 struct mec_i2c_smb_regs *regs = (struct mec_i2c_smb_regs *)i2c_instances[i].base_addr;
790
791 if (i2c_pm_save_buf[i]) {
792 regs->CONFIG |= MEC_BIT(MEC_I2C_SMB_CONFIG_ENAB_Pos);
793 }
794 }
795 }
796
797 /* end mec_i2c.c */
798