PCM1716を使用するにはシステムクロックが必要になるので
Raspberry Pi I2S 出力で外部クロック使用 その2
のようにPLL1707で外部クロックを生成するのですが、当時は16bit、48kHzまでしか想定していないのと768fsを使いたかったせいで、そのままでは使えませんでした。
そんなわけでシンプルにしてみました。
PLL1707は96kHzだと384fsまでしか出せないっぽいので、システムクロックにはPLL1707のSCKO3の384fsを。
RPiの入力に必要なビットクロック64fsはSCKO2の256fsを74AC163で4分周しました。
次にI2Sドライバー側です。過去の記事とほぼ一緒ですが...
以下、GPIOのピン番号はRPi B+用になってます。
sound/soc/bcm/bcm2708-i2s.c
53行目辺り
#include <linux/gpio.h>
#include <linux/delay.h>
539行目辺り
gpio_request_one(26, GPIOF_OUT_INIT_LOW, "MyTest");
if (sampling_rate == 48000 || sampling_rate == 96000) {
gpio_set_value(26, 0);
} else {
gpio_set_value(26, 1);
}
gpio_free(26);
gpio_request_one(13, GPIOF_OUT_INIT_LOW, "MyTest");
if (sampling_rate == 96000) {
gpio_set_value(13, 1);
} else {
gpio_set_value(13, 0);
}
gpio_free(13);
gpio_request_one(16, GPIOF_OUT_INIT_LOW, "MyTest");
if (data_length == 16) {
gpio_set_value(16, 0);
} else {
gpio_set_value(16, 1);
}
gpio_free(16);
GPIO26をPLL1707のFS1に繋いで44.1kHzか48kHzかを設定。GPIO13をPLL1707のSRに繋いで上記周波数を2倍にするか否かを設定。
GPIO16をPCM1716のIWOに繋いで16bitか24bitかを設定しています。
694行目辺り
GPIO12をPCM1716のMUTEに繋いでます。struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); uint32_t mask; int myerr; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: myerr = gpio_request_one(12, GPIOF_OUT_INIT_LOW, "MyTest"); if (myerr == 0) { gpio_set_value(12, 1); gpio_free(12); mdelay(100); } bcm2708_i2s_start_clock(dev); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) mask = BCM2708_I2S_RXON; else mask = BCM2708_I2S_TXON; regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, mask, mask); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: myerr = gpio_request_one(12, GPIOF_OUT_INIT_LOW, "MyTest"); if (myerr == 0) { gpio_set_value(12, 0); gpio_free(12); mdelay(100); } bcm2708_i2s_stop(dev, substream, dai); break;
791行目辺り
24bitの所がコメントアウトされていたので外しました。しかし、最新のソースコードだと元々上記のようになってますね。static struct snd_soc_dai_driver bcm2708_i2s_dai = { .name = "bcm2708-i2s", .probe = bcm2708_i2s_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE // : disable for now, it causes white noise with xbmc | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, .capture = { .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, .ops = &bcm2708_i2s_dai_ops, .symmetric_rates = 1 };
sound/soc/codecs/pcm1794a.c
24行目辺り
static struct snd_soc_dai_driver pcm1794a_dai = {
.name = "pcm1794a-hifi",
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE
},
};
一応、SNDRV_PCM_FMTBIT_S32_LEを追加。sound/soc/bcm/rpi-dac.c
45行目辺り
外部クロックを使うように設定しています。static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = { { .name = "HifiBerry Mini", .stream_name = "HifiBerry Mini HiFi", .cpu_dai_name = "bcm2708-i2s.0", .codec_dai_name = "pcm1794a-hifi", .platform_name = "bcm2708-i2s.0", .codec_name = "pcm1794a-codec", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | //SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBM_CFS, .ops = &snd_rpi_rpi_dac_ops, .init = snd_rpi_rpi_dac_init, }, };
あとはドライバーをコンパイルして適当な場所にコピーして組み込めばOK。
sudo insmod snd-soc-bcm2708-i2s.ko
sudo insmod snd-soc-pcm1794a.ko
sudo insmod snd-soc-rpi-dac.ko
MPDで再生してみるとみごと鳴ってくれました。ヽ(´▽`)ノ