354 lines
10 KiB
C
354 lines
10 KiB
C
/**
|
|
* @file sdrv-cam-os-def.h
|
|
*
|
|
* @brief Semidrive platform camera driver and hal adaptive to operation system header file.
|
|
*
|
|
* @copyright Copyright (C) 2021, Semidrive Communications Inc.
|
|
*
|
|
* This file is licensed under a dual GPLv2 or X11 license.
|
|
*
|
|
*/
|
|
#ifndef __SDRV_CAM_OS_DEF_H__
|
|
#define __SDRV_CAM_OS_DEF_H__
|
|
|
|
#include <assert.h>
|
|
#include <bits.h>
|
|
#include <board.h>
|
|
#include <debug.h>
|
|
#include <errno.h>
|
|
#include <lib/list.h>
|
|
#include <reg.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <types.h>
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "armv7-r/atomic.h"
|
|
#include "armv7-r/cache.h"
|
|
#include "armv7-r/irq.h"
|
|
#include "config.h"
|
|
#include "event_groups.h"
|
|
#include "i2c_cfg.h"
|
|
#include "irq.h"
|
|
#include "irq_num.h"
|
|
#include "queue.h"
|
|
#include "regs_base.h"
|
|
#include "sdrv_gpio.h"
|
|
#include "sdrv_i2c.h"
|
|
#include "task.h"
|
|
|
|
// define from cmsis_os2.h
|
|
#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default).
|
|
#define osFlagsWaitAll 0x00000001U ///< Wait for all flags.
|
|
#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for.
|
|
#define MAX_BITS_EVENT_GROUPS 24U
|
|
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
|
|
|
|
#define csi_err(x...) ssdk_printf(SSDK_ERR, x)
|
|
#define csi_warn(x...) ssdk_printf(SSDK_WARNING, x)
|
|
#define csi_info(x...) ssdk_printf(SSDK_NOTICE, x)
|
|
#define csi_debug(x...) ssdk_printf(SSDK_DEBUG, x)
|
|
|
|
#define cam_err(x...) ssdk_printf(SSDK_ERR, x)
|
|
#define cam_info(x...) ssdk_printf(SSDK_NOTICE, x)
|
|
#define cam_debug(x...) ssdk_printf(SSDK_DEBUG, x)
|
|
|
|
#define sensor_err(x...) ssdk_printf(SSDK_ERR, x)
|
|
#define sensor_info(x...) ssdk_printf(SSDK_NOTICE, x)
|
|
#define sensor_debug(x...) ssdk_printf(SSDK_DEBUG, x)
|
|
|
|
#define deser_crit(x...) ssdk_printf(SSDK_CRIT, x)
|
|
#define deser_err(x...) ssdk_printf(SSDK_ERR, x)
|
|
#define deser_info(x...) ssdk_printf(SSDK_NOTICE, x)
|
|
#define deser_debug(x...) ssdk_printf(SSDK_DEBUG, x)
|
|
|
|
#define HAL_LOGE(x...) ssdk_printf(SSDK_ERR, x)
|
|
#define HAL_LOGI(x...) ssdk_printf(SSDK_NOTICE, x)
|
|
#define HAL_LOGD(x...) ssdk_printf(SSDK_DEBUG, x)
|
|
|
|
typedef enum {
|
|
osOK = 0, ///< Operation completed successfully.
|
|
osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
|
osErrorTimeout = -2, ///< Operation not completed within the timeout period.
|
|
osErrorResource = -3, ///< Resource not available.
|
|
osErrorParameter = -4, ///< Parameter error.
|
|
osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
|
osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
|
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
|
} osStatus_t;
|
|
|
|
#ifndef reg_addr_t
|
|
typedef paddr_t reg_addr_t;
|
|
#endif
|
|
|
|
#ifndef dma_addr_t
|
|
typedef paddr_t dma_addr_t;
|
|
#endif
|
|
|
|
#define CSI_COMPLETE_EVENT_FLAG 1u
|
|
|
|
typedef void *osEventFlagsId_t;
|
|
typedef struct {
|
|
osEventFlagsId_t event;
|
|
} completion_t;
|
|
|
|
|
|
static inline uint32_t reg_read(reg_addr_t base, uint32_t addr)
|
|
{
|
|
return readl(base + addr);
|
|
}
|
|
|
|
static inline void reg_write(reg_addr_t base, uint32_t addr, uint32_t val)
|
|
{
|
|
writel(val, base + addr);
|
|
}
|
|
|
|
//#define usleep_range(min, max) vTaskDelay(min >> 1)
|
|
static inline void usleep_range(uint32_t min, uint32_t max)
|
|
{
|
|
max = max / 2 + min / 2;
|
|
if (max < 1000)
|
|
max = 1000;
|
|
|
|
max /= 1000;
|
|
vTaskDelay(max);
|
|
}
|
|
|
|
#define mdelay(ms) vTaskDelay(ms)
|
|
#define udelay(us) vTaskDelay((us + 999) / 1000)
|
|
|
|
static inline uint32_t IRQ_Context(void)
|
|
{
|
|
uint32_t irq;
|
|
BaseType_t state;
|
|
|
|
irq = 0U;
|
|
|
|
if (arch_in_irq_mode()) {
|
|
/* Called from interrupt context */
|
|
irq = 1U;
|
|
} else {
|
|
/* Get FreeRTOS scheduler state */
|
|
state = xTaskGetSchedulerState();
|
|
|
|
if (state != taskSCHEDULER_NOT_STARTED) {
|
|
/* Scheduler was started */
|
|
if (arch_irq_is_masked()) {
|
|
/* Interrupts are masked */
|
|
irq = 1U;
|
|
}
|
|
}
|
|
}
|
|
/* Return context, 0: thread context, 1: IRQ context */
|
|
return (irq);
|
|
}
|
|
|
|
inline static void completion_init(completion_t *com)
|
|
{
|
|
// com->event = osEventFlagsNew(NULL);
|
|
EventGroupHandle_t hEventGroup;
|
|
|
|
hEventGroup = NULL;
|
|
if (IRQ_Context() == 0U) { // thread context
|
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
|
hEventGroup = xEventGroupCreate();
|
|
#endif
|
|
}
|
|
/* Return event flags ID */
|
|
com->event = ((osEventFlagsId_t)hEventGroup);
|
|
}
|
|
|
|
inline static void completion_destroy(completion_t *com)
|
|
{
|
|
// osEventFlagsDelete(com->event);
|
|
#ifndef USE_FreeRTOS_HEAP_1
|
|
if (IRQ_Context() == 0U && com->event != NULL) {
|
|
vEventGroupDelete(com->event);
|
|
}
|
|
return;
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
inline static int wait_completion_timeout(completion_t *com, uint32_t timeout)
|
|
{
|
|
// ret = osEventFlagsWait(com->event, CSI_COMPLETE_EVENT_FLAG,
|
|
// osFlagsWaitAny, timeout);
|
|
|
|
uint32_t flags = CSI_COMPLETE_EVENT_FLAG;
|
|
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)com->event;
|
|
BaseType_t wait_all;
|
|
BaseType_t exit_clr;
|
|
uint32_t rflags;
|
|
|
|
if ((hEventGroup == NULL) || ((flags & EVENT_FLAGS_INVALID_BITS) != 0U)) {
|
|
rflags = (uint32_t)osErrorParameter;
|
|
} else if (IRQ_Context() != 0U) {
|
|
rflags = (uint32_t)osErrorISR;
|
|
} else {
|
|
wait_all = pdFAIL;
|
|
exit_clr = pdTRUE;
|
|
|
|
rflags = xEventGroupWaitBits(hEventGroup, (EventBits_t)flags, exit_clr,
|
|
wait_all, (TickType_t)timeout);
|
|
if ((flags & rflags) == 0U) {
|
|
if (timeout > 0U) {
|
|
rflags = (uint32_t)osErrorTimeout;
|
|
} else {
|
|
rflags = (uint32_t)osErrorResource;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (int)rflags;
|
|
}
|
|
|
|
inline static void completion_done(completion_t *com)
|
|
{
|
|
// osEventFlagsSet(com->event, CSI_COMPLETE_EVENT_FLAG);
|
|
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)com->event;
|
|
BaseType_t yield;
|
|
|
|
if ((hEventGroup == NULL) ||
|
|
((CSI_COMPLETE_EVENT_FLAG & EVENT_FLAGS_INVALID_BITS) != 0U)) {
|
|
; // rflags = (uint32_t)osErrorParameter;
|
|
} else if (IRQ_Context() != 0U) {
|
|
#if (configUSE_OS2_EVENTFLAGS_FROM_ISR == 0)
|
|
(void)yield;
|
|
/* Enable timers and xTimerPendFunctionCall function to support
|
|
* osEventFlagsSet from ISR */
|
|
// rflags = (uint32_t)osErrorResource;
|
|
#else
|
|
yield = pdFALSE;
|
|
|
|
if (xEventGroupSetBitsFromISR(hEventGroup,
|
|
(EventBits_t)CSI_COMPLETE_EVENT_FLAG,
|
|
&yield) == pdFAIL) {
|
|
; // rflags = (uint32_t)osErrorResource;
|
|
} else {
|
|
// rflags = CSI_COMPLETE_EVENT_FLAG;
|
|
portYIELD_FROM_ISR(yield);
|
|
}
|
|
#endif
|
|
} else {
|
|
xEventGroupSetBits(hEventGroup, (EventBits_t)CSI_COMPLETE_EVENT_FLAG);
|
|
}
|
|
/* Return event flags after setting */
|
|
// return (rflags);
|
|
}
|
|
|
|
// single R5, no need spin lock
|
|
typedef void *spinlock_t;
|
|
#define spin_lock_init(a) (*a = NULL)
|
|
|
|
#define spin_lock_irqsave(spinlock, flags) \
|
|
do { \
|
|
irq_state_t state = arch_irq_save(); \
|
|
flags = state; \
|
|
} while (0)
|
|
|
|
#define spin_unlock_irqrestore(spinlock, flags) \
|
|
do { \
|
|
irq_state_t state = (irq_state_t)flags; \
|
|
arch_irq_restore(state); \
|
|
} while (0)
|
|
|
|
// gpio_set: set output, and set level to gpio
|
|
static inline void gpio_set(void *dev, unsigned int pin, bool level)
|
|
{
|
|
(void)dev;
|
|
sdrv_gpio_set_pin_direction(pin, GPIO_DIR_OUT);
|
|
sdrv_gpio_set_pin_output_level(pin, level);
|
|
}
|
|
|
|
// I2C interface:
|
|
static inline void wait_idle_and_set_busy(void *ctrl)
|
|
{
|
|
sdrv_i2cdrv_bus_stat_t bus_stat;
|
|
int i = 10;
|
|
|
|
bus_stat = sdrv_i2c_get_bus_stat(ctrl);
|
|
while (bus_stat == SDRV_I2CDRV_BUS_BUSY && i-- > 0) {
|
|
vTaskDelay(2);
|
|
bus_stat = sdrv_i2c_get_bus_stat(ctrl);
|
|
}
|
|
|
|
sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_BUSY);
|
|
}
|
|
|
|
inline static int i2c_write(void *adap, uint8_t addr, uint8_t *buf, int count)
|
|
{
|
|
int ret;
|
|
|
|
wait_idle_and_set_busy(adap);
|
|
sdrv_i2c_write(adap, addr, buf, count, 1000, true);
|
|
ret = sdrv_i2c_get_trans_stat(adap);
|
|
sdrv_i2c_set_bus_stat(adap, SDRV_I2CDRV_BUS_IDLE);
|
|
|
|
return (ret == SDRV_I2CDRV_TRANS_OK) ? 0 : -1;
|
|
}
|
|
|
|
inline static int i2c_read(void *adap, uint8_t addr, uint8_t *buf, int count)
|
|
{
|
|
int ret;
|
|
|
|
wait_idle_and_set_busy(adap);
|
|
sdrv_i2c_read(adap, addr, buf, count, 1000, true);
|
|
ret = sdrv_i2c_get_trans_stat(adap);
|
|
sdrv_i2c_set_bus_stat(adap, SDRV_I2CDRV_BUS_IDLE);
|
|
|
|
return (ret == SDRV_I2CDRV_TRANS_OK) ? 0 : -1;
|
|
}
|
|
|
|
inline static int i2c_write_read(void *adap, uint8_t addr, uint8_t *reg,
|
|
int regc, uint8_t *buf, int bufc)
|
|
{
|
|
int ret;
|
|
|
|
wait_idle_and_set_busy(adap);
|
|
sdrv_i2c_write(adap, addr, reg, regc, 1000, true);
|
|
|
|
ret = sdrv_i2c_get_trans_stat(adap);
|
|
if (ret == SDRV_I2CDRV_TRANS_OK) {
|
|
sdrv_i2c_read(adap, addr, buf, bufc, 1000, true);
|
|
ret = sdrv_i2c_get_trans_stat(adap);
|
|
}
|
|
|
|
sdrv_i2c_set_bus_stat(adap, SDRV_I2CDRV_BUS_IDLE);
|
|
|
|
return (ret == SDRV_I2CDRV_TRANS_OK) ? 0 : -1;
|
|
}
|
|
|
|
// mutext
|
|
typedef QueueHandle_t osMutexId_t;
|
|
static inline osMutexId_t osMutexNew(void *p)
|
|
{
|
|
(void)p;
|
|
return xQueueCreateMutex(queueQUEUE_TYPE_MUTEX);
|
|
}
|
|
|
|
static inline void osMutexDelete(void *p)
|
|
{
|
|
if (p)
|
|
vQueueDelete(p);
|
|
}
|
|
|
|
static inline void osMutexAcquire(void *p, int t)
|
|
{
|
|
(void)p;
|
|
(void)t;
|
|
xQueueTakeMutexRecursive(p, t);
|
|
}
|
|
|
|
static inline void osMutexRelease(void *p)
|
|
{
|
|
(void)p;
|
|
xQueueGiveMutexRecursive(p);
|
|
}
|
|
|
|
#endif /* __SDRV_CAM_OS_DEF_H__ */
|