📄 s3c24xx-uda1341.c
字号:
if ( stream_id == SNDRV_PCM_STREAM_PLAYBACK )
{
// FIXME it must be located here?
init_s3c2410_iis_bus_tx();
}
else
{
// FIXME it must be located here?
init_s3c2410_iis_bus_rx();
}
/* Set requested samplerate */
s3c24xx_uda1341_set_samplerate( chip, runtime -> rate );
s -> period = 0;
s -> periods = 0;
return 0;
}
static snd_pcm_uframes_t snd_s3c24xx_uda1341_pointer( struct snd_pcm_substream *substream )
{
struct s3c24xx_uda1341 *chip = snd_pcm_substream_chip( substream );
struct audio_stream *s = &chip -> s[ substream -> pstr -> stream ];
dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_pointer() start...\n" );
return audio_get_dma_pos( s );
}
static int snd_s3c24xx_uda1341_trigger( struct snd_pcm_substream *substream, int cmd )
{
struct s3c24xx_uda1341 *chip = snd_pcm_substream_chip( substream );
int stream_id = substream -> pstr -> stream;
struct audio_stream *s = &chip -> s[ stream_id ];
struct audio_stream *s1 = &chip -> s[ stream_id ^ 1 ];
int err = 0;
spin_lock( &s -> dma_lock );
switch ( cmd )
{
case SNDRV_PCM_TRIGGER_START:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_START...\n" );
if ( stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1 -> active )
{
s1 -> tx_spin = 1;
audio_process_dma( s1 );
}
else
{
s -> tx_spin = 0;
}
s -> active = 1;
audio_process_dma( s );
break;
case SNDRV_PCM_TRIGGER_STOP:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_STOP...\n" );
s -> active = 0;
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );
if ( stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1 -> active )
{
s -> tx_spin = 1;
audio_process_dma( s );
}
else
{
if ( s1 -> tx_spin )
{
s1 -> tx_spin = 0;
s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_STOP );
s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_FLUSH );
}
}
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_SUSPEND...\n" );
s -> active = 0;
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );
s -> periods = 0;
break;
case SNDRV_PCM_TRIGGER_RESUME:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_RESUME...\n" );
s -> active = 1;
s -> tx_spin = 0;
audio_process_dma( s );
if ( stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1 -> active )
{
s1 -> tx_spin = 1;
audio_process_dma( s1 );
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH...\n" );
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );
s -> active = 0;
if ( stream_id == SNDRV_PCM_STREAM_PLAYBACK )
{
if ( s1 -> active )
{
s -> tx_spin = 1;
s -> old_offset = audio_get_dma_pos( s ) + 1;
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );
audio_process_dma( s );
}
}
else
{
if ( s1 -> tx_spin )
{
s1 -> tx_spin = 0;
s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_FLUSH );
}
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_PAUSE_RELEASE...\n" );
s -> active = 1;
if ( s -> old_offset )
{
s -> tx_spin = 0;
audio_process_dma( s );
break;
}
if ( stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1 -> active )
{
s1 -> tx_spin = 1;
audio_process_dma( s1 );
}
s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_START );
break;
default:
err = -EINVAL;
break;
}
spin_unlock( &s -> dma_lock );
return err;
}
static int snd_s3c24xx_uda1341_mmap( struct snd_pcm_substream *substream, struct vm_area_struct *vma )
{
struct snd_pcm_runtime *runtime = substream -> runtime;
return dma_mmap_coherent( substream -> pcm -> card -> dev, vma, runtime -> dma_area, runtime -> dma_addr, runtime -> dma_bytes );
}
/*
* PCM operations
*/
static struct snd_pcm_ops snd_card_s3c24xx_uda1341_playback_ops = {
.open = snd_card_s3c24xx_uda1341_open,
.close = snd_card_s3c24xx_uda1341_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_s3c24xx_uda1341_hw_params,
.hw_free = snd_s3c24xx_uda1341_hw_free,
.prepare = snd_s3c24xx_uda1341_prepare,
.trigger = snd_s3c24xx_uda1341_trigger,
.pointer = snd_s3c24xx_uda1341_pointer,
.mmap = snd_s3c24xx_uda1341_mmap,
};
static struct snd_pcm_ops snd_card_s3c24xx_uda1341_capture_ops = {
.open = snd_card_s3c24xx_uda1341_open,
.close = snd_card_s3c24xx_uda1341_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_s3c24xx_uda1341_hw_params,
.hw_free = snd_s3c24xx_uda1341_hw_free,
.prepare = snd_s3c24xx_uda1341_prepare,
.trigger = snd_s3c24xx_uda1341_trigger,
.pointer = snd_s3c24xx_uda1341_pointer,
.mmap = snd_s3c24xx_uda1341_mmap,
};
static int __devinit snd_card_s3c24xx_uda1341_pcm( struct snd_card *card, struct s3c24xx_uda1341 *chip, int device )
{
struct snd_pcm *pcm;
int err;
audio_stream_t *input_stream, *output_stream;
if ( ( err = snd_pcm_new( card, "UDA1341 PCM", device, 1, 1, &pcm ) ) < 0 )
{
return err;
}
/*
* I'm not sure whether it's the right choice to set the dma_type to isa.
* but is actually works
*/
snd_pcm_lib_preallocate_pages_for_all( pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), 64 * 1024, 64 * 1024 );
snd_pcm_set_ops( pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_s3c24xx_uda1341_playback_ops );
snd_pcm_set_ops( pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_s3c24xx_uda1341_capture_ops );
pcm -> private_data = chip;
pcm -> info_flags = 0;
strcpy( pcm -> name, "UDA1341 PCM" );
/*
* Setup DMA controller
*/
output_stream = &chip -> s[ SNDRV_PCM_STREAM_PLAYBACK ];
output_stream -> id = "UDA1341 OUT";
output_stream -> stream_id = SNDRV_PCM_STREAM_PLAYBACK;
output_stream -> dma_ch = DMA_CH2;
if ( !audio_init_dma ( output_stream, "UDA1341 out" ) )
{
audio_clear_dma ( output_stream, &s3c24xxiis_dma_client_out );
dbg ( dbg_err, AUDIO_NAME_VERBOSE
": unable to get DMA channels\n" );
return -EBUSY;
}
input_stream = &chip -> s[ SNDRV_PCM_STREAM_CAPTURE ];
input_stream -> id = "UDA1341 IN";
input_stream -> stream_id = SNDRV_PCM_STREAM_CAPTURE;
input_stream -> dma_ch = DMA_CH1;
if ( !audio_init_dma ( input_stream, "UDA1341 in" ) )
{
audio_clear_dma ( input_stream, &s3c24xxiis_dma_client_in );
dbg ( dbg_err, AUDIO_NAME_VERBOSE
": unable to get DMA channels\n" );
return -EBUSY;
}
chip -> pcm = pcm;
return 0;
}
void snd_s3c24xx_uda1341_free( struct snd_card *card )
{
struct s3c24xx_uda1341 *chip = card -> private_data;
audio_clear_dma( &chip -> s[ SNDRV_PCM_STREAM_PLAYBACK ], &s3c24xxiis_dma_client_out );
audio_clear_dma( &chip -> s[ SNDRV_PCM_STREAM_CAPTURE ], &s3c24xxiis_dma_client_in );
}
static int __devinit s3c24xxiis_probe ( struct platform_device *pdev )
{
struct snd_card *card;
struct s3c24xx_uda1341 *chip;
int ret;
dbg ( dbg_debug, "s3c24xxiis_probe...\n" );
res = platform_get_resource ( pdev, IORESOURCE_MEM, 0 );
if ( res == NULL )
{
dbg ( dbg_err, PFX "failed to get memory region resouce\n" );
ret = -ENOENT;
goto probe_out;
}
res = request_mem_region( res->start, RESSIZE( res ), pdev->name );
if ( res == 0 )
{
dbg ( dbg_err, PFX "failed to request io memory region resouce\n" );
ret = -ENOENT;
goto probe_out;
}
iis_base = ioremap( res->start, RESSIZE( res ) );
if ( iis_base == 0 )
{
dbg ( dbg_err, PFX "failed to ioremap() io memory region\n" );
ret = -ENOENT;
goto probe_free_mem_region;
}
iis_clock = clk_get ( &pdev->dev, "iis" );
if ( iis_clock == NULL )
{
dbg ( dbg_err, PFX "failed to find clock source\n" );
ret = -EINVAL;
goto probe_iounmap;
}
clk_enable ( iis_clock );
/*
* The Initialization of resouce and clock has been ended
* Now it is the snd's turn
*/
/*
* Register the soundcard
*/
card = snd_card_new( -1, id, THIS_MODULE, sizeof( struct s3c24xx_uda1341 ) );
if ( card == NULL )
{
dbg( dbg_err, PFX "failed to allocate sound card\n" );
ret = -ENOMEM;
goto probe_clk_free;
}
chip = card -> private_data;
spin_lock_init( &chip -> s[ 0 ].dma_lock );
spin_lock_init( &chip -> s[ 1 ].dma_lock );
card -> private_free = snd_s3c24xx_uda1341_free;
chip -> card = card;
chip -> samplerate = AUDIO_RATE_DEFAULT;
/*
* Initialize soundcard hardware information
*/
if ( ( ret = snd_card_s3c24xx_uda1341_init( card, pdev, chip ) ) < 0 )
{
dbg( dbg_err, PFX "failed to initialize hardware\n" );
goto probe_snd_free;
}
// mixer
if ( ( ret = snd_chip_uda1341_mixer_new( card, chip ) ) < 0 )
{
dbg( dbg_err, PFX "failed to register mixer device\n" );
goto probe_snd_free;
}
// PCM
if ( ( ret = snd_card_s3c24xx_uda1341_pcm( card, chip, 0 ) ) < 0 )
{
dbg( dbg_err, PFX "failed to register PCM device\n" );
goto probe_snd_free;
}
// todo sigh! complicated!
#ifdef CONFIG_PROC_FS
snd_chip_uda1341_proc_init( card, chip );
#endif /*CONFIG_PROC_FS*/
strcpy( card -> driver, "UDA1341" );
strcpy( card -> shortname, "S3C24XX UDA1341" );
strcpy( card -> longname, "SAMSUNG S3C24XX with Philips UDA1341TS" );
/*
* Register sound card
*/
if ( ( ret = snd_card_register( card ) ) != 0 )
{
dbg( dbg_err, PFX "faled to register sound card\n" );
goto probe_snd_free;
}
platform_set_drvdata( pdev, card );
dbg ( dbg_info, AUDIO_NAME_VERBOSE " initialized\n" );
return 0;
probe_snd_free:
snd_card_free( card );
probe_clk_free:
clk_disable( iis_clock );
clk_put( iis_clock );
probe_iounmap:
iounmap( iis_base );
probe_free_mem_region:
release_mem_region( res->start, RESSIZE( res ) );
probe_out:
return ret;
}
static int __devexit s3c24xxiis_remove ( struct platform_device *pdev )
{
//free snd_card
snd_card_free( platform_get_drvdata( pdev ) );
platform_set_drvdata( pdev, NULL );
clk_disable ( iis_clock);
clk_put ( iis_clock );
iounmap ( iis_base );
release_mem_region( res->start, RESSIZE( res ) );
kfree( res );
dbg ( dbg_info, AUDIO_NAME_VERBOSE " unloaded\n" );
return 0;
}
static struct platform_driver s3c24xxiis_driver =
{
.probe = s3c24xxiis_probe,
.remove = s3c24xxiis_remove,
.driver =
{
.name = "s3c2410-iis", /* match the resource name in arch/arm/plat-s3c24xx/devs.c */
.owner = THIS_MODULE,
},
};
static int __init s3c24xx_uda1341_init( void )
{
return platform_driver_register( &s3c24xxiis_driver );
}
static void __exit s3c24xx_uda1341_exit( void )
{
return platform_driver_unregister( &s3c24xxiis_driver );
}
module_init ( s3c24xx_uda1341_init );
module_exit ( s3c24xx_uda1341_exit );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -