linux/sound/soc/samsung/arndale_rt5631.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3// Copyright (c) 2014, Insignal Co., Ltd.
   4//
   5//  Author: Claude <claude@insginal.co.kr>
   6
   7#include <linux/module.h>
   8#include <linux/platform_device.h>
   9#include <linux/clk.h>
  10
  11#include <sound/soc.h>
  12#include <sound/soc-dapm.h>
  13#include <sound/pcm.h>
  14#include <sound/pcm_params.h>
  15
  16#include "i2s.h"
  17
  18static int arndale_hw_params(struct snd_pcm_substream *substream,
  19        struct snd_pcm_hw_params *params)
  20{
  21        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  22        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  23        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  24        int rfs, ret;
  25        unsigned long rclk;
  26
  27        rfs = 256;
  28
  29        rclk = params_rate(params) * rfs;
  30
  31        ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
  32                                        0, SND_SOC_CLOCK_OUT);
  33        if (ret < 0)
  34                return ret;
  35
  36        ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
  37                                        0, SND_SOC_CLOCK_OUT);
  38
  39        if (ret < 0)
  40                return ret;
  41
  42        ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
  43        if (ret < 0)
  44                return ret;
  45
  46        return 0;
  47}
  48
  49static struct snd_soc_ops arndale_ops = {
  50        .hw_params = arndale_hw_params,
  51};
  52
  53static struct snd_soc_dai_link arndale_rt5631_dai[] = {
  54        {
  55                .name = "RT5631 HiFi",
  56                .stream_name = "Primary",
  57                .codec_dai_name = "rt5631-hifi",
  58                .dai_fmt = SND_SOC_DAIFMT_I2S
  59                        | SND_SOC_DAIFMT_NB_NF
  60                        | SND_SOC_DAIFMT_CBS_CFS,
  61                .ops = &arndale_ops,
  62        },
  63};
  64
  65static struct snd_soc_card arndale_rt5631 = {
  66        .name = "Arndale RT5631",
  67        .owner = THIS_MODULE,
  68        .dai_link = arndale_rt5631_dai,
  69        .num_links = ARRAY_SIZE(arndale_rt5631_dai),
  70};
  71
  72static int arndale_audio_probe(struct platform_device *pdev)
  73{
  74        int n, ret;
  75        struct device_node *np = pdev->dev.of_node;
  76        struct snd_soc_card *card = &arndale_rt5631;
  77
  78        card->dev = &pdev->dev;
  79
  80        for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
  81                if (!arndale_rt5631_dai[n].cpu_dai_name) {
  82                        arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np,
  83                                        "samsung,audio-cpu", n);
  84
  85                        if (!arndale_rt5631_dai[n].cpu_of_node) {
  86                                dev_err(&pdev->dev,
  87                                "Property 'samsung,audio-cpu' missing or invalid\n");
  88                                return -EINVAL;
  89                        }
  90                }
  91                if (!arndale_rt5631_dai[n].platform_name)
  92                        arndale_rt5631_dai[n].platform_of_node =
  93                                        arndale_rt5631_dai[n].cpu_of_node;
  94
  95                arndale_rt5631_dai[n].codec_name = NULL;
  96                arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np,
  97                                        "samsung,audio-codec", n);
  98                if (!arndale_rt5631_dai[0].codec_of_node) {
  99                        dev_err(&pdev->dev,
 100                        "Property 'samsung,audio-codec' missing or invalid\n");
 101                        return -EINVAL;
 102                }
 103        }
 104
 105        ret = devm_snd_soc_register_card(card->dev, card);
 106
 107        if (ret)
 108                dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
 109
 110        return ret;
 111}
 112
 113static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
 114        { .compatible = "samsung,arndale-rt5631", },
 115        { .compatible = "samsung,arndale-alc5631", },
 116        {},
 117};
 118MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
 119
 120static struct platform_driver arndale_audio_driver = {
 121        .driver = {
 122                .name   = "arndale-audio",
 123                .pm = &snd_soc_pm_ops,
 124                .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
 125        },
 126        .probe = arndale_audio_probe,
 127};
 128
 129module_platform_driver(arndale_audio_driver);
 130
 131MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
 132MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
 133MODULE_LICENSE("GPL");
 134