// SPDX-License-Identifier: GPL-2.0
//
// Mediatek ALSA BT SCO CVSD/MSBC Driver
//
// Copyright (c) 2019 MediaTek Inc.
// Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/sched/clock.h>
#include <sound/soc.h>
#define BTCVSD_SND_NAME "mtk-btcvsd-snd"
#define BT_CVSD_TX_NREADY BIT(21)
#define BT_CVSD_RX_READY BIT(22)
#define BT_CVSD_TX_UNDERFLOW BIT(23)
#define BT_CVSD_RX_OVERFLOW BIT(24)
#define BT_CVSD_INTERRUPT BIT(31)
#define BT_CVSD_CLEAR \
(BT_CVSD_TX_NREADY | BT_CVSD_RX_READY | BT_CVSD_TX_UNDERFLOW |\
BT_CVSD_RX_OVERFLOW | BT_CVSD_INTERRUPT)
/* TX */
#define SCO_TX_ENCODE_SIZE (60)
/* 18 = 6 * 180 / SCO_TX_ENCODE_SIZE */
#define SCO_TX_PACKER_BUF_NUM (18)
/* RX */
#define SCO_RX_PLC_SIZE (30)
#define SCO_RX_PACKER_BUF_NUM (64)
#define SCO_RX_PACKET_MASK (0x3F)
#define SCO_CVSD_PACKET_VALID_SIZE 2
#define SCO_PACKET_120 120
#define SCO_PACKET_180 180
#define BTCVSD_RX_PACKET_SIZE (SCO_RX_PLC_SIZE + SCO_CVSD_PACKET_VALID_SIZE)
#define BTCVSD_TX_PACKET_SIZE (SCO_TX_ENCODE_SIZE)
#define BTCVSD_RX_BUF_SIZE (BTCVSD_RX_PACKET_SIZE * SCO_RX_PACKER_BUF_NUM)
#define BTCVSD_TX_BUF_SIZE (BTCVSD_TX_PACKET_SIZE * SCO_TX_PACKER_BUF_NUM)
enum bt_sco_state {
BT_SCO_STATE_IDLE,
BT_SCO_STATE_RUNNING,
BT_SCO_STATE_ENDING,
BT_SCO_STATE_LOOPBACK,
};
enum bt_sco_direct {
BT_SCO_DIRECT_BT2ARM,
BT_SCO_DIRECT_ARM2BT,
};
enum bt_sco_packet_len {
BT_SCO_CVSD_30 = 0,
BT_SCO_CVSD_60,
BT_SCO_CVSD_90,
BT_SCO_CVSD_120,
BT_SCO_CVSD_10,
BT_SCO_CVSD_20,
BT_SCO_CVSD_MAX,
};
enum BT_SCO_BAND {
BT_SCO_NB,
BT_SCO_WB,
};
struct mtk_btcvsd_snd_hw_info {
unsigned int num_valid_addr;
unsigned long bt_sram_addr[20];
unsigned int packet_length;
unsigned int packet_num;
};
struct mtk_btcvsd_snd_stream {
struct snd_pcm_substream *substream;
int stream;
enum bt_sco_state state;
unsigned int packet_size;
unsigned int buf_size;
u8 temp_packet_buf[SCO_PACKET_180];
int packet_w;
int packet_r;
snd_pcm_uframes_t prev_frame;
int prev_packet_idx;
unsigned int xrun:1;
unsigned int timeout:1;
unsigned int mute:1;
unsigned int trigger_start:1;
unsigned