mirror of https://gitee.com/openkylin/linux.git
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
This commit is contained in:
parent
cb78ba7629
commit
889c2b7ec4
|
@ -1,27 +1,47 @@
|
|||
config COMMON_CLK_AMLOGIC
|
||||
bool
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
select COMMON_CLK_REGMAP_MESON
|
||||
config COMMON_CLK_MESON_INPUT
|
||||
tristate
|
||||
|
||||
config COMMON_CLK_AMLOGIC_AUDIO
|
||||
bool
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
select COMMON_CLK_AMLOGIC
|
||||
|
||||
config COMMON_CLK_MESON_AO
|
||||
bool
|
||||
depends on OF
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
select COMMON_CLK_REGMAP_MESON
|
||||
select RESET_CONTROLLER
|
||||
|
||||
config COMMON_CLK_REGMAP_MESON
|
||||
bool
|
||||
config COMMON_CLK_MESON_REGMAP
|
||||
tristate
|
||||
select REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_DUALDIV
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_MPLL
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_PHASE
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_PLL
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_SCLK_DIV
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_VID_PLL_DIV
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
|
||||
config COMMON_CLK_MESON_AO_CLKC
|
||||
tristate
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_INPUT
|
||||
select RESET_CONTROLLER
|
||||
|
||||
config COMMON_CLK_MESON8B
|
||||
bool
|
||||
select COMMON_CLK_AMLOGIC
|
||||
depends on ARCH_MESON
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_MPLL
|
||||
select COMMON_CLK_MESON_PLL
|
||||
select MFD_SYSCON
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
Support for the clock controller on AmLogic S802 (Meson8),
|
||||
|
@ -30,8 +50,14 @@ config COMMON_CLK_MESON8B
|
|||
|
||||
config COMMON_CLK_GXBB
|
||||
bool
|
||||
select COMMON_CLK_AMLOGIC
|
||||
select COMMON_CLK_MESON_AO
|
||||
depends on ARCH_MESON
|
||||
select COMMON_CLK_MESON_INPUT
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_DUALDIV
|
||||
select COMMON_CLK_MESON_VID_PLL_DIV
|
||||
select COMMON_CLK_MESON_MPLL
|
||||
select COMMON_CLK_MESON_PLL
|
||||
select COMMON_CLK_MESON_AO_CLKC
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Support for the clock controller on AmLogic S905 devices, aka gxbb.
|
||||
|
@ -39,8 +65,13 @@ config COMMON_CLK_GXBB
|
|||
|
||||
config COMMON_CLK_AXG
|
||||
bool
|
||||
select COMMON_CLK_AMLOGIC
|
||||
select COMMON_CLK_MESON_AO
|
||||
depends on ARCH_MESON
|
||||
select COMMON_CLK_MESON_INPUT
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_DUALDIV
|
||||
select COMMON_CLK_MESON_MPLL
|
||||
select COMMON_CLK_MESON_PLL
|
||||
select COMMON_CLK_MESON_AO_CLKC
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Support for the clock controller on AmLogic A113D devices, aka axg.
|
||||
|
@ -48,8 +79,11 @@ config COMMON_CLK_AXG
|
|||
|
||||
config COMMON_CLK_AXG_AUDIO
|
||||
tristate "Meson AXG Audio Clock Controller Driver"
|
||||
depends on COMMON_CLK_AXG
|
||||
select COMMON_CLK_AMLOGIC_AUDIO
|
||||
depends on ARCH_MESON
|
||||
select COMMON_CLK_MESON_INPUT
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_PHASE
|
||||
select COMMON_CLK_MESON_SCLK_DIV
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Support for the audio clock controller on AmLogic A113D devices,
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
#
|
||||
# Makefile for Meson specific clk
|
||||
#
|
||||
# Amlogic clock drivers
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o clk-dualdiv.o
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
|
||||
|
||||
# Amlogic Clock controllers
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
|
||||
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include "clkc.h"
|
||||
#include "meson-aoclk.h"
|
||||
#include "axg-aoclk.h"
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-dualdiv.h"
|
||||
|
||||
#define IN_PREFIX "ao-in-"
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clkc-audio.h"
|
||||
#include "axg-audio.h"
|
||||
#include "clk-input.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-phase.h"
|
||||
#include "sclk-div.h"
|
||||
|
||||
#define AXG_MST_IN_COUNT 8
|
||||
#define AXG_SLV_SCLK_COUNT 10
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "clkc.h"
|
||||
#include "clk-input.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-mpll.h"
|
||||
#include "axg.h"
|
||||
|
||||
#define IN_PREFIX "ee-in-"
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clkc.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-dualdiv.h"
|
||||
|
||||
static inline struct meson_clk_dualdiv_data *
|
||||
meson_clk_dualdiv_data(struct clk_regmap *clk)
|
||||
|
@ -128,3 +131,8 @@ const struct clk_ops meson_clk_dualdiv_ro_ops = {
|
|||
.recalc_rate = meson_clk_dualdiv_recalc_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic dual divider driver");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLK_DUALDIV_H
|
||||
#define __MESON_CLK_DUALDIV_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "parm.h"
|
||||
|
||||
struct meson_clk_dualdiv_param {
|
||||
unsigned int n1;
|
||||
unsigned int n2;
|
||||
unsigned int m1;
|
||||
unsigned int m2;
|
||||
unsigned int dual;
|
||||
};
|
||||
|
||||
struct meson_clk_dualdiv_data {
|
||||
struct parm n1;
|
||||
struct parm n2;
|
||||
struct parm m1;
|
||||
struct parm m2;
|
||||
struct parm dual;
|
||||
const struct meson_clk_dualdiv_param *table;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_clk_dualdiv_ops;
|
||||
extern const struct clk_ops meson_clk_dualdiv_ro_ops;
|
||||
|
||||
#endif /* __MESON_CLK_DUALDIV_H */
|
|
@ -7,7 +7,8 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include "clkc.h"
|
||||
#include <linux/module.h>
|
||||
#include "clk-input.h"
|
||||
|
||||
static const struct clk_ops meson_clk_no_ops = {};
|
||||
|
||||
|
@ -42,3 +43,7 @@ struct clk_hw *meson_clk_hw_register_input(struct device *dev,
|
|||
return ret ? ERR_PTR(ret) : hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_clk_hw_register_input);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic clock input helper");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLK_INPUT_H
|
||||
#define __MESON_CLK_INPUT_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct device;
|
||||
|
||||
struct clk_hw *meson_clk_hw_register_input(struct device *dev,
|
||||
const char *of_name,
|
||||
const char *clk_name,
|
||||
unsigned long flags);
|
||||
|
||||
#endif /* __MESON_CLK_INPUT_H */
|
|
@ -12,7 +12,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clkc.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-mpll.h"
|
||||
|
||||
#define SDM_DEN 16384
|
||||
#define N2_MIN 4
|
||||
|
@ -138,9 +142,15 @@ const struct clk_ops meson_clk_mpll_ro_ops = {
|
|||
.recalc_rate = mpll_recalc_rate,
|
||||
.round_rate = mpll_round_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops);
|
||||
|
||||
const struct clk_ops meson_clk_mpll_ops = {
|
||||
.recalc_rate = mpll_recalc_rate,
|
||||
.round_rate = mpll_round_rate,
|
||||
.set_rate = mpll_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic MPLL driver");
|
||||
MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLK_MPLL_H
|
||||
#define __MESON_CLK_MPLL_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "parm.h"
|
||||
|
||||
struct meson_clk_mpll_data {
|
||||
struct parm sdm;
|
||||
struct parm sdm_en;
|
||||
struct parm n2;
|
||||
struct parm ssen;
|
||||
struct parm misc;
|
||||
spinlock_t *lock;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
extern const struct clk_ops meson_clk_mpll_ro_ops;
|
||||
extern const struct clk_ops meson_clk_mpll_ops;
|
||||
|
||||
#endif /* __MESON_CLK_MPLL_H */
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clkc.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-phase.h"
|
||||
|
||||
#define phase_step(_width) (360 / (1 << (_width)))
|
||||
|
||||
|
@ -15,13 +18,12 @@ meson_clk_phase_data(struct clk_regmap *clk)
|
|||
return (struct meson_clk_phase_data *)clk->data;
|
||||
}
|
||||
|
||||
int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
|
||||
static int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
|
||||
{
|
||||
return phase_step(width) * val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
|
||||
|
||||
unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
|
||||
static unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
|
||||
{
|
||||
unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
|
||||
|
||||
|
@ -31,7 +33,6 @@ unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
|
|||
*/
|
||||
return val % (1 << width);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
|
||||
|
||||
static int meson_clk_phase_get_phase(struct clk_hw *hw)
|
||||
{
|
||||
|
@ -61,3 +62,67 @@ const struct clk_ops meson_clk_phase_ops = {
|
|||
.set_phase = meson_clk_phase_set_phase,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
|
||||
|
||||
/*
|
||||
* This is a special clock for the audio controller.
|
||||
* The phase of mst_sclk clock output can be controlled independently
|
||||
* for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
|
||||
* Controlling these 3 phases as just one makes things simpler and
|
||||
* give the same clock view to all the element on the i2s bus.
|
||||
* If necessary, we can still control the phase in the tdm block
|
||||
* which makes these independent control redundant.
|
||||
*/
|
||||
static inline struct meson_clk_triphase_data *
|
||||
meson_clk_triphase_data(struct clk_regmap *clk)
|
||||
{
|
||||
return (struct meson_clk_triphase_data *)clk->data;
|
||||
}
|
||||
|
||||
static void meson_clk_triphase_sync(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
/* Get phase 0 and sync it to phase 1 and 2 */
|
||||
val = meson_parm_read(clk->map, &tph->ph0);
|
||||
meson_parm_write(clk->map, &tph->ph1, val);
|
||||
meson_parm_write(clk->map, &tph->ph2, val);
|
||||
}
|
||||
|
||||
static int meson_clk_triphase_get_phase(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
/* Phase are in sync, reading phase 0 is enough */
|
||||
val = meson_parm_read(clk->map, &tph->ph0);
|
||||
|
||||
return meson_clk_degrees_from_val(val, tph->ph0.width);
|
||||
}
|
||||
|
||||
static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
|
||||
meson_parm_write(clk->map, &tph->ph0, val);
|
||||
meson_parm_write(clk->map, &tph->ph1, val);
|
||||
meson_parm_write(clk->map, &tph->ph2, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops meson_clk_triphase_ops = {
|
||||
.init = meson_clk_triphase_sync,
|
||||
.get_phase = meson_clk_triphase_get_phase,
|
||||
.set_phase = meson_clk_triphase_set_phase,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic phase driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLK_PHASE_H
|
||||
#define __MESON_CLK_PHASE_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "parm.h"
|
||||
|
||||
struct meson_clk_phase_data {
|
||||
struct parm ph;
|
||||
};
|
||||
|
||||
struct meson_clk_triphase_data {
|
||||
struct parm ph0;
|
||||
struct parm ph1;
|
||||
struct parm ph2;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_clk_phase_ops;
|
||||
extern const struct clk_ops meson_clk_triphase_ops;
|
||||
|
||||
#endif /* __MESON_CLK_PHASE_H */
|
|
@ -32,11 +32,9 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "clkc.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
|
||||
static inline struct meson_clk_pll_data *
|
||||
meson_clk_pll_data(struct clk_regmap *clk)
|
||||
|
@ -309,8 +307,15 @@ const struct clk_ops meson_clk_pll_ops = {
|
|||
.enable = meson_clk_pll_enable,
|
||||
.disable = meson_clk_pll_disable
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_pll_ops);
|
||||
|
||||
const struct clk_ops meson_clk_pll_ro_ops = {
|
||||
.recalc_rate = meson_clk_pll_recalc_rate,
|
||||
.is_enabled = meson_clk_pll_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic PLL driver");
|
||||
MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLK_PLL_H
|
||||
#define __MESON_CLK_PLL_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "parm.h"
|
||||
|
||||
struct pll_params_table {
|
||||
u16 m;
|
||||
u16 n;
|
||||
};
|
||||
|
||||
#define PLL_PARAMS(_m, _n) \
|
||||
{ \
|
||||
.m = (_m), \
|
||||
.n = (_n), \
|
||||
}
|
||||
|
||||
#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
struct meson_clk_pll_data {
|
||||
struct parm en;
|
||||
struct parm m;
|
||||
struct parm n;
|
||||
struct parm frac;
|
||||
struct parm l;
|
||||
struct parm rst;
|
||||
const struct reg_sequence *init_regs;
|
||||
unsigned int init_count;
|
||||
const struct pll_params_table *table;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_clk_pll_ro_ops;
|
||||
extern const struct clk_ops meson_clk_pll_ops;
|
||||
|
||||
#endif /* __MESON_CLK_PLL_H */
|
|
@ -4,6 +4,7 @@
|
|||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
|
||||
|
@ -180,3 +181,7 @@ const struct clk_ops clk_regmap_mux_ro_ops = {
|
|||
.get_parent = clk_regmap_mux_get_parent,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -111,4 +111,19 @@ clk_get_regmap_mux_data(struct clk_regmap *clk)
|
|||
extern const struct clk_ops clk_regmap_mux_ops;
|
||||
extern const struct clk_ops clk_regmap_mux_ro_ops;
|
||||
|
||||
#define MESON_GATE(_name, _reg, _bit) \
|
||||
struct clk_regmap _name = { \
|
||||
.data = &(struct clk_regmap_gate_data){ \
|
||||
.offset = (_reg), \
|
||||
.bit_idx = (_bit), \
|
||||
}, \
|
||||
.hw.init = &(struct clk_init_data) { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_regmap_gate_ops, \
|
||||
.parent_names = (const char *[]){ "clk81" }, \
|
||||
.num_parents = 1, \
|
||||
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#endif /* __CLK_REGMAP_H */
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2018 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clkc-audio.h"
|
||||
|
||||
/*
|
||||
* This is a special clock for the audio controller.
|
||||
* The phase of mst_sclk clock output can be controlled independently
|
||||
* for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
|
||||
* Controlling these 3 phases as just one makes things simpler and
|
||||
* give the same clock view to all the element on the i2s bus.
|
||||
* If necessary, we can still control the phase in the tdm block
|
||||
* which makes these independent control redundant.
|
||||
*/
|
||||
static inline struct meson_clk_triphase_data *
|
||||
meson_clk_triphase_data(struct clk_regmap *clk)
|
||||
{
|
||||
return (struct meson_clk_triphase_data *)clk->data;
|
||||
}
|
||||
|
||||
static void meson_clk_triphase_sync(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
/* Get phase 0 and sync it to phase 1 and 2 */
|
||||
val = meson_parm_read(clk->map, &tph->ph0);
|
||||
meson_parm_write(clk->map, &tph->ph1, val);
|
||||
meson_parm_write(clk->map, &tph->ph2, val);
|
||||
}
|
||||
|
||||
static int meson_clk_triphase_get_phase(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
/* Phase are in sync, reading phase 0 is enough */
|
||||
val = meson_parm_read(clk->map, &tph->ph0);
|
||||
|
||||
return meson_clk_degrees_from_val(val, tph->ph0.width);
|
||||
}
|
||||
|
||||
static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
|
||||
{
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
|
||||
unsigned int val;
|
||||
|
||||
val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
|
||||
meson_parm_write(clk->map, &tph->ph0, val);
|
||||
meson_parm_write(clk->map, &tph->ph1, val);
|
||||
meson_parm_write(clk->map, &tph->ph2, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops meson_clk_triphase_ops = {
|
||||
.init = meson_clk_triphase_sync,
|
||||
.get_phase = meson_clk_triphase_get_phase,
|
||||
.set_phase = meson_clk_triphase_set_phase,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);
|
|
@ -1,146 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*/
|
||||
|
||||
#ifndef __CLKC_H
|
||||
#define __CLKC_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clk-regmap.h"
|
||||
|
||||
#define PMASK(width) GENMASK(width - 1, 0)
|
||||
#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift)
|
||||
#define CLRPMASK(width, shift) (~SETPMASK(width, shift))
|
||||
|
||||
#define PARM_GET(width, shift, reg) \
|
||||
(((reg) & SETPMASK(width, shift)) >> (shift))
|
||||
#define PARM_SET(width, shift, reg, val) \
|
||||
(((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
|
||||
|
||||
#define MESON_PARM_APPLICABLE(p) (!!((p)->width))
|
||||
|
||||
struct parm {
|
||||
u16 reg_off;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(map, p->reg_off, &val);
|
||||
return PARM_GET(p->width, p->shift, val);
|
||||
}
|
||||
|
||||
static inline void meson_parm_write(struct regmap *map, struct parm *p,
|
||||
unsigned int val)
|
||||
{
|
||||
regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift),
|
||||
val << p->shift);
|
||||
}
|
||||
|
||||
|
||||
struct pll_params_table {
|
||||
u16 m;
|
||||
u16 n;
|
||||
};
|
||||
|
||||
#define PLL_PARAMS(_m, _n) \
|
||||
{ \
|
||||
.m = (_m), \
|
||||
.n = (_n), \
|
||||
}
|
||||
|
||||
#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
struct meson_clk_pll_data {
|
||||
struct parm en;
|
||||
struct parm m;
|
||||
struct parm n;
|
||||
struct parm frac;
|
||||
struct parm l;
|
||||
struct parm rst;
|
||||
const struct reg_sequence *init_regs;
|
||||
unsigned int init_count;
|
||||
const struct pll_params_table *table;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
|
||||
|
||||
struct meson_clk_mpll_data {
|
||||
struct parm sdm;
|
||||
struct parm sdm_en;
|
||||
struct parm n2;
|
||||
struct parm ssen;
|
||||
struct parm misc;
|
||||
spinlock_t *lock;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
struct meson_clk_phase_data {
|
||||
struct parm ph;
|
||||
};
|
||||
|
||||
int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
|
||||
unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
|
||||
|
||||
struct meson_vid_pll_div_data {
|
||||
struct parm val;
|
||||
struct parm sel;
|
||||
};
|
||||
|
||||
#define MESON_GATE(_name, _reg, _bit) \
|
||||
struct clk_regmap _name = { \
|
||||
.data = &(struct clk_regmap_gate_data){ \
|
||||
.offset = (_reg), \
|
||||
.bit_idx = (_bit), \
|
||||
}, \
|
||||
.hw.init = &(struct clk_init_data) { \
|
||||
.name = #_name, \
|
||||
.ops = &clk_regmap_gate_ops, \
|
||||
.parent_names = (const char *[]){ "clk81" }, \
|
||||
.num_parents = 1, \
|
||||
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
|
||||
}, \
|
||||
};
|
||||
|
||||
struct meson_clk_dualdiv_param {
|
||||
unsigned int n1;
|
||||
unsigned int n2;
|
||||
unsigned int m1;
|
||||
unsigned int m2;
|
||||
unsigned int dual;
|
||||
};
|
||||
|
||||
struct meson_clk_dualdiv_data {
|
||||
struct parm n1;
|
||||
struct parm n2;
|
||||
struct parm m1;
|
||||
struct parm m2;
|
||||
struct parm dual;
|
||||
const struct meson_clk_dualdiv_param *table;
|
||||
};
|
||||
|
||||
/* clk_ops */
|
||||
extern const struct clk_ops meson_clk_pll_ro_ops;
|
||||
extern const struct clk_ops meson_clk_pll_ops;
|
||||
extern const struct clk_ops meson_clk_cpu_ops;
|
||||
extern const struct clk_ops meson_clk_mpll_ro_ops;
|
||||
extern const struct clk_ops meson_clk_mpll_ops;
|
||||
extern const struct clk_ops meson_clk_phase_ops;
|
||||
extern const struct clk_ops meson_vid_pll_div_ro_ops;
|
||||
extern const struct clk_ops meson_clk_dualdiv_ops;
|
||||
extern const struct clk_ops meson_clk_dualdiv_ro_ops;
|
||||
|
||||
struct clk_hw *meson_clk_hw_register_input(struct device *dev,
|
||||
const char *of_name,
|
||||
const char *clk_name,
|
||||
unsigned long flags);
|
||||
|
||||
#endif /* __CLKC_H */
|
|
@ -5,10 +5,12 @@
|
|||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include "clkc.h"
|
||||
#include "meson-aoclk.h"
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-dualdiv.h"
|
||||
|
||||
#define IN_PREFIX "ao-in-"
|
||||
|
||||
/* AO Configuration Clock registers offsets */
|
||||
|
|
|
@ -12,9 +12,12 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "clkc.h"
|
||||
#include "gxbb.h"
|
||||
#include "clk-input.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-mpll.h"
|
||||
#include "vid-pll-div.h"
|
||||
|
||||
#define IN_PREFIX "ee-in-"
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include "meson-aoclk.h"
|
||||
|
||||
#include "clk-input.h"
|
||||
|
||||
static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
|
|
|
@ -11,9 +11,12 @@
|
|||
#ifndef __MESON_AOCLK_H__
|
||||
#define __MESON_AOCLK_H__
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include "clkc.h"
|
||||
|
||||
#include "clk-regmap.h"
|
||||
|
||||
struct meson_aoclk_input {
|
||||
const char *name;
|
||||
|
|
|
@ -16,9 +16,10 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "clkc.h"
|
||||
#include "meson8b.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-mpll.h"
|
||||
|
||||
static DEFINE_SPINLOCK(meson_clk_lock);
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015 Endless Mobile, Inc.
|
||||
* Author: Carlo Caione <carlo@endlessm.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_PARM_H
|
||||
#define __MESON_PARM_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define PMASK(width) GENMASK(width - 1, 0)
|
||||
#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift)
|
||||
#define CLRPMASK(width, shift) (~SETPMASK(width, shift))
|
||||
|
||||
#define PARM_GET(width, shift, reg) \
|
||||
(((reg) & SETPMASK(width, shift)) >> (shift))
|
||||
#define PARM_SET(width, shift, reg, val) \
|
||||
(((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
|
||||
|
||||
#define MESON_PARM_APPLICABLE(p) (!!((p)->width))
|
||||
|
||||
struct parm {
|
||||
u16 reg_off;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(map, p->reg_off, &val);
|
||||
return PARM_GET(p->width, p->shift, val);
|
||||
}
|
||||
|
||||
static inline void meson_parm_write(struct regmap *map, struct parm *p,
|
||||
unsigned int val)
|
||||
{
|
||||
regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift),
|
||||
val << p->shift);
|
||||
}
|
||||
|
||||
#endif /* __MESON_PARM_H */
|
||||
|
|
@ -16,7 +16,11 @@
|
|||
* duty_cycle = (1 + hi) / (1 + val)
|
||||
*/
|
||||
|
||||
#include "clkc-audio.h"
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "sclk-div.h"
|
||||
|
||||
static inline struct meson_sclk_div_data *
|
||||
meson_sclk_div_data(struct clk_regmap *clk)
|
||||
|
@ -241,3 +245,7 @@ const struct clk_ops meson_sclk_div_ops = {
|
|||
.init = sclk_div_init,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic Sample divider driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -4,16 +4,11 @@
|
|||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_CLKC_AUDIO_H
|
||||
#define __MESON_CLKC_AUDIO_H
|
||||
#ifndef __MESON_SCLK_DIV_H
|
||||
#define __MESON_SCLK_DIV_H
|
||||
|
||||
#include "clkc.h"
|
||||
|
||||
struct meson_clk_triphase_data {
|
||||
struct parm ph0;
|
||||
struct parm ph1;
|
||||
struct parm ph2;
|
||||
};
|
||||
#include <linux/clk-provider.h>
|
||||
#include "parm.h"
|
||||
|
||||
struct meson_sclk_div_data {
|
||||
struct parm div;
|
||||
|
@ -22,7 +17,6 @@ struct meson_sclk_div_data {
|
|||
struct clk_duty cached_duty;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_clk_triphase_ops;
|
||||
extern const struct clk_ops meson_sclk_div_ops;
|
||||
|
||||
#endif /* __MESON_CLKC_AUDIO_H */
|
||||
#endif /* __MESON_SCLK_DIV_H */
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "clkc.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "clk-regmap.h"
|
||||
#include "vid-pll-div.h"
|
||||
|
||||
static inline struct meson_vid_pll_div_data *
|
||||
meson_vid_pll_div_data(struct clk_regmap *clk)
|
||||
|
@ -89,3 +92,8 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
|
|||
const struct clk_ops meson_vid_pll_div_ro_ops = {
|
||||
.recalc_rate = meson_vid_pll_div_recalc_rate,
|
||||
};
|
||||
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");
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2019 BayLibre, SAS.
|
||||
* Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_VID_PLL_DIV_H
|
||||
#define __MESON_VID_PLL_DIV_H
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include "parm.h"
|
||||
|
||||
struct meson_vid_pll_div_data {
|
||||
struct parm val;
|
||||
struct parm sel;
|
||||
};
|
||||
|
||||
extern const struct clk_ops meson_vid_pll_div_ro_ops;
|
||||
|
||||
#endif /* __MESON_VID_PLL_DIV_H */
|
Loading…
Reference in New Issue