Newer
Older
mbed-os / targets / TARGET_Samsung / TARGET_SIDK_S5JS100 / serial_api.c
/****************************************************************************
 *
 * Copyright 2020 Samsung Electronics All Rights Reserved.
 * 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.
 *
 ****************************************************************************/

#if DEVICE_SERIAL

// math.h required for floating point operations for baud rate calculation
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "device.h"
#include "serial_api.h"
#include "cmsis.h"
#include "pinmap.h"
#include "PinNames.h"
#include "mbed_error.h"
#include "gpio_api.h"

#include "mbed_assert.h"



void usi_serial_init(void *obj, PinName tx, PinName rx);
void pl011_serial_init(void *obj, PinName tx, PinName rx);
void dummy_serial_init(void *obj, PinName tx, PinName rx);

/******************************************************************************
 * INITIALIZATION
 ******************************************************************************/

static const PinMap PinMap_UART_TX[] = {
    {UART_TX0, UART_0, UART_TX0},
    {UART_TX1, UART_1, UART_TX1},
    {UART_TX2, UART_2, UART_TX2},
    {UART_TX3, UART_3, UART_TX3},
    {UART_TX4, UART_4, UART_TX4},
    {UART_TX5, UART_5, UART_TX5},
    {NC, NC, NC}
};
static const PinMap PinMap_UART_RX[] = {
    {UART_RX0, UART_0, UART_RX0},
    {UART_RX1, UART_1, UART_RX1},
    {UART_RX2, UART_2, UART_RX2},
    {UART_RX3, UART_3, UART_RX3},
    {UART_RX4, UART_4, UART_RX4},
    {UART_RX5, UART_5, UART_RX5},
    {NC, NC, NC}
};

/*
static const PinMap PinMap_UART_CTS[] = {
    {UART0_CTS, UART_0, UART0_CTS},
    {UART1_CTS, UART_1, UART1_CTS},
    {UART2_CTS, UART_2, UART2_CTS},
    {UART3_CTS, UART_3, UART3_CTS},
    {NC, NC, NC}
};

static const PinMap PinMap_UART_RTS[] = {
    {UART0_RTS, UART_0, UART0_RTS},
    {UART1_RTS, UART_1, UART1_RTS},
    {UART2_RTS, UART_2, UART2_RTS},
    {UART3_RTS, UART_3, UART3_RTS},
    {NC, NC, NC}
};
*/


/* Used in platform/mbed_retarget.cpp  */
/* What shall I do with it??? What is it for? */
int stdio_uart_inited = 0;
serial_t stdio_uart;


void serial_init(serial_t *obj, PinName tx, PinName rx)
{
    struct serial_s *priv = (struct serial_s *)obj;

    // determine the UART to use ???
    // Shall we check if it is already allocated ???
    UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
    UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
    UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
    if ((PinName)uart == NC) {
        error("Serial pinout mapping failed");
    }
    if ((PinName)uart_tx != NC) {
        s5js100_configgpio(pinmap_find_function(tx, PinMap_UART_TX));
    }

    if ((PinName)uart_rx != NC) {
        s5js100_configgpio(pinmap_find_function(rx, PinMap_UART_RX));
    }

    /* BAD Pointer assignment!!! Better to redesign*/
    priv->uart = (void *)uart;
    switch (uart) {
        case UART_0:
        case UART_1:
            usi_serial_init(obj, tx, rx);
            break;

        case UART_2:
        case UART_3:
            pl011_serial_init(obj, tx, rx);
            break;

        case UART_4:
        case UART_5:
            dummy_serial_init(obj, tx, rx);
            break;
    }

    // set default baud rate and format
    obj->ops.serial_baud(obj, 115200);
    obj->ops.serial_format(obj, 8, ParityNone, 1);

    if (uart == STDIO_UART) {
        stdio_uart_inited = 1;
        memcpy(&stdio_uart, obj, sizeof(serial_t));
    }
}

void serial_free(serial_t *obj)
{
    //needs release serial
}

// serial_baud
// set the baud rate, taking in to account the current SystemFrequency
void serial_baud(serial_t *obj, int baudrate)
{
    obj->ops.serial_baud(obj, baudrate);

}

void serial_format(serial_t *obj, int data_bits,
                   SerialParity parity, int stop_bits)
{
    obj->ops.serial_format(obj, data_bits, parity, stop_bits);
}


void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
{
    obj->ops.serial_irq_handler(obj, handler, id);
}


void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
    obj->ops.serial_irq_set(obj, irq, enable);
}

#if DEVICE_SERIAL_FC
void serial_set_flow_control(serial_t *obj, FlowControl type,
                             PinName rxflow, PinName txflow)
{
    struct serial_s *priv = (struct serial_s *)obj;

    UARTName uart_rts = (UARTName)pinmap_peripheral(rxflow, PinMap_UART_RTS);
    UARTName uart_cts = (UARTName)pinmap_peripheral(txflow, PinMap_UART_CTS);
    UARTName uart = (UARTName)pinmap_merge(uart_rts, uart_cts);
    if ((PinName)uart == NC) {
        error("Serial pinout mapping failed");
    }

    if ((int)uart != (int)priv->uart) {
        error("Serial pinout mapping failed");
    }


    if (type == FlowControlRTS) {
        // Enable RTS
        MBED_ASSERT(uart_rts != (UARTName)NC);
        // Enable the pin for RTS function
        s5js100_configgpio(pinmap_find_function(rxflow, PinMap_UART_RTS));
    }
    if (type == FlowControlCTS) {
        // Enable CTS
        MBED_ASSERT(uart_cts != (UARTName)NC);
        // Enable the pin for CTS function
        s5js100_configgpio(pinmap_find_function(txflow, PinMap_UART_CTS));
    }
    if (type == FlowControlRTSCTS) {
        // Enable CTS & RTS
        MBED_ASSERT(uart_rts != (UARTName)NC);
        MBED_ASSERT(uart_cts != (UARTName)NC);
        // Enable the pin for CTS function
        s5js100_configgpio(pinmap_find_function(txflow, PinMap_UART_CTS));
        // Enable the pin for RTS function
        s5js100_configgpio(pinmap_find_function(rxflow, PinMap_UART_RTS));
    }


    obj->ops.serial_set_flow_control(obj, type, rxflow, txflow);
}
#endif


/******************************************************************************
 * READ/WRITE
 ******************************************************************************/
int serial_getc(serial_t *obj)
{
    return obj->ops.serial_getc(obj);
}

void serial_putc(serial_t *obj, int c)
{
    obj->ops.serial_putc(obj, c);
}

int serial_readable(serial_t *obj)
{
    return obj->ops.serial_readable(obj);
}

int serial_writable(serial_t *obj)
{
    return obj->ops.serial_writable(obj);
}


/* Shall it be ever used ???
void serial_clear(serial_t *obj)
{
    if (obj->index < 2)
    {
        USI_PTR(obj->uart)->URXH = 0x00;
        while ((getreg32(0x83015018) & UART_UFSTAT_TX_FIFO_FULL));
        while ((getreg32(0x83015018) & UART_UFSTAT_TX_FIFO_COUNT_MASK));
        putreg8('C', 0x83015020);
        while ((getreg32(0x83015018) & UART_UFSTAT_TX_FIFO_FULL));
        while ((getreg32(0x83015018) & UART_UFSTAT_TX_FIFO_COUNT_MASK));
        putreg8('C', 0x83015020);
        putreg8('C', 0x83015020);
        putreg8('C', 0x83015020);
        putreg8('C', 0x83015020);
        putreg8('C', 0x83015020);
        putreg8('C', 0x83015020);
    }
    else
    {
        UART_PTR(obj->uart)->DR = 0x00;
        while (UART_PTR(obj->uart)->FR & (1u << 5));
        while (UART_PTR(obj->uart)->FR & (1u << 7));
        UART_PTR(obj->uart)->DR = 'C';
        while (UART_PTR(obj->uart)->FR & (1u << 5));
        while (UART_PTR(obj->uart)->FR & (1u << 7));
        UART_PTR(obj->uart)->DR = 'C';
        UART_PTR(obj->uart)->DR = 'C';
        UART_PTR(obj->uart)->DR = 'C';
        UART_PTR(obj->uart)->DR = 'C';
        UART_PTR(obj->uart)->DR = 'C';
        UART_PTR(obj->uart)->DR = 'C';
    }
}
*/

/* Used in
 * features/unsupported/tests/libs/SerialHalfDuplex/SerialHalfDuplex.cpp
 * What is it for?
 */
void serial_pinout_tx(PinName tx)
{
    pinmap_pinout(tx, PinMap_UART_TX);
}


/* Serial break may never be used.
 * In general set TX to "0".
 * However - shall we?
 */

void serial_break_set(serial_t *obj)
{
}

void serial_break_clear(serial_t *obj)
{
}


/* pinmap test entry */

const PinMap *serial_tx_pinmap()
{
    return PinMap_UART_TX;
}

const PinMap *serial_rx_pinmap()
{
    return PinMap_UART_RX;
}

#endif // DEVICE_SERIAL