2018-11-06 15:57:34 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2018 BayLibre , SAS .
* Author : Neil Armstrong < narmstrong @ baylibre . com >
*/
# include <linux/clk-provider.h>
clk: meson: rework and clean drivers dependencies
Initially, the meson clock directory only hosted 2 controllers drivers,
for meson8 and gxbb. At the time, both used the same set of clock drivers
so managing the dependencies was not a big concern.
Since this ancient time, entropy did its job, controllers with different
requirement and specific clock drivers have been added. Unfortunately, we
did not do a great job at managing the dependencies between the
controllers and the different clock drivers. Some drivers, such as
clk-phase or vid-pll-div, are compiled even if they are useless on the
target (meson8). As we are adding new controllers, we need to be able to
pick a driver w/o pulling the whole thing.
The patch aims to clean things up by:
* providing a dedicated CONFIG_ for each clock drivers
* allowing clock drivers to be compiled as a modules, if possible
* stating explicitly which drivers are required by each controller.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://lkml.kernel.org/r/20190201125841.26785-5-jbrunet@baylibre.com
2019-02-01 13:58:41 +01:00
# include <linux/module.h>
# include "clk-regmap.h"
# include "vid-pll-div.h"
2018-11-06 15:57:34 +01:00
static inline struct meson_vid_pll_div_data *
meson_vid_pll_div_data ( struct clk_regmap * clk )
{
return ( struct meson_vid_pll_div_data * ) clk - > data ;
}
/*
* This vid_pll divided is a fully programmable fractionnal divider to
* achieve complex video clock rates .
*
* Here are provided the commonly used fraction values provided by Amlogic .
*/
struct vid_pll_div {
unsigned int shift_val ;
unsigned int shift_sel ;
unsigned int divider ;
unsigned int multiplier ;
} ;
# define VID_PLL_DIV(_val, _sel, _ft, _fb) \
{ \
. shift_val = ( _val ) , \
. shift_sel = ( _sel ) , \
. divider = ( _ft ) , \
. multiplier = ( _fb ) , \
}
static const struct vid_pll_div vid_pll_div_table [ ] = {
VID_PLL_DIV ( 0x0aaa , 0 , 2 , 1 ) , /* 2/1 => /2 */
VID_PLL_DIV ( 0x5294 , 2 , 5 , 2 ) , /* 5/2 => /2.5 */
VID_PLL_DIV ( 0x0db6 , 0 , 3 , 1 ) , /* 3/1 => /3 */
VID_PLL_DIV ( 0x36cc , 1 , 7 , 2 ) , /* 7/2 => /3.5 */
VID_PLL_DIV ( 0x6666 , 2 , 15 , 4 ) , /* 15/4 => /3.75 */
VID_PLL_DIV ( 0x0ccc , 0 , 4 , 1 ) , /* 4/1 => /4 */
VID_PLL_DIV ( 0x739c , 2 , 5 , 1 ) , /* 5/1 => /5 */
VID_PLL_DIV ( 0x0e38 , 0 , 6 , 1 ) , /* 6/1 => /6 */
VID_PLL_DIV ( 0x0000 , 3 , 25 , 4 ) , /* 25/4 => /6.25 */
VID_PLL_DIV ( 0x3c78 , 1 , 7 , 1 ) , /* 7/1 => /7 */
VID_PLL_DIV ( 0x78f0 , 2 , 15 , 2 ) , /* 15/2 => /7.5 */
VID_PLL_DIV ( 0x0fc0 , 0 , 12 , 1 ) , /* 12/1 => /12 */
VID_PLL_DIV ( 0x3f80 , 1 , 14 , 1 ) , /* 14/1 => /14 */
VID_PLL_DIV ( 0x7f80 , 2 , 15 , 1 ) , /* 15/1 => /15 */
} ;
# define to_meson_vid_pll_div(_hw) \
container_of ( _hw , struct meson_vid_pll_div , hw )
2018-12-03 13:52:56 -08:00
static const struct vid_pll_div * _get_table_val ( unsigned int shift_val ,
unsigned int shift_sel )
2018-11-06 15:57:34 +01:00
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( vid_pll_div_table ) ; + + i ) {
if ( vid_pll_div_table [ i ] . shift_val = = shift_val & &
vid_pll_div_table [ i ] . shift_sel = = shift_sel )
return & vid_pll_div_table [ i ] ;
}
return NULL ;
}
static unsigned long meson_vid_pll_div_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct meson_vid_pll_div_data * pll_div = meson_vid_pll_div_data ( clk ) ;
const struct vid_pll_div * div ;
div = _get_table_val ( meson_parm_read ( clk - > map , & pll_div - > val ) ,
meson_parm_read ( clk - > map , & pll_div - > sel ) ) ;
if ( ! div | | ! div - > divider ) {
2019-03-27 16:13:48 +01:00
pr_debug ( " %s: Invalid config value for vid_pll_div \n " , __func__ ) ;
return 0 ;
2018-11-06 15:57:34 +01:00
}
return DIV_ROUND_UP_ULL ( parent_rate * div - > multiplier , div - > divider ) ;
}
const struct clk_ops meson_vid_pll_div_ro_ops = {
. recalc_rate = meson_vid_pll_div_recalc_rate ,
} ;
clk: meson: rework and clean drivers dependencies
Initially, the meson clock directory only hosted 2 controllers drivers,
for meson8 and gxbb. At the time, both used the same set of clock drivers
so managing the dependencies was not a big concern.
Since this ancient time, entropy did its job, controllers with different
requirement and specific clock drivers have been added. Unfortunately, we
did not do a great job at managing the dependencies between the
controllers and the different clock drivers. Some drivers, such as
clk-phase or vid-pll-div, are compiled even if they are useless on the
target (meson8). As we are adding new controllers, we need to be able to
pick a driver w/o pulling the whole thing.
The patch aims to clean things up by:
* providing a dedicated CONFIG_ for each clock drivers
* allowing clock drivers to be compiled as a modules, if possible
* stating explicitly which drivers are required by each controller.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://lkml.kernel.org/r/20190201125841.26785-5-jbrunet@baylibre.com
2019-02-01 13:58:41 +01:00
EXPORT_SYMBOL_GPL ( meson_vid_pll_div_ro_ops ) ;
MODULE_DESCRIPTION ( " Amlogic video pll divider driver " ) ;
MODULE_AUTHOR ( " Neil Armstrong <narmstrong@baylibre.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;