Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge series "ASoC: q6afe: add clocks support" from Srinivas Kandagatla <srinivas.kandagatla@linaro.org>:

q6afe already exposes clocks using apis, but not as proper
clock controller driver. This patch puts those clocks
in to a proper clock controller so that other drivers that
depend on those clocks can be properly expressed.

Srinivas Kandagatla (2):
ASoC: q6afe: dt-bindings: add q6afe clock bindings
ASoC: q6afe-clocks: add q6afe clock controller

.../devicetree/bindings/sound/qcom,q6afe.txt | 23 ++
include/dt-bindings/sound/qcom,q6afe.h | 74 ++++-
sound/soc/qcom/Kconfig | 4 +
sound/soc/qcom/qdsp6/Makefile | 1 +
sound/soc/qcom/qdsp6/q6afe-clocks.c | 270 ++++++++++++++++++
5 files changed, 371 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/qcom/qdsp6/q6afe-clocks.c

--
2.21.0

+371 -1
+23
Documentation/devicetree/bindings/sound/qcom,q6afe.txt
··· 98 98 0 - MSB 99 99 1 - LSB 100 100 101 + = AFE CLOCKSS 102 + "clocks" subnode of the AFE node. It represents q6afe clocks 103 + "clocks" node should have following properties. 104 + - compatible: 105 + Usage: required 106 + Value type: <stringlist> 107 + Definition: must be "qcom,q6afe-clocks" 108 + 109 + - #clock-cells: 110 + Usage: required 111 + Value type: <u32> 112 + Definition: Must be 2. Clock Id followed by 113 + below valid clock coupling attributes. 114 + 1 - for no coupled clock 115 + 2 - for dividend of the coupled clock 116 + 3 - for divisor of the coupled clock 117 + 4 - for inverted and no couple clock 118 + 101 119 = EXAMPLE 102 120 103 121 apr-service@4 { ··· 192 174 reg = <QUATERNARY_MI2S_TX>; 193 175 qcom,sd-lines = <1>; 194 176 }; 177 + }; 178 + 179 + clocks { 180 + compatible = "qcom,q6afe-clocks"; 181 + #clock-cells = <2>; 195 182 }; 196 183 };
+73 -1
include/dt-bindings/sound/qcom,q6afe.h
··· 130 130 #define RX_CODEC_DMA_RX_6 125 131 131 #define RX_CODEC_DMA_RX_7 126 132 132 133 - #endif /* __DT_BINDINGS_Q6_AFE_H__ */ 133 + #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 134 + #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 135 + #define LPASS_CLK_ID_SEC_MI2S_IBIT 3 136 + #define LPASS_CLK_ID_SEC_MI2S_EBIT 4 137 + #define LPASS_CLK_ID_TER_MI2S_IBIT 5 138 + #define LPASS_CLK_ID_TER_MI2S_EBIT 6 139 + #define LPASS_CLK_ID_QUAD_MI2S_IBIT 7 140 + #define LPASS_CLK_ID_QUAD_MI2S_EBIT 8 141 + #define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9 142 + #define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10 143 + #define LPASS_CLK_ID_SPEAKER_I2S_OSR 11 144 + #define LPASS_CLK_ID_QUI_MI2S_IBIT 12 145 + #define LPASS_CLK_ID_QUI_MI2S_EBIT 13 146 + #define LPASS_CLK_ID_SEN_MI2S_IBIT 14 147 + #define LPASS_CLK_ID_SEN_MI2S_EBIT 15 148 + #define LPASS_CLK_ID_INT0_MI2S_IBIT 16 149 + #define LPASS_CLK_ID_INT1_MI2S_IBIT 17 150 + #define LPASS_CLK_ID_INT2_MI2S_IBIT 18 151 + #define LPASS_CLK_ID_INT3_MI2S_IBIT 19 152 + #define LPASS_CLK_ID_INT4_MI2S_IBIT 20 153 + #define LPASS_CLK_ID_INT5_MI2S_IBIT 21 154 + #define LPASS_CLK_ID_INT6_MI2S_IBIT 22 155 + #define LPASS_CLK_ID_QUI_MI2S_OSR 23 156 + #define LPASS_CLK_ID_PRI_PCM_IBIT 24 157 + #define LPASS_CLK_ID_PRI_PCM_EBIT 25 158 + #define LPASS_CLK_ID_SEC_PCM_IBIT 26 159 + #define LPASS_CLK_ID_SEC_PCM_EBIT 27 160 + #define LPASS_CLK_ID_TER_PCM_IBIT 28 161 + #define LPASS_CLK_ID_TER_PCM_EBIT 29 162 + #define LPASS_CLK_ID_QUAD_PCM_IBIT 30 163 + #define LPASS_CLK_ID_QUAD_PCM_EBIT 31 164 + #define LPASS_CLK_ID_QUIN_PCM_IBIT 32 165 + #define LPASS_CLK_ID_QUIN_PCM_EBIT 33 166 + #define LPASS_CLK_ID_QUI_PCM_OSR 34 167 + #define LPASS_CLK_ID_PRI_TDM_IBIT 35 168 + #define LPASS_CLK_ID_PRI_TDM_EBIT 36 169 + #define LPASS_CLK_ID_SEC_TDM_IBIT 37 170 + #define LPASS_CLK_ID_SEC_TDM_EBIT 38 171 + #define LPASS_CLK_ID_TER_TDM_IBIT 39 172 + #define LPASS_CLK_ID_TER_TDM_EBIT 40 173 + #define LPASS_CLK_ID_QUAD_TDM_IBIT 41 174 + #define LPASS_CLK_ID_QUAD_TDM_EBIT 42 175 + #define LPASS_CLK_ID_QUIN_TDM_IBIT 43 176 + #define LPASS_CLK_ID_QUIN_TDM_EBIT 44 177 + #define LPASS_CLK_ID_QUIN_TDM_OSR 45 178 + #define LPASS_CLK_ID_MCLK_1 46 179 + #define LPASS_CLK_ID_MCLK_2 47 180 + #define LPASS_CLK_ID_MCLK_3 48 181 + #define LPASS_CLK_ID_MCLK_4 49 182 + #define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50 183 + #define LPASS_CLK_ID_INT_MCLK_0 51 184 + #define LPASS_CLK_ID_INT_MCLK_1 52 185 + #define LPASS_CLK_ID_MCLK_5 53 186 + #define LPASS_CLK_ID_WSA_CORE_MCLK 54 187 + #define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55 188 + #define LPASS_CLK_ID_VA_CORE_MCLK 56 189 + #define LPASS_CLK_ID_TX_CORE_MCLK 57 190 + #define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58 191 + #define LPASS_CLK_ID_RX_CORE_MCLK 59 192 + #define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60 193 + #define LPASS_CLK_ID_VA_CORE_2X_MCLK 61 134 194 195 + #define LPASS_HW_AVTIMER_VOTE 101 196 + #define LPASS_HW_MACRO_VOTE 102 197 + #define LPASS_HW_DCODEC_VOTE 103 198 + 199 + #define Q6AFE_MAX_CLK_ID 104 200 + 201 + #define LPASS_CLK_ATTRIBUTE_INVALID 0x0 202 + #define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 203 + #define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 204 + #define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3 205 + 206 + #endif /* __DT_BINDINGS_Q6_AFE_H__ */
+4
sound/soc/qcom/Kconfig
··· 63 63 config SND_SOC_QDSP6_AFE_DAI 64 64 tristate 65 65 66 + config SND_SOC_QDSP6_AFE_CLOCKS 67 + tristate 68 + 66 69 config SND_SOC_QDSP6_ADM 67 70 tristate 68 71 ··· 86 83 select SND_SOC_QDSP6_CORE 87 84 select SND_SOC_QDSP6_AFE 88 85 select SND_SOC_QDSP6_AFE_DAI 86 + select SND_SOC_QDSP6_AFE_CLOCKS 89 87 select SND_SOC_QDSP6_ADM 90 88 select SND_SOC_QDSP6_ROUTING 91 89 select SND_SOC_QDSP6_ASM
+1
sound/soc/qcom/qdsp6/Makefile
··· 3 3 obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o 4 4 obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o 5 5 obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.o 6 + obj-$(CONFIG_SND_SOC_QDSP6_AFE_CLOCKS) += q6afe-clocks.o 6 7 obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o 7 8 obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o 8 9 obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o
+270
sound/soc/qcom/qdsp6/q6afe-clocks.c
··· 1 + // SPDX-License-Identifier: GPL-1.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) &(struct q6afe_clk) { \ 15 + .clk_id = id, \ 16 + .afe_clk_id = Q6AFE_##id, \ 17 + .name = #id, \ 18 + .attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \ 19 + .hw.init = &(struct clk_init_data) { \ 20 + .ops = &clk_q6afe_ops, \ 21 + .name = #id, \ 22 + }, \ 23 + } 24 + 25 + #define Q6AFE_VOTE_CLK(id, blkid, n) &(struct q6afe_clk) { \ 26 + .clk_id = id, \ 27 + .afe_clk_id = blkid, \ 28 + .name = #n, \ 29 + .hw.init = &(struct clk_init_data) { \ 30 + .ops = &clk_vote_q6afe_ops, \ 31 + .name = #id, \ 32 + }, \ 33 + } 34 + 35 + struct q6afe_clk { 36 + struct device *dev; 37 + int clk_id; 38 + int afe_clk_id; 39 + char *name; 40 + int attributes; 41 + int rate; 42 + uint32_t handle; 43 + struct clk_hw hw; 44 + }; 45 + 46 + #define to_q6afe_clk(_hw) container_of(_hw, struct q6afe_clk, hw) 47 + 48 + struct q6afe_cc { 49 + struct device *dev; 50 + struct q6afe_clk **clks; 51 + int num_clks; 52 + }; 53 + 54 + static int clk_q6afe_prepare(struct clk_hw *hw) 55 + { 56 + struct q6afe_clk *clk = to_q6afe_clk(hw); 57 + 58 + return q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes, 59 + Q6AFE_LPASS_CLK_ROOT_DEFAULT, clk->rate); 60 + } 61 + 62 + static void clk_q6afe_unprepare(struct clk_hw *hw) 63 + { 64 + struct q6afe_clk *clk = to_q6afe_clk(hw); 65 + 66 + q6afe_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes, 67 + Q6AFE_LPASS_CLK_ROOT_DEFAULT, 0); 68 + } 69 + 70 + static int clk_q6afe_set_rate(struct clk_hw *hw, unsigned long rate, 71 + unsigned long parent_rate) 72 + { 73 + struct q6afe_clk *clk = to_q6afe_clk(hw); 74 + 75 + clk->rate = rate; 76 + 77 + return 0; 78 + } 79 + 80 + static unsigned long clk_q6afe_recalc_rate(struct clk_hw *hw, 81 + unsigned long parent_rate) 82 + { 83 + struct q6afe_clk *clk = to_q6afe_clk(hw); 84 + 85 + return clk->rate; 86 + } 87 + 88 + static long clk_q6afe_round_rate(struct clk_hw *hw, unsigned long rate, 89 + unsigned long *parent_rate) 90 + { 91 + return rate; 92 + } 93 + 94 + static const struct clk_ops clk_q6afe_ops = { 95 + .prepare = clk_q6afe_prepare, 96 + .unprepare = clk_q6afe_unprepare, 97 + .set_rate = clk_q6afe_set_rate, 98 + .round_rate = clk_q6afe_round_rate, 99 + .recalc_rate = clk_q6afe_recalc_rate, 100 + }; 101 + 102 + static int clk_vote_q6afe_block(struct clk_hw *hw) 103 + { 104 + struct q6afe_clk *clk = to_q6afe_clk(hw); 105 + 106 + return q6afe_vote_lpass_core_hw(clk->dev, clk->afe_clk_id, 107 + clk->name, &clk->handle); 108 + } 109 + 110 + static void clk_unvote_q6afe_block(struct clk_hw *hw) 111 + { 112 + struct q6afe_clk *clk = to_q6afe_clk(hw); 113 + 114 + q6afe_unvote_lpass_core_hw(clk->dev, clk->afe_clk_id, clk->handle); 115 + } 116 + 117 + static const struct clk_ops clk_vote_q6afe_ops = { 118 + .prepare = clk_vote_q6afe_block, 119 + .unprepare = clk_unvote_q6afe_block, 120 + }; 121 + 122 + struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = { 123 + [LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT), 124 + [LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT), 125 + [LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT), 126 + [LPASS_CLK_ID_SEC_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT), 127 + [LPASS_CLK_ID_TER_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT), 128 + [LPASS_CLK_ID_TER_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT), 129 + [LPASS_CLK_ID_QUAD_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT), 130 + [LPASS_CLK_ID_QUAD_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT), 131 + [LPASS_CLK_ID_SPEAKER_I2S_IBIT] = 132 + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT), 133 + [LPASS_CLK_ID_SPEAKER_I2S_EBIT] = 134 + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT), 135 + [LPASS_CLK_ID_SPEAKER_I2S_OSR] = 136 + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR), 137 + [LPASS_CLK_ID_QUI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT), 138 + [LPASS_CLK_ID_QUI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT), 139 + [LPASS_CLK_ID_SEN_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT), 140 + [LPASS_CLK_ID_SEN_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT), 141 + [LPASS_CLK_ID_INT0_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT), 142 + [LPASS_CLK_ID_INT1_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT), 143 + [LPASS_CLK_ID_INT2_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT), 144 + [LPASS_CLK_ID_INT3_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT), 145 + [LPASS_CLK_ID_INT4_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT), 146 + [LPASS_CLK_ID_INT5_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT), 147 + [LPASS_CLK_ID_INT6_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT), 148 + [LPASS_CLK_ID_QUI_MI2S_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR), 149 + [LPASS_CLK_ID_PRI_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT), 150 + [LPASS_CLK_ID_PRI_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT), 151 + [LPASS_CLK_ID_SEC_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT), 152 + [LPASS_CLK_ID_SEC_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT), 153 + [LPASS_CLK_ID_TER_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT), 154 + [LPASS_CLK_ID_TER_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT), 155 + [LPASS_CLK_ID_QUAD_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT), 156 + [LPASS_CLK_ID_QUAD_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT), 157 + [LPASS_CLK_ID_QUIN_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT), 158 + [LPASS_CLK_ID_QUIN_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT), 159 + [LPASS_CLK_ID_QUI_PCM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR), 160 + [LPASS_CLK_ID_PRI_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT), 161 + [LPASS_CLK_ID_PRI_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT), 162 + [LPASS_CLK_ID_SEC_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT), 163 + [LPASS_CLK_ID_SEC_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT), 164 + [LPASS_CLK_ID_TER_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT), 165 + [LPASS_CLK_ID_TER_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT), 166 + [LPASS_CLK_ID_QUAD_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT), 167 + [LPASS_CLK_ID_QUAD_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT), 168 + [LPASS_CLK_ID_QUIN_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT), 169 + [LPASS_CLK_ID_QUIN_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT), 170 + [LPASS_CLK_ID_QUIN_TDM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR), 171 + [LPASS_CLK_ID_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_1), 172 + [LPASS_CLK_ID_MCLK_2] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_2), 173 + [LPASS_CLK_ID_MCLK_3] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_3), 174 + [LPASS_CLK_ID_MCLK_4] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_4), 175 + [LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE] = 176 + Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE), 177 + [LPASS_CLK_ID_INT_MCLK_0] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0), 178 + [LPASS_CLK_ID_INT_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1), 179 + [LPASS_CLK_ID_WSA_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), 180 + [LPASS_CLK_ID_WSA_CORE_NPL_MCLK] = 181 + Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), 182 + [LPASS_CLK_ID_VA_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_MCLK), 183 + [LPASS_CLK_ID_TX_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_MCLK), 184 + [LPASS_CLK_ID_TX_CORE_NPL_MCLK] = 185 + Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK), 186 + [LPASS_CLK_ID_RX_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_MCLK), 187 + [LPASS_CLK_ID_RX_CORE_NPL_MCLK] = 188 + Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK), 189 + [LPASS_CLK_ID_VA_CORE_2X_MCLK] = 190 + Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK), 191 + [LPASS_HW_AVTIMER_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE, 192 + Q6AFE_LPASS_CORE_AVTIMER_BLOCK, 193 + "LPASS_AVTIMER_MACRO"), 194 + [LPASS_HW_MACRO_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE, 195 + Q6AFE_LPASS_CORE_HW_MACRO_BLOCK, 196 + "LPASS_HW_MACRO"), 197 + [LPASS_HW_DCODEC_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE, 198 + Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK, 199 + "LPASS_HW_DCODEC"), 200 + }; 201 + 202 + static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec, 203 + void *data) 204 + { 205 + struct q6afe_cc *cc = data; 206 + unsigned int idx = clkspec->args[0]; 207 + unsigned int attr = clkspec->args[1]; 208 + 209 + if (idx >= cc->num_clks || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) { 210 + dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr); 211 + return ERR_PTR(-EINVAL); 212 + } 213 + 214 + if (cc->clks[idx]) { 215 + cc->clks[idx]->attributes = attr; 216 + return &cc->clks[idx]->hw; 217 + } 218 + 219 + return ERR_PTR(-ENOENT); 220 + } 221 + 222 + static int q6afe_clock_dev_probe(struct platform_device *pdev) 223 + { 224 + struct q6afe_cc *cc; 225 + struct device *dev = &pdev->dev; 226 + int i, ret; 227 + 228 + cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); 229 + if (!cc) 230 + return -ENOMEM; 231 + 232 + cc->clks = &q6afe_clks[0]; 233 + cc->num_clks = ARRAY_SIZE(q6afe_clks); 234 + for (i = 0; i < ARRAY_SIZE(q6afe_clks); i++) { 235 + if (!q6afe_clks[i]) 236 + continue; 237 + 238 + q6afe_clks[i]->dev = dev; 239 + 240 + ret = devm_clk_hw_register(dev, &q6afe_clks[i]->hw); 241 + if (ret) 242 + return ret; 243 + } 244 + 245 + ret = of_clk_add_hw_provider(dev->of_node, q6afe_of_clk_hw_get, cc); 246 + if (ret) 247 + return ret; 248 + 249 + dev_set_drvdata(dev, cc); 250 + 251 + return 0; 252 + } 253 + 254 + static const struct of_device_id q6afe_clock_device_id[] = { 255 + { .compatible = "qcom,q6afe-clocks" }, 256 + {}, 257 + }; 258 + MODULE_DEVICE_TABLE(of, q6afe_clock_device_id); 259 + 260 + static struct platform_driver q6afe_clock_platform_driver = { 261 + .driver = { 262 + .name = "q6afe-clock", 263 + .of_match_table = of_match_ptr(q6afe_clock_device_id), 264 + }, 265 + .probe = q6afe_clock_dev_probe, 266 + }; 267 + module_platform_driver(q6afe_clock_platform_driver); 268 + 269 + MODULE_DESCRIPTION("Q6 Audio Frontend clock driver"); 270 + MODULE_LICENSE("GPL v2");