Wei Dongshan embedded Linux video tutorial _3 combat phase of the project from the ALSA sound card _ framework of preparation of zero (based Liuzhou excellent FS2410 development board, UDA1341 sound card)

First, to achieve machine-driven framework (s3c2440_uda1341.c)

(Reference sound \ soc \ samsung \ s3c24xx_uda134x.c)

1. Assign a registration platform called soc-audio equipment of

2. The device has a private internet data snd_soc_card, which has a snd_soc_dai_link, is used to determine the drive of each part ASOC

static  struct snd_soc_ops s3c2440_uda1341_ops = {
 // .STARTUP = s3c24xx_uda134x_startup, // transplant from the kernel, these functions temporarily masked, and the like when used together with 
// = s3c24xx_uda134x_shutdown .shutdown, 
// .hw_params = s3c24xx_uda134x_hw_params, 
} ; static struct snd_soc_dai_link s3c2440_uda1341_dai_link = { 
	.name = " 100ask_UDA1341 ", 
	.stream_name = " 100ask_UDA1341 ", 
	.codec_name = " UDA1341-codec ", // must be the same name of the driver and codec 
	.codec_dai_name = " UDA1341-IIS ", // and the name of the driver must codec_dai same 
	.cpu_dai_name = " S3C2440-IIS ", the same // name of the driver must cpu_dai
 
	.ops = &s3c2440_uda1341_ops,
	.platform_name	= "s3c2440-dma",
};
static struct snd_soc_card myalsa_card = {
	.name = "S3C2440_UDA1341",
	.owner = THIS_MODULE,
	.dai_link = &s3c2440_uda1341_dai_link, // snd_soc_dai_link被用来决定ASOC各部分的驱动
	.num_links = 1,
};
static void asoc_release(struct device * dev)
{
}
static struct platform_device asoc_dev = {
    .name         = "soc-audio",
    .id       = -1,
    .dev = {
    	.release = asoc_release,
	}, 
};
static  int s3c2440_uda1341_init ( void ) 
{ 
    platform_set_drvdata (& asoc_dev, & myalsa_card); // This device has a private internet data snd_soc_card 
    platform_device_register (& asoc_dev);     // allocate a register called soc-audio equipment platform 
    return 0; 
}

Second, the realization of the drive frame codec (uda1341.c)

(Reference sound \ soc \ codecs \ uda134x.c)

1. Construct a snd_soc_dai_driver

static  const  struct snd_soc_dai_ops uda1341_dai_ops = {
 // .STARTUP = uda134x_startup, // transplant from the kernel, these functions temporarily masked, and the like when used together with 
// = uda134x_shutdown .shutdown, 
// .hw_params = uda134x_hw_params, 
uda134x_mute .digital_mute = //, 
// .set_sysclk = uda134x_set_dai_sysclk, 
// .set_fmt = uda134x_set_dai_fmt, 
}; static struct snd_soc_dai_driver uda1341_dai = { 
	.name = " UDA1341-IIS ",    // s3c2440_uda1341_dai_link.codec_dai_name must be consistent and machine-driven / * Capabilities playback * / // respective capture and playback attribute values will be used to call such as soc_pcm_open in runtime-> hw.rate_min = max (codec_dai_drv-> playback.rate_min,
 
	
	 cpu_dai_drv->playback.rate_min);
        .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 = &uda1341_dai_ops,
};

2. Construct a snd_soc_codec_driver

static  struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
 // .PROBE = uda134x_soc_probe, // transplant from the kernel, these functions temporarily masked, and the like when used together with 
// = uda134x_soc_remove .remove, 
// .suspend = uda134x_soc_suspend, 
// = uda134x_soc_resume .resume, 
// = .reg_cache_size the sizeof (uda134x_reg), 
// = .reg_word_size the sizeof (U8), 
// .reg_cache_default = uda134x_reg, 
// = .reg_cache_step. 1, 
// = uda134x_read_reg_cache .read, 
// .write uda134x_write =, 
// .set_bias_level = uda134x_set_bias_level, 
};

3. register them (a little trick: because snd_soc_register_codec need to pass device parameters can not be called directly in uda1341_init () in snd_soc_register_codec, and more so around a bend, by registering platform_device, platform_driver, in its probe () function call snd_soc_register_codec)

static  struct platform_device uda1341_dev = { 
    .name = " UDA1341-CODEC ", // and the machine must be driven s3c2440_uda1341_dai_link.codec_name consistent 
    .id = -1, 
    .dev = { 
    	.release = uda1341_dev_release, 
	}, 
}; struct platform_driver uda1341_drv = { 
	= uda1341_probe .PROBE, // snd_soc_register_codec calls registered in it and drive codec_dai codec driver 
	. Remove 		= uda1341_remove, 
	.driver = { 
	.name = " UDA1341-codec ", // must be the same name uda1341_dev 
	} 
}; static int uda1341_init ( void 
{

  )
    platform_device_register(&uda1341_dev);
    platform_driver_register(&uda1341_drv);
    return 0;
}
static void uda1341_exit(void)
{
    platform_device_unregister(&uda1341_dev);
    platform_driver_unregister(&uda1341_drv);
}
module_init(uda1341_init);
module_exit(uda1341_exit);
MODULE_LICENSE("GPL");

Third, to achieve cpu_dai driven framework (s3c2440_iis.c)

(Reference sound \ soc \ samsung \ s3c24xx-i2s.c)

static  const  struct snd_soc_dai_ops s3c2440_i2s_dai_ops = {
 //.trigger = s3c24xx_i2s_trigger, // transplant from the kernel, these functions temporarily masked, and the like when used together with 
// = s3c24xx_i2s_hw_params .hw_params, 
// .set_fmt = s3c24xx_i2s_set_fmt, 
s3c24xx_i2s_set_clkdiv .set_clkdiv = //, 
// .set_sysclk = s3c24xx_i2s_set_syscl 
}; 

#define S3C24XX_I2S_RATES \ 
	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 
	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 
	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) static struct snd_soc_dai_driver s3c2440_i2s_dai = {

 // no name, in fact, name copy snd_soc_register_dai () will s3c2440_iis_dev in to dai-> name 
// .PROBE = s3c24xx_i2s_probe, // from the kernel transplant, temporarily block out the functions, such as when used together
//	.suspend = s3c24xx_i2s_suspend,
//	.resume = s3c24xx_i2s_resum
	.playback = {
		.channels_min = 2,
		.channels_max = 2,
		.rates = S3C24XX_I2S_RATES,
		.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
	.capture = {
		.channels_min = 2,
		.channels_max = 2,
		.rates = S3C24XX_I2S_RATES,
		.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
	.ops = &s3c2440_i2s_dai_ops,
};

2. Sign it

static int s3c2440_iis_probe(struct platform_device *pdev)
{
    return snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);
}
static int s3c2440_iis_remove(struct platform_device *pdev)
{
    snd_soc_unregister_dai(&pdev->dev);
    return 0;
}
static void s3c2440_iis_release(struct device * dev)
{
}
static struct platform_device s3c2440_iis_dev = {
    .name         = "s3c2440-iis", //必须和machine驱动的s3c2440_uda1341_dai_link.cpu_dai_name一致
    .id       = -1,
    .dev = {
    	.release = s3c2440_iis_release,
	},
};
struct platform_driver s3c2440_iis_drv = {
	.probe		= s3c2440_iis_probe,
	.remove		= s3c2440_iis_remove,
	.driver		= {
	    .name	= "s3c2440-iis", //必须和s3c2440_iis_dev的name一致
	}
};
static int s3c2440_iis_init(void)
{
    platform_device_register(&s3c2440_iis_dev);
    platform_driver_register(&s3c2440_iis_drv);
    return 0;
}

static void s3c2440_iis_exit(void)
{
    struct clk *clk;
    platform_device_unregister(&s3c2440_iis_dev);
    platform_driver_unregister(&s3c2440_iis_drv);
}
static void s3c2440_iis_exit(void)
{
    platform_device_unregister(&s3c2440_iis_dev);
    platform_driver_unregister(&s3c2440_iis_drv);
}
module_init(s3c2440_iis_init);
module_exit(s3c2440_iis_exit);
MODULE_LICENSE("GPL");

Attaining driven platform frame (s3c2440_dma.c)

( Reference sound \ soc \ samsung \ dma.c)

1. Construct a snd_soc_platform_driver

static  struct snd_pcm_ops dma_ops = {
 // .Open = dma_open, // transplant from the kernel, these functions temporarily masked, and the like when used together with 
// = .close dma_close, 
// .ioctl = snd_pcm_lib_ioctl, 
/ / = dma_hw_params .hw_params, 
// .hw_free = dma_hw_free, 
// = the .Prepare dma_prepare, 
// = .trigger dma_trigger, 
// .pointer = dma_pointer, 
// .mmap = dma_mmap, 
}; static struct snd_soc_platform_driver s3c2440_dma_platform = { 
	. = & s3c2440_dma_ops OPS, // .pcm_new = dma_new, // transplant from the kernel, these functions temporarily masked, and the like when used together with // = dma_free_dma_buffer .pcm_free 
};
 
	

2. Sign it
static int s3c2440_dma_probe(struct platform_device *pdev)
{
    return snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);
}
static int s3c2440_dma_remove(struct platform_device *pdev)
{
    snd_soc_unregister_platform(&pdev->dev);
    return 0;
}
static void s3c2440_dma_release(struct device * dev)
{
}
static struct platform_device s3c2440_dma_dev = {
    .name         = "s3c2440-dma",  // and the machine must be driven s3c2440_uda1341_dai_link platform_name consistent 
    .id = -1, 
    .dev = { 
    	.release = s3c2440_dma_release, 
	}, 
}; struct platform_driver s3c2440_dma_drv = { 
	.PROBE = s3c2440_dma_probe, 
	. Remove 		= s3c2440_dma_remove, 
	.driver = { 
	    . = name " S3C2440-DMA ", // must be the same name s3c2440_dma_dev 
	} 
}; static int s3c2440_dma_init ( void ) 
{ 
    dma_regs = ioremap (DMA2_BASE_ADDR, the sizeof ( struct s3c_dma_regs));

  
    platform_device_register (& s3c2440_dma_dev);
    platform_driver_register(&s3c2440_dma_drv);
    return 0;
}
static void s3c2440_dma_exit(void)
{
    platform_device_unregister(&s3c2440_dma_dev);
    platform_driver_unregister(&s3c2440_dma_drv);
    iounmap(dma_regs);
}
module_init(s3c2440_dma_init);
module_exit(s3c2440_dma_exit);
MODULE_LICENSE("GPL");

V. References

Framework Lesson 2 1.1_17 _ALSA sound 08_ write it from scratch: 1. Wei Dongshan embedded Linux video tutorial _3 of the project combat the ALSA sound card

2. DroidPhone "Linux ALSA sound drivers."

Guess you like

Origin www.cnblogs.com/normalmanzhao2003/p/12326438.html