Newer
Older
mbed-os / targets / TARGET_ARM_SSG / TARGET_MUSCA_S1 / gpio_api_ns.c
@Gabor Toth Gabor Toth on 10 Sep 2020 3 KB Add platform support to Musca S1
/* mbed Microcontroller Library
 * Copyright (c) 2020 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.
 */

/*
 * This file implements APIS defined in hal/gpio_api.h
 * Note: Due to a HW limitation, GPIO in Musca-S1 is Secure only, so secure
 *       service should be used for GPIO in NS domain.
 */

#include <stddef.h>
#include "gpio_api.h"
#include "pinmap.h"
#include "objects.h"
#include "mbed_error.h"
#include "mbed_assert.h"
#include "rtx_lib.h"
#include "tfm_platform_api.h"
#include "tfm_ioctl_api.h"

#define RETURN_VOID_true return;
#define RETURN_VOID_false return 0;

#define IRQ_MODE_CHECK(is_func_void) \
    /* Secure service can't be called in interrupt context. */ \
    if (IsIrqMode()) { \
        MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_HAL, \
                MBED_ERROR_INVALID_OPERATION), \
                "GPIO secure service can't be called in interrupt context\n"); \
        RETURN_VOID_ ## is_func_void \
    }


uint32_t gpio_set(PinName pin)
{
    pin_function(pin, (int)PRIMARY_FUNC);

    /* Return the correct mask of the given PIN */
    return (1 << GPIO_PIN_NUMBER(pin));

}

void gpio_init(gpio_t *obj, PinName pin)
{
    obj->pin_num = (uint32_t)NC;
    uint32_t result = 0;
    enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS;

    if (pin >= PA0 && pin <= PA15) {
        IRQ_MODE_CHECK(true);
        ret = tfm_platform_gpio_init(&result);
        if (ret || result) {
            return;
        }

        obj->pin_num = pin;
        /* GPIO is input by default */
        obj->direction = PIN_INPUT;
        return;
    }
}

void gpio_mode(gpio_t *obj, PinMode mode)
{
    pin_mode(obj->pin_num, mode);

}

void gpio_dir(gpio_t *obj, PinDirection direction)
{
    uint32_t pin_dir = (direction == PIN_INPUT ? 0 : 1);
    uint32_t result = 0;
    enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS;

    IRQ_MODE_CHECK(true);

    ret = tfm_platform_gpio_pin_config(obj->pin_num, pin_dir, &result);
    if (ret || result) {
        error("gpio_dir failed, error %d, gpio error %d", ret, result);
    }
    obj->direction = direction;
}


int gpio_is_connected(const gpio_t *obj)
{
    if (obj->pin_num == (uint32_t)NC) {
        return 0;
    } else {
        return 1;
    }

}

void gpio_write(gpio_t *obj, int value)
{
    enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS;
    uint32_t result = 0;

    IRQ_MODE_CHECK(true);

    ret = tfm_platform_gpio_pin_write(obj->pin_num, (uint32_t)value, &result);

    if (ret || result) {
        error("Can not write pin %d; error %d, gpio error %d",
                                                     obj->pin_num, ret, result);
    }

}

int gpio_read(gpio_t *obj)
{
    enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS;
    uint32_t result = 0;
    uint32_t data = 0;

    IRQ_MODE_CHECK(false);

    ret = tfm_platform_gpio_pin_read(obj->pin_num, &data, &result);

    /* The valid return values of this API are 0 and 1 */
    if (ret || result) {
        return 0;
    } else {
        return data;
    }
}