linux/sound/soc/stm/stm32_sai.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
   4 *
   5 * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
   6 * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
   7 */
   8
   9#include <linux/bitfield.h>
  10#include <linux/clk.h>
  11#include <linux/delay.h>
  12#include <linux/module.h>
  13#include <linux/of_platform.h>
  14#include <linux/pinctrl/consumer.h>
  15#include <linux/reset.h>
  16
  17#include <sound/dmaengine_pcm.h>
  18#include <sound/core.h>
  19
  20#include "stm32_sai.h"
  21
  22static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai);
  23
  24static const struct stm32_sai_conf stm32_sai_conf_f4 = {
  25        .version = STM_SAI_STM32F4,
  26        .fifo_size = 8,
  27        .has_spdif_pdm = false,
  28        .get_sai_ck_parent = stm32_sai_get_parent_clk,
  29};
  30
  31/*
  32 * Default settings for STM32H7x socs and STM32MP1x.
  33 * These default settings will be overridden if the soc provides
  34 * support of hardware configuration registers.
  35 * - STM32H7: rely on default settings
  36 * - STM32MP1: retrieve settings from registers
  37 */
  38static const struct stm32_sai_conf stm32_sai_conf_h7 = {
  39        .version = STM_SAI_STM32H7,
  40        .fifo_size = 8,
  41        .has_spdif_pdm = true,
  42        .get_sai_ck_parent = stm32_sai_get_parent_clk,
  43};
  44
  45/*
  46 * STM32MP2x:
  47 * - do not use SAI parent clock source selection
  48 * - do not use DMA burst mode
  49 */
  50static const struct stm32_sai_conf stm32_sai_conf_mp25 = {
  51        .no_dma_burst = true,
  52};
  53
  54static const struct of_device_id stm32_sai_ids[] = {
  55        { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 },
  56        { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 },
  57        { .compatible = "st,stm32mp25-sai", .data = (void *)&stm32_sai_conf_mp25 },
  58        {}
  59};
  60
  61static int stm32_sai_pclk_disable(struct device *dev)
  62{
  63        struct stm32_sai_data *sai = dev_get_drvdata(dev);
  64
  65        clk_disable_unprepare(sai->pclk);
  66
  67        return 0;
  68}
  69
  70static int stm32_sai_pclk_enable(struct device *dev)
  71{
  72        struct stm32_sai_data *sai = dev_get_drvdata(dev);
  73        int ret;
  74
  75        ret = clk_prepare_enable(sai->pclk);
  76        if (ret) {
  77                dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
  78                return ret;
  79        }
  80
  81        return 0;
  82}
  83
  84static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
  85{
  86        int ret;
  87
  88        /* Enable peripheral clock to allow GCR register access */
  89        ret = stm32_sai_pclk_enable(&sai->pdev->dev);
  90        if (ret)
  91                return ret;
  92
  93        writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
  94
  95        stm32_sai_pclk_disable(&sai->pdev->dev);
  96
  97        return 0;
  98}
  99
 100static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
 101{
 102        u32 prev_synco;
 103        int ret;
 104
 105        /* Enable peripheral clock to allow GCR register access */
 106        ret = stm32_sai_pclk_enable(&sai->pdev->dev);
 107        if (ret)
 108                return ret;
 109
 110        dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
 111                sai->pdev->dev.of_node,
 112                synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
 113
 114        prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
 115        if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
 116                dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
 117                        sai->pdev->dev.of_node,
 118                        prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
 119                stm32_sai_pclk_disable(&sai->pdev->dev);
 120                return -EINVAL;
 121        }
 122
 123        writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
 124
 125        stm32_sai_pclk_disable(&sai->pdev->dev);
 126
 127        return 0;
 128}
 129
 130static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
 131                              struct device_node *np_provider,
 132                              int synco, int synci)
 133{
 134        struct platform_device *pdev = of_find_device_by_node(np_provider);
 135        struct stm32_sai_data *sai_provider;
 136        int ret;
 137
 138        if (!pdev) {
 139                dev_err(&sai_client->pdev->dev,
 140                        "Device not found for node %pOFn\n", np_provider);
 141                of_node_put(np_provider);
 142                return -ENODEV;
 143        }
 144
 145        sai_provider = platform_get_drvdata(pdev);
 146        if (!sai_provider) {
 147                dev_err(&sai_client->pdev->dev,
 148                        "SAI sync provider data not found\n");
 149                ret = -EINVAL;
 150                goto error;
 151        }
 152
 153        /* Configure sync client */
 154        ret = stm32_sai_sync_conf_client(sai_client, synci);
 155        if (ret < 0)
 156                goto error;
 157
 158        /* Configure sync provider */
 159        ret = stm32_sai_sync_conf_provider(sai_provider, synco);
 160
 161error:
 162        put_device(&pdev->dev);
 163        of_node_put(np_provider);
 164        return ret;
 165}
 166
 167static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai)
 168{
 169        struct device *dev = &sai->pdev->dev;
 170
 171        sai->clk_x8k = devm_clk_get(dev, "x8k");
 172        if (IS_ERR(sai->clk_x8k))
 173                return dev_err_probe(dev, PTR_ERR(sai->clk_x8k),
 174                                     "missing x8k parent clock\n");
 175
 176        sai->clk_x11k = devm_clk_get(dev, "x11k");
 177        if (IS_ERR(sai->clk_x11k))
 178                return dev_err_probe(dev, PTR_ERR(sai->clk_x11k),
 179                                     "missing x11k parent clock\n");
 180
 181        return 0;
 182}
 183
 184static int stm32_sai_probe(struct platform_device *pdev)
 185{
 186        struct stm32_sai_data *sai;
 187        const struct stm32_sai_conf *conf;
 188        struct reset_control *rst;
 189        u32 val;
 190        int ret;
 191
 192        sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 193        if (!sai)
 194                return -ENOMEM;
 195
 196        sai->pdev = pdev;
 197
 198        sai->base = devm_platform_ioremap_resource(pdev, 0);
 199        if (IS_ERR(sai->base))
 200                return PTR_ERR(sai->base);
 201
 202        conf = device_get_match_data(&pdev->dev);
 203        if (conf)
 204                memcpy(&sai->conf, (const struct stm32_sai_conf *)conf,
 205                       sizeof(struct stm32_sai_conf));
 206        else
 207                return -EINVAL;
 208
 209        if (!STM_SAI_IS_F4(sai)) {
 210                sai->pclk = devm_clk_get(&pdev->dev, "pclk");
 211                if (IS_ERR(sai->pclk))
 212                        return dev_err_probe(&pdev->dev, PTR_ERR(sai->pclk),
 213                                             "missing bus clock pclk\n");
 214        }
 215
 216        if (sai->conf.get_sai_ck_parent) {
 217                ret = sai->conf.get_sai_ck_parent(sai);
 218                if (ret)
 219                        return ret;
 220        }
 221
 222        /* init irqs */
 223        sai->irq = platform_get_irq(pdev, 0);
 224        if (sai->irq < 0)
 225                return sai->irq;
 226
 227        /* reset */
 228        rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
 229        if (IS_ERR(rst))
 230                return dev_err_probe(&pdev->dev, PTR_ERR(rst),
 231                                     "Reset controller error\n");
 232
 233        reset_control_assert(rst);
 234        udelay(2);
 235        reset_control_deassert(rst);
 236
 237        /* Enable peripheral clock to allow register access */
 238        ret = clk_prepare_enable(sai->pclk);
 239        if (ret) {
 240                dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
 241                return ret;
 242        }
 243
 244        val = FIELD_GET(SAI_IDR_ID_MASK,
 245                        readl_relaxed(sai->base + STM_SAI_IDR));
 246        if (val == SAI_IPIDR_NUMBER) {
 247                val = readl_relaxed(sai->base + STM_SAI_HWCFGR);
 248                sai->conf.fifo_size = FIELD_GET(SAI_HWCFGR_FIFO_SIZE, val);
 249                sai->conf.has_spdif_pdm = !!FIELD_GET(SAI_HWCFGR_SPDIF_PDM,
 250                                                      val);
 251
 252                val = readl_relaxed(sai->base + STM_SAI_VERR);
 253                sai->conf.version = val;
 254
 255                dev_dbg(&pdev->dev, "SAI version: %lu.%lu registered\n",
 256                        FIELD_GET(SAI_VERR_MAJ_MASK, val),
 257                        FIELD_GET(SAI_VERR_MIN_MASK, val));
 258        }
 259        clk_disable_unprepare(sai->pclk);
 260
 261        sai->set_sync = &stm32_sai_set_sync;
 262        platform_set_drvdata(pdev, sai);
 263
 264        return devm_of_platform_populate(&pdev->dev);
 265}
 266
 267/*
 268 * When pins are shared by two sai sub instances, pins have to be defined
 269 * in sai parent node. In this case, pins state is not managed by alsa fw.
 270 * These pins are managed in suspend/resume callbacks.
 271 */
 272static int stm32_sai_suspend(struct device *dev)
 273{
 274        struct stm32_sai_data *sai = dev_get_drvdata(dev);
 275        int ret;
 276
 277        ret = stm32_sai_pclk_enable(dev);
 278        if (ret)
 279                return ret;
 280
 281        sai->gcr = readl_relaxed(sai->base);
 282        stm32_sai_pclk_disable(dev);
 283
 284        return pinctrl_pm_select_sleep_state(dev);
 285}
 286
 287static int stm32_sai_resume(struct device *dev)
 288{
 289        struct stm32_sai_data *sai = dev_get_drvdata(dev);
 290        int ret;
 291
 292        ret = stm32_sai_pclk_enable(dev);
 293        if (ret)
 294                return ret;
 295
 296        writel_relaxed(sai->gcr, sai->base);
 297        stm32_sai_pclk_disable(dev);
 298
 299        return pinctrl_pm_select_default_state(dev);
 300}
 301
 302static const struct dev_pm_ops stm32_sai_pm_ops = {
 303        SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
 304};
 305
 306MODULE_DEVICE_TABLE(of, stm32_sai_ids);
 307
 308static struct platform_driver stm32_sai_driver = {
 309        .driver = {
 310                .name = "st,stm32-sai",
 311                .of_match_table = stm32_sai_ids,
 312                .pm = pm_ptr(&stm32_sai_pm_ops),
 313        },
 314        .probe = stm32_sai_probe,
 315};
 316
 317module_platform_driver(stm32_sai_driver);
 318
 319MODULE_DESCRIPTION("STM32 Soc SAI Interface");
 320MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
 321MODULE_ALIAS("platform:st,stm32-sai");
 322MODULE_LICENSE("GPL v2");
 323