linux/sound/soc/qcom/qdsp6/q6afe-clocks.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2020, Linaro Limited
   3
   4#include <linux/err.h>
   5#include <linux/init.h>
   6#include <linux/clk-provider.h>
   7#include <linux/module.h>
   8#include <linux/device.h>
   9#include <linux/platform_device.h>
  10#include <linux/of.h>
  11#include <linux/slab.h>
  12#include "q6afe.h"
  13
  14#define Q6AFE_CLK(id) {                                 \
  15                .clk_id = id,                           \
  16                .afe_clk_id     = Q6AFE_##id,           \
  17                .name = #id,                            \
  18                .rate = 19200000,                       \
  19        }
  20
  21#define Q6AFE_VOTE_CLK(id, blkid, n) {                  \
  22                .clk_id = id,                           \
  23                .afe_clk_id = blkid,                    \
  24                .name = n,                              \
  25        }
  26
  27struct q6afe_clk_init {
  28        int clk_id;
  29        int afe_clk_id;
  30        char *name;
  31        int rate;
  32};
  33
  34struct q6afe_clk {
  35        struct device *dev;
  36        int afe_clk_id;
  37        int attributes;
  38        int rate;
  39        uint32_t handle;
  40        struct clk_hw hw;
  41};
  42
  43#define to_q6afe_clk(_hw) container_of(_hw, struct q6afe_clk, hw)
  44
  45struct q6afe_cc {
  46        struct device *dev;
  47        struct q6afe_clk *clks[Q6AFE_MAX_CLK_ID];
  48};
  49
  50static int clk_q6afe_prepare(struct clk_hw *hw)
  51{
  52        struct q6afe_clk *clk = to_q6afe_clk(hw);
  53
  54        return q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes,
  55                                     Q6AFE_LPASS_CLK_ROOT_DEFAULT, clk->rate);
  56}
  57
  58static void clk_q6afe_unprepare(struct clk_hw *hw)
  59{
  60        struct q6afe_clk *clk = to_q6afe_clk(hw);
  61
  62        q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes,
  63                              Q6AFE_LPASS_CLK_ROOT_DEFAULT, 0);
  64}
  65
  66static int clk_q6afe_set_rate(struct clk_hw *hw, unsigned long rate,
  67                              unsigned long parent_rate)
  68{
  69        struct q6afe_clk *clk = to_q6afe_clk(hw);
  70
  71        clk->rate = rate;
  72
  73        return 0;
  74}
  75
  76static unsigned long clk_q6afe_recalc_rate(struct clk_hw *hw,
  77                                           unsigned long parent_rate)
  78{
  79        struct q6afe_clk *clk = to_q6afe_clk(hw);
  80
  81        return clk->rate;
  82}
  83
  84static long clk_q6afe_round_rate(struct clk_hw *hw, unsigned long rate,
  85                                 unsigned long *parent_rate)
  86{
  87        return rate;
  88}
  89
  90static const struct clk_ops clk_q6afe_ops = {
  91        .prepare        = clk_q6afe_prepare,
  92        .unprepare      = clk_q6afe_unprepare,
  93        .set_rate       = clk_q6afe_set_rate,
  94        .round_rate     = clk_q6afe_round_rate,
  95        .recalc_rate    = clk_q6afe_recalc_rate,
  96};
  97
  98static int clk_vote_q6afe_block(struct clk_hw *hw)
  99{
 100        struct q6afe_clk *clk = to_q6afe_clk(hw);
 101
 102        return q6afe_vote_lpass_core_hw(clk->dev, clk->afe_clk_id,
 103                                        clk_hw_get_name(&clk->hw), &clk->handle);
 104}
 105
 106static void clk_unvote_q6afe_block(struct clk_hw *hw)
 107{
 108        struct q6afe_clk *clk = to_q6afe_clk(hw);
 109
 110        q6afe_unvote_lpass_core_hw(clk->dev, clk->afe_clk_id, clk->handle);
 111}
 112
 113static const struct clk_ops clk_vote_q6afe_ops = {
 114        .prepare        = clk_vote_q6afe_block,
 115        .unprepare      = clk_unvote_q6afe_block,
 116};
 117
 118static const struct q6afe_clk_init q6afe_clks[] = {
 119        Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT),
 120        Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT),
 121        Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT),
 122        Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT),
 123        Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT),
 124        Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT),
 125        Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT),
 126        Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT),
 127        Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT),
 128        Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT),
 129        Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR),
 130        Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT),
 131        Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT),
 132        Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT),
 133        Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT),
 134        Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT),
 135        Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT),
 136        Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT),
 137        Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT),
 138        Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT),
 139        Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT),
 140        Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT),
 141        Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR),
 142        Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT),
 143        Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT),
 144        Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT),
 145        Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT),
 146        Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT),
 147        Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT),
 148        Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT),
 149        Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT),
 150        Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT),
 151        Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT),
 152        Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR),
 153        Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT),
 154        Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT),
 155        Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT),
 156        Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT),
 157        Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT),
 158        Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT),
 159        Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT),
 160        Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT),
 161        Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT),
 162        Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT),
 163        Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR),
 164        Q6AFE_CLK(LPASS_CLK_ID_MCLK_1),
 165        Q6AFE_CLK(LPASS_CLK_ID_MCLK_2),
 166        Q6AFE_CLK(LPASS_CLK_ID_MCLK_3),
 167        Q6AFE_CLK(LPASS_CLK_ID_MCLK_4),
 168        Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE),
 169        Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0),
 170        Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1),
 171        Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK),
 172        Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK),
 173        Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_MCLK),
 174        Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_MCLK),
 175        Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK),
 176        Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_MCLK),
 177        Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK),
 178        Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK),
 179        Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE,
 180                       Q6AFE_LPASS_CORE_AVTIMER_BLOCK,
 181                       "LPASS_AVTIMER_MACRO"),
 182        Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE,
 183                       Q6AFE_LPASS_CORE_HW_MACRO_BLOCK,
 184                       "LPASS_HW_MACRO"),
 185        Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE,
 186                       Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK,
 187                       "LPASS_HW_DCODEC"),
 188};
 189
 190static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec,
 191                                          void *data)
 192{
 193        struct q6afe_cc *cc = data;
 194        unsigned int idx = clkspec->args[0];
 195        unsigned int attr = clkspec->args[1];
 196
 197        if (idx >= Q6AFE_MAX_CLK_ID || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) {
 198                dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr);
 199                return ERR_PTR(-EINVAL);
 200        }
 201
 202        if (cc->clks[idx]) {
 203                cc->clks[idx]->attributes = attr;
 204                return &cc->clks[idx]->hw;
 205        }
 206
 207        return ERR_PTR(-ENOENT);
 208}
 209
 210static int q6afe_clock_dev_probe(struct platform_device *pdev)
 211{
 212        struct q6afe_cc *cc;
 213        struct device *dev = &pdev->dev;
 214        int i, ret;
 215
 216        cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
 217        if (!cc)
 218                return -ENOMEM;
 219
 220        cc->dev = dev;
 221        for (i = 0; i < ARRAY_SIZE(q6afe_clks); i++) {
 222                unsigned int id = q6afe_clks[i].clk_id;
 223                struct clk_init_data init = {
 224                        .name =  q6afe_clks[i].name,
 225                };
 226                struct q6afe_clk *clk;
 227
 228                clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
 229                if (!clk)
 230                        return -ENOMEM;
 231
 232                clk->dev = dev;
 233                clk->afe_clk_id = q6afe_clks[i].afe_clk_id;
 234                clk->rate = q6afe_clks[i].rate;
 235                clk->hw.init = &init;
 236
 237                if (clk->rate)
 238                        init.ops = &clk_q6afe_ops;
 239                else
 240                        init.ops = &clk_vote_q6afe_ops;
 241
 242                cc->clks[id] = clk;
 243
 244                ret = devm_clk_hw_register(dev, &clk->hw);
 245                if (ret)
 246                        return ret;
 247        }
 248
 249        ret = devm_of_clk_add_hw_provider(dev, q6afe_of_clk_hw_get, cc);
 250        if (ret)
 251                return ret;
 252
 253        dev_set_drvdata(dev, cc);
 254
 255        return 0;
 256}
 257
 258#ifdef CONFIG_OF
 259static const struct of_device_id q6afe_clock_device_id[] = {
 260        { .compatible = "qcom,q6afe-clocks" },
 261        {},
 262};
 263MODULE_DEVICE_TABLE(of, q6afe_clock_device_id);
 264#endif
 265
 266static struct platform_driver q6afe_clock_platform_driver = {
 267        .driver = {
 268                .name = "q6afe-clock",
 269                .of_match_table = of_match_ptr(q6afe_clock_device_id),
 270        },
 271        .probe = q6afe_clock_dev_probe,
 272};
 273module_platform_driver(q6afe_clock_platform_driver);
 274
 275MODULE_DESCRIPTION("Q6 Audio Frontend clock driver");
 276MODULE_LICENSE("GPL v2");
 277