Linux音頻驅動之五:UDA1341芯片操作接口

本文是基於mini2440開發板Linux版本號是linux-2.6.32.2的學習筆記

一. uda1341的硬件信息

CPU通過L3接口控制uda1341芯片,分別是:
L3DATA: 數據線
L3MODE: 模式控制線,置0時,地址模式;置1時,數據模式
L3CLOCK: 時鐘線

  • 地址模式:
    data[7:2]:表示的是設備地址,UDA1341TS芯片的設備地址是 000101
    data[1:0]:表示的是傳輸類型
    在這裏插入圖片描述
    00:地址寄存器,音量,低音增強,高音,峯值檢測
    擴展寄存器地址,AGC控制,MIC靈敏度控制等
    01:讀回峯值信息
    10: STATUS狀態信息,復位、時鐘、數據輸入格式(數據位寬)等

STATUS控制,地址是:00010110 = 0x16
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

data0控制:地址是:00010100 = 0x14
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

data1控制,地址是:00010101 = 0x15
在這裏插入圖片描述

三. uda1341的寫控制函數

寫控制函數定義如下:

static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
  • 將value保存在cache[reg]中。
uda134x_write_reg_cache(codec, reg, value);
  • 根據傳入的reg值,寫地址。
  • UDA134X_EA000 ~ UDA134X_EA111屬於擴展地址,也屬於data[0:0]
    發送地址是:(5 << 2) | 0 ),發送地址時,L3MODE引腳拉低,地址模式。
    發送擴展地址,擴展地址最多有8個,但是擴展地址的最高兩位爲1,所以地址要與上0xc0
#define UDA134X_EXTADDR_PREFIX	0xC0
addr =  (reg | UDA134X_EXTADDR_PREFIX);
ret = l3_write(&pd->l3, UDA134X_DATA0_ADDR, &addr, 1);

發送擴展數據,擴展數據的高三位都是1,所以要在原來value上加0xe0

#define UDA134X_EXTDATA_PREFIX	0xE0
data = (value | UDA134X_EXTDATA_PREFIX);
ret = l3_write(&pd->l3, addr, &data, 1);

發送擴展地址和發送擴展數據,實際上都是發送數據,L3MODE引腳要拉高,選擇數據模式。
在這裏插入圖片描述

  • UDA134X_STATUS0和UDA134X_STATUS1屬於data[1:0]
    發送地址是:(5 << 2) | 2 )
    發送數據:
#define UDA134X_STATUS_ADDR	((UDA134X_L3ADDR << 2) | 2)
addr = UDA134X_STATUS_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
  • UDA134X_DATA000,UDA134X_DATA001,UDA134X_DATA010屬於data[0:0]
    發送地址是:(5 << 2) | 0 )
    發送數據:
#define UDA134X_L3ADDR	5
#define UDA134X_DATA0_ADDR	((UDA134X_L3ADDR << 2) | 0)
addr = UDA134X_DATA0_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
  • UDA134X_DATA1屬於data[0:1]
    發送地址是:(5 << 2) | 1 )
    發送數據:
#define UDA134X_L3ADDR	5
#define UDA134X_DATA1_ADDR	((UDA134X_L3ADDR << 2) | 1)
addr = UDA134X_DATA1_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
四. uda1341的復位操作

發送地址:(5 << 2) | 2 )
發送數據:value | (1<<6)

五. uda1341的靜音操作

發送地址:(5 << 2) | 0 )
發送數據:value | (1<<2)

六. uda1341的時鐘設置

1.設置系統時鐘
uda1341支持三種系統時鐘, 512fs, 384fs,256fs
2.uda1341支持的採樣率爲:8000,11025,16000,22050,32000,44100,48000
3.則系統時鐘的範圍是:256 * 8000 <= freq <= 512 * 48000

2.設置時鐘調用函數uda134x_set_dai_sysclk

static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct uda134x_priv *uda134x = codec->private_data;

	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
		 clk_id, freq, dir);

	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
	   because the codec is slave. Of course limitations of the clock
	   master (the IIS controller) apply.
	   We'll error out on set_hw_params if it's not OK */
	if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
		uda134x->sysclk = freq;
		return 0;
	}

	printk(KERN_ERR "%s unsupported sysclk\n", __func__);
	return -EINVAL;
}

在這裏系統時鐘並沒有真正的設置下去,而是保存到了uda134x->sysclk變量中,留在後面設置。

七. 設置支持數據格式

1.uda1341支持的格式如下:

(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
  1. 設置數據格式調用的函數是uda134x_set_dai_fmt
static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct uda134x_priv *uda134x = codec->private_data;

	pr_debug("%s fmt: %08X\n", __func__, fmt);

	/* codec supports only full slave mode */
	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
		printk(KERN_ERR "%s unsupported slave mode\n", __func__);
		return -EINVAL;
	}

	/* no support for clock inversion */
	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
		printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
		return -EINVAL;
	}

	/* We can't setup DAI format here as it depends on the word bit num */
	/* so let's just store the value for later */
	uda134x->dai_fmt = fmt;

	return 0;
}
八. uda1341設置bias(猜測是電源)等級

SND_SOC_BIAS_ON等級:
把ADC, DAC打開
發送地址:(5 << 2) | 2 )
發送數據:0x83
在這裏插入圖片描述
SND_SOC_BIAS_PREPARE等級:

pd->power(1);
for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
    codec->write(codec, i, *cache++);

SND_SOC_BIAS_STANDBY等級:
發送地址:(5 << 2) | 2 )
發送數據:value & ~(0x03)

SND_SOC_BIAS_OFF等級:

pd->power(0);
九. 設置硬件參數

設置硬件參數調用的函數是uda134x_hw_params

  • 設置芯片的系統時鐘的除數,512, 384,256
switch (uda134x->sysclk / params_rate(params)) 
{
	case 512:
		break;
	case 384:
		hw_params |= (1<<4);
		break;
	case 256:
		hw_params |= (1<<5);
		break;
	default:
		printk(KERN_ERR "%s unsupported fs\n", __func__);
		return -EINVAL;
}

在這裏插入圖片描述
發送數據:384fs(vaule | (1 << 4)) 256fs(value | 1 << 5)

  • 設置數據模式
switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) 
{
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		switch (params_format(params)) {
		case SNDRV_PCM_FORMAT_S16_LE:
			hw_params |= (1<<1);
			break;
		case SNDRV_PCM_FORMAT_S18_3LE:
			hw_params |= (1<<2);
			break;
		case SNDRV_PCM_FORMAT_S20_3LE:
			hw_params |= ((1<<2) | (1<<1));
			break;
		default:
			printk(KERN_ERR "%s unsupported format (right)\n",
			       __func__);
			return -EINVAL;
		}
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		hw_params |= (1<<3);
		break;
	default:
		printk(KERN_ERR "%s unsupported format\n", __func__);
		return -EINVAL;
}

SND_SOC_DAIFMT_I2S:0
SND_SOC_DAIFMT_RIGHT_J和SND_SOC_DAIFMT_LEFT_J模式參考下圖
在這裏插入圖片描述

十. Linux UDA1341芯片接口註冊
static struct snd_soc_dai_ops uda134x_dai_ops = {
	.startup	= uda134x_startup,
	.shutdown	= uda134x_shutdown,
	.hw_params	= uda134x_hw_params,
	.digital_mute	= uda134x_mute,
	.set_sysclk	= uda134x_set_dai_sysclk,
	.set_fmt	= uda134x_set_dai_fmt,
};
struct snd_soc_dai uda134x_dai = {
	.name = "UDA134X",
	/* playback capabilities */
	.playback = {
		.stream_name = "Playback",
		.channels_min = 1,
		.channels_max = 2,
		.rates = UDA134X_RATES,
		.formats = UDA134X_FORMATS,
	},
	/* capture capabilities */
	.capture = {
		.stream_name = "Capture",
		.channels_min = 1,
		.channels_max = 2,
		.rates = UDA134X_RATES,
		.formats = UDA134X_FORMATS,
	},
	/* pcm operations */
	.ops = &uda134x_dai_ops,
};
  • 註冊時間:在啓動內核是調用uda134x_init函數。在uda134x_init函數中註冊UDA1341接口。
static int __init uda134x_init(void)
{
	return snd_soc_register_dai(&uda134x_dai);
}
module_init(uda134x_init);

跟I2S的接口註冊一樣,註冊到一個dai_list的全局鏈表中,dai_list鏈表中是各種各樣的dai接口。

十一. 總結
  • uda134x_dai接口在內核起來時註冊。
  • uda134x_dai接口包含對UDA1341芯片的時鐘,傳輸模式等硬件設置,一個硬件參數操作集uda134x_dai_ops。

參考博客:
https://blog.csdn.net/gqb_driver/article/details/8551551

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章