1.添加和唤醒源同步的逻辑

2.添加宏调整音量
This commit is contained in:
张兆鹏 2025-04-24 18:42:26 +08:00
parent 796620b3ab
commit a270846325
1 changed files with 55 additions and 11 deletions

View File

@ -29,17 +29,35 @@
#define SAMPLE_RATE 16000 #define SAMPLE_RATE 16000
#define PCM_FORMAT_BITS 16 // SNDRV_PCM_FORMAT_S16_LE #define PCM_FORMAT_BITS 16 // SNDRV_PCM_FORMAT_S16_LE
#define PCM_CHANNEL_NUMBER 1 #define PCM_CHANNEL_NUMBER 1
#define SOUND_VOLUME (0x000000A2)// TODO:从806获取音量 0~0xFFdefault 0xA0
struct sunxi_has_mem g_mem; #define HAS_WAIT_WAKEUP_SRC_TIMEOUT 500 // ms
struct sunxi_has_clk g_clk; #define HAS_WAIT_PLAY_END_TIMEOUT 3000 // ms
struct has_pa_config *g_pa_config = NULL;
struct platform_device *g_pdev = NULL; #define WAKEUP_SOURCE_NONE 0x00 // 复位就是0
unsigned int g_pa_pin_max = 0; #define WAKEUP_SOURCE_TOUCH 0x01
#define WAKEUP_SOURCE_STREAM 0x02
#define WAKEUP_SOURCE_DOORBELL 0x03
#define WAKEUP_SOURCE_PEEPHOLE 0x04
#define WAKEUP_SOURCE_INVALID 0xFF // 无效值,忽略,表示已经获取过唤醒源
#define DOOLBELL_PARTITION_NAME "doorbell"
// TODO:可以动态分配管理全局变量,放入device数据中
static struct sunxi_has_mem g_mem;
static struct sunxi_has_clk g_clk;
static struct has_pa_config *g_pa_config = NULL;
static struct platform_device *g_pdev = NULL;
static unsigned int g_pa_pin_max = 0;
struct resource g_res; struct resource g_res;
static unsigned int g_reg_val = 0xA0;
static atomic_t g_wakeup_src = ATOMIC_INIT(0);
// static atomic_t g_wakeup_src;
static DECLARE_COMPLETION(doorbell_end); static DECLARE_COMPLETION(kill_doorbell);
static DECLARE_COMPLETION(relase_done); static DECLARE_COMPLETION(relase_done);
static DECLARE_COMPLETION(wakeup_get);
/* WAV文件格式 */ /* WAV文件格式 */
#pragma pack(1) #pragma pack(1)
@ -100,6 +118,15 @@ static struct dma_slave_config slave_config = {
.src_maxburst = 4, .src_maxburst = 4,
}; };
void doorbell_control(unsigned char wakeup_src) {
if (wakeup_src == WAKEUP_SOURCE_DOORBELL)
{
atomic_set(&g_wakeup_src, wakeup_src);
}
complete(&wakeup_get);
}
EXPORT_SYMBOL(doorbell_control);
static void snd_sunxi_has_mem_deinit(struct platform_device *pdev) static void snd_sunxi_has_mem_deinit(struct platform_device *pdev)
{ {
devm_iounmap(&pdev->dev, g_mem.membase); devm_iounmap(&pdev->dev, g_mem.membase);
@ -140,6 +167,8 @@ static int has_free_own_device(struct platform_device *pdev)
pr_emerg("pdev is NULL\n"); pr_emerg("pdev is NULL\n");
return -1; return -1;
} }
/* set default volume */
regmap_update_bits(g_mem.regmap, SUNXI_DAC_VOL_CTRL, 0x0000FFFF, g_reg_val);
/* clk */ /* clk */
snd_sunxi_has_clk_deinit(); snd_sunxi_has_clk_deinit();
/* memery io unmap */ /* memery io unmap */
@ -155,7 +184,7 @@ static void has_dma_complete(void *arg)
{ {
// enum dma_status status; // enum dma_status status;
// struct dma_tx_state state; // struct dma_tx_state state;
complete(&doorbell_end); complete(&kill_doorbell);
// status = dmaengine_tx_status(dma_chan, dma_cookie, &state); // status = dmaengine_tx_status(dma_chan, dma_cookie, &state);
// pr_emerg("status:%d residue:%d\n", status, state.residue); // pr_emerg("status:%d residue:%d\n", status, state.residue);
} }
@ -166,7 +195,7 @@ static size_t has_decode_WAV_and_getPCM(unsigned char *pcm_data)
size_t retlen = 0; size_t retlen = 0;
struct wav_header_t wav_header; struct wav_header_t wav_header;
mtd = get_mtd_device_nm("logo"); // 名称 mtd = get_mtd_device_nm(DOOLBELL_PARTITION_NAME); // 名称
if (IS_ERR(mtd)) if (IS_ERR(mtd))
{ {
pr_emerg("Failed to get MTD device: %ld\n", PTR_ERR(mtd)); pr_emerg("Failed to get MTD device: %ld\n", PTR_ERR(mtd));
@ -228,6 +257,12 @@ static int snd_has_pcm_playsound(void *param)
dma_addr_t dma_addr = 0; dma_addr_t dma_addr = 0;
unsigned char *dma_area = NULL; unsigned char *dma_area = NULL;
wait_for_completion_interruptible_timeout(&wakeup_get, msecs_to_jiffies(HAS_WAIT_WAKEUP_SRC_TIMEOUT));
if (atomic_read(&g_wakeup_src) != WAKEUP_SOURCE_DOORBELL)
{
goto skip_doorbell;
}
dma_area = dma_alloc_coherent(NULL, DMA_ALLOC_SIZE, &dma_addr, GFP_KERNEL); // 申请dma dma_area = dma_alloc_coherent(NULL, DMA_ALLOC_SIZE, &dma_addr, GFP_KERNEL); // 申请dma
// pr_emerg("dma_area:0x%x dma_addr:0x%x\n", (int)dma_area, (int)dma_addr); // pr_emerg("dma_area:0x%x dma_addr:0x%x\n", (int)dma_area, (int)dma_addr);
if ((!dma_area) || (!dma_addr)) if ((!dma_area) || (!dma_addr))
@ -278,7 +313,7 @@ static int snd_has_pcm_playsound(void *param)
dma_async_issue_pending(dma_chan); dma_async_issue_pending(dma_chan);
// pr_emerg("plad sound start!\n"); // pr_emerg("plad sound start!\n");
wait_for_completion_interruptible(&doorbell_end); wait_for_completion_interruptible_timeout(&kill_doorbell, msecs_to_jiffies(HAS_WAIT_PLAY_END_TIMEOUT));
// dmaengine_synchronize(dma_chan); // dmaengine_synchronize(dma_chan);
dmaengine_terminate_async(dma_chan); dmaengine_terminate_async(dma_chan);
@ -298,6 +333,7 @@ err_request_init:
err_read_init: err_read_init:
dma_free_coherent(NULL, DMA_ALLOC_SIZE, dma_area, dma_addr); dma_free_coherent(NULL, DMA_ALLOC_SIZE, dma_area, dma_addr);
err_alloc_init: err_alloc_init:
skip_doorbell:
has_free_own_device(g_pdev); has_free_own_device(g_pdev);
g_pdev = NULL; g_pdev = NULL;
complete(&relase_done); complete(&relase_done);
@ -868,6 +904,12 @@ static void sunxi_has_codec_init(struct sunxi_has_dts *dts)
regmap_update_bits(regmap, SUNXI_DAC_VOL_CTRL, 1 << DAC_VOL_SEL, 1 << DAC_VOL_SEL); regmap_update_bits(regmap, SUNXI_DAC_VOL_CTRL, 1 << DAC_VOL_SEL, 1 << DAC_VOL_SEL);
regmap_update_bits(regmap, SUNXI_ADC_DIG_CTRL, 1 << ADC1_2_VOL_EN, 1 << ADC1_2_VOL_EN); regmap_update_bits(regmap, SUNXI_ADC_DIG_CTRL, 1 << ADC1_2_VOL_EN, 1 << ADC1_2_VOL_EN);
regmap_read(regmap, SUNXI_DAC_VOL_CTRL, &g_reg_val);
// reg_R_val = (g_reg_val & 0xFF);
// reg_L_val = ((g_reg_val >> 8) & 0xFF);
// pr_emerg("reg_val:0x%08x, L:0x%02x R:0x%02x\n", reg_val, reg_L_val, reg_R_val);
// regmap_update_bits(regmap, SUNXI_DAC_VOL_CTRL, 0x000000FF, SOUND_VOLUME); // R
regmap_update_bits(regmap, SUNXI_DAC_VOL_CTRL, 0x0000FFFF, (SOUND_VOLUME << 8 | SOUND_VOLUME)); // L
} }
static int doolbell_drv_open(struct inode *node, struct file *file) static int doolbell_drv_open(struct inode *node, struct file *file)
@ -892,7 +934,8 @@ static long doolbell_drv_ioctl(struct file *file, unsigned int cmd, unsigned lon
int value; int value;
switch (cmd) { switch (cmd) {
case DOOLBELL_STOP: { case DOOLBELL_STOP: {
complete(&doorbell_end); complete(&kill_doorbell);
complete(&wakeup_get);
wait_for_completion_interruptible(&relase_done); wait_for_completion_interruptible(&relase_done);
if (g_pdev != NULL) if (g_pdev != NULL)
{ {
@ -902,7 +945,7 @@ static long doolbell_drv_ioctl(struct file *file, unsigned int cmd, unsigned lon
break; break;
} }
case DOOLBELL_GET_STATUS: { case DOOLBELL_GET_STATUS: {
/* 用户态应该轮询查询状态 */ /* 用户态应该轮询查询状态轮询不用考虑并发读取g_pdev */
if (g_pdev != NULL) // 启动门铃流程未结束 if (g_pdev != NULL) // 启动门铃流程未结束
{ {
value = DOOLBELL_PLAYING; value = DOOLBELL_PLAYING;
@ -946,6 +989,7 @@ static int has_play_sound_dev_probe(struct platform_device *pdev)
g_mem.dev_name = DRV_NAME; g_mem.dev_name = DRV_NAME;
g_mem.res = &g_res; g_mem.res = &g_res;
g_mem.regmap_config = &g_regmap_config; g_mem.regmap_config = &g_regmap_config;
// atomic_set(&g_wakeup_src, WAKEUP_SOURCE_NONE);
np = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-snd-plat-aaudio"); np = of_find_compatible_node(NULL, NULL, "allwinner,sunxi-snd-plat-aaudio");
if (np) { if (np) {