2010-07-31 00:32:11 +01:00
/*
* wm8741 . c - - WM8741 ALSA SoC Audio driver
*
2012-05-23 12:39:07 +01:00
* Copyright 2010 - 1 Wolfson Microelectronics plc
2010-07-31 00:32:11 +01:00
*
* Author : Ian Lartey < ian @ opensource . wolfsonmicro . com >
*
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
# include <linux/i2c.h>
2011-08-03 17:30:57 +09:00
# include <linux/spi/spi.h>
2010-07-31 00:32:11 +01:00
# include <linux/regulator/consumer.h>
# include <linux/slab.h>
2011-08-03 17:31:26 +09:00
# include <linux/of_device.h>
2010-07-31 00:32:11 +01:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/initval.h>
# include <sound/tlv.h>
# include "wm8741.h"
# define WM8741_NUM_SUPPLIES 2
static const char * wm8741_supply_names [ WM8741_NUM_SUPPLIES ] = {
" AVDD " ,
" DVDD " ,
} ;
2010-08-27 15:26:27 +01:00
# define WM8741_NUM_RATES 6
2010-07-31 00:32:11 +01:00
/* codec private data */
struct wm8741_priv {
2010-03-17 20:15:21 +00:00
enum snd_soc_control_type control_type ;
2010-07-31 00:32:11 +01:00
struct regulator_bulk_data supplies [ WM8741_NUM_SUPPLIES ] ;
unsigned int sysclk ;
2010-08-27 15:26:27 +01:00
struct snd_pcm_hw_constraint_list * sysclk_constraints ;
2010-07-31 00:32:11 +01:00
} ;
static const u16 wm8741_reg_defaults [ WM8741_REGISTER_COUNT ] = {
0x0000 , /* R0 - DACLLSB Attenuation */
0x0000 , /* R1 - DACLMSB Attenuation */
0x0000 , /* R2 - DACRLSB Attenuation */
0x0000 , /* R3 - DACRMSB Attenuation */
0x0000 , /* R4 - Volume Control */
0x000A , /* R5 - Format Control */
0x0000 , /* R6 - Filter Control */
0x0000 , /* R7 - Mode Control 1 */
0x0002 , /* R8 - Mode Control 2 */
0x0000 , /* R9 - Reset */
0x0002 , /* R32 - ADDITONAL_CONTROL_1 */
} ;
static int wm8741_reset ( struct snd_soc_codec * codec )
{
return snd_soc_write ( codec , WM8741_RESET , 0 ) ;
}
static const DECLARE_TLV_DB_SCALE ( dac_tlv_fine , - 12700 , 13 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( dac_tlv , - 12700 , 400 , 0 ) ;
static const struct snd_kcontrol_new wm8741_snd_controls [ ] = {
SOC_DOUBLE_R_TLV ( " Fine Playback Volume " , WM8741_DACLLSB_ATTENUATION ,
WM8741_DACRLSB_ATTENUATION , 1 , 255 , 1 , dac_tlv_fine ) ,
SOC_DOUBLE_R_TLV ( " Playback Volume " , WM8741_DACLMSB_ATTENUATION ,
WM8741_DACRMSB_ATTENUATION , 0 , 511 , 1 , dac_tlv ) ,
} ;
static const struct snd_soc_dapm_widget wm8741_dapm_widgets [ ] = {
SND_SOC_DAPM_DAC ( " DACL " , " Playback " , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_DAC ( " DACR " , " Playback " , SND_SOC_NOPM , 0 , 0 ) ,
SND_SOC_DAPM_OUTPUT ( " VOUTLP " ) ,
SND_SOC_DAPM_OUTPUT ( " VOUTLN " ) ,
SND_SOC_DAPM_OUTPUT ( " VOUTRP " ) ,
SND_SOC_DAPM_OUTPUT ( " VOUTRN " ) ,
} ;
2011-12-03 17:15:06 +00:00
static const struct snd_soc_dapm_route wm8741_dapm_routes [ ] = {
2010-07-31 00:32:11 +01:00
{ " VOUTLP " , NULL , " DACL " } ,
{ " VOUTLN " , NULL , " DACL " } ,
{ " VOUTRP " , NULL , " DACR " } ,
{ " VOUTRN " , NULL , " DACR " } ,
} ;
static struct {
int value ;
int ratio ;
} lrclk_ratios [ WM8741_NUM_RATES ] = {
2010-08-27 15:26:27 +01:00
{ 1 , 128 } ,
{ 2 , 192 } ,
{ 3 , 256 } ,
{ 4 , 384 } ,
{ 5 , 512 } ,
{ 6 , 768 } ,
} ;
static unsigned int rates_11289 [ ] = {
44100 , 88235 ,
} ;
static struct snd_pcm_hw_constraint_list constraints_11289 = {
. count = ARRAY_SIZE ( rates_11289 ) ,
. list = rates_11289 ,
} ;
static unsigned int rates_12288 [ ] = {
32000 , 48000 , 96000 ,
} ;
static struct snd_pcm_hw_constraint_list constraints_12288 = {
. count = ARRAY_SIZE ( rates_12288 ) ,
. list = rates_12288 ,
} ;
static unsigned int rates_16384 [ ] = {
32000 ,
} ;
static struct snd_pcm_hw_constraint_list constraints_16384 = {
. count = ARRAY_SIZE ( rates_16384 ) ,
. list = rates_16384 ,
} ;
static unsigned int rates_16934 [ ] = {
44100 , 88235 ,
} ;
static struct snd_pcm_hw_constraint_list constraints_16934 = {
. count = ARRAY_SIZE ( rates_16934 ) ,
. list = rates_16934 ,
} ;
static unsigned int rates_18432 [ ] = {
48000 , 96000 ,
} ;
static struct snd_pcm_hw_constraint_list constraints_18432 = {
. count = ARRAY_SIZE ( rates_18432 ) ,
. list = rates_18432 ,
} ;
static unsigned int rates_22579 [ ] = {
44100 , 88235 , 1764000
} ;
static struct snd_pcm_hw_constraint_list constraints_22579 = {
. count = ARRAY_SIZE ( rates_22579 ) ,
. list = rates_22579 ,
} ;
static unsigned int rates_24576 [ ] = {
32000 , 48000 , 96000 , 192000
} ;
static struct snd_pcm_hw_constraint_list constraints_24576 = {
. count = ARRAY_SIZE ( rates_24576 ) ,
. list = rates_24576 ,
} ;
static unsigned int rates_36864 [ ] = {
48000 , 96000 , 19200
} ;
static struct snd_pcm_hw_constraint_list constraints_36864 = {
. count = ARRAY_SIZE ( rates_36864 ) ,
. list = rates_36864 ,
2010-07-31 00:32:11 +01:00
} ;
static int wm8741_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct snd_soc_codec * codec = dai - > codec ;
struct wm8741_priv * wm8741 = snd_soc_codec_get_drvdata ( codec ) ;
/* The set of sample rates that can be supported depends on the
* MCLK supplied to the CODEC - enforce this .
*/
if ( ! wm8741 - > sysclk ) {
dev_err ( codec - > dev ,
" No MCLK configured, call set_sysclk() on init \n " ) ;
return - EINVAL ;
}
snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE ,
2010-08-27 15:26:27 +01:00
wm8741 - > sysclk_constraints ) ;
2010-07-31 00:32:11 +01:00
return 0 ;
}
static int wm8741_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2012-04-04 15:58:16 +01:00
struct snd_soc_codec * codec = dai - > codec ;
2010-07-31 00:32:11 +01:00
struct wm8741_priv * wm8741 = snd_soc_codec_get_drvdata ( codec ) ;
u16 iface = snd_soc_read ( codec , WM8741_FORMAT_CONTROL ) & 0x1FC ;
int i ;
/* Find a supported LRCLK ratio */
for ( i = 0 ; i < ARRAY_SIZE ( lrclk_ratios ) ; i + + ) {
if ( wm8741 - > sysclk / params_rate ( params ) = =
lrclk_ratios [ i ] . ratio )
break ;
}
/* Should never happen, should be handled by constraints */
if ( i = = ARRAY_SIZE ( lrclk_ratios ) ) {
dev_err ( codec - > dev , " MCLK/fs ratio %d unsupported \n " ,
wm8741 - > sysclk / params_rate ( params ) ) ;
return - EINVAL ;
}
/* bit size */
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_S16_LE :
break ;
case SNDRV_PCM_FORMAT_S20_3LE :
iface | = 0x0001 ;
break ;
case SNDRV_PCM_FORMAT_S24_LE :
iface | = 0x0002 ;
break ;
case SNDRV_PCM_FORMAT_S32_LE :
iface | = 0x0003 ;
break ;
default :
dev_dbg ( codec - > dev , " wm8741_hw_params: Unsupported bit size param = %d " ,
params_format ( params ) ) ;
return - EINVAL ;
}
dev_dbg ( codec - > dev , " wm8741_hw_params: bit size param = %d " ,
params_format ( params ) ) ;
snd_soc_write ( codec , WM8741_FORMAT_CONTROL , iface ) ;
return 0 ;
}
static int wm8741_set_dai_sysclk ( struct snd_soc_dai * codec_dai ,
int clk_id , unsigned int freq , int dir )
{
struct snd_soc_codec * codec = codec_dai - > codec ;
struct wm8741_priv * wm8741 = snd_soc_codec_get_drvdata ( codec ) ;
dev_dbg ( codec - > dev , " wm8741_set_dai_sysclk info: freq=%dHz \n " , freq ) ;
2010-08-27 15:26:27 +01:00
switch ( freq ) {
case 11289600 :
wm8741 - > sysclk_constraints = & constraints_11289 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 12288000 :
wm8741 - > sysclk_constraints = & constraints_12288 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 16384000 :
wm8741 - > sysclk_constraints = & constraints_16384 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 16934400 :
wm8741 - > sysclk_constraints = & constraints_16934 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 18432000 :
wm8741 - > sysclk_constraints = & constraints_18432 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 22579200 :
case 33868800 :
wm8741 - > sysclk_constraints = & constraints_22579 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 24576000 :
wm8741 - > sysclk_constraints = & constraints_24576 ;
wm8741 - > sysclk = freq ;
return 0 ;
case 36864000 :
wm8741 - > sysclk_constraints = & constraints_36864 ;
wm8741 - > sysclk = freq ;
return 0 ;
2010-07-31 00:32:11 +01:00
}
2010-08-27 15:26:27 +01:00
return - EINVAL ;
2010-07-31 00:32:11 +01:00
}
static int wm8741_set_dai_fmt ( struct snd_soc_dai * codec_dai ,
unsigned int fmt )
{
struct snd_soc_codec * codec = codec_dai - > codec ;
u16 iface = snd_soc_read ( codec , WM8741_FORMAT_CONTROL ) & 0x1C3 ;
/* check master/slave audio interface */
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
break ;
default :
return - EINVAL ;
}
/* interface format */
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_I2S :
iface | = 0x0008 ;
break ;
case SND_SOC_DAIFMT_RIGHT_J :
break ;
case SND_SOC_DAIFMT_LEFT_J :
iface | = 0x0004 ;
break ;
case SND_SOC_DAIFMT_DSP_A :
2011-10-17 20:14:56 +08:00
iface | = 0x000C ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_DSP_B :
2011-10-17 20:14:56 +08:00
iface | = 0x001C ;
2010-07-31 00:32:11 +01:00
break ;
default :
return - EINVAL ;
}
/* clock inversion */
switch ( fmt & SND_SOC_DAIFMT_INV_MASK ) {
case SND_SOC_DAIFMT_NB_NF :
break ;
case SND_SOC_DAIFMT_IB_IF :
iface | = 0x0010 ;
break ;
case SND_SOC_DAIFMT_IB_NF :
iface | = 0x0020 ;
break ;
case SND_SOC_DAIFMT_NB_IF :
iface | = 0x0030 ;
break ;
default :
return - EINVAL ;
}
dev_dbg ( codec - > dev , " wm8741_set_dai_fmt: Format=%x, Clock Inv=%x \n " ,
fmt & SND_SOC_DAIFMT_FORMAT_MASK ,
( ( fmt & SND_SOC_DAIFMT_INV_MASK ) ) ) ;
snd_soc_write ( codec , WM8741_FORMAT_CONTROL , iface ) ;
return 0 ;
}
# define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
SNDRV_PCM_RATE_192000 )
# define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE )
2011-11-23 11:40:40 +01:00
static const struct snd_soc_dai_ops wm8741_dai_ops = {
2010-07-31 00:32:11 +01:00
. startup = wm8741_startup ,
. hw_params = wm8741_hw_params ,
. set_sysclk = wm8741_set_dai_sysclk ,
. set_fmt = wm8741_set_dai_fmt ,
} ;
2010-03-17 20:15:21 +00:00
static struct snd_soc_dai_driver wm8741_dai = {
2010-08-20 17:18:44 +01:00
. name = " wm8741 " ,
2010-07-31 00:32:11 +01:00
. playback = {
. stream_name = " Playback " ,
. channels_min = 2 , /* Mono modes not yet supported */
. channels_max = 2 ,
. rates = WM8741_RATES ,
. formats = WM8741_FORMATS ,
} ,
. ops = & wm8741_dai_ops ,
} ;
# ifdef CONFIG_PM
2010-03-17 20:15:21 +00:00
static int wm8741_resume ( struct snd_soc_codec * codec )
2010-07-31 00:32:11 +01:00
{
2011-10-17 20:16:37 +08:00
snd_soc_cache_sync ( codec ) ;
2010-07-31 00:32:11 +01:00
return 0 ;
}
# else
# define wm8741_suspend NULL
# define wm8741_resume NULL
# endif
2010-03-17 20:15:21 +00:00
static int wm8741_probe ( struct snd_soc_codec * codec )
2010-07-31 00:32:11 +01:00
{
2010-03-17 20:15:21 +00:00
struct wm8741_priv * wm8741 = snd_soc_codec_get_drvdata ( codec ) ;
2010-07-31 00:32:11 +01:00
int ret = 0 ;
2011-08-03 17:16:11 +09:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( wm8741 - > supplies ) ,
wm8741 - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( codec - > dev , " Failed to enable supplies: %d \n " , ret ) ;
goto err_get ;
}
2010-07-31 00:32:11 +01:00
2010-03-17 20:15:21 +00:00
ret = snd_soc_codec_set_cache_io ( codec , 7 , 9 , wm8741 - > control_type ) ;
if ( ret ! = 0 ) {
dev_err ( codec - > dev , " Failed to set cache I/O: %d \n " , ret ) ;
2011-08-03 17:16:11 +09:00
goto err_enable ;
2010-07-31 00:32:11 +01:00
}
2010-03-17 20:15:21 +00:00
ret = wm8741_reset ( codec ) ;
2010-07-31 00:32:11 +01:00
if ( ret < 0 ) {
2010-03-17 20:15:21 +00:00
dev_err ( codec - > dev , " Failed to issue reset \n " ) ;
2011-08-03 17:16:11 +09:00
goto err_enable ;
2010-07-31 00:32:11 +01:00
}
2010-03-17 20:15:21 +00:00
/* Change some default settings - latch VU */
2010-12-24 16:59:30 +00:00
snd_soc_update_bits ( codec , WM8741_DACLLSB_ATTENUATION ,
WM8741_UPDATELL , WM8741_UPDATELL ) ;
snd_soc_update_bits ( codec , WM8741_DACLMSB_ATTENUATION ,
WM8741_UPDATELM , WM8741_UPDATELM ) ;
snd_soc_update_bits ( codec , WM8741_DACRLSB_ATTENUATION ,
WM8741_UPDATERL , WM8741_UPDATERL ) ;
2011-10-03 11:09:01 +08:00
snd_soc_update_bits ( codec , WM8741_DACRMSB_ATTENUATION ,
2010-12-24 16:59:30 +00:00
WM8741_UPDATERM , WM8741_UPDATERM ) ;
2010-03-17 20:15:21 +00:00
dev_dbg ( codec - > dev , " Successful registration \n " ) ;
2010-07-31 00:32:11 +01:00
return ret ;
2011-08-03 17:16:11 +09:00
err_enable :
regulator_bulk_disable ( ARRAY_SIZE ( wm8741 - > supplies ) , wm8741 - > supplies ) ;
err_get :
err :
return ret ;
}
static int wm8741_remove ( struct snd_soc_codec * codec )
{
struct wm8741_priv * wm8741 = snd_soc_codec_get_drvdata ( codec ) ;
regulator_bulk_disable ( ARRAY_SIZE ( wm8741 - > supplies ) , wm8741 - > supplies ) ;
return 0 ;
2010-07-31 00:32:11 +01:00
}
2010-03-17 20:15:21 +00:00
static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
2010-07-31 00:32:11 +01:00
. probe = wm8741_probe ,
2011-08-03 17:16:11 +09:00
. remove = wm8741_remove ,
2010-07-31 00:32:11 +01:00
. resume = wm8741_resume ,
2010-09-10 18:14:56 +01:00
. reg_cache_size = ARRAY_SIZE ( wm8741_reg_defaults ) ,
2010-03-17 20:15:21 +00:00
. reg_word_size = sizeof ( u16 ) ,
2010-11-08 10:41:53 +00:00
. reg_cache_default = wm8741_reg_defaults ,
2011-12-03 17:15:06 +00:00
. controls = wm8741_snd_controls ,
. num_controls = ARRAY_SIZE ( wm8741_snd_controls ) ,
. dapm_widgets = wm8741_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( wm8741_dapm_widgets ) ,
. dapm_routes = wm8741_dapm_routes ,
. num_dapm_routes = ARRAY_SIZE ( wm8741_dapm_routes ) ,
2010-07-31 00:32:11 +01:00
} ;
2011-08-03 17:31:26 +09:00
static const struct of_device_id wm8741_of_match [ ] = {
{ . compatible = " wlf,wm8741 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , wm8741_of_match ) ;
2010-03-17 20:15:21 +00:00
# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8741_i2c_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * id )
2010-07-31 00:32:11 +01:00
{
2010-03-17 20:15:21 +00:00
struct wm8741_priv * wm8741 ;
2012-09-10 17:52:59 +08:00
int ret , i ;
2010-07-31 00:32:11 +01:00
2011-12-03 17:17:05 +00:00
wm8741 = devm_kzalloc ( & i2c - > dev , sizeof ( struct wm8741_priv ) ,
GFP_KERNEL ) ;
2010-03-17 20:15:21 +00:00
if ( wm8741 = = NULL )
return - ENOMEM ;
2010-07-31 00:32:11 +01:00
2012-09-10 17:52:59 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8741 - > supplies ) ; i + + )
wm8741 - > supplies [ i ] . supply = wm8741_supply_names [ i ] ;
ret = devm_regulator_bulk_get ( & i2c - > dev , ARRAY_SIZE ( wm8741 - > supplies ) ,
wm8741 - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( codec - > dev , " Failed to request supplies: %d \n " , ret ) ;
goto err ;
}
2010-03-17 20:15:21 +00:00
i2c_set_clientdata ( i2c , wm8741 ) ;
wm8741 - > control_type = SND_SOC_I2C ;
2010-07-31 00:32:11 +01:00
2011-08-03 17:16:11 +09:00
ret = snd_soc_register_codec ( & i2c - > dev ,
& soc_codec_dev_wm8741 , & wm8741_dai , 1 ) ;
2010-07-31 00:32:11 +01:00
return ret ;
}
2010-03-17 20:15:21 +00:00
static int wm8741_i2c_remove ( struct i2c_client * client )
2010-07-31 00:32:11 +01:00
{
2010-03-17 20:15:21 +00:00
snd_soc_unregister_codec ( & client - > dev ) ;
2010-07-31 00:32:11 +01:00
return 0 ;
}
static const struct i2c_device_id wm8741_i2c_id [ ] = {
{ " wm8741 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , wm8741_i2c_id ) ;
static struct i2c_driver wm8741_i2c_driver = {
. driver = {
2011-08-03 16:52:10 +09:00
. name = " wm8741 " ,
2010-07-31 00:32:11 +01:00
. owner = THIS_MODULE ,
2011-08-03 17:31:26 +09:00
. of_match_table = wm8741_of_match ,
2010-07-31 00:32:11 +01:00
} ,
. probe = wm8741_i2c_probe ,
2010-03-17 20:15:21 +00:00
. remove = wm8741_i2c_remove ,
2010-07-31 00:32:11 +01:00
. id_table = wm8741_i2c_id ,
} ;
# endif
2011-08-03 17:30:57 +09:00
# if defined(CONFIG_SPI_MASTER)
static int __devinit wm8741_spi_probe ( struct spi_device * spi )
{
struct wm8741_priv * wm8741 ;
2012-09-10 17:52:59 +08:00
int ret , i ;
2011-08-03 17:30:57 +09:00
2011-12-03 17:17:05 +00:00
wm8741 = devm_kzalloc ( & spi - > dev , sizeof ( struct wm8741_priv ) ,
GFP_KERNEL ) ;
2011-08-03 17:30:57 +09:00
if ( wm8741 = = NULL )
return - ENOMEM ;
2012-09-10 17:52:59 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8741 - > supplies ) ; i + + )
wm8741 - > supplies [ i ] . supply = wm8741_supply_names [ i ] ;
ret = devm_regulator_bulk_get ( & i2c - > dev , ARRAY_SIZE ( wm8741 - > supplies ) ,
wm8741 - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( & spi - > dev , " Failed to request supplies: %d \n " , ret ) ;
goto err ;
}
2011-08-03 17:30:57 +09:00
wm8741 - > control_type = SND_SOC_SPI ;
spi_set_drvdata ( spi , wm8741 ) ;
ret = snd_soc_register_codec ( & spi - > dev ,
& soc_codec_dev_wm8741 , & wm8741_dai , 1 ) ;
return ret ;
}
static int __devexit wm8741_spi_remove ( struct spi_device * spi )
{
snd_soc_unregister_codec ( & spi - > dev ) ;
return 0 ;
}
static struct spi_driver wm8741_spi_driver = {
. driver = {
. name = " wm8741 " ,
. owner = THIS_MODULE ,
2011-08-03 17:31:26 +09:00
. of_match_table = wm8741_of_match ,
2011-08-03 17:30:57 +09:00
} ,
. probe = wm8741_spi_probe ,
. remove = __devexit_p ( wm8741_spi_remove ) ,
} ;
# endif /* CONFIG_SPI_MASTER */
2010-07-31 00:32:11 +01:00
static int __init wm8741_modinit ( void )
{
2010-03-17 20:15:21 +00:00
int ret = 0 ;
2010-07-31 00:32:11 +01:00
# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver ( & wm8741_i2c_driver ) ;
2010-08-27 15:26:27 +01:00
if ( ret ! = 0 )
2010-03-17 20:15:21 +00:00
pr_err ( " Failed to register WM8741 I2C driver: %d \n " , ret ) ;
2010-07-31 00:32:11 +01:00
# endif
2011-08-03 17:30:57 +09:00
# if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver ( & wm8741_spi_driver ) ;
if ( ret ! = 0 ) {
printk ( KERN_ERR " Failed to register wm8741 SPI driver: %d \n " ,
ret ) ;
}
# endif
2010-03-17 20:15:21 +00:00
return ret ;
2010-07-31 00:32:11 +01:00
}
module_init ( wm8741_modinit ) ;
static void __exit wm8741_exit ( void )
{
2011-08-03 17:30:57 +09:00
# if defined(CONFIG_SPI_MASTER)
spi_unregister_driver ( & wm8741_spi_driver ) ;
# endif
2010-07-31 00:32:11 +01:00
# if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver ( & wm8741_i2c_driver ) ;
# endif
}
module_exit ( wm8741_exit ) ;
MODULE_DESCRIPTION ( " ASoC WM8741 driver " ) ;
MODULE_AUTHOR ( " Ian Lartey <ian@opensource.wolfsonmicro.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;