2010-03-11 18:32:42 +03:00
/*
* ALSA SoC Voice Codec Interface for TI DAVINCI processor
*
* Copyright ( C ) 2010 Texas Instruments .
*
* Author : Miguel Aguilar < miguel . aguilar @ ridgerun . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/delay.h>
2010-03-29 21:52:29 +04:00
# include <linux/slab.h>
2010-03-11 18:32:42 +03:00
# include <linux/io.h>
# include <linux/mfd/davinci_voicecodec.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/initval.h>
# include <sound/soc.h>
# include "davinci-pcm.h"
# include "davinci-i2s.h"
# define MOD_REG_BIT(val, mask, set) do { \
if ( set ) { \
val | = mask ; \
} else { \
val & = ~ mask ; \
} \
} while ( 0 )
struct davinci_vcif_dev {
struct davinci_vc * davinci_vc ;
struct davinci_pcm_dma_params dma_params [ 2 ] ;
} ;
static void davinci_vcif_start ( struct snd_pcm_substream * substream )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct davinci_vcif_dev * davinci_vcif_dev =
2010-03-17 23:15:21 +03:00
snd_soc_dai_get_drvdata ( rtd - > cpu_dai ) ;
2010-03-11 18:32:42 +03:00
struct davinci_vc * davinci_vc = davinci_vcif_dev - > davinci_vc ;
u32 w ;
/* Start the sample generator and enable transmitter/receiver */
w = readl ( davinci_vc - > base + DAVINCI_VC_CTRL ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2011-07-20 16:06:04 +04:00
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RSTDAC , 0 ) ;
2010-03-11 18:32:42 +03:00
else
2011-07-20 16:06:04 +04:00
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RSTADC , 0 ) ;
2010-03-11 18:32:42 +03:00
writel ( w , davinci_vc - > base + DAVINCI_VC_CTRL ) ;
}
static void davinci_vcif_stop ( struct snd_pcm_substream * substream )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct davinci_vcif_dev * davinci_vcif_dev =
2010-03-17 23:15:21 +03:00
snd_soc_dai_get_drvdata ( rtd - > cpu_dai ) ;
2010-03-11 18:32:42 +03:00
struct davinci_vc * davinci_vc = davinci_vcif_dev - > davinci_vc ;
u32 w ;
/* Reset transmitter/receiver and sample rate/frame sync generators */
w = readl ( davinci_vc - > base + DAVINCI_VC_CTRL ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2011-07-20 16:06:04 +04:00
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RSTDAC , 1 ) ;
2010-03-11 18:32:42 +03:00
else
2011-07-20 16:06:04 +04:00
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RSTADC , 1 ) ;
2010-03-11 18:32:42 +03:00
writel ( w , davinci_vc - > base + DAVINCI_VC_CTRL ) ;
}
static int davinci_vcif_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2010-03-17 23:15:21 +03:00
struct davinci_vcif_dev * davinci_vcif_dev = snd_soc_dai_get_drvdata ( dai ) ;
2010-03-11 18:32:42 +03:00
struct davinci_vc * davinci_vc = davinci_vcif_dev - > davinci_vc ;
struct davinci_pcm_dma_params * dma_params =
& davinci_vcif_dev - > dma_params [ substream - > stream ] ;
u32 w ;
/* Restart the codec before setup */
davinci_vcif_stop ( substream ) ;
davinci_vcif_start ( substream ) ;
/* General line settings */
writel ( DAVINCI_VC_CTRL_MASK , davinci_vc - > base + DAVINCI_VC_CTRL ) ;
writel ( DAVINCI_VC_INT_MASK , davinci_vc - > base + DAVINCI_VC_INTCLR ) ;
writel ( DAVINCI_VC_INT_MASK , davinci_vc - > base + DAVINCI_VC_INTEN ) ;
w = readl ( davinci_vc - > base + DAVINCI_VC_CTRL ) ;
/* Determine xfer data type */
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_U8 :
dma_params - > data_type = 0 ;
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RD_BITS_8 |
DAVINCI_VC_CTRL_RD_UNSIGNED |
DAVINCI_VC_CTRL_WD_BITS_8 |
DAVINCI_VC_CTRL_WD_UNSIGNED , 1 ) ;
break ;
case SNDRV_PCM_FORMAT_S8 :
dma_params - > data_type = 1 ;
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RD_BITS_8 |
DAVINCI_VC_CTRL_WD_BITS_8 , 1 ) ;
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RD_UNSIGNED |
DAVINCI_VC_CTRL_WD_UNSIGNED , 0 ) ;
break ;
case SNDRV_PCM_FORMAT_S16_LE :
dma_params - > data_type = 2 ;
MOD_REG_BIT ( w , DAVINCI_VC_CTRL_RD_BITS_8 |
DAVINCI_VC_CTRL_RD_UNSIGNED |
DAVINCI_VC_CTRL_WD_BITS_8 |
DAVINCI_VC_CTRL_WD_UNSIGNED , 0 ) ;
break ;
default :
printk ( KERN_WARNING " davinci-vcif: unsupported PCM format " ) ;
return - EINVAL ;
}
dma_params - > acnt = dma_params - > data_type ;
writel ( w , davinci_vc - > base + DAVINCI_VC_CTRL ) ;
return 0 ;
}
static int davinci_vcif_trigger ( struct snd_pcm_substream * substream , int cmd ,
struct snd_soc_dai * dai )
{
int ret = 0 ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
davinci_vcif_start ( substream ) ;
2011-07-20 16:07:18 +04:00
break ;
2010-03-11 18:32:42 +03:00
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
davinci_vcif_stop ( substream ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
ASoC: davinci: fixes for multi-component
Multi-component commit f0fba2ad broke a few things which this patch should
fix. Tested on the DM355 EVM. I've been as careful as I can, but it would be
good if those with access to other Davinci boards could test.
--
The multi-component commit put the initialisation of
snd_soc_dai.[capture|playback]_dma_data into snd_soc_dai_ops.hw_params of the
McBSP, McASP & VCIF drivers (davinci-i2s.c, davinci-mcasp.c & davinci-vcif.c).
The initialisation had to be moved from the probe function in these drivers
because davinci_*_dai changed from snd_soc_dai to snd_soc_dai_driver.
Unfortunately, the DMA params pointer is needed by davinci_pcm_open (in
davinci-pcm.c) before hw_params is called. I have moved the initialisation to
a new snd_soc_dai_ops.startup function in each of these drivers. This fix
indicates that all platforms that use davinci-pcm must have been broken and
need to test with this fix.
--
The multi-component commit also changed the McBSP driver name from
"davinci-asp" to "davinci-i2s" in davinci-i2s.c without updating the board
level references to the driver name. This change is understandable, as there
is a similarly named "davinci-mcasp" driver in davinci-mcasp.c.
There is probably no 'correct' name for this driver. The DM6446 datasheet
calls it the "ASP" and describes it as a "specialised McBSP". The DM355
datasheet calls it the "ASP" and describes it as a "specialised ASP". The
DM365 datasheet calls it the "McBSP". Rather than fix this problem by
reverting to "davinci-asp", I've elected to avoid future confusion with the
"davinci-mcasp" driver by changing it to "davinci-mcbsp", which is also
consistent with the names of the functions in the driver. There are other
fixes required, so it was never going to be as simple as a revert anyway.
--
The DM365 only has one McBSP port (of the McBSP platforms, only the DM355 has
2 ports), so I've changed the the id of the platform_device from 0 to -1.
--
In davinci-evm.c, the DM6446 EVM can no longer share a snd_soc_dai_link
structure with the DM355 EVM as they use different cpu DAI names (the DM355
has 2 ports and the EVM uses the second port, but the DM6446 only has 1 port).
This also means that the 2 boards need different snd_soc_card structures.
--
The codec_name entries in davinci-evm.c didn't match the i2c ids in the board
files. I have only checked and fixed the details of the names used for the
McBSP based platforms. Someone with a McASP based platform (eg DA8xx) should
check the others.
Signed-off-by: Chris Paulson-Ellis <chris@edesix.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
2010-11-16 15:27:09 +03:00
static int davinci_vcif_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct davinci_vcif_dev * dev = snd_soc_dai_get_drvdata ( dai ) ;
snd_soc_dai_set_dma_data ( dai , substream , dev - > dma_params ) ;
return 0 ;
}
2010-03-11 18:32:42 +03:00
# define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000
2011-11-23 14:40:40 +04:00
static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
ASoC: davinci: fixes for multi-component
Multi-component commit f0fba2ad broke a few things which this patch should
fix. Tested on the DM355 EVM. I've been as careful as I can, but it would be
good if those with access to other Davinci boards could test.
--
The multi-component commit put the initialisation of
snd_soc_dai.[capture|playback]_dma_data into snd_soc_dai_ops.hw_params of the
McBSP, McASP & VCIF drivers (davinci-i2s.c, davinci-mcasp.c & davinci-vcif.c).
The initialisation had to be moved from the probe function in these drivers
because davinci_*_dai changed from snd_soc_dai to snd_soc_dai_driver.
Unfortunately, the DMA params pointer is needed by davinci_pcm_open (in
davinci-pcm.c) before hw_params is called. I have moved the initialisation to
a new snd_soc_dai_ops.startup function in each of these drivers. This fix
indicates that all platforms that use davinci-pcm must have been broken and
need to test with this fix.
--
The multi-component commit also changed the McBSP driver name from
"davinci-asp" to "davinci-i2s" in davinci-i2s.c without updating the board
level references to the driver name. This change is understandable, as there
is a similarly named "davinci-mcasp" driver in davinci-mcasp.c.
There is probably no 'correct' name for this driver. The DM6446 datasheet
calls it the "ASP" and describes it as a "specialised McBSP". The DM355
datasheet calls it the "ASP" and describes it as a "specialised ASP". The
DM365 datasheet calls it the "McBSP". Rather than fix this problem by
reverting to "davinci-asp", I've elected to avoid future confusion with the
"davinci-mcasp" driver by changing it to "davinci-mcbsp", which is also
consistent with the names of the functions in the driver. There are other
fixes required, so it was never going to be as simple as a revert anyway.
--
The DM365 only has one McBSP port (of the McBSP platforms, only the DM355 has
2 ports), so I've changed the the id of the platform_device from 0 to -1.
--
In davinci-evm.c, the DM6446 EVM can no longer share a snd_soc_dai_link
structure with the DM355 EVM as they use different cpu DAI names (the DM355
has 2 ports and the EVM uses the second port, but the DM6446 only has 1 port).
This also means that the 2 boards need different snd_soc_card structures.
--
The codec_name entries in davinci-evm.c didn't match the i2c ids in the board
files. I have only checked and fixed the details of the names used for the
McBSP based platforms. Someone with a McASP based platform (eg DA8xx) should
check the others.
Signed-off-by: Chris Paulson-Ellis <chris@edesix.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
2010-11-16 15:27:09 +03:00
. startup = davinci_vcif_startup ,
2010-03-11 18:32:42 +03:00
. trigger = davinci_vcif_trigger ,
. hw_params = davinci_vcif_hw_params ,
} ;
2010-03-17 23:15:21 +03:00
static struct snd_soc_dai_driver davinci_vcif_dai = {
2010-03-11 18:32:42 +03:00
. playback = {
. channels_min = 1 ,
. channels_max = 2 ,
. rates = DAVINCI_VCIF_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
. capture = {
. channels_min = 1 ,
. channels_max = 2 ,
. rates = DAVINCI_VCIF_RATES ,
. formats = SNDRV_PCM_FMTBIT_S16_LE , } ,
. ops = & davinci_vcif_dai_ops ,
} ;
static int davinci_vcif_probe ( struct platform_device * pdev )
{
2011-04-06 18:39:45 +04:00
struct davinci_vc * davinci_vc = pdev - > dev . platform_data ;
2010-03-11 18:32:42 +03:00
struct davinci_vcif_dev * davinci_vcif_dev ;
int ret ;
davinci_vcif_dev = kzalloc ( sizeof ( struct davinci_vcif_dev ) , GFP_KERNEL ) ;
2010-07-16 20:16:17 +04:00
if ( ! davinci_vcif_dev ) {
2010-03-11 18:32:42 +03:00
dev_dbg ( & pdev - > dev ,
" could not allocate memory for private data \n " ) ;
return - ENOMEM ;
}
/* DMA tx params */
davinci_vcif_dev - > davinci_vc = davinci_vc ;
davinci_vcif_dev - > dma_params [ SNDRV_PCM_STREAM_PLAYBACK ] . channel =
davinci_vc - > davinci_vcif . dma_tx_channel ;
davinci_vcif_dev - > dma_params [ SNDRV_PCM_STREAM_PLAYBACK ] . dma_addr =
davinci_vc - > davinci_vcif . dma_tx_addr ;
/* DMA rx params */
davinci_vcif_dev - > dma_params [ SNDRV_PCM_STREAM_CAPTURE ] . channel =
davinci_vc - > davinci_vcif . dma_rx_channel ;
davinci_vcif_dev - > dma_params [ SNDRV_PCM_STREAM_CAPTURE ] . dma_addr =
davinci_vc - > davinci_vcif . dma_rx_addr ;
2010-03-17 23:15:21 +03:00
dev_set_drvdata ( & pdev - > dev , davinci_vcif_dev ) ;
2010-03-11 18:32:42 +03:00
2010-03-17 23:15:21 +03:00
ret = snd_soc_register_dai ( & pdev - > dev , & davinci_vcif_dai ) ;
2010-03-11 18:32:42 +03:00
if ( ret ! = 0 ) {
dev_err ( & pdev - > dev , " could not register dai \n " ) ;
goto fail ;
}
return 0 ;
fail :
kfree ( davinci_vcif_dev ) ;
return ret ;
}
static int davinci_vcif_remove ( struct platform_device * pdev )
{
2010-11-25 06:33:14 +03:00
struct davinci_vcif_dev * davinci_vcif_dev = dev_get_drvdata ( & pdev - > dev ) ;
2010-03-17 23:15:21 +03:00
snd_soc_unregister_dai ( & pdev - > dev ) ;
2010-11-25 06:33:14 +03:00
kfree ( davinci_vcif_dev ) ;
2010-03-11 18:32:42 +03:00
return 0 ;
}
static struct platform_driver davinci_vcif_driver = {
. probe = davinci_vcif_probe ,
. remove = davinci_vcif_remove ,
. driver = {
2010-03-17 23:15:21 +03:00
. name = " davinci-vcif " ,
2010-03-11 18:32:42 +03:00
. owner = THIS_MODULE ,
} ,
} ;
2011-11-25 06:09:27 +04:00
module_platform_driver ( davinci_vcif_driver ) ;
2010-03-11 18:32:42 +03:00
MODULE_AUTHOR ( " Miguel Aguilar " ) ;
MODULE_DESCRIPTION ( " Texas Instruments DaVinci ASoC Voice Codec Interface " ) ;
MODULE_LICENSE ( " GPL " ) ;