summaryrefslogtreecommitdiff
path: root/bsp/phytium/libraries/standalone/drivers/can/fcan/fcan_intr.c
blob: a792448e73e849eed9a9c94099131129e886cc3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright : (C) 2022 Phytium Information Technology, Inc.
 * All Rights Reserved.
 *
 * This program is OPEN SOURCE software: you can redistribute it and/or modify it
 * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
 * either version 1.0 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the Phytium Public License for more details.
 *
 *
 * FilePath: fcan_intr.c
 * Date: 2022-02-10 14:53:42
 * LastEditTime: 2022-02-18 08:29:10
 * Description:  This files is for
 *
 * Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#include "finterrupt.h"
#include "fcan.h"
#include "fcan_hw.h"
#include "fassert.h"
#include "ftypes.h"
#include "fdebug.h"

#define FT_CAN_DEBUG_TAG "FT_CAN_INTR"
#define FCAN_DEBUG(format, ...) FT_DEBUG_PRINT_D(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_INFO(format, ...) FT_DEBUG_PRINT_I(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_WARN(format, ...) FT_DEBUG_PRINT_W(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_ERROR(format, ...) FT_DEBUG_PRINT_E(FT_CAN_DEBUG_TAG, format, ##__VA_ARGS__)

#define FCAN_CALL_INTR_EVENT_HANDLDER(instance_p, event) \
    if (instance_p->intr_event[event].handler)                 \
        instance_p->intr_event[event].handler(instance_p->intr_event[event].param)

/**
 * @name: FCanRegisterInterruptHandler
 * @msg: register FCanCtrl interrupt handler function
 * @param {FCanCtrl} *instance_p, pointer to the Can instance
 * @param {FCanIntrEventConfig} *intr_event_p, interrupt event type, handler and parameters
 * @return {*}
 */
void FCanRegisterInterruptHandler(FCanCtrl *instance_p, FCanIntrEventConfig *intr_event_p)
{
    FASSERT(instance_p);
    FASSERT(intr_event_p);
    FCanIntrEventType type = intr_event_p->type;
    FASSERT(intr_event_p->type < FCAN_INTR_EVENT_NUM);
    instance_p->intr_event[type].type = type;
    instance_p->intr_event[type].handler = intr_event_p->handler;
    instance_p->intr_event[type].param = intr_event_p->param;
}

/**
 * @name: FCanIntrHandler
 * @msg:  This function is the interrupt handler for the driver.
 *          It must be connected to an interrupt system by the application such that it
 *          can be called when an interrupt occurs.
 * @param vector Irq num, Don't need attention.
 * @param args  contains a pointer to the driver instance
 * @return {*}
 */
void FCanIntrHandler(s32 vector, void *args)
{
    u32 irq_status;
    FCanCtrl *instance_p = (FCanCtrl *)args;
    FCanConfig *config_p;
    FASSERT(instance_p != NULL);
    FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
    config_p = &instance_p->config;
    irq_status = FCAN_READ_REG32(config_p->base_address, FCAN_INTR_OFFSET);

    if (0 == irq_status)
    {
        return;
    }

    /* Check for the type of error interrupt and Processing it */
    if (irq_status & FCAN_INTR_TEIS_MASK)
    {
        irq_status &= ~FCAN_INTR_REIS_MASK;
        FCAN_SETBIT(config_p->base_address, FCAN_INTR_OFFSET,
                    FCAN_INTR_TEIC_MASK | FCAN_INTR_REIC_MASK);
        FCAN_CLEARBIT(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);
        FCAN_SETBIT(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_TXREQ_MASK);
        FCAN_SETBIT(config_p->base_address, FCAN_CTRL_OFFSET, FCAN_CTRL_XFER_MASK);

        FCAN_CALL_INTR_EVENT_HANDLDER(instance_p, FCAN_INTR_EVENT_SEND);
    }

    if (irq_status & (FCAN_INTR_EIS_MASK | FCAN_INTR_RFIS_MASK | FCAN_INTR_TFIS_MASK |
                      FCAN_INTR_BOIS_MASK | FCAN_INTR_PEIS_MASK | FCAN_INTR_PWIS_MASK))
    {
        FCAN_CALL_INTR_EVENT_HANDLDER(instance_p, FCAN_INTR_EVENT_ERROR);

        FCAN_SETBIT(config_p->base_address, FCAN_INTR_OFFSET,
                    (FCAN_INTR_EIC_MASK | FCAN_INTR_RFIC_MASK | FCAN_INTR_BOIC_MASK |
                     FCAN_INTR_PEIC_MASK | FCAN_INTR_PWIC_MASK));

        /* Check for rx fifo full interrupt and output error information */
        if (irq_status & FCAN_INTR_RFIS_MASK)
        {
            FCAN_ERROR("rx_fifo is full!!!");
            /* disable rx fifo full interrupt */
            FCAN_CLEARBIT(config_p->base_address, FCAN_INTR_OFFSET, FCAN_INTR_RFIE_MASK);
        }

        if (irq_status & FCAN_INTR_TFIS_MASK)
        {
            FCAN_ERROR("tx_fifo is empty!!!");
            /* disable tx fifo empty interrupt */
            FCAN_CLEARBIT(config_p->base_address, FCAN_INTR_OFFSET, FCAN_INTR_TFIE_MASK);
        }
    }

    if (irq_status & FCAN_INTR_REIS_MASK)
    {
        FCAN_SETBIT(config_p->base_address, FCAN_INTR_OFFSET, FCAN_INTR_REIE_MASK);
        FCAN_SETBIT(config_p->base_address, FCAN_INTR_OFFSET, FCAN_INTR_REIC_MASK);
        FCAN_SETBIT(config_p->base_address, FCAN_INTR_OFFSET, FCAN_INTR_REIE_MASK);
        FCAN_CALL_INTR_EVENT_HANDLDER(instance_p, FCAN_INTR_EVENT_RECV);
    }
}