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