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