int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id)
{
	unsigned int i_ret = -1;
	unsigned int base = p_dma_info->base;

	BTIF_TRC_FUNC();

	if (DMA_CTRL_DISABLE == ctrl_id) {
/*if write 0 to EN bit, DMA will be stoped imediately*/
/*if write 1 to STOP bit, DMA will be stoped after current transaction finished*/
		BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT);
		BTIF_DBG_FUNC("BTIF Rx DMA disabled\n");
		i_ret = 0;
	} else if (DMA_CTRL_ENABLE == ctrl_id) {
		BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT);
		BTIF_DBG_FUNC("BTIF Rx DMA enabled\n");
		i_ret = 0;
	} else {
/*TODO: print error log*/
		BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id);
		i_ret = ERR_INVALID_PAR;
	}
	BTIF_TRC_FUNC();

	return i_ret;
}
Пример #2
0
/*****************************************************************************
* FUNCTION
*  hal_btif_is_tx_complete
* DESCRIPTION
*  get tx complete flag
* PARAMETERS
* p_base   [IN]        BTIF module's base address
* RETURNS
*  true means tx complete, false means tx in process
*****************************************************************************/
bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif)
{
    /*Chaozhong: To be implement*/
    bool b_ret = false;
    unsigned int lsr = 0;
	unsigned long flags = 0;
    unsigned int base = p_btif->base;
	unsigned int tx_empty = 0;
	unsigned int rx_dr = 0;
	unsigned int tx_irq_disable = 0;
	/*3 conditions allow clock to be disable
	1. if TEMT is set or not
	2. if DR is set or not
	3. Tx IRQ is disabled or not*/
    lsr = BTIF_READ32(BTIF_LSR(base));
	tx_empty = lsr & BTIF_LSR_TEMT_BIT;
	rx_dr = lsr & BTIF_LSR_DR_BIT;
	tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN;
	
    b_ret = (tx_empty && (0 == tx_irq_disable) && (0 == rx_dr) ) ? true : false;
	if (!b_ret)
	{
	    BTIF_DBG_FUNC("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", tx_empty, rx_dr, tx_irq_disable);
	}
 #if NEW_TX_HANDLING_SUPPORT
    spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags);
	/*clear Tx enable flag if necessary*/
	if (!(kfifo_is_empty(p_btif->p_tx_fifo))){
		BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n");
		b_ret = false;
	}
	spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags);
#endif
    return b_ret;
}
Пример #3
0
int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id)
{
	unsigned int i_ret = -1;
	unsigned long base = p_dma_info->base;
	unsigned int dat;
	BTIF_TRC_FUNC();
	if (DMA_CTRL_DISABLE == ctrl_id) {
		/*if write 0 to EN bit, DMA will be stoped imediately*/
		/*if write 1 to STOP bit, DMA will be stoped after current transaction finished*/
		/*BTIF_CLR_BIT(TX_DMA_EN(base), DMA_EN_BIT);*/
		BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT);
		do {
			dat = BTIF_READ32(TX_DMA_STOP(base));
		} while (0x1 & dat);
		BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n",
			BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base)));
		i_ret = 0;
	} else if (DMA_CTRL_ENABLE == ctrl_id) {
		BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT);
		BTIF_DBG_FUNC("BTIF Tx DMA enabled\n");
		i_ret = 0;
	} else {
/*TODO: print error log*/
		BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id);
		i_ret = ERR_INVALID_PAR;
	}
	BTIF_TRC_FUNC();
	return i_ret;
}
Пример #4
0
/*****************************************************************************
* FUNCTION
*  btif_tx_irq_handler
* DESCRIPTION
*  lower level tx interrupt handler 
* PARAMETERS
* p_base   [IN]        BTIF module's base address
* p_buf     [IN/OUT] pointer to rx data buffer
* max_len  [IN]        max length of rx buffer
* RETURNS
*  0 means success, negative means fail
*****************************************************************************/
static int btif_tx_irq_handler (P_MTK_BTIF_INFO_STR p_btif)
{
    int i_ret = -1;
#if NEW_TX_HANDLING_SUPPORT
    int how_many = 0;
    unsigned int lsr;
	unsigned int ava_len = 0;
	unsigned int base = p_btif->base;
	char local_buf[BTIF_TX_FIFO_SIZE];
	char *p_data = local_buf;
	unsigned long flag = 0;
	
    struct kfifo *p_tx_fifo = p_btif->p_tx_fifo;
	
	/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/
	lsr = BTIF_READ32(BTIF_LSR(base));
	
	if (lsr & BTIF_LSR_TEMT_BIT)
	{
		/*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/
		ava_len = BTIF_TX_FIFO_SIZE;
	}
	else if (lsr & BTIF_LSR_THRE_BIT)
	{
		/*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/
		ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE;
	}else
	{
		/*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/
		ava_len = 0;
		goto ret;
	}
	spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag);
	how_many = kfifo_out(p_tx_fifo, local_buf, ava_len);
	spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag);
	BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, kfifo_avail(p_tx_fifo));
    while (how_many--)
    {
        btif_reg_sync_writeb(*(p_data++), BTIF_THR(base));
    }
	
	spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag);
	/*clear Tx enable flag if necessary*/
	if (kfifo_is_empty(p_tx_fifo)){
        hal_btif_tx_ier_ctrl(p_btif, false);
		BTIF_DBG_FUNC("BTIF tx FIFO is empty\n");
	}
	spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag);
ret:
#else
    /*clear Tx enable flag*/
    hal_btif_tx_ier_ctrl(p_btif, false);
#endif
    i_ret = 0;
    return i_ret;
}
Пример #5
0
int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid)
{
    int i_ret = -1;
	BTIF_DBG_FUNC("op id: %d\n", opid);
	switch (opid)
	{
	    case BTIF_PM_DPIDLE_EN:
			i_ret = 0;
			break;
	    case BTIF_PM_DPIDLE_DIS:
			i_ret = 0;
			break;
        case BTIF_PM_SUSPEND:
			i_ret = 0;
			break;
	    case BTIF_PM_RESUME:
			i_ret = 0;
			break;
	    case BTIF_PM_RESTORE_NOIRQ:
			{
				unsigned int flag = 0;
				P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq;
				switch (p_irq->sens_type)
			    {
			         case IRQ_SENS_EDGE:
			            if (IRQ_EDGE_FALL == p_irq->edge_type)
			                flag = IRQF_TRIGGER_FALLING;
			            else if (IRQ_EDGE_RAISE == p_irq->edge_type)
			                flag = IRQF_TRIGGER_RISING;
			            else if (IRQ_EDGE_BOTH == p_irq->edge_type)
			                flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
			            else
			                flag = IRQF_TRIGGER_FALLING; /*make this as default type*/
			            break;
			         case IRQ_SENS_LVL:
			            if (IRQ_LVL_LOW == p_irq->lvl_type)
			                flag = IRQF_TRIGGER_LOW;
			            else if (IRQ_LVL_HIGH == p_irq->lvl_type)
			                flag = IRQF_TRIGGER_HIGH;
			            else
			                flag = IRQF_TRIGGER_LOW; /*make this as default type*/
			            break;
			        default:
			            flag = IRQF_TRIGGER_LOW;/*make this as default type*/
			            break;
			    }
				//irq_set_irq_type(p_irq->irq_id, flag);
			    i_ret = 0;
	    	}
			break;
		default:
			i_ret = ERR_INVALID_PAR;
			break;
	}

	return i_ret;
}
Пример #6
0
/*****************************************************************************
* FUNCTION
*  hal_btif_is_tx_allow
* DESCRIPTION
*  whether tx is allowed
* PARAMETERS
* p_base   [IN]        BTIF module's base address
* RETURNS
* true if tx operation is allowed; false if tx is not allowed
*****************************************************************************/
bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif)
{
#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000 )
#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000 )

    /*Chaozhong: To be implement*/
    bool b_ret = false;
    unsigned int base = p_btif->base;
    unsigned int lsr = 0;
    unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB ; /*only ava length */
#if NEW_TX_HANDLING_SUPPORT
    unsigned long flags = 0;
    spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags);
	/*clear Tx enable flag if necessary*/
	if (kfifo_is_full(p_btif->p_tx_fifo)){
		BTIF_WARN_FUNC("BTIF tx FIFO is full\n");
		b_ret = false;
	}
	else
	{
	    b_ret = true;
	}
	spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags);
#else
    /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/
    lsr = BTIF_READ32(BTIF_LSR(base));
    
    if(!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)))
    {
        BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us);
        //usleep_range(wait_us, 3 * 10 * wait_us);
        usleep_range(wait_us, 3 * wait_us);
    }
    lsr = BTIF_READ32(BTIF_LSR(base));
    b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false;
    if (!b_ret)
        BTIF_DBG_FUNC(" tx is not allowed for the moment\n");
    else
        BTIF_DBG_FUNC(" tx is allowed\n");
#endif	
    return b_ret;
}
Пример #7
0
/*****************************************************************************
* FUNCTION
*  hal_dma_get_ava_room
* DESCRIPTION
*  get tx available room
* PARAMETERS
* p_dma_info   [IN]        pointer to BTIF dma channel's information
* RETURNS
*  available room  size
*****************************************************************************/
int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info)
{
	int i_ret = -1;
	unsigned long base = p_dma_info->base;

/*read vFIFO's left size*/
	i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base));
	BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret);
	if (0 == i_ret)
		BTIF_INFO_FUNC("DMA tx vfifo is full.\n");

	return i_ret;
}
static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info)
{
    int i_ret = 0;
    unsigned long flag = 0;

    spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag);
    if (NULL == p_btif_info->p_tx_fifo) {
        i_ret = 0;
    } else {
        i_ret = kfifo_avail(p_btif_info->p_tx_fifo);
    }
    spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag);
    BTIF_DBG_FUNC("tx kfifo:0x%x, available room:%d\n", i_ret);
    return i_ret;
}
/*****************************************************************************
* FUNCTION
*  hal_dma_is_tx_complete
* DESCRIPTION
*  get tx complete flag
* PARAMETERS
* p_dma_info   [IN]        pointer to BTIF dma channel's information
* RETURNS
*  true means tx complete, false means tx in process
*****************************************************************************/
bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info)
{
	bool b_ret = -1;
	unsigned int base = p_dma_info->base;
	unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base));
	unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base));
	unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info);

/*only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0,
we can identify tx operation finished
confirmed with DE.
*/
	if ((0 == valid_size) && (0 == inter_size) && (1 == tx_done)) {
		b_ret = true;
		BTIF_DBG_FUNC("DMA tx finished.\n");
	} else {
		BTIF_DBG_FUNC
		    ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n",
		     valid_size, inter_size, tx_done);
		b_ret = false;
	}

	return b_ret;
}
Пример #10
0
static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info)
{
	unsigned int i_ret = -1;
	unsigned long base = p_dma_info->base;
	unsigned int stop = BTIF_READ32(TX_DMA_STOP(base));

/*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/
	if ((DMA_STOP_BIT && stop) != 0)
		BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n");
	else {
		BTIF_DBG_FUNC("flush tx dma\n");
		BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT);
		i_ret = 0;
	}
	return i_ret;
}
Пример #11
0
p_mtk_btif btif_exp_srh_id(unsigned int u_id)
{
	int index = 0;
	p_mtk_btif p_btif = NULL;
	struct list_head *p_list = NULL;
	struct list_head *tmp = NULL;
	p_mtk_btif_user p_user = NULL;

	for (index = 0; (index < BTIF_PORT_NR) && (NULL == p_btif); index++) {
		p_list = &(g_btif[index].user_list);
		list_for_each(tmp, p_list) {
			p_user = container_of(tmp, mtk_btif_user, entry);
			if (u_id == p_user->u_id) {
				p_btif = p_user->p_btif;
				BTIF_DBG_FUNC
				    ("BTIF's user id(0x%08x), p_btif(0x%08x)\n",
				     p_user->u_id, p_btif);
				break;
			}
		}
	}
/*****************************************************************************
* FUNCTION
*  hal_btif_send_data
* DESCRIPTION
*  send data through btif in FIFO mode
* PARAMETERS
* p_base   [IN]        BTIF module's base address
* p_buf     [IN]        pointer to rx data buffer
* max_len  [IN]        tx buffer length
* RETURNS
*   positive means number of data sent; 0 means no data put to FIFO; negative means error happens
*****************************************************************************/
int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif,
                       const unsigned char *p_buf, const unsigned int buf_len)
{
    /*Chaozhong: To be implement*/
    int i_ret = -1;

    unsigned int ava_len = 0;
    unsigned int sent_len = 0;

#if !(NEW_TX_HANDLING_SUPPORT)
    unsigned int base = p_btif->base;
    unsigned int lsr = 0;
    unsigned int left_len = 0;
    unsigned char *p_data = (unsigned char *)p_buf;
#endif

    /*check parameter valid or not*/
    if ((NULL == p_buf) || (buf_len == 0)) {
        i_ret = ERR_INVALID_PAR;
        return i_ret;
    }
#if NEW_TX_HANDLING_SUPPORT
    ava_len = _get_btif_tx_fifo_room(p_btif);
    sent_len = buf_len <= ava_len ? buf_len : ava_len;
    if (0 < sent_len) {
        int enqueue_len = 0;
        unsigned long flag = 0;
        spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag);
        enqueue_len = kfifo_in(p_btif->p_tx_fifo,
                               (unsigned char *)p_buf, sent_len);
        if (sent_len != enqueue_len) {
            BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n",
                          sent_len, enqueue_len);
        }
        i_ret = enqueue_len;
        dsb();
        /*enable BTIF Tx IRQ*/
        hal_btif_tx_ier_ctrl(p_btif, true);
        spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag);
        BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len);
    } else {
        i_ret = 0;
    }
#else
    while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) {
        /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/
        lsr = BTIF_READ32(BTIF_LSR(base));

        if (lsr & BTIF_LSR_TEMT_BIT) {
            /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/
            ava_len = BTIF_TX_FIFO_SIZE;
        } else if (lsr & BTIF_LSR_THRE_BIT) {
            /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/
            ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE;
        } else {
            /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/
            ava_len = 0;
            break;
        }

        left_len = buf_len - sent_len;
        /*ava_len will be real length will write to BTIF THR*/
        ava_len = ava_len > left_len ? left_len : ava_len;
        /*update sent length valud after this operation*/
        sent_len += ava_len;
        /*whether we need memory barrier here?
        Ans: No, no memory ordering issue exist,
        CPU will make sure logically right
        */
        while (ava_len--)
            btif_reg_sync_writeb(*(p_data++), BTIF_THR(base));

    }
    /* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */

    i_ret = sent_len;

    /*enable BTIF Tx IRQ*/
    hal_btif_tx_ier_ctrl(p_btif, true);
#endif
    return i_ret;
}
/*****************************************************************************
* FUNCTION
*  hal_btif_clk_ctrl
* DESCRIPTION
*  control clock output enable/disable of BTIF module
* PARAMETERS
* p_base   [IN]        BTIF module's base address
* RETURNS
*  0 means success, negative means fail
*****************************************************************************/
int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag)
{
    /*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/
    /*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/
    int i_ret = 0;
    unsigned long irq_flag = 0;

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER
    static atomic_t s_clk_ref = ATOMIC_INIT(0);
#else
    static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE;
#endif
    spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);

#if MTK_BTIF_ENABLE_CLK_CTL

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER

    if (CLK_OUT_ENABLE == flag) {
        if (1 == atomic_inc_return(&s_clk_ref)) {
            i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID);
            if (i_ret) {
                BTIF_WARN_FUNC
                ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d",
                 i_ret);
            }
        }
    } else if (CLK_OUT_DISABLE == flag) {
        if (0 == atomic_dec_return(&s_clk_ref)) {
            i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID);
            if (i_ret) {
                BTIF_WARN_FUNC
                ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d",
                 i_ret);
            }
        }
    } else {
        i_ret = ERR_INVALID_PAR;
        BTIF_ERR_FUNC("invalid	clock ctrl flag (%d)\n", flag);
    }

#else

    if (status == flag) {
        i_ret = 0;
        BTIF_DBG_FUNC("btif clock already %s\n",
                      CLK_OUT_ENABLE ==
                      status ? "enabled" : "disabled");
    } else {
        if (CLK_OUT_ENABLE == flag) {
            i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID);
            status = (0 == i_ret) ? flag : status;
            if (i_ret) {
                BTIF_WARN_FUNC
                ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d",
                 i_ret);
            }
        } else if (CLK_OUT_DISABLE == flag) {
            i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID);
            status = (0 == i_ret) ? flag : status;
            if (i_ret) {
                BTIF_WARN_FUNC
                ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d",
                 i_ret);
            }
        } else {
            i_ret = ERR_INVALID_PAR;
            BTIF_ERR_FUNC("invalid	clock ctrl flag (%d)\n", flag);
        }
    }
#endif

#else

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER

#else

    status = flag;
#endif

    i_ret = 0;
#endif

    spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER
    if (0 == i_ret) {
        BTIF_DBG_FUNC("btif clock %s\n",
                      CLK_OUT_ENABLE == flag ? "enabled" : "disabled");
    } else {
        BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n",
                      CLK_OUT_ENABLE == flag ? "enable" : "disable",
                      i_ret);
    }
#else

    if (0 == i_ret) {
        BTIF_DBG_FUNC("btif clock %s\n",
                      CLK_OUT_ENABLE == flag ? "enabled" : "disabled");
    } else {
        BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n",
                      CLK_OUT_ENABLE == flag ? "enable" : "disable",
                      i_ret);
    }
#endif
#if MTK_BTIF_ENABLE_CLK_CTL
    BTIF_DBG_FUNC("BTIF's clock is %s\n",
                  (0 == clock_is_on(MTK_BTIF_CG_BIT)) ? "off" : "on");
#endif

    return i_ret;
}
/*****************************************************************************
* FUNCTION
*  hal_rx_dma_irq_handler
* DESCRIPTION
*  lower level rx interrupt handler
* PARAMETERS
* p_dma_info   [IN]        pointer to BTIF dma channel's information
* p_buf     [IN/OUT] pointer to rx data buffer
* max_len  [IN]        max length of rx buffer
* RETURNS
*  0 means success, negative means fail
*****************************************************************************/
int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info,
			   unsigned char *p_buf, const unsigned int max_len)
{
	int i_ret = -1;
	unsigned int valid_len = 0;
	unsigned int wpt_wrap = 0;
	unsigned int rpt_wrap = 0;
	unsigned int wpt = 0;
	unsigned int rpt = 0;
	unsigned int tail_len = 0;
	unsigned int real_len = 0;
	unsigned int base = p_dma_info->base;
	P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo;
	dma_rx_buf_write rx_cb = p_dma_info->rx_cb;
	unsigned char *p_vff_buf = NULL;
	unsigned char *vff_base = p_vfifo->p_vir_addr;
	unsigned int vff_size = p_vfifo->vfifo_size;
	P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo,
							MTK_BTIF_DMA_VFIFO,
							vfifo);
	unsigned long flag = 0;

	spin_lock_irqsave(&(g_clk_cg_spinlock), flag);
	if (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) {
		spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag);
		BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n",
			      __FILE__);
		return i_ret;
	}
/*disable DMA Rx IER*/
	hal_btif_dma_ier_ctrl(p_dma_info, false);

/*clear Rx DMA's interrupt status*/
	BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE);

	valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base));
	rpt = BTIF_READ32(RX_DMA_VFF_RPT(base));
	wpt = BTIF_READ32(RX_DMA_VFF_WPT(base));
	if ((0 == valid_len) && (rpt == wpt)) {
		BTIF_DBG_FUNC
		    ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n",
		     rpt, wpt);
	}

	i_ret = 0;

	while ((0 < valid_len) || (rpt != wpt)) {
		rpt_wrap = rpt & DMA_RPT_WRAP;
		wpt_wrap = wpt & DMA_WPT_WRAP;
		rpt &= DMA_RPT_MASK;
		wpt &= DMA_WPT_MASK;

/*calcaute length of available data  in vFIFO*/
		if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) {
			real_len = wpt + vff_size - rpt;
		} else {
			real_len = wpt - rpt;
		}

		if (NULL != rx_cb) {
			tail_len = vff_size - rpt;
			p_vff_buf = vff_base + rpt;
			if (tail_len >= real_len) {
				(*rx_cb) (p_dma_info, p_vff_buf, real_len);
			} else {
				(*rx_cb) (p_dma_info, p_vff_buf, tail_len);
				p_vff_buf = vff_base;
				(*rx_cb) (p_dma_info, p_vff_buf, real_len -
					  tail_len);
			}
			i_ret += real_len;
		} else {
			BTIF_ERR_FUNC
			    ("no rx_cb found, please check your init process\n");
		}
		dsb();
		rpt += real_len;
		if (rpt >= vff_size) {
/*read wrap bit should be revert*/
			rpt_wrap ^= DMA_RPT_WRAP;
			rpt %= vff_size;
		}
		rpt |= rpt_wrap;
/*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/
		p_mtk_vfifo->wpt = wpt;
		p_mtk_vfifo->last_wpt_wrap = wpt_wrap;

		p_mtk_vfifo->rpt = rpt;
		p_mtk_vfifo->last_rpt_wrap = rpt_wrap;

/*update rpt information to DMA controller*/
		btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base));

/*get vff valid size again and check if rx data is processed completely*/
		valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base));

		rpt = BTIF_READ32(RX_DMA_VFF_RPT(base));
		wpt = BTIF_READ32(RX_DMA_VFF_WPT(base));
	}

/*enable DMA Rx IER*/
	hal_btif_dma_ier_ctrl(p_dma_info, true);
	spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag);
	return i_ret;
}
/*****************************************************************************
* FUNCTION
*  hal_tx_dma_irq_handler
* DESCRIPTION
*  lower level tx interrupt handler
* PARAMETERS
* p_dma_info   [IN]        pointer to BTIF dma channel's information
* RETURNS
*  0 means success, negative means fail
*****************************************************************************/
int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info)
{
#define MAX_CONTINIOUS_TIMES 512
	unsigned int i_ret = -1;
	unsigned int valid_size = 0;
	unsigned int vff_len = 0;
	unsigned int left_len = 0;
	unsigned int base = p_dma_info->base;
	static int flush_irq_counter;
	static struct timeval start_timer;
	static struct timeval end_timer;
	unsigned long flag = 0;
	spin_lock_irqsave(&(g_clk_cg_spinlock), flag);
	if (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) {
		spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag);
		BTIF_ERR_FUNC
		    ("%s: clock is off before irq status clear done!!!\n",
		     __FILE__);
		return i_ret;
	}
/*check if Tx VFF Left Size equal to VFIFO size or not*/
	vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base));
	valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base));
	left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base));
	if (0 == flush_irq_counter) {
		do_gettimeofday(&start_timer);
	}
	if ((0 < valid_size) && (8 > valid_size)) {
		i_ret = _tx_dma_flush(p_dma_info);
		flush_irq_counter++;
		if (MAX_CONTINIOUS_TIMES <= flush_irq_counter) {
			do_gettimeofday(&end_timer);
/*when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while
we assume that btif cannot send data for a long time
in order not to generate interrupt continiously, which may effect system's performance.
we clear tx flag and disable btif tx interrupt
*/
/*clear interrupt flag*/
			BTIF_CLR_BIT(TX_DMA_INT_FLAG(base),
				     TX_DMA_INT_FLAG_MASK);
/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/
			i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false);
			BTIF_ERR_FUNC
			    ("**********************ERROR, ERROR, ERROR**************************\n");
			BTIF_ERR_FUNC
			    ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n",
			     MAX_CONTINIOUS_TIMES, start_timer.tv_sec,
			     start_timer.tv_usec, end_timer.tv_usec,
			     end_timer.tv_usec);
		}
	} else if (vff_len == left_len) {
		flush_irq_counter = 0;
/*clear interrupt flag*/
		BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK);
/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/
		i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false);
	} else {
#if 0
		BTIF_ERR_FUNC
		    ("**********************WARNING**************************\n");
		BTIF_ERR_FUNC("invalid irq condition, dump register\n");
		hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL);
#endif
		BTIF_DBG_FUNC
		    ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n",
		     vff_len, valid_size, left_len);
	}
	spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag);
	return i_ret;
}
Пример #16
0
/*****************************************************************************
* FUNCTION
*  hal_btif_clk_ctrl
* DESCRIPTION
*  control clock output enable/disable of DMA module
* PARAMETERS
* p_dma_info   [IN]        pointer to BTIF dma channel's information
* RETURNS
*  0 means success, negative means fail
*****************************************************************************/
int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag)
{
/*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/
/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/
	int i_ret = 0;
	unsigned long irq_flag = 0;

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER
	static atomic_t s_clk_ref = ATOMIC_INIT(0);
#else
	static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE;
#endif

#if defined(CONFIG_MTK_LEGACY)
	spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);
#endif

#if MTK_BTIF_ENABLE_CLK_CTL

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER

	if (CLK_OUT_ENABLE == flag) {
		if (1 == atomic_inc_return(&s_clk_ref)) {
#if defined(CONFIG_MTK_LEGACY)
			i_ret =
			    enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID);
			if (i_ret) {
				BTIF_WARN_FUNC
				    ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d",
				     i_ret);
			}
#else
			clk_prepare(clk_btif_apdma);
			spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);
			clk_enable(clk_btif_apdma);
			spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);
			BTIF_INFO_FUNC("[CCF]enable clk_btif_apdma\n");
#endif /* defined(CONFIG_MTK_LEGACY) */
		}
	} else if (CLK_OUT_DISABLE == flag) {
		if (0 == atomic_dec_return(&s_clk_ref)) {
#if defined(CONFIG_MTK_LEGACY)
			i_ret =
			    disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID);
			if (i_ret) {
				BTIF_WARN_FUNC
				    ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d",
				     i_ret);
			}
#else
			spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);
			clk_disable(clk_btif_apdma);
			spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);
			clk_unprepare(clk_btif_apdma);
			BTIF_INFO_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n");
#endif /* defined(CONFIG_MTK_LEGACY) */

		}
	} else {
		i_ret = ERR_INVALID_PAR;
		BTIF_ERR_FUNC("invalid  clock ctrl flag (%d)\n", flag);
	}

#else

	if (status == flag) {
		i_ret = 0;
		BTIF_DBG_FUNC("dma clock already %s\n",
			      CLK_OUT_ENABLE ==
			      status ? "enabled" : "disabled");
	} else {
		if (CLK_OUT_ENABLE == flag) {
#if defined(CONFIG_MTK_LEGACY)
			i_ret =
			    enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID);
			status = (0 == i_ret) ? flag : status;
			if (i_ret) {
				BTIF_WARN_FUNC
				    ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d",
				     i_ret);
			}
#else
			clk_prepare(clk_btif_apdma);
			spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);
			clk_enable(clk_btif_apdma);
			spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);
			BTIF_INFO_FUNC("[CCF]enable clk_btif_apdma\n");
#endif /* defined(CONFIG_MTK_LEGACY) */

		} else if (CLK_OUT_DISABLE == flag) {
#if defined(CONFIG_MTK_LEGACY)
			i_ret =
			    disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID);
			status = (0 == i_ret) ? flag : status;
			if (i_ret) {
				BTIF_WARN_FUNC
				    ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d",
				     i_ret);
			}
#else
			spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);
			clk_disable(clk_btif_apdma);
			spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);
			clk_unprepare(clk_btif_apdma);
			BTIF_INFO_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n");
#endif /* defined(CONFIG_MTK_LEGACY) */

		} else {
			i_ret = ERR_INVALID_PAR;
			BTIF_ERR_FUNC("invalid  clock ctrl flag (%d)\n", flag);
		}
	}
#endif

#else

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER

#else

	status = flag;
#endif

	i_ret = 0;
#endif

#if defined(CONFIG_MTK_LEGACY)
	spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);
#endif

#if MTK_BTIF_ENABLE_CLK_REF_COUNTER
	if (0 == i_ret) {
		BTIF_DBG_FUNC("dma clock %s\n",
			      CLK_OUT_ENABLE == flag ? "enabled" : "disabled");
	} else {
		BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n",
			      CLK_OUT_ENABLE == flag ? "enable" : "disable",
			      i_ret);
	}
#else

	if (0 == i_ret) {
		BTIF_DBG_FUNC("dma clock %s\n",
			      CLK_OUT_ENABLE == flag ? "enabled" : "disabled");
	} else {
		BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n",
			      CLK_OUT_ENABLE == flag ? "enable" : "disable",
			      i_ret);
	}
#endif
#if defined(CONFIG_MTK_LEGACY)
	BTIF_DBG_FUNC("DMA's clock is %s\n",
		      (0 == clock_is_on(MTK_BTIF_APDMA_CLK_CG)) ? "off" : "on");
#endif
	return i_ret;
}