linux/sound/soc/meson/axg-tdm-formatter.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2//
   3// Copyright (c) 2018 BayLibre, SAS.
   4// Author: Jerome Brunet <jbrunet@baylibre.com>
   5
   6#include <linux/clk.h>
   7#include <linux/module.h>
   8#include <linux/of_platform.h>
   9#include <linux/regmap.h>
  10#include <linux/reset.h>
  11#include <sound/soc.h>
  12
  13#include "axg-tdm-formatter.h"
  14
  15struct axg_tdm_formatter {
  16        struct list_head list;
  17        struct axg_tdm_stream *stream;
  18        const struct axg_tdm_formatter_driver *drv;
  19        struct clk *pclk;
  20        struct clk *sclk;
  21        struct clk *lrclk;
  22        struct clk *sclk_sel;
  23        struct clk *lrclk_sel;
  24        struct reset_control *reset;
  25        bool enabled;
  26        struct regmap *map;
  27};
  28
  29int axg_tdm_formatter_set_channel_masks(struct regmap *map,
  30                                        struct axg_tdm_stream *ts,
  31                                        unsigned int offset)
  32{
  33        unsigned int val, ch = ts->channels;
  34        unsigned long mask;
  35        int i, j;
  36
  37        /*
  38         * Distribute the channels of the stream over the available slots
  39         * of each TDM lane
  40         */
  41        for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
  42                val = 0;
  43                mask = ts->mask[i];
  44
  45                for (j = find_first_bit(&mask, 32);
  46                     (j < 32) && ch;
  47                     j = find_next_bit(&mask, 32, j + 1)) {
  48                        val |= 1 << j;
  49                        ch -= 1;
  50                }
  51
  52                regmap_write(map, offset, val);
  53                offset += regmap_get_reg_stride(map);
  54        }
  55
  56        /*
  57         * If we still have channel left at the end of the process, it means
  58         * the stream has more channels than we can accommodate and we should
  59         * have caught this earlier.
  60         */
  61        if (WARN_ON(ch != 0)) {
  62                pr_err("channel mask error\n");
  63                return -EINVAL;
  64        }
  65
  66        return 0;
  67}
  68EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
  69
  70static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
  71{
  72        struct axg_tdm_stream *ts = formatter->stream;
  73        bool invert;
  74        int ret;
  75
  76        /* Do nothing if the formatter is already enabled */
  77        if (formatter->enabled)
  78                return 0;
  79
  80        /*
  81         * On the g12a (and possibly other SoCs), when a stream using
  82         * multiple lanes is restarted, it will sometimes not start
  83         * from the first lane, but randomly from another used one.
  84         * The result is an unexpected and random channel shift.
  85         *
  86         * The hypothesis is that an HW counter is not properly reset
  87         * and the formatter simply starts on the lane it stopped
  88         * before. Unfortunately, there does not seems to be a way to
  89         * reset this through the registers of the block.
  90         *
  91         * However, the g12a has indenpendent reset lines for each audio
  92         * devices. Using this reset before each start solves the issue.
  93         */
  94        ret = reset_control_reset(formatter->reset);
  95        if (ret)
  96                return ret;
  97
  98        /*
  99         * If sclk is inverted, it means the bit should latched on the
 100         * rising edge which is what our HW expects. If not, we need to
 101         * invert it before the formatter.
 102         */
 103        invert = axg_tdm_sclk_invert(ts->iface->fmt);
 104        ret = clk_set_phase(formatter->sclk, invert ? 0 : 180);
 105        if (ret)
 106                return ret;
 107
 108        /* Setup the stream parameter in the formatter */
 109        ret = formatter->drv->ops->prepare(formatter->map,
 110                                           formatter->drv->quirks,
 111                                           formatter->stream);
 112        if (ret)
 113                return ret;
 114
 115        /* Enable the signal clocks feeding the formatter */
 116        ret = clk_prepare_enable(formatter->sclk);
 117        if (ret)
 118                return ret;
 119
 120        ret = clk_prepare_enable(formatter->lrclk);
 121        if (ret) {
 122                clk_disable_unprepare(formatter->sclk);
 123                return ret;
 124        }
 125
 126        /* Finally, actually enable the formatter */
 127        formatter->drv->ops->enable(formatter->map);
 128        formatter->enabled = true;
 129
 130        return 0;
 131}
 132
 133static void axg_tdm_formatter_disable(struct axg_tdm_formatter *formatter)
 134{
 135        /* Do nothing if the formatter is already disabled */
 136        if (!formatter->enabled)
 137                return;
 138
 139        formatter->drv->ops->disable(formatter->map);
 140        clk_disable_unprepare(formatter->lrclk);
 141        clk_disable_unprepare(formatter->sclk);
 142        formatter->enabled = false;
 143}
 144
 145static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
 146{
 147        struct axg_tdm_stream *ts = formatter->stream;
 148        int ret = 0;
 149
 150        mutex_lock(&ts->lock);
 151
 152        /* Catch up if the stream is already running when we attach */
 153        if (ts->ready) {
 154                ret = axg_tdm_formatter_enable(formatter);
 155                if (ret) {
 156                        pr_err("failed to enable formatter\n");
 157                        goto out;
 158                }
 159        }
 160
 161        list_add_tail(&formatter->list, &ts->formatter_list);
 162out:
 163        mutex_unlock(&ts->lock);
 164        return ret;
 165}
 166
 167static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
 168{
 169        struct axg_tdm_stream *ts = formatter->stream;
 170
 171        mutex_lock(&ts->lock);
 172        list_del(&formatter->list);
 173        mutex_unlock(&ts->lock);
 174
 175        axg_tdm_formatter_disable(formatter);
 176}
 177
 178static int axg_tdm_formatter_power_up(struct axg_tdm_formatter *formatter,
 179                                      struct snd_soc_dapm_widget *w)
 180{
 181        struct axg_tdm_stream *ts = formatter->drv->ops->get_stream(w);
 182        int ret;
 183
 184        /*
 185         * If we don't get a stream at this stage, it would mean that the
 186         * widget is powering up but is not attached to any backend DAI.
 187         * It should not happen, ever !
 188         */
 189        if (WARN_ON(!ts))
 190                return -ENODEV;
 191
 192        /* Clock our device */
 193        ret = clk_prepare_enable(formatter->pclk);
 194        if (ret)
 195                return ret;
 196
 197        /* Reparent the bit clock to the TDM interface */
 198        ret = clk_set_parent(formatter->sclk_sel, ts->iface->sclk);
 199        if (ret)
 200                goto disable_pclk;
 201
 202        /* Reparent the sample clock to the TDM interface */
 203        ret = clk_set_parent(formatter->lrclk_sel, ts->iface->lrclk);
 204        if (ret)
 205                goto disable_pclk;
 206
 207        formatter->stream = ts;
 208        ret = axg_tdm_formatter_attach(formatter);
 209        if (ret)
 210                goto disable_pclk;
 211
 212        return 0;
 213
 214disable_pclk:
 215        clk_disable_unprepare(formatter->pclk);
 216        return ret;
 217}
 218
 219static void axg_tdm_formatter_power_down(struct axg_tdm_formatter *formatter)
 220{
 221        axg_tdm_formatter_dettach(formatter);
 222        clk_disable_unprepare(formatter->pclk);
 223        formatter->stream = NULL;
 224}
 225
 226int axg_tdm_formatter_event(struct snd_soc_dapm_widget *w,
 227                            struct snd_kcontrol *control,
 228                            int event)
 229{
 230        struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
 231        struct axg_tdm_formatter *formatter = snd_soc_component_get_drvdata(c);
 232        int ret = 0;
 233
 234        switch (event) {
 235        case SND_SOC_DAPM_PRE_PMU:
 236                ret = axg_tdm_formatter_power_up(formatter, w);
 237                break;
 238
 239        case SND_SOC_DAPM_PRE_PMD:
 240                axg_tdm_formatter_power_down(formatter);
 241                break;
 242
 243        default:
 244                dev_err(c->dev, "Unexpected event %d\n", event);
 245                return -EINVAL;
 246        }
 247
 248        return ret;
 249}
 250EXPORT_SYMBOL_GPL(axg_tdm_formatter_event);
 251
 252int axg_tdm_formatter_probe(struct platform_device *pdev)
 253{
 254        struct device *dev = &pdev->dev;
 255        const struct axg_tdm_formatter_driver *drv;
 256        struct axg_tdm_formatter *formatter;
 257        void __iomem *regs;
 258        int ret;
 259
 260        drv = of_device_get_match_data(dev);
 261        if (!drv) {
 262                dev_err(dev, "failed to match device\n");
 263                return -ENODEV;
 264        }
 265
 266        formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
 267        if (!formatter)
 268                return -ENOMEM;
 269        platform_set_drvdata(pdev, formatter);
 270        formatter->drv = drv;
 271
 272        regs = devm_platform_ioremap_resource(pdev, 0);
 273        if (IS_ERR(regs))
 274                return PTR_ERR(regs);
 275
 276        formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
 277        if (IS_ERR(formatter->map)) {
 278                dev_err(dev, "failed to init regmap: %ld\n",
 279                        PTR_ERR(formatter->map));
 280                return PTR_ERR(formatter->map);
 281        }
 282
 283        /* Peripharal clock */
 284        formatter->pclk = devm_clk_get(dev, "pclk");
 285        if (IS_ERR(formatter->pclk)) {
 286                ret = PTR_ERR(formatter->pclk);
 287                if (ret != -EPROBE_DEFER)
 288                        dev_err(dev, "failed to get pclk: %d\n", ret);
 289                return ret;
 290        }
 291
 292        /* Formatter bit clock */
 293        formatter->sclk = devm_clk_get(dev, "sclk");
 294        if (IS_ERR(formatter->sclk)) {
 295                ret = PTR_ERR(formatter->sclk);
 296                if (ret != -EPROBE_DEFER)
 297                        dev_err(dev, "failed to get sclk: %d\n", ret);
 298                return ret;
 299        }
 300
 301        /* Formatter sample clock */
 302        formatter->lrclk = devm_clk_get(dev, "lrclk");
 303        if (IS_ERR(formatter->lrclk)) {
 304                ret = PTR_ERR(formatter->lrclk);
 305                if (ret != -EPROBE_DEFER)
 306                        dev_err(dev, "failed to get lrclk: %d\n", ret);
 307                return ret;
 308        }
 309
 310        /* Formatter bit clock input multiplexer */
 311        formatter->sclk_sel = devm_clk_get(dev, "sclk_sel");
 312        if (IS_ERR(formatter->sclk_sel)) {
 313                ret = PTR_ERR(formatter->sclk_sel);
 314                if (ret != -EPROBE_DEFER)
 315                        dev_err(dev, "failed to get sclk_sel: %d\n", ret);
 316                return ret;
 317        }
 318
 319        /* Formatter sample clock input multiplexer */
 320        formatter->lrclk_sel = devm_clk_get(dev, "lrclk_sel");
 321        if (IS_ERR(formatter->lrclk_sel)) {
 322                ret = PTR_ERR(formatter->lrclk_sel);
 323                if (ret != -EPROBE_DEFER)
 324                        dev_err(dev, "failed to get lrclk_sel: %d\n", ret);
 325                return ret;
 326        }
 327
 328        /* Formatter dedicated reset line */
 329        formatter->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
 330        if (IS_ERR(formatter->reset)) {
 331                ret = PTR_ERR(formatter->reset);
 332                if (ret != -EPROBE_DEFER)
 333                        dev_err(dev, "failed to get reset: %d\n", ret);
 334                return ret;
 335        }
 336
 337        return devm_snd_soc_register_component(dev, drv->component_drv,
 338                                               NULL, 0);
 339}
 340EXPORT_SYMBOL_GPL(axg_tdm_formatter_probe);
 341
 342int axg_tdm_stream_start(struct axg_tdm_stream *ts)
 343{
 344        struct axg_tdm_formatter *formatter;
 345        int ret = 0;
 346
 347        mutex_lock(&ts->lock);
 348        ts->ready = true;
 349
 350        /* Start all the formatters attached to the stream */
 351        list_for_each_entry(formatter, &ts->formatter_list, list) {
 352                ret = axg_tdm_formatter_enable(formatter);
 353                if (ret) {
 354                        pr_err("failed to start tdm stream\n");
 355                        goto out;
 356                }
 357        }
 358
 359out:
 360        mutex_unlock(&ts->lock);
 361        return ret;
 362}
 363EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
 364
 365void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
 366{
 367        struct axg_tdm_formatter *formatter;
 368
 369        mutex_lock(&ts->lock);
 370        ts->ready = false;
 371
 372        /* Stop all the formatters attached to the stream */
 373        list_for_each_entry(formatter, &ts->formatter_list, list) {
 374                axg_tdm_formatter_disable(formatter);
 375        }
 376
 377        mutex_unlock(&ts->lock);
 378}
 379EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);
 380
 381struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface)
 382{
 383        struct axg_tdm_stream *ts;
 384
 385        ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 386        if (ts) {
 387                INIT_LIST_HEAD(&ts->formatter_list);
 388                mutex_init(&ts->lock);
 389                ts->iface = iface;
 390        }
 391
 392        return ts;
 393}
 394EXPORT_SYMBOL_GPL(axg_tdm_stream_alloc);
 395
 396void axg_tdm_stream_free(struct axg_tdm_stream *ts)
 397{
 398        /*
 399         * If the list is not empty, it would mean that one of the formatter
 400         * widget is still powered and attached to the interface while we
 401         * are removing the TDM DAI. It should not be possible
 402         */
 403        WARN_ON(!list_empty(&ts->formatter_list));
 404        mutex_destroy(&ts->lock);
 405        kfree(ts);
 406}
 407EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
 408
 409MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
 410MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 411MODULE_LICENSE("GPL v2");
 412