55 * Copyright (C) 2022 Marek Vasut <[email protected] > 66 */
77
8+ #include <linux/auxiliary_bus.h>
89#include <linux/clk-provider.h>
910#include <linux/device.h>
1011#include <linux/io.h>
1314#include <linux/of.h>
1415#include <linux/platform_device.h>
1516#include <linux/pm_runtime.h>
17+ #include <linux/slab.h>
1618
1719#include <dt-bindings/clock/imx8mp-clock.h>
1820
@@ -154,6 +156,15 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = {
154156 PDM_SEL, 2, 0 \
155157 }
156158
159+ #define CLK_GATE_PARENT (gname , cname , pname ) \
160+ { \
161+ gname"_cg", \
162+ IMX8MP_CLK_AUDIOMIX_##cname, \
163+ { .fw_name = pname, .name = pname }, NULL, 1, \
164+ CLKEN0 + 4 * !!(IMX8MP_CLK_AUDIOMIX_##cname / 32), \
165+ 1, IMX8MP_CLK_AUDIOMIX_##cname % 32 \
166+ }
167+
157168struct clk_imx8mp_audiomix_sel {
158169 const char * name ;
159170 int clkid ;
@@ -171,14 +182,14 @@ static struct clk_imx8mp_audiomix_sel sels[] = {
171182 CLK_GATE ("earc" , EARC_IPG ),
172183 CLK_GATE ("ocrama" , OCRAMA_IPG ),
173184 CLK_GATE ("aud2htx" , AUD2HTX_IPG ),
174- CLK_GATE ("earc_phy" , EARC_PHY ),
185+ CLK_GATE_PARENT ("earc_phy" , EARC_PHY , "sai_pll_out_div2" ),
175186 CLK_GATE ("sdma2" , SDMA2_ROOT ),
176187 CLK_GATE ("sdma3" , SDMA3_ROOT ),
177188 CLK_GATE ("spba2" , SPBA2_ROOT ),
178189 CLK_GATE ("dsp" , DSP_ROOT ),
179190 CLK_GATE ("dspdbg" , DSPDBG_ROOT ),
180191 CLK_GATE ("edma" , EDMA_ROOT ),
181- CLK_GATE ("audpll" , AUDPLL_ROOT ),
192+ CLK_GATE_PARENT ("audpll" , AUDPLL_ROOT , "osc_24m" ),
182193 CLK_GATE ("mu2" , MU2_ROOT ),
183194 CLK_GATE ("mu3" , MU3_ROOT ),
184195 CLK_PDM ,
@@ -217,6 +228,63 @@ struct clk_imx8mp_audiomix_priv {
217228 struct clk_hw_onecell_data clk_data ;
218229};
219230
231+ #if IS_ENABLED (CONFIG_RESET_CONTROLLER )
232+
233+ static void clk_imx8mp_audiomix_reset_unregister_adev (void * _adev )
234+ {
235+ struct auxiliary_device * adev = _adev ;
236+
237+ auxiliary_device_delete (adev );
238+ auxiliary_device_uninit (adev );
239+ }
240+
241+ static void clk_imx8mp_audiomix_reset_adev_release (struct device * dev )
242+ {
243+ struct auxiliary_device * adev = to_auxiliary_dev (dev );
244+
245+ kfree (adev );
246+ }
247+
248+ static int clk_imx8mp_audiomix_reset_controller_register (struct device * dev ,
249+ struct clk_imx8mp_audiomix_priv * priv )
250+ {
251+ struct auxiliary_device * adev __free (kfree ) = NULL ;
252+ int ret ;
253+
254+ if (!of_property_present (dev -> of_node , "#reset-cells" ))
255+ return 0 ;
256+
257+ adev = kzalloc (sizeof (* adev ), GFP_KERNEL );
258+ if (!adev )
259+ return - ENOMEM ;
260+
261+ adev -> name = "reset" ;
262+ adev -> dev .parent = dev ;
263+ adev -> dev .release = clk_imx8mp_audiomix_reset_adev_release ;
264+
265+ ret = auxiliary_device_init (adev );
266+ if (ret )
267+ return ret ;
268+
269+ ret = auxiliary_device_add (adev );
270+ if (ret ) {
271+ auxiliary_device_uninit (adev );
272+ return ret ;
273+ }
274+
275+ return devm_add_action_or_reset (dev , clk_imx8mp_audiomix_reset_unregister_adev ,
276+ no_free_ptr (adev ));
277+ }
278+
279+ #else /* !CONFIG_RESET_CONTROLLER */
280+
281+ static int clk_imx8mp_audiomix_reset_controller_register (struct clk_imx8mp_audiomix_priv * priv )
282+ {
283+ return 0 ;
284+ }
285+
286+ #endif /* !CONFIG_RESET_CONTROLLER */
287+
220288static void clk_imx8mp_audiomix_save_restore (struct device * dev , bool save )
221289{
222290 struct clk_imx8mp_audiomix_priv * priv = dev_get_drvdata (dev );
@@ -269,12 +337,12 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
269337 for (i = 0 ; i < ARRAY_SIZE (sels ); i ++ ) {
270338 if (sels [i ].num_parents == 1 ) {
271339 hw = devm_clk_hw_register_gate_parent_data (dev ,
272- sels [i ].name , & sels [i ].parent , 0 ,
340+ sels [i ].name , & sels [i ].parent , CLK_SET_RATE_PARENT ,
273341 base + sels [i ].reg , sels [i ].shift , 0 , NULL );
274342 } else {
275343 hw = devm_clk_hw_register_mux_parent_data_table (dev ,
276344 sels [i ].name , sels [i ].parents ,
277- sels [i ].num_parents , 0 ,
345+ sels [i ].num_parents , CLK_SET_RATE_PARENT ,
278346 base + sels [i ].reg ,
279347 sels [i ].shift , sels [i ].width ,
280348 0 , NULL , NULL );
@@ -317,7 +385,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
317385 clk_hw_data -> hws [IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS ] = hw ;
318386
319387 hw = devm_clk_hw_register_gate (dev , "sai_pll_out" , "sai_pll_bypass" ,
320- 0 , base + SAI_PLL_GNRL_CTL , 13 ,
388+ CLK_SET_RATE_PARENT ,
389+ base + SAI_PLL_GNRL_CTL , 13 ,
321390 0 , NULL );
322391 if (IS_ERR (hw )) {
323392 ret = PTR_ERR (hw );
@@ -326,7 +395,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
326395 clk_hw_data -> hws [IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT ] = hw ;
327396
328397 hw = devm_clk_hw_register_fixed_factor (dev , "sai_pll_out_div2" ,
329- "sai_pll_out" , 0 , 1 , 2 );
398+ "sai_pll_out" ,
399+ CLK_SET_RATE_PARENT , 1 , 2 );
330400 if (IS_ERR (hw )) {
331401 ret = PTR_ERR (hw );
332402 goto err_clk_register ;
@@ -337,6 +407,10 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
337407 if (ret )
338408 goto err_clk_register ;
339409
410+ ret = clk_imx8mp_audiomix_reset_controller_register (dev , priv );
411+ if (ret )
412+ goto err_clk_register ;
413+
340414 pm_runtime_put_sync (dev );
341415 return 0 ;
342416
0 commit comments