Newer
Older
mbed-os / targets / TARGET_ARM_SSG / TARGET_MUSCA_B1 / device / drivers / uart_pl011_drv.c
@Harrison Mutai Harrison Mutai on 15 Oct 2020 30 KB Add SPDX license identifier to Arm files
/*
 * Copyright (c) 2016-2019 Arm Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "uart_pl011_drv.h"

#include <stddef.h>
#include "cmsis_compiler.h"

#define FREQ_IRLPBAUD16_MIN             (1420000u)     /* 1.42 MHz */
#define FREQ_IRLPBAUD16_MAX             (2120000u)     /* 2.12 MHz */
#define SAMPLING_FACTOR                 (16u)
#define UART_PL011_FBRD_WIDTH           (6u)

/**
 * \brief UART PL011 register map structure
 */
struct _uart_pl011_reg_map_t {
    volatile uint32_t uartdr;          /*!< Offset: 0x000 (R/W) Data register */
    union {
        volatile uint32_t uartrsr;
                /*!< Offset: 0x004 (R/ ) Receive status register */
        volatile uint32_t uartecr;
                /*!< Offset: 0x004 ( /W) Error clear register */
    };
    volatile uint32_t reserved_0[4];   /*!< Offset: 0x008-0x014 Reserved */
    volatile uint32_t uartfr;          /*!< Offset: 0x018 (R/ ) Flag register */
    volatile uint32_t reserved_1;      /*!< Offset: 0x01C       Reserved */
    volatile uint32_t uartilpr;
                /*!< Offset: 0x020 (R/W) IrDA low-power counter register */
    volatile uint32_t uartibrd;
                /*!< Offset: 0x024 (R/W) Integer baud rate register */
    volatile uint32_t uartfbrd;
                /*!< Offset: 0x028 (R/W) Fractional baud rate register */
    volatile uint32_t uartlcr_h;
                /*!< Offset: 0x02C (R/W) Line control register */
    volatile uint32_t uartcr;
                /*!< Offset: 0x030 (R/W) Control register */
    volatile uint32_t uartifls;
                /*!< Offset: 0x034 (R/W) Interrupt FIFO level select register */
    volatile uint32_t uartimsc;
                /*!< Offset: 0x038 (R/W) Interrupt mask set/clear register */
    volatile uint32_t uartris;
                /*!< Offset: 0x03C (R/ ) Raw interrupt status register */
    volatile uint32_t uartmis;
                /*!< Offset: 0x040 (R/ ) Masked interrupt status register */
    volatile uint32_t uarticr;
                /*!< Offset: 0x044 ( /W) Interrupt clear register */
    volatile uint32_t uartdmacr;
                /*!< Offset: 0x048 (R/W) DMA control register */
    volatile uint32_t reserved_2[13];  /*!< Offset: 0x04C-0x07C Reserved */
    volatile uint32_t reserved_3[4];
                /*!< Offset: 0x080-0x08C Reserved for test purposes */
    volatile uint32_t reserved_4[976]; /*!< Offset: 0x090-0xFCC Reserved */
    volatile uint32_t reserved_5[4];
                /*!< Offset: 0xFD0-0xFDC Reserved for future ID expansion */
    volatile uint32_t uartperiphid0;
                /*!< Offset: 0xFE0 (R/ ) UARTPeriphID0 register */
    volatile uint32_t uartperiphid1;
                /*!< Offset: 0xFE4 (R/ ) UARTPeriphID1 register */
    volatile uint32_t uartperiphid2;
                /*!< Offset: 0xFE8 (R/ ) UARTPeriphID2 register */
    volatile uint32_t uartperiphid3;
                /*!< Offset: 0xFEC (R/ ) UARTPeriphID3 register */
    volatile uint32_t uartpcellid0;
                /*!< Offset: 0xFF0 (R/ ) UARTPCellID0 register */
    volatile uint32_t uartpcellid1;
                /*!< Offset: 0xFF4 (R/ ) UARTPCellID1 register */
    volatile uint32_t uartpcellid2;
                /*!< Offset: 0xFF8 (R/ ) UARTPCellID2 register */
    volatile uint32_t uartpcellid3;
                /*!< Offset: 0xFFC (R/ ) UARTPCellID3 register */
};

#define UART_PL011_UARTFR_CTS_MASK (                    \
            0x1u<<UART_PL011_UARTFR_CTS_OFF)
#define UART_PL011_UARTFR_DSR_MASK (                    \
            0x1u<<UART_PL011_UARTFR_DSR_OFF)
#define UART_PL011_UARTFR_DCD_MASK (                    \
            0x1u<<UART_PL011_UARTFR_DCD_OFF)
#define UART_PL011_UARTFR_BUSYBIT (                     \
            0x1u<<UART_PL011_UARTFR_BUSYBIT_OFF)
#define UART_PL011_UARTFR_RX_FIFO_EMPTY (               \
            0x1u<<UART_PL011_UARTFR_RX_FIFO_EMPTY_OFF)
#define UART_PL011_UARTFR_TX_FIFO_FULL (                \
            0x1u<<UART_PL011_UARTFR_TX_FIFO_FULL_OFF)
#define UART_PL011_UARTFR_RI_MASK (                     \
            0x1u<<UART_PL011_UARTFR_RI_OFF)

#define UART_PL011_UARTLCR_H_BRK_MASK (                 \
            0x1u<<UART_PL011_UARTLCR_H_BRK_OFF)
#define UART_PL011_UARTLCR_H_PARITY_MASK (              \
            0x1u<<UART_PL011_UARTLCR_H_PEN_OFF          \
          | 0x1u<<UART_PL011_UARTLCR_H_EPS_OFF          \
          | 0x1u<<UART_PL011_UARTLCR_H_SPS_OFF)
#define UART_PL011_UARTLCR_H_STOPBIT_MASK (             \
            0x1u<<UART_PL011_UARTLCR_H_STP2_OFF)
#define UART_PL011_UARTLCR_H_FEN_MASK (                 \
            0x1u<<UART_PL011_UARTLCR_H_FEN_OFF)
#define UART_PL011_UARTLCR_H_WLEN_MASK (                \
            0x3u<<UART_PL011_UARTLCR_H_WLEN_OFF)
#define UART_PL011_FORMAT_MASK (                        \
            UART_PL011_UARTLCR_H_PARITY_MASK            \
          | UART_PL011_UARTLCR_H_STOPBIT_MASK           \
          | UART_PL011_UARTLCR_H_WLEN_MASK)

#define UART_PL011_UARTCR_EN_MASK (                     \
            0x1u<<UART_PL011_UARTCR_UARTEN_OFF)
#define UART_PL011_UARTCR_SIREN_MASK (                  \
            0x1u<<UART_PL011_UARTCR_SIREN_OFF)
#define UART_PL011_UARTCR_SIRLP_MASK (                  \
            0x1u<<UART_PL011_UARTCR_SIRLP_OFF)
#define UART_PL011_UARTCR_LBE_MASK (                    \
            0x1u<<UART_PL011_UARTCR_LBE_OFF)
#define UART_PL011_UARTCR_TX_EN_MASK (                  \
            0x1u<<UART_PL011_UARTCR_TXE_OFF)
#define UART_PL011_UARTCR_RX_EN_MASK (                  \
            0x1u<<UART_PL011_UARTCR_RXE_OFF)
#define UART_PL011_UARTCR_DTR_MASK (                    \
            0x1u<<UART_PL011_UARTCR_DTR_OFF)
#define UART_PL011_UARTCR_RTS_MASK (                    \
            0x1u<<UART_PL011_UARTCR_RTS_OFF)
#define UART_PL011_UARTCR_OUT1_MASK (                   \
            0x1u<<UART_PL011_UARTCR_OUT1_OFF)
#define UART_PL011_UARTCR_OUT2_MASK (                   \
            0x1u<<UART_PL011_UARTCR_OUT2_OFF)
#define UART_PL011_UARTCR_RTSE_MASK (                   \
            0x1u<<UART_PL011_UARTCR_RTSE_OFF)
#define UART_PL011_UARTCR_CTSE_MASK (                   \
            0x1u<<UART_PL011_UARTCR_CTSE_OFF)

#define UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK (          \
            0x7u<<UART_PL011_UARTIFLS_TX_OFF)
#define UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK (          \
            0x7u<<UART_PL011_UARTIFLS_RX_OFF)

#define UART_PL011_UARTDMACR_RX_MASK (                  \
            0x1u<<UART_PL011_UARTDMACR_RXEN_OFF         \
          | 0x1u<<UART_PL011_UARTDMACR_ON_ERR_OFF)
#define UART_PL011_UARTDMACR_TX_MASK (                  \
            0x1u<<UART_PL011_UARTDMACR_TXEN_OFF)

/* Default register values of UART PL011 */
#define UART_PL011_DATA_REG_RESET_VALUE     (0x0u)
#define UART_PL011_ECR_REG_CLEAR_VALUE      (0xFFu)
#define UART_PL011_ILPR_REG_RESET_VALUE     (0x0u)
#define UART_PL011_IBRD_REG_RESET_VALUE     (0x0u)
#define UART_PL011_FBRD_REG_RESET_VALUE     (0x0u)
#define UART_PL011_LCR_H_REG_RESET_VALUE    (0x0u)
#define UART_PL011_CR_REG_RESET_VALUE       (0x0300u)
#define UART_PL011_IFLS_REG_RESET_VALUE     (0x12u)
#define UART_PL011_IMSC_REG_RESET_VALUE     (0x0u)
#define UART_PL011_ICR_REG_CLEAR_VALUE      (0x7FFu)
#define UART_PL011_DMACR_REG_RESET_VALUE    (0x0u)

static void _uart_pl011_enable(struct _uart_pl011_reg_map_t* p_uart)
{
    p_uart->uartcr |=  UART_PL011_UARTCR_EN_MASK;
}

static void _uart_pl011_disable(struct _uart_pl011_reg_map_t* p_uart)
{
    p_uart->uartcr &= ~UART_PL011_UARTCR_EN_MASK;
}

static bool _uart_pl011_is_enabled(struct _uart_pl011_reg_map_t* p_uart)
{
    return (bool)(p_uart->uartcr & UART_PL011_UARTCR_EN_MASK);
}

static void _uart_pl011_enable_fifo(struct _uart_pl011_reg_map_t* p_uart)
{
    p_uart->uartlcr_h |= UART_PL011_UARTLCR_H_FEN_MASK;
}

static void _uart_pl011_disable_fifo(struct _uart_pl011_reg_map_t* p_uart)
{
    p_uart->uartlcr_h &= ~UART_PL011_UARTLCR_H_FEN_MASK;
}

static bool _uart_pl011_is_fifo_enabled(struct _uart_pl011_reg_map_t* p_uart)
{
    return (bool)(p_uart->uartlcr_h & UART_PL011_UARTLCR_H_FEN_MASK);
}

static bool _uart_pl011_is_busy(struct _uart_pl011_reg_map_t* p_uart)
{
    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT);
}

static enum uart_pl011_error_t _uart_pl011_set_baudrate(
                    struct _uart_pl011_reg_map_t* p_uart,
                    uint32_t clk, uint32_t baudrate)
{
    /* Avoiding float calculations, bauddiv is left shifted by 6 */
    uint64_t bauddiv = (((uint64_t)clk)<<UART_PL011_FBRD_WIDTH)
                       /(SAMPLING_FACTOR*baudrate);

    /* Valid bauddiv value
     * uart_clk (min) >= 16 x baud_rate (max)
     * uart_clk (max) <= 16 x 65535 x baud_rate (min)
     */
    if((bauddiv < (1u<<UART_PL011_FBRD_WIDTH))
       || (bauddiv > (65535u<<UART_PL011_FBRD_WIDTH))) {
        return UART_PL011_ERR_INVALID_BAUD;
    }

    p_uart->uartibrd = (uint32_t)(bauddiv >> UART_PL011_FBRD_WIDTH);
    p_uart->uartfbrd = (uint32_t)(bauddiv &
                                 ((1u << UART_PL011_FBRD_WIDTH) - 1u));

    __DMB();

    /* In order to internally update the contents of uartibrd or uartfbrd, a
     * uartlcr_h write must always be performed at the end
     * ARM DDI 0183F, Pg 3-13
     */
    p_uart->uartlcr_h = p_uart->uartlcr_h;

    return UART_PL011_ERR_NONE;
}

static void _uart_pl011_set_format(struct _uart_pl011_reg_map_t* p_uart,
                    enum uart_pl011_wlen_t word_len,
                    enum uart_pl011_parity_t parity,
                    enum uart_pl011_stopbit_t stop_bits)
{
    uint32_t ctrl_reg = p_uart->uartlcr_h & ~(UART_PL011_FORMAT_MASK);

    /* Making sure other bit are not changed */
    word_len  &= UART_PL011_UARTLCR_H_WLEN_MASK;
    parity    &= UART_PL011_UARTLCR_H_PARITY_MASK;
    stop_bits &= UART_PL011_UARTLCR_H_STOPBIT_MASK;

    p_uart->uartlcr_h = ctrl_reg | word_len | parity | stop_bits;

}

static void _uart_pl011_set_cr_bit(struct _uart_pl011_reg_map_t* p_uart,
                    uint32_t mask)
{
    bool uart_enabled = _uart_pl011_is_enabled(p_uart);
    bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart);

    /* UART must be disabled before any Control Register or
     * Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    /* Flush the transmit FIFO by disabling bit 4 (FEN) in
     * the line control register (UARTCLR_H) */
    _uart_pl011_disable_fifo(p_uart);

    p_uart->uartcr |= (mask);

    /* Enabling the FIFOs if previously enabled */
    if(fifo_enabled) {
        _uart_pl011_enable_fifo(p_uart);
    }

    /* Enabling the UART if previously enabled */
    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }
}

static void _uart_pl011_clear_cr_bit(struct _uart_pl011_reg_map_t* p_uart,
                    uint32_t mask)
{
    bool uart_enabled = _uart_pl011_is_enabled(p_uart);
    bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart);

    /* UART must be disabled before any Control Register or
     * Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    /* Flush the transmit FIFO by disabling bit 4 (FEN) in
     * the line control register (UARTCLR_H) */
    _uart_pl011_disable_fifo(p_uart);

    p_uart->uartcr &= ~(mask);

    /* Enabling the FIFOs if previously enabled */
    if(fifo_enabled) {
        _uart_pl011_enable_fifo(p_uart);
    }

    /* Enabling the UART if previously enabled */
    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }
}

static void _uart_pl011_set_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart,
                    uint32_t mask)
{
    bool uart_enabled = _uart_pl011_is_enabled(p_uart);

    /* UART must be disabled before any Control Register or
     * Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    p_uart->uartlcr_h |= (mask);

    /* Enabling the UART if previously enabled */
    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }
}

static void _uart_pl011_clear_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart,
                    uint32_t mask)
{
    bool uart_enabled = _uart_pl011_is_enabled(p_uart);

    /* UART must be disabled before any Control Register or
     * Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    p_uart->uartlcr_h &= ~(mask);

    /* Enabling the UART if previously enabled */
    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }
}

static void _uart_pl011_reset_regs(struct _uart_pl011_reg_map_t* p_uart)
{
    /* Restore the default value of UART registers, the registers which
     * are not listed below are Read-Only */

    /* Will disable the UART */
    p_uart->uartcr      = UART_PL011_CR_REG_RESET_VALUE;
    p_uart->uartdr      = UART_PL011_DATA_REG_RESET_VALUE;
    /* Clear all the errors */
    p_uart->uartecr     = UART_PL011_ECR_REG_CLEAR_VALUE;
    p_uart->uartilpr    = UART_PL011_ILPR_REG_RESET_VALUE;
    p_uart->uartibrd    = UART_PL011_IBRD_REG_RESET_VALUE;
    p_uart->uartfbrd    = UART_PL011_FBRD_REG_RESET_VALUE;
    p_uart->uartlcr_h   = UART_PL011_LCR_H_REG_RESET_VALUE;
    p_uart->uartifls    = UART_PL011_IFLS_REG_RESET_VALUE;
    p_uart->uartimsc    = UART_PL011_IMSC_REG_RESET_VALUE;
    /* Clear all the interrupts */
    p_uart->uarticr     = UART_PL011_ICR_REG_CLEAR_VALUE;
    p_uart->uartdmacr   = UART_PL011_DMACR_REG_RESET_VALUE;
}

enum uart_pl011_error_t uart_pl011_init(struct uart_pl011_dev_t* dev,
                    uint32_t uart_clk)
{
    enum uart_pl011_error_t err;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    uint32_t def_baud = dev->cfg->def_baudrate;

    if(uart_clk == 0) {
        return UART_PL011_ERR_INVALID_ARG;
    }

    if(def_baud == 0) {
        return UART_PL011_ERR_INVALID_BAUD;
    }

    /* Updating the system clock */
    dev->data->uart_clk = uart_clk;

    /* Setting the default baudrate */
    err = _uart_pl011_set_baudrate(p_uart, uart_clk, def_baud);

    if(err != UART_PL011_ERR_NONE) {
        return err;
    }

    /* Setting the default character format */
    _uart_pl011_set_format(p_uart, dev->cfg->def_wlen,
                                   dev->cfg->def_parity,
                                   dev->cfg->def_stopbit);

    /* Enabling the FIFOs */
    _uart_pl011_enable_fifo(p_uart);

    dev->data->state = UART_PL011_INITIALIZED;

    return UART_PL011_ERR_NONE;
}

void uart_pl011_uninit(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    while(_uart_pl011_is_busy(p_uart));

    /* Disable and restore the default configuration of the peripheral */
    _uart_pl011_reset_regs(p_uart);

    dev->data->state = UART_PL011_UNINITIALIZED;

    return;
}

enum uart_pl011_state_t uart_pl011_get_state(struct uart_pl011_dev_t* dev)
{
    return dev->data->state;
}

enum uart_pl011_error_t uart_pl011_set_baudrate(
                    struct uart_pl011_dev_t* dev, uint32_t baudrate)
{
    enum uart_pl011_error_t err = UART_PL011_ERR_NONE;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    bool uart_enabled = _uart_pl011_is_enabled(p_uart);

    if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) {
        return UART_PL011_ERR_NOT_INIT;
    }

    if(baudrate == 0) {
        return UART_PL011_ERR_INVALID_BAUD;
    }

    /* UART must be disabled before any Control Register or
    *  Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    /* If baudrate is not valid ie UART_PL011_ERR_NONE is not returned then
     * the UART will continue to function at the old baudrate */
    err = _uart_pl011_set_baudrate(p_uart, dev->data->uart_clk, baudrate);

    if(err == UART_PL011_ERR_NONE) {
        dev->data->baudrate = baudrate;
    }

    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }

    return err;
}

uint32_t uart_pl011_get_baudrate(struct uart_pl011_dev_t* dev)
{
    return dev->data->baudrate;
}

void uart_pl011_enable_intr(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_intr_t mask)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    p_uart->uartimsc |= (uint32_t)(mask);

    return;
}

void uart_pl011_disable_intr(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_intr_t mask)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    p_uart->uartimsc &= (uint32_t)(~mask);

    return;
}

void uart_pl011_clear_intr(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_intr_t mask)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    p_uart->uarticr = (uint32_t)mask;

    return;
}


enum uart_pl011_intr_t uart_pl011_get_masked_intr_status(
                    struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    return (enum uart_pl011_intr_t)(p_uart->uartmis);

}

enum uart_pl011_intr_t uart_pl011_get_raw_intr_status(
                    struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    return (enum uart_pl011_intr_t)(p_uart->uartris);
}

void uart_pl011_set_rx_fifo_lvl(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_rx_fifo_lvl_t rx_lvl)
{
    uint32_t fifo_lvl;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    /* Check if rx_lvl have valid values */
    rx_lvl &= UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK;

    fifo_lvl = p_uart->uartifls
                        & ~(UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK);
    p_uart->uartifls = fifo_lvl | rx_lvl;

    return;
}

void uart_pl011_set_tx_fifo_lvl(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_tx_fifo_lvl_t tx_lvl)
{
    uint32_t fifo_lvl;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;
    /* Check if tx_lvl have valid values */
    tx_lvl &= UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK;

    fifo_lvl = p_uart->uartifls
                        & ~(UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK);
    p_uart->uartifls = fifo_lvl | tx_lvl;

    return;
}

void uart_pl011_set_tx_dma(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_tx_dma_t enable)
{
    uint32_t dma_cr;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    enable &= UART_PL011_UARTDMACR_TX_MASK;

    dma_cr = p_uart->uartdmacr
                      & ~(UART_PL011_UARTDMACR_TX_MASK);

    p_uart->uartdmacr = dma_cr | enable;

    return;
}

void uart_pl011_set_rx_dma(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_rx_dma_t enable)
{
    uint32_t dma_cr;

    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    enable &= UART_PL011_UARTDMACR_RX_MASK;

    dma_cr = p_uart->uartdmacr
                      & ~(UART_PL011_UARTDMACR_RX_MASK);

    p_uart->uartdmacr = dma_cr | enable;

    return;
}

bool uart_pl011_is_readable(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) &&
                /* UART is initialized */
        (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) &&
                /* UART is enabled */
        (p_uart->uartcr & UART_PL011_UARTCR_RX_EN_MASK) &&
                /* Receive is enabled */
        ((p_uart->uartfr & UART_PL011_UARTFR_RX_FIFO_EMPTY) == 0)) {
                /* Receive Fifo is not empty */
        return true;
    }

    return false;

}

enum uart_pl011_error_t uart_pl011_read(
                    struct uart_pl011_dev_t* dev, uint8_t* byte)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    *byte = p_uart->uartdr;

    return (enum uart_pl011_error_t)(p_uart->uartrsr
                                         & UART_PL011_RX_ERR_MASK);
}

bool uart_pl011_is_writable(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) &&
                /* UART is initialized */
        (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) &&
                /* UART is enabled */
        (p_uart->uartcr & UART_PL011_UARTCR_TX_EN_MASK) &&
                /* Transmit is enabled */
        ((p_uart->uartfr & UART_PL011_UARTFR_TX_FIFO_FULL) == 0)) {
                /* Transmit Fifo is not full */
        return true;
    }
    return false;

}

void uart_pl011_write(struct uart_pl011_dev_t* dev, uint8_t byte)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    p_uart->uartdr = byte;

    return;
}

enum uart_pl011_error_t uart_pl011_set_format(struct uart_pl011_dev_t* dev,
                    enum uart_pl011_wlen_t word_len,
                    enum uart_pl011_parity_t parity,
                    enum uart_pl011_stopbit_t stop_bits)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    bool uart_enabled = _uart_pl011_is_enabled(p_uart);

    if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) {
        return UART_PL011_ERR_NOT_INIT;
    }

    /* UART must be disabled before any Control Register or
     * Line Control Register are reprogrammed */
    _uart_pl011_disable(p_uart);

    _uart_pl011_set_format(p_uart, word_len, parity, stop_bits);

    /* Enabling the UART if previously enabled */
    if(uart_enabled) {
        _uart_pl011_enable(p_uart);
    }

    return UART_PL011_ERR_NONE;
}

void uart_pl011_enable_fifo(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK);

    return;
}

void uart_pl011_disable_fifo(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK);

    return;
}

void uart_pl011_enable_break(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK);

    return;
}

void uart_pl011_disable_break(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK);

    return;
}

void uart_pl011_enable_cts_flowcontrol(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK);

    return;
}

void uart_pl011_disable_cts_flowcontrol(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK);

    return;
}

void uart_pl011_enable_rts_flowcontrol(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK);

    return;
}

void uart_pl011_disable_rts_flowcontrol(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK);

    return;
}

void uart_pl011_enable_ri(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK);

    return;
}

void uart_pl011_disable_ri(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK);

    return;
}

void uart_pl011_enable_dcd(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK);

    return;
}

void uart_pl011_disable_dcd(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK);

    return;
}

void uart_pl011_set_rts(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK);

    return;
}

void uart_pl011_clear_rts(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK);

    return;
}

void uart_pl011_set_dtr(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK);

    return;
}

void uart_pl011_clear_dtr(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK);

    return;
}

void uart_pl011_enable_receive(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK);

    return;
}

void uart_pl011_disable_receive(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK);

    return;
}

void uart_pl011_enable_transmit(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK);

    return;
}

void uart_pl011_disable_transmit(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK);

    return;
}

void uart_pl011_set_loopback(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK);

    return;
}

void uart_pl011_clear_loopback(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK);

    return;
}

void uart_pl011_enable_sirlp(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart,
     UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK);

    return;
}

void uart_pl011_disable_sirlp(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart,
     UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK);

    return;
}

void uart_pl011_enable_sir(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK);

    return;
}

void uart_pl011_disable_sir(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK);

    return;
}

void uart_pl011_enable(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_enable(p_uart);

    return;
}

void uart_pl011_disable(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    _uart_pl011_disable(p_uart);

    return;
}

bool uart_pl011_get_cts_status(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;
    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_CTS_MASK);

}

bool uart_pl011_get_dsr_status(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;
    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DSR_MASK);

}

bool uart_pl011_get_dcd_status(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;
    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DCD_MASK);

}

bool uart_pl011_get_ri_status(struct uart_pl011_dev_t* dev)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;
    return (bool)(p_uart->uartfr & UART_PL011_UARTFR_RI_MASK);

}

enum uart_pl011_error_t uart_pl011_set_sirlp_divisor(
            struct uart_pl011_dev_t* dev, uint32_t value)
{
    struct _uart_pl011_reg_map_t* p_uart =
        (struct _uart_pl011_reg_map_t*)dev->cfg->base;

    uint32_t irlp_baud16_clk;

    if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) {
        return UART_PL011_ERR_NOT_INIT;
    }

    if(value == 0) {
        return UART_PL011_ERR_INVALID_ARG;
    }

    irlp_baud16_clk = dev->data->uart_clk/value;

    /* Chose the divisor so that 1.42MHz < FIrLPBaud16 < 2.12MHz, that
     * results in a low-power pulse duration of 1.41–2.11μs (three times
     * the period of IrLPBaud16). ARM DDI0183F Pg 3-9 */
    if(irlp_baud16_clk < FREQ_IRLPBAUD16_MIN ||
       irlp_baud16_clk > FREQ_IRLPBAUD16_MAX) {
        return UART_PL011_ERR_INVALID_ARG;
    }

    p_uart->uartilpr = value;

    return UART_PL011_ERR_NONE;
}