2011-05-18 19:25:10 +04:00
/*
* SoC audio for HP iPAQ hx4700
*
* Copyright ( c ) 2009 Philipp Zabel
*
* 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 .
*
*/
# include <linux/module.h>
# include <linux/timer.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/delay.h>
# include <linux/gpio.h>
# include <sound/core.h>
# include <sound/jack.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <mach/hx4700.h>
# include <asm/mach-types.h>
# include "pxa2xx-i2s.h"
# include "../codecs/ak4641.h"
static struct snd_soc_jack hs_jack ;
/* Headphones jack detection DAPM pin */
static struct snd_soc_jack_pin hs_jack_pin [ ] = {
{
. pin = " Headphone Jack " ,
. mask = SND_JACK_HEADPHONE ,
} ,
{
. pin = " Speaker " ,
/* disable speaker when hp jack is inserted */
. mask = SND_JACK_HEADPHONE ,
. invert = 1 ,
} ,
} ;
/* Headphones jack detection GPIO */
static struct snd_soc_jack_gpio hs_jack_gpio = {
. gpio = GPIO75_HX4700_EARPHONE_nDET ,
. invert = true ,
. name = " hp-gpio " ,
. report = SND_JACK_HEADPHONE ,
. debounce_time = 200 ,
} ;
/*
* iPAQ hx4700 uses I2S for capture and playback .
*/
static int hx4700_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct snd_soc_dai * codec_dai = rtd - > codec_dai ;
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
int ret = 0 ;
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt ( codec_dai ,
SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ) ;
if ( ret < 0 )
return ret ;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt ( cpu_dai ,
SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ) ;
if ( ret < 0 )
return ret ;
/* set the I2S system clock as output */
ret = snd_soc_dai_set_sysclk ( cpu_dai , PXA2XX_I2S_SYSCLK , 0 ,
SND_SOC_CLOCK_OUT ) ;
if ( ret < 0 )
return ret ;
/* inform codec driver about clock freq *
* ( PXA I2S always uses divider 256 ) */
ret = snd_soc_dai_set_sysclk ( codec_dai , 0 , 256 * params_rate ( params ) ,
SND_SOC_CLOCK_IN ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
static struct snd_soc_ops hx4700_ops = {
. hw_params = hx4700_hw_params ,
} ;
static int hx4700_spk_power ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
gpio_set_value ( GPIO107_HX4700_SPK_nSD , ! ! SND_SOC_DAPM_EVENT_ON ( event ) ) ;
return 0 ;
}
static int hx4700_hp_power ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
gpio_set_value ( GPIO92_HX4700_HP_DRIVER , ! ! SND_SOC_DAPM_EVENT_ON ( event ) ) ;
return 0 ;
}
/* hx4700 machine dapm widgets */
static const struct snd_soc_dapm_widget hx4700_dapm_widgets [ ] = {
SND_SOC_DAPM_HP ( " Headphone Jack " , hx4700_hp_power ) ,
SND_SOC_DAPM_SPK ( " Speaker " , hx4700_spk_power ) ,
SND_SOC_DAPM_MIC ( " Built-in Microphone " , NULL ) ,
} ;
/* hx4700 machine audio_map */
static const struct snd_soc_dapm_route hx4700_audio_map [ ] = {
/* Headphone connected to LOUT, ROUT */
{ " Headphone Jack " , NULL , " LOUT " } ,
{ " Headphone Jack " , NULL , " ROUT " } ,
/* Speaker connected to MOUT2 */
{ " Speaker " , NULL , " MOUT2 " } ,
/* Microphone connected to MICIN */
{ " MICIN " , NULL , " Built-in Microphone " } ,
{ " AIN " , NULL , " MICOUT " } ,
} ;
/*
* Logic for a ak4641 as connected on a HP iPAQ hx4700
*/
static int hx4700_ak4641_init ( struct snd_soc_pcm_runtime * rtd )
{
struct snd_soc_codec * codec = rtd - > codec ;
struct snd_soc_dapm_context * dapm = & codec - > dapm ;
int err ;
/* NC codec pins */
/* FIXME: is anything connected here? */
snd_soc_dapm_nc_pin ( dapm , " MOUT1 " ) ;
snd_soc_dapm_nc_pin ( dapm , " MICEXT " ) ;
snd_soc_dapm_nc_pin ( dapm , " AUX " ) ;
/* Jack detection API stuff */
err = snd_soc_jack_new ( codec , " Headphone Jack " ,
SND_JACK_HEADPHONE , & hs_jack ) ;
if ( err )
return err ;
err = snd_soc_jack_add_pins ( & hs_jack , ARRAY_SIZE ( hs_jack_pin ) ,
hs_jack_pin ) ;
if ( err )
return err ;
err = snd_soc_jack_add_gpios ( & hs_jack , 1 , & hs_jack_gpio ) ;
return err ;
}
/* hx4700 digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link hx4700_dai = {
. name = " ak4641 " ,
. stream_name = " AK4641 " ,
. cpu_dai_name = " pxa2xx-i2s " ,
. codec_dai_name = " ak4641-hifi " ,
. platform_name = " pxa-pcm-audio " ,
. codec_name = " ak4641.0-0012 " ,
. init = hx4700_ak4641_init ,
. ops = & hx4700_ops ,
} ;
/* hx4700 audio machine driver */
static struct snd_soc_card snd_soc_card_hx4700 = {
. name = " iPAQ hx4700 " ,
. dai_link = & hx4700_dai ,
. num_links = 1 ,
. dapm_widgets = hx4700_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( hx4700_dapm_widgets ) ,
. dapm_routes = hx4700_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( hx4700_audio_map ) ,
} ;
static struct gpio hx4700_audio_gpios [ ] = {
{ GPIO107_HX4700_SPK_nSD , GPIOF_OUT_INIT_HIGH , " SPK_POWER " } ,
{ GPIO92_HX4700_HP_DRIVER , GPIOF_OUT_INIT_LOW , " EP_POWER " } ,
} ;
static int __devinit hx4700_audio_probe ( struct platform_device * pdev )
{
int ret ;
if ( ! machine_is_h4700 ( ) )
return - ENODEV ;
ret = gpio_request_array ( hx4700_audio_gpios ,
ARRAY_SIZE ( hx4700_audio_gpios ) ) ;
if ( ret )
return ret ;
snd_soc_card_hx4700 . dev = & pdev - > dev ;
ret = snd_soc_register_card ( & snd_soc_card_hx4700 ) ;
if ( ret )
2011-12-12 07:26:00 +04:00
gpio_free_array ( hx4700_audio_gpios ,
ARRAY_SIZE ( hx4700_audio_gpios ) ) ;
2011-05-18 19:25:10 +04:00
2011-12-12 07:26:00 +04:00
return ret ;
2011-05-18 19:25:10 +04:00
}
static int __devexit hx4700_audio_remove ( struct platform_device * pdev )
{
snd_soc_jack_free_gpios ( & hs_jack , 1 , & hs_jack_gpio ) ;
snd_soc_unregister_card ( & snd_soc_card_hx4700 ) ;
gpio_set_value ( GPIO92_HX4700_HP_DRIVER , 0 ) ;
gpio_set_value ( GPIO107_HX4700_SPK_nSD , 0 ) ;
gpio_free_array ( hx4700_audio_gpios , ARRAY_SIZE ( hx4700_audio_gpios ) ) ;
return 0 ;
}
static struct platform_driver hx4700_audio_driver = {
. driver = {
. name = " hx4700-audio " ,
. owner = THIS_MODULE ,
. pm = & snd_soc_pm_ops ,
} ,
. probe = hx4700_audio_probe ,
. remove = __devexit_p ( hx4700_audio_remove ) ,
} ;
2011-11-25 06:13:37 +04:00
module_platform_driver ( hx4700_audio_driver ) ;
2011-05-18 19:25:10 +04:00
MODULE_AUTHOR ( " Philipp Zabel " ) ;
MODULE_DESCRIPTION ( " ALSA SoC iPAQ hx4700 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:hx4700-audio " ) ;