#include "core/system.h"
#include "core/pio.h"
#include "lib/string.h"
+#include "lib/utils.h"
+#include "drivers/serial.h"
#define SERIAL_OUT_BUFF_SIZE 64
struct uart_device
struct lpc_uart* regs;
uint32_t baudrate;
uint32_t config;
+ uint32_t capabilities;
+ uint32_t current_mode;
/* Output buffer */
volatile char out_buff[SERIAL_OUT_BUFF_SIZE];
volatile uint32_t out_length; /* actual position to add in out buffer */
/* Input */
- void (*rx_callback)(char); /* Possible RX callback */
+ void (*rx_callback)(uint8_t); /* Possible RX callback */
};
#define NUM_UARTS 2
.sending = 0,
.out_lock = 0,
.rx_callback = 0,
+ .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
+ .current_mode = SERIAL_MODE_UART,
},
{
.num = 1,
.sending = 0,
.out_lock = 0,
.rx_callback = 0,
+ .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_IRDA),
+ .current_mode = SERIAL_MODE_UART,
},
};
}
+
/***************************************************************************** */
/* Serial Write
*
-
/***************************************************************************** */
/* UART Setup : private part : Clocks, Pins, Power and Mode */
sys_ctrl->uart_clk_div[uart_num] = 0;
}
-static uint32_t uart_mode_setup(uint32_t uart_num)
+static uint32_t uart_setup(uint32_t uart_num)
{
struct lpc_uart* uart = uarts[uart_num].regs; /* Get the right registers */
uint32_t status = 0;
}
}
+/* Change uart mode to RS485
+ * return -ENODEV when the device does not support RS485 mode.
+ */
+int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay)
+{
+ struct uart_device* uart = NULL;
+ struct lpc_uart* uart_regs = NULL;
+ if (uart_num >= NUM_UARTS)
+ return -EINVAL;
+ uart = &uarts[uart_num];
+ uart_regs = uart->regs; /* Get the right registers */
+
+ if (!(uart->capabilities & SERIAL_CAP_RS485)) {
+ return -ENODEV;
+ }
+ /* Disable all other modes */
+ uart_regs->irda_ctrl = 0;
+
+ /* Set current mode */
+ uart->current_mode = SERIAL_MODE_RS485;
+ uart_regs->RS485_ctrl = (control & 0xFF);
+ uart_regs->RS485_addr_match = LPC_RS485_ADDR(addr);
+ uart_regs->RS485_dir_ctrl_delay = LPC_RS485_DIR_DELAY(delay);
+ return 0;
+}
+
+/* Change uart mode to IRDA
+ * pulse_width is the number of clock cycles for a pulse. Should dbe a power of 2.
+ * return -ENODEV when the device does not support IrDA mode.
+ */
+int uart_set_mode_irda(uint32_t uart_num, uint32_t control, uint16_t pulse_width)
+{
+ struct uart_device* uart = NULL;
+ struct lpc_uart* uart_regs = NULL;
+ uint8_t pulse_div = 0;
+
+ if (uart_num >= NUM_UARTS)
+ return -EINVAL;
+ uart = &uarts[uart_num];
+ uart_regs = uart->regs; /* Get the right registers */
+
+ if (!(uart->capabilities & SERIAL_CAP_IRDA)) {
+ return -ENODEV;
+ }
+ /* Disable all other modes */
+ uart_regs->RS485_ctrl = 0;
+
+ /* Set current mode */
+ uart->current_mode = SERIAL_MODE_IRDA;
+ /* Setup IrDA */
+ if (pulse_width < 2) {
+ pulse_div = 0;
+ } else {
+ pulse_div = (31 - clz(pulse_width & 0x1FF));
+ }
+ uart_regs->irda_ctrl = control | LPC_IRDA_PULSEDIV(pulse_div);
+ return 0;
+}
+
+
/* Do we need to allow setting of other parameters ? (Other than 8n1) */
-int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(char))
+int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t))
{
struct uart_def* uart = NULL;
uint32_t status = 0;
/* Setup clock acording to baudrate */
uart_clk_on(uart_num, baudrate);
/* Setup mode, fifo, ... */
- status = uart_mode_setup(uart_num);
+ status = uart_setup(uart_num);
/* Enable interrupts back on */
NVIC_EnableIRQ( uart->irq );
volatile const uint32_t modem_status; /* 0x018 : Modem status Register (R/ ) */
volatile uint32_t scratch_pad; /* 0x01C : Scratch Pad Register (R/W) */
volatile uint32_t auto_baud_ctrl; /* 0x020 : Auto-baud Control Register (R/W) */
- uint32_t reserved_0;
+ volatile uint32_t irda_ctrl; /* 0x024 : UART IrDA Control Register (R/W) */
volatile uint32_t fractional_div; /* 0x028 : Fractional Divider Register (R/W) */
uint32_t reserved_1;
volatile uint32_t transmit_enable; /* 0x030 : Transmit Enable Register (R/W) */
#define LPC_UART_INT_RX (0x2 << 1)
#define LPC_UART_INT_RX_STATUS (0x3 << 1)
#define LPC_UART_INT_TIMEOUT (0x6 << 1)
+/* RS485 Control */
+#define LPC_RS485_ENABLE (0x1 << 0)
+#define LPC_RS485_RX_DIS (0x1 << 1)
+#define LPC_RS485_AUTO_ADDR_EN (0x1 << 2)
+#define LPC_RS485_DIR_PIN_RTS (0x0 << 3)
+#define LPC_RS485_DIR_PIN_DTR (0x1 << 3)
+#define LPC_RS485_AUTO_DIR_EN (0x1 << 4)
+#define LPC_RS485_DIR_CTRL_INV (0x1 << 5)
+/* RS485 */
+#define LPC_RS485_ADDR(x) ((x) & 0xFF)
+#define LPC_RS485_DIR_DELAY(x) ((x) & 0xFF)
+/* IrDA */
+#define LPC_IRDA_PULSEDIV(x) (((x) & 0x07) << 3)
/***************************************************************************** */
#include <stdint.h>
+#define SERIAL_CAP_UART (1 << 0)
+#define SERIAL_CAP_RS485 (1 << 1)
+#define SERIAL_CAP_IRDA (1 << 2)
+
+#define SERIAL_MODE_UART SERIAL_CAP_UART
+#define SERIAL_MODE_RS485 SERIAL_CAP_RS485
+#define SERIAL_MODE_IRDA SERIAL_CAP_IRDA
+
/***************************************************************************** */
/* Serial Write
*
/***************************************************************************** */
/* Public access to UART setup */
+/* Change uart mode to RS485
+ * return -ENODEV when the device does not support RS485 mode.
+ */
+int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay);
+
+/* Change uart mode to IRDA
+ * return -ENODEV when the device does not support IrDA mode.
+ */
+int uart_set_mode_irda(uint32_t uart_num, uint32_t control, uint16_t pulse_width);
/* Allow any change to the main clock to be forwarded to us */
void uart_clk_update(void);
/* Do we need to allow setting of other parameters ? (Other than 8n1) */
-int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(char));
+int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t));
void uart_off(uint32_t uart_num);