blob: f82e34a6b490db979437179698c36617de8a53c9 [file] [log] [blame]
/**
* Copyright (c) 2018 Linaro
* Copyright (c) 2020 ATL Electronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT inventek_eswifi_uart
#include "eswifi_log.h"
LOG_MODULE_DECLARE(LOG_MODULE_NAME);
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/uart.h>
#include "eswifi.h"
#define ESWIFI_RING_BUF_SIZE 2048
enum eswifi_uart_fsm {
ESWIFI_UART_FSM_WAIT_CR,
ESWIFI_UART_FSM_WAIT_LF,
ESWIFI_UART_FSM_WAIT_MARK,
ESWIFI_UART_FSM_WAIT_SPACE,
ESWIFI_UART_FSM_END,
};
struct eswifi_uart_data {
const struct device *dev;
enum eswifi_uart_fsm fsm;
size_t rx_count;
size_t rx_buf_size;
char *rx_buf;
/* RX Ring Buf */
uint8_t iface_rb_buf[ESWIFI_RING_BUF_SIZE];
struct ring_buf rx_rb;
};
static struct eswifi_uart_data eswifi_uart0; /* Static instance */
static void eswifi_iface_uart_flush(struct eswifi_uart_data *uart)
{
uint8_t c;
while (uart_fifo_read(uart->dev, &c, 1) > 0) {
continue;
}
}
static void eswifi_iface_uart_isr(const struct device *uart_dev,
void *user_data)
{
struct eswifi_uart_data *uart = &eswifi_uart0; /* Static instance */
int rx = 0;
uint8_t *dst;
uint32_t partial_size = 0;
uint32_t total_size = 0;
ARG_UNUSED(user_data);
while (uart_irq_update(uart->dev) &&
uart_irq_rx_ready(uart->dev)) {
if (!partial_size) {
partial_size = ring_buf_put_claim(&uart->rx_rb, &dst,
UINT32_MAX);
}
if (!partial_size) {
LOG_ERR("Rx buffer doesn't have enough space");
eswifi_iface_uart_flush(uart);
break;
}
rx = uart_fifo_read(uart->dev, dst, partial_size);
if (rx <= 0) {
continue;
}
dst += rx;
total_size += rx;
partial_size -= rx;
}
ring_buf_put_finish(&uart->rx_rb, total_size);
}
static char get_fsm_char(int fsm)
{
switch (fsm) {
case ESWIFI_UART_FSM_WAIT_CR:
return('C');
case ESWIFI_UART_FSM_WAIT_LF:
return('L');
case ESWIFI_UART_FSM_WAIT_MARK:
return('M');
case ESWIFI_UART_FSM_WAIT_SPACE:
return('S');
case ESWIFI_UART_FSM_END:
return('E');
}
return('?');
}
static int eswifi_uart_get_resp(struct eswifi_uart_data *uart)
{
uint8_t c;
while (ring_buf_get(&uart->rx_rb, &c, 1) > 0) {
LOG_DBG("FSM: %c, RX: 0x%02x : %c",
get_fsm_char(uart->fsm), c, c);
if (uart->rx_buf_size > 0) {
uart->rx_buf[uart->rx_count++] = c;
if (uart->rx_count == uart->rx_buf_size) {
return -ENOMEM;
}
}
switch (uart->fsm) {
case ESWIFI_UART_FSM_WAIT_CR:
if (c == '\r') {
uart->fsm = ESWIFI_UART_FSM_WAIT_LF;
}
break;
case ESWIFI_UART_FSM_WAIT_LF:
if (c == '\n') {
uart->fsm = ESWIFI_UART_FSM_WAIT_MARK;
} else if (c != '\r') {
uart->fsm = ESWIFI_UART_FSM_WAIT_CR;
}
break;
case ESWIFI_UART_FSM_WAIT_MARK:
if (c == '>') {
uart->fsm = ESWIFI_UART_FSM_WAIT_SPACE;
} else if (c == '\r') {
uart->fsm = ESWIFI_UART_FSM_WAIT_LF;
} else {
uart->fsm = ESWIFI_UART_FSM_WAIT_CR;
}
break;
case ESWIFI_UART_FSM_WAIT_SPACE:
if (c == ' ') {
uart->fsm = ESWIFI_UART_FSM_END;
} else if (c == '\r') {
uart->fsm = ESWIFI_UART_FSM_WAIT_LF;
} else {
uart->fsm = ESWIFI_UART_FSM_WAIT_CR;
}
break;
default:
break;
}
}
return 0;
}
static int eswifi_uart_wait_prompt(struct eswifi_uart_data *uart)
{
unsigned int max_retries = 60 * 1000; /* 1 minute */
int err;
while (--max_retries) {
err = eswifi_uart_get_resp(uart);
if (err) {
LOG_DBG("Err: 0x%08x - %d", err, err);
return err;
}
if (uart->fsm == ESWIFI_UART_FSM_END) {
LOG_DBG("Success!");
return uart->rx_count;
}
/* allow other threads to be scheduled */
k_sleep(K_MSEC(1));
}
LOG_DBG("Timeout");
return -ETIMEDOUT;
}
static int eswifi_uart_request(struct eswifi_dev *eswifi, char *cmd,
size_t clen, char *rsp, size_t rlen)
{
struct eswifi_uart_data *uart = eswifi->bus_data;
int count;
int err;
LOG_DBG("cmd=%p (%u byte), rsp=%p (%u byte)", cmd, clen, rsp, rlen);
/* Send CMD */
for (count = 0; count < clen; count++) {
uart_poll_out(uart->dev, cmd[count]);
}
uart->fsm = ESWIFI_UART_FSM_WAIT_CR;
uart->rx_count = 0;
uart->rx_buf = rsp;
uart->rx_buf_size = rlen;
err = eswifi_uart_wait_prompt(uart);
if (err > 0) {
LOG_HEXDUMP_DBG(uart->rx_buf, uart->rx_count, "Stream");
}
return err;
}
int eswifi_uart_init(struct eswifi_dev *eswifi)
{
struct eswifi_uart_data *uart = &eswifi_uart0; /* Static instance */
uart->dev = DEVICE_DT_GET(DT_INST_BUS(0));
if (!device_is_ready(uart->dev)) {
LOG_ERR("Bus device is not ready");
return -ENODEV;
}
eswifi->bus_data = uart;
uart_irq_rx_disable(uart->dev);
uart_irq_tx_disable(uart->dev);
eswifi_iface_uart_flush(uart);
uart_irq_callback_set(uart->dev, eswifi_iface_uart_isr);
uart_irq_rx_enable(uart->dev);
ring_buf_init(&uart->rx_rb, sizeof(uart->iface_rb_buf),
uart->iface_rb_buf);
LOG_DBG("success");
return 0;
}
static struct eswifi_bus_ops eswifi_bus_ops_uart = {
.init = eswifi_uart_init,
.request = eswifi_uart_request,
};
struct eswifi_bus_ops *eswifi_get_bus(void)
{
return &eswifi_bus_ops_uart;
}