2018-02-12 15:58:32 +01:00
// SPDX-License-Identifier: GPL-2.0
2018-05-16 10:50:40 +02:00
/*
* Copyright ( c ) 2018 BayLibre , SAS .
* Author : Jerome Brunet < jbrunet @ baylibre . com >
*/
2018-02-12 15:58:32 +01:00
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>
2018-02-12 15:58:32 +01:00
# include "clk-regmap.h"
static int clk_regmap_gate_endisable ( struct clk_hw * hw , int enable )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_gate_data * gate = clk_get_regmap_gate_data ( clk ) ;
int set = gate - > flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0 ;
set ^ = enable ;
return regmap_update_bits ( clk - > map , gate - > offset , BIT ( gate - > bit_idx ) ,
set ? BIT ( gate - > bit_idx ) : 0 ) ;
}
static int clk_regmap_gate_enable ( struct clk_hw * hw )
{
return clk_regmap_gate_endisable ( hw , 1 ) ;
}
static void clk_regmap_gate_disable ( struct clk_hw * hw )
{
clk_regmap_gate_endisable ( hw , 0 ) ;
}
static int clk_regmap_gate_is_enabled ( struct clk_hw * hw )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_gate_data * gate = clk_get_regmap_gate_data ( clk ) ;
unsigned int val ;
regmap_read ( clk - > map , gate - > offset , & val ) ;
if ( gate - > flags & CLK_GATE_SET_TO_DISABLE )
val ^ = BIT ( gate - > bit_idx ) ;
val & = BIT ( gate - > bit_idx ) ;
return val ? 1 : 0 ;
}
const struct clk_ops clk_regmap_gate_ops = {
. enable = clk_regmap_gate_enable ,
. disable = clk_regmap_gate_disable ,
. is_enabled = clk_regmap_gate_is_enabled ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_gate_ops ) ;
2018-11-22 22:40:15 +01:00
const struct clk_ops clk_regmap_gate_ro_ops = {
. is_enabled = clk_regmap_gate_is_enabled ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_gate_ro_ops ) ;
2018-02-12 15:58:32 +01:00
static unsigned long clk_regmap_div_recalc_rate ( struct clk_hw * hw ,
unsigned long prate )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_div_data * div = clk_get_regmap_div_data ( clk ) ;
unsigned int val ;
int ret ;
ret = regmap_read ( clk - > map , div - > offset , & val ) ;
if ( ret )
/* Gives a hint that something is wrong */
return 0 ;
val > > = div - > shift ;
val & = clk_div_mask ( div - > width ) ;
return divider_recalc_rate ( hw , prate , val , div - > table , div - > flags ,
div - > width ) ;
}
2021-06-28 00:39:59 +02:00
static int clk_regmap_div_determine_rate ( struct clk_hw * hw ,
struct clk_rate_request * req )
2018-02-12 15:58:32 +01:00
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_div_data * div = clk_get_regmap_div_data ( clk ) ;
unsigned int val ;
int ret ;
/* if read only, just return current value */
if ( div - > flags & CLK_DIVIDER_READ_ONLY ) {
ret = regmap_read ( clk - > map , div - > offset , & val ) ;
if ( ret )
2021-06-28 00:39:59 +02:00
return ret ;
2018-02-12 15:58:32 +01:00
val > > = div - > shift ;
val & = clk_div_mask ( div - > width ) ;
2021-06-28 00:39:59 +02:00
return divider_ro_determine_rate ( hw , req , div - > table ,
div - > width , div - > flags , val ) ;
2018-02-12 15:58:32 +01:00
}
2021-06-28 00:39:59 +02:00
return divider_determine_rate ( hw , req , div - > table , div - > width ,
div - > flags ) ;
2018-02-12 15:58:32 +01:00
}
static int clk_regmap_div_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_div_data * div = clk_get_regmap_div_data ( clk ) ;
unsigned int val ;
int ret ;
ret = divider_get_val ( rate , parent_rate , div - > table , div - > width ,
div - > flags ) ;
if ( ret < 0 )
return ret ;
val = ( unsigned int ) ret < < div - > shift ;
return regmap_update_bits ( clk - > map , div - > offset ,
clk_div_mask ( div - > width ) < < div - > shift , val ) ;
} ;
/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
const struct clk_ops clk_regmap_divider_ops = {
. recalc_rate = clk_regmap_div_recalc_rate ,
2021-06-28 00:39:59 +02:00
. determine_rate = clk_regmap_div_determine_rate ,
2018-02-12 15:58:32 +01:00
. set_rate = clk_regmap_div_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_divider_ops ) ;
const struct clk_ops clk_regmap_divider_ro_ops = {
. recalc_rate = clk_regmap_div_recalc_rate ,
2021-06-28 00:39:59 +02:00
. determine_rate = clk_regmap_div_determine_rate ,
2018-02-12 15:58:32 +01:00
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_divider_ro_ops ) ;
static u8 clk_regmap_mux_get_parent ( struct clk_hw * hw )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_mux_data * mux = clk_get_regmap_mux_data ( clk ) ;
unsigned int val ;
int ret ;
ret = regmap_read ( clk - > map , mux - > offset , & val ) ;
if ( ret )
return ret ;
val > > = mux - > shift ;
val & = mux - > mask ;
return clk_mux_val_to_index ( hw , mux - > table , mux - > flags , val ) ;
}
static int clk_regmap_mux_set_parent ( struct clk_hw * hw , u8 index )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_mux_data * mux = clk_get_regmap_mux_data ( clk ) ;
unsigned int val = clk_mux_index_to_val ( mux - > table , mux - > flags , index ) ;
return regmap_update_bits ( clk - > map , mux - > offset ,
mux - > mask < < mux - > shift ,
val < < mux - > shift ) ;
}
2018-04-09 15:59:21 +02:00
static int clk_regmap_mux_determine_rate ( struct clk_hw * hw ,
struct clk_rate_request * req )
{
struct clk_regmap * clk = to_clk_regmap ( hw ) ;
struct clk_regmap_mux_data * mux = clk_get_regmap_mux_data ( clk ) ;
return clk_mux_determine_rate_flags ( hw , req , mux - > flags ) ;
}
2018-02-12 15:58:32 +01:00
const struct clk_ops clk_regmap_mux_ops = {
. get_parent = clk_regmap_mux_get_parent ,
. set_parent = clk_regmap_mux_set_parent ,
2018-04-09 15:59:21 +02:00
. determine_rate = clk_regmap_mux_determine_rate ,
2018-02-12 15:58:32 +01:00
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_mux_ops ) ;
const struct clk_ops clk_regmap_mux_ro_ops = {
. get_parent = clk_regmap_mux_get_parent ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_mux_ro_ops ) ;
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
MODULE_DESCRIPTION ( " Amlogic regmap backed clock driver " ) ;
MODULE_AUTHOR ( " Jerome Brunet <jbrunet@baylibre.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;