Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35b9a994 authored by Odelu Kukatla's avatar Odelu Kukatla Committed by Gerrit - the friendly Code Review server
Browse files

clk: qcom: Add video clock driver for ATOLL



Add support for the video clock controller found on ATOLL
based devices. This will allow video device drivers to
probe and control their clocks.

Change-Id: Ib852ff32b6bdf8a07ffb9c4fbc3411a089a950cf
Signed-off-by: default avatarOdelu Kukatla <okukatla@codeaurora.org>
parent f10d72b6
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@ Qualcomm Technologies, Inc. Video Clock & Reset Controller Bindings
Required properties:
- compatible: shall contain "qcom,videocc-sm8150" or "qcom,videocc-sm8150-v2" or
				"qcom,videocc-sm6150", "qcom,videocc-sdmmagpie" or
				"qcom,videocc-trinket" or "qcom,videocc-sa6155".
				"qcom,videocc-trinket" or "qcom,videocc-sa6155" or
				"qcom,atoll-videocc".
- reg: shall contain base register location and length.
- reg-names: names of registers listed in the same order as in the reg property.
- vdd_<mm/cx>-supply: the logic rail supply which could be either MM or CX.
+9 −0
Original line number Diff line number Diff line
@@ -587,3 +587,12 @@ config SM_CAMCC_ATOLL
	  ATOLL devices.
	  Say Y if you want to support camera devices and functionality such as
	  capturing pictures.

config SM_VIDEOCC_ATOLL
	tristate "ATOLL Video Clock Controller"
	depends on COMMON_CLK_QCOM
	help
	  Support for the video clock controller on Qualcomm Technologies, Inc.
	  ATOLL devices.
	  Say Y if you want to support video devices and functionality such as
	  video encode/decode.
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ obj-$(CONFIG_SM_DISPCC_TRINKET) += dispcc-trinket.o
obj-$(CONFIG_SM_GCC_ATOLL) += gcc-atoll.o
obj-$(CONFIG_SM_GCC_TRINKET) += gcc-trinket.o
obj-$(CONFIG_SM_GPUCC_TRINKET) += gpucc-trinket.o
obj-$(CONFIG_SM_VIDEOCC_ATOLL) += videocc-atoll.o
obj-$(CONFIG_SM_VIDEOCC_TRINKET) += videocc-trinket.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
obj-$(CONFIG_VIRTIO_CLK) += virtio_clk.o virtio_clk_sm8150.o virtio_clk_sm6150.o virtio_clk_sa8195p.o
+326 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#define pr_fmt(fmt) "clk: %s: " fmt, __func__

#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>

#include <dt-bindings/clock/qcom,videocc-atoll.h>

#include "common.h"
#include "clk-regmap.h"
#include "clk-rcg.h"
#include "clk-branch.h"
#include "clk-alpha-pll.h"
#include "vdd-level-sdmmagpie.h"

#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }

static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner);

enum {
	P_BI_TCXO,
	P_CHIP_SLEEP_CLK,
	P_CORE_BI_PLL_TEST_SE,
	P_VIDEO_PLL0_OUT_EVEN,
	P_VIDEO_PLL0_OUT_MAIN,
	P_VIDEO_PLL0_OUT_ODD,
};

static const struct parent_map video_cc_parent_map_0[] = {
	{ P_CHIP_SLEEP_CLK, 0 },
	{ P_CORE_BI_PLL_TEST_SE, 7 },
};

static const char * const video_cc_parent_names_0[] = {
	"chip_sleep_clk",
	"core_bi_pll_test_se",
};

static const struct parent_map video_cc_parent_map_1[] = {
	{ P_BI_TCXO, 0 },
	{ P_VIDEO_PLL0_OUT_MAIN, 1 },
	{ P_VIDEO_PLL0_OUT_EVEN, 2 },
	{ P_VIDEO_PLL0_OUT_ODD, 3 },
	{ P_CORE_BI_PLL_TEST_SE, 7 },
};

static const char * const video_cc_parent_names_1[] = {
	"bi_tcxo",
	"video_pll0",
	"video_pll0_out_even",
	"video_pll0_out_odd",
	"core_bi_pll_test_se",
};

static const struct parent_map video_cc_parent_map_2[] = {
	{ P_BI_TCXO, 0 },
	{ P_CORE_BI_PLL_TEST_SE, 7 },
};

static const char * const video_cc_parent_names_2[] = {
	"bi_tcxo",
	"core_bi_pll_test_se",
};

static struct pll_vco fabia_vco[] = {
	{ 249600000, 2000000000, 0 },
	{ 125000000, 1000000000, 1 },
};

static struct alpha_pll_config video_pll0_config = {
	.l = 0x1F,
	.frac = 0x4000,
	.user_ctl_val = 0x00000001,
	.user_ctl_hi_val = 0x00004805,
};

static struct clk_alpha_pll video_pll0 = {
	.offset = 0x42c,
	.vco_table = fabia_vco,
	.num_vco = ARRAY_SIZE(fabia_vco),
	.type = FABIA_PLL,
	.clkr = {
		.hw.init = &(struct clk_init_data){
			.name = "video_pll0",
			.parent_names = (const char *[]){ "bi_tcxo" },
			.num_parents = 1,
			.ops = &clk_fabia_pll_ops,
			.vdd_class = &vdd_cx,
			.num_rate_max = VDD_NUM,
			.rate_max = (unsigned long[VDD_NUM]) {
				[VDD_MIN] = 615000000,
				[VDD_LOW] = 1066000000,
				[VDD_LOW_L1] = 1600000000,
				[VDD_NOMINAL] = 2000000000},
		},
	},
};

static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = {
	F(19200000, P_BI_TCXO, 1, 0, 0),
	F(150000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0),
	F(270000000, P_VIDEO_PLL0_OUT_MAIN, 2.5, 0, 0),
	F(340000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
	F(434000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
	F(500000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
	{ }
};

static struct clk_rcg2 video_cc_venus_clk_src = {
	.cmd_rcgr = 0x7f0,
	.mnd_width = 0,
	.hid_width = 5,
	.parent_map = video_cc_parent_map_1,
	.freq_tbl = ftbl_video_cc_venus_clk_src,
	.enable_safe_config = true,
	.clkr.hw.init = &(struct clk_init_data){
		.name = "video_cc_venus_clk_src",
		.parent_names = video_cc_parent_names_1,
		.num_parents = 5,
		.flags = CLK_SET_RATE_PARENT,
		.ops = &clk_rcg2_ops,
		.vdd_class = &vdd_cx,
		.num_rate_max = VDD_NUM,
		.rate_max = (unsigned long[VDD_NUM]) {
			[VDD_LOWER] = 150000000,
			[VDD_LOW] = 270000000,
			[VDD_LOW_L1] = 340000000,
			[VDD_NOMINAL] = 434000000,
			[VDD_HIGH] = 500000000},
	},
};

static struct clk_branch video_cc_vcodec0_axi_clk = {
	.halt_reg = 0x9ec,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0x9ec,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_vcodec0_axi_clk",
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch video_cc_vcodec0_core_clk = {
	.halt_reg = 0x890,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0x890,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_vcodec0_core_clk",
			.parent_names = (const char *[]){
				"video_cc_venus_clk_src",
			},
			.num_parents = 1,
			.flags = CLK_SET_RATE_PARENT,
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch video_cc_venus_ahb_clk = {
	.halt_reg = 0xa4c,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0xa4c,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_venus_ahb_clk",
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch video_cc_venus_ctl_axi_clk = {
	.halt_reg = 0x9cc,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0x9cc,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_venus_ctl_axi_clk",
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch video_cc_venus_ctl_core_clk = {
	.halt_reg = 0x850,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0x850,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_venus_ctl_core_clk",
			.parent_names = (const char *[]){
				"video_cc_venus_clk_src",
			},
			.num_parents = 1,
			.flags = CLK_SET_RATE_PARENT,
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch video_cc_xo_clk = {
	.halt_reg = 0x984,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0x984,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "video_cc_xo_clk",
			.flags = CLK_IS_CRITICAL,
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_regmap *video_cc_atoll_clocks[] = {
	[VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr,
	[VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr,
	[VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr,
	[VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr,
	[VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr,
	[VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr,
	[VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr,
	[VIDEO_PLL0] = &video_pll0.clkr,
};

static const struct regmap_config video_cc_atoll_regmap_config = {
	.reg_bits = 32,
	.reg_stride = 4,
	.val_bits = 32,
	.max_register = 0xb94,
	.fast_io = true,
};

static const struct qcom_cc_desc video_cc_atoll_desc = {
	.config = &video_cc_atoll_regmap_config,
	.clks = video_cc_atoll_clocks,
	.num_clks = ARRAY_SIZE(video_cc_atoll_clocks),
};

static const struct of_device_id video_cc_atoll_match_table[] = {
	{ .compatible = "qcom,atoll-videocc" },
	{ }
};
MODULE_DEVICE_TABLE(of, video_cc_atoll_match_table);

static int video_cc_atoll_probe(struct platform_device *pdev)
{
	struct regmap *regmap;
	int ret;

	vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx");
	if (IS_ERR(vdd_cx.regulator[0])) {
		if (PTR_ERR(vdd_cx.regulator[0]) != -EPROBE_DEFER)
			dev_err(&pdev->dev,
					"Unable to get vdd_cx regulator\n");
		return PTR_ERR(vdd_cx.regulator[0]);
	}

	regmap = qcom_cc_map(pdev, &video_cc_atoll_desc);
	if (IS_ERR(regmap)) {
		pr_err("Failed to map the video_cc registers\n");
		return PTR_ERR(regmap);
	}

	clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config);

	ret = qcom_cc_really_probe(pdev, &video_cc_atoll_desc, regmap);
	if (ret) {
		dev_err(&pdev->dev, "Failed to register Video CC clocks\n");
		return ret;
	}

	dev_info(&pdev->dev, "Registered Video CC clocks\n");
	return ret;
}

static struct platform_driver video_cc_atoll_driver = {
	.probe = video_cc_atoll_probe,
	.driver = {
		.name = "atoll-videocc",
		.of_match_table = video_cc_atoll_match_table,
	},
};

static int __init video_cc_atoll_init(void)
{
	return platform_driver_register(&video_cc_atoll_driver);
}
subsys_initcall(video_cc_atoll_init);

static void __exit video_cc_atoll_exit(void)
{
	platform_driver_unregister(&video_cc_atoll_driver);
}
module_exit(video_cc_atoll_exit);

MODULE_DESCRIPTION("QTI VIDEO_CC atoll Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:video_cc-atoll");
+8 −11
Original line number Diff line number Diff line
@@ -15,16 +15,13 @@
#define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_ATOLL_H

/* VIDEO_CC clocks */
#define VIDEO_PLL0_OUT_MAIN					0
#define VIDEO_CC_APB_CLK					1
#define VIDEO_CC_SLEEP_CLK					2
#define VIDEO_CC_SLEEP_CLK_SRC					3
#define VIDEO_CC_VCODEC0_AXI_CLK				4
#define VIDEO_CC_VCODEC0_CORE_CLK				5
#define VIDEO_CC_VENUS_AHB_CLK					6
#define VIDEO_CC_VENUS_CLK_SRC					7
#define VIDEO_CC_VENUS_CTL_AXI_CLK				8
#define VIDEO_CC_VENUS_CTL_CORE_CLK				9
#define VIDEO_CC_XO_CLK						10
#define VIDEO_PLL0						0
#define VIDEO_CC_VCODEC0_AXI_CLK				1
#define VIDEO_CC_VCODEC0_CORE_CLK				2
#define VIDEO_CC_VENUS_AHB_CLK					3
#define VIDEO_CC_VENUS_CLK_SRC					4
#define VIDEO_CC_VENUS_CTL_AXI_CLK				5
#define VIDEO_CC_VENUS_CTL_CORE_CLK				6
#define VIDEO_CC_XO_CLK						7

#endif