[alsa-devel] [PATCH 2/2] ASoC: AMD: Enable/Disable auxiliary clock via common clock framework

Agrawal, Akshu Akshu.Agrawal at amd.com
Wed Apr 11 12:07:47 CEST 2018



On 4/10/2018 11:13 AM, Daniel Kurtz wrote:
>> On 4/4/2018 12:27 AM, Daniel Kurtz wrote:
>>> Hi Akshu,
>>>
>>> On Fri, Mar 30, 2018 at 4:05 AM Akshu Agrawal <akshu.agrawal at amd.com>
> wrote:
>>>
>>>> This enables/disables and sets auxiliary clock at 25Mhz. It uses
>>>> common clock framework for proper ref counting. This approach will
>>>> save power in comparison to keeping it always On in firmware.
>>>
>>> I have some general concern with the approach in this patch:
>>>
>>> (1) The 25 MHz clock being created here is a general system clock
>>> resource.  I think it should be created in an SoC clock driver, rather
> than
>>> here in an audio machine driver.   This has several advantages:
>>>      (a) the clock resource would be available for other boards that use
> it but
>>> don't use this particular audio machine driver
>>>      (b) the clock would be instantiated at boot, rather than at machine
> driver
>>> load.
>>>      (c) the machine driver would not then need the additional clkdev
> code
>>>
>>> (2) The oscout1 clock is a pretty standard clk_gate with a clk_mux.  We
> can
>>> use some standard helpers to better model the clock tree rather than
>>> rewriting them:
>>>
>>> static struct clk *clk_48m;
>>> static struct clk *clk_25m;
>>> static struct clk *clk_oscout1_mux;
>>> static struct clk *clk_oscout1;
>>>
>>> static const char *clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };
>>>
>>> {
>>>       clk_48m = clk_register_fixed_rate(dev, "clk48MHz", NULL, 0,
> 48000000);
>>>       clk_25m = clk_register_fixed_rate(dev, "clk25MHz", NULL, 0,
> 25000000);
>>>
>>>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>       res_base = devm_ioremap_nocache(dev, res->start,
> resource_size(res));
>>>
>>>       clk_oscout1_mux = clk_register_mux(dev, "oscout1_mux",
>>>           clk_oscout1_parents, ARRAY_SIZE(clk_oscout1_parents),
>>>           0, res_base + CLKDRVSTR2, OSCOUT1CLK25MHZ, 3, 0, NULL);
>>>
>>>       clk_set_parent(clk_oscout1_mux, clk_25m);
>>>
>>>       clk_oscout1 = clk_register_gate(dev, "oscout1", "oscout1_mux", 0,
>>>             res_base + MISCCLKCNTL1, OSCCLKENB, 0, NULL);
>>>
>>>
>>> (3) IIUC, the 25 MHz clock (oscout1) is actually the da7219's mclk.  The
>>> da7219 already
>>> has infrastructure to enable/disable its mclk as needed.  Once we
> establish
>>> the system clock,
>>> we can then wire this clock up to the da7219 via ACPI / devicetree
>>> properties.
>>>
>> The above design is something used in almost all ARM based platform
>> where we define all mux, pll, divider and gate and then each device uses
>> them though the devicetree.
>> The clock here are controlled in firmware. Enable/disable is handled in
>> firmware, where this being the exception case. Hence, I don't think it
>> will be of much value add.
> 
> The value add to properly modeling the SoC's clock tree is highlighted
> above.
> In addition to making the code more understandable, and the SoC easier to
> use for other designs in the future, the clock tree as expressed via
> debugfs (/sys/kernel/debug/clk/clk_summary) will make more sense.
> In the particular case of the acp-da7219-max98357a.c machine driver and
> da7219 codec driver, properly modeling the oscout1 clock tree as a
> fixed_clks+mux+gate and then passing it to da7219 as its mclk will allow
> the mclk driver to do what it expects using its existing code - set the
> mclk rate (via oscout1's parent mux selector) and then enable/disable as
> needed.
> 
>> For ST/CZ we have other platforms which do not use this clock. They have
>> a dedicated Oscillator for the codec.
> 
> Exactly, such platforms will just not use this machine driver and this
> clock will be defined properly, but remain in the state programmed by
> firmware.
> 
>> If you think its beneficial for other platform based on ST/CZ then maybe
>> we can take this as a separate activity. Where we move the clocks to a
>> common file and use the same framework.
> 
> Moving the clock configuration out of acp-da7219-max98357a.c allows this
> system clock to be available independent of when this machine driver kernel
> module is loaded.
> 

I understand the advantages of having it moved to drivers/clk and also 
connecting it to d7219's mclk. This is good to have feature for other 
ST/CZ platforms. Would take it up this as a separate activity.

> [snip]
> 
>>>> +struct cz_clock {
>>>> +       const char* acp_clks_name;
>>>
>>> I still think you should remove acp_clks_name, acp_clks_lookup and
> acp_clks
>>> from the struct since they are used locally during
>>> register_acpd7219_clocks, and, afaict, never referenced again.
>>>
>> I don't think putting in struct is bad. Plus it helps me get res_base
>> value on clk_enable using clk_hw.
> 
> Yes, you can use a struct to store the fields that are needed, like
> res_base.  However, fields that are only used locally in a single function
> waste memory and confuse driver reviewers, since storing them in the struct
> implies that the field is state that must be preserved, when in fact the
> field's use is transitory.
> 
> Please remove the extraneous fields from the struct: acp_clk_name,
> acp_clk_lookup, and acp_clk (unless you write an unregister that releases
> this clock, and therefore needs this).
> 
>> +struct cz_clock {
>> +     const char* acp_clk_name;
>> +     struct clk_hw acp_clk_hw;
>> +     struct clk_lookup *acp_clk_lookup;
>> +     struct clk *acp_clk;
>> +     void __iomem *res_base;
>> +};
> 
Accepted.

> [snip]
> 
>>>
>>> Enable on hw_params() and disable on hw_free() doesn't sound balanced?
>>> Will there always be exactly one hw_free() for every hw_params()?
>>>
>> Yes, all resources allocated by hw_paramns are freed in hw_free.
> 
> Right, but is it possible for hw_params() to get called mulitple times
> *without* hw_free()?
> This would cause more enables than disables.
> 
> Documentation/sound/kernel-api/writing-an-alsa-driver.rst says:
> """
> Note that this and ``prepare`` callbacks may be called multiple times
> per initialization. For example, the OSS emulation may call these
> callbacks at each change via its ioctl.
> 
> Thus, you need to be careful not to allocate the same buffers many
> times, which will lead to memory leaks! Calling the helper function
> above many times is OK. It will release the previous buffer
> automatically when it was already allocated.
> """
> 
I get there is a remote possibility that hw_params maybe called multiple 
times without hw_free (though I haven't come across it in my testing).
The other option was to use trigger. But, that is not possible as kernel 
crashes when we call clk_prepare_enable(da7219_dai_clk) from trigger 
registered to a non da7219 codec, like of max98357

3>[   45.690976] BUG: sleeping function called from invalid context at 
/mnt/host/source/src/third_party/kernel/v4.14/kernel/locking/mutex.c:23
8
<3>[   45.690988] in_atomic(): 1, irqs_disabled(): 1, pid: 2104, name: aplay
<4>[   45.690996] CPU: 1 PID: 2104 Comm: aplay Not tainted 4.14.31 #7
<4>[   45.691001] Hardware name: Google Grunt/Grunt, BIOS 
Google_Grunt.10531.0.0 03/30/2018
<4>[   45.691005] Call Trace:
<4>[   45.691022]  dump_stack+0x4d/0x63
<4>[   45.691033]  ___might_sleep+0x11f/0x12e
<4>[   45.691040]  mutex_lock+0x20/0x42
<4>[   45.691049]  regmap_update_bits_base+0x35/0x7c
<4>[   45.691056]  snd_soc_component_update_bits+0x39/0x67
<4>[   45.691064]  ? __mutex_trylock_or_owner+0x4d/0x6a
<4>[   45.691073]  da7219_dai_clks_prepare+0x27/0x2b [snd_soc_da7219]
<4>[   45.691081]  clk_core_prepare+0xa8/0x122
<4>[   45.691088]  clk_prepare+0x21/0x2d
<4>[   45.691095]  cz_da7219_trigger+0x45/0xfb 
[snd_soc_acp_da7219mx98357_mach]
<4>[   45.691101]  soc_pcm_trigger+0xf6/0x112

> [snip]
> 
>>>> +static int register_acpd7219_clocks(struct platform_device *pdev)
>>>
>>> Where is the corresponding unregister?  Isn't this a module that can be
>>> unloaded?
>>>
>> I see none of the machine driver have registered a remove callback, I
>> wonder why?
> 
> I don't know, either?  Perhaps because they don't instantiate anything that
> won't be cleaned up by devm_ on unload?
> This patch as written is currently instantiating clocks, though, so should
> really clean that up when removed.
> 
Accepted.

> -Dan
> 

Regards,
Akshu


More information about the Alsa-devel mailing list