2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
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 >
*/
# 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>
2012-09-10 18:00:21 +08:00
# include <linux/regmap.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 " ,
} ;
/* codec private data */
struct wm8741_priv {
2015-05-13 11:39:01 +02:00
struct wm8741_platform_data pdata ;
2012-09-10 18:00:21 +08:00
struct regmap * regmap ;
2010-07-31 00:32:11 +01:00
struct regulator_bulk_data supplies [ WM8741_NUM_SUPPLIES ] ;
unsigned int sysclk ;
2014-02-05 21:54:35 +01:00
const struct snd_pcm_hw_constraint_list * sysclk_constraints ;
2010-07-31 00:32:11 +01:00
} ;
2012-09-10 18:00:21 +08:00
static const struct reg_default wm8741_reg_defaults [ ] = {
{ 0 , 0x0000 } , /* R0 - DACLLSB Attenuation */
{ 1 , 0x0000 } , /* R1 - DACLMSB Attenuation */
{ 2 , 0x0000 } , /* R2 - DACRLSB Attenuation */
{ 3 , 0x0000 } , /* R3 - DACRMSB Attenuation */
{ 4 , 0x0000 } , /* R4 - Volume Control */
{ 5 , 0x000A } , /* R5 - Format Control */
{ 6 , 0x0000 } , /* R6 - Filter Control */
{ 7 , 0x0000 } , /* R7 - Mode Control 1 */
{ 8 , 0x0002 } , /* R8 - Mode Control 2 */
{ 32 , 0x0002 } , /* R32 - ADDITONAL_CONTROL_1 */
2010-07-31 00:32:11 +01:00
} ;
2018-01-29 03:04:06 +00:00
static int wm8741_reset ( struct snd_soc_component * component )
2010-07-31 00:32:11 +01:00
{
2018-01-29 03:04:06 +00:00
return snd_soc_component_write ( component , WM8741_RESET , 0 ) ;
2010-07-31 00:32:11 +01:00
}
static const DECLARE_TLV_DB_SCALE ( dac_tlv_fine , - 12700 , 13 , 0 ) ;
static const DECLARE_TLV_DB_SCALE ( dac_tlv , - 12700 , 400 , 0 ) ;
2015-05-13 11:39:01 +02:00
static const struct snd_kcontrol_new wm8741_snd_controls_stereo [ ] = {
2010-07-31 00:32:11 +01:00
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 ) ,
} ;
2015-05-13 11:39:01 +02:00
static const struct snd_kcontrol_new wm8741_snd_controls_mono_left [ ] = {
SOC_SINGLE_TLV ( " Fine Playback Volume " , WM8741_DACLLSB_ATTENUATION ,
1 , 255 , 1 , dac_tlv_fine ) ,
SOC_SINGLE_TLV ( " Playback Volume " , WM8741_DACLMSB_ATTENUATION ,
0 , 511 , 1 , dac_tlv ) ,
} ;
static const struct snd_kcontrol_new wm8741_snd_controls_mono_right [ ] = {
SOC_SINGLE_TLV ( " Fine Playback Volume " , WM8741_DACRLSB_ATTENUATION ,
1 , 255 , 1 , dac_tlv_fine ) ,
SOC_SINGLE_TLV ( " Playback Volume " , WM8741_DACRMSB_ATTENUATION ,
0 , 511 , 1 , dac_tlv ) ,
} ;
2010-07-31 00:32:11 +01:00
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 " } ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_11289 [ ] = {
2015-03-24 21:13:22 +01:00
44100 , 88200 ,
2010-08-27 15:26:27 +01:00
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_11289 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_11289 ) ,
. list = rates_11289 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_12288 [ ] = {
2010-08-27 15:26:27 +01:00
32000 , 48000 , 96000 ,
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_12288 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_12288 ) ,
. list = rates_12288 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_16384 [ ] = {
2010-08-27 15:26:27 +01:00
32000 ,
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_16384 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_16384 ) ,
. list = rates_16384 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_16934 [ ] = {
2015-03-24 21:13:22 +01:00
44100 , 88200 ,
2010-08-27 15:26:27 +01:00
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_16934 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_16934 ) ,
. list = rates_16934 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_18432 [ ] = {
2010-08-27 15:26:27 +01:00
48000 , 96000 ,
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_18432 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_18432 ) ,
. list = rates_18432 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_22579 [ ] = {
2015-03-24 21:13:22 +01:00
44100 , 88200 , 176400
2010-08-27 15:26:27 +01:00
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_22579 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_22579 ) ,
. list = rates_22579 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_24576 [ ] = {
2010-08-27 15:26:27 +01:00
32000 , 48000 , 96000 , 192000
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_24576 = {
2010-08-27 15:26:27 +01:00
. count = ARRAY_SIZE ( rates_24576 ) ,
. list = rates_24576 ,
} ;
2014-02-05 21:54:35 +01:00
static const unsigned int rates_36864 [ ] = {
2015-03-24 21:13:22 +01:00
48000 , 96000 , 192000
2010-08-27 15:26:27 +01:00
} ;
2014-02-05 21:54:35 +01:00
static const struct snd_pcm_hw_constraint_list constraints_36864 = {
2010-08-27 15:26:27 +01:00
. 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 )
{
2018-01-29 03:04:06 +00:00
struct snd_soc_component * component = dai - > component ;
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2010-07-31 00:32:11 +01:00
2015-06-06 11:25:48 +02:00
if ( wm8741 - > sysclk )
snd_pcm_hw_constraint_list ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE ,
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 )
{
2018-01-29 03:04:06 +00:00
struct snd_soc_component * component = dai - > component ;
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2019-02-10 16:29:29 +01:00
unsigned int iface , mode ;
2010-07-31 00:32:11 +01:00
int i ;
2015-06-06 11:25:48 +02:00
/* The set of sample rates that can be supported depends on the
* MCLK supplied to the CODEC - enforce this .
*/
if ( ! wm8741 - > sysclk ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > dev ,
2015-06-06 11:25:48 +02:00
" No MCLK configured, call set_sysclk() on init or in hw_params \n " ) ;
return - EINVAL ;
}
/* Find a supported LRCLK rate */
for ( i = 0 ; i < wm8741 - > sysclk_constraints - > count ; i + + ) {
if ( wm8741 - > sysclk_constraints - > list [ i ] = = params_rate ( params ) )
2010-07-31 00:32:11 +01:00
break ;
}
2015-06-06 11:25:48 +02:00
if ( i = = wm8741 - > sysclk_constraints - > count ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > dev , " LRCLK %d unsupported with MCLK %d \n " ,
2015-06-06 11:25:48 +02:00
params_rate ( params ) , wm8741 - > sysclk ) ;
2010-07-31 00:32:11 +01:00
return - EINVAL ;
}
/* bit size */
2014-07-31 12:51:45 +01:00
switch ( params_width ( params ) ) {
case 16 :
2017-11-01 11:03:25 +00:00
iface = 0x0 ;
2010-07-31 00:32:11 +01:00
break ;
2014-07-31 12:51:45 +01:00
case 20 :
2017-11-01 11:03:25 +00:00
iface = 0x1 ;
2010-07-31 00:32:11 +01:00
break ;
2014-07-31 12:51:45 +01:00
case 24 :
2017-11-01 11:03:25 +00:00
iface = 0x2 ;
2010-07-31 00:32:11 +01:00
break ;
2014-07-31 12:51:45 +01:00
case 32 :
2017-11-01 11:03:25 +00:00
iface = 0x3 ;
2010-07-31 00:32:11 +01:00
break ;
default :
2018-01-29 03:04:06 +00:00
dev_dbg ( component - > dev , " wm8741_hw_params: Unsupported bit size param = %d " ,
2014-07-31 12:51:45 +01:00
params_width ( params ) ) ;
2010-07-31 00:32:11 +01:00
return - EINVAL ;
}
2019-02-10 16:29:29 +01:00
/* oversampling rate */
if ( params_rate ( params ) > 96000 )
mode = 0x40 ;
else if ( params_rate ( params ) > 48000 )
mode = 0x20 ;
else
mode = 0x00 ;
2018-01-29 03:04:06 +00:00
dev_dbg ( component - > dev , " wm8741_hw_params: bit size param = %d, rate param = %d " ,
2015-06-06 11:25:48 +02:00
params_width ( params ) , params_rate ( params ) ) ;
2010-07-31 00:32:11 +01:00
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_FORMAT_CONTROL , WM8741_IWL_MASK ,
2017-11-01 11:03:25 +00:00
iface ) ;
2019-02-10 16:29:29 +01:00
snd_soc_component_update_bits ( component , WM8741_MODE_CONTROL_1 , WM8741_OSR_MASK ,
mode ) ;
2017-11-01 11:03:25 +00:00
2010-07-31 00:32:11 +01:00
return 0 ;
}
static int wm8741_set_dai_sysclk ( struct snd_soc_dai * codec_dai ,
int clk_id , unsigned int freq , int dir )
{
2018-01-29 03:04:06 +00:00
struct snd_soc_component * component = codec_dai - > component ;
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2010-07-31 00:32:11 +01:00
2018-01-29 03:04:06 +00:00
dev_dbg ( component - > dev , " wm8741_set_dai_sysclk info: freq=%dHz \n " , freq ) ;
2010-07-31 00:32:11 +01:00
2010-08-27 15:26:27 +01:00
switch ( freq ) {
2015-06-06 11:25:48 +02:00
case 0 :
wm8741 - > sysclk_constraints = NULL ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 11289600 :
wm8741 - > sysclk_constraints = & constraints_11289 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 12288000 :
wm8741 - > sysclk_constraints = & constraints_12288 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 16384000 :
wm8741 - > sysclk_constraints = & constraints_16384 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 16934400 :
wm8741 - > sysclk_constraints = & constraints_16934 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 18432000 :
wm8741 - > sysclk_constraints = & constraints_18432 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 22579200 :
case 33868800 :
wm8741 - > sysclk_constraints = & constraints_22579 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 24576000 :
wm8741 - > sysclk_constraints = & constraints_24576 ;
2015-07-30 10:24:03 +08:00
break ;
2010-08-27 15:26:27 +01:00
case 36864000 :
wm8741 - > sysclk_constraints = & constraints_36864 ;
2015-07-30 10:24:03 +08:00
break ;
default :
return - EINVAL ;
2010-07-31 00:32:11 +01:00
}
2015-07-30 10:24:03 +08:00
wm8741 - > sysclk = freq ;
return 0 ;
2010-07-31 00:32:11 +01:00
}
static int wm8741_set_dai_fmt ( struct snd_soc_dai * codec_dai ,
unsigned int fmt )
{
2018-01-29 03:04:06 +00:00
struct snd_soc_component * component = codec_dai - > component ;
2017-11-01 11:03:25 +00:00
unsigned int iface ;
2010-07-31 00:32:11 +01:00
/* 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 :
2017-11-01 11:03:25 +00:00
iface = 0x08 ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_RIGHT_J :
2017-11-01 11:03:25 +00:00
iface = 0x00 ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_LEFT_J :
2017-11-01 11:03:25 +00:00
iface = 0x04 ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_DSP_A :
2017-11-01 11:03:25 +00:00
iface = 0x0C ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_DSP_B :
2017-11-01 11:03:25 +00:00
iface = 0x1C ;
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 ;
2017-11-03 19:34:28 +01:00
case SND_SOC_DAIFMT_NB_IF :
2017-11-01 11:03:25 +00:00
iface | = 0x10 ;
2010-07-31 00:32:11 +01:00
break ;
case SND_SOC_DAIFMT_IB_NF :
2017-11-01 11:03:25 +00:00
iface | = 0x20 ;
2010-07-31 00:32:11 +01:00
break ;
2017-11-03 19:34:28 +01:00
case SND_SOC_DAIFMT_IB_IF :
2017-11-01 11:03:25 +00:00
iface | = 0x30 ;
2010-07-31 00:32:11 +01:00
break ;
default :
return - EINVAL ;
}
2018-01-29 03:04:06 +00:00
dev_dbg ( component - > dev , " wm8741_set_dai_fmt: Format=%x, Clock Inv=%x \n " ,
2010-07-31 00:32:11 +01:00
fmt & SND_SOC_DAIFMT_FORMAT_MASK ,
( ( fmt & SND_SOC_DAIFMT_INV_MASK ) ) ) ;
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_FORMAT_CONTROL ,
2017-11-01 11:03:25 +00:00
WM8741_BCP_MASK | WM8741_LRP_MASK | WM8741_FMT_MASK ,
iface ) ;
2010-07-31 00:32:11 +01:00
return 0 ;
}
2019-02-16 01:35:56 +00:00
static int wm8741_mute ( struct snd_soc_dai * codec_dai , int mute )
2019-02-10 16:28:04 +01:00
{
struct snd_soc_component * component = codec_dai - > component ;
snd_soc_component_update_bits ( component , WM8741_VOLUME_CONTROL ,
WM8741_SOFT_MASK , ! ! mute < < WM8741_SOFT_SHIFT ) ;
return 0 ;
}
2010-07-31 00:32:11 +01:00
# 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 ,
2019-02-10 16:28:04 +01:00
. digital_mute = wm8741_mute ,
2010-07-31 00:32:11 +01:00
} ;
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 " ,
2015-05-13 11:39:01 +02:00
. channels_min = 2 ,
2010-07-31 00:32:11 +01:00
. channels_max = 2 ,
. rates = WM8741_RATES ,
. formats = WM8741_FORMATS ,
} ,
. ops = & wm8741_dai_ops ,
} ;
# ifdef CONFIG_PM
2018-01-29 03:04:06 +00:00
static int wm8741_resume ( struct snd_soc_component * component )
2010-07-31 00:32:11 +01:00
{
2018-01-29 03:04:06 +00:00
snd_soc_component_cache_sync ( component ) ;
2010-07-31 00:32:11 +01:00
return 0 ;
}
# else
# define wm8741_resume NULL
# endif
2018-01-29 03:04:06 +00:00
static int wm8741_configure ( struct snd_soc_component * component )
2015-05-13 11:39:01 +02:00
{
2018-01-29 03:04:06 +00:00
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2015-05-13 11:39:01 +02:00
/* Configure differential mode */
switch ( wm8741 - > pdata . diff_mode ) {
case WM8741_DIFF_MODE_STEREO :
case WM8741_DIFF_MODE_STEREO_REVERSED :
case WM8741_DIFF_MODE_MONO_LEFT :
case WM8741_DIFF_MODE_MONO_RIGHT :
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_MODE_CONTROL_2 ,
2015-05-13 11:39:01 +02:00
WM8741_DIFF_MASK ,
wm8741 - > pdata . diff_mode < < WM8741_DIFF_SHIFT ) ;
break ;
default :
return - EINVAL ;
}
/* Change some default settings - latch VU */
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_DACLLSB_ATTENUATION ,
2015-05-13 11:39:01 +02:00
WM8741_UPDATELL , WM8741_UPDATELL ) ;
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_DACLMSB_ATTENUATION ,
2015-05-13 11:39:01 +02:00
WM8741_UPDATELM , WM8741_UPDATELM ) ;
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_DACRLSB_ATTENUATION ,
2015-05-13 11:39:01 +02:00
WM8741_UPDATERL , WM8741_UPDATERL ) ;
2018-01-29 03:04:06 +00:00
snd_soc_component_update_bits ( component , WM8741_DACRMSB_ATTENUATION ,
2015-05-13 11:39:01 +02:00
WM8741_UPDATERM , WM8741_UPDATERM ) ;
return 0 ;
}
2018-01-29 03:04:06 +00:00
static int wm8741_add_controls ( struct snd_soc_component * component )
2015-05-13 11:39:01 +02:00
{
2018-01-29 03:04:06 +00:00
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2015-05-13 11:39:01 +02:00
switch ( wm8741 - > pdata . diff_mode ) {
case WM8741_DIFF_MODE_STEREO :
case WM8741_DIFF_MODE_STEREO_REVERSED :
2018-01-29 03:04:06 +00:00
snd_soc_add_component_controls ( component ,
2015-05-13 11:39:01 +02:00
wm8741_snd_controls_stereo ,
ARRAY_SIZE ( wm8741_snd_controls_stereo ) ) ;
break ;
case WM8741_DIFF_MODE_MONO_LEFT :
2018-01-29 03:04:06 +00:00
snd_soc_add_component_controls ( component ,
2015-05-13 11:39:01 +02:00
wm8741_snd_controls_mono_left ,
ARRAY_SIZE ( wm8741_snd_controls_mono_left ) ) ;
break ;
case WM8741_DIFF_MODE_MONO_RIGHT :
2018-01-29 03:04:06 +00:00
snd_soc_add_component_controls ( component ,
2015-05-13 11:39:01 +02:00
wm8741_snd_controls_mono_right ,
ARRAY_SIZE ( wm8741_snd_controls_mono_right ) ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2018-01-29 03:04:06 +00:00
static int wm8741_probe ( struct snd_soc_component * component )
2010-07-31 00:32:11 +01:00
{
2018-01-29 03:04:06 +00:00
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
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 ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > dev , " Failed to enable supplies: %d \n " , ret ) ;
2011-08-03 17:16:11 +09:00
goto err_get ;
}
2010-07-31 00:32:11 +01:00
2018-01-29 03:04:06 +00:00
ret = wm8741_reset ( component ) ;
2010-07-31 00:32:11 +01:00
if ( ret < 0 ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > 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
}
2018-01-29 03:04:06 +00:00
ret = wm8741_configure ( component ) ;
2015-05-13 11:39:01 +02:00
if ( ret < 0 ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > dev , " Failed to change default settings \n " ) ;
2015-05-13 11:39:01 +02:00
goto err_enable ;
}
2018-01-29 03:04:06 +00:00
ret = wm8741_add_controls ( component ) ;
2015-05-13 11:39:01 +02:00
if ( ret < 0 ) {
2018-01-29 03:04:06 +00:00
dev_err ( component - > dev , " Failed to add controls \n " ) ;
2015-05-13 11:39:01 +02:00
goto err_enable ;
}
2010-03-17 20:15:21 +00:00
2018-01-29 03:04:06 +00:00
dev_dbg ( component - > 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 :
return ret ;
}
2018-01-29 03:04:06 +00:00
static void wm8741_remove ( struct snd_soc_component * component )
2011-08-03 17:16:11 +09:00
{
2018-01-29 03:04:06 +00:00
struct wm8741_priv * wm8741 = snd_soc_component_get_drvdata ( component ) ;
2011-08-03 17:16:11 +09:00
regulator_bulk_disable ( ARRAY_SIZE ( wm8741 - > supplies ) , wm8741 - > supplies ) ;
2010-07-31 00:32:11 +01:00
}
2018-01-29 03:04:06 +00:00
static const struct snd_soc_component_driver soc_component_dev_wm8741 = {
. probe = wm8741_probe ,
. remove = wm8741_remove ,
. resume = wm8741_resume ,
. 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 ) ,
. idle_bias_on = 1 ,
. use_pmdown_time = 1 ,
. endianness = 1 ,
. non_legacy_dai_naming = 1 ,
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 ) ;
2012-09-10 18:00:21 +08:00
static const struct regmap_config wm8741_regmap = {
. reg_bits = 7 ,
. val_bits = 9 ,
. max_register = WM8741_MAX_REGISTER ,
. reg_defaults = wm8741_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( wm8741_reg_defaults ) ,
. cache_type = REGCACHE_RBTREE ,
} ;
2015-05-13 11:39:01 +02:00
static int wm8741_set_pdata ( struct device * dev , struct wm8741_priv * wm8741 )
{
const struct wm8741_platform_data * pdata = dev_get_platdata ( dev ) ;
u32 diff_mode ;
if ( dev - > of_node ) {
if ( of_property_read_u32 ( dev - > of_node , " diff-mode " , & diff_mode )
> = 0 )
wm8741 - > pdata . diff_mode = diff_mode ;
} else {
if ( pdata ! = NULL )
memcpy ( & wm8741 - > pdata , pdata , sizeof ( wm8741 - > pdata ) ) ;
}
return 0 ;
}
2013-11-21 12:38:45 -02:00
# if IS_ENABLED(CONFIG_I2C)
2010-03-17 20:15:21 +00:00
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 ) {
2012-09-10 18:00:21 +08:00
dev_err ( & i2c - > dev , " Failed to request supplies: %d \n " , ret ) ;
return ret ;
}
2012-11-22 09:38:37 +05:30
wm8741 - > regmap = devm_regmap_init_i2c ( i2c , & wm8741_regmap ) ;
2012-09-10 18:00:21 +08:00
if ( IS_ERR ( wm8741 - > regmap ) ) {
ret = PTR_ERR ( wm8741 - > regmap ) ;
dev_err ( & i2c - > dev , " Failed to init regmap: %d \n " , ret ) ;
return ret ;
2012-09-10 17:52:59 +08:00
}
2015-05-20 10:40:35 +03:00
ret = wm8741_set_pdata ( & i2c - > dev , wm8741 ) ;
2015-05-13 11:39:01 +02:00
if ( ret ! = 0 ) {
dev_err ( & i2c - > dev , " Failed to set pdata: %d \n " , ret ) ;
return ret ;
}
2010-03-17 20:15:21 +00:00
i2c_set_clientdata ( i2c , wm8741 ) ;
2010-07-31 00:32:11 +01:00
2018-01-29 03:04:06 +00:00
ret = devm_snd_soc_register_component ( & i2c - > dev ,
& soc_component_dev_wm8741 , & wm8741_dai , 1 ) ;
2010-07-31 00:32:11 +01:00
return ret ;
}
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 " ,
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 ,
. id_table = wm8741_i2c_id ,
} ;
# endif
2011-08-03 17:30:57 +09:00
# if defined(CONFIG_SPI_MASTER)
2012-12-07 09:26:37 -05:00
static int wm8741_spi_probe ( struct spi_device * spi )
2011-08-03 17:30:57 +09:00
{
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 ] ;
2012-09-10 18:00:21 +08:00
ret = devm_regulator_bulk_get ( & spi - > dev , ARRAY_SIZE ( wm8741 - > supplies ) ,
2012-09-10 17:52:59 +08:00
wm8741 - > supplies ) ;
if ( ret ! = 0 ) {
dev_err ( & spi - > dev , " Failed to request supplies: %d \n " , ret ) ;
2012-09-10 18:00:21 +08:00
return ret ;
}
2012-11-22 09:38:37 +05:30
wm8741 - > regmap = devm_regmap_init_spi ( spi , & wm8741_regmap ) ;
2012-09-10 18:00:21 +08:00
if ( IS_ERR ( wm8741 - > regmap ) ) {
ret = PTR_ERR ( wm8741 - > regmap ) ;
dev_err ( & spi - > dev , " Failed to init regmap: %d \n " , ret ) ;
return ret ;
2012-09-10 17:52:59 +08:00
}
2015-05-20 10:40:35 +03:00
ret = wm8741_set_pdata ( & spi - > dev , wm8741 ) ;
2015-05-13 11:39:01 +02:00
if ( ret ! = 0 ) {
dev_err ( & spi - > dev , " Failed to set pdata: %d \n " , ret ) ;
return ret ;
}
2011-08-03 17:30:57 +09:00
spi_set_drvdata ( spi , wm8741 ) ;
2018-01-29 03:04:06 +00:00
ret = devm_snd_soc_register_component ( & spi - > dev ,
& soc_component_dev_wm8741 , & wm8741_dai , 1 ) ;
2011-08-03 17:30:57 +09:00
return ret ;
}
static struct spi_driver wm8741_spi_driver = {
. driver = {
. name = " wm8741 " ,
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 ,
} ;
# 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 ;
2013-11-21 12:38:45 -02:00
# if IS_ENABLED(CONFIG_I2C)
2010-07-31 00:32:11 +01:00
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
2013-11-21 12:38:45 -02:00
# if IS_ENABLED(CONFIG_I2C)
2010-07-31 00:32:11 +01:00
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 " ) ;