Merge branches 'clk-microchip', 'clk-si', 'clk-mtk', 'clk-at91' and 'clk-st' into clk-next

- Clock configuration on Microchip PolarFire SoCs
 - Free allocations on probe error in Mediatek clk driver
 - Modernize Mediatek clk driver by consolidating code

* clk-microchip:
  clk: microchip: Add driver for Microchip PolarFire SoC
  dt-bindings: clk: microchip: Add Microchip PolarFire host binding

* clk-si:
  clk-si5341: replace snprintf in show functions with sysfs_emit
  clk: si5341: fix reported clk_rate when output divider is 2

* clk-mtk: (32 commits)
  clk: mediatek: Warn if clk IDs are duplicated
  clk: mediatek: mt8195: Implement remove functions
  clk: mediatek: mt8195: Implement error handling in probe functions
  clk: mediatek: mt8195: Hook up mtk_clk_simple_remove()
  clk: mediatek: Unregister clks in mtk_clk_simple_probe() error path
  clk: mediatek: mtk: Implement error handling in register APIs
  clk: mediatek: pll: Implement error handling in register API
  clk: mediatek: mux: Implement error handling in register API
  clk: mediatek: mux: Reverse check for existing clk to reduce nesting level
  clk: mediatek: gate: Implement error handling in register API
  clk: mediatek: cpumux: Implement error handling in register API
  clk: mediatek: mtk: Clean up included headers
  clk: mediatek: Add mtk_clk_simple_remove()
  clk: mediatek: Implement mtk_clk_unregister_composites() API
  clk: mediatek: Implement mtk_clk_unregister_divider_clks() API
  clk: mediatek: Implement mtk_clk_unregister_factors() API
  clk: mediatek: Implement mtk_clk_unregister_fixed_clks() API
  clk: mediatek: pll: Clean up included headers
  clk: mediatek: pll: Implement unregister API
  clk: mediatek: pll: Split definitions into separate header file
  ...

* clk-at91:
  clk: at91: clk-master: remove dead code
  clk: at91: sama7g5: fix parents of PDMCs' GCLK
  clk: at91: sama7g5: Allow MCK1 to be exported and referenced in DT
  clk: at91: allow setting PMC_AUDIOPINCK clock parents via DT

* clk-st:
  clk: stm32mp1: Add parent_data to ETHRX clock
  clk: stm32mp1: Split ETHCK_K into separate MUX and GATE clock
This commit is contained in:
Stephen Boyd 2022-03-29 10:18:21 -07:00
69 changed files with 1541 additions and 485 deletions

View file

@ -0,0 +1,58 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/microchip,mpfs.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip PolarFire Clock Control Module Binding
maintainers:
- Daire McNamara <daire.mcnamara@microchip.com>
description: |
Microchip PolarFire clock control (CLKCFG) is an integrated clock controller,
which gates and enables all peripheral clocks.
This device tree binding describes 33 gate clocks. Clocks are referenced by
user nodes by the CLKCFG node phandle and the clock index in the group, from
0 to 32.
properties:
compatible:
const: microchip,mpfs-clkcfg
reg:
maxItems: 1
clocks:
maxItems: 1
'#clock-cells':
const: 1
description: |
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/microchip,mpfs-clock.h
for the full list of PolarFire clock IDs.
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
# Clock Config node:
- |
#include <dt-bindings/clock/microchip,mpfs-clock.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
clkcfg: clock-controller@20002000 {
compatible = "microchip,mpfs-clkcfg";
reg = <0x0 0x20002000 0x0 0x1000>;
clocks = <&ref>;
#clock-cells = <1>;
};
};

View file

@ -330,9 +330,6 @@ config COMMON_CLK_PXA
help
Support for the Marvell PXA SoC.
config COMMON_CLK_PIC32
def_bool COMMON_CLK && MACH_PIC32
config COMMON_CLK_OXNAS
bool "Clock driver for the OXNAS SoC Family"
depends on ARCH_OXNAS || COMPILE_TEST
@ -407,6 +404,7 @@ source "drivers/clk/keystone/Kconfig"
source "drivers/clk/mediatek/Kconfig"
source "drivers/clk/meson/Kconfig"
source "drivers/clk/mstar/Kconfig"
source "drivers/clk/microchip/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/pistachio/Kconfig"
source "drivers/clk/qcom/Kconfig"

View file

@ -91,7 +91,7 @@ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
obj-y += mediatek/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_MACH_PIC32) += microchip/
obj-y += microchip/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif

View file

@ -143,8 +143,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
parent_names,
&at91rm9200_master_layout,
&rm9200_mck_characteristics,
&rm9200_mck_lock, CLK_SET_RATE_GATE,
INT_MIN);
&rm9200_mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -419,8 +419,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
parent_names,
&at91rm9200_master_layout,
data->mck_characteristics,
&at91sam9260_mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&at91sam9260_mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -154,8 +154,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
parent_names,
&at91rm9200_master_layout,
&mck_characteristics,
&at91sam9g45_mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&at91sam9g45_mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -181,8 +181,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
parent_names,
&at91sam9x5_master_layout,
&mck_characteristics,
&at91sam9n12_mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&at91sam9n12_mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -123,8 +123,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
parent_names,
&at91rm9200_master_layout,
&sam9rl_mck_characteristics,
&sam9rl_mck_lock, CLK_SET_RATE_GATE,
INT_MIN);
&sam9rl_mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -201,8 +201,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
parent_names,
&at91sam9x5_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -374,85 +374,6 @@ static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
}
}
static int clk_master_pres_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_master *master = to_clk_master(hw);
struct clk_rate_request req_parent = *req;
const struct clk_master_characteristics *characteristics =
master->characteristics;
struct clk_hw *parent;
long best_rate = LONG_MIN, best_diff = LONG_MIN;
u32 pres;
int i;
if (master->chg_pid < 0)
return -EOPNOTSUPP;
parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
if (!parent)
return -EOPNOTSUPP;
for (i = 0; i <= MASTER_PRES_MAX; i++) {
if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
pres = 3;
else
pres = 1 << i;
req_parent.rate = req->rate * pres;
if (__clk_determine_rate(parent, &req_parent))
continue;
clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
&best_diff, &best_rate, pres);
if (!best_diff)
break;
}
return 0;
}
static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
unsigned int pres, mckr, tmp;
int ret;
pres = DIV_ROUND_CLOSEST(parent_rate, rate);
if (pres > MASTER_PRES_MAX)
return -EINVAL;
else if (pres == 3)
pres = MASTER_PRES_MAX;
else if (pres)
pres = ffs(pres) - 1;
spin_lock_irqsave(master->lock, flags);
ret = regmap_read(master->regmap, master->layout->offset, &mckr);
if (ret)
goto unlock;
mckr &= master->layout->mask;
tmp = (mckr >> master->layout->pres_shift) & MASTER_PRES_MASK;
if (pres == tmp)
goto unlock;
mckr &= ~(MASTER_PRES_MASK << master->layout->pres_shift);
mckr |= (pres << master->layout->pres_shift);
ret = regmap_write(master->regmap, master->layout->offset, mckr);
if (ret)
goto unlock;
while (!clk_master_ready(master))
cpu_relax();
unlock:
spin_unlock_irqrestore(master->lock, flags);
return ret;
}
static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@ -539,13 +460,6 @@ static void clk_master_pres_restore_context(struct clk_hw *hw)
pr_warn("MCKR PRES was not configured properly by firmware!\n");
}
static void clk_master_pres_restore_context_chg(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
clk_master_pres_set_rate(hw, master->pms.rate, master->pms.parent_rate);
}
static const struct clk_ops master_pres_ops = {
.prepare = clk_master_prepare,
.is_prepared = clk_master_is_prepared,
@ -555,25 +469,13 @@ static const struct clk_ops master_pres_ops = {
.restore_context = clk_master_pres_restore_context,
};
static const struct clk_ops master_pres_ops_chg = {
.prepare = clk_master_prepare,
.is_prepared = clk_master_is_prepared,
.determine_rate = clk_master_pres_determine_rate,
.recalc_rate = clk_master_pres_recalc_rate,
.get_parent = clk_master_pres_get_parent,
.set_rate = clk_master_pres_set_rate,
.save_context = clk_master_pres_save_context,
.restore_context = clk_master_pres_restore_context_chg,
};
static struct clk_hw * __init
at91_clk_register_master_internal(struct regmap *regmap,
const char *name, int num_parents,
const char **parent_names,
const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics,
const struct clk_ops *ops, spinlock_t *lock, u32 flags,
int chg_pid)
const struct clk_ops *ops, spinlock_t *lock, u32 flags)
{
struct clk_master *master;
struct clk_init_data init;
@ -599,7 +501,6 @@ at91_clk_register_master_internal(struct regmap *regmap,
master->layout = layout;
master->characteristics = characteristics;
master->regmap = regmap;
master->chg_pid = chg_pid;
master->lock = lock;
if (ops == &master_div_ops_chg) {
@ -628,19 +529,13 @@ at91_clk_register_master_pres(struct regmap *regmap,
const char **parent_names,
const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics,
spinlock_t *lock, u32 flags, int chg_pid)
spinlock_t *lock)
{
const struct clk_ops *ops;
if (flags & CLK_SET_RATE_GATE)
ops = &master_pres_ops;
else
ops = &master_pres_ops_chg;
return at91_clk_register_master_internal(regmap, name, num_parents,
parent_names, layout,
characteristics, ops,
lock, flags, chg_pid);
characteristics,
&master_pres_ops,
lock, CLK_SET_RATE_GATE);
}
struct clk_hw * __init
@ -661,7 +556,7 @@ at91_clk_register_master_div(struct regmap *regmap,
hw = at91_clk_register_master_internal(regmap, name, 1,
&parent_name, layout,
characteristics, ops,
lock, flags, -EINVAL);
lock, flags);
if (!IS_ERR(hw) && safe_div) {
master_div = to_clk_master(hw);

View file

@ -392,8 +392,7 @@ of_at91_clk_master_setup(struct device_node *np,
hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
parent_names, layout,
characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
characteristics, &mck_lock);
if (IS_ERR(hw))
goto out_free_characteristics;

View file

@ -175,7 +175,7 @@ at91_clk_register_master_pres(struct regmap *regmap, const char *name,
int num_parents, const char **parent_names,
const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics,
spinlock_t *lock, u32 flags, int chg_pid);
spinlock_t *lock);
struct clk_hw * __init
at91_clk_register_master_div(struct regmap *regmap, const char *name,

View file

@ -271,8 +271,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
parent_names[2] = "pllack_divck";
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
parent_names, &sam9x60_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -168,7 +168,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPLLCK + 1,
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPINCK + 1,
nck(sama5d2_systemck),
nck(sama5d2_periph32ck),
nck(sama5d2_gck), 3);
@ -216,6 +216,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_AUDIOPINCK] = hw;
hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck",
"audiopll_fracck");
if (IS_ERR(hw))
@ -240,8 +242,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
parent_names,
&at91sam9x5_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -175,8 +175,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
parent_names,
&at91sam9x5_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -190,8 +190,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
parent_names,
&at91sam9x5_master_layout,
&mck_characteristics, &mck_lock,
CLK_SET_RATE_GATE, INT_MIN);
&mck_characteristics, &mck_lock);
if (IS_ERR(hw))
goto err_free;

View file

@ -302,6 +302,7 @@ static const struct {
* @ep_count: extra parents count
* @ep_mux_table: mux table for extra parents
* @id: clock id
* @eid: export index in sama7g5->chws[] array
* @c: true if clock is critical and cannot be disabled
*/
static const struct {
@ -311,6 +312,7 @@ static const struct {
u8 ep_count;
u8 ep_mux_table[4];
u8 id;
u8 eid;
u8 c;
} sama7g5_mckx[] = {
{ .n = "mck1",
@ -319,6 +321,7 @@ static const struct {
.ep_mux_table = { 5, },
.ep_count = 1,
.ep_chg_id = INT_MIN,
.eid = PMC_MCK1,
.c = 1, },
{ .n = "mck2",
@ -696,16 +699,16 @@ static const struct {
{ .n = "pdmc0_gclk",
.id = 68,
.r = { .max = 50000000 },
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
.pp_mux_table = { 5, 8, },
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
.pp_mux_table = { 5, 9, },
.pp_count = 2,
.pp_chg_id = INT_MIN, },
{ .n = "pdmc1_gclk",
.id = 69,
.r = { .max = 50000000, },
.pp = { "syspll_divpmcck", "baudpll_divpmcck", },
.pp_mux_table = { 5, 8, },
.pp = { "syspll_divpmcck", "audiopll_divpmcck", },
.pp_mux_table = { 5, 9, },
.pp_count = 2,
.pp_chg_id = INT_MIN, },
@ -913,7 +916,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama7g5_pmc = pmc_data_allocate(PMC_CPU + 1,
sama7g5_pmc = pmc_data_allocate(PMC_MCK1 + 1,
nck(sama7g5_systemck),
nck(sama7g5_periphck),
nck(sama7g5_gck), 8);
@ -1027,6 +1030,9 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
goto err_free;
alloc_mem[alloc_mem_size++] = mux_table;
if (sama7g5_mckx[i].eid)
sama7g5_pmc->chws[sama7g5_mckx[i].eid] = hw;
}
hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal");

View file

@ -798,6 +798,15 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
u32 r_divider;
u8 r[3];
err = regmap_read(output->data->regmap,
SI5341_OUT_CONFIG(output), &val);
if (err < 0)
return err;
/* If SI5341_OUT_CFG_RDIV_FORCE2 is set, r_divider is 2 */
if (val & SI5341_OUT_CFG_RDIV_FORCE2)
return parent_rate / 2;
err = regmap_bulk_read(output->data->regmap,
SI5341_OUT_R_REG(output), r, 3);
if (err < 0)
@ -814,13 +823,6 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
r_divider += 1;
r_divider <<= 1;
err = regmap_read(output->data->regmap,
SI5341_OUT_CONFIG(output), &val);
if (err < 0)
return err;
if (val & SI5341_OUT_CFG_RDIV_FORCE2)
r_divider = 2;
return parent_rate / r_divider;
}
@ -1468,7 +1470,7 @@ static ssize_t input_present_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present);
@ -1483,7 +1485,7 @@ static ssize_t input_present_sticky_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present_sticky);
@ -1498,7 +1500,7 @@ static ssize_t pll_locked_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked);
@ -1513,7 +1515,7 @@ static ssize_t pll_locked_sticky_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
return snprintf(buf, PAGE_SIZE, "%d\n", res);
return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked_sticky);

View file

@ -155,6 +155,10 @@ static const char * const eth_src[] = {
"pll4_p", "pll3_q"
};
const struct clk_parent_data ethrx_src[] = {
{ .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" },
};
static const char * const rng_src[] = {
"ck_csi", "pll4_r", "ck_lse", "ck_lsi"
};
@ -317,6 +321,7 @@ struct clock_config {
const char *name;
const char *parent_name;
const char * const *parent_names;
const struct clk_parent_data *parent_data;
int num_parents;
unsigned long flags;
void *cfg;
@ -576,6 +581,7 @@ static struct clk_hw *
clk_stm32_register_gate_ops(struct device *dev,
const char *name,
const char *parent_name,
const struct clk_parent_data *parent_data,
unsigned long flags,
void __iomem *base,
const struct stm32_gate_cfg *cfg,
@ -586,7 +592,10 @@ clk_stm32_register_gate_ops(struct device *dev,
int ret;
init.name = name;
init.parent_names = &parent_name;
if (parent_name)
init.parent_names = &parent_name;
if (parent_data)
init.parent_data = parent_data;
init.num_parents = 1;
init.flags = flags;
@ -611,6 +620,7 @@ clk_stm32_register_gate_ops(struct device *dev,
static struct clk_hw *
clk_stm32_register_composite(struct device *dev,
const char *name, const char * const *parent_names,
const struct clk_parent_data *parent_data,
int num_parents, void __iomem *base,
const struct stm32_composite_cfg *cfg,
unsigned long flags, spinlock_t *lock)
@ -1135,6 +1145,7 @@ _clk_stm32_register_gate(struct device *dev,
return clk_stm32_register_gate_ops(dev,
cfg->name,
cfg->parent_name,
cfg->parent_data,
cfg->flags,
base,
cfg->cfg,
@ -1148,8 +1159,8 @@ _clk_stm32_register_composite(struct device *dev,
const struct clock_config *cfg)
{
return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names,
cfg->num_parents, base, cfg->cfg,
cfg->flags, lock);
cfg->parent_data, cfg->num_parents,
base, cfg->cfg, cfg->flags, lock);
}
#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
@ -1258,6 +1269,16 @@ _clk_stm32_register_composite(struct device *dev,
.func = _clk_stm32_register_gate,\
}
#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\
{\
.id = _id,\
.name = _name,\
.parent_data = _parent,\
.flags = _flags,\
.cfg = (struct stm32_gate_cfg *) {_gate},\
.func = _clk_stm32_register_gate,\
}
#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\
(&(struct stm32_gate_cfg) {\
&(struct gate_cfg) {\
@ -1291,6 +1312,10 @@ _clk_stm32_register_composite(struct device *dev,
STM32_GATE(_id, _name, _parent, _flags,\
_STM32_MGATE(_mgate))
#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\
STM32_GATE_PDATA(_id, _name, _parent, _flags,\
_STM32_MGATE(_mgate))
#define _STM32_DIV(_div_offset, _div_shift, _div_width,\
_div_flags, _div_table, _ops)\
.div = &(struct stm32_div_cfg) {\
@ -1354,6 +1379,9 @@ _clk_stm32_register_composite(struct device *dev,
#define PCLK(_id, _name, _parent, _flags, _mgate)\
MGATE_MP1(_id, _name, _parent, _flags, _mgate)
#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\
MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)
#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\
CLK_SET_RATE_NO_REPARENT | _flags,\
@ -1951,7 +1979,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA),
PCLK(GPU, "gpu", "ck_axi", 0, G_GPU),
PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX),
PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX),
PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX),
PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC),
PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC),
PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI),
@ -2008,7 +2036,6 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI),
KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1),
KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO),
KCLK(ETHCK_K, "ethck_k", eth_src, 0, G_ETHCK, M_ETHCK),
/* Particulary Kernel Clocks (no mux or no gate) */
MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM),
@ -2017,11 +2044,16 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU),
MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12),
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE |
COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_NO_REPARENT,
_NO_GATE,
_MMUX(M_ETHCK),
_DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
_NO_DIV),
MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK),
DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0),
/* RTC clock */
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE,

View file

@ -92,7 +92,7 @@ struct clk * __init mtk_clk_register_ref2usb_tx(const char *name,
clk = clk_register(NULL, &tx->hw);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk));
pr_err("Failed to register clk %s: %pe\n", name, clk);
kfree(tx);
}

View file

@ -5,13 +5,24 @@
*/
#include <linux/clk-provider.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-cpumux.h"
struct mtk_clk_cpumux {
struct clk_hw hw;
struct regmap *regmap;
u32 reg;
u32 mask;
u8 shift;
};
static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
{
return container_of(_hw, struct mtk_clk_cpumux, hw);
@ -77,6 +88,21 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux,
return clk;
}
static void mtk_clk_unregister_cpumux(struct clk *clk)
{
struct mtk_clk_cpumux *cpumux;
struct clk_hw *hw;
hw = __clk_get_hw(clk);
if (!hw)
return;
cpumux = to_mtk_clk_cpumux(hw);
clk_unregister(clk);
kfree(cpumux);
}
int mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data)
@ -87,25 +113,58 @@ int mtk_clk_register_cpumuxes(struct device_node *node,
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
pr_err("Cannot find regmap for %pOF: %ld\n", node,
PTR_ERR(regmap));
pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_composite *mux = &clks[i];
if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
node, mux->id);
continue;
}
clk = mtk_clk_register_cpumux(mux, regmap);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
mux->name, PTR_ERR(clk));
continue;
pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
goto err;
}
clk_data->clks[mux->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_composite *mux = &clks[i];
if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
continue;
mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
for (i = num; i > 0; i--) {
const struct mtk_composite *mux = &clks[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
continue;
mtk_clk_unregister_cpumux(clk_data->clks[mux->id]);
clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
}
}
MODULE_LICENSE("GPL");

View file

@ -7,16 +7,15 @@
#ifndef __DRV_CLK_CPUMUX_H
#define __DRV_CLK_CPUMUX_H
struct mtk_clk_cpumux {
struct clk_hw hw;
struct regmap *regmap;
u32 reg;
u32 mask;
u8 shift;
};
struct clk_onecell_data;
struct device_node;
struct mtk_composite;
int mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data);
#endif /* __DRV_CLK_CPUMUX_H */

View file

@ -4,18 +4,30 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "clk-mtk.h"
#include "clk-gate.h"
struct mtk_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
int set_ofs;
int clr_ofs;
int sta_ofs;
u8 bit;
};
static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
{
return container_of(hw, struct mtk_clk_gate, hw);
}
static u32 mtk_get_clockgating(struct clk_hw *hw)
{
struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
@ -140,17 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
struct clk *mtk_clk_register_gate(
const char *name,
const char *parent_name,
struct regmap *regmap,
int set_ofs,
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops,
unsigned long flags,
struct device *dev)
static struct clk *mtk_clk_register_gate(const char *name,
const char *parent_name,
struct regmap *regmap, int set_ofs,
int clr_ofs, int sta_ofs, u8 bit,
const struct clk_ops *ops,
unsigned long flags, struct device *dev)
{
struct mtk_clk_gate *cg;
struct clk *clk;
@ -180,6 +187,107 @@ struct clk *mtk_clk_register_gate(
return clk;
}
EXPORT_SYMBOL_GPL(mtk_clk_register_gate);
static void mtk_clk_unregister_gate(struct clk *clk)
{
struct mtk_clk_gate *cg;
struct clk_hw *hw;
hw = __clk_get_hw(clk);
if (!hw)
return;
cg = to_mtk_clk_gate(hw);
clk_unregister(clk);
kfree(cg);
}
int mtk_clk_register_gates_with_dev(struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data,
struct device *dev)
{
int i;
struct clk *clk;
struct regmap *regmap;
if (!clk_data)
return -ENOMEM;
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_gate *gate = &clks[i];
if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) {
pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
node, gate->id);
continue;
}
clk = mtk_clk_register_gate(gate->name, gate->parent_name,
regmap,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops,
gate->flags, dev);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %pe\n", gate->name, clk);
goto err;
}
clk_data->clks[gate->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_gate *gate = &clks[i];
if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
continue;
mtk_clk_unregister_gate(clk_data->clks[gate->id]);
clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
int mtk_clk_register_gates(struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data)
{
return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_gate *gate = &clks[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[gate->id]))
continue;
mtk_clk_unregister_gate(clk_data->clks[gate->id]);
clk_data->clks[gate->id] = ERR_PTR(-ENOENT);
}
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates);
MODULE_LICENSE("GPL");

View file

@ -7,41 +7,34 @@
#ifndef __DRV_CLK_GATE_H
#define __DRV_CLK_GATE_H
#include <linux/regmap.h>
#include <linux/clk-provider.h>
#include <linux/types.h>
struct clk;
struct mtk_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
int set_ofs;
int clr_ofs;
int sta_ofs;
u8 bit;
};
static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw)
{
return container_of(hw, struct mtk_clk_gate, hw);
}
struct clk_onecell_data;
struct clk_ops;
struct device;
struct device_node;
extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
struct clk *mtk_clk_register_gate(
const char *name,
const char *parent_name,
struct regmap *regmap,
int set_ofs,
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops,
unsigned long flags,
struct device *dev);
struct mtk_gate_regs {
u32 sta_ofs;
u32 clr_ofs;
u32 set_ofs;
};
struct mtk_gate {
int id;
const char *name;
const char *parent_name;
const struct mtk_gate_regs *regs;
int shift;
const struct clk_ops *ops;
unsigned long flags;
};
#define GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, \
_ops, _flags) { \
@ -57,4 +50,16 @@ struct clk *mtk_clk_register_gate(
#define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \
GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0)
int mtk_clk_register_gates(struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data);
int mtk_clk_register_gates_with_dev(struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data,
struct device *dev);
void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data);
#endif /* __DRV_CLK_GATE_H */

View file

@ -10,9 +10,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-cpumux.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt2701-clk.h>

View file

@ -13,8 +13,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-pll.h"
#include "clk-mtk.h"
#include <dt-bindings/clock/mt2712-clk.h>

View file

@ -12,9 +12,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt6765-clk.h>

View file

@ -10,9 +10,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
#include "clk-gate.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt6779-clk.h>

View file

@ -9,8 +9,9 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt6797-clk.h>

View file

@ -11,9 +11,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-cpumux.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt7622-clk.h>
#include <linux/clk.h> /* for consumer */

View file

@ -12,9 +12,10 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-cpumux.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt7629-clk.h>

View file

@ -10,9 +10,11 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt7986-clk.h>
#include <linux/clk.h>

View file

@ -11,8 +11,9 @@
#include <linux/mfd/syscon.h>
#include <dt-bindings/clock/mt8135-clk.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
static DEFINE_SPINLOCK(mt8135_clk_lock);

View file

@ -12,8 +12,9 @@
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8167-clk.h>

View file

@ -8,9 +8,10 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-cpumux.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8173-clk.h>

View file

@ -11,9 +11,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
#include "clk-gate.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8183-clk.h>

View file

@ -12,9 +12,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-mux.h"
#include "clk-gate.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8192-clk.h>
@ -1236,9 +1237,17 @@ static int clk_mt8192_infra_probe(struct platform_device *pdev)
r = mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);
if (r)
return r;
goto free_clk_data;
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_clk_data;
return r;
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8192_peri_probe(struct platform_device *pdev)
@ -1253,9 +1262,17 @@ static int clk_mt8192_peri_probe(struct platform_device *pdev)
r = mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), clk_data);
if (r)
return r;
goto free_clk_data;
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_clk_data;
return r;
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
@ -1271,9 +1288,17 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
if (r)
return r;
goto free_clk_data;
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_clk_data;
return r;
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
}
static const struct of_device_id of_match_clk_mt8192[] = {

View file

@ -5,6 +5,7 @@
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8195-clk.h>
#include <linux/of_device.h>
@ -119,24 +120,47 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
if (r)
goto free_apmixed_data;
r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
if (r)
goto unregister_plls;
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_apmixed_data;
goto unregister_gates;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_gates:
mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
unregister_plls:
mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
free_apmixed_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8195_apmixed_remove(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
of_clk_del_provider(node);
mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
mtk_free_clk_data(clk_data);
return 0;
}
static struct platform_driver clk_mt8195_apmixed_drv = {
.probe = clk_mt8195_apmixed_probe,
.remove = clk_mt8195_apmixed_remove,
.driver = {
.name = "clk-mt8195-apmixed",
.of_match_table = of_match_clk_mt8195_apmixed,

View file

@ -4,6 +4,7 @@
// Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8195-clk.h>
#include <linux/clk-provider.h>
@ -65,18 +66,37 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
if (r)
goto free_apusys_pll_data;
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto unregister_plls;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_plls:
mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
free_apusys_pll_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8195_apusys_pll_remove(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data);
mtk_free_clk_data(clk_data);
return 0;
}
static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
{ .compatible = "mediatek,mt8195-apusys_pll", },
{}
@ -84,6 +104,7 @@ static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = {
static struct platform_driver clk_mt8195_apusys_pll_drv = {
.probe = clk_mt8195_apusys_pll_probe,
.remove = clk_mt8195_apusys_pll_remove,
.driver = {
.name = "clk-mt8195-apusys_pll",
.of_match_table = of_match_clk_mt8195_apusys_pll,

View file

@ -134,6 +134,7 @@ static const struct of_device_id of_match_clk_mt8195_cam[] = {
static struct platform_driver clk_mt8195_cam_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-cam",
.of_match_table = of_match_clk_mt8195_cam,

View file

@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8195_ccu[] = {
static struct platform_driver clk_mt8195_ccu_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-ccu",
.of_match_table = of_match_clk_mt8195_ccu,

View file

@ -88,6 +88,7 @@ static const struct of_device_id of_match_clk_mt8195_img[] = {
static struct platform_driver clk_mt8195_img_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-img",
.of_match_table = of_match_clk_mt8195_img,

View file

@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8195_imp_iic_wrap[] = {
static struct platform_driver clk_mt8195_imp_iic_wrap_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-imp_iic_wrap",
.of_match_table = of_match_clk_mt8195_imp_iic_wrap,

View file

@ -198,6 +198,7 @@ static const struct of_device_id of_match_clk_mt8195_infra_ao[] = {
static struct platform_driver clk_mt8195_infra_ao_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-infra_ao",
.of_match_table = of_match_clk_mt8195_infra_ao,

View file

@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8195_ipe[] = {
static struct platform_driver clk_mt8195_ipe_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-ipe",
.of_match_table = of_match_clk_mt8195_ipe,

View file

@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_mfg[] = {
static struct platform_driver clk_mt8195_mfg_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-mfg",
.of_match_table = of_match_clk_mt8195_mfg,

View file

@ -54,6 +54,7 @@ static const struct of_device_id of_match_clk_mt8195_peri_ao[] = {
static struct platform_driver clk_mt8195_peri_ao_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-peri_ao",
.of_match_table = of_match_clk_mt8195_peri_ao,

View file

@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_scp_adsp[] = {
static struct platform_driver clk_mt8195_scp_adsp_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-scp_adsp",
.of_match_table = of_match_clk_mt8195_scp_adsp,

View file

@ -1239,32 +1239,79 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev)
goto free_top_data;
}
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
top_clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
&mt8195_clk_lock, top_clk_data);
mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
&mt8195_clk_lock, top_clk_data);
mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
&mt8195_clk_lock, top_clk_data);
r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
top_clk_data);
if (r)
goto free_top_data;
r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
if (r)
goto unregister_fixed_clks;
r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
&mt8195_clk_lock, top_clk_data);
if (r)
goto unregister_factors;
r = mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
&mt8195_clk_lock, top_clk_data);
if (r)
goto unregister_muxes;
r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
&mt8195_clk_lock, top_clk_data);
if (r)
goto unregister_composite_muxes;
r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
if (r)
goto unregister_composite_divs;
r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data);
if (r)
goto free_top_data;
goto unregister_gates;
platform_set_drvdata(pdev, top_clk_data);
return r;
unregister_gates:
mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
unregister_composite_divs:
mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
unregister_composite_muxes:
mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
unregister_muxes:
mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
unregister_factors:
mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
unregister_fixed_clks:
mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
free_top_data:
mtk_free_clk_data(top_clk_data);
return r;
}
static int clk_mt8195_topck_remove(struct platform_device *pdev)
{
struct clk_onecell_data *top_clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data);
mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data);
mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data);
mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data);
mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
mtk_free_clk_data(top_clk_data);
return 0;
}
static struct platform_driver clk_mt8195_topck_drv = {
.probe = clk_mt8195_topck_probe,
.remove = clk_mt8195_topck_remove,
.driver = {
.name = "clk-mt8195-topck",
.of_match_table = of_match_clk_mt8195_topck,

View file

@ -96,6 +96,7 @@ static const struct of_device_id of_match_clk_mt8195_vdec[] = {
static struct platform_driver clk_mt8195_vdec_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vdec",
.of_match_table = of_match_clk_mt8195_vdec,

View file

@ -105,17 +105,35 @@ static int clk_mt8195_vdo0_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_vdo0_data;
goto unregister_gates;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_gates:
mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
free_vdo0_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8195_vdo0_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->parent->of_node;
struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
of_clk_del_provider(node);
mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
mtk_free_clk_data(clk_data);
return 0;
}
static struct platform_driver clk_mt8195_vdo0_drv = {
.probe = clk_mt8195_vdo0_probe,
.remove = clk_mt8195_vdo0_remove,
.driver = {
.name = "clk-mt8195-vdo0",
},

View file

@ -122,17 +122,35 @@ static int clk_mt8195_vdo1_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_vdo1_data;
goto unregister_gates;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_gates:
mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
free_vdo1_data:
mtk_free_clk_data(clk_data);
return r;
}
static int clk_mt8195_vdo1_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->parent->of_node;
struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
of_clk_del_provider(node);
mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
mtk_free_clk_data(clk_data);
return 0;
}
static struct platform_driver clk_mt8195_vdo1_drv = {
.probe = clk_mt8195_vdo1_probe,
.remove = clk_mt8195_vdo1_remove,
.driver = {
.name = "clk-mt8195-vdo1",
},

View file

@ -61,6 +61,7 @@ static const struct of_device_id of_match_clk_mt8195_venc[] = {
static struct platform_driver clk_mt8195_venc_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-venc",
.of_match_table = of_match_clk_mt8195_venc,

View file

@ -102,6 +102,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp0[] = {
static struct platform_driver clk_mt8195_vpp0_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vpp0",
.of_match_table = of_match_clk_mt8195_vpp0,

View file

@ -100,6 +100,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp1[] = {
static struct platform_driver clk_mt8195_vpp1_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-vpp1",
.of_match_table = of_match_clk_mt8195_vpp1,

View file

@ -135,6 +135,7 @@ static const struct of_device_id of_match_clk_mt8195_wpe[] = {
static struct platform_driver clk_mt8195_wpe_drv = {
.probe = mtk_clk_simple_probe,
.remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8195-wpe",
.of_match_table = of_match_clk_mt8195_wpe,

View file

@ -11,8 +11,9 @@
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-mtk.h"
#include "clk-pll.h"
#include <dt-bindings/clock/mt8516-clk.h>

View file

@ -4,17 +4,16 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/clkdev.h>
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-gate.h"
@ -54,112 +53,135 @@ void mtk_free_clk_data(struct clk_onecell_data *clk_data)
kfree(clk_data);
}
void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
int num, struct clk_onecell_data *clk_data)
int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
struct clk *clk;
if (!clk_data)
return -ENOMEM;
for (i = 0; i < num; i++) {
const struct mtk_fixed_clk *rc = &clks[i];
if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) {
pr_warn("Trying to register duplicate clock ID: %d\n", rc->id);
continue;
}
clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
rc->rate);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
rc->name, PTR_ERR(clk));
continue;
pr_err("Failed to register clk %s: %pe\n", rc->name, clk);
goto err;
}
if (clk_data)
clk_data->clks[rc->id] = clk;
clk_data->clks[rc->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_fixed_clk *rc = &clks[i];
if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
continue;
clk_unregister_fixed_rate(clk_data->clks[rc->id]);
clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks);
void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
int num, struct clk_onecell_data *clk_data)
void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_fixed_clk *rc = &clks[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
continue;
clk_unregister_fixed_rate(clk_data->clks[rc->id]);
clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
}
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks);
int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
struct clk *clk;
if (!clk_data)
return -ENOMEM;
for (i = 0; i < num; i++) {
const struct mtk_fixed_factor *ff = &clks[i];
if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) {
pr_warn("Trying to register duplicate clock ID: %d\n", ff->id);
continue;
}
clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
CLK_SET_RATE_PARENT, ff->mult, ff->div);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
ff->name, PTR_ERR(clk));
continue;
pr_err("Failed to register clk %s: %pe\n", ff->name, clk);
goto err;
}
if (clk_data)
clk_data->clks[ff->id] = clk;
}
}
EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
int mtk_clk_register_gates_with_dev(struct device_node *node,
const struct mtk_gate *clks,
int num, struct clk_onecell_data *clk_data,
struct device *dev)
{
int i;
struct clk *clk;
struct regmap *regmap;
if (!clk_data)
return -ENOMEM;
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
pr_err("Cannot find regmap for %pOF: %ld\n", node,
PTR_ERR(regmap));
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_gate *gate = &clks[i];
if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
continue;
clk = mtk_clk_register_gate(gate->name, gate->parent_name,
regmap,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops, gate->flags, dev);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
gate->name, PTR_ERR(clk));
continue;
}
clk_data->clks[gate->id] = clk;
clk_data->clks[ff->id] = clk;
}
return 0;
}
int mtk_clk_register_gates(struct device_node *node,
const struct mtk_gate *clks,
int num, struct clk_onecell_data *clk_data)
{
return mtk_clk_register_gates_with_dev(node,
clks, num, clk_data, NULL);
err:
while (--i >= 0) {
const struct mtk_fixed_factor *ff = &clks[i];
if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
continue;
clk_unregister_fixed_factor(clk_data->clks[ff->id]);
clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_fixed_factor *ff = &clks[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
continue;
clk_unregister_fixed_factor(clk_data->clks[ff->id]);
clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
}
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
void __iomem *base, spinlock_t *lock)
@ -248,58 +270,161 @@ struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
return ERR_PTR(ret);
}
void mtk_clk_register_composites(const struct mtk_composite *mcs,
int num, void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data)
static void mtk_clk_unregister_composite(struct clk *clk)
{
struct clk *clk;
int i;
struct clk_hw *hw;
struct clk_composite *composite;
struct clk_mux *mux = NULL;
struct clk_gate *gate = NULL;
struct clk_divider *div = NULL;
for (i = 0; i < num; i++) {
const struct mtk_composite *mc = &mcs[i];
hw = __clk_get_hw(clk);
if (!hw)
return;
if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
continue;
composite = to_clk_composite(hw);
if (composite->mux_hw)
mux = to_clk_mux(composite->mux_hw);
if (composite->gate_hw)
gate = to_clk_gate(composite->gate_hw);
if (composite->rate_hw)
div = to_clk_divider(composite->rate_hw);
clk = mtk_clk_register_composite(mc, base, lock);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
mc->name, PTR_ERR(clk));
continue;
}
if (clk_data)
clk_data->clks[mc->id] = clk;
}
clk_unregister_composite(clk);
kfree(div);
kfree(gate);
kfree(mux);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
int num, void __iomem *base, spinlock_t *lock,
int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data)
{
struct clk *clk;
int i;
if (!clk_data)
return -ENOMEM;
for (i = 0; i < num; i++) {
const struct mtk_composite *mc = &mcs[i];
if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) {
pr_warn("Trying to register duplicate clock ID: %d\n",
mc->id);
continue;
}
clk = mtk_clk_register_composite(mc, base, lock);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %pe\n", mc->name, clk);
goto err;
}
clk_data->clks[mc->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_composite *mc = &mcs[i];
if (IS_ERR_OR_NULL(clk_data->clks[mcs->id]))
continue;
mtk_clk_unregister_composite(clk_data->clks[mc->id]);
clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_composite *mc = &mcs[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[mc->id]))
continue;
mtk_clk_unregister_composite(clk_data->clks[mc->id]);
clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
}
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites);
int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data)
{
struct clk *clk;
int i;
if (!clk_data)
return -ENOMEM;
for (i = 0; i < num; i++) {
const struct mtk_clk_divider *mcd = &mcds[i];
if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) {
pr_warn("Trying to register duplicate clock ID: %d\n",
mcd->id);
continue;
}
clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
mcd->flags, base + mcd->div_reg, mcd->div_shift,
mcd->div_width, mcd->clk_divider_flags, lock);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
mcd->name, PTR_ERR(clk));
continue;
pr_err("Failed to register clk %s: %pe\n", mcd->name, clk);
goto err;
}
if (clk_data)
clk_data->clks[mcd->id] = clk;
clk_data->clks[mcd->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_clk_divider *mcd = &mcds[i];
if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
continue;
mtk_clk_unregister_composite(clk_data->clks[mcd->id]);
clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_clk_divider *mcd = &mcds[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
continue;
clk_unregister_divider(clk_data->clks[mcd->id]);
clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
}
}
@ -324,13 +449,30 @@ int mtk_clk_simple_probe(struct platform_device *pdev)
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
goto free_data;
goto unregister_clks;
platform_set_drvdata(pdev, clk_data);
return r;
unregister_clks:
mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
free_data:
mtk_free_clk_data(clk_data);
return r;
}
int mtk_clk_simple_remove(struct platform_device *pdev)
{
const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev);
struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
mtk_free_clk_data(clk_data);
return 0;
}
MODULE_LICENSE("GPL");

View file

@ -7,19 +7,19 @@
#ifndef __DRV_CLK_MTK_H
#define __DRV_CLK_MTK_H
#include <linux/regmap.h>
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
struct clk;
struct clk_onecell_data;
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#define MAX_MUX_GATE_BIT 31
#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
#define MHZ (1000 * 1000)
struct platform_device;
struct mtk_fixed_clk {
int id;
const char *name;
@ -34,8 +34,10 @@ struct mtk_fixed_clk {
.rate = _rate, \
}
void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
int num, struct clk_onecell_data *clk_data);
int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
struct clk_onecell_data *clk_data);
struct mtk_fixed_factor {
int id;
@ -53,8 +55,10 @@ struct mtk_fixed_factor {
.div = _div, \
}
void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
int num, struct clk_onecell_data *clk_data);
int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
struct clk_onecell_data *clk_data);
struct mtk_composite {
int id;
@ -146,34 +150,11 @@ struct mtk_composite {
struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
void __iomem *base, spinlock_t *lock);
void mtk_clk_register_composites(const struct mtk_composite *mcs,
int num, void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data);
struct mtk_gate_regs {
u32 sta_ofs;
u32 clr_ofs;
u32 set_ofs;
};
struct mtk_gate {
int id;
const char *name;
const char *parent_name;
const struct mtk_gate_regs *regs;
int shift;
const struct clk_ops *ops;
unsigned long flags;
};
int mtk_clk_register_gates(struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_onecell_data *clk_data);
int mtk_clk_register_gates_with_dev(struct device_node *node,
const struct mtk_gate *clks,
int num, struct clk_onecell_data *clk_data,
struct device *dev);
int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
struct clk_onecell_data *clk_data);
struct mtk_clk_divider {
int id;
@ -197,52 +178,15 @@ struct mtk_clk_divider {
.div_width = _width, \
}
void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
int num, void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data);
int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
void __iomem *base, spinlock_t *lock,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
struct clk_onecell_data *clk_data);
struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
void mtk_free_clk_data(struct clk_onecell_data *clk_data);
#define HAVE_RST_BAR BIT(0)
#define PLL_AO BIT(1)
struct mtk_pll_div_table {
u32 div;
unsigned long freq;
};
struct mtk_pll_data {
int id;
const char *name;
u32 reg;
u32 pwr_reg;
u32 en_mask;
u32 pd_reg;
u32 tuner_reg;
u32 tuner_en_reg;
u8 tuner_en_bit;
int pd_shift;
unsigned int flags;
const struct clk_ops *ops;
u32 rst_bar_mask;
unsigned long fmin;
unsigned long fmax;
int pcwbits;
int pcwibits;
u32 pcw_reg;
int pcw_shift;
u32 pcw_chg_reg;
const struct mtk_pll_div_table *div_table;
const char *parent_name;
u32 en_reg;
u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
};
void mtk_clk_register_plls(struct device_node *node,
const struct mtk_pll_data *plls, int num_plls,
struct clk_onecell_data *clk_data);
struct clk *mtk_clk_register_ref2usb_tx(const char *name,
const char *parent_name, void __iomem *reg);
@ -258,5 +202,6 @@ struct mtk_clk_desc {
};
int mtk_clk_simple_probe(struct platform_device *pdev);
int mtk_clk_simple_remove(struct platform_device *pdev);
#endif /* __DRV_CLK_MTK_H */

View file

@ -4,15 +4,26 @@
* Author: Owen Chen <owen.chen@mediatek.com>
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/compiler_types.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-mux.h"
struct mtk_clk_mux {
struct clk_hw hw;
struct regmap *regmap;
const struct mtk_mux *data;
spinlock_t *lock;
bool reparent;
};
static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
{
return container_of(hw, struct mtk_clk_mux, hw);
@ -164,6 +175,21 @@ static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
return clk;
}
static void mtk_clk_unregister_mux(struct clk *clk)
{
struct mtk_clk_mux *mux;
struct clk_hw *hw;
hw = __clk_get_hw(clk);
if (!hw)
return;
mux = to_mtk_clk_mux(hw);
clk_unregister(clk);
kfree(mux);
}
int mtk_clk_register_muxes(const struct mtk_mux *muxes,
int num, struct device_node *node,
spinlock_t *lock,
@ -175,29 +201,64 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
regmap = device_node_to_regmap(node);
if (IS_ERR(regmap)) {
pr_err("Cannot find regmap for %pOF: %ld\n", node,
PTR_ERR(regmap));
pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap);
return PTR_ERR(regmap);
}
for (i = 0; i < num; i++) {
const struct mtk_mux *mux = &muxes[i];
if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
clk = mtk_clk_register_mux(mux, regmap, lock);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
mux->name, PTR_ERR(clk));
continue;
}
clk_data->clks[mux->id] = clk;
if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
node, mux->id);
continue;
}
clk = mtk_clk_register_mux(mux, regmap, lock);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %pe\n", mux->name, clk);
goto err;
}
clk_data->clks[mux->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_mux *mux = &muxes[i];
if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
continue;
mtk_clk_unregister_mux(clk_data->clks[mux->id]);
clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
}
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_muxes);
void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
struct clk_onecell_data *clk_data)
{
int i;
if (!clk_data)
return;
for (i = num; i > 0; i--) {
const struct mtk_mux *mux = &muxes[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[mux->id]))
continue;
mtk_clk_unregister_mux(clk_data->clks[mux->id]);
clk_data->clks[mux->id] = ERR_PTR(-ENOENT);
}
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_muxes);
MODULE_LICENSE("GPL");

View file

@ -7,15 +7,13 @@
#ifndef __DRV_CLK_MTK_MUX_H
#define __DRV_CLK_MTK_MUX_H
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <linux/types.h>
struct mtk_clk_mux {
struct clk_hw hw;
struct regmap *regmap;
const struct mtk_mux *data;
spinlock_t *lock;
bool reparent;
};
struct clk;
struct clk_onecell_data;
struct clk_ops;
struct device_node;
struct mtk_mux {
int id;
@ -88,4 +86,7 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
spinlock_t *lock,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num,
struct clk_onecell_data *clk_data);
#endif /* __DRV_CLK_MTK_MUX_H */

View file

@ -4,15 +4,18 @@
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk-provider.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/clkdev.h>
#include <linux/delay.h>
#include "clk-mtk.h"
#include "clk-pll.h"
#define MHZ (1000 * 1000)
#define REG_CON0 0
#define REG_CON1 4
@ -359,8 +362,24 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
return clk;
}
void mtk_clk_register_plls(struct device_node *node,
const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
static void mtk_clk_unregister_pll(struct clk *clk)
{
struct clk_hw *hw;
struct mtk_clk_pll *pll;
hw = __clk_get_hw(clk);
if (!hw)
return;
pll = to_mtk_clk_pll(hw);
clk_unregister(clk);
kfree(pll);
}
int mtk_clk_register_plls(struct device_node *node,
const struct mtk_pll_data *plls, int num_plls,
struct clk_onecell_data *clk_data)
{
void __iomem *base;
int i;
@ -369,23 +388,82 @@ void mtk_clk_register_plls(struct device_node *node,
base = of_iomap(node, 0);
if (!base) {
pr_err("%s(): ioremap failed\n", __func__);
return;
return -EINVAL;
}
for (i = 0; i < num_plls; i++) {
const struct mtk_pll_data *pll = &plls[i];
if (!IS_ERR_OR_NULL(clk_data->clks[pll->id])) {
pr_warn("%pOF: Trying to register duplicate clock ID: %d\n",
node, pll->id);
continue;
}
clk = mtk_clk_register_pll(pll, base);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
pll->name, PTR_ERR(clk));
continue;
pr_err("Failed to register clk %s: %pe\n", pll->name, clk);
goto err;
}
clk_data->clks[pll->id] = clk;
}
return 0;
err:
while (--i >= 0) {
const struct mtk_pll_data *pll = &plls[i];
mtk_clk_unregister_pll(clk_data->clks[pll->id]);
clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
}
iounmap(base);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_plls);
static __iomem void *mtk_clk_pll_get_base(struct clk *clk,
const struct mtk_pll_data *data)
{
struct clk_hw *hw = __clk_get_hw(clk);
struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
return pll->base_addr - data->reg;
}
void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
struct clk_onecell_data *clk_data)
{
__iomem void *base = NULL;
int i;
if (!clk_data)
return;
for (i = num_plls; i > 0; i--) {
const struct mtk_pll_data *pll = &plls[i - 1];
if (IS_ERR_OR_NULL(clk_data->clks[pll->id]))
continue;
/*
* This is quite ugly but unfortunately the clks don't have
* any device tied to them, so there's no place to store the
* pointer to the I/O region base address. We have to fetch
* it from one of the registered clks.
*/
base = mtk_clk_pll_get_base(clk_data->clks[pll->id], pll);
mtk_clk_unregister_pll(clk_data->clks[pll->id]);
clk_data->clks[pll->id] = ERR_PTR(-ENOENT);
}
iounmap(base);
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_plls);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: James Liao <jamesjj.liao@mediatek.com>
*/
#ifndef __DRV_CLK_MTK_PLL_H
#define __DRV_CLK_MTK_PLL_H
#include <linux/types.h>
struct clk_ops;
struct clk_onecell_data;
struct device_node;
struct mtk_pll_div_table {
u32 div;
unsigned long freq;
};
#define HAVE_RST_BAR BIT(0)
#define PLL_AO BIT(1)
struct mtk_pll_data {
int id;
const char *name;
u32 reg;
u32 pwr_reg;
u32 en_mask;
u32 pd_reg;
u32 tuner_reg;
u32 tuner_en_reg;
u8 tuner_en_bit;
int pd_shift;
unsigned int flags;
const struct clk_ops *ops;
u32 rst_bar_mask;
unsigned long fmin;
unsigned long fmax;
int pcwbits;
int pcwibits;
u32 pcw_reg;
int pcw_shift;
u32 pcw_chg_reg;
const struct mtk_pll_div_table *div_table;
const char *parent_name;
u32 en_reg;
u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
};
int mtk_clk_register_plls(struct device_node *node,
const struct mtk_pll_data *plls, int num_plls,
struct clk_onecell_data *clk_data);
void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls,
struct clk_onecell_data *clk_data);
#endif /* __DRV_CLK_MTK_PLL_H */

View file

@ -100,8 +100,7 @@ static void mtk_register_reset_controller_common(struct device_node *np,
regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) {
pr_err("Cannot find regmap for %pOF: %ld\n", np,
PTR_ERR(regmap));
pr_err("Cannot find regmap for %pOF: %pe\n", np, regmap);
return;
}

View file

@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
config COMMON_CLK_PIC32
def_bool COMMON_CLK && MACH_PIC32
config MCHP_CLK_MPFS
bool "Clk driver for PolarFire SoC"
depends on (RISCV && SOC_MICROCHIP_POLARFIRE) || COMPILE_TEST
help
Supports Clock Configuration for PolarFire SoC

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o
obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o
obj-$(CONFIG_MCHP_CLK_MPFS) += clk-mpfs.o

View file

@ -0,0 +1,381 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Daire McNamara,<daire.mcnamara@microchip.com>
* Copyright (C) 2020 Microchip Technology Inc. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <dt-bindings/clock/microchip,mpfs-clock.h>
/* address offset of control registers */
#define REG_CLOCK_CONFIG_CR 0x08u
#define REG_SUBBLK_CLOCK_CR 0x84u
#define REG_SUBBLK_RESET_CR 0x88u
struct mpfs_clock_data {
void __iomem *base;
struct clk_hw_onecell_data hw_data;
};
struct mpfs_cfg_clock {
const struct clk_div_table *table;
unsigned int id;
u8 shift;
u8 width;
};
struct mpfs_cfg_hw_clock {
struct mpfs_cfg_clock cfg;
void __iomem *sys_base;
struct clk_hw hw;
struct clk_init_data init;
};
#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
struct mpfs_periph_clock {
unsigned int id;
u8 shift;
};
struct mpfs_periph_hw_clock {
struct mpfs_periph_clock periph;
void __iomem *sys_base;
struct clk_hw hw;
};
#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
/*
* mpfs_clk_lock prevents anything else from writing to the
* mpfs clk block while a software locked register is being written.
*/
static DEFINE_SPINLOCK(mpfs_clk_lock);
static const struct clk_parent_data mpfs_cfg_parent[] = {
{ .index = 0 },
};
static const struct clk_div_table mpfs_div_cpu_axi_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
{ 0, 0 }
};
static const struct clk_div_table mpfs_div_ahb_table[] = {
{ 1, 2 }, { 2, 4}, { 3, 8 },
{ 0, 0 }
};
static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
{
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
void __iomem *base_addr = cfg_hw->sys_base;
u32 val;
val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR) >> cfg->shift;
val &= clk_div_mask(cfg->width);
return prate / (1u << val);
}
static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
{
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, 0);
}
static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
{
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
void __iomem *base_addr = cfg_hw->sys_base;
unsigned long flags;
u32 val;
int divider_setting;
divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0);
if (divider_setting < 0)
return divider_setting;
spin_lock_irqsave(&mpfs_clk_lock, flags);
val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR);
val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
val |= divider_setting << cfg->shift;
writel_relaxed(val, base_addr + REG_CLOCK_CONFIG_CR);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
return 0;
}
static const struct clk_ops mpfs_clk_cfg_ops = {
.recalc_rate = mpfs_cfg_clk_recalc_rate,
.round_rate = mpfs_cfg_clk_round_rate,
.set_rate = mpfs_cfg_clk_set_rate,
};
#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags) { \
.cfg.id = _id, \
.cfg.shift = _shift, \
.cfg.width = _width, \
.cfg.table = _table, \
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_cfg_ops, \
_flags), \
}
static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
CLK_CFG(CLK_CPU, "clk_cpu", mpfs_cfg_parent, 0, 2, mpfs_div_cpu_axi_table, 0),
CLK_CFG(CLK_AXI, "clk_axi", mpfs_cfg_parent, 2, 2, mpfs_div_cpu_axi_table, 0),
CLK_CFG(CLK_AHB, "clk_ahb", mpfs_cfg_parent, 4, 2, mpfs_div_ahb_table, 0),
};
static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hw,
void __iomem *sys_base)
{
cfg_hw->sys_base = sys_base;
return devm_clk_hw_register(dev, &cfg_hw->hw);
}
static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
unsigned int num_clks, struct mpfs_clock_data *data)
{
void __iomem *sys_base = data->base;
unsigned int i, id;
int ret;
for (i = 0; i < num_clks; i++) {
struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
ret = mpfs_clk_register_cfg(dev, cfg_hw, sys_base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
cfg_hw->cfg.id);
id = cfg_hws[i].cfg.id;
data->hw_data.hws[id] = &cfg_hw->hw;
}
return 0;
}
static int mpfs_periph_clk_enable(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
void __iomem *base_addr = periph_hw->sys_base;
u32 reg, val;
unsigned long flags;
spin_lock_irqsave(&mpfs_clk_lock, flags);
reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
val = reg & ~(1u << periph->shift);
writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
val = reg | (1u << periph->shift);
writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
return 0;
}
static void mpfs_periph_clk_disable(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
void __iomem *base_addr = periph_hw->sys_base;
u32 reg, val;
unsigned long flags;
spin_lock_irqsave(&mpfs_clk_lock, flags);
reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
val = reg | (1u << periph->shift);
writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
val = reg & ~(1u << periph->shift);
writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
}
static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
void __iomem *base_addr = periph_hw->sys_base;
u32 reg;
reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
if ((reg & (1u << periph->shift)) == 0u) {
reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
if (reg & (1u << periph->shift))
return 1;
}
return 0;
}
static const struct clk_ops mpfs_periph_clk_ops = {
.enable = mpfs_periph_clk_enable,
.disable = mpfs_periph_clk_disable,
.is_enabled = mpfs_periph_clk_is_enabled,
};
#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
.periph.id = _id, \
.periph.shift = _shift, \
.hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, \
_flags), \
}
#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
/*
* Critical clocks:
* - CLK_ENVM: reserved by hart software services (hss) superloop monitor/m mode interrupt
* trap handler
* - CLK_MMUART0: reserved by the hss
* - CLK_DDRC: provides clock to the ddr subsystem
* - CLK_FICx: these provide clocks for sections of the fpga fabric, disabling them would
* cause the fabric to go into reset
*/
static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
CLK_PERIPH(CLK_ENVM, "clk_periph_envm", PARENT_CLK(AHB), 0, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", PARENT_CLK(AHB), 1, 0),
CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", PARENT_CLK(AHB), 2, 0),
CLK_PERIPH(CLK_MMC, "clk_periph_mmc", PARENT_CLK(AHB), 3, 0),
CLK_PERIPH(CLK_TIMER, "clk_periph_timer", PARENT_CLK(AHB), 4, 0),
CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", PARENT_CLK(AHB), 5, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", PARENT_CLK(AHB), 6, 0),
CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", PARENT_CLK(AHB), 7, 0),
CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", PARENT_CLK(AHB), 8, 0),
CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", PARENT_CLK(AHB), 9, 0),
CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", PARENT_CLK(AHB), 10, 0),
CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", PARENT_CLK(AHB), 11, 0),
CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", PARENT_CLK(AHB), 12, 0),
CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", PARENT_CLK(AHB), 13, 0),
CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0),
CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0),
CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0),
CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, 0),
CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0),
CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0),
CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0),
CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", PARENT_CLK(AHB), 22, 0),
CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", PARENT_CLK(AHB), 23, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", PARENT_CLK(AHB), 24, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", PARENT_CLK(AHB), 25, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", PARENT_CLK(AHB), 26, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", PARENT_CLK(AHB), 27, CLK_IS_CRITICAL),
CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", PARENT_CLK(AHB), 28, 0),
CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0),
};
static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_clock *periph_hw,
void __iomem *sys_base)
{
periph_hw->sys_base = sys_base;
return devm_clk_hw_register(dev, &periph_hw->hw);
}
static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
int num_clks, struct mpfs_clock_data *data)
{
void __iomem *sys_base = data->base;
unsigned int i, id;
int ret;
for (i = 0; i < num_clks; i++) {
struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
ret = mpfs_clk_register_periph(dev, periph_hw, sys_base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
periph_hw->periph.id);
id = periph_hws[i].periph.id;
data->hw_data.hws[id] = &periph_hw->hw;
}
return 0;
}
static int mpfs_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpfs_clock_data *clk_data;
unsigned int num_clks;
int ret;
/* CLK_RESERVED is not part of cfg_clks nor periph_clks, so add 1 */
num_clks = ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1;
clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
clk_data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(clk_data->base))
return PTR_ERR(clk_data->base);
clk_data->hw_data.num = num_clks;
ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
if (ret)
return ret;
ret = mpfs_clk_register_periphs(dev, mpfs_periph_clks, ARRAY_SIZE(mpfs_periph_clks),
clk_data);
if (ret)
return ret;
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
if (ret)
return ret;
return ret;
}
static const struct of_device_id mpfs_clk_of_match_table[] = {
{ .compatible = "microchip,mpfs-clkcfg", },
{}
};
MODULE_DEVICE_TABLE(of, mpfs_clk_match_table);
static struct platform_driver mpfs_clk_driver = {
.probe = mpfs_clk_probe,
.driver = {
.name = "microchip-mpfs-clkcfg",
.of_match_table = mpfs_clk_of_match_table,
},
};
static int __init clk_mpfs_init(void)
{
return platform_driver_register(&mpfs_clk_driver);
}
core_initcall(clk_mpfs_init);
static void __exit clk_mpfs_exit(void)
{
platform_driver_unregister(&mpfs_clk_driver);
}
module_exit(clk_mpfs_exit);
MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
MODULE_LICENSE("GPL v2");

View file

@ -24,6 +24,7 @@
#define PMC_PLLACK 7
#define PMC_PLLBCK 8
#define PMC_AUDIOPLLCK 9
#define PMC_AUDIOPINCK 10
/* SAMA7G5 */
#define PMC_CPUPLL (PMC_MAIN + 1)
@ -35,6 +36,7 @@
#define PMC_AUDIOIOPLL (PMC_MAIN + 7)
#define PMC_ETHPLL (PMC_MAIN + 8)
#define PMC_CPU (PMC_MAIN + 9)
#define PMC_MCK1 (PMC_MAIN + 10)
#ifndef AT91_PMC_MOSCS
#define AT91_PMC_MOSCS 0 /* MOSCS Flag */

View file

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Daire McNamara,<daire.mcnamara@microchip.com>
* Copyright (C) 2020 Microchip Technology Inc. All rights reserved.
*/
#ifndef _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_
#define _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_
#define CLK_CPU 0
#define CLK_AXI 1
#define CLK_AHB 2
#define CLK_ENVM 3
#define CLK_MAC0 4
#define CLK_MAC1 5
#define CLK_MMC 6
#define CLK_TIMER 7
#define CLK_MMUART0 8
#define CLK_MMUART1 9
#define CLK_MMUART2 10
#define CLK_MMUART3 11
#define CLK_MMUART4 12
#define CLK_SPI0 13
#define CLK_SPI1 14
#define CLK_I2C0 15
#define CLK_I2C1 16
#define CLK_CAN0 17
#define CLK_CAN1 18
#define CLK_USB 19
#define CLK_RESERVED 20
#define CLK_RTC 21
#define CLK_QSPI 22
#define CLK_GPIO0 23
#define CLK_GPIO1 24
#define CLK_GPIO2 25
#define CLK_DDRC 26
#define CLK_FIC0 27
#define CLK_FIC1 28
#define CLK_FIC2 29
#define CLK_FIC3 30
#define CLK_ATHENA 31
#define CLK_CFM 32
#endif /* _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_ */