blob: 6f562f95dd4b261d5f52acabc984567dc8ce119f [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <dt-bindings/clock/sm1-clkc.h>
#include "clkc.h"
#include "sm1.h"
#ifdef CONFIG_ARM
static const struct pll_params_table sm1_gp1_pll_params_table[] = {
/* set od 0 default */
PLL_PARAMS(128, 1, 7), /*DCO=3072M OD=24M*/
PLL_PARAMS(128, 1, 6), /*DCO=3072M OD=48M*/
PLL_PARAMS(128, 1, 5), /*DCO=3072M OD=96M*/
PLL_PARAMS(128, 1, 4), /*DCO=3072M OD=192M*/
PLL_PARAMS(208, 1, 4), /*DCO=4992M OD=312M*/
PLL_PARAMS(136, 1, 3), /*DCO=3264M OD=408M*/
PLL_PARAMS(200, 1, 3), /*DCO=4800M OD=600M*/
PLL_PARAMS(232, 1, 3), /*DCO=5568M OD=696M*/
PLL_PARAMS(132, 1, 2), /*DCO=3168M OD=792M*/
PLL_PARAMS(141, 1, 2), /*DCO=3384M OD=846M*/
PLL_PARAMS(142, 1, 2), /*DCO=3408M OD=852M*/
PLL_PARAMS(149, 1, 2), /*DCO=3576M OD=894M*/
PLL_PARAMS(152, 1, 2), /*DCO=3648M OD=912M*/
PLL_PARAMS(168, 1, 2), /*DCO=4032M OD=1008M*/
PLL_PARAMS(184, 1, 2), /*DCO=4416M OD=1104M*/
PLL_PARAMS(200, 1, 2), /*DCO=4800M OD=1200M*/
PLL_PARAMS(216, 1, 2), /*DCO=5184M OD=1296M*/
PLL_PARAMS(233, 1, 2), /*DCO=5592M OD=1398M*/
PLL_PARAMS(249, 1, 2), /*DCO=5976M OD=1494M*/
PLL_PARAMS(126, 1, 1), /*DCO=3024M OD=1512M*/
{ /* sentinel */ },
};
#else
static const struct pll_params_table sm1_gp1_pll_params_table[] = {
PLL_PARAMS(128, 1), /*DCO=3072M */
PLL_PARAMS(128, 1), /*DCO=3072M */
PLL_PARAMS(128, 1), /*DCO=3072M */
PLL_PARAMS(128, 1), /*DCO=3072M */
PLL_PARAMS(208, 1), /*DCO=4992M */
PLL_PARAMS(136, 1), /*DCO=3264M */
PLL_PARAMS(200, 1), /*DCO=4800M */
PLL_PARAMS(232, 1), /*DCO=5568M */
PLL_PARAMS(132, 1), /*DCO=3168M */
PLL_PARAMS(141, 1), /*DCO=3384M */
PLL_PARAMS(142, 1), /*DCO=3408M */
PLL_PARAMS(149, 1), /*DCO=3576M */
PLL_PARAMS(152, 1), /*DCO=3648M */
PLL_PARAMS(168, 1), /*DCO=4032M */
PLL_PARAMS(184, 1), /*DCO=4416M */
PLL_PARAMS(200, 1), /*DCO=4800M */
PLL_PARAMS(216, 1), /*DCO=5184M */
PLL_PARAMS(233, 1), /*DCO=5592M */
PLL_PARAMS(249, 1), /*DCO=5976M */
PLL_PARAMS(126, 1), /*DCO=3024M */
PLL_PARAMS(134, 1), /*DCO=3216M */
PLL_PARAMS(142, 1), /*DCO=3408M */
PLL_PARAMS(150, 1), /*DCO=3600M */
PLL_PARAMS(158, 1), /*DCO=3792M */
PLL_PARAMS(159, 1), /*DCO=3816M */
PLL_PARAMS(160, 1), /*DCO=3840M */
PLL_PARAMS(168, 1), /*DCO=4032M */
{ /* sentinel */ },
};
#endif
/*
* Internal gp1 pll emulation configuration parameters
*/
static const struct reg_sequence sm1_gp1_init_regs[] = {
{ .reg = HHI_GP1_PLL_CNTL1, .def = 0x00000000 },
{ .reg = HHI_GP1_PLL_CNTL2, .def = 0x00000000 },
{ .reg = HHI_GP1_PLL_CNTL3, .def = 0x48681c00 },
{ .reg = HHI_GP1_PLL_CNTL4, .def = 0x33771290 },
{ .reg = HHI_GP1_PLL_CNTL5, .def = 0x39272000 },
{ .reg = HHI_GP1_PLL_CNTL6, .def = 0x56540000, .delay_us = 10 },
};
static struct clk_regmap sm1_gp1_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 28,
.width = 1,
},
.m = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 0,
.width = 8,
},
.n = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 10,
.width = 5,
},
/* for 32bit */
.od = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 16,
.width = 3,
},
.frac = {
.reg_off = HHI_GP1_PLL_CNTL1,
.shift = 0,
.width = 19,
},
.l = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_GP1_PLL_CNTL0,
.shift = 29,
.width = 1,
},
.init_en = 0,
.table = sm1_gp1_pll_params_table,
.init_regs = sm1_gp1_init_regs,
.init_count = ARRAY_SIZE(sm1_gp1_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "sm1_gp1_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "sm1_ee_core" },
.num_parents = 1,
.flags = CLK_IGNORE_UNUSED,
},
};
#ifdef CONFIG_ARM
static struct clk_regmap sm1_gp1_pll = {
.hw.init = &(struct clk_init_data){
.name = "gp1_pll",
.ops = &meson_pll_clk_no_ops,
.parent_names = (const char *[]){ "gp1_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
#else
static struct clk_regmap sm1_gp1_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_GP1_PLL_CNTL0,
.shift = 16,
.width = 3,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "gp1_pll",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "gp1_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
#endif
static const char * const media_parent_names[] = { "sm1_ee_core",
"gp0_pll", "hifi_pll", "fclk_div2p5", "fclk_div3", "fclk_div4",
"fclk_div5", "fclk_div7"};
static struct clk_regmap cts_vipnanoq_core_clk_mux = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.mask = 0x7,
.shift = 9,
},
.hw.init = &(struct clk_init_data){
.name = "cts_vipnanoq_core_clk_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = media_parent_names,
.num_parents = 8,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_vipnanoq_core_clk_div = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_vipnanoq_core_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_vipnanoq_core_clk_mux" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_vipnanoq_core_clk_gate = {
.data = &(struct clk_regmap_gate_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_vipnanoq_core_clk_gate",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_vipnanoq_core_clk_div" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_vipnanoq_axi_clk_mux = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.mask = 0x7,
.shift = 25,
},
.hw.init = &(struct clk_init_data){
.name = "cts_vipnanoq_axi_clk_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = media_parent_names,
.num_parents = 8,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_vipnanoq_axi_clk_div = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.shift = 16,
.width = 7,
},
.hw.init = &(struct clk_init_data){
.name = "cts_vipnanoq_axi_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_vipnanoq_axi_clk_mux" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_vipnanoq_axi_clk_gate = {
.data = &(struct clk_regmap_gate_data) {
.offset = HHI_VIPNANOQ_CLK_CNTL,
.bit_idx = 24,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_vipnanoq_axi_clk_gate",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_vipnanoq_axi_clk_div" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static const char * const media_parent_names_mipi[] = { "sm1_ee_core",
"gp0_pll", "mpll1", "mpll2", "fclk_div3", "fclk_div4",
"fclk_div5", "fclk_div7"
};
static struct clk_regmap cts_mipi_csi_phy_clk_mux = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_MIPI_CSI_PHY_CLK_CNTL,
.mask = 3,
.shift = 9,
},
.hw.init = &(struct clk_init_data){
.name = "cts_mipi_csi_phy_clk_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = media_parent_names_mipi,
.num_parents = 8,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_mipi_csi_phy_clk_div = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_MIPI_CSI_PHY_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(struct clk_init_data){
.name = "cts_mipi_csi_phy_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_mipi_csi_phy_clk_mux" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_mipi_csi_phy_clk_gate = {
.data = &(struct clk_regmap_gate_data) {
.offset = HHI_MIPI_CSI_PHY_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_mipi_csi_phy_clk_gate",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_mipi_csi_phy_clk_div" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static const char * const media_parent_names_adapt[] = { "sm1_ee_core",
"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "mpll2",
"mpll3", "gp0_pll"
};
static struct clk_regmap cts_csi_adapt_clk_mux = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_CSI2_ADAPT_CLK_CNTL,
.mask = 0x7,
.shift = 9,
},
.hw.init = &(struct clk_init_data){
.name = "cts_csi_adapt_clk_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = media_parent_names_adapt,
.num_parents = 8,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_csi_adapt_clk_div = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_CSI2_ADAPT_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(struct clk_init_data){
.name = "cts_csi_adapt_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "cts_csi_adapt_clk_mux" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap cts_csi_adapt_clk_gate = {
.data = &(struct clk_regmap_gate_data) {
.offset = HHI_CSI2_ADAPT_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_csi_adapt_clk_gate",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_csi_adapt_clk_div" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap sm1_dsu_pre_src_clk_mux0 = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x3,
.shift = 0,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre_src0",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "sm1_ee_core", "fclk_div2",
"fclk_div3", "gp1_pll" },
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap sm1_dsu_pre_src_clk_mux1 = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x3,
.shift = 16,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre_src1",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "sm1_ee_core", "fclk_div2",
"fclk_div3", "gp1_pll" },
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap sm1_dsu_clk_div0 = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.shift = 4,
.width = 6,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_clk_div0",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "dsu_pre_src0" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap sm1_dsu_clk_div1 = {
.data = &(struct clk_regmap_div_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.shift = 20,
.width = 6,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_clk_div1",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "dsu_pre_src1" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap sm1_dsu_pre_clk_mux0 = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x1,
.shift = 2,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre0",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "dsu_pre_src0",
"dsu_clk_div0",},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap sm1_dsu_pre_clk_mux1 = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x1,
.shift = 18,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre1",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "dsu_pre_src1",
"dsu_clk_div1",},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap sm1_dsu_pre_post_clk_mux = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x1,
.shift = 10,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre_post",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "dsu_pre0",
"dsu_pre1",},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap sm1_dsu_pre_clk = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL5,
.mask = 0x1,
.shift = 11,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_pre_clk",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "dsu_pre_post",
"sys_pll",},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap sm1_dsu_clk = {
.data = &(struct clk_regmap_mux_data) {
.offset = HHI_SYS_CPU_CLK_CNTL6,
.mask = 0x1,
.shift = 27,
},
.hw.init = &(struct clk_init_data){
.name = "dsu_clk",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "cpu_clk",
"dsu_pre_clk",},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static MESON_GATE(sm1_csi_dig, HHI_GCLK_MPEG1, 18);
static MESON_GATE(sm1_nna, HHI_GCLK_MPEG1, 19);
static MESON_GATE(sm1_parser1, HHI_GCLK_MPEG1, 28);
static MESON_GATE(sm1_csi_host, HHI_GCLK_MPEG2, 16);
static MESON_GATE(sm1_csi_adpat, HHI_GCLK_MPEG2, 17);
static MESON_GATE(sm1_temp_sensor, HHI_GCLK_MPEG2, 22);
static MESON_GATE(sm1_csi_phy, HHI_GCLK_MPEG2, 29);
static struct clk_regmap *const sm1_clk_regmaps[] = {
&sm1_gp1_pll_dco,
&sm1_gp1_pll,
&sm1_dsu_pre_src_clk_mux0,
&sm1_dsu_pre_src_clk_mux1,
&sm1_dsu_clk_div0,
&sm1_dsu_clk_div1,
&sm1_dsu_pre_clk_mux0,
&sm1_dsu_pre_clk_mux1,
&sm1_dsu_pre_post_clk_mux,
&sm1_dsu_pre_clk,
&sm1_dsu_clk,
&sm1_csi_dig,
&sm1_nna,
&sm1_parser1,
&sm1_csi_host,
&sm1_csi_adpat,
&sm1_temp_sensor,
&sm1_csi_phy,
&cts_vipnanoq_core_clk_mux,
&cts_vipnanoq_core_clk_div,
&cts_vipnanoq_core_clk_gate,
&cts_vipnanoq_axi_clk_mux,
&cts_vipnanoq_axi_clk_div,
&cts_vipnanoq_axi_clk_gate,
&cts_mipi_csi_phy_clk_mux,
&cts_mipi_csi_phy_clk_div,
&cts_mipi_csi_phy_clk_gate,
&cts_csi_adapt_clk_mux,
&cts_csi_adapt_clk_div,
&cts_csi_adapt_clk_gate,
};
static struct clk_hw_onecell_data sm1_hw_onecell_data = {
.hws = {
[CLKID_GP1_PLL_DCO] = &sm1_gp1_pll_dco.hw,
[CLKID_GP1_PLL] = &sm1_gp1_pll.hw,
[CLKID_DSU_PRE_SRC0] = &sm1_dsu_pre_src_clk_mux0.hw,
[CLKID_DSU_PRE_SRC1] = &sm1_dsu_pre_src_clk_mux1.hw,
[CLKID_DSU_CLK_DIV0] = &sm1_dsu_clk_div0.hw,
[CLKID_DSU_CLK_DIV1] = &sm1_dsu_clk_div1.hw,
[CLKID_DSU_PRE_MUX0] = &sm1_dsu_pre_clk_mux0.hw,
[CLKID_DSU_PRE_MUX1] = &sm1_dsu_pre_clk_mux1.hw,
[CLKID_DSU_PRE_POST_MUX] = &sm1_dsu_pre_post_clk_mux.hw,
[CLKID_DSU_PRE_CLK] = &sm1_dsu_pre_clk.hw,
[CLKID_DSU_CLK] = &sm1_dsu_clk.hw,
[CLKID_CSI_DIG_CLK] = &sm1_csi_dig.hw,
[CLKID_NNA_CLK] = &sm1_nna.hw,
[CLKID_PARSER1_CLK] = &sm1_parser1.hw,
[CLKID_CSI_HOST_CLK] = &sm1_csi_host.hw,
[CLKID_CSI_ADPAT_CLK] = &sm1_csi_adpat.hw,
[CLKID_TEMP_SENSOR_CLK] = &sm1_temp_sensor.hw,
[CLKID_CSI_PHY_CLK] = &sm1_csi_phy.hw,
[CLKID_VNANOQ_CORE_MUX_CLK] = &cts_vipnanoq_core_clk_mux.hw,
[CLKID_VNANOQ_CORE_DIV_CLK] = &cts_vipnanoq_core_clk_div.hw,
[CLKID_VNANOQ_CORE_CLK_COMP] = &cts_vipnanoq_core_clk_gate.hw,
[CLKID_VNANOQ_AXI_MUX_CLK] = &cts_vipnanoq_axi_clk_mux.hw,
[CLKID_VNANOQ_AXI_DIV_CLK] = &cts_vipnanoq_axi_clk_div.hw,
[CLKID_VNANOQ_AXI_CLK_COMP] = &cts_vipnanoq_axi_clk_gate.hw,
[CLKID_MIPI_CSI_PHY_MUX_CLK] = &cts_mipi_csi_phy_clk_mux.hw,
[CLKID_MIPI_CSI_PHY_DIV_CLK] = &cts_mipi_csi_phy_clk_div.hw,
[CLKID_MIPI_CSI_PHY_CLK_COMP] = &cts_mipi_csi_phy_clk_gate.hw,
[CLKID_CSI_ADAPT_MUX_CLK] = &cts_csi_adapt_clk_mux.hw,
[CLKID_CSI_ADAPT_DIV_CLK] = &cts_csi_adapt_clk_div.hw,
[CLKID_CSI_ADAPT_CLK_COMP] = &cts_csi_adapt_clk_gate.hw,
},
.num = SM1_NR_CLKS,
};
static const struct of_device_id clkc_match_table[] = {
{ .compatible = "amlogic,sm1-clkc-1" },
{}
};
struct sm1_nb_data {
struct notifier_block nb;
};
static int sm1_dsu_mux_clk_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct clk *dsu_pre_clk, *parent_clk;
int ret;
switch (event) {
case PRE_RATE_CHANGE:
parent_clk = sm1_dsu_pre_clk_mux1.hw.clk;
break;
case POST_RATE_CHANGE:
parent_clk = sm1_dsu_pre_clk_mux0.hw.clk;
break;
default:
return NOTIFY_DONE;
}
dsu_pre_clk = sm1_dsu_pre_post_clk_mux.hw.clk;
ret = clk_set_parent(dsu_pre_clk, parent_clk);
if (ret)
return notifier_from_errno(ret);
usleep_range(80, 120);
return NOTIFY_OK;
}
static struct sm1_nb_data sm1_dsu_nb_data = {
.nb.notifier_call = sm1_dsu_mux_clk_notifier_cb,
};
static int sm1_clkc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap *map;
struct clk_hw *hw;
int ret, i;
struct clk *fclk_div2;
/* Get the hhi system controller node */
map = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(map)) {
dev_err(dev, "failed to get HHI regmap\n");
return PTR_ERR(map);
}
hw = meson_clk_hw_register_input(dev, "core", "sm1_ee_core", 0);
if (IS_ERR(hw))
return PTR_ERR(hw);
sm1_hw_onecell_data.hws[CLKID_SM1_EE_CLK] = hw;
/* Populate regmap for the regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(sm1_clk_regmaps); i++)
sm1_clk_regmaps[i]->map = map;
for (i = 1; i < sm1_hw_onecell_data.num; i++) {
/* array might be sparse */
if (!sm1_hw_onecell_data.hws[i])
continue;
ret = devm_clk_hw_register(dev, sm1_hw_onecell_data.hws[i]);
if (ret) {
dev_err(dev, "Clock registration failed %d\n", i);
return ret;
}
}
/* set sm1_dsu_pre_src_clk_mux1 parent to fclk_div2 1G */
fclk_div2 = of_clk_get_by_name(dev->of_node, "clkin0");
if (IS_ERR(fclk_div2)) {
pr_err("faied to get clkin0\n");
return PTR_ERR(fclk_div2);
}
ret = clk_set_parent(sm1_dsu_pre_src_clk_mux1.hw.clk, fclk_div2);
if (ret < 0) {
pr_err("%s: failed to set parent for dsu_pre_src_clk_mux1\n",
__func__);
return ret;
}
/*
* when change sm1_dsu_pre_clk_mux0, switch to
* sm1_dsu_pre_clk_mux1 to avoid crash
*/
ret = clk_notifier_register(sm1_dsu_pre_clk_mux0.hw.clk,
&sm1_dsu_nb_data.nb);
if (ret) {
pr_err("%s:failed to register clock notifier for dsu\n",
__func__);
return ret;
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
&sm1_hw_onecell_data);
}
static struct platform_driver sm1_clk_driver = {
.probe = sm1_clkc_probe,
.driver = {
.name = "sm1-clkc",
.of_match_table = clkc_match_table,
},
};
static int sm1_clkc_init(void)
{
return platform_driver_register(&sm1_clk_driver);
}
arch_initcall_sync(sm1_clkc_init);