2018-07-02 06:30:28 +00:00
// SPDX-License-Identifier: GPL-2.0
//
// ASoC simple sound card support
//
// Copyright (C) 2012 Renesas Solutions Corp.
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
2013-11-20 15:25:02 +09:00
# include <linux/clk.h>
2014-02-14 09:34:36 +08:00
# include <linux/device.h>
2012-04-08 21:17:50 -07:00
# include <linux/module.h>
2013-11-20 15:25:02 +09:00
# include <linux/of.h>
2012-04-08 21:17:50 -07:00
# include <linux/platform_device.h>
2014-01-14 12:35:32 +08:00
# include <linux/string.h>
2012-04-08 21:17:50 -07:00
# include <sound/simple_card.h>
2014-02-14 09:34:36 +08:00
# include <sound/soc-dai.h>
# include <sound/soc.h>
2012-04-08 21:17:50 -07:00
2014-01-15 16:51:56 +01:00
struct simple_card_data {
struct snd_soc_card snd_card ;
2014-03-20 10:52:41 +01:00
struct simple_dai_props {
2018-12-04 08:19:43 +00:00
struct asoc_simple_dai * cpu_dai ;
struct asoc_simple_dai * codec_dai ;
2018-08-31 03:08:24 +00:00
struct snd_soc_dai_link_component codecs ; /* single codec */
2018-08-31 03:10:33 +00:00
struct snd_soc_dai_link_component platform ;
2018-12-14 11:35:10 +09:00
struct asoc_simple_card_data adata ;
struct snd_soc_codec_conf * codec_conf ;
2015-06-05 10:19:05 +02:00
unsigned int mclk_fs ;
2014-03-20 10:52:41 +01:00
} * dai_props ;
2014-05-22 17:31:49 +02:00
unsigned int mclk_fs ;
2016-05-31 08:59:46 +00:00
struct asoc_simple_jack hp_jack ;
struct asoc_simple_jack mic_jack ;
2016-08-26 03:10:25 +00:00
struct snd_soc_dai_link * dai_link ;
2018-12-04 08:19:43 +00:00
struct asoc_simple_dai * dais ;
2018-12-14 11:35:10 +09:00
struct asoc_simple_card_data adata ;
struct snd_soc_codec_conf * codec_conf ;
2014-01-15 16:51:56 +01:00
} ;
2017-03-15 04:44:00 +00:00
# define simple_priv_to_card(priv) (&(priv)->snd_card)
2016-08-26 03:06:23 +00:00
# define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
2017-03-15 04:44:00 +00:00
# define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
# define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
2014-09-09 21:37:57 -07:00
2016-08-08 06:02:07 +00:00
# define DAI "sound-dai"
# define CELL "#sound-dai-cells"
2016-05-31 08:59:01 +00:00
# define PREFIX "simple-audio-card,"
2015-01-13 21:16:34 +02:00
static int asoc_simple_card_startup ( struct snd_pcm_substream * substream )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct simple_card_data * priv = snd_soc_card_get_drvdata ( rtd - > card ) ;
struct simple_dai_props * dai_props =
2016-08-26 03:06:51 +00:00
simple_priv_to_props ( priv , rtd - > num ) ;
2015-01-13 21:16:34 +02:00
int ret ;
2018-12-04 08:19:43 +00:00
ret = asoc_simple_card_clk_enable ( dai_props - > cpu_dai ) ;
2015-01-13 21:16:34 +02:00
if ( ret )
return ret ;
2016-08-26 03:07:59 +00:00
2018-12-04 08:19:43 +00:00
ret = asoc_simple_card_clk_enable ( dai_props - > codec_dai ) ;
2015-01-13 21:16:34 +02:00
if ( ret )
2018-12-04 08:19:43 +00:00
asoc_simple_card_clk_disable ( dai_props - > cpu_dai ) ;
2015-01-13 21:16:34 +02:00
return ret ;
}
static void asoc_simple_card_shutdown ( struct snd_pcm_substream * substream )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct simple_card_data * priv = snd_soc_card_get_drvdata ( rtd - > card ) ;
struct simple_dai_props * dai_props =
2016-08-26 03:06:51 +00:00
simple_priv_to_props ( priv , rtd - > num ) ;
2015-01-13 21:16:34 +02:00
2018-12-04 08:19:43 +00:00
asoc_simple_card_clk_disable ( dai_props - > cpu_dai ) ;
2015-01-13 21:16:34 +02:00
2018-12-04 08:19:43 +00:00
asoc_simple_card_clk_disable ( dai_props - > codec_dai ) ;
2015-01-13 21:16:34 +02:00
}
2018-05-30 21:45:56 +02:00
static int asoc_simple_set_clk_rate ( struct asoc_simple_dai * simple_dai ,
unsigned long rate )
{
2018-12-14 11:35:10 +09:00
if ( ! simple_dai )
return 0 ;
2018-05-30 21:45:56 +02:00
if ( ! simple_dai - > clk )
return 0 ;
if ( clk_get_rate ( simple_dai - > clk ) = = rate )
return 0 ;
return clk_set_rate ( simple_dai - > clk , rate ) ;
}
2014-05-22 17:31:49 +02:00
static int asoc_simple_card_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 ;
2015-06-05 10:19:06 +02:00
struct snd_soc_dai * cpu_dai = rtd - > cpu_dai ;
2014-05-22 17:31:49 +02:00
struct simple_card_data * priv = snd_soc_card_get_drvdata ( rtd - > card ) ;
2016-08-26 03:06:51 +00:00
struct simple_dai_props * dai_props =
simple_priv_to_props ( priv , rtd - > num ) ;
2015-06-05 10:19:05 +02:00
unsigned int mclk , mclk_fs = 0 ;
2014-05-22 17:31:49 +02:00
int ret = 0 ;
2015-06-05 10:19:05 +02:00
if ( priv - > mclk_fs )
mclk_fs = priv - > mclk_fs ;
else if ( dai_props - > mclk_fs )
mclk_fs = dai_props - > mclk_fs ;
if ( mclk_fs ) {
mclk = params_rate ( params ) * mclk_fs ;
2018-05-30 21:45:56 +02:00
2018-12-04 08:19:43 +00:00
ret = asoc_simple_set_clk_rate ( dai_props - > codec_dai , mclk ) ;
2018-05-30 21:45:56 +02:00
if ( ret < 0 )
return ret ;
2018-12-04 08:19:43 +00:00
ret = asoc_simple_set_clk_rate ( dai_props - > cpu_dai , mclk ) ;
2018-05-30 21:45:56 +02:00
if ( ret < 0 )
return ret ;
2014-05-22 17:31:49 +02:00
ret = snd_soc_dai_set_sysclk ( codec_dai , 0 , mclk ,
SND_SOC_CLOCK_IN ) ;
2015-06-05 10:19:06 +02:00
if ( ret & & ret ! = - ENOTSUPP )
goto err ;
ret = snd_soc_dai_set_sysclk ( cpu_dai , 0 , mclk ,
SND_SOC_CLOCK_OUT ) ;
if ( ret & & ret ! = - ENOTSUPP )
goto err ;
2014-05-22 17:31:49 +02:00
}
2016-01-24 00:36:40 +02:00
return 0 ;
2015-06-05 10:19:06 +02:00
err :
2014-05-22 17:31:49 +02:00
return ret ;
}
2016-10-15 16:55:49 +02:00
static const struct snd_soc_ops asoc_simple_card_ops = {
2015-01-13 21:16:34 +02:00
. startup = asoc_simple_card_startup ,
. shutdown = asoc_simple_card_shutdown ,
2014-05-22 17:31:49 +02:00
. hw_params = asoc_simple_card_hw_params ,
} ;
2012-04-08 21:17:50 -07:00
static int asoc_simple_card_dai_init ( struct snd_soc_pcm_runtime * rtd )
{
2014-04-24 19:14:00 +08:00
struct simple_card_data * priv = snd_soc_card_get_drvdata ( rtd - > card ) ;
2018-12-04 08:19:43 +00:00
struct simple_dai_props * dai_props = simple_priv_to_props ( priv , rtd - > num ) ;
2015-11-18 02:34:11 -05:00
int ret ;
2012-04-08 21:17:50 -07:00
2018-12-04 08:19:43 +00:00
ret = asoc_simple_card_init_dai ( rtd - > codec_dai ,
dai_props - > codec_dai ) ;
2013-01-10 16:49:11 -08:00
if ( ret < 0 )
return ret ;
2012-04-08 21:17:50 -07:00
2018-12-04 08:19:43 +00:00
ret = asoc_simple_card_init_dai ( rtd - > cpu_dai ,
dai_props - > cpu_dai ) ;
2013-01-10 16:49:11 -08:00
if ( ret < 0 )
return ret ;
2012-04-08 21:17:50 -07:00
return 0 ;
}
2018-12-14 11:35:10 +09:00
static int asoc_simple_card_be_hw_params_fixup ( struct snd_soc_pcm_runtime * rtd ,
struct snd_pcm_hw_params * params )
{
struct simple_card_data * priv = snd_soc_card_get_drvdata ( rtd - > card ) ;
struct simple_dai_props * dai_props = simple_priv_to_props ( priv , rtd - > num ) ;
asoc_simple_card_convert_fixup ( & dai_props - > adata , params ) ;
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup ( & priv - > adata , params ) ;
return 0 ;
}
static int asoc_simple_card_dai_link_of_dpcm ( struct device_node * node ,
struct device_node * np ,
struct device_node * codec ,
struct simple_card_data * priv ,
int * dai_idx , int link_idx ,
int * conf_idx , int is_fe ,
bool is_top_level_node )
{
struct device * dev = simple_priv_to_dev ( priv ) ;
struct snd_soc_dai_link * dai_link = simple_priv_to_link ( priv , link_idx ) ;
struct simple_dai_props * dai_props = simple_priv_to_props ( priv , link_idx ) ;
struct snd_soc_card * card = simple_priv_to_card ( priv ) ;
struct asoc_simple_dai * dai ;
char * prefix = " " ;
int ret ;
/* For single DAI link & old style of DT node */
if ( is_top_level_node )
prefix = PREFIX ;
if ( is_fe ) {
int is_single_links = 0 ;
struct snd_soc_dai_link_component * codecs ;
/* BE is dummy */
codecs = dai_link - > codecs ;
codecs - > of_node = NULL ;
codecs - > dai_name = " snd-soc-dummy-dai " ;
codecs - > name = " snd-soc-dummy " ;
/* FE settings */
dai_link - > dynamic = 1 ;
dai_link - > dpcm_merged_format = 1 ;
dai =
dai_props - > cpu_dai = & priv - > dais [ ( * dai_idx ) + + ] ;
ret = asoc_simple_card_parse_cpu ( np , dai_link , DAI , CELL ,
& is_single_links ) ;
if ( ret )
return ret ;
ret = asoc_simple_card_parse_clk_cpu ( dev , np , dai_link , dai ) ;
if ( ret < 0 )
return ret ;
ret = asoc_simple_card_set_dailink_name ( dev , dai_link ,
" fe.%s " ,
dai_link - > cpu_dai_name ) ;
if ( ret < 0 )
return ret ;
asoc_simple_card_canonicalize_cpu ( dai_link , is_single_links ) ;
} else {
struct snd_soc_codec_conf * cconf ;
/* FE is dummy */
dai_link - > cpu_of_node = NULL ;
dai_link - > cpu_dai_name = " snd-soc-dummy-dai " ;
dai_link - > cpu_name = " snd-soc-dummy " ;
/* BE settings */
dai_link - > no_pcm = 1 ;
dai_link - > be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup ;
dai =
dai_props - > codec_dai = & priv - > dais [ ( * dai_idx ) + + ] ;
cconf =
dai_props - > codec_conf = & priv - > codec_conf [ ( * conf_idx ) + + ] ;
ret = asoc_simple_card_parse_codec ( np , dai_link , DAI , CELL ) ;
if ( ret < 0 )
return ret ;
ret = asoc_simple_card_parse_clk_codec ( dev , np , dai_link , dai ) ;
if ( ret < 0 )
return ret ;
ret = asoc_simple_card_set_dailink_name ( dev , dai_link ,
" be.%s " ,
dai_link - > codecs - > dai_name ) ;
if ( ret < 0 )
return ret ;
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix ( card , cconf ,
dai_link - > codecs - > of_node ,
PREFIX " prefix " ) ;
/* check "prefix" from each node if top doesn't have */
if ( ! cconf - > of_node )
snd_soc_of_parse_node_prefix ( np , cconf ,
dai_link - > codecs - > of_node ,
" prefix " ) ;
}
asoc_simple_card_parse_convert ( dev , node , prefix , & dai_props - > adata ) ;
ret = asoc_simple_card_of_parse_tdm ( np , dai ) ;
if ( ret )
return ret ;
ret = asoc_simple_card_canonicalize_dailink ( dai_link ) ;
if ( ret < 0 )
return ret ;
of_property_read_u32 ( np , " mclk-fs " , & dai_props - > mclk_fs ) ;
ret = asoc_simple_card_parse_daifmt ( dev , node , codec ,
prefix , & dai_link - > dai_fmt ) ;
if ( ret < 0 )
return ret ;
dai_link - > dpcm_playback = 1 ;
dai_link - > dpcm_capture = 1 ;
dai_link - > ops = & asoc_simple_card_ops ;
dai_link - > init = asoc_simple_card_dai_init ;
return 0 ;
}
2014-08-27 20:07:46 -07:00
static int asoc_simple_card_dai_link_of ( struct device_node * node ,
2014-09-09 21:37:57 -07:00
struct simple_card_data * priv ,
2018-12-04 08:19:43 +00:00
int * dai_idx , int link_idx ,
2014-08-27 20:07:46 -07:00
bool is_top_level_node )
2014-03-20 11:49:55 +01:00
{
2014-09-09 21:37:57 -07:00
struct device * dev = simple_priv_to_dev ( priv ) ;
2018-12-04 08:19:43 +00:00
struct snd_soc_dai_link * dai_link = simple_priv_to_link ( priv , link_idx ) ;
struct simple_dai_props * dai_props = simple_priv_to_props ( priv , link_idx ) ;
struct asoc_simple_dai * cpu_dai ;
struct asoc_simple_dai * codec_dai ;
2014-10-27 18:04:52 -07:00
struct device_node * cpu = NULL ;
2015-04-29 18:11:07 +08:00
struct device_node * plat = NULL ;
2014-10-27 18:04:52 -07:00
struct device_node * codec = NULL ;
2014-03-24 12:15:25 +02:00
char prop [ 128 ] ;
char * prefix = " " ;
2016-08-08 06:02:07 +00:00
int ret , single_cpu ;
2014-03-20 11:49:55 +01:00
2014-09-03 10:23:39 +08:00
/* For single DAI link & old style of DT node */
2014-04-24 19:42:00 +03:00
if ( is_top_level_node )
2016-05-31 08:59:01 +00:00
prefix = PREFIX ;
2014-03-24 12:15:25 +02:00
snprintf ( prop , sizeof ( prop ) , " %scpu " , prefix ) ;
2014-10-27 18:04:52 -07:00
cpu = of_get_child_by_name ( node , prop ) ;
2017-05-24 12:28:23 +02:00
if ( ! cpu ) {
ret = - EINVAL ;
dev_err ( dev , " %s: Can't find %s DT node \n " , __func__ , prop ) ;
goto dai_link_of_err ;
}
2015-04-29 18:11:07 +08:00
snprintf ( prop , sizeof ( prop ) , " %splat " , prefix ) ;
plat = of_get_child_by_name ( node , prop ) ;
2014-10-27 18:04:52 -07:00
snprintf ( prop , sizeof ( prop ) , " %scodec " , prefix ) ;
codec = of_get_child_by_name ( node , prop ) ;
2017-05-24 12:28:23 +02:00
if ( ! codec ) {
2014-03-24 12:15:25 +02:00
ret = - EINVAL ;
2014-04-24 19:13:59 +08:00
dev_err ( dev , " %s: Can't find %s DT node \n " , __func__ , prop ) ;
2014-03-24 12:15:25 +02:00
goto dai_link_of_err ;
2014-03-20 11:49:55 +01:00
}
2014-03-24 12:15:25 +02:00
2018-12-04 08:19:43 +00:00
cpu_dai =
dai_props - > cpu_dai = & priv - > dais [ ( * dai_idx ) + + ] ;
codec_dai =
dai_props - > codec_dai = & priv - > dais [ ( * dai_idx ) + + ] ;
2016-06-30 06:02:46 +00:00
ret = asoc_simple_card_parse_daifmt ( dev , node , codec ,
prefix , & dai_link - > dai_fmt ) ;
2014-10-27 18:04:52 -07:00
if ( ret < 0 )
goto dai_link_of_err ;
2016-08-26 03:05:58 +00:00
of_property_read_u32 ( node , " mclk-fs " , & dai_props - > mclk_fs ) ;
2015-06-05 10:19:05 +02:00
2016-08-08 06:02:07 +00:00
ret = asoc_simple_card_parse_cpu ( cpu , dai_link ,
DAI , CELL , & single_cpu ) ;
if ( ret < 0 )
goto dai_link_of_err ;
ret = asoc_simple_card_parse_codec ( codec , dai_link , DAI , CELL ) ;
if ( ret < 0 )
goto dai_link_of_err ;
ret = asoc_simple_card_parse_platform ( plat , dai_link , DAI , CELL ) ;
if ( ret < 0 )
goto dai_link_of_err ;
2017-06-14 00:34:53 +00:00
ret = asoc_simple_card_of_parse_tdm ( cpu , cpu_dai ) ;
2014-03-24 12:15:25 +02:00
if ( ret < 0 )
goto dai_link_of_err ;
2017-06-14 00:34:53 +00:00
ret = asoc_simple_card_of_parse_tdm ( codec , codec_dai ) ;
2016-05-20 09:40:41 +00:00
if ( ret < 0 )
goto dai_link_of_err ;
2017-01-23 07:29:42 +00:00
ret = asoc_simple_card_parse_clk_cpu ( dev , cpu , dai_link , cpu_dai ) ;
2016-07-19 02:53:13 +00:00
if ( ret < 0 )
goto dai_link_of_err ;
2017-01-23 07:29:42 +00:00
ret = asoc_simple_card_parse_clk_codec ( dev , codec , dai_link , codec_dai ) ;
2016-07-19 02:53:13 +00:00
if ( ret < 0 )
goto dai_link_of_err ;
2016-08-09 05:50:02 +00:00
ret = asoc_simple_card_canonicalize_dailink ( dai_link ) ;
if ( ret < 0 )
2014-04-24 19:14:00 +08:00
goto dai_link_of_err ;
2014-03-24 12:15:25 +02:00
2016-07-11 23:57:34 +00:00
ret = asoc_simple_card_set_dailink_name ( dev , dai_link ,
" %s-%s " ,
dai_link - > cpu_dai_name ,
2018-08-31 03:08:24 +00:00
dai_link - > codecs - > dai_name ) ;
2016-07-11 23:57:34 +00:00
if ( ret < 0 )
2015-03-03 18:59:00 +05:30
goto dai_link_of_err ;
2014-05-22 17:31:49 +02:00
dai_link - > ops = & asoc_simple_card_ops ;
2014-08-27 20:08:27 -07:00
dai_link - > init = asoc_simple_card_dai_init ;
2014-03-24 12:15:25 +02:00
2016-08-10 02:20:43 +00:00
asoc_simple_card_canonicalize_cpu ( dai_link , single_cpu ) ;
2014-08-27 20:08:06 -07:00
2014-03-24 12:15:25 +02:00
dai_link_of_err :
2014-10-27 18:04:52 -07:00
of_node_put ( cpu ) ;
of_node_put ( codec ) ;
2014-03-20 11:49:55 +01:00
return ret ;
}
2016-09-26 12:56:51 +03:00
static int asoc_simple_card_parse_aux_devs ( struct device_node * node ,
struct simple_card_data * priv )
{
struct device * dev = simple_priv_to_dev ( priv ) ;
struct device_node * aux_node ;
2017-03-15 04:44:00 +00:00
struct snd_soc_card * card = simple_priv_to_card ( priv ) ;
2016-09-26 12:56:51 +03:00
int i , n , len ;
if ( ! of_find_property ( node , PREFIX " aux-devs " , & len ) )
return 0 ; /* Ok to have no aux-devs */
n = len / sizeof ( __be32 ) ;
if ( n < = 0 )
return - EINVAL ;
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-12 14:07:58 -07:00
card - > aux_dev = devm_kcalloc ( dev ,
n , sizeof ( * card - > aux_dev ) , GFP_KERNEL ) ;
2017-03-15 04:44:00 +00:00
if ( ! card - > aux_dev )
2016-09-26 12:56:51 +03:00
return - ENOMEM ;
for ( i = 0 ; i < n ; i + + ) {
aux_node = of_parse_phandle ( node , PREFIX " aux-devs " , i ) ;
if ( ! aux_node )
return - EINVAL ;
2017-03-15 04:44:00 +00:00
card - > aux_dev [ i ] . codec_of_node = aux_node ;
2016-09-26 12:56:51 +03:00
}
2017-03-15 04:44:00 +00:00
card - > num_aux_devs = n ;
2016-09-26 12:56:51 +03:00
return 0 ;
}
2017-06-07 00:37:05 +00:00
static int asoc_simple_card_parse_of ( struct simple_card_data * priv )
2013-11-20 15:25:02 +09:00
{
2014-09-09 21:37:57 -07:00
struct device * dev = simple_priv_to_dev ( priv ) ;
2018-12-14 11:35:10 +09:00
struct device_node * top = dev - > of_node ;
2017-03-15 04:44:00 +00:00
struct snd_soc_card * card = simple_priv_to_card ( priv ) ;
2018-12-14 11:35:10 +09:00
struct device_node * node ;
struct device_node * np ;
struct device_node * codec ;
bool is_fe ;
int ret , loop ;
int dai_idx , link_idx , conf_idx ;
if ( ! top )
2014-09-03 10:23:39 +08:00
return - EINVAL ;
2017-06-16 01:39:11 +00:00
ret = asoc_simple_card_of_parse_widgets ( card , PREFIX ) ;
if ( ret < 0 )
2018-12-14 11:35:10 +09:00
return ret ;
2014-02-08 15:59:53 +08:00
2018-11-21 02:11:13 +00:00
ret = asoc_simple_card_of_parse_routing ( card , PREFIX ) ;
2017-06-15 00:25:17 +00:00
if ( ret < 0 )
2018-12-14 11:35:10 +09:00
return ret ;
2013-12-23 12:57:01 +08:00
2014-05-22 17:31:49 +02:00
/* Factor to mclk, used in hw_params() */
2018-12-14 11:35:10 +09:00
of_property_read_u32 ( top , PREFIX " mclk-fs " , & priv - > mclk_fs ) ;
asoc_simple_card_parse_convert ( dev , top , PREFIX , & priv - > adata ) ;
2014-05-22 17:31:49 +02:00
2014-09-03 10:23:39 +08:00
/* Single/Muti DAI link(s) & New style of DT node */
2018-12-14 11:35:10 +09:00
loop = 1 ;
link_idx = 0 ;
dai_idx = 0 ;
conf_idx = 0 ;
node = of_get_child_by_name ( top , PREFIX " dai-link " ) ;
if ( ! node ) {
node = dev - > of_node ;
loop = 0 ;
}
do {
/* DPCM */
if ( of_get_child_count ( node ) > 2 ) {
for_each_child_of_node ( node , np ) {
codec = of_get_child_by_name ( node ,
loop ? " codec " :
PREFIX " codec " ) ;
if ( ! codec )
return - ENODEV ;
is_fe = ( np ! = codec ) ;
ret = asoc_simple_card_dai_link_of_dpcm (
node , np , codec , priv ,
& dai_idx , link_idx + + , & conf_idx ,
is_fe , ! loop ) ;
2014-03-24 12:15:25 +02:00
}
2018-12-14 11:35:10 +09:00
} else {
ret = asoc_simple_card_dai_link_of (
node , priv ,
& dai_idx , link_idx + + , ! loop ) ;
2014-03-20 11:49:55 +01:00
}
if ( ret < 0 )
2018-12-14 11:35:10 +09:00
return ret ;
node = of_get_next_child ( top , node ) ;
} while ( loop & & node ) ;
2013-12-20 14:39:50 +08:00
2017-03-15 04:44:00 +00:00
ret = asoc_simple_card_parse_card_name ( card , PREFIX ) ;
2016-09-26 12:56:51 +03:00
if ( ret < 0 )
2018-12-14 11:35:10 +09:00
return ret ;
2014-02-27 18:25:24 -08:00
2018-12-14 11:35:10 +09:00
ret = asoc_simple_card_parse_aux_devs ( top , priv ) ;
2016-08-26 03:05:16 +00:00
return ret ;
2013-11-20 15:25:02 +09:00
}
2018-12-14 11:35:10 +09:00
static void asoc_simple_card_get_dais_count ( struct device * dev ,
int * link_num ,
int * dais_num ,
int * ccnf_num )
{
struct device_node * top = dev - > of_node ;
struct device_node * node ;
int loop ;
int num ;
/*
* link_num : number of links .
* CPU - Codec / CPU - dummy / dummy - Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for " dummy-Codec "
*
* ex1 )
* CPU0 - - - Codec0 link : 5
* CPU1 - - - Codec1 dais : 7
* CPU2 - / ccnf : 1
* CPU3 - - - Codec2
*
* = > 5 links = 2 xCPU - Codec + 2 xCPU - dummy + 1 xdummy - Codec
* = > 7 DAIs = 4 xCPU + 3 xCodec
* = > 1 ccnf = 1 xdummy - Codec
*
* ex2 )
* CPU0 - - - Codec0 link : 5
* CPU1 - - - Codec1 dais : 6
* CPU2 - / ccnf : 1
* CPU3 - /
*
* = > 5 links = 1 xCPU - Codec + 3 xCPU - dummy + 1 xdummy - Codec
* = > 6 DAIs = 4 xCPU + 2 xCodec
* = > 1 ccnf = 1 xdummy - Codec
*
* ex3 )
* CPU0 - - - Codec0 link : 6
* CPU1 - / dais : 6
* CPU2 - - - Codec1 ccnf : 2
* CPU3 - /
*
* = > 6 links = 0xC PU - Codec + 4 xCPU - dummy + 2 xdummy - Codec
* = > 6 DAIs = 4 xCPU + 2 xCodec
* = > 2 ccnf = 2 xdummy - Codec
*/
if ( ! top ) {
( * link_num ) = 1 ;
( * dais_num ) = 2 ;
( * ccnf_num ) = 0 ;
return ;
}
loop = 1 ;
node = of_get_child_by_name ( top , PREFIX " dai-link " ) ;
if ( ! node ) {
node = top ;
loop = 0 ;
}
do {
num = of_get_child_count ( node ) ;
( * dais_num ) + = num ;
if ( num > 2 ) {
( * link_num ) + = num ;
( * ccnf_num ) + + ;
} else {
( * link_num ) + + ;
}
node = of_get_next_child ( top , node ) ;
} while ( loop & & node ) ;
}
2018-06-11 17:32:13 +09:00
static int asoc_simple_soc_card_probe ( struct snd_soc_card * card )
{
struct simple_card_data * priv = snd_soc_card_get_drvdata ( card ) ;
int ret ;
ret = asoc_simple_card_init_hp ( card , & priv - > hp_jack , PREFIX ) ;
if ( ret < 0 )
return ret ;
ret = asoc_simple_card_init_mic ( card , & priv - > mic_jack , PREFIX ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
2012-04-08 21:17:50 -07:00
static int asoc_simple_card_probe ( struct platform_device * pdev )
{
2014-01-15 16:51:56 +01:00
struct simple_card_data * priv ;
2014-01-15 16:51:45 +01:00
struct snd_soc_dai_link * dai_link ;
2016-08-26 03:10:25 +00:00
struct simple_dai_props * dai_props ;
2018-12-04 08:19:43 +00:00
struct asoc_simple_dai * dais ;
2012-12-25 22:52:33 -08:00
struct device * dev = & pdev - > dev ;
2017-03-15 04:43:21 +00:00
struct device_node * np = dev - > of_node ;
2017-03-15 04:44:00 +00:00
struct snd_soc_card * card ;
2018-12-14 11:35:10 +09:00
struct snd_soc_codec_conf * cconf ;
int lnum = 0 , dnum = 0 , cnum = 0 ;
int ret , i ;
2012-04-08 21:17:50 -07:00
2014-09-10 09:59:55 +08:00
/* Allocate the private data and the DAI link array */
2016-08-26 03:10:25 +00:00
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
2014-01-15 16:51:52 +01:00
if ( ! priv )
2014-01-14 12:35:32 +08:00
return - ENOMEM ;
2018-12-14 11:35:10 +09:00
asoc_simple_card_get_dais_count ( dev , & lnum , & dnum , & cnum ) ;
if ( ! lnum | | ! dnum )
return - EINVAL ;
dai_props = devm_kcalloc ( dev , lnum , sizeof ( * dai_props ) , GFP_KERNEL ) ;
dai_link = devm_kcalloc ( dev , lnum , sizeof ( * dai_link ) , GFP_KERNEL ) ;
dais = devm_kcalloc ( dev , dnum , sizeof ( * dais ) , GFP_KERNEL ) ;
cconf = devm_kcalloc ( dev , cnum , sizeof ( * cconf ) , GFP_KERNEL ) ;
2018-12-04 08:19:43 +00:00
if ( ! dai_props | | ! dai_link | | ! dais )
2016-08-26 03:10:25 +00:00
return - ENOMEM ;
2018-08-31 03:08:24 +00:00
/*
* Use snd_soc_dai_link_component instead of legacy style
* It is codec only . but cpu / platform will be supported in the future .
* see
* soc - core . c : : snd_soc_init_multicodec ( )
*/
2018-12-14 11:35:10 +09:00
for ( i = 0 ; i < lnum ; i + + ) {
2018-08-31 03:08:24 +00:00
dai_link [ i ] . codecs = & dai_props [ i ] . codecs ;
dai_link [ i ] . num_codecs = 1 ;
2018-08-31 03:10:33 +00:00
dai_link [ i ] . platform = & dai_props [ i ] . platform ;
2018-08-31 03:08:24 +00:00
}
2016-08-26 03:10:25 +00:00
priv - > dai_props = dai_props ;
priv - > dai_link = dai_link ;
2018-12-04 08:19:43 +00:00
priv - > dais = dais ;
2018-12-14 11:35:10 +09:00
priv - > codec_conf = cconf ;
2016-08-26 03:10:25 +00:00
2014-09-10 09:59:55 +08:00
/* Init snd_soc_card */
2017-03-15 04:44:00 +00:00
card = simple_priv_to_card ( priv ) ;
card - > owner = THIS_MODULE ;
card - > dev = dev ;
card - > dai_link = priv - > dai_link ;
2018-12-14 11:35:10 +09:00
card - > num_links = lnum ;
card - > codec_conf = cconf ;
card - > num_configs = cnum ;
2018-06-11 17:32:13 +09:00
card - > probe = asoc_simple_soc_card_probe ;
2014-01-15 16:51:41 +01:00
2013-11-20 15:25:02 +09:00
if ( np & & of_device_is_available ( np ) ) {
2014-01-14 12:35:32 +08:00
2017-06-07 00:37:05 +00:00
ret = asoc_simple_card_parse_of ( priv ) ;
2014-01-14 12:35:32 +08:00
if ( ret < 0 ) {
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " parse error %d \n " , ret ) ;
2014-03-11 10:03:40 +01:00
goto err ;
2013-11-20 15:25:02 +09:00
}
2014-03-20 11:49:55 +01:00
2013-11-20 15:25:02 +09:00
} else {
2014-01-15 16:51:52 +01:00
struct asoc_simple_card_info * cinfo ;
2018-08-31 03:08:24 +00:00
struct snd_soc_dai_link_component * codecs ;
2018-08-31 03:10:33 +00:00
struct snd_soc_dai_link_component * platform ;
2018-12-13 14:15:20 +09:00
int dai_idx = 0 ;
2014-01-15 16:51:52 +01:00
cinfo = dev - > platform_data ;
if ( ! cinfo ) {
2014-01-09 17:49:40 +08:00
dev_err ( dev , " no info for asoc-simple-card \n " ) ;
return - EINVAL ;
}
2013-11-20 15:25:02 +09:00
2014-04-24 19:14:00 +08:00
if ( ! cinfo - > name | |
! cinfo - > codec_dai . name | |
! cinfo - > codec | |
! cinfo - > platform | |
2014-01-15 16:51:33 +01:00
! cinfo - > cpu_dai . name ) {
dev_err ( dev , " insufficient asoc_simple_card_info settings \n " ) ;
return - EINVAL ;
}
2014-01-15 16:51:37 +01:00
2018-12-13 14:15:20 +09:00
dai_props - > cpu_dai = & priv - > dais [ dai_idx + + ] ;
dai_props - > codec_dai = & priv - > dais [ dai_idx + + ] ;
2018-08-31 03:08:24 +00:00
codecs = dai_link - > codecs ;
codecs - > name = cinfo - > codec ;
codecs - > dai_name = cinfo - > codec_dai . name ;
2018-08-31 03:10:33 +00:00
platform = dai_link - > platform ;
platform - > name = cinfo - > platform ;
2017-03-15 04:44:00 +00:00
card - > name = ( cinfo - > card ) ? cinfo - > card : cinfo - > name ;
2014-01-15 16:51:45 +01:00
dai_link - > name = cinfo - > name ;
dai_link - > stream_name = cinfo - > name ;
2014-01-15 16:51:48 +01:00
dai_link - > cpu_dai_name = cinfo - > cpu_dai . name ;
2015-03-24 01:07:08 +00:00
dai_link - > dai_fmt = cinfo - > daifmt ;
2014-08-27 20:08:27 -07:00
dai_link - > init = asoc_simple_card_dai_init ;
2018-12-13 14:15:20 +09:00
memcpy ( priv - > dai_props - > cpu_dai , & cinfo - > cpu_dai ,
sizeof ( * priv - > dai_props - > cpu_dai ) ) ;
memcpy ( priv - > dai_props - > codec_dai , & cinfo - > codec_dai ,
sizeof ( * priv - > dai_props - > codec_dai ) ) ;
2012-04-08 21:17:50 -07:00
}
2017-03-15 04:44:00 +00:00
snd_soc_card_set_drvdata ( card , priv ) ;
2012-04-08 21:17:50 -07:00
2017-03-15 04:44:00 +00:00
ret = devm_snd_soc_register_card ( dev , card ) ;
2017-05-19 00:57:21 +00:00
if ( ret < 0 )
goto err ;
return 0 ;
2014-03-11 10:03:40 +01:00
err :
2017-03-15 04:44:00 +00:00
asoc_simple_card_clean_reference ( card ) ;
2016-08-26 03:07:59 +00:00
2014-03-11 10:03:40 +01:00
return ret ;
2012-04-08 21:17:50 -07:00
}
2014-09-01 14:46:52 +08:00
static int asoc_simple_card_remove ( struct platform_device * pdev )
{
2014-10-01 14:25:20 -07:00
struct snd_soc_card * card = platform_get_drvdata ( pdev ) ;
2016-08-10 02:21:42 +00:00
return asoc_simple_card_clean_reference ( card ) ;
2014-09-01 14:46:52 +08:00
}
2013-11-20 15:25:02 +09:00
static const struct of_device_id asoc_simple_of_match [ ] = {
{ . compatible = " simple-audio-card " , } ,
2018-12-14 11:35:10 +09:00
{ . compatible = " simple-scu-audio-card " , } ,
2013-11-20 15:25:02 +09:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , asoc_simple_of_match ) ;
2012-04-08 21:17:50 -07:00
static struct platform_driver asoc_simple_card = {
. driver = {
2014-04-24 19:14:00 +08:00
. name = " asoc-simple-card " ,
2016-05-09 13:38:10 +03:00
. pm = & snd_soc_pm_ops ,
2013-11-20 15:25:02 +09:00
. of_match_table = asoc_simple_of_match ,
2012-04-08 21:17:50 -07:00
} ,
2014-04-24 19:14:00 +08:00
. probe = asoc_simple_card_probe ,
2014-09-01 14:46:52 +08:00
. remove = asoc_simple_card_remove ,
2012-04-08 21:17:50 -07:00
} ;
module_platform_driver ( asoc_simple_card ) ;
2013-08-23 14:35:17 -03:00
MODULE_ALIAS ( " platform:asoc-simple-card " ) ;
2016-08-26 03:07:28 +00:00
MODULE_LICENSE ( " GPL v2 " ) ;
2012-04-08 21:17:50 -07:00
MODULE_DESCRIPTION ( " ASoC Simple Sound Card " ) ;
MODULE_AUTHOR ( " Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> " ) ;