1 /*
2 * Copyright (c) 2023 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ambiq_i2c
8
9 #include <errno.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/pm/device.h>
13 #include <zephyr/pm/policy.h>
14 #include <zephyr/pm/device_runtime.h>
15
16 #include <am_mcu_apollo.h>
17
18 #ifdef CONFIG_I2C_AMBIQ_BUS_RECOVERY
19 #include <zephyr/drivers/gpio.h>
20 #include "i2c_bitbang.h"
21 #endif /* CONFIG_I2C_AMBIQ_BUS_RECOVERY */
22
23 #include <zephyr/logging/log.h>
24 #include <zephyr/drivers/pinctrl.h>
25
26 LOG_MODULE_REGISTER(ambiq_i2c, CONFIG_I2C_LOG_LEVEL);
27
28 typedef int (*ambiq_i2c_pwr_func_t)(void);
29
30 #define PWRCTRL_MAX_WAIT_US 5
31 #define I2C_TRANSFER_TIMEOUT_MSEC 500 /* Transfer timeout period */
32
33 #include "i2c-priv.h"
34
35 struct i2c_ambiq_config {
36 #ifdef CONFIG_I2C_AMBIQ_BUS_RECOVERY
37 struct gpio_dt_spec scl;
38 struct gpio_dt_spec sda;
39 #endif /* CONFIG_I2C_AMBIQ_BUS_RECOVERY */
40 uint32_t base;
41 int size;
42 uint32_t bitrate;
43 const struct pinctrl_dev_config *pcfg;
44 ambiq_i2c_pwr_func_t pwr_func;
45 void (*irq_config_func)(void);
46 };
47
48 typedef void (*i2c_ambiq_callback_t)(const struct device *dev, int result, void *data);
49
50 struct i2c_ambiq_data {
51 am_hal_iom_config_t iom_cfg;
52 void *iom_handler;
53 struct k_sem bus_sem;
54 struct k_sem transfer_sem;
55 i2c_ambiq_callback_t callback;
56 void *callback_data;
57 int inst_idx;
58 uint32_t transfer_status;
59 bool pm_policy_state_on;
60 };
61
i2c_ambiq_pm_policy_state_lock_get(const struct device * dev)62 static void i2c_ambiq_pm_policy_state_lock_get(const struct device *dev)
63 {
64 if (IS_ENABLED(CONFIG_PM)) {
65 struct i2c_ambiq_data *data = dev->data;
66
67 if (!data->pm_policy_state_on) {
68 data->pm_policy_state_on = true;
69 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
70 pm_device_runtime_get(dev);
71 }
72 }
73 }
74
i2c_ambiq_pm_policy_state_lock_put(const struct device * dev)75 static void i2c_ambiq_pm_policy_state_lock_put(const struct device *dev)
76 {
77 if (IS_ENABLED(CONFIG_PM)) {
78 struct i2c_ambiq_data *data = dev->data;
79
80 if (data->pm_policy_state_on) {
81 data->pm_policy_state_on = false;
82 pm_device_runtime_put(dev);
83 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
84 }
85 }
86 }
87
88 #ifdef CONFIG_I2C_AMBIQ_DMA
89 static __aligned(32) struct {
90 __aligned(32) uint32_t buf[CONFIG_I2C_DMA_TCB_BUFFER_SIZE];
91 } i2c_dma_tcb_buf[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)] __attribute__((__section__(".nocache")));
92
i2c_ambiq_callback(void * callback_ctxt,uint32_t status)93 static void i2c_ambiq_callback(void *callback_ctxt, uint32_t status)
94 {
95 const struct device *dev = callback_ctxt;
96 struct i2c_ambiq_data *data = dev->data;
97
98 if (data->callback) {
99 data->callback(dev, status, data->callback_data);
100 }
101 data->transfer_status = status;
102 }
103 #endif
104
i2c_ambiq_isr(const struct device * dev)105 static void i2c_ambiq_isr(const struct device *dev)
106 {
107 uint32_t ui32Status;
108 struct i2c_ambiq_data *data = dev->data;
109
110 am_hal_iom_interrupt_status_get(data->iom_handler, false, &ui32Status);
111 am_hal_iom_interrupt_clear(data->iom_handler, ui32Status);
112 am_hal_iom_interrupt_service(data->iom_handler, ui32Status);
113 k_sem_give(&data->transfer_sem);
114 }
115
i2c_ambiq_read(const struct device * dev,struct i2c_msg * msg,uint16_t addr)116 static int i2c_ambiq_read(const struct device *dev, struct i2c_msg *msg, uint16_t addr)
117 {
118 struct i2c_ambiq_data *data = dev->data;
119
120 int ret = 0;
121
122 am_hal_iom_transfer_t trans = {0};
123
124 trans.ui8Priority = 1;
125 trans.eDirection = AM_HAL_IOM_RX;
126 trans.uPeerInfo.ui32I2CDevAddr = addr;
127 trans.ui32NumBytes = msg->len;
128 trans.pui32RxBuffer = (uint32_t *)msg->buf;
129
130 #ifdef CONFIG_I2C_AMBIQ_DMA
131 data->transfer_status = -EFAULT;
132 ret = am_hal_iom_nonblocking_transfer(data->iom_handler, &trans, i2c_ambiq_callback,
133 (void *)dev);
134 if (k_sem_take(&data->transfer_sem, K_MSEC(I2C_TRANSFER_TIMEOUT_MSEC))) {
135 LOG_ERR("Timeout waiting for transfer complete");
136 /* cancel timed out transaction */
137 am_hal_iom_disable(data->iom_handler);
138 /* clean up for next xfer */
139 k_sem_reset(&data->transfer_sem);
140 am_hal_iom_enable(data->iom_handler);
141 return -ETIMEDOUT;
142 }
143 ret = data->transfer_status;
144 #else
145 ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans);
146 #endif
147 return (ret != AM_HAL_STATUS_SUCCESS) ? -EIO : 0;
148 }
149
i2c_ambiq_write(const struct device * dev,struct i2c_msg * msg,uint16_t addr)150 static int i2c_ambiq_write(const struct device *dev, struct i2c_msg *msg, uint16_t addr)
151 {
152 struct i2c_ambiq_data *data = dev->data;
153
154 int ret = 0;
155
156 am_hal_iom_transfer_t trans = {0};
157
158 trans.ui8Priority = 1;
159 trans.eDirection = AM_HAL_IOM_TX;
160 trans.uPeerInfo.ui32I2CDevAddr = addr;
161 trans.ui32NumBytes = msg->len;
162 trans.pui32TxBuffer = (uint32_t *)msg->buf;
163
164 #ifdef CONFIG_I2C_AMBIQ_DMA
165 data->transfer_status = -EFAULT;
166 ret = am_hal_iom_nonblocking_transfer(data->iom_handler, &trans, i2c_ambiq_callback,
167 (void *)dev);
168
169 if (k_sem_take(&data->transfer_sem, K_MSEC(I2C_TRANSFER_TIMEOUT_MSEC))) {
170 LOG_ERR("Timeout waiting for transfer complete");
171 /* cancel timed out transaction */
172 am_hal_iom_disable(data->iom_handler);
173 /* clean up for next xfer */
174 k_sem_reset(&data->transfer_sem);
175 am_hal_iom_enable(data->iom_handler);
176 return -ETIMEDOUT;
177 }
178 ret = data->transfer_status;
179 #else
180 ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans);
181 #endif
182
183 return (ret != AM_HAL_STATUS_SUCCESS) ? -EIO : 0;
184 }
185
i2c_ambiq_configure(const struct device * dev,uint32_t dev_config)186 static int i2c_ambiq_configure(const struct device *dev, uint32_t dev_config)
187 {
188 struct i2c_ambiq_data *data = dev->data;
189
190 if (!(I2C_MODE_CONTROLLER & dev_config)) {
191 return -EINVAL;
192 }
193
194 switch (I2C_SPEED_GET(dev_config)) {
195 case I2C_SPEED_STANDARD:
196 data->iom_cfg.ui32ClockFreq = AM_HAL_IOM_100KHZ;
197 break;
198 case I2C_SPEED_FAST:
199 data->iom_cfg.ui32ClockFreq = AM_HAL_IOM_400KHZ;
200 break;
201 case I2C_SPEED_FAST_PLUS:
202 data->iom_cfg.ui32ClockFreq = AM_HAL_IOM_1MHZ;
203 break;
204 default:
205 return -EINVAL;
206 }
207
208 #ifdef CONFIG_I2C_AMBIQ_DMA
209 data->iom_cfg.pNBTxnBuf = i2c_dma_tcb_buf[data->inst_idx].buf;
210 data->iom_cfg.ui32NBTxnBufLength = CONFIG_I2C_DMA_TCB_BUFFER_SIZE;
211 #endif
212
213 am_hal_iom_configure(data->iom_handler, &data->iom_cfg);
214
215 return 0;
216 }
217
i2c_ambiq_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)218 static int i2c_ambiq_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
219 uint16_t addr)
220 {
221 struct i2c_ambiq_data *data = dev->data;
222 int ret = 0;
223
224 if (!num_msgs) {
225 return 0;
226 }
227
228 i2c_ambiq_pm_policy_state_lock_get(dev);
229
230 /* Send out messages */
231 k_sem_take(&data->bus_sem, K_FOREVER);
232
233 for (int i = 0; i < num_msgs; i++) {
234 if (msgs[i].flags & I2C_MSG_READ) {
235 ret = i2c_ambiq_read(dev, &(msgs[i]), addr);
236 } else {
237 ret = i2c_ambiq_write(dev, &(msgs[i]), addr);
238 }
239
240 if (ret != 0) {
241 LOG_ERR("i2c transfer failed: %d", ret);
242 break;
243 }
244 }
245
246 k_sem_give(&data->bus_sem);
247
248 i2c_ambiq_pm_policy_state_lock_put(dev);
249
250 return ret;
251 }
252
253 #if CONFIG_I2C_AMBIQ_BUS_RECOVERY
i2c_ambiq_bitbang_set_scl(void * io_context,int state)254 static void i2c_ambiq_bitbang_set_scl(void *io_context, int state)
255 {
256 const struct i2c_ambiq_config *config = io_context;
257
258 gpio_pin_set_dt(&config->scl, state);
259 }
260
i2c_ambiq_bitbang_set_sda(void * io_context,int state)261 static void i2c_ambiq_bitbang_set_sda(void *io_context, int state)
262 {
263 const struct i2c_ambiq_config *config = io_context;
264
265 gpio_pin_set_dt(&config->sda, state);
266 }
267
i2c_ambiq_bitbang_get_sda(void * io_context)268 static int i2c_ambiq_bitbang_get_sda(void *io_context)
269 {
270 const struct i2c_ambiq_config *config = io_context;
271
272 return gpio_pin_get_dt(&config->sda) == 0 ? 0 : 1;
273 }
274
i2c_ambiq_recover_bus(const struct device * dev)275 static int i2c_ambiq_recover_bus(const struct device *dev)
276 {
277 const struct i2c_ambiq_config *config = dev->config;
278 struct i2c_ambiq_data *data = dev->data;
279 struct i2c_bitbang bitbang_ctx;
280 struct i2c_bitbang_io bitbang_io = {
281 .set_scl = i2c_ambiq_bitbang_set_scl,
282 .set_sda = i2c_ambiq_bitbang_set_sda,
283 .get_sda = i2c_ambiq_bitbang_get_sda,
284 };
285 uint32_t bitrate_cfg;
286 int error = 0;
287
288 LOG_ERR("attempting to recover bus");
289
290 if (!gpio_is_ready_dt(&config->scl)) {
291 LOG_ERR("SCL GPIO device not ready");
292 return -EIO;
293 }
294
295 if (!gpio_is_ready_dt(&config->sda)) {
296 LOG_ERR("SDA GPIO device not ready");
297 return -EIO;
298 }
299
300 k_sem_take(&data->bus_sem, K_FOREVER);
301
302 error = gpio_pin_configure_dt(&config->scl, GPIO_OUTPUT_HIGH);
303 if (error != 0) {
304 LOG_ERR("failed to configure SCL GPIO (err %d)", error);
305 goto restore;
306 }
307
308 error = gpio_pin_configure_dt(&config->sda, GPIO_OUTPUT_HIGH);
309 if (error != 0) {
310 LOG_ERR("failed to configure SDA GPIO (err %d)", error);
311 goto restore;
312 }
313
314 i2c_bitbang_init(&bitbang_ctx, &bitbang_io, (void *)config);
315
316 bitrate_cfg = i2c_map_dt_bitrate(config->bitrate) | I2C_MODE_CONTROLLER;
317 error = i2c_bitbang_configure(&bitbang_ctx, bitrate_cfg);
318 if (error != 0) {
319 LOG_ERR("failed to configure I2C bitbang (err %d)", error);
320 goto restore;
321 }
322
323 error = i2c_bitbang_recover_bus(&bitbang_ctx);
324 if (error != 0) {
325 LOG_ERR("failed to recover bus (err %d)", error);
326 }
327
328 restore:
329 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
330
331 k_sem_give(&data->bus_sem);
332
333 return error;
334 }
335 #endif /* CONFIG_I2C_AMBIQ_BUS_RECOVERY */
336
i2c_ambiq_init(const struct device * dev)337 static int i2c_ambiq_init(const struct device *dev)
338 {
339 struct i2c_ambiq_data *data = dev->data;
340 const struct i2c_ambiq_config *config = dev->config;
341 uint32_t bitrate_cfg = i2c_map_dt_bitrate(config->bitrate);
342 int ret = 0;
343
344 data->iom_cfg.eInterfaceMode = AM_HAL_IOM_I2C_MODE;
345
346 if (AM_HAL_STATUS_SUCCESS !=
347 am_hal_iom_initialize((config->base - IOM0_BASE) / config->size,
348 &data->iom_handler)) {
349 LOG_ERR("Fail to initialize I2C\n");
350 return -ENXIO;
351 }
352
353 ret = config->pwr_func();
354
355 ret |= i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
356 if (ret < 0) {
357 LOG_ERR("Fail to config I2C\n");
358 goto end;
359 }
360
361 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
362 if (ret < 0) {
363 LOG_ERR("Fail to config I2C pins\n");
364 goto end;
365 }
366
367 #ifdef CONFIG_I2C_AMBIQ_DMA
368 am_hal_iom_interrupt_clear(data->iom_handler, AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP);
369 am_hal_iom_interrupt_enable(data->iom_handler, AM_HAL_IOM_INT_DCMP | AM_HAL_IOM_INT_CMDCMP);
370 config->irq_config_func();
371 #endif
372
373 if (AM_HAL_STATUS_SUCCESS != am_hal_iom_enable(data->iom_handler)) {
374 LOG_ERR("Fail to enable I2C\n");
375 ret = -EIO;
376 }
377 end:
378 if (ret < 0) {
379 am_hal_iom_uninitialize(data->iom_handler);
380 }
381 return ret;
382 }
383
384 static DEVICE_API(i2c, i2c_ambiq_driver_api) = {
385 .configure = i2c_ambiq_configure,
386 .transfer = i2c_ambiq_transfer,
387 #if CONFIG_I2C_AMBIQ_BUS_RECOVERY
388 .recover_bus = i2c_ambiq_recover_bus,
389 #endif /* CONFIG_I2C_AMBIQ_BUS_RECOVERY */
390 #ifdef CONFIG_I2C_RTIO
391 .iodev_submit = i2c_iodev_submit_fallback,
392 #endif
393 };
394
395 #ifdef CONFIG_PM_DEVICE
i2c_ambiq_pm_action(const struct device * dev,enum pm_device_action action)396 static int i2c_ambiq_pm_action(const struct device *dev, enum pm_device_action action)
397 {
398 struct i2c_ambiq_data *data = dev->data;
399 uint32_t ret;
400 am_hal_sysctrl_power_state_e status;
401
402 switch (action) {
403 case PM_DEVICE_ACTION_RESUME:
404 status = AM_HAL_SYSCTRL_WAKE;
405 break;
406 case PM_DEVICE_ACTION_SUSPEND:
407 status = AM_HAL_SYSCTRL_DEEPSLEEP;
408 break;
409 default:
410 return -ENOTSUP;
411 }
412
413 ret = am_hal_iom_power_ctrl(data->iom_handler, status, true);
414
415 if (ret != AM_HAL_STATUS_SUCCESS) {
416 return -EPERM;
417 } else {
418 return 0;
419 }
420 }
421 #endif /* CONFIG_PM_DEVICE */
422
423 #define AMBIQ_I2C_DEFINE(n) \
424 PINCTRL_DT_INST_DEFINE(n); \
425 static int pwr_on_ambiq_i2c_##n(void) \
426 { \
427 uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \
428 DT_INST_PHA(n, ambiq_pwrcfg, offset); \
429 sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \
430 k_busy_wait(PWRCTRL_MAX_WAIT_US); \
431 return 0; \
432 } \
433 static void i2c_irq_config_func_##n(void) \
434 { \
435 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_ambiq_isr, \
436 DEVICE_DT_INST_GET(n), 0); \
437 irq_enable(DT_INST_IRQN(n)); \
438 }; \
439 static struct i2c_ambiq_data i2c_ambiq_data##n = { \
440 .bus_sem = Z_SEM_INITIALIZER(i2c_ambiq_data##n.bus_sem, 1, 1), \
441 .transfer_sem = Z_SEM_INITIALIZER(i2c_ambiq_data##n.transfer_sem, 0, 1), \
442 .inst_idx = n, \
443 }; \
444 static const struct i2c_ambiq_config i2c_ambiq_config##n = { \
445 .base = DT_INST_REG_ADDR(n), \
446 .size = DT_INST_REG_SIZE(n), \
447 .bitrate = DT_INST_PROP(n, clock_frequency), \
448 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
449 .irq_config_func = i2c_irq_config_func_##n, \
450 .pwr_func = pwr_on_ambiq_i2c_##n, \
451 IF_ENABLED(CONFIG_I2C_AMBIQ_BUS_RECOVERY, \
452 (.scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}),\
453 .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}),)) }; \
454 PM_DEVICE_DT_INST_DEFINE(n, i2c_ambiq_pm_action); \
455 I2C_DEVICE_DT_INST_DEFINE(n, i2c_ambiq_init, PM_DEVICE_DT_INST_GET(n), &i2c_ambiq_data##n, \
456 &i2c_ambiq_config##n, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \
457 &i2c_ambiq_driver_api);
458
459 DT_INST_FOREACH_STATUS_OKAY(AMBIQ_I2C_DEFINE)
460