2019-05-28 20:10:04 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-08-03 11:10:00 +03:00
/*
* Rockchip machine ASoC driver for boards using MAX98357A / RT5514 / DA7219
*
* Copyright ( c ) 2016 , ROCKCHIP CORPORATION . All rights reserved .
*/
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/gpio.h>
# include <linux/of_gpio.h>
# include <linux/delay.h>
# include <linux/spi/spi.h>
2017-09-19 15:57:59 +03:00
# include <linux/i2c.h>
2016-09-16 02:10:06 +03:00
# include <linux/input.h>
2016-08-03 11:10:00 +03:00
# include <sound/core.h>
# include <sound/jack.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include "rockchip_i2s.h"
# include "../codecs/da7219.h"
# include "../codecs/rt5514.h"
# define DRV_NAME "rk3399-gru-sound"
# define SOUND_FS 256
2017-08-22 18:35:48 +03:00
static unsigned int dmic_wakeup_delay ;
2016-09-22 16:50:06 +03:00
2016-08-03 11:10:00 +03:00
static struct snd_soc_jack rockchip_sound_jack ;
2020-07-21 21:27:10 +03:00
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin rockchip_sound_jack_pins [ ] = {
{
. pin = " Headphones " ,
. mask = SND_JACK_HEADPHONE ,
} ,
{
. pin = " Headset Mic " ,
. mask = SND_JACK_MICROPHONE ,
} ,
} ;
2016-08-03 11:10:00 +03:00
static const struct snd_soc_dapm_widget rockchip_dapm_widgets [ ] = {
SND_SOC_DAPM_HP ( " Headphones " , NULL ) ,
SND_SOC_DAPM_SPK ( " Speakers " , NULL ) ,
SND_SOC_DAPM_MIC ( " Headset Mic " , NULL ) ,
SND_SOC_DAPM_MIC ( " Int Mic " , NULL ) ,
2017-09-18 14:17:59 +03:00
SND_SOC_DAPM_LINE ( " HDMI " , NULL ) ,
2016-08-03 11:10:00 +03:00
} ;
static const struct snd_kcontrol_new rockchip_controls [ ] = {
SOC_DAPM_PIN_SWITCH ( " Headphones " ) ,
SOC_DAPM_PIN_SWITCH ( " Speakers " ) ,
SOC_DAPM_PIN_SWITCH ( " Headset Mic " ) ,
SOC_DAPM_PIN_SWITCH ( " Int Mic " ) ,
2017-09-18 14:17:59 +03:00
SOC_DAPM_PIN_SWITCH ( " HDMI " ) ,
2016-08-03 11:10:00 +03:00
} ;
static int rockchip_sound_max98357a_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 04:18:28 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2016-08-03 11:10:00 +03:00
unsigned int mclk ;
int ret ;
2019-06-21 18:58:08 +03:00
mclk = params_rate ( params ) * SOUND_FS ;
2016-08-03 11:10:00 +03:00
2020-03-23 08:20:09 +03:00
ret = snd_soc_dai_set_sysclk ( asoc_rtd_to_cpu ( rtd , 0 ) , 0 , mclk , 0 ) ;
2016-08-03 11:10:00 +03:00
if ( ret ) {
dev_err ( rtd - > card - > dev , " %s() error setting sysclk to %u: %d \n " ,
__func__ , mclk , ret ) ;
return ret ;
}
return 0 ;
}
static int rockchip_sound_rt5514_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 04:18:28 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 08:20:09 +03:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2016-08-03 11:10:00 +03:00
unsigned int mclk ;
int ret ;
mclk = params_rate ( params ) * SOUND_FS ;
ret = snd_soc_dai_set_sysclk ( cpu_dai , 0 , mclk ,
SND_SOC_CLOCK_OUT ) ;
if ( ret < 0 ) {
dev_err ( rtd - > card - > dev , " Can't set cpu clock out %d \n " , ret ) ;
return ret ;
}
ret = snd_soc_dai_set_sysclk ( codec_dai , RT5514_SCLK_S_MCLK ,
mclk , SND_SOC_CLOCK_IN ) ;
if ( ret ) {
dev_err ( rtd - > card - > dev , " %s() error setting sysclk to %u: %d \n " ,
__func__ , params_rate ( params ) * 512 , ret ) ;
return ret ;
}
2016-09-22 16:50:06 +03:00
/* Wait for DMIC stable */
2017-08-22 18:35:48 +03:00
msleep ( dmic_wakeup_delay ) ;
2016-09-22 16:50:06 +03:00
2016-08-03 11:10:00 +03:00
return 0 ;
}
static int rockchip_sound_da7219_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 04:18:28 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 08:20:09 +03:00
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2016-08-03 11:10:00 +03:00
int mclk , ret ;
/* in bypass mode, the mclk has to be one of the frequencies below */
switch ( params_rate ( params ) ) {
case 8000 :
case 16000 :
case 24000 :
case 32000 :
case 48000 :
case 64000 :
case 96000 :
mclk = 12288000 ;
break ;
case 11025 :
case 22050 :
case 44100 :
case 88200 :
mclk = 11289600 ;
break ;
default :
return - EINVAL ;
}
ret = snd_soc_dai_set_sysclk ( cpu_dai , 0 , mclk ,
SND_SOC_CLOCK_OUT ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " Can't set cpu clock out %d \n " , ret ) ;
return ret ;
}
ret = snd_soc_dai_set_sysclk ( codec_dai , 0 , mclk ,
SND_SOC_CLOCK_IN ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " Can't set codec clock in %d \n " , ret ) ;
return ret ;
}
ret = snd_soc_dai_set_pll ( codec_dai , 0 , DA7219_SYSCLK_MCLK , 0 , 0 ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " Can't set pll sysclk mclk %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
2022-01-15 02:02:09 +03:00
static struct snd_soc_jack cdn_dp_card_jack ;
static int rockchip_sound_cdndp_init ( struct snd_soc_pcm_runtime * rtd )
{
struct snd_soc_component * component = asoc_rtd_to_codec ( rtd , 0 ) - > component ;
struct snd_soc_card * card = rtd - > card ;
int ret ;
/* Enable jack detection. */
ret = snd_soc_card_jack_new ( card , " DP Jack " , SND_JACK_LINEOUT ,
2022-04-08 07:11:14 +03:00
& cdn_dp_card_jack ) ;
2022-01-15 02:02:09 +03:00
if ( ret ) {
dev_err ( card - > dev , " Can't create DP Jack %d \n " , ret ) ;
return ret ;
}
return snd_soc_component_set_jack ( component , & cdn_dp_card_jack , NULL ) ;
}
2016-08-03 11:10:00 +03:00
static int rockchip_sound_da7219_init ( struct snd_soc_pcm_runtime * rtd )
{
2020-03-23 08:20:09 +03:00
struct snd_soc_component * component = asoc_rtd_to_codec ( rtd , 0 ) - > component ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2016-08-03 11:10:00 +03:00
int ret ;
/* We need default MCLK and PLL settings for the accessory detection */
ret = snd_soc_dai_set_sysclk ( codec_dai , 0 , 12288000 ,
SND_SOC_CLOCK_IN ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " Init can't set codec clock in %d \n " , ret ) ;
return ret ;
}
ret = snd_soc_dai_set_pll ( codec_dai , 0 , DA7219_SYSCLK_MCLK , 0 , 0 ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " Init can't set pll sysclk mclk %d \n " , ret ) ;
return ret ;
}
/* Enable Headset and 4 Buttons Jack detection */
2022-04-08 07:11:14 +03:00
ret = snd_soc_card_jack_new_pins ( rtd - > card , " Headset Jack " ,
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 ,
& rockchip_sound_jack ,
rockchip_sound_jack_pins ,
ARRAY_SIZE ( rockchip_sound_jack_pins ) ) ;
2016-08-03 11:10:00 +03:00
if ( ret ) {
dev_err ( rtd - > card - > dev , " New Headset Jack failed! (%d) \n " , ret ) ;
return ret ;
}
2017-11-22 23:56:42 +03:00
snd_jack_set_key (
rockchip_sound_jack . jack , SND_JACK_BTN_0 , KEY_PLAYPAUSE ) ;
2016-09-16 02:10:06 +03:00
snd_jack_set_key (
rockchip_sound_jack . jack , SND_JACK_BTN_1 , KEY_VOLUMEUP ) ;
snd_jack_set_key (
rockchip_sound_jack . jack , SND_JACK_BTN_2 , KEY_VOLUMEDOWN ) ;
snd_jack_set_key (
rockchip_sound_jack . jack , SND_JACK_BTN_3 , KEY_VOICECOMMAND ) ;
2022-10-31 19:02:24 +03:00
snd_soc_component_set_jack ( component , & rockchip_sound_jack , NULL ) ;
2016-08-03 11:10:00 +03:00
return 0 ;
}
2017-08-24 07:52:26 +03:00
static int rockchip_sound_dmic_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-20 04:18:28 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2017-08-24 07:52:26 +03:00
unsigned int mclk ;
int ret ;
mclk = params_rate ( params ) * SOUND_FS ;
2020-03-23 08:20:09 +03:00
ret = snd_soc_dai_set_sysclk ( asoc_rtd_to_cpu ( rtd , 0 ) , 0 , mclk , 0 ) ;
2017-08-24 07:52:26 +03:00
if ( ret ) {
dev_err ( rtd - > card - > dev , " %s() error setting sysclk to %u: %d \n " ,
__func__ , mclk , ret ) ;
return ret ;
}
/* Wait for DMIC stable */
msleep ( dmic_wakeup_delay ) ;
return 0 ;
}
2020-06-30 12:16:15 +03:00
static int rockchip_sound_startup ( struct snd_pcm_substream * substream )
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
runtime - > hw . formats = SNDRV_PCM_FMTBIT_S16_LE ;
return snd_pcm_hw_constraint_minmax ( runtime , SNDRV_PCM_HW_PARAM_RATE ,
8000 , 96000 ) ;
}
2016-10-15 17:55:47 +03:00
static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
2020-06-30 12:16:15 +03:00
. startup = rockchip_sound_startup ,
2016-08-03 11:10:00 +03:00
. hw_params = rockchip_sound_max98357a_hw_params ,
} ;
2016-10-15 17:55:47 +03:00
static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
2020-06-30 12:16:15 +03:00
. startup = rockchip_sound_startup ,
2016-08-03 11:10:00 +03:00
. hw_params = rockchip_sound_rt5514_hw_params ,
} ;
2016-10-15 17:55:47 +03:00
static const struct snd_soc_ops rockchip_sound_da7219_ops = {
2020-06-30 12:16:15 +03:00
. startup = rockchip_sound_startup ,
2016-08-03 11:10:00 +03:00
. hw_params = rockchip_sound_da7219_hw_params ,
} ;
2017-08-30 12:58:14 +03:00
static const struct snd_soc_ops rockchip_sound_dmic_ops = {
2020-06-30 12:16:15 +03:00
. startup = rockchip_sound_startup ,
2017-08-24 07:52:26 +03:00
. hw_params = rockchip_sound_dmic_hw_params ,
} ;
2017-08-24 07:52:24 +03:00
static struct snd_soc_card rockchip_sound_card = {
. name = " rk3399-gru-sound " ,
. owner = THIS_MODULE ,
. dapm_widgets = rockchip_dapm_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( rockchip_dapm_widgets ) ,
. controls = rockchip_controls ,
. num_controls = ARRAY_SIZE ( rockchip_controls ) ,
} ;
2016-08-03 11:10:00 +03:00
enum {
2017-08-24 07:52:25 +03:00
DAILINK_CDNDP ,
2017-08-24 07:52:24 +03:00
DAILINK_DA7219 ,
2017-08-24 07:52:26 +03:00
DAILINK_DMIC ,
2016-08-03 11:10:00 +03:00
DAILINK_MAX98357A ,
DAILINK_RT5514 ,
2016-08-19 16:56:12 +03:00
DAILINK_RT5514_DSP ,
2016-08-03 11:10:00 +03:00
} ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( cdndp ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_CODEC ( NULL , " spdif-hifi " ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( da7219 ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_CODEC ( NULL , " da7219-hifi " ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( dmic ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_CODEC ( NULL , " dmic-hifi " ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( max98357a ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_CODEC ( NULL , " HiFi " ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( rt5514 ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_CODEC ( NULL , " rt5514-aif1 " ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_DEFS ( rt5514_dsp ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ,
2019-06-28 04:49:52 +03:00
DAILINK_COMP_ARRAY ( COMP_DUMMY ( ) ) ,
DAILINK_COMP_ARRAY ( COMP_EMPTY ( ) ) ) ;
2019-06-06 07:17:10 +03:00
2017-08-24 07:52:24 +03:00
static const struct snd_soc_dai_link rockchip_dais [ ] = {
2017-08-24 07:52:25 +03:00
[ DAILINK_CDNDP ] = {
. name = " DP " ,
. stream_name = " DP PCM " ,
2022-01-15 02:02:09 +03:00
. init = rockchip_sound_cdndp_init ,
2017-08-24 07:52:25 +03:00
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( cdndp ) ,
2017-08-24 07:52:25 +03:00
} ,
2017-08-24 07:52:24 +03:00
[ DAILINK_DA7219 ] = {
. name = " DA7219 " ,
. stream_name = " DA7219 PCM " ,
. init = rockchip_sound_da7219_init ,
. ops = & rockchip_sound_da7219_ops ,
/* set da7219 as slave */
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( da7219 ) ,
2017-08-24 07:52:24 +03:00
} ,
2017-08-24 07:52:26 +03:00
[ DAILINK_DMIC ] = {
. name = " DMIC " ,
. stream_name = " DMIC PCM " ,
. ops = & rockchip_sound_dmic_ops ,
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( dmic ) ,
2017-08-24 07:52:26 +03:00
} ,
2016-08-03 11:10:00 +03:00
[ DAILINK_MAX98357A ] = {
. name = " MAX98357A " ,
. stream_name = " MAX98357A PCM " ,
. ops = & rockchip_sound_max98357a_ops ,
/* set max98357a as slave */
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( max98357a ) ,
2016-08-03 11:10:00 +03:00
} ,
[ DAILINK_RT5514 ] = {
. name = " RT5514 " ,
. stream_name = " RT5514 PCM " ,
. ops = & rockchip_sound_rt5514_ops ,
/* set rt5514 as slave */
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( rt5514 ) ,
2016-08-03 11:10:00 +03:00
} ,
2016-08-19 16:56:12 +03:00
/* RT5514 DSP for voice wakeup via spi bus */
[ DAILINK_RT5514_DSP ] = {
. name = " RT5514 DSP " ,
. stream_name = " Wake on Voice " ,
2019-06-06 07:17:10 +03:00
SND_SOC_DAILINK_REG ( rt5514_dsp ) ,
2016-08-19 16:56:12 +03:00
} ,
2016-08-03 11:10:00 +03:00
} ;
2017-09-19 15:57:58 +03:00
static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes [ ] = {
/* Output */
{ " HDMI " , NULL , " TX " } ,
} ;
static const struct snd_soc_dapm_route rockchip_sound_da7219_routes [ ] = {
/* Output */
{ " Headphones " , NULL , " HPL " } ,
{ " Headphones " , NULL , " HPR " } ,
/* Input */
{ " MIC " , NULL , " Headset Mic " } ,
} ;
static const struct snd_soc_dapm_route rockchip_sound_dmic_routes [ ] = {
/* Input */
{ " DMic " , NULL , " Int Mic " } ,
} ;
static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes [ ] = {
/* Output */
{ " Speakers " , NULL , " Speaker " } ,
} ;
static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes [ ] = {
/* Input */
{ " DMIC1L " , NULL , " Int Mic " } ,
{ " DMIC1R " , NULL , " Int Mic " } ,
} ;
struct rockchip_sound_route {
const struct snd_soc_dapm_route * routes ;
int num_routes ;
} ;
static const struct rockchip_sound_route rockchip_routes [ ] = {
[ DAILINK_CDNDP ] = {
. routes = rockchip_sound_cdndp_routes ,
. num_routes = ARRAY_SIZE ( rockchip_sound_cdndp_routes ) ,
} ,
[ DAILINK_DA7219 ] = {
. routes = rockchip_sound_da7219_routes ,
. num_routes = ARRAY_SIZE ( rockchip_sound_da7219_routes ) ,
} ,
[ DAILINK_DMIC ] = {
. routes = rockchip_sound_dmic_routes ,
. num_routes = ARRAY_SIZE ( rockchip_sound_dmic_routes ) ,
} ,
[ DAILINK_MAX98357A ] = {
. routes = rockchip_sound_max98357a_routes ,
. num_routes = ARRAY_SIZE ( rockchip_sound_max98357a_routes ) ,
} ,
[ DAILINK_RT5514 ] = {
. routes = rockchip_sound_rt5514_routes ,
. num_routes = ARRAY_SIZE ( rockchip_sound_rt5514_routes ) ,
} ,
[ DAILINK_RT5514_DSP ] = { } ,
} ;
2017-09-19 15:57:59 +03:00
struct dailink_match_data {
const char * compatible ;
struct bus_type * bus_type ;
} ;
static const struct dailink_match_data dailink_match [ ] = {
[ DAILINK_CDNDP ] = {
. compatible = " rockchip,rk3399-cdn-dp " ,
} ,
[ DAILINK_DA7219 ] = {
. compatible = " dlg,da7219 " ,
} ,
[ DAILINK_DMIC ] = {
. compatible = " dmic-codec " ,
} ,
[ DAILINK_MAX98357A ] = {
. compatible = " maxim,max98357a " ,
} ,
[ DAILINK_RT5514 ] = {
. compatible = " realtek,rt5514 " ,
. bus_type = & i2c_bus_type ,
} ,
[ DAILINK_RT5514_DSP ] = {
. compatible = " realtek,rt5514 " ,
. bus_type = & spi_bus_type ,
} ,
} ;
2017-08-24 07:52:24 +03:00
static int rockchip_sound_codec_node_match ( struct device_node * np_codec )
2016-08-19 16:56:12 +03:00
{
2017-09-19 15:57:59 +03:00
struct device * dev ;
2017-08-24 07:52:24 +03:00
int i ;
2016-08-19 16:56:12 +03:00
2017-09-19 15:57:59 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( dailink_match ) ; i + + ) {
if ( ! of_device_is_compatible ( np_codec ,
dailink_match [ i ] . compatible ) )
continue ;
if ( dailink_match [ i ] . bus_type ) {
2019-07-24 01:18:33 +03:00
dev = bus_find_device_by_of_node ( dailink_match [ i ] . bus_type ,
np_codec ) ;
2017-09-19 15:57:59 +03:00
if ( ! dev )
continue ;
put_device ( dev ) ;
}
return i ;
2016-08-03 11:10:00 +03:00
}
2017-08-24 07:52:24 +03:00
return - 1 ;
}
2016-08-03 11:10:00 +03:00
2017-08-24 07:52:24 +03:00
static int rockchip_sound_of_parse_dais ( struct device * dev ,
struct snd_soc_card * card )
{
2017-08-24 07:52:25 +03:00
struct device_node * np_cpu , * np_cpu0 , * np_cpu1 ;
2017-08-24 07:52:24 +03:00
struct device_node * np_codec ;
struct snd_soc_dai_link * dai ;
2017-09-19 15:57:58 +03:00
struct snd_soc_dapm_route * routes ;
2017-08-24 07:52:24 +03:00
int i , index ;
2017-09-30 01:03:24 +03:00
int num_routes ;
2017-08-24 07:52:24 +03:00
card - > dai_link = devm_kzalloc ( dev , sizeof ( rockchip_dais ) ,
GFP_KERNEL ) ;
if ( ! card - > dai_link )
return - ENOMEM ;
2017-09-30 01:03:24 +03:00
num_routes = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( rockchip_routes ) ; i + + )
num_routes + = rockchip_routes [ i ] . num_routes ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
routes = devm_kcalloc ( dev , num_routes , sizeof ( * routes ) ,
2017-09-19 15:57:58 +03:00
GFP_KERNEL ) ;
if ( ! routes )
return - ENOMEM ;
card - > dapm_routes = routes ;
2017-08-24 07:52:25 +03:00
np_cpu0 = of_parse_phandle ( dev - > of_node , " rockchip,cpu " , 0 ) ;
np_cpu1 = of_parse_phandle ( dev - > of_node , " rockchip,cpu " , 1 ) ;
2017-08-24 07:52:24 +03:00
2017-09-19 15:57:58 +03:00
card - > num_dapm_routes = 0 ;
2017-08-24 07:52:24 +03:00
card - > num_links = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( rockchip_dais ) ; i + + ) {
np_codec = of_parse_phandle ( dev - > of_node ,
" rockchip,codec " , i ) ;
if ( ! np_codec )
break ;
if ( ! of_device_is_available ( np_codec ) )
continue ;
index = rockchip_sound_codec_node_match ( np_codec ) ;
if ( index < 0 )
continue ;
2017-11-21 11:25:17 +03:00
switch ( index ) {
case DAILINK_CDNDP :
np_cpu = np_cpu1 ;
break ;
case DAILINK_RT5514_DSP :
np_cpu = np_codec ;
break ;
default :
np_cpu = np_cpu0 ;
break ;
}
2017-08-24 07:52:24 +03:00
if ( ! np_cpu ) {
dev_err ( dev , " Missing 'rockchip,cpu' for %s \n " ,
rockchip_dais [ index ] . name ) ;
2016-08-03 11:10:00 +03:00
return - EINVAL ;
}
2017-08-24 07:52:24 +03:00
dai = & card - > dai_link [ card - > num_links + + ] ;
* dai = rockchip_dais [ index ] ;
2019-06-06 07:17:10 +03:00
if ( ! dai - > codecs - > name )
dai - > codecs - > of_node = np_codec ;
2019-06-28 04:49:52 +03:00
dai - > platforms - > of_node = np_cpu ;
2019-06-06 07:17:10 +03:00
dai - > cpus - > of_node = np_cpu ;
2017-09-19 15:57:58 +03:00
2017-09-30 01:03:24 +03:00
if ( card - > num_dapm_routes + rockchip_routes [ index ] . num_routes >
num_routes ) {
dev_err ( dev , " Too many routes \n " ) ;
return - EINVAL ;
}
2017-09-19 15:57:58 +03:00
memcpy ( routes + card - > num_dapm_routes ,
rockchip_routes [ index ] . routes ,
rockchip_routes [ index ] . num_routes * sizeof ( * routes ) ) ;
card - > num_dapm_routes + = rockchip_routes [ index ] . num_routes ;
2016-08-19 16:56:12 +03:00
}
2017-08-24 07:52:24 +03:00
return 0 ;
}
static int rockchip_sound_probe ( struct platform_device * pdev )
{
struct snd_soc_card * card = & rockchip_sound_card ;
int ret ;
ret = rockchip_sound_of_parse_dais ( & pdev - > dev , card ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Failed to parse dais: %d \n " , ret ) ;
return ret ;
2016-08-19 16:56:12 +03:00
}
2017-08-22 18:35:48 +03:00
/* Set DMIC wakeup delay */
ret = device_property_read_u32 ( & pdev - > dev , " dmic-wakeup-delay-ms " ,
& dmic_wakeup_delay ) ;
2016-09-22 16:50:06 +03:00
if ( ret ) {
2017-08-22 18:35:48 +03:00
dmic_wakeup_delay = 0 ;
2016-09-22 16:50:06 +03:00
dev_dbg ( & pdev - > dev ,
2017-08-22 18:35:48 +03:00
" no optional property 'dmic-wakeup-delay-ms' found, default: no delay \n " ) ;
2016-09-22 16:50:06 +03:00
}
2016-08-03 11:10:00 +03:00
card - > dev = & pdev - > dev ;
2017-08-24 07:52:24 +03:00
return devm_snd_soc_register_card ( & pdev - > dev , card ) ;
2016-08-03 11:10:00 +03:00
}
static const struct of_device_id rockchip_sound_of_match [ ] = {
{ . compatible = " rockchip,rk3399-gru-sound " , } ,
{ } ,
} ;
static struct platform_driver rockchip_sound_driver = {
. probe = rockchip_sound_probe ,
. driver = {
. name = DRV_NAME ,
. of_match_table = rockchip_sound_of_match ,
# ifdef CONFIG_PM
. pm = & snd_soc_pm_ops ,
# endif
} ,
} ;
module_platform_driver ( rockchip_sound_driver ) ;
MODULE_AUTHOR ( " Xing Zheng <zhengxing@rock-chips.com> " ) ;
MODULE_DESCRIPTION ( " Rockchip ASoC Machine Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;
MODULE_DEVICE_TABLE ( of , rockchip_sound_of_match ) ;