812 lines
20 KiB
C
Raw Normal View History

2025-10-10 16:07:00 +08:00
// Copyright 2023-2024 Beken
//
// 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 <os/os.h>
#include <os/mem.h>
#include <driver/gpio.h>
#include <driver/int.h>
#include <driver/lin.h>
#include <driver/lin_types.h>
#include "clock_driver.h"
#include "gpio_driver.h"
#include "power_driver.h"
#include "lin_statis.h"
#include "lin_driver.h"
#include "lin_hal.h"
#include "sys_driver.h"
#include "FreeRTOS.h"
#include "task.h"
#if CONFIG_LIN_PM_CB_SUPPORT
#include <modules/pm.h>
#endif
#if CONFIG_LIN_DEVICE_MASTER
#define LIN_DEV LIN_MASTER
#define LIN_DEV_ID LIN_IDENT0
#define LIN_CHN LIN_CHAN_2
#else
#define LIN_DEV LIN_SLAVE
#define LIN_DEV_ID LIN_IDENT0
#define LIN_CHN LIN_CHAN_2
#endif
#define LIN_TAG "lin"
#define LIN_BAUD_RATE (2000)
#define LIN_RETURN_ON_DEVICE_NOT_INIT() do { \
if (!s_lin_driver_is_init) { \
LIN_LOGE("lin driver not init\r\n"); \
return BK_ERR_LIN_NOT_INIT; \
} \
} while(0)
#define LIN_RETURN_ON_INVALID_INT(type) do { \
if ((type) >= LIN_INT_MAX) { \
return BK_ERR_LIN_INT_TYPE; \
} \
} while(0)
static lin_callback_t s_lin_isr[LIN_INT_MAX] = {NULL};
static bool s_lin_driver_is_init = false;
static lin_buf_t s_lin_buf;
static TaskHandle_t lin_xBlockTasks;
static lin_gpio_t s_lin_gpio[LIN_CHAN_MAX] = LIN_GPIO_MAP;
static lin_config_t s_lin_def_cfg = {
.chn = LIN_CHN,
.dev = LIN_DEV,
.length = LIN_DATA_LEN_8BYTES,
.checksum = LIN_CLASSIC,
.rate = LIN_BAUD_RATE,
.bus_inactiv_time = LIN_BUS_INACTIVITY_10S,
.wup_repeat_time = LIN_WUP_REPEAT_240MS,
};
#if (CONFIG_LIN_PM_CB_SUPPORT)
#define LIN_PM_CHECK_RESTORE() do {\
if (bk_pm_module_lv_sleep_state_get(PM_DEV_ID_LIN)) {\
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_AHBP_LIN, PM_POWER_MODULE_STATE_ON);\
lin_pm_restore(0, NULL);\
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_LIN);\
}\
} while(0)
static uint32_t s_lin_pm_backup[LIN_PM_BACKUP_REG_NUM];
static uint8_t s_lin_pm_backup_is_valid;
static int lin_pm_backup(uint64_t sleep_time, void *args)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
if (!s_lin_pm_backup_is_valid)
{
s_lin_pm_backup_is_valid = 1;
lin_hal_backup(&s_lin_pm_backup[0]);
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_LIN, CLK_PWR_CTRL_PWR_DOWN);
}
return BK_OK;
}
static int lin_pm_restore(uint64_t sleep_time, void *args)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
if (s_lin_pm_backup_is_valid)
{
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_LIN, CLK_PWR_CTRL_PWR_UP);
lin_hal_restore(&s_lin_pm_backup[0]);
s_lin_pm_backup_is_valid = 0;
}
return BK_OK;
}
#else
#define LIN_PM_CHECK_RESTORE()
#endif
bk_err_t bk_lin_gpio_init(lin_channel_t chn)
{
if (chn >= LIN_CHAN_MAX || chn < LIN_CHAN_0) {
LIN_LOGD("unsupported lin chnnal\r\n");
return BK_ERR_PARAM;
}
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].tx_gpio.id));
BK_LOG_ON_ERR(gpio_dev_map(s_lin_gpio[chn].tx_gpio.id, s_lin_gpio[chn].tx_gpio.dev));
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].rx_gpio.id));
BK_LOG_ON_ERR(gpio_dev_map(s_lin_gpio[chn].rx_gpio.id, s_lin_gpio[chn].rx_gpio.dev));
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].sleep_gpio.id));
BK_LOG_ON_ERR(gpio_dev_map(s_lin_gpio[chn].sleep_gpio.id, s_lin_gpio[chn].sleep_gpio.dev));
return BK_OK;
}
static bk_err_t bk_lin_gpio_deinit(lin_channel_t chn)
{
if (chn >= LIN_CHAN_MAX || chn < LIN_CHAN_0) {
LIN_LOGD("unsupported lin chnnal\r\n");
return BK_ERR_PARAM;
}
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].tx_gpio.id));
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].rx_gpio.id));
BK_LOG_ON_ERR(gpio_dev_unmap(s_lin_gpio[chn].sleep_gpio.id));
return BK_OK;
}
bk_err_t bk_lin_clock_enable(void)
{
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_LIN, CLK_PWR_CTRL_PWR_UP);
return BK_OK;
}
bk_err_t bk_lin_clock_disable(void)
{
sys_drv_dev_clk_pwr_up(CLK_PWR_ID_LIN, CLK_PWR_CTRL_PWR_DOWN);
return BK_OK;
}
bk_err_t bk_lin_interrupt_enable(void)
{
sys_drv_int_group2_enable(LIN_INTERRUPT_CTRL_BIT);
return BK_OK;
}
bk_err_t bk_lin_interrupt_disable(void)
{
sys_drv_int_group2_disable(LIN_INTERRUPT_CTRL_BIT);
return BK_OK;
}
void lin_error(void)
{
__attribute__((__unused__)) lin_statis_t *lin_statis = lin_statis_get_statis(lin_hal_get_ident_id());
if (lin_hal_get_error_bit() != 0) {
LIN_LOGD("bit error occurs during data transmission!!!\n");
if (s_lin_isr[LIN_INT_BIT_ERR].isr) {
s_lin_isr[LIN_INT_BIT_ERR].isr(s_lin_isr[LIN_INT_BIT_ERR].arg);
}
LIN_STATIS_INC(lin_statis->bit_err_cnt);
} else if (lin_hal_get_error_chk() != 0 ) {
LIN_LOGD("checksum error occurs!!!\n");
if (s_lin_isr[LIN_INT_CHK_ERR].isr) {
s_lin_isr[LIN_INT_CHK_ERR].isr(s_lin_isr[LIN_INT_CHK_ERR].arg);
}
LIN_STATIS_INC(lin_statis->chk_err_cnt);
} else if (lin_hal_get_error_timeout() != 0) {
LIN_LOGD("timeout error occurs!!!\n");
if (s_lin_isr[LIN_INT_TIMEOUT_ERR].isr) {
s_lin_isr[LIN_INT_TIMEOUT_ERR].isr(s_lin_isr[LIN_INT_TIMEOUT_ERR].arg);
}
LIN_STATIS_INC(lin_statis->timeout_err_cnt);
} else if (lin_hal_get_error_parity() != 0) {
LIN_LOGD("parity occurs!!!\n");
if (s_lin_isr[LIN_INT_PARITY_ERR].isr) {
s_lin_isr[LIN_INT_PARITY_ERR].isr(s_lin_isr[LIN_INT_PARITY_ERR].arg);
}
LIN_STATIS_INC(lin_statis->parity_err_cnt);
} else {
LIN_LOGD("lin unknown interrupt error!!!\n");
}
}
static void lin_isr_master(void)
{
__attribute__((__unused__)) lin_statis_t *lin_statis = lin_statis_get_statis(lin_hal_get_ident_id());
if (lin_hal_get_status_error() != 0) {
lin_error();
LIN_STATIS_INC(lin_statis->error_cnt);
} else if (lin_hal_get_status_wake_up() != 0) {
/* TODO, after waking up, you can do corresponding operations */
LIN_LOGD("The device has sent or received a wakeup signal!!!\n");
LIN_STATIS_INC(lin_statis->parity_err_cnt);
if (s_lin_isr[LIN_INT_WAKEUP].isr) {
s_lin_isr[LIN_INT_WAKEUP].isr(s_lin_isr[LIN_INT_WAKEUP].arg);
}
LIN_STATIS_INC(lin_statis->wakeup_cnt);
} else if (lin_hal_get_status_complete() != 0) {
/* TODO, you can do corresponding operations */
LIN_LOGD("master transmit completed\n");
if (s_lin_isr[LIN_INT_COMPLETE].isr) {
s_lin_isr[LIN_INT_COMPLETE].isr(s_lin_isr[LIN_INT_COMPLETE].arg);
}
LIN_STATIS_INC(lin_statis->completed_cnt);
} else {
LIN_LOGD("lin unknown interrupt!!!\n");
}
lin_hal_set_ctrl_reset_error();
lin_hal_set_ctrl_reset_int();
LIN_STATIS_INC(lin_statis->isr_cnt);
}
static void lin_isr_slave(void)
{
__attribute__((__unused__)) lin_statis_t *lin_statis = lin_statis_get_statis(lin_hal_get_ident_id());
if (lin_hal_get_status_error() != 0) {
lin_error();
LIN_STATIS_INC(lin_statis->error_cnt);
} else if (lin_hal_get_status_data_req() != 0) {
LIN_LOGD("data_req occures!!!\n");
if (s_lin_isr[LIN_INT_DATA_REQ].isr) {
s_lin_isr[LIN_INT_DATA_REQ].isr(s_lin_isr[LIN_INT_DATA_REQ].arg);
}
LIN_STATIS_INC(lin_statis->data_req_cnt);
} else if (lin_hal_get_status_aborted() != 0) {
LIN_LOGD("transmission is aborted!!!\n");
if (s_lin_isr[LIN_INT_ABORTED].isr) {
s_lin_isr[LIN_INT_ABORTED].isr(s_lin_isr[LIN_INT_ABORTED].arg);
}
LIN_STATIS_INC(lin_statis->aborted_cnt);
} else if (lin_hal_get_status_bus_idle_timeout() != 0) {
LIN_LOGD("bus idle timeout occurs,go to sleep!!!\n");
if (s_lin_isr[LIN_INT_IDLE_TIMEOUT].isr) {
s_lin_isr[LIN_INT_IDLE_TIMEOUT].isr(s_lin_isr[LIN_INT_IDLE_TIMEOUT].arg);
}
bk_lin_set_sleep();
LIN_STATIS_INC(lin_statis->bus_idle_timeout_cnt);
} else if (lin_hal_get_status_wake_up() != 0) {
/* TODO, after waking up, you can do corresponding operations */
LIN_LOGD("The device has sent or received a wakeup signal!!!\n");
if (s_lin_isr[LIN_INT_WAKEUP].isr) {
s_lin_isr[LIN_INT_WAKEUP].isr(s_lin_isr[LIN_INT_WAKEUP].arg);
}
// bk_lin_set_wakeup();
LIN_STATIS_INC(lin_statis->wakeup_cnt);
} else if (lin_hal_get_status_complete() != 0) {
/* TODO, you can do corresponding operations */
LIN_LOGD("transmission is completed!!!\n");
if (s_lin_isr[LIN_INT_COMPLETE].isr) {
s_lin_isr[LIN_INT_COMPLETE].isr(s_lin_isr[LIN_INT_COMPLETE].arg);
}
LIN_STATIS_INC(lin_statis->completed_cnt);
} else {
LIN_LOGD("lin unknown interrupt!!!\n");
}
lin_hal_set_ctrl_reset_error();
lin_hal_set_ctrl_reset_int();
}
static void lin_isr(void)
{
if (lin_hal_get_master() == LIN_MASTER) {
lin_isr_master();
} else {
lin_isr_slave();
}
}
bk_err_t bk_lin_set_dev(lin_dev_t dev)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_master_cfg(dev);
return BK_OK;
}
bk_err_t bk_lin_get_dev(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_master();
}
bk_err_t bk_lin_set_ident(uint32_t ident)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ident_value(ident & LIN_IDENT_MASK);
return BK_OK;
}
bk_err_t bk_lin_get_ident(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_ident_value();
}
bk_err_t bk_lin_set_ident_id(uint32_t id)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ident_id(id);
return BK_OK;
}
uint32_t bk_lin_get_ident_id(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_ident_id();
}
bk_err_t bk_lin_set_rate(double rate)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_rate(rate);
return BK_OK;
}
double bk_lin_get_rate(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_rate();
}
bk_err_t bk_lin_set_data_length(lin_data_len_t len)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
if (len > LIN_DATA_LEN_8BYTES) {
len = LIN_DATA_LEN_8BYTES;
}
lin_hal_set_type_data_length(len);
return BK_OK;
}
bk_err_t bk_lin_get_data_length(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_type_data_length();
}
bk_err_t bk_lin_set_enh_check(lin_checksum_t enh_check)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_type_enh_check(enh_check);
return BK_OK;
}
bk_err_t bk_lin_get_enh_check(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_type_enh_check();
}
bk_err_t bk_lin_set_wup_repeat_time(lin_wup_repeat_time_t time)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_tcfg_wup_repeat_time(time);
return BK_OK;
}
bk_err_t bk_lin_get_wup_repeat_time(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_tcfg_wup_repeat_time();
}
bk_err_t bk_lin_set_bus_inactivity_time(lin_bus_inactivity_time_t time)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_tcfg_bus_inactivity_time(time);
return BK_OK;
}
bk_err_t bk_lin_get_bus_inactivity_time(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_tcfg_bus_inactivity_time();
}
bk_err_t bk_lin_set_transmit(lin_trans_t trans)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ctrl_transmit(trans);
return BK_OK;
}
bk_err_t bk_lin_get_transmit(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_ctrl_transmit();
}
bk_err_t bk_lin_set_start_req(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ctrl_start_req();
return BK_OK;
}
bk_err_t bk_lin_get_start_req(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_ctrl_start_req();
}
bk_err_t bk_lin_set_sleep(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ctrl_sleep();
return BK_OK;
}
bk_err_t bk_lin_get_sleep(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
return lin_hal_get_ctrl_sleep();
}
bk_err_t bk_lin_set_wakeup(void)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
lin_hal_set_ctrl_wakeup();
return BK_OK;
}
static void bk_lin_complete_func(void *arg)
{
if (lin_hal_get_ctrl_transmit() == LIN_RECV) {
if (lin_xBlockTasks != NULL) {
vTaskNotifyGiveFromISR(lin_xBlockTasks, NULL);
lin_xBlockTasks = NULL;
}
LIN_LOGD("recevie completed\r\n");
} else {
LIN_LOGD("send completed\r\n");
}
}
static void bk_lin_data_req_func(void *arg)
{
uint32_t ident, id, dir;
lin_buf_t *lin_buf = (lin_buf_t *)arg;
if (!lin_buf) {
LIN_LOGE("data_req arg is NULL!!!\n");
return;
}
if (lin_buf->id >= LIN_IDENT_MAX) {
LIN_LOGE("error: unknown id!!!\n");
return;
}
/* a. Load the identifier from the field "id" from register IDENT and process it */
ident = bk_lin_get_ident();
id = ident & LIN_IDENT_ID_MASK;
dir = (ident >> LIN_IDENT_DIR_POS) & LIN_IDENT_DIR_MASK;
if (id == lin_buf->id) {
/* b. Adjust the bit "transmit" in register CTRL */
/* c. Load the "data length" and "set enh_check" in register TYPE */
/* d. Load the data to transmit into the data buffer (for transmit operation only) */
/* e. Set the bit "data ack" in register CTRL. */
bk_lin_set_data_length(lin_buf->len);
if (dir == LIN_SEND) {
lin_hal_set_ctrl_transmit(LIN_RECV);
} else {
lin_hal_set_ctrl_transmit(LIN_SEND);
bk_lin_send(lin_buf->tx_buf, lin_buf->len);
}
lin_hal_set_ctrl_data_ack();
} else {
lin_hal_set_ctrl_stop();
}
}
static void bk_lin_wakeup_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("The device has sent or received a wakeup signal!!!\n");
}
static void bk_lin_idle_timeout_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("bus idle timeout occurs!!!\n");
}
static void bk_lin_aborted_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("transmission is aborted!!!\n");
}
static void bk_lin_bit_error_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("bit error occurs during data transmission!!!\n");
}
static void bk_lin_chk_error_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("checksum error occurs!!!\n");
}
static void bk_lin_timeout_error_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("timeout error occurs!!!\n");
}
static void bk_lin_parity_error_func(void *arg)
{
/* TODO, you can do corresponding operations */
LIN_LOGD("parity occurs!!!\n");
}
bk_err_t bk_lin_send(uint8_t *buf, uint32_t len)
{
int i;
uint32_t size = len;
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
BK_RETURN_ON_NULL(buf);
if (len >= LIN_DATA_LEN_MAX) {
LIN_LOGE("length exceeds max\r\n");
size = LIN_DATA_LEN_8BYTES;
}
for (i = 0; i < size; i++) {
lin_hal_set_data_byte(i, buf[i]);
}
return BK_OK;
}
bk_err_t bk_lin_recv(uint8_t *buf, uint32_t len)
{
int i;
uint32_t size = len;
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
BK_RETURN_ON_NULL(buf);
if (len >= LIN_DATA_LEN_MAX) {
LIN_LOGE("length exceeds max\r\n");
size = LIN_DATA_LEN_8BYTES;
}
os_memset(buf, 0, len);
for (i = 0; i < size; i++) {
buf[i] = lin_hal_get_data_byte(i);
}
return BK_OK;
}
bk_err_t bk_lin_tx(lin_id_t id, uint8_t *tx, uint32_t len)
{
uint32_t size = len;
uint32_t ident = id | BIT(4);
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
BK_RETURN_ON_NULL(tx);
if (id >= LIN_IDENT_MAX) {
LIN_LOGE("id exceeds max\r\n");
return BK_FAIL;
}
if (len >= LIN_DATA_LEN_MAX) {
LIN_LOGE("length exceeds max\r\n");
size = LIN_DATA_LEN_8BYTES;
}
lin_hal_set_ctrl_reset_int();
bk_lin_interrupt_enable();
if (bk_lin_get_sleep() != 0) {
bk_lin_set_wakeup();
}
if (lin_hal_get_master() == LIN_MASTER) {
BK_RETURN_ON_ERR(bk_lin_get_start_req());
bk_lin_set_ident(ident);
bk_lin_set_data_length(size);
bk_lin_set_transmit(LIN_SEND);
bk_lin_send(tx, size);
if (bk_lin_get_sleep() != 0) {
bk_lin_set_wakeup();
}
bk_lin_set_start_req();
} else {
s_lin_buf.id = id;
os_memset(s_lin_buf.tx_buf, 0, size);
os_memcpy(s_lin_buf.tx_buf, tx, size);
s_lin_buf.len = size;
bk_lin_register_isr(LIN_INT_DATA_REQ, bk_lin_data_req_func, (void *)&s_lin_buf);
}
return BK_OK;
}
bk_err_t bk_lin_rx(lin_id_t id, uint8_t *rx, uint32_t len, uint32_t timeout)
{
uint32_t size = len;
int ret;
uint32_t ident = id & ~BIT(4);
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
BK_RETURN_ON_NULL(rx);
if (id >= LIN_IDENT_MAX) {
LIN_LOGE("id exceeds max\r\n");
return BK_FAIL;
}
if (len >= LIN_DATA_LEN_MAX) {
LIN_LOGE("length exceeds max\r\n");
size = LIN_DATA_LEN_8BYTES;
}
bk_lin_interrupt_enable();
if (bk_lin_get_sleep() != 0) {
bk_lin_set_wakeup();
}
if (lin_hal_get_master() == LIN_MASTER) {
bk_lin_set_ident(ident);
bk_lin_set_data_length(size);
bk_lin_set_transmit(LIN_RECV);
bk_lin_set_start_req();
} else {
s_lin_buf.id = id;
os_memset(s_lin_buf.tx_buf, 0, size);
os_memset(s_lin_buf.rx_buf, 0, size);
s_lin_buf.len = size;
bk_lin_register_isr(LIN_INT_DATA_REQ, bk_lin_data_req_func, (void *)&s_lin_buf);
}
lin_xBlockTasks = xTaskGetCurrentTaskHandle();
xTaskNotifyStateClear(NULL);
ret = ulTaskNotifyTake(pdTRUE, timeout);
if(ret < 0) {
LIN_LOGE("error occurred!!!\r\n");
lin_hal_set_ctrl_reset_int();
return ret;
} else if (ret == 0) {
LIN_LOGE("TaskNotify timeout occurred!!!\r\n");
}
bk_lin_recv(rx, size);
return ret;
}
bk_err_t bk_lin_register_isr(lin_int_type_t type, lin_isr_t isr, void *arg)
{
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
LIN_RETURN_ON_INVALID_INT(type);
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
s_lin_isr[type].isr = isr;
s_lin_isr[type].arg = arg;
GLOBAL_INT_RESTORE();
return BK_OK;
}
bk_err_t bk_lin_cfg(lin_config_t *cfg)
{
BK_RETURN_ON_NULL(cfg);
LIN_RETURN_ON_DEVICE_NOT_INIT();
LIN_PM_CHECK_RESTORE();
BK_LOG_ON_ERR(bk_lin_gpio_init(cfg->chn));
lin_hal_master_cfg(cfg->dev);
lin_hal_set_rate(cfg->rate);
lin_hal_set_type_enh_check(cfg->checksum);
lin_hal_set_tcfg_bus_inactivity_time(cfg->bus_inactiv_time);
lin_hal_set_tcfg_wup_repeat_time(cfg->wup_repeat_time);
return BK_OK;
}
bk_err_t bk_lin_driver_init(void)
{
if (s_lin_driver_is_init) {
return BK_OK;
}
os_memset(&s_lin_isr, 0, sizeof(s_lin_isr));
s_lin_buf.id = LIN_DEV_ID;
s_lin_buf.len = LIN_DATA_LEN_8BYTES;
#if (CONFIG_LIN_PM_CB_SUPPORT)
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_AHBP_LIN, PM_POWER_MODULE_STATE_ON);
pm_cb_conf_t enter_config = {lin_pm_backup, NULL};
bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_LIN, &enter_config, NULL);
bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_LIN);
#endif
bk_lin_clock_enable();
bk_lin_interrupt_disable();
lin_hal_init();
s_lin_driver_is_init = true;
if (bk_lin_cfg(&s_lin_def_cfg) != BK_OK) {
LIN_LOGE("lin config failed\r\n");
bk_lin_driver_deinit();
return BK_ERR_NOT_INIT;
}
lin_statis_init();
bk_lin_register_isr(LIN_INT_WAKEUP, bk_lin_wakeup_func, NULL);
bk_lin_register_isr(LIN_INT_BIT_ERR, bk_lin_bit_error_func, NULL);
bk_lin_register_isr(LIN_INT_CHK_ERR, bk_lin_chk_error_func, NULL);
bk_lin_register_isr(LIN_INT_TIMEOUT_ERR, bk_lin_timeout_error_func, NULL);
bk_lin_register_isr(LIN_INT_PARITY_ERR, bk_lin_parity_error_func, NULL);
bk_lin_register_isr(LIN_INT_COMPLETE, bk_lin_complete_func, NULL);
if (lin_hal_get_master() == LIN_SLAVE) {
bk_lin_register_isr(LIN_INT_DATA_REQ, bk_lin_data_req_func, (void *)&s_lin_buf);
bk_lin_register_isr(LIN_INT_IDLE_TIMEOUT, bk_lin_idle_timeout_func, NULL);
bk_lin_register_isr(LIN_INT_ABORTED, bk_lin_aborted_func, NULL);
}
bk_int_isr_register(INT_SRC_LIN, lin_isr, NULL);
lin_hal_set_ctrl_reset_error();
lin_hal_set_ctrl_reset_int();
bk_lin_interrupt_enable();
return BK_OK;
}
bk_err_t bk_lin_driver_deinit(void)
{
if (!s_lin_driver_is_init) {
return BK_OK;
}
bk_lin_interrupt_disable();
bk_lin_gpio_deinit(LIN_CHAN_2);
lin_hal_deinit();
bk_int_isr_unregister(INT_SRC_LIN);
bk_lin_clock_disable();
#if (CONFIG_LIN_PM_CB_SUPPORT)
bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_LIN, true, true);
bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_AHBP_LIN, PM_POWER_MODULE_STATE_OFF);
#endif
s_lin_driver_is_init = false;
return BK_OK;
}