I look for rationale of design of imx_clk_divider(), choice of CLK_SET_RATE_PARENT for such clock instances like CAN_PODF.
and here is the line of my interest from clk-imx6ul.c:
787b4271a6a0c (Frank Li 2015-07-10 02:09:42 +0800 302) clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
At 1st I want to be confident of that I read assumptions right and my understanding of above statement is like following:
1.1. "can_sel" stands for parent clock instance to "can_podf",
1.2. CLK_SET_RATE_PARENT stands for that changes to "can_podf" will be propagated to clock mutliplexer as
depicted in i.MX 6ULL Applications Processor Reference Manual, Rev. 1, 11/2017 on page 630, section 18: CCM
I want to find a right API way from perspective of loadable kernel driver module to change value of the CAM_PODF divisor only.
1.3 And because of the way clks[IMX6UL_CLK_CAN_PODF] was created it seems that multiplexer may be affected too even that it is not related to change of the part of "18.6.9 CCM Serial Clock Multiplexer Register 2 (CCM_CSCMR2)" for CAN_PODF
I conducted following test by adding this code to clk-imx6ul.c:
clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6);
printk("%s:%d \"can_podf\" %p\n", __FUNCTION__, __LINE__, clks[IMX6UL_CLK_CAN_PODF]);
printk("%s:%d clk_get(\"can_podf\") %p\n", __FUNCTION__, __LINE__, clk_get(NULL, "can_podf"));
struct clk *can_podf = clks[IMX6UL_CLK_CAN_PODF];
int rate = clk_get_rate(can_podf);
printk("%s:%d clk_podf rate %u\n", __FUNCTION__, __LINE__, rate);
rate = clk_get_rate(can_podf);
printk("%s:%d ->1: clk_podf rate %u\n", __FUNCTION__, __LINE__, rate);
My goal was to change the podf only not messing up with the CCM_CSCMR2 register directly.
And here is kernel log from running the test:
[ 0.000000] imx6ul_clocks_init:299 "can_podf" 88010dc0
[ 0.000000] imx6ul_clocks_init:300 clk_get("can_podf") fffffffe
[ 0.000000] imx6ul_clocks_init:305 clk_podf rate 0
[ 0.000000] Division by zero in kernel.
[ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.11 #17
[ 0.000000] Hardware name: Freescale i.MX6 UltraLite (Device Tree)
[ 0.000000] [<8010ed88>] (unwind_backtrace) from [<8010b390>] (show_stack+0x10/0x14)
[ 0.000000] [<8010b390>] (show_stack) from [<803ad944>] (dump_stack+0x78/0x8c)
[ 0.000000] [<803ad944>] (dump_stack) from [<803ab970>] (Ldiv0_64+0x8/0x18)
[ 0.000000] [<803ab970>] (Ldiv0_64) from [<80427b0c>] (divider_get_val+0x15c/0x17c)
[ 0.000000] [<80427b0c>] (divider_get_val) from [<80427b54>] (clk_divider_set_rate+0x28/0xc0)
[ 0.000000] [<80427b54>] (clk_divider_set_rate) from [<804265dc>] (clk_change_rate+0x194/0x248)
[ 0.000000] [<804265dc>] (clk_change_rate) from [<804266f8>] (clk_core_set_rate_nolock+0x68/0xb0)
[ 0.000000] [<804266f8>] (clk_core_set_rate_nolock) from [<80426760>] (clk_set_rate+0x20/0x30)
[ 0.000000] [<80426760>] (clk_set_rate) from [<80e33274>] (imx6ul_clocks_init+0x1930/0x3aa8)
[ 0.000000] [<80e33274>] (imx6ul_clocks_init) from [<80e1ea04>] (of_clk_init+0x15c/0x1e8)
[ 0.000000] [<80e1ea04>] (of_clk_init) from [<80e04528>] (time_init+0x24/0x2c)
[ 0.000000] [<80e04528>] (time_init) from [<80e00b34>] (start_kernel+0x254/0x388)
[ 0.000000] [<80e00b34>] (start_kernel) from [<8000807c>] (0x8000807c)
[ 0.000000] imx6ul_clocks_init:310 ->1: clk_podf rate 0
2.1. Surprisingly clk_get(NULL||&dev, "can_podf") returns ERR_PTR;
How can I get the pointer to "can_podf" from the driver's module ?
2.2 clk_get_rate() on can_podf instance returns 0 which is invalid because default divider settings is "/2" ie CCM_CSCMR2[7:2] = 1 thus I expected to see 1 or 2 as result but 0.
2.3 clk_set_rate(, 1) causes integer division by 0.
I reckon that if whole "common clock" is designed correctly then this "0" division stands for mistake in clk-imx6ul.c
see also claim 1.3. multiplexer and divider are chained so there is parent relationship indeed but I reckon that these two hardware modules are usually independent from each other, at least I would like to have a facility to select clock source and divisor number, unless there is some well designed abstract clock instance which can set both multiplexer and divider with regard to final flexcan frequency: e.g. clk_set_rate(the_abstract_clock, 24e6 or 30e6 or some other value from finite set with regard to section 18.3 CCM Clock Tree of i.MX 6ULL Applications Processor Reference Manual, Rev. 1, 11/2017). It seems there is no such abstract clock working.
2.4 clk_set_rate() was not successful likely.
I look for solution which will allow to change flexcan clock from default 30MHz, ie pll3_sw_clk clock (60M) /2 to my desired value from perspective of kernel driver module and this solution should not depend on some "quirks" made to clk-imx6ul.c
It turned out that using clk_set_rate() too early, ie just right after instance of the CAN_PODF divider was created, ends up with that division by 0.
if the "clock" freq. setting is moved to the end of all clocks initialization then the CSCMR2[7:2] has expected value.
[ 0.000000] imx6ul_clocks_init:532 clk_podf rate 30000000, CCM_CSCMR2 13192c06
[ 0.000000] imx6ul_clocks_init:537 clk_podf rate 60000000, CCM_CSCMR2 13192c02
Furthermore it is possible to use clk_set_rate(clk_get( ,"per"), freq) from the driver and following clk_get_rate() confirms that the change was successful.