linux/sound/soc/sh/rcar/rsrc-card.c
<<
>>
Prefs
   1/*
   2 * Renesas Sampling Rate Convert Sound Card for DPCM
   3 *
   4 * Copyright (C) 2015 Renesas Solutions Corp.
   5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6 *
   7 * based on ${LINUX}/sound/soc/generic/simple-card.c
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13#include <linux/clk.h>
  14#include <linux/device.h>
  15#include <linux/module.h>
  16#include <linux/of.h>
  17#include <linux/of_device.h>
  18#include <linux/platform_device.h>
  19#include <linux/string.h>
  20#include <sound/jack.h>
  21#include <sound/soc.h>
  22#include <sound/soc-dai.h>
  23
  24struct rsrc_card_of_data {
  25        const char *prefix;
  26        const struct snd_soc_dapm_route *routes;
  27        int num_routes;
  28};
  29
  30static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = {
  31        {"ak4642 Playback", NULL, "DAI0 Playback"},
  32        {"DAI0 Capture", NULL, "ak4642 Capture"},
  33};
  34
  35static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = {
  36        .prefix         = "ak4642",
  37        .routes         = routes_ssi0_ak4642,
  38        .num_routes     = ARRAY_SIZE(routes_ssi0_ak4642),
  39};
  40
  41static const struct of_device_id rsrc_card_of_match[] = {
  42        { .compatible = "renesas,rsrc-card,lager",      .data = &routes_of_ssi0_ak4642 },
  43        { .compatible = "renesas,rsrc-card,koelsch",    .data = &routes_of_ssi0_ak4642 },
  44        {},
  45};
  46MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
  47
  48#define DAI_NAME_NUM    32
  49struct rsrc_card_dai {
  50        unsigned int fmt;
  51        unsigned int sysclk;
  52        struct clk *clk;
  53        char dai_name[DAI_NAME_NUM];
  54};
  55
  56#define IDX_CPU         0
  57#define IDX_CODEC       1
  58struct rsrc_card_priv {
  59        struct snd_soc_card snd_card;
  60        struct snd_soc_codec_conf codec_conf;
  61        struct rsrc_card_dai *dai_props;
  62        struct snd_soc_dai_link *dai_link;
  63        int dai_num;
  64        u32 convert_rate;
  65};
  66
  67#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev)
  68#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
  69#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i))
  70#define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data)
  71
  72static int rsrc_card_startup(struct snd_pcm_substream *substream)
  73{
  74        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  75        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
  76        struct rsrc_card_dai *dai_props =
  77                rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
  78
  79        return clk_prepare_enable(dai_props->clk);
  80}
  81
  82static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
  83{
  84        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  85        struct rsrc_card_priv *priv =   snd_soc_card_get_drvdata(rtd->card);
  86        struct rsrc_card_dai *dai_props =
  87                rsrc_priv_to_props(priv, rtd - rtd->card->rtd);
  88
  89        clk_disable_unprepare(dai_props->clk);
  90}
  91
  92static struct snd_soc_ops rsrc_card_ops = {
  93        .startup = rsrc_card_startup,
  94        .shutdown = rsrc_card_shutdown,
  95};
  96
  97static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
  98{
  99        struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 100        struct snd_soc_dai *dai;
 101        struct snd_soc_dai_link *dai_link;
 102        struct rsrc_card_dai *dai_props;
 103        int num = rtd - rtd->card->rtd;
 104        int ret;
 105
 106        dai_link        = rsrc_priv_to_link(priv, num);
 107        dai_props       = rsrc_priv_to_props(priv, num);
 108        dai             = dai_link->dynamic ?
 109                                rtd->cpu_dai :
 110                                rtd->codec_dai;
 111
 112        if (dai_props->fmt) {
 113                ret = snd_soc_dai_set_fmt(dai, dai_props->fmt);
 114                if (ret && ret != -ENOTSUPP) {
 115                        dev_err(dai->dev, "set_fmt error\n");
 116                        goto err;
 117                }
 118        }
 119
 120        if (dai_props->sysclk) {
 121                ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0);
 122                if (ret && ret != -ENOTSUPP) {
 123                        dev_err(dai->dev, "set_sysclk error\n");
 124                        goto err;
 125                }
 126        }
 127
 128        ret = 0;
 129
 130err:
 131        return ret;
 132}
 133
 134static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 135                                        struct snd_pcm_hw_params *params)
 136{
 137        struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 138        struct snd_interval *rate = hw_param_interval(params,
 139                                                      SNDRV_PCM_HW_PARAM_RATE);
 140
 141        if (!priv->convert_rate)
 142                return 0;
 143
 144        rate->min = rate->max = priv->convert_rate;
 145
 146        return 0;
 147}
 148
 149static int rsrc_card_parse_daifmt(struct device_node *node,
 150                                  struct device_node *np,
 151                                  struct rsrc_card_priv *priv,
 152                                  int idx, bool is_fe)
 153{
 154        struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
 155        struct device_node *bitclkmaster = NULL;
 156        struct device_node *framemaster = NULL;
 157        struct device_node *codec = is_fe ? NULL : np;
 158        unsigned int daifmt;
 159
 160        daifmt = snd_soc_of_parse_daifmt(node, NULL,
 161                                         &bitclkmaster, &framemaster);
 162        daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
 163
 164        if (!bitclkmaster && !framemaster)
 165                return -EINVAL;
 166
 167        if (codec == bitclkmaster)
 168                daifmt |= (codec == framemaster) ?
 169                        SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
 170        else
 171                daifmt |= (codec == framemaster) ?
 172                        SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
 173
 174        dai_props->fmt  = daifmt;
 175
 176        of_node_put(bitclkmaster);
 177        of_node_put(framemaster);
 178
 179        return 0;
 180}
 181
 182static int rsrc_card_parse_links(struct device_node *np,
 183                                 struct rsrc_card_priv *priv,
 184                                 int idx, bool is_fe)
 185{
 186        struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
 187        struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
 188        struct of_phandle_args args;
 189        int ret;
 190
 191        /*
 192         * Get node via "sound-dai = <&phandle port>"
 193         * it will be used as xxx_of_node on soc_bind_dai_link()
 194         */
 195        ret = of_parse_phandle_with_args(np, "sound-dai",
 196                                         "#sound-dai-cells", 0, &args);
 197        if (ret)
 198                return ret;
 199
 200        if (is_fe) {
 201                /* BE is dummy */
 202                dai_link->codec_of_node         = NULL;
 203                dai_link->codec_dai_name        = "snd-soc-dummy-dai";
 204                dai_link->codec_name            = "snd-soc-dummy";
 205
 206                /* FE settings */
 207                dai_link->dynamic               = 1;
 208                dai_link->dpcm_merged_format    = 1;
 209                dai_link->cpu_of_node           = args.np;
 210                snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name);
 211
 212                /* set dai_name */
 213                snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s",
 214                         dai_link->cpu_dai_name);
 215
 216                /*
 217                 * In soc_bind_dai_link() will check cpu name after
 218                 * of_node matching if dai_link has cpu_dai_name.
 219                 * but, it will never match if name was created by
 220                 * fmt_single_name() remove cpu_dai_name if cpu_args
 221                 * was 0. See:
 222                 *      fmt_single_name()
 223                 *      fmt_multiple_name()
 224                 */
 225                if (!args.args_count)
 226                        dai_link->cpu_dai_name = NULL;
 227        } else {
 228                struct device *dev = rsrc_priv_to_dev(priv);
 229                const struct rsrc_card_of_data *of_data;
 230
 231                of_data = rsrc_dev_to_of_data(dev);
 232
 233                /* FE is dummy */
 234                dai_link->cpu_of_node           = NULL;
 235                dai_link->cpu_dai_name          = "snd-soc-dummy-dai";
 236                dai_link->cpu_name              = "snd-soc-dummy";
 237
 238                /* BE settings */
 239                dai_link->no_pcm                = 1;
 240                dai_link->be_hw_params_fixup    = rsrc_card_be_hw_params_fixup;
 241                dai_link->codec_of_node         = args.np;
 242                snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
 243
 244                /* additional name prefix */
 245                priv->codec_conf.of_node        = dai_link->codec_of_node;
 246                priv->codec_conf.name_prefix    = of_data->prefix;
 247
 248                /* set dai_name */
 249                snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s",
 250                         dai_link->codec_dai_name);
 251        }
 252
 253        /* Simple Card assumes platform == cpu */
 254        dai_link->platform_of_node      = dai_link->cpu_of_node;
 255        dai_link->dpcm_playback         = 1;
 256        dai_link->dpcm_capture          = 1;
 257        dai_link->name                  = dai_props->dai_name;
 258        dai_link->stream_name           = dai_props->dai_name;
 259        dai_link->ops                   = &rsrc_card_ops;
 260        dai_link->init                  = rsrc_card_dai_init;
 261
 262        return 0;
 263}
 264
 265static int rsrc_card_parse_clk(struct device_node *np,
 266                               struct rsrc_card_priv *priv,
 267                               int idx, bool is_fe)
 268{
 269        struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
 270        struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
 271        struct clk *clk;
 272        struct device_node *of_np = is_fe ?     dai_link->cpu_of_node :
 273                                                dai_link->codec_of_node;
 274        u32 val;
 275
 276        /*
 277         * Parse dai->sysclk come from "clocks = <&xxx>"
 278         * (if system has common clock)
 279         *  or "system-clock-frequency = <xxx>"
 280         *  or device's module clock.
 281         */
 282        if (of_property_read_bool(np, "clocks")) {
 283                clk = of_clk_get(np, 0);
 284                if (IS_ERR(clk))
 285                        return PTR_ERR(clk);
 286
 287                dai_props->sysclk = clk_get_rate(clk);
 288                dai_props->clk = clk;
 289        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
 290                dai_props->sysclk = val;
 291        } else {
 292                clk = of_clk_get(of_np, 0);
 293                if (!IS_ERR(clk))
 294                        dai_props->sysclk = clk_get_rate(clk);
 295        }
 296
 297        return 0;
 298}
 299
 300static int rsrc_card_dai_link_of(struct device_node *node,
 301                                 struct device_node *np,
 302                                 struct rsrc_card_priv *priv,
 303                                 int idx)
 304{
 305        struct device *dev = rsrc_priv_to_dev(priv);
 306        struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx);
 307        bool is_fe = false;
 308        int ret;
 309
 310        if (0 == strcmp(np->name, "cpu"))
 311                is_fe = true;
 312
 313        ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe);
 314        if (ret < 0)
 315                return ret;
 316
 317        ret = rsrc_card_parse_links(np, priv, idx, is_fe);
 318        if (ret < 0)
 319                return ret;
 320
 321        ret = rsrc_card_parse_clk(np, priv, idx, is_fe);
 322        if (ret < 0)
 323                return ret;
 324
 325        dev_dbg(dev, "\t%s / %04x / %d\n",
 326                dai_props->dai_name,
 327                dai_props->fmt,
 328                dai_props->sysclk);
 329
 330        return ret;
 331}
 332
 333static int rsrc_card_parse_of(struct device_node *node,
 334                              struct rsrc_card_priv *priv,
 335                              struct device *dev)
 336{
 337        const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
 338        struct rsrc_card_dai *props;
 339        struct snd_soc_dai_link *links;
 340        struct device_node *np;
 341        int ret;
 342        int i, num;
 343
 344        if (!node)
 345                return -EINVAL;
 346
 347        num = of_get_child_count(node);
 348        props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL);
 349        links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL);
 350        if (!props || !links)
 351                return -ENOMEM;
 352
 353        priv->dai_props = props;
 354        priv->dai_link  = links;
 355        priv->dai_num   = num;
 356
 357        /* Init snd_soc_card */
 358        priv->snd_card.owner                    = THIS_MODULE;
 359        priv->snd_card.dev                      = dev;
 360        priv->snd_card.dai_link                 = priv->dai_link;
 361        priv->snd_card.num_links                = num;
 362        priv->snd_card.codec_conf               = &priv->codec_conf;
 363        priv->snd_card.num_configs              = 1;
 364        priv->snd_card.of_dapm_routes           = of_data->routes;
 365        priv->snd_card.num_of_dapm_routes       = of_data->num_routes;
 366
 367        /* Parse the card name from DT */
 368        snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
 369
 370        /* sampling rate convert */
 371        of_property_read_u32(node, "convert-rate", &priv->convert_rate);
 372
 373        dev_dbg(dev, "New rsrc-audio-card: %s (%d)\n",
 374                priv->snd_card.name ? priv->snd_card.name : "",
 375                priv->convert_rate);
 376
 377        i = 0;
 378        for_each_child_of_node(node, np) {
 379                ret = rsrc_card_dai_link_of(node, np, priv, i);
 380                if (ret < 0)
 381                        return ret;
 382                i++;
 383        }
 384
 385        if (!priv->snd_card.name)
 386                priv->snd_card.name = priv->snd_card.dai_link->name;
 387
 388        return 0;
 389}
 390
 391/* Decrease the reference count of the device nodes */
 392static int rsrc_card_unref(struct snd_soc_card *card)
 393{
 394        struct snd_soc_dai_link *dai_link;
 395        int num_links;
 396
 397        for (num_links = 0, dai_link = card->dai_link;
 398             num_links < card->num_links;
 399             num_links++, dai_link++) {
 400                of_node_put(dai_link->cpu_of_node);
 401                of_node_put(dai_link->codec_of_node);
 402        }
 403        return 0;
 404}
 405
 406static int rsrc_card_probe(struct platform_device *pdev)
 407{
 408        struct rsrc_card_priv *priv;
 409        struct device_node *np = pdev->dev.of_node;
 410        struct device *dev = &pdev->dev;
 411        int ret;
 412
 413        /* Allocate the private data */
 414        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 415        if (!priv)
 416                return -ENOMEM;
 417
 418        ret = rsrc_card_parse_of(np, priv, dev);
 419        if (ret < 0) {
 420                if (ret != -EPROBE_DEFER)
 421                        dev_err(dev, "parse error %d\n", ret);
 422                goto err;
 423        }
 424
 425        snd_soc_card_set_drvdata(&priv->snd_card, priv);
 426
 427        ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
 428        if (ret >= 0)
 429                return ret;
 430err:
 431        rsrc_card_unref(&priv->snd_card);
 432
 433        return ret;
 434}
 435
 436static int rsrc_card_remove(struct platform_device *pdev)
 437{
 438        struct snd_soc_card *card = platform_get_drvdata(pdev);
 439
 440        return rsrc_card_unref(card);
 441}
 442
 443static struct platform_driver rsrc_card = {
 444        .driver = {
 445                .name = "renesas-src-audio-card",
 446                .of_match_table = rsrc_card_of_match,
 447        },
 448        .probe = rsrc_card_probe,
 449        .remove = rsrc_card_remove,
 450};
 451
 452module_platform_driver(rsrc_card);
 453
 454MODULE_ALIAS("platform:renesas-src-audio-card");
 455MODULE_LICENSE("GPL");
 456MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card");
 457MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 458