diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/sgtl5000.c | 3 | ||||
-rw-r--r-- | sound/soc/codecs/stac9766.c | 8 | ||||
-rw-r--r-- | sound/soc/generic/simple-card.c | 121 | ||||
-rw-r--r-- | sound/soc/sti/sti_uniperif.c | 130 | ||||
-rw-r--r-- | sound/soc/sti/uniperif.h | 28 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_player.c | 83 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_reader.c | 46 | ||||
-rw-r--r-- | sound/soc/sunxi/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/sunxi/sun4i-codec.c | 50 | ||||
-rw-r--r-- | sound/soc/sunxi/sun4i-spdif.c | 17 |
10 files changed, 285 insertions, 202 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a635bd09d637..1589325855bc 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -411,6 +411,8 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 0, 8, 0x7f, 1, headphone_volume), + SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL, + 4, 1, 1), SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL, 5, 1, 0), @@ -423,6 +425,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT, 0x1f, 1, lineout_volume), + SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1), }; /* mute the codec used by alsa core */ diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 2c5941f3a234..27f30d352867 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -85,10 +85,10 @@ static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic); -static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); -static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); -static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0); -static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv, 0, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv, -4500, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv, -3450, 150, 0); static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 55638a800f20..f608f8d23f3d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -37,12 +37,12 @@ struct simple_card_data { unsigned int mclk_fs; struct asoc_simple_jack hp_jack; struct asoc_simple_jack mic_jack; - struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ + struct snd_soc_dai_link *dai_link; }; #define simple_priv_to_dev(priv) ((priv)->snd_card.dev) -#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + i) +#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define DAI "sound-dai" #define CELL "#sound-dai-cells" @@ -114,13 +114,13 @@ 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 = - &priv->dai_props[rtd->num]; + simple_priv_to_props(priv, rtd->num); int ret; ret = clk_prepare_enable(dai_props->cpu_dai.clk); if (ret) return ret; - + ret = clk_prepare_enable(dai_props->codec_dai.clk); if (ret) clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -133,7 +133,7 @@ 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 = - &priv->dai_props[rtd->num]; + simple_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -147,7 +147,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; + struct simple_dai_props *dai_props = + simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -184,7 +185,8 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; - struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; + struct simple_dai_props *dai_props = + simple_priv_to_props(priv, rtd->num); int ret; ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); @@ -222,7 +224,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, char prop[128]; char *prefix = ""; int ret, single_cpu; - u32 val; /* For single DAI link & old style of DT node */ if (is_top_level_node) @@ -248,8 +249,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (ret < 0) goto dai_link_of_err; - if (!of_property_read_u32(node, "mclk-fs", &val)) - dai_props->mclk_fs = val; + of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); ret = asoc_simple_card_parse_cpu(cpu, dai_link, DAI, CELL, &single_cpu); @@ -318,22 +318,54 @@ dai_link_of_err: return ret; } +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; + 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; + + priv->snd_card.aux_dev = devm_kzalloc(dev, + n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL); + if (!priv->snd_card.aux_dev) + return -ENOMEM; + + for (i = 0; i < n; i++) { + aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); + if (!aux_node) + return -EINVAL; + priv->snd_card.aux_dev[i].codec_of_node = aux_node; + } + + priv->snd_card.num_aux_devs = n; + return 0; +} + static int asoc_simple_card_parse_of(struct device_node *node, struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); - u32 val; + struct device_node *dai_link; int ret; if (!node) return -EINVAL; + dai_link = of_get_child_by_name(node, PREFIX "dai-link"); + /* The off-codec widgets */ if (of_property_read_bool(node, PREFIX "widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, PREFIX "widgets"); if (ret) - return ret; + goto card_parse_end; } /* DAPM routes */ @@ -341,16 +373,14 @@ static int asoc_simple_card_parse_of(struct device_node *node, ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); if (ret) - return ret; + goto card_parse_end; } /* Factor to mclk, used in hw_params() */ - ret = of_property_read_u32(node, PREFIX "mclk-fs", &val); - if (ret == 0) - priv->mclk_fs = val; + of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); /* Single/Muti DAI link(s) & New style of DT node */ - if (of_get_child_by_name(node, PREFIX "dai-link")) { + if (dai_link) { struct device_node *np = NULL; int i = 0; @@ -360,7 +390,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, i, false); if (ret < 0) { of_node_put(np); - return ret; + goto card_parse_end; } i++; } @@ -368,51 +398,55 @@ static int asoc_simple_card_parse_of(struct device_node *node, /* For single DAI link & old style of DT node */ ret = asoc_simple_card_dai_link_of(node, priv, 0, true); if (ret < 0) - return ret; + goto card_parse_end; } ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); - if (ret) - return ret; + if (ret < 0) + goto card_parse_end; - return 0; + ret = asoc_simple_card_parse_aux_devs(node, priv); + +card_parse_end: + of_node_put(dai_link); + + return ret; } static int asoc_simple_card_probe(struct platform_device *pdev) { struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; + struct simple_dai_props *dai_props; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - int num_links, ret; + int num, ret; /* Get the number of DAI links */ if (np && of_get_child_by_name(np, PREFIX "dai-link")) - num_links = of_get_child_count(np); + num = of_get_child_count(np); else - num_links = 1; + num = 1; /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, - sizeof(*priv) + sizeof(*dai_link) * num_links, - GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - dai_link = priv->dai_link; - priv->snd_card.dai_link = dai_link; - priv->snd_card.num_links = num_links; - - /* Get room for the other properties */ - priv->dai_props = devm_kzalloc(dev, - sizeof(*priv->dai_props) * num_links, - GFP_KERNEL); - if (!priv->dai_props) + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) return -ENOMEM; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + if (np && of_device_is_available(np)) { ret = asoc_simple_card_parse_of(np, priv); @@ -453,7 +487,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) sizeof(priv->dai_props->cpu_dai)); memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, sizeof(priv->dai_props->codec_dai)); - } snd_soc_card_set_drvdata(&priv->snd_card, priv); @@ -461,9 +494,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); if (ret >= 0) return ret; - err: asoc_simple_card_clean_reference(&priv->snd_card); + return ret; } @@ -497,6 +530,6 @@ static struct platform_driver asoc_simple_card = { module_platform_driver(asoc_simple_card); MODULE_ALIAS("platform:asoc-simple-card"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ASoC Simple Sound Card"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 488ef4ed8fba..549fac349fa0 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -19,6 +19,84 @@ #define UNIPERIF_MAX_FRAME_SZ 0x20 #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) +struct sti_uniperiph_dev_data { + unsigned int id; /* Nb available player instances */ + unsigned int version; /* player IP version */ + unsigned int stream; + const char *dai_names; + enum uniperif_type type; +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_hdmi = { + .id = 0, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #0 (HDMI)", + .type = SND_ST_UNIPERIF_TYPE_HDMI +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_pcm_out = { + .id = 1, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #1 (PCM OUT)", + .type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM, +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_dac = { + .id = 2, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #2 (DAC)", + .type = SND_ST_UNIPERIF_TYPE_PCM, +}; + +static const struct sti_uniperiph_dev_data sti_uniplayer_spdif = { + .id = 3, + .version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0, + .stream = SNDRV_PCM_STREAM_PLAYBACK, + .dai_names = "Uni Player #3 (SPDIF)", + .type = SND_ST_UNIPERIF_TYPE_SPDIF +}; + +static const struct sti_uniperiph_dev_data sti_unireader_pcm_in = { + .id = 0, + .version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + .stream = SNDRV_PCM_STREAM_CAPTURE, + .dai_names = "Uni Reader #0 (PCM IN)", + .type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM, +}; + +static const struct sti_uniperiph_dev_data sti_unireader_hdmi_in = { + .id = 1, + .version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + .stream = SNDRV_PCM_STREAM_CAPTURE, + .dai_names = "Uni Reader #1 (HDMI IN)", + .type = SND_ST_UNIPERIF_TYPE_PCM, +}; + +static const struct of_device_id snd_soc_sti_match[] = { + { .compatible = "st,stih407-uni-player-hdmi", + .data = &sti_uniplayer_hdmi + }, + { .compatible = "st,stih407-uni-player-pcm-out", + .data = &sti_uniplayer_pcm_out + }, + { .compatible = "st,stih407-uni-player-dac", + .data = &sti_uniplayer_dac + }, + { .compatible = "st,stih407-uni-player-spdif", + .data = &sti_uniplayer_spdif + }, + { .compatible = "st,stih407-uni-reader-pcm_in", + .data = &sti_unireader_pcm_in + }, + { .compatible = "st,stih407-uni-reader-hdmi", + .data = &sti_unireader_hdmi_in + }, + {}, +}; + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) @@ -167,8 +245,8 @@ static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) * Uniperipheral instance ID */ ctrl = &uni->snd_ctrls[i]; - ctrl->index = uni->info->id; - ctrl->device = uni->info->id; + ctrl->index = uni->id; + ctrl->device = uni->id; } return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); @@ -186,7 +264,7 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, struct snd_dmaengine_dai_dma_data *dma_data; int transfer_size; - if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) + if (uni->type == SND_ST_UNIPERIF_TYPE_TDM) /* transfer size = user frame size (in 32-bits FIFO cell) */ transfer_size = snd_soc_params_to_frame_size(params) / 32; else @@ -235,7 +313,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) struct uniperif *uni = priv->dai_data.uni; int ret; - if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { ret = uni_player_resume(uni); if (ret) return ret; @@ -256,7 +334,7 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) struct sti_uniperiph_dai *dai_data = &priv->dai_data; /* DMA settings*/ - if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); else snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); @@ -280,25 +358,32 @@ static const struct snd_soc_component_driver sti_uniperiph_dai_component = { static int sti_uniperiph_cpu_dai_of(struct device_node *node, struct sti_uniperiph_data *priv) { - const char *str; - int ret; struct device *dev = &priv->pdev->dev; struct sti_uniperiph_dai *dai_data = &priv->dai_data; struct snd_soc_dai_driver *dai = priv->dai; struct snd_soc_pcm_stream *stream; struct uniperif *uni; + const struct of_device_id *of_id; + const struct sti_uniperiph_dev_data *dev_data; + const char *mode; + + /* Populate data structure depending on compatibility */ + of_id = of_match_node(snd_soc_sti_match, node); + if (!of_id->data) { + dev_err(dev, "data associated to device is missing"); + return -EINVAL; + } + dev_data = (struct sti_uniperiph_dev_data *)of_id->data; uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); if (!uni) return -ENOMEM; + uni->id = dev_data->id; + uni->ver = dev_data->version; + *dai = sti_uniperiph_dai_template; - ret = of_property_read_string(node, "dai-name", &str); - if (ret < 0) { - dev_err(dev, "%s: dai name missing.\n", __func__); - return -EINVAL; - } - dai->name = str; + dai->name = dev_data->dai_names; /* Get resources */ uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); @@ -322,9 +407,20 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, return -ENXIO; } + uni->type = dev_data->type; + + /* check if player should be configured for tdm */ + if (dev_data->type & SND_ST_UNIPERIF_TYPE_TDM) { + if (!of_property_read_string(node, "st,tdm-mode", &mode)) + uni->type = SND_ST_UNIPERIF_TYPE_TDM; + else + uni->type = SND_ST_UNIPERIF_TYPE_PCM; + } + dai_data->uni = uni; + dai_data->stream = dev_data->stream; - if (of_device_is_compatible(node, "st,sti-uni-player")) { + if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { uni_player_init(priv->pdev, uni); stream = &dai->playback; } else { @@ -376,12 +472,6 @@ static int sti_uniperiph_probe(struct platform_device *pdev) &dmaengine_pcm_config, 0); } -static const struct of_device_id snd_soc_sti_match[] = { - { .compatible = "st,sti-uni-player", }, - { .compatible = "st,sti-uni-reader", }, - {}, -}; - static struct platform_driver sti_uniperiph_driver = { .driver = { .name = "sti-uniperiph-dai", diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index eb9933c62ad6..1993c655fb79 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1220,16 +1220,16 @@ #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ #define UNIPERIF_TYPE_IS_HDMI(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI) + ((p)->type == SND_ST_UNIPERIF_TYPE_HDMI) #define UNIPERIF_TYPE_IS_PCM(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM) + ((p)->type == SND_ST_UNIPERIF_TYPE_PCM) #define UNIPERIF_TYPE_IS_SPDIF(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF) + ((p)->type == SND_ST_UNIPERIF_TYPE_SPDIF) #define UNIPERIF_TYPE_IS_IEC958(p) \ (UNIPERIF_TYPE_IS_HDMI(p) || \ UNIPERIF_TYPE_IS_SPDIF(p)) #define UNIPERIF_TYPE_IS_TDM(p) \ - ((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM) + ((p)->type == SND_ST_UNIPERIF_TYPE_TDM) /* * Uniperipheral IP revisions @@ -1249,11 +1249,11 @@ enum uniperif_version { }; enum uniperif_type { - SND_ST_UNIPERIF_TYPE_NONE, - SND_ST_UNIPERIF_TYPE_HDMI, - SND_ST_UNIPERIF_TYPE_PCM, - SND_ST_UNIPERIF_TYPE_SPDIF, - SND_ST_UNIPERIF_TYPE_TDM + SND_ST_UNIPERIF_TYPE_NONE = 0x00, + SND_ST_UNIPERIF_TYPE_HDMI = 0x01, + SND_ST_UNIPERIF_TYPE_PCM = 0x02, + SND_ST_UNIPERIF_TYPE_SPDIF = 0x04, + SND_ST_UNIPERIF_TYPE_TDM = 0x08 }; enum uniperif_state { @@ -1278,12 +1278,6 @@ enum uniperif_word_pos { WORD_MAX }; -struct uniperif_info { - int id; /* instance value of the uniperipheral IP */ - enum uniperif_type type; - int underflow_enabled; /* Underflow recovery mode */ -}; - struct uniperif_iec958_settings { enum uniperif_iec958_encoding_mode encoding_mode; struct snd_aes_iec958 iec958; @@ -1298,8 +1292,10 @@ struct dai_tdm_slot { struct uniperif { /* System information */ - struct uniperif_info *info; + enum uniperif_type type; + int underflow_enabled; /* Underflow recovery mode */ struct device *dev; + int id; /* instance value of the uniperipheral IP */ int ver; /* IP version, used by register access macros */ struct regmap_field *clk_sel; struct regmap_field *valid_sel; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 1ac2db205a0d..1bc8ebc2528e 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -100,7 +100,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) dev_err(player->dev, "FIFO underflow error detected"); /* Interrupt is just for information when underflow recovery */ - if (player->info->underflow_enabled) { + if (player->underflow_enabled) { /* Update state to underflow */ player->state = UNIPERIF_STATE_UNDERFLOW; @@ -134,7 +134,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for underflow recovery done */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { - if (!player->info->underflow_enabled) { + if (!player->underflow_enabled) { dev_err(player->dev, "unexpected Underflow recovering"); return -EPERM; } @@ -764,7 +764,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, } /* Calculate transfer size (in fifo cells and bytes) for frame count */ - if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) { + if (player->type == SND_ST_UNIPERIF_TYPE_TDM) { /* transfer size = user frame size (in 32 bits FIFO cell) */ transfer_size = sti_uniperiph_get_user_frame_size(runtime) / 4; @@ -794,7 +794,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); /* Uniperipheral setup depends on player type */ - switch (player->info->type) { + switch (player->type) { case SND_ST_UNIPERIF_TYPE_HDMI: ret = uni_player_prepare_iec958(player, runtime); break; @@ -884,7 +884,7 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); /* Enable underflow recovery interrupts */ - if (player->info->underflow_enabled) { + if (player->underflow_enabled) { SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); } @@ -893,8 +893,10 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_SOFT_RST_SOFT_RST(player); ret = reset_player(player); - if (ret < 0) + if (ret < 0) { + clk_disable_unprepare(player->clk); return ret; + } /* * Does not use IEC61937 features of the uniperipheral hardware. @@ -1021,8 +1023,8 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, struct reg_field regfield[2] = { /* PCM_CLK_SEL */ REG_FIELD(SYS_CFG_AUDIO_GLUE, - 8 + player->info->id, - 8 + player->info->id), + 8 + player->id, + 8 + player->id), /* PCMP_VALID_SEL */ REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1) }; @@ -1040,60 +1042,6 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, return 0; } -static int uni_player_parse_dt(struct platform_device *pdev, - struct uniperif *player) -{ - struct uniperif_info *info; - struct device *dev = &pdev->dev; - struct device_node *pnode = pdev->dev.of_node; - const char *mode; - - /* Allocate memory for the info structure */ - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - if (of_property_read_u32(pnode, "st,version", &player->ver) || - player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { - dev_err(dev, "Unknown uniperipheral version "); - return -EINVAL; - } - /* Underflow recovery is only supported on later ip revisions */ - if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) - info->underflow_enabled = 1; - - if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) { - dev_err(dev, "uniperipheral id not defined"); - return -EINVAL; - } - - /* Read the device mode property */ - if (of_property_read_string(pnode, "st,mode", &mode)) { - dev_err(dev, "uniperipheral mode not defined"); - return -EINVAL; - } - - if (strcasecmp(mode, "hdmi") == 0) - info->type = SND_ST_UNIPERIF_TYPE_HDMI; - else if (strcasecmp(mode, "pcm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_PCM; - else if (strcasecmp(mode, "spdif") == 0) - info->type = SND_ST_UNIPERIF_TYPE_SPDIF; - else if (strcasecmp(mode, "tdm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_TDM; - else - info->type = SND_ST_UNIPERIF_TYPE_NONE; - - /* Save the info structure */ - player->info = info; - - /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ - if (uni_player_parse_dt_audio_glue(pdev, player)) - return -EINVAL; - - return 0; -} - static const struct snd_soc_dai_ops uni_player_dai_ops = { .startup = uni_player_startup, .shutdown = uni_player_shutdown, @@ -1114,13 +1062,18 @@ int uni_player_init(struct platform_device *pdev, player->state = UNIPERIF_STATE_STOPPED; player->dai_ops = &uni_player_dai_ops; - ret = uni_player_parse_dt(pdev, player); + /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ + ret = uni_player_parse_dt_audio_glue(pdev, player); if (ret < 0) { dev_err(player->dev, "Failed to parse DeviceTree"); return ret; } + /* Underflow recovery is only supported on later ip revisions */ + if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + player->underflow_enabled = 1; + if (UNIPERIF_TYPE_IS_TDM(player)) player->hw = &uni_tdm_hw; else @@ -1144,8 +1097,8 @@ int uni_player_init(struct platform_device *pdev, /* connect to I2S/TDM TX bus */ if (player->valid_sel && - (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) { - ret = regmap_field_write(player->valid_sel, player->info->id); + (player->id == UNIPERIF_PLAYER_I2S_OUT)) { + ret = regmap_field_write(player->valid_sel, player->id); if (ret) { dev_err(player->dev, "%s: unable to connect to tdm bus", __func__); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index eb74a328c928..0e1c3ee56675 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -13,6 +13,7 @@ #include "uniperif.h" +#define UNIPERIF_READER_I2S_IN 0 /* reader id connected to I2S/TDM TX bus */ /* * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate unireader capability in term of rate and supported channels @@ -195,7 +196,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, } /* Calculate transfer size (in fifo cells and bytes) for frame count */ - if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) { + if (reader->type == SND_ST_UNIPERIF_TYPE_TDM) { /* transfer size = unip frame size (in 32 bits FIFO cell) */ transfer_size = sti_uniperiph_get_user_frame_size(runtime) / 4; @@ -280,7 +281,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader); /* Enable underflow recovery interrupts */ - if (reader->info->underflow_enabled) { + if (reader->underflow_enabled) { SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader); SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader); } @@ -394,41 +395,6 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream, } } -static int uni_reader_parse_dt(struct platform_device *pdev, - struct uniperif *reader) -{ - struct uniperif_info *info; - struct device_node *node = pdev->dev.of_node; - const char *mode; - - /* Allocate memory for the info structure */ - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - if (of_property_read_u32(node, "st,version", &reader->ver) || - reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { - dev_err(&pdev->dev, "Unknown uniperipheral version "); - return -EINVAL; - } - - /* Read the device mode property */ - if (of_property_read_string(node, "st,mode", &mode)) { - dev_err(&pdev->dev, "uniperipheral mode not defined"); - return -EINVAL; - } - - if (strcasecmp(mode, "tdm") == 0) - info->type = SND_ST_UNIPERIF_TYPE_TDM; - else - info->type = SND_ST_UNIPERIF_TYPE_PCM; - - /* Save the info structure */ - reader->info = info; - - return 0; -} - static const struct snd_soc_dai_ops uni_reader_dai_ops = { .startup = uni_reader_startup, .shutdown = uni_reader_shutdown, @@ -448,12 +414,6 @@ int uni_reader_init(struct platform_device *pdev, reader->state = UNIPERIF_STATE_STOPPED; reader->dai_ops = &uni_reader_dai_ops; - ret = uni_reader_parse_dt(pdev, reader); - if (ret < 0) { - dev_err(reader->dev, "Failed to parse DeviceTree"); - return ret; - } - if (UNIPERIF_TYPE_IS_TDM(reader)) reader->hw = &uni_tdm_hw; else diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 2a954bd01fd8..dd2368297fd3 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -1,4 +1,5 @@ menu "Allwinner SoC Audio support" + depends on ARCH_SUNXI || COMPILE_TEST config SND_SUN4I_CODEC tristate "Allwinner A10 Codec Support" diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 0e19c5070005..e047ec06d538 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -96,8 +96,8 @@ /* Other various ADC registers */ #define SUN4I_CODEC_DAC_TXCNT (0x30) #define SUN4I_CODEC_ADC_RXCNT (0x34) -#define SUN4I_CODEC_AC_SYS_VERI (0x38) -#define SUN4I_CODEC_AC_MIC_PHONE_CAL (0x3c) +#define SUN7I_CODEC_AC_DAC_CAL (0x38) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) struct sun4i_codec { struct device *dev; @@ -509,7 +509,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); -static const struct snd_kcontrol_new sun4i_codec_widgets[] = { +static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), @@ -629,8 +629,8 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { static struct snd_soc_codec_driver sun4i_codec_codec = { .component_driver = { - .controls = sun4i_codec_widgets, - .num_controls = ARRAY_SIZE(sun4i_codec_widgets), + .controls = sun4i_codec_controls, + .num_controls = ARRAY_SIZE(sun4i_codec_controls), .dapm_widgets = sun4i_codec_codec_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), .dapm_routes = sun4i_codec_codec_dapm_routes, @@ -682,12 +682,37 @@ static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = SUN4I_CODEC_AC_MIC_PHONE_CAL, + .max_register = SUN4I_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun7i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, +}; + +struct sun4i_codec_quirks { + const struct regmap_config *regmap_config; +}; + +static const struct sun4i_codec_quirks sun4i_codec_quirks = { + .regmap_config = &sun4i_codec_regmap_config, +}; + +static const struct sun4i_codec_quirks sun7i_codec_quirks = { + .regmap_config = &sun7i_codec_regmap_config, }; static const struct of_device_id sun4i_codec_of_match[] = { - { .compatible = "allwinner,sun4i-a10-codec" }, - { .compatible = "allwinner,sun7i-a20-codec" }, + { + .compatible = "allwinner,sun4i-a10-codec", + .data = &sun4i_codec_quirks, + }, + { + .compatible = "allwinner,sun7i-a20-codec", + .data = &sun7i_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); @@ -760,6 +785,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct sun4i_codec *scodec; + const struct sun4i_codec_quirks *quirks; struct resource *res; void __iomem *base; int ret; @@ -777,8 +803,14 @@ static int sun4i_codec_probe(struct platform_device *pdev) return PTR_ERR(base); } + quirks = of_device_get_match_data(&pdev->dev); + if (quirks == NULL) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &sun4i_codec_regmap_config); + quirks->regmap_config); if (IS_ERR(scodec->regmap)) { dev_err(&pdev->dev, "Failed to create our regmap\n"); return PTR_ERR(scodec->regmap); diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index 0b04fb02125c..88fbb3a1e660 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -162,6 +163,7 @@ struct sun4i_spdif_dev { struct platform_device *pdev; struct clk *spdif_clk; struct clk *apb_clk; + struct reset_control *rst; struct snd_soc_dai_driver cpu_dai_drv; struct regmap *regmap; struct snd_dmaengine_dai_dma_data dma_params_tx; @@ -411,6 +413,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { static const struct of_device_id sun4i_spdif_of_match[] = { { .compatible = "allwinner,sun4i-a10-spdif", }, + { .compatible = "allwinner,sun6i-a31-spdif", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match); @@ -482,11 +485,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev) } host->dma_params_tx.addr = res->start + SUN4I_SPDIF_TXFIFO; - host->dma_params_tx.maxburst = 4; + host->dma_params_tx.maxburst = 8; host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; platform_set_drvdata(pdev, host); + if (of_device_is_compatible(pdev->dev.of_node, + "allwinner,sun6i-a31-spdif")) { + host->rst = devm_reset_control_get_optional(&pdev->dev, NULL); + if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); + goto err_disable_apb_clk; + } + if (!IS_ERR(host->rst)) + reset_control_deassert(host->rst); + } + ret = devm_snd_soc_register_component(&pdev->dev, &sun4i_spdif_component, &sun4i_spdif_dai, 1); if (ret) |