linux/sound/soc/intel/boards/sof_sdw_rt1308.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2020 Intel Corporation
   3
   4/*
   5 *  sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/errno.h>
  10#include <sound/soc.h>
  11#include <sound/soc-acpi.h>
  12#include "sof_sdw_common.h"
  13#include "../../codecs/rt1308.h"
  14
  15static const struct snd_soc_dapm_widget rt1308_widgets[] = {
  16        SND_SOC_DAPM_SPK("Speaker", NULL),
  17};
  18
  19/*
  20 * dapm routes for rt1308 will be registered dynamically according
  21 * to the number of rt1308 used. The first two entries will be registered
  22 * for one codec case, and the last two entries are also registered
  23 * if two 1308s are used.
  24 */
  25static const struct snd_soc_dapm_route rt1308_map[] = {
  26        { "Speaker", NULL, "rt1308-1 SPOL" },
  27        { "Speaker", NULL, "rt1308-1 SPOR" },
  28        { "Speaker", NULL, "rt1308-2 SPOL" },
  29        { "Speaker", NULL, "rt1308-2 SPOR" },
  30};
  31
  32static const struct snd_kcontrol_new rt1308_controls[] = {
  33        SOC_DAPM_PIN_SWITCH("Speaker"),
  34};
  35
  36static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
  37{
  38        struct snd_soc_card *card = rtd->card;
  39        int ret;
  40
  41        card->components = devm_kasprintf(card->dev, GFP_KERNEL,
  42                                          "%s spk:rt1308",
  43                                          card->components);
  44        if (!card->components)
  45                return -ENOMEM;
  46
  47        ret = snd_soc_add_card_controls(card, rt1308_controls,
  48                                        ARRAY_SIZE(rt1308_controls));
  49        if (ret) {
  50                dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret);
  51                return ret;
  52        }
  53
  54        ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets,
  55                                        ARRAY_SIZE(rt1308_widgets));
  56        if (ret) {
  57                dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret);
  58                return ret;
  59        }
  60
  61        ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2);
  62        if (ret)
  63                dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
  64
  65        return ret;
  66}
  67
  68static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
  69{
  70        struct snd_soc_card *card = rtd->card;
  71        int ret;
  72
  73        ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2);
  74        if (ret)
  75                dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
  76
  77        return ret;
  78}
  79
  80static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
  81{
  82        int ret;
  83
  84        ret = first_spk_init(rtd);
  85        if (ret)
  86                return ret;
  87
  88        return second_spk_init(rtd);
  89}
  90
  91static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream,
  92                                struct snd_pcm_hw_params *params)
  93{
  94        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  95        struct snd_soc_card *card = rtd->card;
  96        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  97        int clk_id, clk_freq, pll_out;
  98        int err;
  99
 100        clk_id = RT1308_PLL_S_MCLK;
 101        clk_freq = 38400000;
 102
 103        pll_out = params_rate(params) * 512;
 104
 105        /* Set rt1308 pll */
 106        err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
 107        if (err < 0) {
 108                dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err);
 109                return err;
 110        }
 111
 112        /* Set rt1308 sysclk */
 113        err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out,
 114                                     SND_SOC_CLOCK_IN);
 115        if (err < 0) {
 116                dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err);
 117                return err;
 118        }
 119
 120        return 0;
 121}
 122
 123/* machine stream operations */
 124struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
 125        .hw_params = rt1308_i2s_hw_params,
 126};
 127
 128int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link,
 129                        struct snd_soc_dai_link *dai_links,
 130                        struct sof_sdw_codec_info *info,
 131                        bool playback)
 132{
 133        info->amp_num++;
 134        if (info->amp_num == 1)
 135                dai_links->init = first_spk_init;
 136
 137        if (info->amp_num == 2) {
 138                /*
 139                 * if two 1308s are in one dai link, the init function
 140                 * in this dai link will be first set for the first speaker,
 141                 * and it should be reset to initialize all speakers when
 142                 * the second speaker is found.
 143                 */
 144                if (dai_links->init)
 145                        dai_links->init = all_spk_init;
 146                else
 147                        dai_links->init = second_spk_init;
 148        }
 149
 150        return 0;
 151}
 152