From adeabd63770c9cc8285c0841b479f23b4dcc5f9a Mon Sep 17 00:00:00 2001
From: Mis012 <michael.srba@seznam.cz>
Date: Wed, 12 Jan 2022 14:03:31 +0100
Subject: [PATCH 3/3] SSC WIP

---
 .../boot/dts/qcom/msm8998-fxtec-pro1.dts      |  76 ++++-
 arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi     |  42 ++-
 drivers/bus/Kconfig                           |   6 +
 drivers/bus/Makefile                          |   1 +
 drivers/bus/qcom-ssc-block-bus.c              | 231 +++++++++++++
 drivers/clk/qcom/scc-msm8998.c                | 323 ++++++++++++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |   2 +-
 include/dt-bindings/clock/qcom,scc-msm8998.h  |  32 ++
 8 files changed, 707 insertions(+), 6 deletions(-)
 create mode 100644 drivers/bus/qcom-ssc-block-bus.c
 create mode 100644 drivers/clk/qcom/scc-msm8998.c
 create mode 100644 include/dt-bindings/clock/qcom,scc-msm8998.h

diff --git a/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts b/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
index dc5b9b274df3..ead43c013b31 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
+++ b/arch/arm64/boot/dts/qcom/msm8998-fxtec-pro1.dts
@@ -11,6 +11,7 @@
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/clock/qcom,scc-msm8998.h> // FIXME
 
 / {
 	model = "F(x)tec Pro1 (QX1000)";
@@ -52,7 +53,7 @@ gpio-kb-extra-keys {
 		home {
 			label = "Home";
 			gpios = <&tlmm 21 GPIO_ACTIVE_LOW>;
-			linux,code = <KEY_HOMEPAGE>;
+			linux,code = <KEY_LEFTMETA>;
 			debounce-interval = <15>;
 			linux,can-disable;
 		};
@@ -68,7 +69,7 @@ super-l {
 		super-r {
 			label = "Super Right";
 			gpios = <&tlmm 33 GPIO_ACTIVE_LOW>;
-			linux,code = <KEY_FN>;
+			linux,code = <KEY_RIGHTALT>;
 			debounce-interval = <15>;
 			linux,can-disable;
 		};
@@ -315,3 +316,74 @@ &vreg_l28_3p0 {
 	regulator-min-microvolt = <2800000>;
 	regulator-max-microvolt = <2800000>;
 };
+
+&soc {
+	ssc_ahb_slave { // devices under this node are physically located in the SSC block, connected to an ssc-internal bus;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		compatible = "qcom,ssc-block-bus";
+
+		clocks = <&xo>, // TODO: use <&rpmcc RPM_SMD_XO_CLK_SRC>
+			 <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+			 <&gcc GCC_IM_SLEEP>,
+			 <&gcc AGGRE2_SNOC_NORTH_AXI>,
+			 <&gcc SSC_XO>,
+			 <&gcc SSC_CNOC_AHBS_CLK>;
+		clock-names = "xo", "aggre2", "gcc_im_sleep", "aggre2_north", "ssc_xo", "ssc_ahbs";
+
+		resets = <&gcc GCC_SSC_RESET>, <&gcc GCC_SSC_BCR>;
+		reset-names = "ssc_reset", "ssc_bcr";
+
+		power-domains = <&rpmpd MSM8998_SSCCX>, <&rpmpd MSM8998_SSCMX>;
+		power-domain-names = "ssc_cx", "ssc_mx";
+
+		ssc_tlmm: pinctrl@5e10000 {
+			compatible = "qcom,msm8998-ssc-tlmm-pinctrl";
+			reg = <0x5E10000 0x10000>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&ssc_tlmm 0 0 20>;
+
+/* TODO: are these actually needed (try turning them off)
+			assigned-clocks = <&scc AHB_TIMEOUT_CLK>, <&scc CFG_AHB_CLK>;
+			assigned-clock-parents = <&scc SCC_100M_CLK_SRC>, <&scc SCC_100M_CLK_SRC>;*/
+		};
+/*
+		scc: clock-controller@5e20000 {
+			compatible = "qcom,msm8998-scc";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			#power-domain-cells = <1>;
+			reg = <0x5e20000 0x10000>;
+
+			assigned-clocks = <&scc SCC_PLL>, <&scc SCC_PLL_OUT_EVEN>;
+			assigned-clock-rates = <600000000>, <300000000>;
+
+			clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; // and sleep clock, but dunno how this is supposed to be represented
+			clock-names = "xo";
+		};
+*/
+	};
+
+	sensor-i2c {
+		compatible = "i2c-gpio";
+		sda-gpios = <&ssc_tlmm 2 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+		scl-gpios = <&ssc_tlmm 3 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		imu@68 {
+			compatible = "invensense,icm20608";
+			reg = <0x68>;
+			interrupt-parent = <&tlmm>;
+			interrupts = <118 IRQ_TYPE_LEVEL_HIGH>;
+
+			mount-matrix =  "0", "1", "0",
+						   "-1", "0", "0",
+						    "0", "0", "1";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
index af67c641df4e..50b853a42a76 100644
--- a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi
@@ -174,6 +174,12 @@ pm8998-regulators {
 		vdd_l26-supply = <&vreg_s3a_1p35>;
 		vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
 
+		/*
+		vreg_s1a_0p348: s1 { // <&rpmpd MSM8998_VDDCX>
+			regulator-min-microvolt = <348000>;
+			regulator-max-microvolt = <348000>;
+		};
+		*/
 		vreg_s3a_1p35: s3 {
 			regulator-min-microvolt = <1352000>;
 			regulator-max-microvolt = <1352000>;
@@ -191,6 +197,18 @@ vreg_s7a_1p025: s7 {
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <1028000>;
 		};
+		/*
+		vreg_s8a_0p348: s8 { // vdda_ebi - no rpmpd constant
+			regulator-min-microvolt = <348000>;
+			regulator-max-microvolt = <348000>;
+		};
+		*/
+		/*
+		vreg_s9a_0p488: s9 { // <&rpmpd MSM8998_VDDMX>
+			regulator-min-microvolt = <488000>;
+			regulator-max-microvolt = <488000>;
+		};
+		*/
 		vreg_l1a_0p875: l1 {
 			regulator-min-microvolt = <880000>;
 			regulator-max-microvolt = <880000>;
@@ -203,6 +221,14 @@ vreg_l3a_1p0: l3 {
 			regulator-min-microvolt = <1000000>;
 			regulator-max-microvolt = <1000000>;
 		};
+		/*
+		vreg_l4a_0p488: l4 { // <&rpmpd MSM8998_SSCMX>
+			regulator-min-microvolt = <488000>;
+			regulator-max-microvolt = <488000>;
+
+			regulator-always-on; //RMME
+		};*/
+
 		vreg_l5a_0p8: l5 {
 			regulator-min-microvolt = <800000>;
 			regulator-max-microvolt = <800000>;
@@ -295,19 +321,29 @@ vreg_l26a_1p2: l26 {
 			regulator-max-microvolt = <1200000>;
 			regulator-allow-set-load;
 		};
+		/*
+		vreg_l27a_0p352: l27 { // <&rpmpd MSM8998_SSCCX>
+			regulator-min-microvolt = <352000>;
+			regulator-max-microvolt = <352000>;
+
+			regulator-always-on; //RMME
+		};
+		*/
 		vreg_l28_3p0: l28 {
 			regulator-min-microvolt = <3008000>;
 			regulator-max-microvolt = <3008000>;
 		};
 
 		vreg_lvs1a_1p8: lvs1 {
-			regulator-min-microvolt = <1800000>;
+			regulator-min-microvolt = <1800000>;	
 			regulator-max-microvolt = <1800000>;
 		};
 
 		vreg_lvs2a_1p8: lvs2 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
+
+			regulator-always-on; //RMME
 		};
 
 	};
@@ -332,9 +368,9 @@ &remoteproc_mss {
 	status = "okay";
 };
 
-&remoteproc_slpi {
+/*&remoteproc_slpi {
 	status = "okay";
-};
+};*/
 
 &tlmm {
 	gpio-reserved-ranges = <0 4>, <81 4>;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 3c68e174a113..f2b2e3098491 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -173,6 +173,12 @@ config SUNXI_RSB
 	  with various RSB based devices, such as AXP223, AXP8XX PMICs,
 	  and AC100/AC200 ICs.
 
+config QCOM_SSC_BLOCK_BUS
+	bool "Qualcomm SSC Block Bus Init Driver"
+	  help
+	  Say y here to enable support for initializing the bus that connects the SSC block's internal
+	  bus to the cNoC on (some) qcom SoCs
+
 config TEGRA_ACONNECT
 	tristate "Tegra ACONNECT Bus Driver"
 	depends on ARCH_TEGRA_210_SOC
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 52c2f35a26a9..e6756e83a9c4 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT)	+= omap_l3_smx.o omap_l3_noc.o
 
 obj-$(CONFIG_OMAP_OCP2SCP)	+= omap-ocp2scp.o
 obj-$(CONFIG_QCOM_EBI2)		+= qcom-ebi2.o
+obj-$(CONFIG_QCOM_SSC_BLOCK_BUS)	+= qcom-ssc-block-bus.o
 obj-$(CONFIG_SUN50I_DE2_BUS)	+= sun50i-de2.o
 obj-$(CONFIG_SUNXI_RSB)		+= sunxi-rsb.o
 obj-$(CONFIG_OF)		+= simple-pm-bus.o
diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c
new file mode 100644
index 000000000000..d1f8515bc7d7
--- /dev/null
+++ b/drivers/bus/qcom-ssc-block-bus.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2021, Michael Srba
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+static const char *qcom_ssc_block_pd_names[] = {
+	"ssc_cx",
+	"ssc_mx"
+};
+
+struct qcom_ssc_block_bus_data {
+	int num_pds;
+	const char **pd_names;
+	struct device *pds[ARRAY_SIZE(qcom_ssc_block_pd_names)];
+	char __iomem *reg_mpm_sscaon_config0; // MPM - msm power manager; AON - always-on
+	char __iomem *reg_mpm_sscaon_config1; // that's as much as we know about these
+	char __iomem *reg_ssc_axi_haltreq;
+	struct clk *xo_clk;
+	struct clk *aggre2_clk;
+	struct clk *gcc_im_sleep_clk;
+	struct clk *aggre2_north_clk;
+	struct clk *ssc_xo_clk;
+	struct clk *ssc_ahbs_clk;
+	struct reset_control *ssc_bcr;
+	struct reset_control *ssc_reset;
+};
+
+static void reg32_set_bits(char __iomem *reg, u32 value)
+{
+	u32 tmp = ioread32(reg);
+	iowrite32(tmp | value, reg);
+}
+
+static void reg32_unset_bits(char __iomem *reg, u32 value)
+{
+	u32 tmp = ioread32(reg);
+	iowrite32(tmp & (~value), reg);
+}
+
+
+static int qcom_ssc_block_bus_FIXME(struct device *dev)
+{
+	int ret;
+
+	struct qcom_ssc_block_bus_data *data = dev_get_drvdata(dev);
+
+	clk_prepare_enable(data->xo_clk);
+	clk_prepare_enable(data->aggre2_clk);
+
+	clk_prepare_enable(data->gcc_im_sleep_clk);
+
+	reg32_unset_bits(data->reg_mpm_sscaon_config0, BIT(4) | BIT(5)); // the meaning of these bits is not documented
+	reg32_unset_bits(data->reg_mpm_sscaon_config1, BIT(31)); // the meaning of this bit is not documented
+
+	clk_disable(data->aggre2_north_clk);
+
+	ret = reset_control_deassert(data->ssc_reset);
+	if(ret) {
+		dev_err(dev, "error deasserting ssc_reset: %d\n", ret);
+		return ret;
+	}
+
+	clk_prepare_enable(data->aggre2_north_clk);
+
+	ret = reset_control_deassert(data->ssc_bcr);
+	if(ret) {
+		dev_err(dev, "error deasserting ssc_bcr: %d\n", ret);
+		return ret;
+	}
+
+	reg32_unset_bits(data->reg_ssc_axi_haltreq, BIT(0));
+
+	clk_prepare_enable(data->ssc_xo_clk);
+
+	clk_prepare_enable(data->ssc_ahbs_clk);
+
+	return 0;
+}
+
+static int qcom_ssc_block_bus_pds_attach(struct device *dev, struct device **pds, const char **pd_names,
+										 size_t num_pds)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < num_pds; i++) {
+		pds[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
+		if (IS_ERR_OR_NULL(pds[i])) {
+			ret = PTR_ERR(pds[i]) ? : -ENODATA;
+			goto unroll_attach;
+		}
+	}
+
+	return num_pds;
+
+unroll_attach:
+	for (i--; i >= 0; i--)
+		dev_pm_domain_detach(pds[i], false);
+
+	return ret;
+};
+
+static void qcom_ssc_block_bus_pds_detach(struct device *dev, struct device **pds, size_t num_pds)
+{
+	int i;
+
+	for (i = 0; i < num_pds; i++)
+		dev_pm_domain_detach(pds[i], false);
+}
+
+static int qcom_ssc_block_bus_pds_enable(struct device **pds, size_t num_pds)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < num_pds; i++) {
+		dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
+		ret = pm_runtime_get_sync(pds[i]);
+		if (ret < 0)
+			goto unroll_pd_votes;
+	}
+
+	return 0;
+
+unroll_pd_votes:
+	for (i--; i >= 0; i--) {
+		dev_pm_genpd_set_performance_state(pds[i], 0);
+		pm_runtime_put(pds[i]);
+	}
+
+	return ret;
+};
+
+static void qcom_ssc_block_bus_pds_disable(struct device **pds, size_t num_pds)
+{
+	int i;
+
+	for (i = 0; i < num_pds; i++) {
+		dev_pm_genpd_set_performance_state(pds[i], 0);
+		pm_runtime_put(pds[i]);
+	}
+}
+
+/* * * * * * * * * * * *
+ *                     *
+ *     ENTRY POINT     *
+ *                     *
+ * * * * * * * * * * * */
+
+static int qcom_ssc_block_bus_probe(struct platform_device *pdev)
+{
+	struct qcom_ssc_block_bus_data *data;
+
+	struct device_node *np = pdev->dev.of_node;
+
+	if (np)
+		of_platform_populate(np, NULL, NULL, &pdev->dev);
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	platform_set_drvdata(pdev, data);
+
+	data->pd_names = qcom_ssc_block_pd_names;
+	data->num_pds = ARRAY_SIZE(qcom_ssc_block_pd_names);
+
+	qcom_ssc_block_bus_pds_attach(&pdev->dev, data->pds, data->pd_names, data->num_pds);
+	qcom_ssc_block_bus_pds_enable(data->pds, data->num_pds);
+
+	data->reg_mpm_sscaon_config0 = ioremap(0x10AC008, 4);
+	data->reg_mpm_sscaon_config1 = ioremap(0x10AC010, 4);
+	data->reg_ssc_axi_haltreq = ioremap(0x1F66000, 4);
+
+	data->ssc_bcr = devm_reset_control_get_exclusive(&pdev->dev, "ssc_bcr");
+	data->ssc_reset = devm_reset_control_get_exclusive(&pdev->dev, "ssc_reset");
+
+	data->xo_clk = devm_clk_get(&pdev->dev, "xo");
+	data->aggre2_clk = devm_clk_get(&pdev->dev, "aggre2");
+	data->gcc_im_sleep_clk = devm_clk_get(&pdev->dev, "gcc_im_sleep");
+	data->aggre2_north_clk = devm_clk_get(&pdev->dev, "aggre2_north");
+	data->ssc_xo_clk = devm_clk_get(&pdev->dev, "ssc_xo");
+	data->ssc_ahbs_clk = devm_clk_get(&pdev->dev, "ssc_ahbs");
+
+	qcom_ssc_block_bus_FIXME(&pdev->dev);
+
+	return 0;
+}
+
+static int qcom_ssc_block_bus_remove(struct platform_device *pdev)
+{
+	struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev);
+
+	iounmap(data->reg_mpm_sscaon_config0);
+	iounmap(data->reg_mpm_sscaon_config1);
+	iounmap(data->reg_ssc_axi_haltreq);
+
+	qcom_ssc_block_bus_pds_disable(data->pds, data->num_pds);
+	qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds);
+	pm_runtime_disable(&pdev->dev);
+	pm_clk_destroy(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id qcom_ssc_block_bus_of_match[] = {
+	{ .compatible = "qcom,ssc-block-bus", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match);
+
+static struct platform_driver qcom_ssc_block_bus_driver = {
+	.probe = qcom_ssc_block_bus_probe,
+	.remove = qcom_ssc_block_bus_remove,
+	.driver = {
+		.name = "qcom-ssc-block-bus",
+		.of_match_table = qcom_ssc_block_bus_of_match,
+	},
+};
+
+module_platform_driver(qcom_ssc_block_bus_driver);
+
+MODULE_DESCRIPTION("A driver for handling the init sequence needed for accesing the SSC block on (some) qcom SoCs over AHB");
+MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/scc-msm8998.c b/drivers/clk/qcom/scc-msm8998.c
new file mode 100644
index 000000000000..b98c810fbc00
--- /dev/null
+++ b/drivers/clk/qcom/scc-msm8998.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Michael Srba
+ */
+
+#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-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,scc-msm8998.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+
+enum {
+	P_SCC_PLL_OUT_EVEN,
+};
+
+static const struct clk_div_table post_div_table_fabia_even[] = {
+	{ 0x0, 1 },
+	{ 0x1, 2 },
+	{ 0x3, 4 },
+	{ 0x7, 8 },
+	{ }
+};
+
+static struct pll_vco fabia_vco[] = { // TODO there is actually no VCO control on fabia afaict, so test if this can be absent
+	{ 600000000, 600000000, 0 },
+};
+
+static struct clk_alpha_pll scc_pll = { //PLL is not part of the name, unlike elsewhere (e.g GPU_PLL0_PLL); the name is just "SCC" (sensor clock controller?)
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+	.vco_table = fabia_vco,
+	.num_vco = ARRAY_SIZE(fabia_vco),
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "scc_pll",
+		.parent_data = &(const struct clk_parent_data){
+			.fw_name = "sleep_clk",
+			.name = "sleep_clk"
+		},
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_fabia_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv scc_pll_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 8,
+	.post_div_table = post_div_table_fabia_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "scc_pll_out_even",
+		.parent_hws = (const struct clk_hw *[]){ &scc_pll.clkr.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_alpha_pll_postdiv_fabia_ops,
+	},
+};
+
+static const struct parent_map scc_pll_out_even_map[] = {
+	{ P_SCC_PLL_OUT_EVEN, 2 },
+};
+
+static const struct freq_tbl ftbl_scc_100m_clk_src[] = {
+	F(100000000, P_SCC_PLL_OUT_EVEN, 3, 0, 0), // 300 MHz / 3 = 100 MHz
+	{ }
+};
+
+static struct clk_rcg2 scc_100m_clk_src = {
+	.cmd_rcgr = 0x1000,
+	.hid_width = 5,
+	.parent_map = scc_pll_out_even_map,
+	.freq_tbl = ftbl_scc_100m_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "scc_100m_clk_src",
+		.parent_hws = (const struct clk_hw *[]){ &scc_pll_out_even.clkr.hw },
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch qup_spi1_clk = {
+	.halt_reg = 0x2008,
+	.clkr = {
+		.enable_reg = 0x2008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_spi1_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch qup_i2c1_clk = {
+	.halt_reg = 0x200c,
+	.clkr = {
+		.enable_reg = 0x200c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_i2c1_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch qup_spi2_clk = {
+	.halt_reg = 0x3008,
+	.clkr = {
+		.enable_reg = 0x3008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_spi2_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch qup_i2c2_clk = {
+	.halt_reg = 0x300c,
+	.clkr = {
+		.enable_reg = 0x300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_i2c2_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch qup_spi3_clk = {
+	.halt_reg = 0x4008,
+	.clkr = {
+		.enable_reg = 0x4008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_spi3_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch qup_i2c3_clk = {
+	.halt_reg = 0x400c,
+	.clkr = {
+		.enable_reg = 0x400c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "qup_i2c3_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch crif_clk = {
+	.halt_reg = 0x9008,
+	.clkr = {
+		.enable_reg = 0x9008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "crif_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch csr_h_clk = {
+	.halt_reg = 0x900c,
+	.clkr = {
+		.enable_reg = 0x900c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "csr_h_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch data_h_clk = {
+	.halt_reg = 0x9010,
+	.clkr = {
+		.enable_reg = 0x9010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "data_h_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch cfg_ahb_clk = {
+	.halt_reg = 0x9014,
+	.clkr = {
+		.enable_reg = 0x9014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "cfg_ahb_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+static struct clk_branch ahb_timeout_clk = {
+	.halt_reg = 0x9038,
+	.clkr = {
+		.enable_reg = 0x9038,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "ahb_timeout_clk",
+			.parent_hws = (const struct clk_hw *[]){ &scc_100m_clk_src.clkr.hw },
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+			.flags = CLK_SET_RATE_PARENT,
+		},
+	},
+};
+
+static struct clk_regmap *scc_msm8998_clocks[] = {
+	[SCC_PLL] = &scc_pll.clkr,
+	[SCC_PLL_OUT_EVEN] = &scc_pll_out_even.clkr,
+
+	[SCC_100M_CLK_SRC] = &scc_100m_clk_src.clkr,
+
+	[AHB_TIMEOUT_CLK] = &ahb_timeout_clk.clkr,
+	[CFG_AHB_CLK] = &cfg_ahb_clk.clkr,
+	[CRIF_CLK] = &crif_clk.clkr,
+	[CSR_H_CLK] = &csr_h_clk.clkr,
+	[DATA_H_CLK] = &data_h_clk.clkr,
+	[QUP_I2C1_CLK] = &qup_i2c1_clk.clkr,
+	[QUP_I2C2_CLK] = &qup_i2c2_clk.clkr,
+	[QUP_I2C3_CLK] = &qup_i2c3_clk.clkr,
+	[QUP_SPI1_CLK] = &qup_spi1_clk.clkr,
+	[QUP_SPI2_CLK] = &qup_spi2_clk.clkr,
+	[QUP_SPI3_CLK] = &qup_spi3_clk.clkr,
+};
+
+static const struct qcom_reset_map scc_msm8998_resets[] = {
+	[SPI_I2C1_BCR] = { 0x2000 },
+	[SPI_I2C2_BCR] = { 0x3000 },
+	[SPI_I2C3_BCR] = { 0x4000 },
+	[BUS_BCR] = { 0x9000 },
+	[BLSP_BCR] = { 0x9018 },
+	[AHB_TIMEOUT_BCR] = { 0x9034 },
+};
+
+static const struct regmap_config scc_msm8998_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0xD000,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc scc_msm8998_desc = {
+	.config = &scc_msm8998_regmap_config,
+	.clks = scc_msm8998_clocks,
+	.num_clks = ARRAY_SIZE(scc_msm8998_clocks),
+	.resets = scc_msm8998_resets,
+	.num_resets = ARRAY_SIZE(scc_msm8998_resets),
+};
+
+static const struct of_device_id scc_msm8998_match_table[] = {
+	{ .compatible = "qcom,msm8998-scc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, scc_msm8998_match_table);
+
+static int scc_msm8998_probe(struct platform_device *pdev)
+{
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &scc_msm8998_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return qcom_cc_really_probe(pdev, &scc_msm8998_desc, regmap);
+}
+
+static struct platform_driver scc_msm8998_driver = {
+	.probe		= scc_msm8998_probe,
+	.driver		= {
+		.name	= "scc-msm8998",
+		.of_match_table = scc_msm8998_match_table,
+	},
+};
+module_platform_driver(scc_msm8998_driver);
+
+MODULE_DESCRIPTION("QCOM SCC MSM8998 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index c6aa36ee966a..86a9b4a63e8e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -393,7 +393,7 @@ struct inv_mpu6050_state {
 #define INV_MPU9250_WHOAMI_VALUE		0x71
 #define INV_MPU9255_WHOAMI_VALUE		0x73
 #define INV_MPU6515_WHOAMI_VALUE		0x74
-#define INV_ICM20608_WHOAMI_VALUE		0xAF
+#define INV_ICM20608_WHOAMI_VALUE		0xAE
 #define INV_ICM20609_WHOAMI_VALUE		0xA6
 #define INV_ICM20689_WHOAMI_VALUE		0x98
 #define INV_ICM20602_WHOAMI_VALUE		0x12
diff --git a/include/dt-bindings/clock/qcom,scc-msm8998.h b/include/dt-bindings/clock/qcom,scc-msm8998.h
new file mode 100644
index 000000000000..5a5575799c63
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,scc-msm8998.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021, Michael Srba
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_SCC_8998_H
+#define _DT_BINDINGS_CLK_MSM_SCC_8998_H
+
+#define SCC_PLL						0
+#define SCC_PLL_OUT_EVEN				1
+#define SCC_100M_CLK_SRC				2
+#define AHB_TIMEOUT_CLK					3
+#define CFG_AHB_CLK					4
+#define CRIF_CLK					5
+#define CSR_H_CLK					6
+#define DATA_H_CLK					7
+#define QUP_I2C1_CLK					8
+#define QUP_I2C2_CLK					9
+#define QUP_I2C3_CLK					10
+#define QUP_SPI1_CLK					11
+#define QUP_SPI2_CLK					12
+#define QUP_SPI3_CLK					13
+
+#define SPI_I2C1_BCR					0
+#define SPI_I2C2_BCR					1
+#define SPI_I2C3_BCR					2
+#define UART1_BCR					3
+#define BUS_BCR						4
+#define BLSP_BCR					5
+#define AHB_TIMEOUT_BCR					6
+
+#endif
-- 
2.34.1

