linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
@ 2018-04-07 13:59 Craig Tatlor
  2018-04-07 13:59 ` [PATCH v3 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
                   ` (7 more replies)
  0 siblings, 8 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 13:59 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

This patch adds a driver for the BMS (Battery Monitoring System)
block of the PM8941 PMIC, it uses a lookup table defined in the
device tree to generate a capacity from the BMS supplied OCV, it
then ammends the coulomb counter to that to increase the accuracy
of the estimated capacity.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 drivers/power/supply/Kconfig    |   9 +
 drivers/power/supply/Makefile   |   1 +
 drivers/power/supply/qcom_bms.c | 500 ++++++++++++++++++++++++++++++++
 3 files changed, 510 insertions(+)
 create mode 100644 drivers/power/supply/qcom_bms.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 428b426842f4..6c354c37bc55 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -82,6 +82,15 @@ config BATTERY_ACT8945A
 	  Say Y here to enable support for power supply provided by
 	  Active-semi ActivePath ACT8945A charger.
 
+config BATTERY_BMS
+	tristate "Qualcomm Battery Monitoring System driver"
+	depends on MFD_SPMI_PMIC || COMPILE_TEST
+	depends on OF
+	depends on REGMAP_SPMI
+	help
+	  Say Y to include support for the Battery Monitoring hardware
+	  found in some Qualcomm PM series PMICs.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index e83aa843bcc6..04204174b047 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
+obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
 obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
new file mode 100644
index 000000000000..5aa6e906d1b9
--- /dev/null
+++ b/drivers/power/supply/qcom_bms.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL
+
+/*
+ * Qualcomm Battery Monitoring System driver
+ *
+ * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/iio/consumer.h>
+
+#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
+#define REG_BMS_SHDW_CC_DATA0		0xA8
+#define REG_BMS_CC_DATA_CTL		0x42
+#define REG_BMS_CC_CLEAR_CTL		0x4
+
+#define BMS_HOLD_OREG_DATA		BIT(0)
+#define BMS_CLEAR_SHDW_CC		BIT(6)
+
+#define CC_36_BIT_MASK			0xFFFFFFFFFLL
+#define SIGN_EXTEND_36_TO_64_MASK	(-1LL ^ CC_36_BIT_MASK)
+
+#define BMS_CC_READING_RESOLUTION_N	542535
+#define BMS_CC_READING_RESOLUTION_D	10000
+#define BMS_CC_READING_TICKS		56
+#define BMS_SLEEP_CLK_HZ		32764
+
+#define SECONDS_PER_HOUR		3600
+#define TEMPERATURE_COLS		5
+#define MAX_CAPACITY_ROWS		50
+
+/* lookup table for ocv -> capacity conversion */
+struct bms_ocv_lut {
+	int rows;
+	s8 temp_legend[TEMPERATURE_COLS];
+	u8 capacity_legend[MAX_CAPACITY_ROWS];
+	u16 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
+};
+
+/* lookup table for battery temperature -> fcc conversion */
+struct bms_fcc_lut {
+	s8 temp_legend[TEMPERATURE_COLS];
+	u16 lut[TEMPERATURE_COLS];
+};
+
+struct bms_device_info {
+	struct device *dev;
+	struct regmap *regmap;
+	struct power_supply *bat;
+	struct power_supply_desc bat_desc;
+	struct bms_ocv_lut ocv_lut;
+	struct bms_fcc_lut fcc_lut;
+	struct iio_channel *adc;
+	spinlock_t bms_output_lock;
+	int base_addr;
+
+	int ocv_thr_irq;
+	int ocv;
+};
+
+static s64 sign_extend_s36(uint64_t raw)
+{
+	raw = raw & CC_36_BIT_MASK;
+
+	return (raw >> 35) == 0LL ?
+		raw : (SIGN_EXTEND_36_TO_64_MASK | raw);
+}
+
+static unsigned int interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+static unsigned int between(int left, int right, int val)
+{
+	if (left <= val && val >= right)
+		return 1;
+
+	return 0;
+}
+
+static unsigned int interpolate_capacity(int temp, u16 ocv,
+				struct bms_ocv_lut ocv_lut)
+{
+	unsigned int pcj_minus_one = 0, pcj = 0;
+	int i, j;
+
+	for (j = 0; j < TEMPERATURE_COLS; j++)
+		if (temp <= ocv_lut.temp_legend[j])
+			break;
+
+	if (ocv >= ocv_lut.lut[0][j])
+		return ocv_lut.capacity_legend[0];
+
+	if (ocv <= ocv_lut.lut[ocv_lut.rows - 1][j - 1])
+		return ocv_lut.capacity_legend[ocv_lut.rows - 1];
+
+	for (i = 0; i < ocv_lut.rows - 1; i++) {
+		if (pcj == 0 && between(ocv_lut.lut[i][j],
+					ocv_lut.lut[i+1][j], ocv))
+			pcj = interpolate(ocv_lut.capacity_legend[i],
+					  ocv_lut.lut[i][j],
+					  ocv_lut.capacity_legend[i + 1],
+					  ocv_lut.lut[i+1][j],
+					  ocv);
+
+		if (pcj_minus_one == 0 && between(ocv_lut.lut[i][j-1],
+						  ocv_lut.lut[i+1][j-1], ocv))
+			pcj_minus_one = interpolate(ocv_lut.capacity_legend[i],
+						    ocv_lut.lut[i][j-1],
+						    ocv_lut.capacity_legend[i + 1],
+						    ocv_lut.lut[i+1][j-1],
+						    ocv);
+
+		if (pcj && pcj_minus_one)
+			return interpolate(pcj_minus_one,
+					   ocv_lut.temp_legend[j-1],
+					   pcj,
+					   ocv_lut.temp_legend[j],
+					   temp);
+	}
+
+	if (pcj)
+		return pcj;
+
+	if (pcj_minus_one)
+		return pcj_minus_one;
+
+	return 100;
+}
+
+static unsigned long interpolate_fcc(int temp, struct bms_fcc_lut fcc_lut)
+{
+	int i, fcc_mv;
+
+	for (i = 0; i < TEMPERATURE_COLS; i++)
+		if (temp <= fcc_lut.temp_legend[i])
+			break;
+
+	fcc_mv = interpolate(fcc_lut.lut[i - 1],
+			     fcc_lut.temp_legend[i - 1],
+			     fcc_lut.lut[i],
+			     fcc_lut.temp_legend[i],
+			     temp);
+
+	return fcc_mv * 10000;
+}
+
+static int bms_lock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to lock bms output: %d", ret);
+		return ret;
+	}
+
+	/*
+	 * Sleep for 100 microseconds here to make sure there has
+	 * been at least three cycles of the sleep clock so that 
+	 * the registers are correctly locked.
+	 */
+	udelay(100);
+
+	return 0;
+}
+
+static int bms_unlock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, 0);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to unlock bms output: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bms_read_ocv(struct bms_device_info *di, int *ocv)
+{
+	unsigned long flags;
+	int ret;
+	u16 read_ocv;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = bms_lock_output_data(di);
+	if (ret < 0)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
+	if (ret < 0) {
+		dev_err(di->dev, "OCV read failed: %d", ret);
+		return ret;
+	}
+
+	dev_dbg(di->dev, "read OCV value of: %d", read_ocv);
+	*ocv = read_ocv;
+
+	ret = bms_unlock_output_data(di);
+
+err_lock:
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+
+	return ret;
+}
+
+static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
+{
+	unsigned long flags;
+	int ret;
+	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = bms_lock_output_data(di);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_SHDW_CC_DATA0,
+			       &cc_raw_s36, 5);
+	if (ret < 0) {
+		dev_err(di->dev, "coulomb counter read failed: %d", ret);
+		return ret;
+	}
+
+	ret = bms_unlock_output_data(di);
+	if (ret < 0)
+		return ret;
+
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+
+	cc_raw = sign_extend_s36(cc_raw_s36);
+
+	/* convert raw to uv */
+	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
+			BMS_CC_READING_RESOLUTION_D);
+
+	/* convert uv to pvh */
+	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
+			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR) * 10;
+
+	/* divide by impedance */
+	*cc_uah = div_s64(cc_pvh, 10000);
+
+	dev_dbg(di->dev, "read coulomb counter value of: %lld", *cc_uah);
+
+	return 0;
+}
+
+static void bms_reset_cc(struct bms_device_info *di)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC,
+				 BMS_CLEAR_SHDW_CC);
+	if (ret < 0) {
+		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
+		goto err_lock;
+	}
+
+	/* wait two sleep cycles for cc to reset */
+	udelay(100);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC, 0);
+	if (ret < 0)
+		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
+
+err_lock:
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+}
+
+static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
+{
+	unsigned long ocv_capacity, fcc;
+	int ret, temp, temp_degc;
+	s64 cc, capacity_nodiv;
+
+	ret = iio_read_channel_raw(di->adc, &temp);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read temperature: %d", ret);
+		return ret;
+	}
+
+	temp_degc = (temp + 500) / 1000;
+
+	ret = bms_read_cc(di, &cc);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
+		return ret;
+	}
+
+	ocv_capacity = interpolate_capacity(temp_degc, (di->ocv + 5) / 10,
+					    di->ocv_lut);
+	fcc = interpolate_fcc(temp_degc, di->fcc_lut);
+
+	capacity_nodiv = ((fcc * ocv_capacity) / 100 - cc) * 100;
+	*capacity = div64_ul(capacity_nodiv, fcc);
+
+	return 0;
+}
+
+
+
+/*
+ * Return power_supply property
+ */
+static int bms_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct bms_device_info *di = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = bms_calculate_capacity(di, &val->intval);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (val->intval == INT_MAX || val->intval == INT_MIN)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static enum power_supply_property bms_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
+{
+	struct bms_device_info *di = dev_id;
+
+	if (bms_read_ocv(di, &di->ocv) < 0)
+		return IRQ_HANDLED;
+
+	bms_reset_cc(di);
+	return IRQ_HANDLED;
+}
+
+static int bms_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct bms_device_info *di;
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, di);
+
+	di->dev = &pdev->dev;
+
+	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!di->regmap) {
+		dev_err(di->dev, "Unable to get regmap");
+		return -EINVAL;
+	}
+
+	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
+	if (IS_ERR(di->adc))
+		return PTR_ERR(di->adc);
+
+	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,ocv-temp-legend",
+						 (u8 *)di->ocv_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no ocv temperature legend found");
+		return ret;
+	}
+
+	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
+						 "qcom,ocv-capacity-legend",
+						 di->ocv_lut.capacity_legend, 0,
+						 MAX_CAPACITY_ROWS);
+	if (di->ocv_lut.rows < 0) {
+		dev_err(di->dev, "no ocv capacity legend found");
+		return ret;
+	}
+
+	ret = of_property_read_variable_u16_array(di->dev->of_node,
+						  "qcom,ocv-lut",
+						  (u16 *)di->ocv_lut.lut,
+						  TEMPERATURE_COLS,
+						  TEMPERATURE_COLS *
+						  MAX_CAPACITY_ROWS);
+	if (ret < 0) {
+		dev_err(di->dev, "no ocv lut array found");
+		return ret;
+	}
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,fcc-temp-legend",
+						 (u8 *)di->fcc_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no fcc temperature legend found");
+		return ret;
+	}
+
+	ret = of_property_read_u16_array(di->dev->of_node,
+						  "qcom,fcc-lut",
+						  di->fcc_lut.lut,
+						  TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no fcc lut array found");
+		return ret;
+	}
+
+	ret = bms_read_ocv(di, &di->ocv);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read initial ocv: %d", ret);
+		return ret;
+	}
+
+	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
+
+	ret = devm_request_irq(di->dev, di->ocv_thr_irq,
+					bms_ocv_thr_irq_handler,
+					IRQF_TRIGGER_RISING,
+					pdev->name, di);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to request handler for ocv threshold IRQ");
+		return ret;
+	}
+
+	spin_lock_init(&di->bms_output_lock);
+
+	di->bat_desc.name = "bms";
+	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat_desc.properties = bms_props;
+	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
+	di->bat_desc.get_property = bms_get_property;
+
+	psy_cfg.drv_data = di;
+	di->bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
+	if (IS_ERR(di->bat))
+		return PTR_ERR(di->bat);
+
+	return 0;
+}
+
+static const struct of_device_id bms_of_match[] = {
+	{.compatible = "qcom,pm8941-bms", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bms_of_match);
+
+static struct platform_driver bms_driver = {
+	.probe = bms_probe,
+	.driver = {
+		.name = "qcom-bms",
+		.of_match_table = of_match_ptr(bms_of_match),
+	},
+};
+module_platform_driver(bms_driver);
+
+MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm BMS driver");
+MODULE_LICENSE("GPL");
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v3 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-04-07 13:59 ` Craig Tatlor
  2018-04-07 13:59 ` [PATCH v3 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 13:59 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Add bindings for the Qualcomm Battery Monitoring system.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 .../bindings/power/supply/qcom_bms.txt        | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt

diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
new file mode 100644
index 000000000000..6296399edc09
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
@@ -0,0 +1,93 @@
+Qualcomm Battery Measurement System
+
+The Qualcomm Battery Measurement System is found inside of Qualcomm PM8941
+PMICs. It provides OCV and coulomb counter registers that allow the kernel
+to infer a capacity level.
+
+Required properties:
+- compatible:               Should contain "qcom,pm8941-bms".
+- reg:                      Specifies the SPMI address and length of the
+			    controller's registers.
+- interrupts:               OCV threshold interrupt.
+- io-channels:              Should contain IIO channel specifier for the
+			    ADC channel that reports battery temperature.
+- io-channel-names:         Should contain "temp".
+- qcom,fcc-temp-legend:     An array containing the temperature, in degC,
+			    for each column of the FCC lookup table.
+- qcom,fcc-lut:             An array of FCC values in mah, one entry for each
+			    temperature defined in in qcom,fcc-temp-legend.
+- qcom,ocv-temp-legend:     An array containing the temperature, in degC,
+			    for each column of the OCV lookup table.
+- qcom,ocv-capacity-legend: An array containing the capacity for each
+			    row of the OCV lookup table.
+- qcom,ocv-lut:             An array of OCV values in mV, one entry for each
+			    capacity defined in qcom,ocv-capacity-legend.
+
+Example:
+
+		pm8941_vadc: vadc@3100 {
+			compatible = "qcom,spmi-vadc";
+			reg = <0x3100>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+
+			bat_temp {
+				reg = <VADC_LR_MUX1_BAT_THERM>;
+			};
+		};
+
+		bms@4000 {
+			compatible = "qcom,pm8941-bms";
+			reg = <0x4000>;
+			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ocv_thr";
+
+			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
+			io-channel-names = "temp";
+
+			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
+
+			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
+							     80 75 70 65
+							     60 55 50 45
+							     40 35 30 25
+							     20 15 10 9
+							     8 7 6 5 4
+							     3 2 1 0>;
+
+			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
+						  4261 4241 4259 4266 4246
+						  4201 4181 4201 4207 4187
+						  4153 4133 4150 4155 4135
+						  4105 4085 4100 4104 4084
+						  4058 4038 4052 4058 4038
+						  4012 3992 4004 4014 3994
+						  3970 3950 3959 3971 3951
+						  3931 3911 3915 3927 3907
+						  3899 3879 3880 3884 3864
+						  3873 3853 3851 3853 3833
+						  3848 3828 3827 3829 3809
+						  3829 3809 3808 3809 3789
+						  3815 3795 3791 3791 3771
+						  3801 3781 3775 3772 3752
+						  3785 3765 3751 3746 3726
+						  3767 3747 3727 3719 3699
+						  3750 3730 3702 3692 3672
+						  3728 3708 3680 3672 3652
+						  3720 3700 3676 3665 3645
+						  3712 3692 3670 3660 3645
+						  3695 3675 3658 3648 3633
+						  3662 3647 3629 3620 3610
+						  3620 3605 3589 3580 3570
+						  3562 3552 3538 3529 3519
+						  3490 3480 3474 3470 3465
+						  3403 3398 3388 3380 3375
+						  3320 3300 3255 3221 3206
+						  3000 3000 3000 3000 3000>;
+		};
+	};
+};
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v3 3/3] MAINTAINERS: Add entry for the Qualcomm BMS
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
  2018-04-07 13:59 ` [PATCH v3 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-04-07 13:59 ` Craig Tatlor
  2018-04-07 16:37 ` [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Randy Dunlap
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 13:59 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0c3ad62c638c..aaf54b665f86 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11605,6 +11605,12 @@ W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
+QUALCOMM BATTERY MONITORING SYSTEM
+M:	Craig Tatlor <ctatlor97@gmail.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/qcom_bms.c
+
 QUALCOMM CAMERA SUBSYSTEM DRIVER
 M:	Todor Tomov <todor.tomov@linaro.org>
 L:	linux-media@vger.kernel.org
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
  2018-04-07 13:59 ` [PATCH v3 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
  2018-04-07 13:59 ` [PATCH v3 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
@ 2018-04-07 16:37 ` Randy Dunlap
  2018-04-07 17:40   ` Craig Tatlor
  2018-04-07 17:54   ` Craig Tatlor
  2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 60+ messages in thread
From: Randy Dunlap @ 2018-04-07 16:37 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, linux-pm, devicetree, linux-kernel

On 04/07/2018 06:59 AM, Craig Tatlor wrote:
> This patch adds a driver for the BMS (Battery Monitoring System)
> block of the PM8941 PMIC, it uses a lookup table defined in the
> device tree to generate a capacity from the BMS supplied OCV, it
> then ammends the coulomb counter to that to increase the accuracy
> of the estimated capacity.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
>  drivers/power/supply/Kconfig    |   9 +
>  drivers/power/supply/Makefile   |   1 +
>  drivers/power/supply/qcom_bms.c | 500 ++++++++++++++++++++++++++++++++
>  3 files changed, 510 insertions(+)
>  create mode 100644 drivers/power/supply/qcom_bms.c

> diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
> new file mode 100644
> index 000000000000..5aa6e906d1b9
> --- /dev/null
> +++ b/drivers/power/supply/qcom_bms.c
> @@ -0,0 +1,500 @@

Hi,

> +static unsigned int between(int left, int right, int val)
> +{
> +	if (left <= val && val >= right)

maybe double-check those if() conditions?
[or I need my morning coffee]

> +		return 1;
> +
> +	return 0;
> +}

thanks,
-- 
~Randy

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-07 16:37 ` [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Randy Dunlap
@ 2018-04-07 17:40   ` Craig Tatlor
  2018-04-07 17:54   ` Craig Tatlor
  1 sibling, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 17:40 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, linux-pm, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1281 bytes --]

On Sat, Apr 7, 2018 at 5:37 PM, Randy Dunlap <rdunlap@infradead.org> wrote:

> On 04/07/2018 06:59 AM, Craig Tatlor wrote:
> > This patch adds a driver for the BMS (Battery Monitoring System)
> > block of the PM8941 PMIC, it uses a lookup table defined in the
> > device tree to generate a capacity from the BMS supplied OCV, it
> > then ammends the coulomb counter to that to increase the accuracy
> > of the estimated capacity.
> >
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> > ---
> >  drivers/power/supply/Kconfig    |   9 +
> >  drivers/power/supply/Makefile   |   1 +
> >  drivers/power/supply/qcom_bms.c | 500 ++++++++++++++++++++++++++++++++
> >  3 files changed, 510 insertions(+)
> >  create mode 100644 drivers/power/supply/qcom_bms.c
>
> > diff --git a/drivers/power/supply/qcom_bms.c
> b/drivers/power/supply/qcom_bms.c
> > new file mode 100644
> > index 000000000000..5aa6e906d1b9
> > --- /dev/null
> > +++ b/drivers/power/supply/qcom_bms.c
> > @@ -0,0 +1,500 @@
>
> Hi,
>
> > +static unsigned int between(int left, int right, int val)
> > +{
> > +     if (left <= val && val >= right)
>
> maybe double-check those if() conditions?
> [or I need my morning coffee]
>
> > +             return 1;
> > +
> > +     return 0;
> > +}
>
> thanks,
> --
> ~Randy
>

[-- Attachment #2: Type: text/html, Size: 2042 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-07 16:37 ` [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Randy Dunlap
  2018-04-07 17:40   ` Craig Tatlor
@ 2018-04-07 17:54   ` Craig Tatlor
  1 sibling, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 17:54 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, linux-pm, devicetree, linux-kernel

On Sat, Apr 07, 2018 at 09:37:21AM -0700, Randy Dunlap wrote:
> On 04/07/2018 06:59 AM, Craig Tatlor wrote:
> > This patch adds a driver for the BMS (Battery Monitoring System)
> > block of the PM8941 PMIC, it uses a lookup table defined in the
> > device tree to generate a capacity from the BMS supplied OCV, it
> > then ammends the coulomb counter to that to increase the accuracy
> > of the estimated capacity.
> > 
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> > ---
> >  drivers/power/supply/Kconfig    |   9 +
> >  drivers/power/supply/Makefile   |   1 +
> >  drivers/power/supply/qcom_bms.c | 500 ++++++++++++++++++++++++++++++++
> >  3 files changed, 510 insertions(+)
> >  create mode 100644 drivers/power/supply/qcom_bms.c
> 
> > diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
> > new file mode 100644
> > index 000000000000..5aa6e906d1b9
> > --- /dev/null
> > +++ b/drivers/power/supply/qcom_bms.c
> > @@ -0,0 +1,500 @@
> 
> Hi,
Hey
> 
> > +static unsigned int between(int left, int right, int val)
> > +{
> > +	if (left <= val && val >= right)
> 
> maybe double-check those if() conditions?
> [or I need my morning coffee]
Yeah, they are wrong, will fix.
> 
> > +		return 1;
> > +
> > +	return 0;
> > +}
> 
> thanks,
> -- 
> ~Randy

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                   ` (2 preceding siblings ...)
  2018-04-07 16:37 ` [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Randy Dunlap
@ 2018-04-07 17:57 ` Craig Tatlor
  2018-04-07 17:57   ` [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
                     ` (2 more replies)
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
                   ` (3 subsequent siblings)
  7 siblings, 3 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 17:57 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

This patch adds a driver for the BMS (Battery Monitoring System)
block of the PM8941 PMIC, it uses a lookup table defined in the
device tree to generate a capacity from the BMS supplied OCV, it
then ammends the coulomb counter to that to increase the accuracy
of the estimated capacity.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 drivers/power/supply/Kconfig    |   9 +
 drivers/power/supply/Makefile   |   1 +
 drivers/power/supply/qcom_bms.c | 500 ++++++++++++++++++++++++++++++++
 3 files changed, 510 insertions(+)
 create mode 100644 drivers/power/supply/qcom_bms.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 428b426842f4..6c354c37bc55 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -82,6 +82,15 @@ config BATTERY_ACT8945A
 	  Say Y here to enable support for power supply provided by
 	  Active-semi ActivePath ACT8945A charger.
 
+config BATTERY_BMS
+	tristate "Qualcomm Battery Monitoring System driver"
+	depends on MFD_SPMI_PMIC || COMPILE_TEST
+	depends on OF
+	depends on REGMAP_SPMI
+	help
+	  Say Y to include support for the Battery Monitoring hardware
+	  found in some Qualcomm PM series PMICs.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index e83aa843bcc6..04204174b047 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
+obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
 obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
new file mode 100644
index 000000000000..f31c99c03518
--- /dev/null
+++ b/drivers/power/supply/qcom_bms.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL
+
+/*
+ * Qualcomm Battery Monitoring System driver
+ *
+ * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/iio/consumer.h>
+
+#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
+#define REG_BMS_SHDW_CC_DATA0		0xA8
+#define REG_BMS_CC_DATA_CTL		0x42
+#define REG_BMS_CC_CLEAR_CTL		0x4
+
+#define BMS_HOLD_OREG_DATA		BIT(0)
+#define BMS_CLEAR_SHDW_CC		BIT(6)
+
+#define CC_36_BIT_MASK			0xFFFFFFFFFLL
+#define SIGN_EXTEND_36_TO_64_MASK	(-1LL ^ CC_36_BIT_MASK)
+
+#define BMS_CC_READING_RESOLUTION_N	542535
+#define BMS_CC_READING_RESOLUTION_D	10000
+#define BMS_CC_READING_TICKS		56
+#define BMS_SLEEP_CLK_HZ		32764
+
+#define SECONDS_PER_HOUR		3600
+#define TEMPERATURE_COLS		5
+#define MAX_CAPACITY_ROWS		50
+
+/* lookup table for ocv -> capacity conversion */
+struct bms_ocv_lut {
+	int rows;
+	s8 temp_legend[TEMPERATURE_COLS];
+	u8 capacity_legend[MAX_CAPACITY_ROWS];
+	u16 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
+};
+
+/* lookup table for battery temperature -> fcc conversion */
+struct bms_fcc_lut {
+	s8 temp_legend[TEMPERATURE_COLS];
+	u16 lut[TEMPERATURE_COLS];
+};
+
+struct bms_device_info {
+	struct device *dev;
+	struct regmap *regmap;
+	struct power_supply *bat;
+	struct power_supply_desc bat_desc;
+	struct bms_ocv_lut ocv_lut;
+	struct bms_fcc_lut fcc_lut;
+	struct iio_channel *adc;
+	spinlock_t bms_output_lock;
+	int base_addr;
+
+	int ocv_thr_irq;
+	int ocv;
+};
+
+static s64 sign_extend_s36(uint64_t raw)
+{
+	raw = raw & CC_36_BIT_MASK;
+
+	return (raw >> 35) == 0LL ?
+		raw : (SIGN_EXTEND_36_TO_64_MASK | raw);
+}
+
+static unsigned int interpolate(int y0, int x0, int y1, int x1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+static unsigned int between(int left, int right, int val)
+{
+	if (left <= val && val <= right)
+		return 1;
+
+	return 0;
+}
+
+static unsigned int interpolate_capacity(int temp, u16 ocv,
+				struct bms_ocv_lut ocv_lut)
+{
+	unsigned int pcj_minus_one = 0, pcj = 0;
+	int i, j;
+
+	for (j = 0; j < TEMPERATURE_COLS; j++)
+		if (temp <= ocv_lut.temp_legend[j])
+			break;
+
+	if (ocv >= ocv_lut.lut[0][j])
+		return ocv_lut.capacity_legend[0];
+
+	if (ocv <= ocv_lut.lut[ocv_lut.rows - 1][j - 1])
+		return ocv_lut.capacity_legend[ocv_lut.rows - 1];
+
+	for (i = 0; i < ocv_lut.rows - 1; i++) {
+		if (pcj == 0 && between(ocv_lut.lut[i][j],
+					ocv_lut.lut[i+1][j], ocv))
+			pcj = interpolate(ocv_lut.capacity_legend[i],
+					  ocv_lut.lut[i][j],
+					  ocv_lut.capacity_legend[i + 1],
+					  ocv_lut.lut[i+1][j],
+					  ocv);
+
+		if (pcj_minus_one == 0 && between(ocv_lut.lut[i][j-1],
+						  ocv_lut.lut[i+1][j-1], ocv))
+			pcj_minus_one = interpolate(ocv_lut.capacity_legend[i],
+						    ocv_lut.lut[i][j-1],
+						    ocv_lut.capacity_legend[i + 1],
+						    ocv_lut.lut[i+1][j-1],
+						    ocv);
+
+		if (pcj && pcj_minus_one)
+			return interpolate(pcj_minus_one,
+					   ocv_lut.temp_legend[j-1],
+					   pcj,
+					   ocv_lut.temp_legend[j],
+					   temp);
+	}
+
+	if (pcj)
+		return pcj;
+
+	if (pcj_minus_one)
+		return pcj_minus_one;
+
+	return 100;
+}
+
+static unsigned long interpolate_fcc(int temp, struct bms_fcc_lut fcc_lut)
+{
+	int i, fcc_mv;
+
+	for (i = 0; i < TEMPERATURE_COLS; i++)
+		if (temp <= fcc_lut.temp_legend[i])
+			break;
+
+	fcc_mv = interpolate(fcc_lut.lut[i - 1],
+			     fcc_lut.temp_legend[i - 1],
+			     fcc_lut.lut[i],
+			     fcc_lut.temp_legend[i],
+			     temp);
+
+	return fcc_mv * 10000;
+}
+
+static int bms_lock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to lock bms output: %d", ret);
+		return ret;
+	}
+
+	/*
+	 * Sleep for 100 microseconds here to make sure there has
+	 * been at least three cycles of the sleep clock so that
+	 * the registers are correctly locked.
+	 */
+	udelay(100);
+
+	return 0;
+}
+
+static int bms_unlock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, 0);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to unlock bms output: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bms_read_ocv(struct bms_device_info *di, int *ocv)
+{
+	unsigned long flags;
+	int ret;
+	u16 read_ocv;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = bms_lock_output_data(di);
+	if (ret < 0)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
+	if (ret < 0) {
+		dev_err(di->dev, "OCV read failed: %d", ret);
+		return ret;
+	}
+
+	dev_dbg(di->dev, "read OCV value of: %d", read_ocv);
+	*ocv = read_ocv;
+
+	ret = bms_unlock_output_data(di);
+
+err_lock:
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+
+	return ret;
+}
+
+static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
+{
+	unsigned long flags;
+	int ret;
+	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = bms_lock_output_data(di);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_SHDW_CC_DATA0,
+			       &cc_raw_s36, 5);
+	if (ret < 0) {
+		dev_err(di->dev, "coulomb counter read failed: %d", ret);
+		return ret;
+	}
+
+	ret = bms_unlock_output_data(di);
+	if (ret < 0)
+		return ret;
+
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+
+	cc_raw = sign_extend_s36(cc_raw_s36);
+
+	/* convert raw to uv */
+	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
+			BMS_CC_READING_RESOLUTION_D);
+
+	/* convert uv to pvh */
+	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
+			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR) * 10;
+
+	/* divide by impedance */
+	*cc_uah = div_s64(cc_pvh, 10000);
+
+	dev_dbg(di->dev, "read coulomb counter value of: %lld", *cc_uah);
+
+	return 0;
+}
+
+static void bms_reset_cc(struct bms_device_info *di)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&di->bms_output_lock, flags);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC,
+				 BMS_CLEAR_SHDW_CC);
+	if (ret < 0) {
+		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
+		goto err_lock;
+	}
+
+	/* wait two sleep cycles for cc to reset */
+	udelay(100);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC, 0);
+	if (ret < 0)
+		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
+
+err_lock:
+	spin_unlock_irqrestore(&di->bms_output_lock, flags);
+}
+
+static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
+{
+	unsigned long ocv_capacity, fcc;
+	int ret, temp, temp_degc;
+	s64 cc, capacity_nodiv;
+
+	ret = iio_read_channel_raw(di->adc, &temp);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read temperature: %d", ret);
+		return ret;
+	}
+
+	temp_degc = (temp + 500) / 1000;
+
+	ret = bms_read_cc(di, &cc);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
+		return ret;
+	}
+
+	ocv_capacity = interpolate_capacity(temp_degc, (di->ocv + 5) / 10,
+					    di->ocv_lut);
+	fcc = interpolate_fcc(temp_degc, di->fcc_lut);
+
+	capacity_nodiv = ((fcc * ocv_capacity) / 100 - cc) * 100;
+	*capacity = div64_ul(capacity_nodiv, fcc);
+
+	return 0;
+}
+
+
+
+/*
+ * Return power_supply property
+ */
+static int bms_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct bms_device_info *di = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = bms_calculate_capacity(di, &val->intval);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (val->intval == INT_MAX || val->intval == INT_MIN)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static enum power_supply_property bms_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
+{
+	struct bms_device_info *di = dev_id;
+
+	if (bms_read_ocv(di, &di->ocv) < 0)
+		return IRQ_HANDLED;
+
+	bms_reset_cc(di);
+	return IRQ_HANDLED;
+}
+
+static int bms_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct bms_device_info *di;
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, di);
+
+	di->dev = &pdev->dev;
+
+	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!di->regmap) {
+		dev_err(di->dev, "Unable to get regmap");
+		return -EINVAL;
+	}
+
+	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
+	if (IS_ERR(di->adc))
+		return PTR_ERR(di->adc);
+
+	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,ocv-temp-legend",
+						 (u8 *)di->ocv_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no ocv temperature legend found");
+		return ret;
+	}
+
+	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
+						 "qcom,ocv-capacity-legend",
+						 di->ocv_lut.capacity_legend, 0,
+						 MAX_CAPACITY_ROWS);
+	if (di->ocv_lut.rows < 0) {
+		dev_err(di->dev, "no ocv capacity legend found");
+		return ret;
+	}
+
+	ret = of_property_read_variable_u16_array(di->dev->of_node,
+						  "qcom,ocv-lut",
+						  (u16 *)di->ocv_lut.lut,
+						  TEMPERATURE_COLS,
+						  TEMPERATURE_COLS *
+						  MAX_CAPACITY_ROWS);
+	if (ret < 0) {
+		dev_err(di->dev, "no ocv lut array found");
+		return ret;
+	}
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,fcc-temp-legend",
+						 (u8 *)di->fcc_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no fcc temperature legend found");
+		return ret;
+	}
+
+	ret = of_property_read_u16_array(di->dev->of_node,
+						  "qcom,fcc-lut",
+						  di->fcc_lut.lut,
+						  TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no fcc lut array found");
+		return ret;
+	}
+
+	ret = bms_read_ocv(di, &di->ocv);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read initial ocv: %d", ret);
+		return ret;
+	}
+
+	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
+
+	ret = devm_request_irq(di->dev, di->ocv_thr_irq,
+					bms_ocv_thr_irq_handler,
+					IRQF_TRIGGER_RISING,
+					pdev->name, di);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to request handler for ocv threshold IRQ");
+		return ret;
+	}
+
+	spin_lock_init(&di->bms_output_lock);
+
+	di->bat_desc.name = "bms";
+	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat_desc.properties = bms_props;
+	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
+	di->bat_desc.get_property = bms_get_property;
+
+	psy_cfg.drv_data = di;
+	di->bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
+	if (IS_ERR(di->bat))
+		return PTR_ERR(di->bat);
+
+	return 0;
+}
+
+static const struct of_device_id bms_of_match[] = {
+	{.compatible = "qcom,pm8941-bms", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bms_of_match);
+
+static struct platform_driver bms_driver = {
+	.probe = bms_probe,
+	.driver = {
+		.name = "qcom-bms",
+		.of_match_table = of_match_ptr(bms_of_match),
+	},
+};
+module_platform_driver(bms_driver);
+
+MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm BMS driver");
+MODULE_LICENSE("GPL");
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
@ 2018-04-07 17:57   ` Craig Tatlor
  2018-04-13 16:35     ` Rob Herring
  2018-04-07 17:57   ` [PATCH v4 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2018-04-26 11:34   ` [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Linus Walleij
  2 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 17:57 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Add bindings for the Qualcomm Battery Monitoring system.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 .../bindings/power/supply/qcom_bms.txt        | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt

diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
new file mode 100644
index 000000000000..6296399edc09
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
@@ -0,0 +1,93 @@
+Qualcomm Battery Measurement System
+
+The Qualcomm Battery Measurement System is found inside of Qualcomm PM8941
+PMICs. It provides OCV and coulomb counter registers that allow the kernel
+to infer a capacity level.
+
+Required properties:
+- compatible:               Should contain "qcom,pm8941-bms".
+- reg:                      Specifies the SPMI address and length of the
+			    controller's registers.
+- interrupts:               OCV threshold interrupt.
+- io-channels:              Should contain IIO channel specifier for the
+			    ADC channel that reports battery temperature.
+- io-channel-names:         Should contain "temp".
+- qcom,fcc-temp-legend:     An array containing the temperature, in degC,
+			    for each column of the FCC lookup table.
+- qcom,fcc-lut:             An array of FCC values in mah, one entry for each
+			    temperature defined in in qcom,fcc-temp-legend.
+- qcom,ocv-temp-legend:     An array containing the temperature, in degC,
+			    for each column of the OCV lookup table.
+- qcom,ocv-capacity-legend: An array containing the capacity for each
+			    row of the OCV lookup table.
+- qcom,ocv-lut:             An array of OCV values in mV, one entry for each
+			    capacity defined in qcom,ocv-capacity-legend.
+
+Example:
+
+		pm8941_vadc: vadc@3100 {
+			compatible = "qcom,spmi-vadc";
+			reg = <0x3100>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+
+			bat_temp {
+				reg = <VADC_LR_MUX1_BAT_THERM>;
+			};
+		};
+
+		bms@4000 {
+			compatible = "qcom,pm8941-bms";
+			reg = <0x4000>;
+			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ocv_thr";
+
+			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
+			io-channel-names = "temp";
+
+			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
+
+			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
+							     80 75 70 65
+							     60 55 50 45
+							     40 35 30 25
+							     20 15 10 9
+							     8 7 6 5 4
+							     3 2 1 0>;
+
+			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
+						  4261 4241 4259 4266 4246
+						  4201 4181 4201 4207 4187
+						  4153 4133 4150 4155 4135
+						  4105 4085 4100 4104 4084
+						  4058 4038 4052 4058 4038
+						  4012 3992 4004 4014 3994
+						  3970 3950 3959 3971 3951
+						  3931 3911 3915 3927 3907
+						  3899 3879 3880 3884 3864
+						  3873 3853 3851 3853 3833
+						  3848 3828 3827 3829 3809
+						  3829 3809 3808 3809 3789
+						  3815 3795 3791 3791 3771
+						  3801 3781 3775 3772 3752
+						  3785 3765 3751 3746 3726
+						  3767 3747 3727 3719 3699
+						  3750 3730 3702 3692 3672
+						  3728 3708 3680 3672 3652
+						  3720 3700 3676 3665 3645
+						  3712 3692 3670 3660 3645
+						  3695 3675 3658 3648 3633
+						  3662 3647 3629 3620 3610
+						  3620 3605 3589 3580 3570
+						  3562 3552 3538 3529 3519
+						  3490 3480 3474 3470 3465
+						  3403 3398 3388 3380 3375
+						  3320 3300 3255 3221 3206
+						  3000 3000 3000 3000 3000>;
+		};
+	};
+};
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v4 3/3] MAINTAINERS: Add entry for the Qualcomm BMS
  2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
  2018-04-07 17:57   ` [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-04-07 17:57   ` Craig Tatlor
  2018-04-26 11:34   ` [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Linus Walleij
  2 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-07 17:57 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Linus Walleij, Andrew Morton, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0c3ad62c638c..aaf54b665f86 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11605,6 +11605,12 @@ W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
+QUALCOMM BATTERY MONITORING SYSTEM
+M:	Craig Tatlor <ctatlor97@gmail.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/qcom_bms.c
+
 QUALCOMM CAMERA SUBSYSTEM DRIVER
 M:	Todor Tomov <todor.tomov@linaro.org>
 L:	linux-media@vger.kernel.org
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-07 17:57   ` [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-04-13 16:35     ` Rob Herring
  2018-04-13 17:08       ` Craig Tatlor
  2018-04-15 12:55       ` Craig Tatlor
  0 siblings, 2 replies; 60+ messages in thread
From: Rob Herring @ 2018-04-13 16:35 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, Randy Dunlap, linux-pm, devicetree,
	linux-kernel

On Sat, Apr 07, 2018 at 06:57:45PM +0100, Craig Tatlor wrote:
> Add bindings for the Qualcomm Battery Monitoring system.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
>  .../bindings/power/supply/qcom_bms.txt        | 93 +++++++++++++++++++
>  1 file changed, 93 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> new file mode 100644
> index 000000000000..6296399edc09
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> @@ -0,0 +1,93 @@
> +Qualcomm Battery Measurement System
> +
> +The Qualcomm Battery Measurement System is found inside of Qualcomm PM8941

Is it Monitoring or Measurment?

> +PMICs. It provides OCV and coulomb counter registers that allow the kernel
> +to infer a capacity level.

s/kernel/OS/

OCV?

> +
> +Required properties:
> +- compatible:               Should contain "qcom,pm8941-bms".
> +- reg:                      Specifies the SPMI address and length of the
> +			    controller's registers.
> +- interrupts:               OCV threshold interrupt.
> +- io-channels:              Should contain IIO channel specifier for the
> +			    ADC channel that reports battery temperature.
> +- io-channel-names:         Should contain "temp".
> +- qcom,fcc-temp-legend:     An array containing the temperature, in degC,
> +			    for each column of the FCC lookup table.

What's FCC?

> +- qcom,fcc-lut:             An array of FCC values in mah, one entry for each
> +			    temperature defined in in qcom,fcc-temp-legend.
> +- qcom,ocv-temp-legend:     An array containing the temperature, in degC,
> +			    for each column of the OCV lookup table.
> +- qcom,ocv-capacity-legend: An array containing the capacity for each
> +			    row of the OCV lookup table.
> +- qcom,ocv-lut:             An array of OCV values in mV, one entry for each
> +			    capacity defined in qcom,ocv-capacity-legend.

Need to specify the sizes of these if not 32-bit.

All these seem to have units, so add unit suffixes as defined in 
property-units.txt.

> +
> +Example:
> +
> +		pm8941_vadc: vadc@3100 {

adc@...

> +			compatible = "qcom,spmi-vadc";
> +			reg = <0x3100>;
> +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			#io-channel-cells = <1>;
> +
> +			bat_temp {
> +				reg = <VADC_LR_MUX1_BAT_THERM>;
> +			};
> +		};
> +
> +		bms@4000 {
> +			compatible = "qcom,pm8941-bms";
> +			reg = <0x4000>;
> +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
> +			interrupt-names = "ocv_thr";
> +
> +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
> +			io-channel-names = "temp";
> +
> +			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
> +			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
> +
> +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
> +							     80 75 70 65
> +							     60 55 50 45
> +							     40 35 30 25
> +							     20 15 10 9
> +							     8 7 6 5 4
> +							     3 2 1 0>;
> +
> +			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
> +			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
> +						  4261 4241 4259 4266 4246
> +						  4201 4181 4201 4207 4187
> +						  4153 4133 4150 4155 4135
> +						  4105 4085 4100 4104 4084
> +						  4058 4038 4052 4058 4038
> +						  4012 3992 4004 4014 3994
> +						  3970 3950 3959 3971 3951
> +						  3931 3911 3915 3927 3907
> +						  3899 3879 3880 3884 3864
> +						  3873 3853 3851 3853 3833
> +						  3848 3828 3827 3829 3809
> +						  3829 3809 3808 3809 3789
> +						  3815 3795 3791 3791 3771
> +						  3801 3781 3775 3772 3752
> +						  3785 3765 3751 3746 3726
> +						  3767 3747 3727 3719 3699
> +						  3750 3730 3702 3692 3672
> +						  3728 3708 3680 3672 3652
> +						  3720 3700 3676 3665 3645
> +						  3712 3692 3670 3660 3645
> +						  3695 3675 3658 3648 3633
> +						  3662 3647 3629 3620 3610
> +						  3620 3605 3589 3580 3570
> +						  3562 3552 3538 3529 3519
> +						  3490 3480 3474 3470 3465
> +						  3403 3398 3388 3380 3375
> +						  3320 3300 3255 3221 3206
> +						  3000 3000 3000 3000 3000>;
> +		};
> +	};
> +};
> -- 
> 2.17.0
> 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-13 16:35     ` Rob Herring
@ 2018-04-13 17:08       ` Craig Tatlor
  2018-04-13 17:10         ` Craig Tatlor
  2018-04-15 12:55       ` Craig Tatlor
  1 sibling, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-04-13 17:08 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, Randy Dunlap, linux-pm, devicetree,
	linux-kernel



On 13 April 2018 17:35:27 BST, Rob Herring <robh@kernel.org> wrote:
>On Sat, Apr 07, 2018 at 06:57:45PM +0100, Craig Tatlor wrote:
>> Add bindings for the Qualcomm Battery Monitoring system.
>> 
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> ---
>>  .../bindings/power/supply/qcom_bms.txt        | 93
>+++++++++++++++++++
>>  1 file changed, 93 insertions(+)
>>  create mode 100644
>Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> 
>> diff --git
>a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> new file mode 100644
>> index 000000000000..6296399edc09
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> @@ -0,0 +1,93 @@
>> +Qualcomm Battery Measurement System
>> +
>> +The Qualcomm Battery Measurement System is found inside of Qualcomm
>PM8941
>
>Is it Monitoring or Measurment?
>
>> +PMICs. It provides OCV and coulomb counter registers that allow the
>kernel
>> +to infer a capacity level.
>
>s/kernel/OS/
>
>OCV?
Open Circuit Voltage - should I expand this?
>
>> +
>> +Required properties:
>> +- compatible:               Should contain "qcom,pm8941-bms".
>> +- reg:                      Specifies the SPMI address and length of
>the
>> +			    controller's registers.
>> +- interrupts:               OCV threshold interrupt.
>> +- io-channels:              Should contain IIO channel specifier for
>the
>> +			    ADC channel that reports battery temperature.
>> +- io-channel-names:         Should contain "temp".
>> +- qcom,fcc-temp-legend:     An array containing the temperature, in
>degC,
>> +			    for each column of the FCC lookup table.
>
>What's FCC?
Full charge capacity - Should i also expand this? or maybe explain in header paragraph?
>
>> +- qcom,fcc-lut:             An array of FCC values in mah, one entry
>for each
>> +			    temperature defined in in qcom,fcc-temp-legend.
>> +- qcom,ocv-temp-legend:     An array containing the temperature, in
>degC,
>> +			    for each column of the OCV lookup table.
>> +- qcom,ocv-capacity-legend: An array containing the capacity for
>each
>> +			    row of the OCV lookup table.
>> +- qcom,ocv-lut:             An array of OCV values in mV, one entry
>for each
>> +			    capacity defined in qcom,ocv-capacity-legend.
>
>Need to specify the sizes of these if not 32-bit.
Right.
>
>All these seem to have units, so add unit suffixes as defined in 
>property-units.txt.
Will do.
>
>> +
>> +Example:
>> +
>> +		pm8941_vadc: vadc@3100 {
>
>adc@...
Okay.
>
>> +			compatible = "qcom,spmi-vadc";
>> +			reg = <0x3100>;
>> +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +			#io-channel-cells = <1>;
>> +
>> +			bat_temp {
>> +				reg = <VADC_LR_MUX1_BAT_THERM>;
>> +			};
>> +		};
>> +
>> +		bms@4000 {
>> +			compatible = "qcom,pm8941-bms";
>> +			reg = <0x4000>;
>> +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
>> +			interrupt-names = "ocv_thr";
>> +
>> +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
>> +			io-channel-names = "temp";
>> +
>> +			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
>> +			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
>> +
>> +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
>> +							     80 75 70 65
>> +							     60 55 50 45
>> +							     40 35 30 25
>> +							     20 15 10 9
>> +							     8 7 6 5 4
>> +							     3 2 1 0>;
>> +
>> +			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
>> +			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
>> +						  4261 4241 4259 4266 4246
>> +						  4201 4181 4201 4207 4187
>> +						  4153 4133 4150 4155 4135
>> +						  4105 4085 4100 4104 4084
>> +						  4058 4038 4052 4058 4038
>> +						  4012 3992 4004 4014 3994
>> +						  3970 3950 3959 3971 3951
>> +						  3931 3911 3915 3927 3907
>> +						  3899 3879 3880 3884 3864
>> +						  3873 3853 3851 3853 3833
>> +						  3848 3828 3827 3829 3809
>> +						  3829 3809 3808 3809 3789
>> +						  3815 3795 3791 3791 3771
>> +						  3801 3781 3775 3772 3752
>> +						  3785 3765 3751 3746 3726
>> +						  3767 3747 3727 3719 3699
>> +						  3750 3730 3702 3692 3672
>> +						  3728 3708 3680 3672 3652
>> +						  3720 3700 3676 3665 3645
>> +						  3712 3692 3670 3660 3645
>> +						  3695 3675 3658 3648 3633
>> +						  3662 3647 3629 3620 3610
>> +						  3620 3605 3589 3580 3570
>> +						  3562 3552 3538 3529 3519
>> +						  3490 3480 3474 3470 3465
>> +						  3403 3398 3388 3380 3375
>> +						  3320 3300 3255 3221 3206
>> +						  3000 3000 3000 3000 3000>;
>> +		};
>> +	};
>> +};
>> -- 
>> 2.17.0
>> 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-13 17:08       ` Craig Tatlor
@ 2018-04-13 17:10         ` Craig Tatlor
  0 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-13 17:10 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, Randy Dunlap, linux-pm, devicetree,
	linux-kernel



On 13 April 2018 18:08:54 BST, Craig Tatlor <ctatlor97@gmail.com> wrote:
>
>
>On 13 April 2018 17:35:27 BST, Rob Herring <robh@kernel.org> wrote:
>>On Sat, Apr 07, 2018 at 06:57:45PM +0100, Craig Tatlor wrote:
>>> Add bindings for the Qualcomm Battery Monitoring system.
>>> 
>>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>>> ---
>>>  .../bindings/power/supply/qcom_bms.txt        | 93
>>+++++++++++++++++++
>>>  1 file changed, 93 insertions(+)
>>>  create mode 100644
>>Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>>> 
>>> diff --git
>>a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>>b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>>> new file mode 100644
>>> index 000000000000..6296399edc09
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>>> @@ -0,0 +1,93 @@
>>> +Qualcomm Battery Measurement System
>>> +
>>> +The Qualcomm Battery Measurement System is found inside of Qualcomm
>>PM8941
>>
>>Is it Monitoring or Measurment?
Monitoring, not sure how I missed that :)
>>
>>> +PMICs. It provides OCV and coulomb counter registers that allow the
>>kernel
>>> +to infer a capacity level.
>>
>>s/kernel/OS/
>>
>>OCV?
>Open Circuit Voltage - should I expand this?
>>
>>> +
>>> +Required properties:
>>> +- compatible:               Should contain "qcom,pm8941-bms".
>>> +- reg:                      Specifies the SPMI address and length
>of
>>the
>>> +			    controller's registers.
>>> +- interrupts:               OCV threshold interrupt.
>>> +- io-channels:              Should contain IIO channel specifier
>for
>>the
>>> +			    ADC channel that reports battery temperature.
>>> +- io-channel-names:         Should contain "temp".
>>> +- qcom,fcc-temp-legend:     An array containing the temperature, in
>>degC,
>>> +			    for each column of the FCC lookup table.
>>
>>What's FCC?
>Full charge capacity - Should i also expand this? or maybe explain in
>header paragraph?
>>
>>> +- qcom,fcc-lut:             An array of FCC values in mah, one
>entry
>>for each
>>> +			    temperature defined in in qcom,fcc-temp-legend.
>>> +- qcom,ocv-temp-legend:     An array containing the temperature, in
>>degC,
>>> +			    for each column of the OCV lookup table.
>>> +- qcom,ocv-capacity-legend: An array containing the capacity for
>>each
>>> +			    row of the OCV lookup table.
>>> +- qcom,ocv-lut:             An array of OCV values in mV, one entry
>>for each
>>> +			    capacity defined in qcom,ocv-capacity-legend.
>>
>>Need to specify the sizes of these if not 32-bit.
>Right.
>>
>>All these seem to have units, so add unit suffixes as defined in 
>>property-units.txt.
>Will do.
>>
>>> +
>>> +Example:
>>> +
>>> +		pm8941_vadc: vadc@3100 {
>>
>>adc@...
>Okay.
>>
>>> +			compatible = "qcom,spmi-vadc";
>>> +			reg = <0x3100>;
>>> +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
>>> +			#address-cells = <1>;
>>> +			#size-cells = <0>;
>>> +			#io-channel-cells = <1>;
>>> +
>>> +			bat_temp {
>>> +				reg = <VADC_LR_MUX1_BAT_THERM>;
>>> +			};
>>> +		};
>>> +
>>> +		bms@4000 {
>>> +			compatible = "qcom,pm8941-bms";
>>> +			reg = <0x4000>;
>>> +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
>>> +			interrupt-names = "ocv_thr";
>>> +
>>> +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
>>> +			io-channel-names = "temp";
>>> +
>>> +			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
>>> +			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
>>> +
>>> +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
>>> +							     80 75 70 65
>>> +							     60 55 50 45
>>> +							     40 35 30 25
>>> +							     20 15 10 9
>>> +							     8 7 6 5 4
>>> +							     3 2 1 0>;
>>> +
>>> +			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
>>> +			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
>>> +						  4261 4241 4259 4266 4246
>>> +						  4201 4181 4201 4207 4187
>>> +						  4153 4133 4150 4155 4135
>>> +						  4105 4085 4100 4104 4084
>>> +						  4058 4038 4052 4058 4038
>>> +						  4012 3992 4004 4014 3994
>>> +						  3970 3950 3959 3971 3951
>>> +						  3931 3911 3915 3927 3907
>>> +						  3899 3879 3880 3884 3864
>>> +						  3873 3853 3851 3853 3833
>>> +						  3848 3828 3827 3829 3809
>>> +						  3829 3809 3808 3809 3789
>>> +						  3815 3795 3791 3791 3771
>>> +						  3801 3781 3775 3772 3752
>>> +						  3785 3765 3751 3746 3726
>>> +						  3767 3747 3727 3719 3699
>>> +						  3750 3730 3702 3692 3672
>>> +						  3728 3708 3680 3672 3652
>>> +						  3720 3700 3676 3665 3645
>>> +						  3712 3692 3670 3660 3645
>>> +						  3695 3675 3658 3648 3633
>>> +						  3662 3647 3629 3620 3610
>>> +						  3620 3605 3589 3580 3570
>>> +						  3562 3552 3538 3529 3519
>>> +						  3490 3480 3474 3470 3465
>>> +						  3403 3398 3388 3380 3375
>>> +						  3320 3300 3255 3221 3206
>>> +						  3000 3000 3000 3000 3000>;
>>> +		};
>>> +	};
>>> +};
>>> -- 
>>> 2.17.0
>>> 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-13 16:35     ` Rob Herring
  2018-04-13 17:08       ` Craig Tatlor
@ 2018-04-15 12:55       ` Craig Tatlor
  2018-04-18 21:16         ` Rob Herring
  1 sibling, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-04-15 12:55 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, Randy Dunlap, linux-pm, devicetree,
	linux-kernel

On Fri, Apr 13, 2018 at 11:35:27AM -0500, Rob Herring wrote:
> On Sat, Apr 07, 2018 at 06:57:45PM +0100, Craig Tatlor wrote:
> > Add bindings for the Qualcomm Battery Monitoring system.
> > 
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> > ---
> >  .../bindings/power/supply/qcom_bms.txt        | 93 +++++++++++++++++++
> >  1 file changed, 93 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > new file mode 100644
> > index 000000000000..6296399edc09
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > @@ -0,0 +1,93 @@
> > +Qualcomm Battery Measurement System
> > +
> > +The Qualcomm Battery Measurement System is found inside of Qualcomm PM8941
> 
> Is it Monitoring or Measurment?
> 
> > +PMICs. It provides OCV and coulomb counter registers that allow the kernel
> > +to infer a capacity level.
> 
> s/kernel/OS/
> 
> OCV?
> 
> > +
> > +Required properties:
> > +- compatible:               Should contain "qcom,pm8941-bms".
> > +- reg:                      Specifies the SPMI address and length of the
> > +			    controller's registers.
> > +- interrupts:               OCV threshold interrupt.
> > +- io-channels:              Should contain IIO channel specifier for the
> > +			    ADC channel that reports battery temperature.
> > +- io-channel-names:         Should contain "temp".
> > +- qcom,fcc-temp-legend:     An array containing the temperature, in degC,
> > +			    for each column of the FCC lookup table.
> 
> What's FCC?
> 
> > +- qcom,fcc-lut:             An array of FCC values in mah, one entry for each
> > +			    temperature defined in in qcom,fcc-temp-legend.
> > +- qcom,ocv-temp-legend:     An array containing the temperature, in degC,
> > +			    for each column of the OCV lookup table.
> > +- qcom,ocv-capacity-legend: An array containing the capacity for each
> > +			    row of the OCV lookup table.
> > +- qcom,ocv-lut:             An array of OCV values in mV, one entry for each
> > +			    capacity defined in qcom,ocv-capacity-legend.
> 
> Need to specify the sizes of these if not 32-bit.
> 
> All these seem to have units, so add unit suffixes as defined in 
> property-units.txt.
Should i change code to use microamphours & microvolts or add a new
suffix?
> 
> > +
> > +Example:
> > +
> > +		pm8941_vadc: vadc@3100 {
> 
> adc@...
> 
> > +			compatible = "qcom,spmi-vadc";
> > +			reg = <0x3100>;
> > +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +			#io-channel-cells = <1>;
> > +
> > +			bat_temp {
> > +				reg = <VADC_LR_MUX1_BAT_THERM>;
> > +			};
> > +		};
> > +
> > +		bms@4000 {
> > +			compatible = "qcom,pm8941-bms";
> > +			reg = <0x4000>;
> > +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
> > +			interrupt-names = "ocv_thr";
> > +
> > +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
> > +			io-channel-names = "temp";
> > +
> > +			qcom,fcc-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
> > +			qcom,fcc-lut = /bits/ 16 <6010 6070 6680 6780 6670>;
> > +
> > +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85
> > +							     80 75 70 65
> > +							     60 55 50 45
> > +							     40 35 30 25
> > +							     20 15 10 9
> > +							     8 7 6 5 4
> > +							     3 2 1 0>;
> > +
> > +			qcom,ocv-temp-legend = /bits/ 8 <(-10) 0 25 50 65>;
> > +			qcom,ocv-lut = /bits/ 16 <4288 4288 4306 4315 4315
> > +						  4261 4241 4259 4266 4246
> > +						  4201 4181 4201 4207 4187
> > +						  4153 4133 4150 4155 4135
> > +						  4105 4085 4100 4104 4084
> > +						  4058 4038 4052 4058 4038
> > +						  4012 3992 4004 4014 3994
> > +						  3970 3950 3959 3971 3951
> > +						  3931 3911 3915 3927 3907
> > +						  3899 3879 3880 3884 3864
> > +						  3873 3853 3851 3853 3833
> > +						  3848 3828 3827 3829 3809
> > +						  3829 3809 3808 3809 3789
> > +						  3815 3795 3791 3791 3771
> > +						  3801 3781 3775 3772 3752
> > +						  3785 3765 3751 3746 3726
> > +						  3767 3747 3727 3719 3699
> > +						  3750 3730 3702 3692 3672
> > +						  3728 3708 3680 3672 3652
> > +						  3720 3700 3676 3665 3645
> > +						  3712 3692 3670 3660 3645
> > +						  3695 3675 3658 3648 3633
> > +						  3662 3647 3629 3620 3610
> > +						  3620 3605 3589 3580 3570
> > +						  3562 3552 3538 3529 3519
> > +						  3490 3480 3474 3470 3465
> > +						  3403 3398 3388 3380 3375
> > +						  3320 3300 3255 3221 3206
> > +						  3000 3000 3000 3000 3000>;
> > +		};
> > +	};
> > +};
> > -- 
> > 2.17.0
> > 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-04-15 12:55       ` Craig Tatlor
@ 2018-04-18 21:16         ` Rob Herring
  0 siblings, 0 replies; 60+ messages in thread
From: Rob Herring @ 2018-04-18 21:16 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Linus Walleij, Andrew Morton, Randy Dunlap, linux-pm, devicetree,
	linux-kernel

On Sun, Apr 15, 2018 at 7:55 AM, Craig Tatlor <ctatlor97@gmail.com> wrote:
> On Fri, Apr 13, 2018 at 11:35:27AM -0500, Rob Herring wrote:
>> On Sat, Apr 07, 2018 at 06:57:45PM +0100, Craig Tatlor wrote:
>> > Add bindings for the Qualcomm Battery Monitoring system.
>> >
>> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> > ---
>> >  .../bindings/power/supply/qcom_bms.txt        | 93 +++++++++++++++++++
>> >  1 file changed, 93 insertions(+)
>> >  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> > new file mode 100644
>> > index 000000000000..6296399edc09
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> > @@ -0,0 +1,93 @@
>> > +Qualcomm Battery Measurement System
>> > +
>> > +The Qualcomm Battery Measurement System is found inside of Qualcomm PM8941
>>
>> Is it Monitoring or Measurment?
>>
>> > +PMICs. It provides OCV and coulomb counter registers that allow the kernel
>> > +to infer a capacity level.
>>
>> s/kernel/OS/
>>
>> OCV?
>>
>> > +
>> > +Required properties:
>> > +- compatible:               Should contain "qcom,pm8941-bms".
>> > +- reg:                      Specifies the SPMI address and length of the
>> > +                       controller's registers.
>> > +- interrupts:               OCV threshold interrupt.
>> > +- io-channels:              Should contain IIO channel specifier for the
>> > +                       ADC channel that reports battery temperature.
>> > +- io-channel-names:         Should contain "temp".
>> > +- qcom,fcc-temp-legend:     An array containing the temperature, in degC,
>> > +                       for each column of the FCC lookup table.
>>
>> What's FCC?
>>
>> > +- qcom,fcc-lut:             An array of FCC values in mah, one entry for each
>> > +                       temperature defined in in qcom,fcc-temp-legend.
>> > +- qcom,ocv-temp-legend:     An array containing the temperature, in degC,
>> > +                       for each column of the OCV lookup table.
>> > +- qcom,ocv-capacity-legend: An array containing the capacity for each
>> > +                       row of the OCV lookup table.
>> > +- qcom,ocv-lut:             An array of OCV values in mV, one entry for each
>> > +                       capacity defined in qcom,ocv-capacity-legend.
>>
>> Need to specify the sizes of these if not 32-bit.
>>
>> All these seem to have units, so add unit suffixes as defined in
>> property-units.txt.
> Should i change code to use microamphours & microvolts or add a new
> suffix?

It is preferred to use the existing ones unless you have some
justification to add new ones.

Rob

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
  2018-04-07 17:57   ` [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
  2018-04-07 17:57   ` [PATCH v4 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
@ 2018-04-26 11:34   ` Linus Walleij
  2018-04-30 18:06     ` Craig Tatlor
  2 siblings, 1 reply; 60+ messages in thread
From: Linus Walleij @ 2018-04-26 11:34 UTC (permalink / raw)
  To: Craig Tatlor, Antonio Ospite, Hans Verkuil, Jonathan Cameron
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Sat, Apr 7, 2018 at 7:57 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:

Hi Craig! Thanks for your patch!

> This patch adds a driver for the BMS (Battery Monitoring System)
> block of the PM8941 PMIC, it uses a lookup table defined in the
> device tree to generate a capacity from the BMS supplied OCV, it
> then ammends the coulomb counter to that to increase the accuracy
> of the estimated capacity.
>
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>

Just some minor remarks.

NB: I see that you are writing from a private email address
so if you're working as a hobbyist on your precious sparetime
I have lower expectation on how much work you will put into
this, so see it more as suggestions than demands.

My overall feedback is that for algorithmic charger what
we need is infrastructure. What is currently piling up in
drivers/power/supply scares me a bit in it's lack of
framework and code reuse.

It also scares me because this is vital technology dealing
with physical devices and as such really need to have
modularized reusable reviewed code with several users
and deployments.

Code reuse would include:

- Mathematical helpers such as interpolation of
  values from absolute values or tables
  Suggestions below!
- State machines and transitions
- CC/CV alorithms (using the above)
- Many other things

Not that *I* can make the situation much better, I'm just
sharing my fears,

> +static s64 sign_extend_s36(uint64_t raw)
> +{
> +       raw = raw & CC_36_BIT_MASK;
> +
> +       return (raw >> 35) == 0LL ?
> +               raw : (SIGN_EXTEND_36_TO_64_MASK | raw);
> +}

#include <linux/bitops.h>

Use sign_extend32()

> +static unsigned int interpolate(int y0, int x0, int y1, int x1, int x)
> +{
> +       if (y0 == y1 || x == x0)
> +               return y0;
> +       if (x1 == x0 || x == x1)
> +               return y1;
> +
> +       return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
> +}
> +
> +static unsigned int between(int left, int right, int val)
> +{
> +       if (left <= val && val <= right)
> +               return 1;
> +
> +       return 0;
> +}

How are these things not library functions?

Every cell of my brain says this code should be reusable.

Can you put this in <linux/fixp-arith.h>?

I bet a million to one that the video people will sooner or later
need linear interpolation and there are more users in the kernel
than drivers/power/, certainly drivers/iio as well.

If noone else says anything I vote to put at least the linear
interpolation into <linux/fixp-arith.h> with a bonus if you
move some of the current users in drivers/power over
while you're at it.

> +static unsigned int interpolate_capacity(int temp, u16 ocv,
> +                               struct bms_ocv_lut ocv_lut)
> +{
> +       unsigned int pcj_minus_one = 0, pcj = 0;
> +       int i, j;
> +
> +       for (j = 0; j < TEMPERATURE_COLS; j++)
> +               if (temp <= ocv_lut.temp_legend[j])
> +                       break;
> +
> +       if (ocv >= ocv_lut.lut[0][j])
> +               return ocv_lut.capacity_legend[0];
> +
> +       if (ocv <= ocv_lut.lut[ocv_lut.rows - 1][j - 1])
> +               return ocv_lut.capacity_legend[ocv_lut.rows - 1];
> +
> +       for (i = 0; i < ocv_lut.rows - 1; i++) {
> +               if (pcj == 0 && between(ocv_lut.lut[i][j],
> +                                       ocv_lut.lut[i+1][j], ocv))
> +                       pcj = interpolate(ocv_lut.capacity_legend[i],
> +                                         ocv_lut.lut[i][j],
> +                                         ocv_lut.capacity_legend[i + 1],
> +                                         ocv_lut.lut[i+1][j],
> +                                         ocv);
> +
> +               if (pcj_minus_one == 0 && between(ocv_lut.lut[i][j-1],
> +                                                 ocv_lut.lut[i+1][j-1], ocv))
> +                       pcj_minus_one = interpolate(ocv_lut.capacity_legend[i],
> +                                                   ocv_lut.lut[i][j-1],
> +                                                   ocv_lut.capacity_legend[i + 1],
> +                                                   ocv_lut.lut[i+1][j-1],
> +                                                   ocv);
> +
> +               if (pcj && pcj_minus_one)
> +                       return interpolate(pcj_minus_one,
> +                                          ocv_lut.temp_legend[j-1],
> +                                          pcj,
> +                                          ocv_lut.temp_legend[j],
> +                                          temp);
> +       }

This code really needs some comments to tell what is going on
here. Also I sense that you can break out a smaller function
for interpolation based on table values, such as a function
that would take a standard format of tables, look up where we
are in that table and interpolate from the neighboring values.

People can then later go in and refine the algorithms if they
e.g. want to introduce spline or RMS interpolation instead
and we can get better interpolation for everybody.

> +static unsigned long interpolate_fcc(int temp, struct bms_fcc_lut fcc_lut)
> +{
> +       int i, fcc_mv;
> +
> +       for (i = 0; i < TEMPERATURE_COLS; i++)
> +               if (temp <= fcc_lut.temp_legend[i])
> +                       break;
> +
> +       fcc_mv = interpolate(fcc_lut.lut[i - 1],
> +                            fcc_lut.temp_legend[i - 1],
> +                            fcc_lut.lut[i],
> +                            fcc_lut.temp_legend[i],
> +                            temp);
> +
> +       return fcc_mv * 10000;
> +}

So then only this would really remain: pass a table and interpolate.

> +static int bms_lock_output_data(struct bms_device_info *di)
> +{
> +       int ret;
> +
> +       ret = regmap_update_bits(di->regmap, di->base_addr +
> +                                REG_BMS_CC_DATA_CTL,
> +                                BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
> +       if (ret < 0) {
> +               dev_err(di->dev, "failed to lock bms output: %d", ret);
> +               return ret;
> +       }

Reuse of regmap is very nice, thanks for doing it this way.

> +static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
> +static void bms_reset_cc(struct bms_device_info *di)

These indeed need to be mostly hardware-specific so they
are fine.

> +static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
> +{
> +       unsigned long ocv_capacity, fcc;
> +       int ret, temp, temp_degc;
> +       s64 cc, capacity_nodiv;
> +
> +       ret = iio_read_channel_raw(di->adc, &temp);
> +       if (ret < 0) {
> +               dev_err(di->dev, "failed to read temperature: %d", ret);
> +               return ret;
> +       }

Very nice that you use IIO ADC as a back-end.

> +       temp_degc = (temp + 500) / 1000;

That deserves a comment I think. Like what the manual
says about this and why the raw temperature is given
like this.

Maybe you want to use DIV_ROUND_CLOSEST()
or DIV_ROUND_UP() from <linux/kernel.h> instead
of just "/"?

Maybe you want to use that in other places too like
the below divisions.

> +       ret = bms_read_cc(di, &cc);
> +       if (ret < 0) {
> +               dev_err(di->dev, "failed to read coulomb counter: %d", ret);
> +               return ret;
> +       }
> +
> +       ocv_capacity = interpolate_capacity(temp_degc, (di->ocv + 5) / 10,
> +                                           di->ocv_lut);
> +       fcc = interpolate_fcc(temp_degc, di->fcc_lut);
> +
> +       capacity_nodiv = ((fcc * ocv_capacity) / 100 - cc) * 100;
> +       *capacity = div64_ul(capacity_nodiv, fcc);

So I guess you fit the capacity between 0..100, please
add some comment on what's going on here.

> +static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
> +{
> +       struct bms_device_info *di = dev_id;
> +
> +       if (bms_read_ocv(di, &di->ocv) < 0)
> +               return IRQ_HANDLED;
> +
> +       bms_reset_cc(di);
> +       return IRQ_HANDLED;
> +}

So that is a coloumb counter interrupt? Please add some
comment on when this gets called. Is it called whenever
a coloumb is added/removed from the battery?

> +       ret = of_property_read_u8_array(di->dev->of_node,
> +                                                "qcom,ocv-temp-legend",
> +                                                (u8 *)di->ocv_lut.temp_legend,
> +                                                TEMPERATURE_COLS);
> +       if (ret < 0) {
> +               dev_err(di->dev, "no ocv temperature legend found");
> +               return ret;
> +       }
> +
> +       di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
> +                                                "qcom,ocv-capacity-legend",
> +                                                di->ocv_lut.capacity_legend, 0,
> +                                                MAX_CAPACITY_ROWS);
> +       if (di->ocv_lut.rows < 0) {
> +               dev_err(di->dev, "no ocv capacity legend found");
> +               return ret;
> +       }
> +
> +       ret = of_property_read_variable_u16_array(di->dev->of_node,
> +                                                 "qcom,ocv-lut",
> +                                                 (u16 *)di->ocv_lut.lut,
> +                                                 TEMPERATURE_COLS,
> +                                                 TEMPERATURE_COLS *
> +                                                 MAX_CAPACITY_ROWS);
> +       if (ret < 0) {
> +               dev_err(di->dev, "no ocv lut array found");
> +               return ret;
> +       }
> +
> +       ret = of_property_read_u8_array(di->dev->of_node,
> +                                                "qcom,fcc-temp-legend",
> +                                                (u8 *)di->fcc_lut.temp_legend,
> +                                                TEMPERATURE_COLS);
> +       if (ret < 0) {
> +               dev_err(di->dev, "no fcc temperature legend found");
> +               return ret;
> +       }
> +
> +       ret = of_property_read_u16_array(di->dev->of_node,
> +                                                 "qcom,fcc-lut",
> +                                                 di->fcc_lut.lut,
> +                                                 TEMPERATURE_COLS);
> +       if (ret < 0) {
> +               dev_err(di->dev, "no fcc lut array found");
> +               return ret;
> +       }

These tables (that I also suggest to use libraries to parse)
should probably have standardized DT names so other
battery drivers can use the same properties and we can
use the same DT parsing code for all.

> +       ret = bms_read_ocv(di, &di->ocv);
> +       if (ret < 0) {
> +               dev_err(di->dev, "failed to read initial ocv: %d", ret);
> +               return ret;
> +       }

OCV = original coloumb counter value?

Please expand the acronym somewhere because I get
a bit lost.

Overall it is a very nicely coded driver. My worries are
all about code reuse, not code quality per se.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-04-26 11:34   ` [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Linus Walleij
@ 2018-04-30 18:06     ` Craig Tatlor
  0 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-04-30 18:06 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Antonio Ospite, Hans Verkuil, Jonathan Cameron, linux-arm-msm,
	Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

Thanks for review, replies inline.

On Thu, Apr 26, 2018 at 01:34:00PM +0200, Linus Walleij wrote:
> On Sat, Apr 7, 2018 at 7:57 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:
> 
> Hi Craig! Thanks for your patch!
> 
> > This patch adds a driver for the BMS (Battery Monitoring System)
> > block of the PM8941 PMIC, it uses a lookup table defined in the
> > device tree to generate a capacity from the BMS supplied OCV, it
> > then ammends the coulomb counter to that to increase the accuracy
> > of the estimated capacity.
> >
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> 
> Just some minor remarks.
> 
> NB: I see that you are writing from a private email address
> so if you're working as a hobbyist on your precious sparetime
> I have lower expectation on how much work you will put into
> this, so see it more as suggestions than demands.
Yeah, I am a just hobbyist :)
> 
> My overall feedback is that for algorithmic charger what
> we need is infrastructure. What is currently piling up in
> drivers/power/supply scares me a bit in it's lack of
> framework and code reuse.
> 
> It also scares me because this is vital technology dealing
> with physical devices and as such really need to have
> modularized reusable reviewed code with several users
> and deployments.
> 
> Code reuse would include:
> 
> - Mathematical helpers such as interpolation of
>   values from absolute values or tables
>   Suggestions below!
> - State machines and transitions
> - CC/CV alorithms (using the above)
> - Many other things
> 
> Not that *I* can make the situation much better, I'm just
> sharing my fears,
> 
> > +static s64 sign_extend_s36(uint64_t raw)
> > +{
> > +       raw = raw & CC_36_BIT_MASK;
> > +
> > +       return (raw >> 35) == 0LL ?
> > +               raw : (SIGN_EXTEND_36_TO_64_MASK | raw);
> > +}
> 
> #include <linux/bitops.h>
> 
> Use sign_extend32()
Right.
> 
> > +static unsigned int interpolate(int y0, int x0, int y1, int x1, int x)
> > +{
> > +       if (y0 == y1 || x == x0)
> > +               return y0;
> > +       if (x1 == x0 || x == x1)
> > +               return y1;
> > +
> > +       return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
> > +}
> > +
> > +static unsigned int between(int left, int right, int val)
> > +{
> > +       if (left <= val && val <= right)
> > +               return 1;
> > +
> > +       return 0;
> > +}
> 
> How are these things not library functions?
> 
> Every cell of my brain says this code should be reusable.
> 
> Can you put this in <linux/fixp-arith.h>?
> 
> I bet a million to one that the video people will sooner or later
> need linear interpolation and there are more users in the kernel
> than drivers/power/, certainly drivers/iio as well.
> 
> If noone else says anything I vote to put at least the linear
> interpolation into <linux/fixp-arith.h> with a bonus if you
> move some of the current users in drivers/power over
> while you're at it.
I was pretty surprised there wasn't a library function for it
aswell, i will add it there. 
> 
> > +static unsigned int interpolate_capacity(int temp, u16 ocv,
> > +                               struct bms_ocv_lut ocv_lut)
> > +{
> > +       unsigned int pcj_minus_one = 0, pcj = 0;
> > +       int i, j;
> > +
> > +       for (j = 0; j < TEMPERATURE_COLS; j++)
> > +               if (temp <= ocv_lut.temp_legend[j])
> > +                       break;
> > +
> > +       if (ocv >= ocv_lut.lut[0][j])
> > +               return ocv_lut.capacity_legend[0];
> > +
> > +       if (ocv <= ocv_lut.lut[ocv_lut.rows - 1][j - 1])
> > +               return ocv_lut.capacity_legend[ocv_lut.rows - 1];
> > +
> > +       for (i = 0; i < ocv_lut.rows - 1; i++) {
> > +               if (pcj == 0 && between(ocv_lut.lut[i][j],
> > +                                       ocv_lut.lut[i+1][j], ocv))
> > +                       pcj = interpolate(ocv_lut.capacity_legend[i],
> > +                                         ocv_lut.lut[i][j],
> > +                                         ocv_lut.capacity_legend[i + 1],
> > +                                         ocv_lut.lut[i+1][j],
> > +                                         ocv);
> > +
> > +               if (pcj_minus_one == 0 && between(ocv_lut.lut[i][j-1],
> > +                                                 ocv_lut.lut[i+1][j-1], ocv))
> > +                       pcj_minus_one = interpolate(ocv_lut.capacity_legend[i],
> > +                                                   ocv_lut.lut[i][j-1],
> > +                                                   ocv_lut.capacity_legend[i + 1],
> > +                                                   ocv_lut.lut[i+1][j-1],
> > +                                                   ocv);
> > +
> > +               if (pcj && pcj_minus_one)
> > +                       return interpolate(pcj_minus_one,
> > +                                          ocv_lut.temp_legend[j-1],
> > +                                          pcj,
> > +                                          ocv_lut.temp_legend[j],
> > +                                          temp);
> > +       }
> 
> This code really needs some comments to tell what is going on
> here. Also I sense that you can break out a smaller function
> for interpolation based on table values, such as a function
> that would take a standard format of tables, look up where we
> are in that table and interpolate from the neighboring values.
Yeah, ill add some comments.
Tbh i'm not really sure how that would work as I interpolate from
values at several different indecies, can you expand ont this?
> 
> People can then later go in and refine the algorithms if they
> e.g. want to introduce spline or RMS interpolation instead
> and we can get better interpolation for everybody.
> 
> > +static unsigned long interpolate_fcc(int temp, struct bms_fcc_lut fcc_lut)
> > +{
> > +       int i, fcc_mv;
> > +
> > +       for (i = 0; i < TEMPERATURE_COLS; i++)
> > +               if (temp <= fcc_lut.temp_legend[i])
> > +                       break;
> > +
> > +       fcc_mv = interpolate(fcc_lut.lut[i - 1],
> > +                            fcc_lut.temp_legend[i - 1],
> > +                            fcc_lut.lut[i],
> > +                            fcc_lut.temp_legend[i],
> > +                            temp);
> > +
> > +       return fcc_mv * 10000;
> > +}
> 
> So then only this would really remain: pass a table and interpolate.
> 
> > +static int bms_lock_output_data(struct bms_device_info *di)
> > +{
> > +       int ret;
> > +
> > +       ret = regmap_update_bits(di->regmap, di->base_addr +
> > +                                REG_BMS_CC_DATA_CTL,
> > +                                BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "failed to lock bms output: %d", ret);
> > +               return ret;
> > +       }
> 
> Reuse of regmap is very nice, thanks for doing it this way.
> 
> > +static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
> > +static void bms_reset_cc(struct bms_device_info *di)
> 
> These indeed need to be mostly hardware-specific so they
> are fine.
> 
Thanks :)
> > +static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
> > +{
> > +       unsigned long ocv_capacity, fcc;
> > +       int ret, temp, temp_degc;
> > +       s64 cc, capacity_nodiv;
> > +
> > +       ret = iio_read_channel_raw(di->adc, &temp);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "failed to read temperature: %d", ret);
> > +               return ret;
> > +       }
> 
> Very nice that you use IIO ADC as a back-end.
> 
> > +       temp_degc = (temp + 500) / 1000;
> 
> That deserves a comment I think. Like what the manual
> says about this and why the raw temperature is given
> like this.
> 
> Maybe you want to use DIV_ROUND_CLOSEST()
> or DIV_ROUND_UP() from <linux/kernel.h> instead
> of just "/"?
> 
> Maybe you want to use that in other places too like
> the below divisions.
That was just converting it to celcius, adding 500 to round it. 
I'll skip that and make bindings use millicelcius.
> 
> > +       ret = bms_read_cc(di, &cc);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "failed to read coulomb counter: %d", ret);
> > +               return ret;
> > +       }
> > +
> > +       ocv_capacity = interpolate_capacity(temp_degc, (di->ocv + 5) / 10,
> > +                                           di->ocv_lut);
> > +       fcc = interpolate_fcc(temp_degc, di->fcc_lut);
> > +
> > +       capacity_nodiv = ((fcc * ocv_capacity) / 100 - cc) * 100;
> > +       *capacity = div64_ul(capacity_nodiv, fcc);
> 
> So I guess you fit the capacity between 0..100, please
> add some comment on what's going on here.
Basically,
1. Read coulomb counter delta since last ocv update
2. Interpolate open circuit voltage (ocv) and full charge capacity (fcc)
3. Math just ammends the coulomb counter delta to the last taken ocv
reading, Used the nodiv variable to make it a bit more but i could
probably just take that out.

Will add something like this in code.
> 
> > +static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
> > +{
> > +       struct bms_device_info *di = dev_id;
> > +
> > +       if (bms_read_ocv(di, &di->ocv) < 0)
> > +               return IRQ_HANDLED;
> > +
> > +       bms_reset_cc(di);
> > +       return IRQ_HANDLED;
> > +}
> 
> So that is a coloumb counter interrupt? Please add some
> comment on when this gets called. Is it called whenever
> a coloumb is added/removed from the battery?
Its called whenever a new open circuit voltage reading happens, which
only occurs when device us using very little power (probably below 10mA).
The coulomb counter is reset because its kept as a delta.
> 
> > +       ret = of_property_read_u8_array(di->dev->of_node,
> > +                                                "qcom,ocv-temp-legend",
> > +                                                (u8 *)di->ocv_lut.temp_legend,
> > +                                                TEMPERATURE_COLS);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "no ocv temperature legend found");
> > +               return ret;
> > +       }
> > +
> > +       di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
> > +                                                "qcom,ocv-capacity-legend",
> > +                                                di->ocv_lut.capacity_legend, 0,
> > +                                                MAX_CAPACITY_ROWS);
> > +       if (di->ocv_lut.rows < 0) {
> > +               dev_err(di->dev, "no ocv capacity legend found");
> > +               return ret;
> > +       }
> > +
> > +       ret = of_property_read_variable_u16_array(di->dev->of_node,
> > +                                                 "qcom,ocv-lut",
> > +                                                 (u16 *)di->ocv_lut.lut,
> > +                                                 TEMPERATURE_COLS,
> > +                                                 TEMPERATURE_COLS *
> > +                                                 MAX_CAPACITY_ROWS);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "no ocv lut array found");
> > +               return ret;
> > +       }
> > +
> > +       ret = of_property_read_u8_array(di->dev->of_node,
> > +                                                "qcom,fcc-temp-legend",
> > +                                                (u8 *)di->fcc_lut.temp_legend,
> > +                                                TEMPERATURE_COLS);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "no fcc temperature legend found");
> > +               return ret;
> > +       }
> > +
> > +       ret = of_property_read_u16_array(di->dev->of_node,
> > +                                                 "qcom,fcc-lut",
> > +                                                 di->fcc_lut.lut,
> > +                                                 TEMPERATURE_COLS);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "no fcc lut array found");
> > +               return ret;
> > +       }
> 
> These tables (that I also suggest to use libraries to parse)
> should probably have standardized DT names so other
> battery drivers can use the same properties and we can
> use the same DT parsing code for all.
Okay, any recommendations on names?
> 
> > +       ret = bms_read_ocv(di, &di->ocv);
> > +       if (ret < 0) {
> > +               dev_err(di->dev, "failed to read initial ocv: %d", ret);
> > +               return ret;
> > +       }
> 
> OCV = original coloumb counter value?
Nope, open circuit voltage.
> 
> Please expand the acronym somewhere because I get
> a bit lost.
Will do.
> 
> Overall it is a very nicely coded driver. My worries are
> all about code reuse, not code quality per se.
Thanks!
> 
> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v5 1/4] fixp-arith: add a linear interpolation function
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                   ` (3 preceding siblings ...)
  2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
@ 2018-06-07 18:12 ` Craig Tatlor
  2018-06-07 18:12   ` [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                     ` (3 more replies)
  2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
                   ` (2 subsequent siblings)
  7 siblings, 4 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-07 18:12 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Andrew Morton, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Adds a function to interpolate against two points,
this is carried arount as a helper function by tons of drivers.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 include/linux/fixp-arith.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h
index d4686fe1cac7..c21de4f358dd 100644
--- a/include/linux/fixp-arith.h
+++ b/include/linux/fixp-arith.h
@@ -153,4 +153,24 @@ static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
 #define fixp_cos32_rad(rad, twopi)	\
 	fixp_sin32_rad(rad + twopi / 4, twopi)
 
+
+/**
+ * fixp_linear_interpolate() - interpolates a value from two known points
+ *
+ * @x0: x value of point 0
+ * @y0: y value of point 0
+ * @x1: x value of point 1
+ * @y1: y value of point 1
+ * @x: the linear interpolant
+ */
+static inline int fixp_linear_interpolate(int x0, int y0, int x1, int y1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
 #endif
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
@ 2018-06-07 18:12   ` Craig Tatlor
  2018-06-07 19:08     ` Randy Dunlap
  2018-06-07 18:12   ` [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-07 18:12 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Andrew Morton, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

This patch adds a driver for the BMS (Battery Monitoring System)
block of the PM8941 PMIC, it uses a lookup table defined in the
device tree to generate a capacity from the BMS supplied OCV, it
then ammends the coulomb counter to that to increase the accuracy
of the estimated capacity.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
* Changes from v4:
  Cleaned up percentage interpolation function,
  uses new fixp interpolation helper,
  added some more error cases,
  uses devm_power_supply_register(),
  uses a DIV_ROUND_CLOSEST for division and
  uses micro(volts / amp hours) instead of
  milli (volts / amp hours).

 drivers/power/supply/Kconfig    |   9 +
 drivers/power/supply/Makefile   |   1 +
 drivers/power/supply/qcom_bms.c | 487 ++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+)
 create mode 100644 drivers/power/supply/qcom_bms.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 428b426842f4..6c354c37bc55 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -82,6 +82,15 @@ config BATTERY_ACT8945A
 	  Say Y here to enable support for power supply provided by
 	  Active-semi ActivePath ACT8945A charger.
 
+config BATTERY_BMS
+	tristate "Qualcomm Battery Monitoring System driver"
+	depends on MFD_SPMI_PMIC || COMPILE_TEST
+	depends on OF
+	depends on REGMAP_SPMI
+	help
+	  Say Y to include support for the Battery Monitoring hardware
+	  found in some Qualcomm PM series PMICs.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index e83aa843bcc6..04204174b047 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
+obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
 obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
new file mode 100644
index 000000000000..e1d6fdbf11d1
--- /dev/null
+++ b/drivers/power/supply/qcom_bms.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL
+
+/*
+ * Qualcomm Battery Monitoring System driver
+ *
+ * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/fixp-arith.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/iio/consumer.h>
+
+#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
+#define REG_BMS_SHDW_CC_DATA0		0xA8
+#define REG_BMS_CC_DATA_CTL		0x42
+#define REG_BMS_CC_CLEAR_CTL		0x4
+
+#define BMS_HOLD_OREG_DATA		BIT(0)
+#define BMS_CLEAR_SHDW_CC		BIT(6)
+
+#define BMS_CC_READING_RESOLUTION_N	542535
+#define BMS_CC_READING_RESOLUTION_D	10000
+#define BMS_CC_READING_TICKS		56
+#define BMS_SLEEP_CLK_HZ		32764
+
+#define SECONDS_PER_HOUR		3600
+#define TEMPERATURE_COLS		5
+#define MAX_CAPACITY_ROWS		50
+
+/* lookup table for ocv -> capacity conversion */
+struct bms_ocv_lut {
+	int rows;
+	s8 temp_legend[TEMPERATURE_COLS];
+	u8 capacity_legend[MAX_CAPACITY_ROWS];
+	u32 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
+};
+
+/* lookup table for battery temperature -> fcc conversion */
+struct bms_fcc_lut {
+	s8 temp_legend[TEMPERATURE_COLS];
+	u32 lut[TEMPERATURE_COLS];
+};
+
+struct bms_device_info {
+	struct device *dev;
+	struct regmap *regmap;
+	struct bms_ocv_lut ocv_lut;
+	struct power_supply_desc bat_desc;
+	struct bms_fcc_lut fcc_lut;
+	struct iio_channel *adc;
+	struct mutex bms_output_lock;
+	u32 base_addr;
+
+	int ocv_thr_irq;
+	u32 ocv;
+};
+
+static bool between(int left, int right, int val)
+{
+	if (left <= val && val <= right)
+		return true;
+
+	if (left >= val && val >= right)
+		return true;
+
+	return false;
+}
+
+static int interpolate_capacity(int temp, u32 ocv,
+				struct bms_ocv_lut *ocv_lut)
+{
+	int pcj_minus_one = 0, pcj = 0, i2 = 0, i3 = 0, i, j;
+
+	for (j = 0; j < TEMPERATURE_COLS; j++)
+		if (temp <= ocv_lut->temp_legend[j])
+			break;
+
+	if (ocv >= ocv_lut->lut[0][j])
+		return ocv_lut->capacity_legend[0];
+
+	if (ocv <= ocv_lut->lut[ocv_lut->rows-1][j-1])
+		return ocv_lut->capacity_legend[ocv_lut->rows-1];
+
+	for (i = 0; i < ocv_lut->rows-1; i++) {
+		if (between(ocv_lut->lut[i][j],
+			    ocv_lut->lut[i+1][j], ocv))
+			i2 = i;
+
+		if (between(ocv_lut->lut[i][j-1],
+			    ocv_lut->lut[i+1][j-1], ocv))
+			i3 = i;
+	}
+
+	/* interpolate two capacities */
+	pcj = fixp_linear_interpolate(ocv_lut->lut[i2][j],
+				      ocv_lut->capacity_legend[i2],
+				      ocv_lut->lut[i2+1][j],
+				      ocv_lut->capacity_legend[i2+1],
+				      ocv);
+
+	pcj_minus_one = fixp_linear_interpolate(ocv_lut->lut[i3][j-1],
+						ocv_lut->capacity_legend[i3],
+						ocv_lut->lut[i3+1][j-1],
+						ocv_lut->capacity_legend[i3+1],
+						ocv);
+
+	/* interpolate them with the battery temperature */
+	return fixp_linear_interpolate(ocv_lut->temp_legend[j-1],
+				       pcj_minus_one,
+				       ocv_lut->temp_legend[j],
+				       pcj,
+				       temp);
+}
+
+static int interpolate_fcc(int temp, struct bms_fcc_lut *fcc_lut)
+{
+	int i;
+
+	for (i = 0; i < TEMPERATURE_COLS; i++)
+		if (temp <= fcc_lut->temp_legend[i])
+			break;
+
+	return fixp_linear_interpolate(fcc_lut->temp_legend[i-1],
+			     fcc_lut->lut[i-1],
+			     fcc_lut->temp_legend[i],
+			     fcc_lut->lut[i],
+			     temp);
+}
+
+static int bms_lock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
+	if (ret) {
+		dev_err(di->dev, "failed to lock bms output: %d", ret);
+		return ret;
+	}
+
+	/*
+	 * Sleep for at least 100 microseconds here to make sure
+	 * there has been at least three cycles of the sleep clock
+	 * so that the registers are correctly locked.
+	 */
+	usleep_range(100, 1000);
+
+	return 0;
+}
+
+static int bms_unlock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, 0);
+	if (ret) {
+		dev_err(di->dev, "failed to unlock bms output: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bms_read_ocv(struct bms_device_info *di, u32 *ocv)
+{
+	int ret;
+	u16 read_ocv;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr+
+			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
+	if (ret) {
+		dev_err(di->dev, "open circuit voltage read failed: %d", ret);
+		goto err_read;
+	}
+
+	dev_dbg(di->dev, "read open circuit voltage of: %d mv", read_ocv);
+
+
+	*ocv = read_ocv * 1000;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
+{
+	int ret;
+	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_SHDW_CC_DATA0,
+			       &cc_raw_s36, 5);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter read failed: %d", ret);
+		goto err_read;
+	}
+
+	ret = bms_unlock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	mutex_unlock(&di->bms_output_lock);
+
+	cc_raw = sign_extend32(cc_raw_s36, 28);
+
+	/* convert raw to uv */
+	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
+			BMS_CC_READING_RESOLUTION_D);
+
+	/* convert uv to pvh */
+	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
+			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR);
+
+	/* divide by impedance */
+	*cc_uah = div_s64(cc_pvh, 10000);
+
+	dev_dbg(di->dev, "read coulomb counter value of: %lld uah", *cc_uah);
+
+	return 0;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static void bms_reset_cc(struct bms_device_info *di)
+{
+	int ret;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC,
+				 BMS_CLEAR_SHDW_CC);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
+		goto err_lock;
+	}
+
+	/* wait at least three sleep cycles for cc to reset */
+	usleep_range(100, 1000);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC, 0);
+	if (ret)
+		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+}
+
+static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
+{
+	unsigned long fcc;
+	int ret, temp, ocv_capacity, temp_degc;
+	s64 cc = 0;
+
+	ret = iio_read_channel_raw(di->adc, &temp);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read temperature: %d", ret);
+		return ret;
+	}
+
+	temp_degc = DIV_ROUND_CLOSEST(temp, 1000);
+
+	ret = bms_read_cc(di, &cc);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
+		return ret;
+	}
+
+	/* interpolate capacity from open circuit voltage */
+	ocv_capacity = interpolate_capacity(temp_degc, di->ocv,
+					    &di->ocv_lut);
+
+	/* interpolate the full charge capacity from temperature */
+	fcc = interpolate_fcc(temp_degc, &di->fcc_lut);
+
+	/* append coloumb counter to capacity */
+	*capacity = DIV_ROUND_CLOSEST(fcc * ocv_capacity, 100);
+	*capacity = div_s64((*capacity - cc) * 100, fcc);
+
+	return 0;
+}
+
+
+
+/*
+ * Return power_supply property
+ */
+static int bms_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct bms_device_info *di = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = bms_calculate_capacity(di, &val->intval);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (val->intval == INT_MAX || val->intval == INT_MIN)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static enum power_supply_property bms_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
+{
+	struct bms_device_info *di = dev_id;
+
+	if (bms_read_ocv(di, &di->ocv) < 0)
+		return IRQ_HANDLED;
+
+	bms_reset_cc(di);
+	return IRQ_HANDLED;
+}
+
+static int bms_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct bms_device_info *di;
+	struct power_supply *bat;
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	di->dev = &pdev->dev;
+
+	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!di->regmap) {
+		dev_err(di->dev, "Unable to get regmap");
+		return -EINVAL;
+	}
+
+	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
+	if (IS_ERR(di->adc))
+		return PTR_ERR(di->adc);
+
+	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,ocv-temp-legend-celsius",
+						 (u8 *)di->ocv_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage temperature legend found");
+		return ret;
+	}
+
+	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
+						 "qcom,ocv-capacity-legend",
+						 di->ocv_lut.capacity_legend, 0,
+						 MAX_CAPACITY_ROWS);
+	if (di->ocv_lut.rows < 0) {
+		dev_err(di->dev, "no open circuit voltage capacity legend found");
+		return ret;
+	}
+
+	ret = of_property_read_variable_u32_array(di->dev->of_node,
+						  "qcom,ocv-lut-microvolt",
+						  (u32 *)di->ocv_lut.lut,
+						  TEMPERATURE_COLS,
+						  TEMPERATURE_COLS *
+						  MAX_CAPACITY_ROWS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage lut array found");
+		return ret;
+	}
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,fcc-temp-legend-celsius",
+						 (u8 *)di->fcc_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity temperature legend found");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(di->dev->of_node,
+						  "qcom,fcc-lut-microamp-hours",
+						  di->fcc_lut.lut,
+						  TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity lut array found");
+		return ret;
+	}
+
+	ret = bms_read_ocv(di, &di->ocv);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read initial open circuit voltage: %d",
+			ret);
+		return ret;
+	}
+
+	mutex_init(&di->bms_output_lock);
+
+	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
+
+	ret = devm_request_threaded_irq(di->dev, di->ocv_thr_irq, NULL,
+					bms_ocv_thr_irq_handler,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, di);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to request handler for open circuit voltage threshold IRQ");
+		return ret;
+	}
+
+
+	di->bat_desc.name = "bms";
+	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat_desc.properties = bms_props;
+	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
+	di->bat_desc.get_property = bms_get_property;
+
+	psy_cfg.drv_data = di;
+	bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
+
+	return PTR_ERR_OR_ZERO(bat);
+}
+
+static const struct of_device_id bms_of_match[] = {
+	{.compatible = "qcom,pm8941-bms", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bms_of_match);
+
+static struct platform_driver bms_driver = {
+	.probe = bms_probe,
+	.driver = {
+		.name = "qcom-bms",
+		.of_match_table = of_match_ptr(bms_of_match),
+	},
+};
+module_platform_driver(bms_driver);
+
+MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm BMS driver");
+MODULE_LICENSE("GPL");
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
  2018-06-07 18:12   ` [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-06-07 18:12   ` Craig Tatlor
  2018-06-11 18:15     ` Rob Herring
  2018-06-07 18:12   ` [PATCH v5 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2018-06-13 11:06   ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Linus Walleij
  3 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-07 18:12 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Andrew Morton, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Add bindings for the Qualcomm Battery Monitoring system.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
* Changes from v4:
  Uses proper units and expands some definitions,
  along with changing vadc@ to adc@.

 .../bindings/power/supply/qcom_bms.txt        | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt

diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
new file mode 100644
index 000000000000..a1a32d6ab460
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
@@ -0,0 +1,91 @@
+Qualcomm Battery Monitoring System
+
+The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
+PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
+that allow the OS to infer a capacity level.
+
+Required properties:
+- compatible:                   Should contain "qcom,pm8941-bms".
+- reg:                          Specifies the SPMI address and length of the
+				controller's registers.
+- interrupts:                   OCV threshold interrupt.
+- io-channels:                  Should contain IIO channel specifier for the
+				ADC channel that reports battery temperature.
+- io-channel-names:             Should contain "temp".
+- qcom,fcc-temp-legend-celcius: An array containing the temperature, in degC,
+				for each column of the full charge capacity
+				lookup table.
+- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uah,
+				one entry for each temperature defined in in
+				qcom,fcc-temp-legend-celcius.
+- qcom,ocv-temp-legend-celcius: An array containing the temperature, in degC,
+				for each column of the OCV lookup table.
+- qcom,ocv-capacity-legend:     An array containing the capacity for each
+				row of the OCV lookup table.
+- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
+				capacity defined in qcom,ocv-capacity-legend.
+
+Example:
+		pm8941_vadc: adc@3100 {
+			compatible = "qcom,spmi-vadc";
+			reg = <0x3100>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+
+			bat_temp {
+				reg = <VADC_LR_MUX1_BAT_THERM>;
+			};
+		};
+
+		bms@4000 {
+			compatible = "qcom,pm8941-bms";
+			reg = <0x4000>;
+			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ocv_thr";
+
+			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
+			io-channel-names = "temp";
+
+			qcom,fcc-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,fcc-lut-microamp-hours = <3230000 3260000 3380000 3410000 3360000>;
+
+			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75
+							     70 65 60 55 50 45
+							     40 35 30 25 20 15
+							     10 9 8 7 6 5 4 3 2
+							     1 0>;
+			qcom,ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,ocv-lut-microvolt = <43050000 43050000 43030000 42990000 42950000
+						  42770000 42570000 42550000 42510000 42310000
+						  42180000 41980000 41970000 41920000 41720000
+						  41590000 41390000 41450000 41400000 41200000
+						  41010000 40810000 40920000 40890000 40690000
+						  40480000 40280000 40440000 40420000 40220000
+						  40040000 39840000 40010000 39980000 39780000
+						  39620000 39420000 39550000 39560000 39360000
+						  39210000 39010000 39090000 39160000 38960000
+						  38830000 38630000 38740000 38790000 38590000
+						  38550000 38350000 38440000 38430000 38230000
+						  38310000 38110000 38230000 38180000 37980000
+						  38190000 37990000 38040000 38000000 37800000
+						  38060000 37860000 37900000 37840000 37640000
+						  37890000 37690000 37770000 37660000 37460000
+						  37720000 37520000 37560000 37450000 37250000
+						  37480000 37280000 37290000 37250000 37050000
+						  37240000 37040000 37020000 36990000 36790000
+						  37030000 36830000 36730000 36700000 36500000
+						  36940000 36740000 36670000 36640000 36440000
+						  36850000 36650000 36600000 36590000 36390000
+						  36750000 36550000 36520000 36550000 36350000
+						  36690000 36490000 36380000 36400000 36200000
+						  36460000 36260000 36180000 36120000 35920000
+						  36080000 35880000 35680000 35640000 35440000
+						  35510000 35310000 35050000 35020000 34820000
+						  34730000 34530000 34300000 34250000 34050000
+						  33870000 33670000 33040000 32820000 32620000
+						  30000000 30000000 30000000 30000000 30000000>;
+		};
+	};
+};
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v5 4/4] MAINTAINERS: Add entry for the Qualcomm BMS
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
  2018-06-07 18:12   ` [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
  2018-06-07 18:12   ` [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-06-07 18:12   ` Craig Tatlor
  2018-06-13 11:06   ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Linus Walleij
  3 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-07 18:12 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Greg Kroah-Hartman, Andrew Morton, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9c125f705f78..be485caf9313 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11646,6 +11646,12 @@ W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
+QUALCOMM BATTERY MONITORING SYSTEM
+M:	Craig Tatlor <ctatlor97@gmail.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/qcom_bms.c
+
 QUALCOMM CAMERA SUBSYSTEM DRIVER
 M:	Todor Tomov <todor.tomov@linaro.org>
 L:	linux-media@vger.kernel.org
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-07 18:12   ` [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-06-07 19:08     ` Randy Dunlap
  2018-06-13 15:58       ` Craig Tatlor
  0 siblings, 1 reply; 60+ messages in thread
From: Randy Dunlap @ 2018-06-07 19:08 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Linus Walleij, linux-pm, devicetree, linux-kernel

On 06/07/2018 11:12 AM, Craig Tatlor wrote:
> This patch adds a driver for the BMS (Battery Monitoring System)
> block of the PM8941 PMIC, it uses a lookup table defined in the
> device tree to generate a capacity from the BMS supplied OCV, it
> then ammends the coulomb counter to that to increase the accuracy

       amends

> of the estimated capacity.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---

> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 428b426842f4..6c354c37bc55 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -82,6 +82,15 @@ config BATTERY_ACT8945A
>  	  Say Y here to enable support for power supply provided by
>  	  Active-semi ActivePath ACT8945A charger.
>  
> +config BATTERY_BMS
> +	tristate "Qualcomm Battery Monitoring System driver"
> +	depends on MFD_SPMI_PMIC || COMPILE_TEST
> +	depends on OF
> +	depends on REGMAP_SPMI

	select REGMAP_SPMI

I'm not a fan of "select", but it does not have a prompt string so it isn't
user settable (not directly; it can be set indirectly).
And all other uses of it in Kconfig files use "select".

> +	help
> +	  Say Y to include support for the Battery Monitoring hardware
> +	  found in some Qualcomm PM series PMICs.
> +
>  config BATTERY_CPCAP
>  	tristate "Motorola CPCAP PMIC battery driver"
>  	depends on MFD_CPCAP && IIO


-- 
~Randy

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-07 18:12   ` [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-06-11 18:15     ` Rob Herring
  2018-06-13 16:00       ` Craig Tatlor
  0 siblings, 1 reply; 60+ messages in thread
From: Rob Herring @ 2018-06-11 18:15 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Linus Walleij, Randy Dunlap, linux-pm, devicetree,
	linux-kernel

On Thu, Jun 07, 2018 at 07:12:51PM +0100, Craig Tatlor wrote:
> Add bindings for the Qualcomm Battery Monitoring system.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
> * Changes from v4:
>   Uses proper units and expands some definitions,
>   along with changing vadc@ to adc@.
> 
>  .../bindings/power/supply/qcom_bms.txt        | 91 +++++++++++++++++++
>  1 file changed, 91 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> new file mode 100644
> index 000000000000..a1a32d6ab460
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> @@ -0,0 +1,91 @@
> +Qualcomm Battery Monitoring System
> +
> +The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
> +PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
> +that allow the OS to infer a capacity level.
> +
> +Required properties:
> +- compatible:                   Should contain "qcom,pm8941-bms".
> +- reg:                          Specifies the SPMI address and length of the
> +				controller's registers.
> +- interrupts:                   OCV threshold interrupt.
> +- io-channels:                  Should contain IIO channel specifier for the
> +				ADC channel that reports battery temperature.
> +- io-channel-names:             Should contain "temp".
> +- qcom,fcc-temp-legend-celcius: An array containing the temperature, in degC,
> +				for each column of the full charge capacity
> +				lookup table.
> +- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uah,
> +				one entry for each temperature defined in in
> +				qcom,fcc-temp-legend-celcius.
> +- qcom,ocv-temp-legend-celcius: An array containing the temperature, in degC,
> +				for each column of the OCV lookup table.
> +- qcom,ocv-capacity-legend:     An array containing the capacity for each
> +				row of the OCV lookup table.
> +- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
> +				capacity defined in qcom,ocv-capacity-legend.

Need to say which of these are 8-bit values.

With that,

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 1/4] fixp-arith: add a linear interpolation function
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
                     ` (2 preceding siblings ...)
  2018-06-07 18:12   ` [PATCH v5 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
@ 2018-06-13 11:06   ` Linus Walleij
  2018-06-13 11:12     ` Linus Walleij
  3 siblings, 1 reply; 60+ messages in thread
From: Linus Walleij @ 2018-06-13 11:06 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Thu, Jun 7, 2018 at 8:12 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:

> Adds a function to interpolate against two points,
> this is carried arount as a helper function by tons of drivers.
>
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>

The linear formula seems to fit the most natural form of linear
interpolation.

I bet some John Carmack algorithm type people will soon
start to optimize this... :D

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 1/4] fixp-arith: add a linear interpolation function
  2018-06-13 11:06   ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Linus Walleij
@ 2018-06-13 11:12     ` Linus Walleij
  2018-06-13 16:01       ` Craig Tatlor
  0 siblings, 1 reply; 60+ messages in thread
From: Linus Walleij @ 2018-06-13 11:12 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Wed, Jun 13, 2018 at 1:06 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Thu, Jun 7, 2018 at 8:12 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:
>
>> Adds a function to interpolate against two points,
>> this is carried arount as a helper function by tons of drivers.
>>
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>
> The linear formula seems to fit the most natural form of linear
> interpolation.
>
> I bet some John Carmack algorithm type people will soon
> start to optimize this... :D

For your entertainment here is some sunday reading:
https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-07 19:08     ` Randy Dunlap
@ 2018-06-13 15:58       ` Craig Tatlor
  0 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 15:58 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Linus Walleij, linux-pm, devicetree, linux-kernel

On Thu, Jun 07, 2018 at 12:08:20PM -0700, Randy Dunlap wrote:
> On 06/07/2018 11:12 AM, Craig Tatlor wrote:
> > This patch adds a driver for the BMS (Battery Monitoring System)
> > block of the PM8941 PMIC, it uses a lookup table defined in the
> > device tree to generate a capacity from the BMS supplied OCV, it
> > then ammends the coulomb counter to that to increase the accuracy
> 
>        amends
> 
> > of the estimated capacity.
> > 
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> > ---
> 
> > diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> > index 428b426842f4..6c354c37bc55 100644
> > --- a/drivers/power/supply/Kconfig
> > +++ b/drivers/power/supply/Kconfig
> > @@ -82,6 +82,15 @@ config BATTERY_ACT8945A
> >  	  Say Y here to enable support for power supply provided by
> >  	  Active-semi ActivePath ACT8945A charger.
> >  
> > +config BATTERY_BMS
> > +	tristate "Qualcomm Battery Monitoring System driver"
> > +	depends on MFD_SPMI_PMIC || COMPILE_TEST
> > +	depends on OF
> > +	depends on REGMAP_SPMI
> 
> 	select REGMAP_SPMI
> 
> I'm not a fan of "select", but it does not have a prompt string so it isn't
> user settable (not directly; it can be set indirectly).
> And all other uses of it in Kconfig files use "select".
> 
> > +	help
> > +	  Say Y to include support for the Battery Monitoring hardware
> > +	  found in some Qualcomm PM series PMICs.
> > +
> >  config BATTERY_CPCAP
> >  	tristate "Motorola CPCAP PMIC battery driver"
> >  	depends on MFD_CPCAP && IIO
> 
Thanks for the review.
> 
> -- 
> ~Randy

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-11 18:15     ` Rob Herring
@ 2018-06-13 16:00       ` Craig Tatlor
  0 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:00 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-arm-msm, Sebastian Reichel, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Linus Walleij, Randy Dunlap, linux-pm, devicetree,
	linux-kernel

On Mon, Jun 11, 2018 at 12:15:15PM -0600, Rob Herring wrote:
> On Thu, Jun 07, 2018 at 07:12:51PM +0100, Craig Tatlor wrote:
> > Add bindings for the Qualcomm Battery Monitoring system.
> > 
> > Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> > ---
> > * Changes from v4:
> >   Uses proper units and expands some definitions,
> >   along with changing vadc@ to adc@.
> > 
> >  .../bindings/power/supply/qcom_bms.txt        | 91 +++++++++++++++++++
> >  1 file changed, 91 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > new file mode 100644
> > index 000000000000..a1a32d6ab460
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> > @@ -0,0 +1,91 @@
> > +Qualcomm Battery Monitoring System
> > +
> > +The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
> > +PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
> > +that allow the OS to infer a capacity level.
> > +
> > +Required properties:
> > +- compatible:                   Should contain "qcom,pm8941-bms".
> > +- reg:                          Specifies the SPMI address and length of the
> > +				controller's registers.
> > +- interrupts:                   OCV threshold interrupt.
> > +- io-channels:                  Should contain IIO channel specifier for the
> > +				ADC channel that reports battery temperature.
> > +- io-channel-names:             Should contain "temp".
> > +- qcom,fcc-temp-legend-celcius: An array containing the temperature, in degC,
> > +				for each column of the full charge capacity
> > +				lookup table.
> > +- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uah,
> > +				one entry for each temperature defined in in
> > +				qcom,fcc-temp-legend-celcius.
> > +- qcom,ocv-temp-legend-celcius: An array containing the temperature, in degC,
> > +				for each column of the OCV lookup table.
> > +- qcom,ocv-capacity-legend:     An array containing the capacity for each
> > +				row of the OCV lookup table.
> > +- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
> > +				capacity defined in qcom,ocv-capacity-legend.
> 
> Need to say which of these are 8-bit values.
> 
> With that,
> 
> Reviewed-by: Rob Herring <robh@kernel.org>

Thanks for the review, will mark as 8 bit in v6

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v5 1/4] fixp-arith: add a linear interpolation function
  2018-06-13 11:12     ` Linus Walleij
@ 2018-06-13 16:01       ` Craig Tatlor
  0 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:01 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Wed, Jun 13, 2018 at 01:12:45PM +0200, Linus Walleij wrote:
> On Wed, Jun 13, 2018 at 1:06 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Thu, Jun 7, 2018 at 8:12 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:
> >
> >> Adds a function to interpolate against two points,
> >> this is carried arount as a helper function by tons of drivers.
> >>
> >> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> >
> > The linear formula seems to fit the most natural form of linear
> > interpolation.
> >
> > I bet some John Carmack algorithm type people will soon
> > start to optimize this... :D
> 
> For your entertainment here is some sunday reading:
> https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
> 
> Yours,
> Linus Walleij

Thanks, interesting read.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v6 1/4] fixp-arith: add a linear interpolation function
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                   ` (4 preceding siblings ...)
  2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
@ 2018-06-13 16:06 ` Craig Tatlor
  2018-06-13 16:06   ` [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                     ` (2 more replies)
  2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
  7 siblings, 3 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:06 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Adds a function to interpolate against two points,
this is carried arount as a helper function by tons of drivers.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 include/linux/fixp-arith.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h
index d4686fe1cac7..c21de4f358dd 100644
--- a/include/linux/fixp-arith.h
+++ b/include/linux/fixp-arith.h
@@ -153,4 +153,24 @@ static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
 #define fixp_cos32_rad(rad, twopi)	\
 	fixp_sin32_rad(rad + twopi / 4, twopi)
 
+
+/**
+ * fixp_linear_interpolate() - interpolates a value from two known points
+ *
+ * @x0: x value of point 0
+ * @y0: y value of point 0
+ * @x1: x value of point 1
+ * @y1: y value of point 1
+ * @x: the linear interpolant
+ */
+static inline int fixp_linear_interpolate(int x0, int y0, int x1, int y1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
 #endif
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
@ 2018-06-13 16:06   ` Craig Tatlor
  2018-06-14 14:06     ` Linus Walleij
  2018-06-13 16:06   ` [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
  2018-06-13 16:06   ` [PATCH v6 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:06 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

This patch adds a driver for the BMS (Battery Monitoring System)
block of the PM8941 PMIC, it uses a lookup table defined in the
device tree to generate a capacity from the BMS supplied OCV, it
then amends the coulomb counter to that to increase the accuracy
of the estimated capacity.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---

* Changes from v5:
  Uses select for REGMAP_SPMI.

* Changes from v4:
  Cleaned up percentage interpolation function,
  uses new fixp interpolation helper,
  added some more error cases,
  uses devm_power_supply_register(),
  uses a DIV_ROUND_CLOSEST for division and
  uses micro(volts / amp hours) instead of
  milli (volts / amp hours).

 drivers/power/supply/Kconfig    |   9 +
 drivers/power/supply/Makefile   |   1 +
 drivers/power/supply/qcom_bms.c | 487 ++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+)
 create mode 100644 drivers/power/supply/qcom_bms.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 428b426842f4..75f2f375f992 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -82,6 +82,15 @@ config BATTERY_ACT8945A
 	  Say Y here to enable support for power supply provided by
 	  Active-semi ActivePath ACT8945A charger.
 
+config BATTERY_BMS
+	tristate "Qualcomm Battery Monitoring System driver"
+	depends on MFD_SPMI_PMIC || COMPILE_TEST
+	depends on OF
+	select REGMAP_SPMI
+	help
+	  Say Y to include support for the Battery Monitoring hardware
+	  found in some Qualcomm PM series PMICs.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index e83aa843bcc6..04204174b047 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
+obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
 obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
new file mode 100644
index 000000000000..e1d6fdbf11d1
--- /dev/null
+++ b/drivers/power/supply/qcom_bms.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL
+
+/*
+ * Qualcomm Battery Monitoring System driver
+ *
+ * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/fixp-arith.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/iio/consumer.h>
+
+#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
+#define REG_BMS_SHDW_CC_DATA0		0xA8
+#define REG_BMS_CC_DATA_CTL		0x42
+#define REG_BMS_CC_CLEAR_CTL		0x4
+
+#define BMS_HOLD_OREG_DATA		BIT(0)
+#define BMS_CLEAR_SHDW_CC		BIT(6)
+
+#define BMS_CC_READING_RESOLUTION_N	542535
+#define BMS_CC_READING_RESOLUTION_D	10000
+#define BMS_CC_READING_TICKS		56
+#define BMS_SLEEP_CLK_HZ		32764
+
+#define SECONDS_PER_HOUR		3600
+#define TEMPERATURE_COLS		5
+#define MAX_CAPACITY_ROWS		50
+
+/* lookup table for ocv -> capacity conversion */
+struct bms_ocv_lut {
+	int rows;
+	s8 temp_legend[TEMPERATURE_COLS];
+	u8 capacity_legend[MAX_CAPACITY_ROWS];
+	u32 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
+};
+
+/* lookup table for battery temperature -> fcc conversion */
+struct bms_fcc_lut {
+	s8 temp_legend[TEMPERATURE_COLS];
+	u32 lut[TEMPERATURE_COLS];
+};
+
+struct bms_device_info {
+	struct device *dev;
+	struct regmap *regmap;
+	struct bms_ocv_lut ocv_lut;
+	struct power_supply_desc bat_desc;
+	struct bms_fcc_lut fcc_lut;
+	struct iio_channel *adc;
+	struct mutex bms_output_lock;
+	u32 base_addr;
+
+	int ocv_thr_irq;
+	u32 ocv;
+};
+
+static bool between(int left, int right, int val)
+{
+	if (left <= val && val <= right)
+		return true;
+
+	if (left >= val && val >= right)
+		return true;
+
+	return false;
+}
+
+static int interpolate_capacity(int temp, u32 ocv,
+				struct bms_ocv_lut *ocv_lut)
+{
+	int pcj_minus_one = 0, pcj = 0, i2 = 0, i3 = 0, i, j;
+
+	for (j = 0; j < TEMPERATURE_COLS; j++)
+		if (temp <= ocv_lut->temp_legend[j])
+			break;
+
+	if (ocv >= ocv_lut->lut[0][j])
+		return ocv_lut->capacity_legend[0];
+
+	if (ocv <= ocv_lut->lut[ocv_lut->rows-1][j-1])
+		return ocv_lut->capacity_legend[ocv_lut->rows-1];
+
+	for (i = 0; i < ocv_lut->rows-1; i++) {
+		if (between(ocv_lut->lut[i][j],
+			    ocv_lut->lut[i+1][j], ocv))
+			i2 = i;
+
+		if (between(ocv_lut->lut[i][j-1],
+			    ocv_lut->lut[i+1][j-1], ocv))
+			i3 = i;
+	}
+
+	/* interpolate two capacities */
+	pcj = fixp_linear_interpolate(ocv_lut->lut[i2][j],
+				      ocv_lut->capacity_legend[i2],
+				      ocv_lut->lut[i2+1][j],
+				      ocv_lut->capacity_legend[i2+1],
+				      ocv);
+
+	pcj_minus_one = fixp_linear_interpolate(ocv_lut->lut[i3][j-1],
+						ocv_lut->capacity_legend[i3],
+						ocv_lut->lut[i3+1][j-1],
+						ocv_lut->capacity_legend[i3+1],
+						ocv);
+
+	/* interpolate them with the battery temperature */
+	return fixp_linear_interpolate(ocv_lut->temp_legend[j-1],
+				       pcj_minus_one,
+				       ocv_lut->temp_legend[j],
+				       pcj,
+				       temp);
+}
+
+static int interpolate_fcc(int temp, struct bms_fcc_lut *fcc_lut)
+{
+	int i;
+
+	for (i = 0; i < TEMPERATURE_COLS; i++)
+		if (temp <= fcc_lut->temp_legend[i])
+			break;
+
+	return fixp_linear_interpolate(fcc_lut->temp_legend[i-1],
+			     fcc_lut->lut[i-1],
+			     fcc_lut->temp_legend[i],
+			     fcc_lut->lut[i],
+			     temp);
+}
+
+static int bms_lock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
+	if (ret) {
+		dev_err(di->dev, "failed to lock bms output: %d", ret);
+		return ret;
+	}
+
+	/*
+	 * Sleep for at least 100 microseconds here to make sure
+	 * there has been at least three cycles of the sleep clock
+	 * so that the registers are correctly locked.
+	 */
+	usleep_range(100, 1000);
+
+	return 0;
+}
+
+static int bms_unlock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, 0);
+	if (ret) {
+		dev_err(di->dev, "failed to unlock bms output: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bms_read_ocv(struct bms_device_info *di, u32 *ocv)
+{
+	int ret;
+	u16 read_ocv;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr+
+			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
+	if (ret) {
+		dev_err(di->dev, "open circuit voltage read failed: %d", ret);
+		goto err_read;
+	}
+
+	dev_dbg(di->dev, "read open circuit voltage of: %d mv", read_ocv);
+
+
+	*ocv = read_ocv * 1000;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
+{
+	int ret;
+	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_SHDW_CC_DATA0,
+			       &cc_raw_s36, 5);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter read failed: %d", ret);
+		goto err_read;
+	}
+
+	ret = bms_unlock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	mutex_unlock(&di->bms_output_lock);
+
+	cc_raw = sign_extend32(cc_raw_s36, 28);
+
+	/* convert raw to uv */
+	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
+			BMS_CC_READING_RESOLUTION_D);
+
+	/* convert uv to pvh */
+	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
+			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR);
+
+	/* divide by impedance */
+	*cc_uah = div_s64(cc_pvh, 10000);
+
+	dev_dbg(di->dev, "read coulomb counter value of: %lld uah", *cc_uah);
+
+	return 0;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static void bms_reset_cc(struct bms_device_info *di)
+{
+	int ret;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC,
+				 BMS_CLEAR_SHDW_CC);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
+		goto err_lock;
+	}
+
+	/* wait at least three sleep cycles for cc to reset */
+	usleep_range(100, 1000);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC, 0);
+	if (ret)
+		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+}
+
+static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
+{
+	unsigned long fcc;
+	int ret, temp, ocv_capacity, temp_degc;
+	s64 cc = 0;
+
+	ret = iio_read_channel_raw(di->adc, &temp);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read temperature: %d", ret);
+		return ret;
+	}
+
+	temp_degc = DIV_ROUND_CLOSEST(temp, 1000);
+
+	ret = bms_read_cc(di, &cc);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
+		return ret;
+	}
+
+	/* interpolate capacity from open circuit voltage */
+	ocv_capacity = interpolate_capacity(temp_degc, di->ocv,
+					    &di->ocv_lut);
+
+	/* interpolate the full charge capacity from temperature */
+	fcc = interpolate_fcc(temp_degc, &di->fcc_lut);
+
+	/* append coloumb counter to capacity */
+	*capacity = DIV_ROUND_CLOSEST(fcc * ocv_capacity, 100);
+	*capacity = div_s64((*capacity - cc) * 100, fcc);
+
+	return 0;
+}
+
+
+
+/*
+ * Return power_supply property
+ */
+static int bms_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct bms_device_info *di = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = bms_calculate_capacity(di, &val->intval);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (val->intval == INT_MAX || val->intval == INT_MIN)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static enum power_supply_property bms_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
+{
+	struct bms_device_info *di = dev_id;
+
+	if (bms_read_ocv(di, &di->ocv) < 0)
+		return IRQ_HANDLED;
+
+	bms_reset_cc(di);
+	return IRQ_HANDLED;
+}
+
+static int bms_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct bms_device_info *di;
+	struct power_supply *bat;
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	di->dev = &pdev->dev;
+
+	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!di->regmap) {
+		dev_err(di->dev, "Unable to get regmap");
+		return -EINVAL;
+	}
+
+	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
+	if (IS_ERR(di->adc))
+		return PTR_ERR(di->adc);
+
+	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,ocv-temp-legend-celsius",
+						 (u8 *)di->ocv_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage temperature legend found");
+		return ret;
+	}
+
+	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
+						 "qcom,ocv-capacity-legend",
+						 di->ocv_lut.capacity_legend, 0,
+						 MAX_CAPACITY_ROWS);
+	if (di->ocv_lut.rows < 0) {
+		dev_err(di->dev, "no open circuit voltage capacity legend found");
+		return ret;
+	}
+
+	ret = of_property_read_variable_u32_array(di->dev->of_node,
+						  "qcom,ocv-lut-microvolt",
+						  (u32 *)di->ocv_lut.lut,
+						  TEMPERATURE_COLS,
+						  TEMPERATURE_COLS *
+						  MAX_CAPACITY_ROWS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage lut array found");
+		return ret;
+	}
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,fcc-temp-legend-celsius",
+						 (u8 *)di->fcc_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity temperature legend found");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(di->dev->of_node,
+						  "qcom,fcc-lut-microamp-hours",
+						  di->fcc_lut.lut,
+						  TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity lut array found");
+		return ret;
+	}
+
+	ret = bms_read_ocv(di, &di->ocv);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read initial open circuit voltage: %d",
+			ret);
+		return ret;
+	}
+
+	mutex_init(&di->bms_output_lock);
+
+	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
+
+	ret = devm_request_threaded_irq(di->dev, di->ocv_thr_irq, NULL,
+					bms_ocv_thr_irq_handler,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, di);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to request handler for open circuit voltage threshold IRQ");
+		return ret;
+	}
+
+
+	di->bat_desc.name = "bms";
+	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat_desc.properties = bms_props;
+	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
+	di->bat_desc.get_property = bms_get_property;
+
+	psy_cfg.drv_data = di;
+	bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
+
+	return PTR_ERR_OR_ZERO(bat);
+}
+
+static const struct of_device_id bms_of_match[] = {
+	{.compatible = "qcom,pm8941-bms", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bms_of_match);
+
+static struct platform_driver bms_driver = {
+	.probe = bms_probe,
+	.driver = {
+		.name = "qcom-bms",
+		.of_match_table = of_match_ptr(bms_of_match),
+	},
+};
+module_platform_driver(bms_driver);
+
+MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm BMS driver");
+MODULE_LICENSE("GPL");
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
  2018-06-13 16:06   ` [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-06-13 16:06   ` Craig Tatlor
  2018-06-13 22:53     ` Matthias Kaehlcke
  2018-06-13 16:06   ` [PATCH v6 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:06 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Add bindings for the Qualcomm Battery Monitoring system.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---

* Changes from v5:
  Mentions which values are 8 bit.

* Changes from v4:
  Uses proper units and expands some definitions,
  along with changing vadc@ to adc@.
 .../bindings/power/supply/qcom_bms.txt        | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt

diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
new file mode 100644
index 000000000000..9a29a2eb9f04
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
@@ -0,0 +1,92 @@
+Qualcomm Battery Monitoring System
+
+The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
+PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
+that allow the OS to infer a capacity level.
+
+Required properties:
+- compatible:                   Should contain "qcom,pm8941-bms".
+- reg:                          Specifies the SPMI address and length of the
+				controller's registers.
+- interrupts:                   OCV threshold interrupt.
+- io-channels:                  Should contain IIO channel specifier for the
+				ADC channel that reports battery temperature.
+- io-channel-names:             Should contain "temp".
+- qcom,fcc-temp-legend-celcius: An 8 bit array containing the temperature,
+				in degC, for each column of the full charge
+				capacity lookup table.
+- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uah,
+				one entry for each temperature defined in in
+				qcom,fcc-temp-legend-celcius.
+- qcom,ocv-temp-legend-celcius: An 8 bit array containing the temperature,
+				in degC, for each column of the OCV lookup
+				table.
+- qcom,ocv-capacity-legend:     An 8 bit array containing the capacity for each
+				row of the OCV lookup table.
+- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
+				capacity defined in qcom,ocv-capacity-legend.
+
+Example:
+		pm8941_vadc: adc@3100 {
+			compatible = "qcom,spmi-vadc";
+			reg = <0x3100>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+
+			bat_temp {
+				reg = <VADC_LR_MUX1_BAT_THERM>;
+			};
+		};
+
+		bms@4000 {
+			compatible = "qcom,pm8941-bms";
+			reg = <0x4000>;
+			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ocv_thr";
+
+			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
+			io-channel-names = "temp";
+
+			qcom,fcc-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,fcc-lut-microamp-hours = <3230000 3260000 3380000 3410000 3360000>;
+
+			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75
+							     70 65 60 55 50 45
+							     40 35 30 25 20 15
+							     10 9 8 7 6 5 4 3 2
+							     1 0>;
+			qcom,ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,ocv-lut-microvolt = <43050000 43050000 43030000 42990000 42950000
+						  42770000 42570000 42550000 42510000 42310000
+						  42180000 41980000 41970000 41920000 41720000
+						  41590000 41390000 41450000 41400000 41200000
+						  41010000 40810000 40920000 40890000 40690000
+						  40480000 40280000 40440000 40420000 40220000
+						  40040000 39840000 40010000 39980000 39780000
+						  39620000 39420000 39550000 39560000 39360000
+						  39210000 39010000 39090000 39160000 38960000
+						  38830000 38630000 38740000 38790000 38590000
+						  38550000 38350000 38440000 38430000 38230000
+						  38310000 38110000 38230000 38180000 37980000
+						  38190000 37990000 38040000 38000000 37800000
+						  38060000 37860000 37900000 37840000 37640000
+						  37890000 37690000 37770000 37660000 37460000
+						  37720000 37520000 37560000 37450000 37250000
+						  37480000 37280000 37290000 37250000 37050000
+						  37240000 37040000 37020000 36990000 36790000
+						  37030000 36830000 36730000 36700000 36500000
+						  36940000 36740000 36670000 36640000 36440000
+						  36850000 36650000 36600000 36590000 36390000
+						  36750000 36550000 36520000 36550000 36350000
+						  36690000 36490000 36380000 36400000 36200000
+						  36460000 36260000 36180000 36120000 35920000
+						  36080000 35880000 35680000 35640000 35440000
+						  35510000 35310000 35050000 35020000 34820000
+						  34730000 34530000 34300000 34250000 34050000
+						  33870000 33670000 33040000 32820000 32620000
+						  30000000 30000000 30000000 30000000 30000000>;
+		};
+	};
+};
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v6 4/4] MAINTAINERS: Add entry for the Qualcomm BMS
  2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
  2018-06-13 16:06   ` [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
  2018-06-13 16:06   ` [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-06-13 16:06   ` Craig Tatlor
  2 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-13 16:06 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9c125f705f78..be485caf9313 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11646,6 +11646,12 @@ W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
+QUALCOMM BATTERY MONITORING SYSTEM
+M:	Craig Tatlor <ctatlor97@gmail.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/qcom_bms.c
+
 QUALCOMM CAMERA SUBSYSTEM DRIVER
 M:	Todor Tomov <todor.tomov@linaro.org>
 L:	linux-media@vger.kernel.org
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-13 16:06   ` [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-06-13 22:53     ` Matthias Kaehlcke
  0 siblings, 0 replies; 60+ messages in thread
From: Matthias Kaehlcke @ 2018-06-13 22:53 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, linux-pm,
	devicetree, linux-kernel

(sorry if you receive two variants of this mail, I sent one earlier
today but for some reason it didn't make it to the lists)

On Wed, Jun 13, 2018 at 05:06:24PM +0100, Craig Tatlor wrote:
> Add bindings for the Qualcomm Battery Monitoring system.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
> 
> * Changes from v5:
>   Mentions which values are 8 bit.
> 
> * Changes from v4:
>   Uses proper units and expands some definitions,
>   along with changing vadc@ to adc@.
>  .../bindings/power/supply/qcom_bms.txt        | 92 +++++++++++++++++++
>  1 file changed, 92 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> new file mode 100644
> index 000000000000..9a29a2eb9f04
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> @@ -0,0 +1,92 @@
> +Qualcomm Battery Monitoring System
> +
> +The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
> +PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
> +that allow the OS to infer a capacity level.
> +
> +Required properties:
> +- compatible:                   Should contain "qcom,pm8941-bms".
> +- reg:                          Specifies the SPMI address and length of the
> +				controller's registers.
> +- interrupts:                   OCV threshold interrupt.
> +- io-channels:                  Should contain IIO channel specifier for the
> +				ADC channel that reports battery temperature.
> +- io-channel-names:             Should contain "temp".
> +- qcom,fcc-temp-legend-celcius: An 8 bit array containing the temperature,
> +				in degC, for each column of the full charge
> +				capacity lookup table.

s/celcius/celsius/

same for qcom,ocv-temp-legend-celcius

> +- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uah,
> +				one entry for each temperature defined in in

nit: s/uah/uAh/

Thanks

Matthias

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-13 16:06   ` [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-06-14 14:06     ` Linus Walleij
  0 siblings, 0 replies; 60+ messages in thread
From: Linus Walleij @ 2018-06-14 14:06 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Sebastian Reichel, Rob Herring, Mark Rutland,
	Mauro Carvalho Chehab, David S. Miller, Andrew Morton,
	Greg Kroah-Hartman, Randy Dunlap, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Wed, Jun 13, 2018 at 6:06 PM, Craig Tatlor <ctatlor97@gmail.com> wrote:

> This patch adds a driver for the BMS (Battery Monitoring System)
> block of the PM8941 PMIC, it uses a lookup table defined in the
> device tree to generate a capacity from the BMS supplied OCV, it
> then amends the coulomb counter to that to increase the accuracy
> of the estimated capacity.
>
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
>
> * Changes from v5:
>   Uses select for REGMAP_SPMI.

Looks very nice to me!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v7 1/4] fixp-arith: add a linear interpolation function
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                   ` (5 preceding siblings ...)
  2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
@ 2018-06-14 15:14 ` Craig Tatlor
  2018-06-14 15:14   ` [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                     ` (2 more replies)
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
  7 siblings, 3 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-14 15:14 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Adds a function to interpolate against two points,
this is carried arount as a helper function by tons of drivers.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 include/linux/fixp-arith.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h
index d4686fe1cac7..b9e2bb59a734 100644
--- a/include/linux/fixp-arith.h
+++ b/include/linux/fixp-arith.h
@@ -153,4 +153,24 @@ static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
 #define fixp_cos32_rad(rad, twopi)	\
 	fixp_sin32_rad(rad + twopi / 4, twopi)
 
+
+/**
+ * fixp_linear_interpolate() - interpolates a value from two known points
+ *
+ * @x0: x value of point 0
+ * @y0: y value of point 0
+ * @x1: x value of point 1
+ * @y1: y value of point 1
+ * @x: the linear interpolant
+ */
+static inline int fixp_linear_interpolate(int x0, int y0, int x1, int y1, int x)
+{
+	if (y0 == y1 || x == x0)
+		return y0;
+	if (x1 == x0 || x == x1)
+		return y1;
+
+	return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
 #endif
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
@ 2018-06-14 15:14   ` Craig Tatlor
  2018-09-16 13:48     ` Sebastian Reichel
  2018-06-14 15:14   ` [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
  2018-06-14 15:14   ` [PATCH v7 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-14 15:14 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

This patch adds a driver for the BMS (Battery Monitoring System)
block of the PM8941 PMIC, it uses a lookup table defined in the
device tree to generate a capacity from the BMS supplied OCV, it
then amends the coulomb counter to that to increase the accuracy
of the estimated capacity.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---

* Changes from v5:                                                                                                                                                                                                   
  Uses select for REGMAP_SPMI.                                                                                                                                                                                       
                                                                                                                                                                                                                     
* Changes from v4:                                                                                                                                                                                                   
  Cleaned up percentage interpolation function,                                                                                                                                                                      
  uses new fixp interpolation helper,                                                                                                                                                                                
  added some more error cases,                                                                                                                                                                                       
  uses devm_power_supply_register(),                                                                                                                                                                                 
  uses a DIV_ROUND_CLOSEST for division and                                                                                                                                                                          
  uses micro(volts / amp hours) instead of                                                                                                                                                                           
  milli (volts / amp hours).  

 drivers/power/supply/Kconfig    |   9 +
 drivers/power/supply/Makefile   |   1 +
 drivers/power/supply/qcom_bms.c | 487 ++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+)
 create mode 100644 drivers/power/supply/qcom_bms.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 428b426842f4..75f2f375f992 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -82,6 +82,15 @@ config BATTERY_ACT8945A
 	  Say Y here to enable support for power supply provided by
 	  Active-semi ActivePath ACT8945A charger.
 
+config BATTERY_BMS
+	tristate "Qualcomm Battery Monitoring System driver"
+	depends on MFD_SPMI_PMIC || COMPILE_TEST
+	depends on OF
+	select REGMAP_SPMI
+	help
+	  Say Y to include support for the Battery Monitoring hardware
+	  found in some Qualcomm PM series PMICs.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index e83aa843bcc6..04204174b047 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
+obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
 obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
 obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
new file mode 100644
index 000000000000..718fd745c0f7
--- /dev/null
+++ b/drivers/power/supply/qcom_bms.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL
+
+/*
+ * Qualcomm Battery Monitoring System driver
+ *
+ * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/fixp-arith.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/iio/consumer.h>
+
+#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
+#define REG_BMS_SHDW_CC_DATA0		0xA8
+#define REG_BMS_CC_DATA_CTL		0x42
+#define REG_BMS_CC_CLEAR_CTL		0x4
+
+#define BMS_HOLD_OREG_DATA		BIT(0)
+#define BMS_CLEAR_SHDW_CC		BIT(6)
+
+#define BMS_CC_READING_RESOLUTION_N	542535
+#define BMS_CC_READING_RESOLUTION_D	10000
+#define BMS_CC_READING_TICKS		56
+#define BMS_SLEEP_CLK_HZ		32764
+
+#define SECONDS_PER_HOUR		3600
+#define TEMPERATURE_COLS		5
+#define MAX_CAPACITY_ROWS		50
+
+/* lookup table for ocv -> capacity conversion */
+struct bms_ocv_lut {
+	int rows;
+	s8 temp_legend[TEMPERATURE_COLS];
+	u8 capacity_legend[MAX_CAPACITY_ROWS];
+	u32 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
+};
+
+/* lookup table for battery temperature -> fcc conversion */
+struct bms_fcc_lut {
+	s8 temp_legend[TEMPERATURE_COLS];
+	u32 lut[TEMPERATURE_COLS];
+};
+
+struct bms_device_info {
+	struct device *dev;
+	struct regmap *regmap;
+	struct bms_ocv_lut ocv_lut;
+	struct power_supply_desc bat_desc;
+	struct bms_fcc_lut fcc_lut;
+	struct iio_channel *adc;
+	struct mutex bms_output_lock;
+	u32 base_addr;
+
+	int ocv_thr_irq;
+	u32 ocv;
+};
+
+static bool between(int left, int right, int val)
+{
+	if (left <= val && val <= right)
+		return true;
+
+	if (left >= val && val >= right)
+		return true;
+
+	return false;
+}
+
+static int interpolate_capacity(int temp, u32 ocv,
+				struct bms_ocv_lut *ocv_lut)
+{
+	int pcj_minus_one = 0, pcj = 0, i2 = 0, i3 = 0, i, j;
+
+	for (j = 0; j < TEMPERATURE_COLS; j++)
+		if (temp <= ocv_lut->temp_legend[j])
+			break;
+
+	if (ocv >= ocv_lut->lut[0][j])
+		return ocv_lut->capacity_legend[0];
+
+	if (ocv <= ocv_lut->lut[ocv_lut->rows-1][j-1])
+		return ocv_lut->capacity_legend[ocv_lut->rows-1];
+
+	for (i = 0; i < ocv_lut->rows-1; i++) {
+		if (between(ocv_lut->lut[i][j],
+			    ocv_lut->lut[i+1][j], ocv))
+			i2 = i;
+
+		if (between(ocv_lut->lut[i][j-1],
+			    ocv_lut->lut[i+1][j-1], ocv))
+			i3 = i;
+	}
+
+	/* interpolate two capacities */
+	pcj = fixp_linear_interpolate(ocv_lut->lut[i2][j],
+				      ocv_lut->capacity_legend[i2],
+				      ocv_lut->lut[i2+1][j],
+				      ocv_lut->capacity_legend[i2+1],
+				      ocv);
+
+	pcj_minus_one = fixp_linear_interpolate(ocv_lut->lut[i3][j-1],
+						ocv_lut->capacity_legend[i3],
+						ocv_lut->lut[i3+1][j-1],
+						ocv_lut->capacity_legend[i3+1],
+						ocv);
+
+	/* interpolate them with the battery temperature */
+	return fixp_linear_interpolate(ocv_lut->temp_legend[j-1],
+				       pcj_minus_one,
+				       ocv_lut->temp_legend[j],
+				       pcj,
+				       temp);
+}
+
+static int interpolate_fcc(int temp, struct bms_fcc_lut *fcc_lut)
+{
+	int i;
+
+	for (i = 0; i < TEMPERATURE_COLS; i++)
+		if (temp <= fcc_lut->temp_legend[i])
+			break;
+
+	return fixp_linear_interpolate(fcc_lut->temp_legend[i-1],
+			     fcc_lut->lut[i-1],
+			     fcc_lut->temp_legend[i],
+			     fcc_lut->lut[i],
+			     temp);
+}
+
+static int bms_lock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
+	if (ret) {
+		dev_err(di->dev, "failed to lock bms output: %d", ret);
+		return ret;
+	}
+
+	/*
+	 * Sleep for at least 100 microseconds here to make sure
+	 * there has been at least three cycles of the sleep clock
+	 * so that the registers are correctly locked.
+	 */
+	usleep_range(100, 1000);
+
+	return 0;
+}
+
+static int bms_unlock_output_data(struct bms_device_info *di)
+{
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_DATA_CTL,
+				 BMS_HOLD_OREG_DATA, 0);
+	if (ret) {
+		dev_err(di->dev, "failed to unlock bms output: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bms_read_ocv(struct bms_device_info *di, u32 *ocv)
+{
+	int ret;
+	u16 read_ocv;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr+
+			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
+	if (ret) {
+		dev_err(di->dev, "open circuit voltage read failed: %d", ret);
+		goto err_read;
+	}
+
+	dev_dbg(di->dev, "read open circuit voltage of: %d mv", read_ocv);
+
+
+	*ocv = read_ocv * 1000;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
+{
+	int ret;
+	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = bms_lock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	ret = regmap_bulk_read(di->regmap, di->base_addr +
+			       REG_BMS_SHDW_CC_DATA0,
+			       &cc_raw_s36, 5);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter read failed: %d", ret);
+		goto err_read;
+	}
+
+	ret = bms_unlock_output_data(di);
+	if (ret)
+		goto err_lock;
+
+	mutex_unlock(&di->bms_output_lock);
+
+	cc_raw = sign_extend32(cc_raw_s36, 28);
+
+	/* convert raw to uv */
+	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
+			BMS_CC_READING_RESOLUTION_D);
+
+	/* convert uv to pvh */
+	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
+			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR);
+
+	/* divide by impedance */
+	*cc_uah = div_s64(cc_pvh, 10000);
+
+	dev_dbg(di->dev, "read coulomb counter value of: %lld uah", *cc_uah);
+
+	return 0;
+
+err_read:
+	bms_unlock_output_data(di);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+
+	return ret;
+}
+
+static void bms_reset_cc(struct bms_device_info *di)
+{
+	int ret;
+
+	mutex_lock(&di->bms_output_lock);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC,
+				 BMS_CLEAR_SHDW_CC);
+	if (ret) {
+		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
+		goto err_lock;
+	}
+
+	/* wait at least three sleep cycles for cc to reset */
+	usleep_range(100, 1000);
+
+	ret = regmap_update_bits(di->regmap, di->base_addr +
+				 REG_BMS_CC_CLEAR_CTL,
+				 BMS_CLEAR_SHDW_CC, 0);
+	if (ret)
+		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
+
+err_lock:
+	mutex_unlock(&di->bms_output_lock);
+}
+
+static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
+{
+	unsigned long fcc;
+	int ret, temp, ocv_capacity, temp_degc;
+	s64 cc = 0;
+
+	ret = iio_read_channel_raw(di->adc, &temp);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read temperature: %d", ret);
+		return ret;
+	}
+
+	temp_degc = DIV_ROUND_CLOSEST(temp, 1000);
+
+	ret = bms_read_cc(di, &cc);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
+		return ret;
+	}
+
+	/* interpolate capacity from open circuit voltage */
+	ocv_capacity = interpolate_capacity(temp_degc, di->ocv,
+					    &di->ocv_lut);
+
+	/* interpolate the full charge capacity from temperature */
+	fcc = interpolate_fcc(temp_degc, &di->fcc_lut);
+
+	/* append coloumb counter to capacity */
+	*capacity = DIV_ROUND_CLOSEST(fcc * ocv_capacity, 100);
+	*capacity = div_s64((*capacity - cc) * 100, fcc);
+
+	return 0;
+}
+
+
+
+/*
+ * Return power_supply property
+ */
+static int bms_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct bms_device_info *di = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CAPACITY:
+		ret = bms_calculate_capacity(di, &val->intval);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (val->intval == INT_MAX || val->intval == INT_MIN)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static enum power_supply_property bms_props[] = {
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
+{
+	struct bms_device_info *di = dev_id;
+
+	if (bms_read_ocv(di, &di->ocv) < 0)
+		return IRQ_HANDLED;
+
+	bms_reset_cc(di);
+	return IRQ_HANDLED;
+}
+
+static int bms_probe(struct platform_device *pdev)
+{
+	struct power_supply_config psy_cfg = {};
+	struct bms_device_info *di;
+	struct power_supply *bat;
+	int ret;
+
+	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+	if (!di)
+		return -ENOMEM;
+
+	di->dev = &pdev->dev;
+
+	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!di->regmap) {
+		dev_err(di->dev, "Unable to get regmap");
+		return -EINVAL;
+	}
+
+	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
+	if (IS_ERR(di->adc))
+		return PTR_ERR(di->adc);
+
+	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
+	if (ret < 0)
+		return ret;
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,ocv-temp-legend-celsius",
+						 (u8 *)di->ocv_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage temperature legend found");
+		return ret;
+	}
+
+	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
+						 "qcom,ocv-capacity-legend",
+						 di->ocv_lut.capacity_legend, 0,
+						 MAX_CAPACITY_ROWS);
+	if (di->ocv_lut.rows < 0) {
+		dev_err(di->dev, "no open circuit voltage capacity legend found");
+		return ret;
+	}
+
+	ret = of_property_read_variable_u32_array(di->dev->of_node,
+						  "qcom,ocv-lut-microvolt",
+						  (u32 *)di->ocv_lut.lut,
+						  TEMPERATURE_COLS,
+						  TEMPERATURE_COLS *
+						  MAX_CAPACITY_ROWS);
+	if (ret < 0) {
+		dev_err(di->dev, "no open circuit voltage lut array found");
+		return ret;
+	}
+
+	ret = of_property_read_u8_array(di->dev->of_node,
+						 "qcom,fcc-temp-legend-celsius",
+						 (u8 *)di->fcc_lut.temp_legend,
+						 TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity temperature legend found");
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(di->dev->of_node,
+						  "qcom,fcc-lut-microamp-hours",
+						  di->fcc_lut.lut,
+						  TEMPERATURE_COLS);
+	if (ret < 0) {
+		dev_err(di->dev, "no full charge capacity lut array found");
+		return ret;
+	}
+
+	ret = bms_read_ocv(di, &di->ocv);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to read initial open circuit voltage: %d",
+			ret);
+		return ret;
+	}
+
+	mutex_init(&di->bms_output_lock);
+
+	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
+
+	ret = devm_request_threaded_irq(di->dev, di->ocv_thr_irq, NULL,
+					bms_ocv_thr_irq_handler,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, di);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to request handler for open circuit voltage threshold IRQ");
+		return ret;
+	}
+
+
+	di->bat_desc.name = "bms";
+	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	di->bat_desc.properties = bms_props;
+	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
+	di->bat_desc.get_property = bms_get_property;
+
+	psy_cfg.drv_data = di;
+	bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
+
+	return PTR_ERR_OR_ZERO(bat);
+}
+
+static const struct of_device_id bms_of_match[] = {
+	{.compatible = "qcom,pm8941-bms", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bms_of_match);
+
+static struct platform_driver bms_driver = {
+	.probe = bms_probe,
+	.driver = {
+		.name = "qcom-bms",
+		.of_match_table = of_match_ptr(bms_of_match),
+	},
+};
+module_platform_driver(bms_driver);
+
+MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm BMS driver");
+MODULE_LICENSE("GPL");
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
  2018-06-14 15:14   ` [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-06-14 15:14   ` Craig Tatlor
  2018-09-16 12:10     ` Sebastian Reichel
  2018-06-14 15:14   ` [PATCH v7 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
  2 siblings, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-06-14 15:14 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Add bindings for the Qualcomm Battery Monitoring system.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---

* Changes from v6:
  s/celcius/celsius
  change uah to uAh.

* Changes from v5:                                                                                                                                                                                                   
  Mentions which values are 8 bit.                                                                                                                                                                                   
                                                                                                                                                                                                                     
* Changes from v4:                                                                                                                                                                                                   
  Uses proper units and expands some definitions,                                                                                                                                                                    
  along with changing vadc@ to adc@.    

 .../bindings/power/supply/qcom_bms.txt        | 92 +++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt

diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
new file mode 100644
index 000000000000..dc0a9ab9aa64
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
@@ -0,0 +1,92 @@
+Qualcomm Battery Monitoring System
+
+The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
+PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
+that allow the OS to infer a capacity level.
+
+Required properties:
+- compatible:                   Should contain "qcom,pm8941-bms".
+- reg:                          Specifies the SPMI address and length of the
+				controller's registers.
+- interrupts:                   OCV threshold interrupt.
+- io-channels:                  Should contain IIO channel specifier for the
+				ADC channel that reports battery temperature.
+- io-channel-names:             Should contain "temp".
+- qcom,fcc-temp-legend-celsius: An 8 bit array containing the temperature,
+				in degC, for each column of the full charge
+				capacity lookup table.
+- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uAh,
+				one entry for each temperature defined in in
+				qcom,fcc-temp-legend-celsius.
+- qcom,ocv-temp-legend-celsius: An 8 bit array containing the temperature,
+				in degC, for each column of the OCV lookup
+				table.
+- qcom,ocv-capacity-legend:     An 8 bit array containing the capacity for each
+				row of the OCV lookup table.
+- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
+				capacity defined in qcom,ocv-capacity-legend.
+
+Example:
+		pm8941_vadc: adc@3100 {
+			compatible = "qcom,spmi-vadc";
+			reg = <0x3100>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#io-channel-cells = <1>;
+
+			bat_temp {
+				reg = <VADC_LR_MUX1_BAT_THERM>;
+			};
+		};
+
+		bms@4000 {
+			compatible = "qcom,pm8941-bms";
+			reg = <0x4000>;
+			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "ocv_thr";
+
+			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
+			io-channel-names = "temp";
+
+			qcom,fcc-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,fcc-lut-microamp-hours = <3230000 3260000 3380000 3410000 3360000>;
+
+			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75
+							     70 65 60 55 50 45
+							     40 35 30 25 20 15
+							     10 9 8 7 6 5 4 3 2
+							     1 0>;
+			qcom,ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
+			qcom,ocv-lut-microvolt = <43050000 43050000 43030000 42990000 42950000
+						  42770000 42570000 42550000 42510000 42310000
+						  42180000 41980000 41970000 41920000 41720000
+						  41590000 41390000 41450000 41400000 41200000
+						  41010000 40810000 40920000 40890000 40690000
+						  40480000 40280000 40440000 40420000 40220000
+						  40040000 39840000 40010000 39980000 39780000
+						  39620000 39420000 39550000 39560000 39360000
+						  39210000 39010000 39090000 39160000 38960000
+						  38830000 38630000 38740000 38790000 38590000
+						  38550000 38350000 38440000 38430000 38230000
+						  38310000 38110000 38230000 38180000 37980000
+						  38190000 37990000 38040000 38000000 37800000
+						  38060000 37860000 37900000 37840000 37640000
+						  37890000 37690000 37770000 37660000 37460000
+						  37720000 37520000 37560000 37450000 37250000
+						  37480000 37280000 37290000 37250000 37050000
+						  37240000 37040000 37020000 36990000 36790000
+						  37030000 36830000 36730000 36700000 36500000
+						  36940000 36740000 36670000 36640000 36440000
+						  36850000 36650000 36600000 36590000 36390000
+						  36750000 36550000 36520000 36550000 36350000
+						  36690000 36490000 36380000 36400000 36200000
+						  36460000 36260000 36180000 36120000 35920000
+						  36080000 35880000 35680000 35640000 35440000
+						  35510000 35310000 35050000 35020000 34820000
+						  34730000 34530000 34300000 34250000 34050000
+						  33870000 33670000 33040000 32820000 32620000
+						  30000000 30000000 30000000 30000000 30000000>;
+		};
+	};
+};
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v7 4/4] MAINTAINERS: Add entry for the Qualcomm BMS
  2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
  2018-06-14 15:14   ` [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
  2018-06-14 15:14   ` [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-06-14 15:14   ` Craig Tatlor
  2 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-06-14 15:14 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Sebastian Reichel, Rob Herring,
	Mark Rutland, Mauro Carvalho Chehab, David S. Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	linux-pm, devicetree, linux-kernel

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9c125f705f78..be485caf9313 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11646,6 +11646,12 @@ W:	http://wireless.kernel.org/en/users/Drivers/ath9k
 S:	Supported
 F:	drivers/net/wireless/ath/ath9k/
 
+QUALCOMM BATTERY MONITORING SYSTEM
+M:	Craig Tatlor <ctatlor97@gmail.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/qcom_bms.c
+
 QUALCOMM CAMERA SUBSYSTEM DRIVER
 M:	Todor Tomov <todor.tomov@linaro.org>
 L:	linux-media@vger.kernel.org
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
                   ` (6 preceding siblings ...)
  2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
@ 2018-08-10 20:21 ` Craig Tatlor
  2018-08-11 21:30   ` kbuild test robot
                     ` (4 more replies)
  7 siblings, 5 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-08-10 20:21 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Michael Turquette, Stephen Boyd,
	Rob Herring, Mark Rutland, Andy Gross, David Brown, linux-clk,
	devicetree, linux-kernel, linux-soc

Add support for the global clock controller found on SDM660
based devices. This should allow most non-multimedia device
drivers to probe and control their clocks.
Based on CAF implementation.

Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
 drivers/clk/qcom/Kconfig                      |    9 +
 drivers/clk/qcom/Makefile                     |    1 +
 drivers/clk/qcom/gcc-sdm660.c                 | 2479 +++++++++++++++++
 include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
 5 files changed, 2649 insertions(+)
 create mode 100644 drivers/clk/qcom/gcc-sdm660.c
 create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 664ea1fd6c76..e498ad2e8db8 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -19,6 +19,7 @@ Required properties :
 			"qcom,gcc-msm8996"
 			"qcom,gcc-msm8998"
 			"qcom,gcc-mdm9615"
+			"qcom,gcc-sdm660"
 			"qcom,gcc-sdm845"
 
 - reg : shall contain base register location and length
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 9c3480dcc38a..c4bda6d24c1f 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -226,6 +226,15 @@ config MSM_GCC_8998
 	  Say Y if you want to use peripheral devices such as UART, SPI,
 	  i2c, USB, UFS, SD/eMMC, PCIe, etc.
 
+config SDM_GCC_660
+	tristate "SDM660 Global Clock Controller"
+	select QCOM_GDSC
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the global clock controller on SDM660 devices.
+	  Say Y if you want to use peripheral devices such as UART, SPI,
+	  i2C, USB, UFS, SDDC, PCIe, etc.
+
 config SDM_GCC_845
 	tristate "SDM845 Global Clock Controller"
 	select QCOM_GDSC
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 762c01137c2f..6e37d30d7c02 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
 obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
 obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
 obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
+obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
 obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
 obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
 obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
new file mode 100644
index 000000000000..bdb445aa4baa
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -0,0 +1,2479 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#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,gcc-sdm660.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "gdsc.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+	P_XO,
+	P_SLEEP_CLK,
+	P_GPLL0,
+	P_GPLL1,
+	P_GPLL4,
+	P_GPLL0_EARLY_DIV,
+	P_GPLL1_EARLY_DIV,
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0[] = {
+	"xo",
+	"gpll0",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"sleep_clk",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
+	{ P_XO, 0 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const char * const gcc_parent_names_xo_sleep_clk[] = {
+	"xo",
+	"sleep_clk",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll4[] = {
+	"xo",
+	"gpll4",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL1_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll1",
+	"gpll4",
+	"gpll1_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll4",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 2 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll4",
+};
+
+static struct clk_fixed_factor xo = {
+	.mult = 1,
+	.div = 1,
+	.hw.init = &(struct clk_init_data){
+		.name = "xo",
+		.parent_names = (const char *[]){ "xo_board" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll0_early = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll0_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll0_early_div",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+	.offset = 0x00000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll0",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll1_early = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll1_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll1_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll1_early_div",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll1 = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll1",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll4_early = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll4_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data)
+	{
+		.name = "gpll4",
+		.parent_names = (const char *[]) { "gpll4_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x19020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(960000, P_XO, 10, 1, 2),
+	F(4800000, P_XO, 4, 0, 0),
+	F(9600000, P_XO, 2, 0, 0),
+	F(15000000, P_GPLL0, 10, 1, 4),
+	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1900c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1b020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1b00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1d020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1d00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1f020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1f00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+	F(3686400, P_GPLL0, 1, 96, 15625),
+	F(7372800, P_GPLL0, 1, 192, 15625),
+	F(14745600, P_GPLL0, 1, 384, 15625),
+	F(16000000, P_GPLL0, 5, 2, 15),
+	F(19200000, P_XO, 1, 0, 0),
+	F(24000000, P_GPLL0, 5, 1, 5),
+	F(32000000, P_GPLL0, 1, 4, 75),
+	F(40000000, P_GPLL0, 15, 0, 0),
+	F(46400000, P_GPLL0, 1, 29, 375),
+	F(48000000, P_GPLL0, 12.5, 0, 0),
+	F(51200000, P_GPLL0, 1, 32, 375),
+	F(56000000, P_GPLL0, 1, 7, 75),
+	F(58982400, P_GPLL0, 1, 1536, 15625),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(63157895, P_GPLL0, 9.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x1a00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x1c00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x26020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2600c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x28020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2800c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2a020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2a00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2c020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2c00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x2700c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x2900c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+	.cmd_rcgr = 0x64004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp1_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+	.cmd_rcgr = 0x65004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+	.cmd_rcgr = 0x66004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp3_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+	F(300000000, P_GPLL0, 2, 0, 0),
+	F(600000000, P_GPLL0, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+	.cmd_rcgr = 0x4805c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_gpll0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll0_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
+	F(384000000, P_GPLL4, 4, 0, 0),
+	F(768000000, P_GPLL4, 2, 0, 0),
+	F(1536000000, P_GPLL4, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll4_clk_src = {
+	.cmd_rcgr = 0x48074,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll4,
+	.freq_tbl = ftbl_hmss_gpll4_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll4_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll4,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+	.cmd_rcgr = 0x48044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_rbcpr_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+	.cmd_rcgr = 0x33010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pdm2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
+	F(160400000, P_GPLL1, 5, 0, 0),
+	F(267333333, P_GPLL1, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+	.cmd_rcgr = 0x4d00c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+	.freq_tbl = ftbl_qspi_ser_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "qspi_ser_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+		.num_parents = 6,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(384000000, P_GPLL4, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+	.cmd_rcgr = 0x1602c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+	.cmd_rcgr = 0x16010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+	.cmd_rcgr = 0x14010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+	.cmd_rcgr = 0x75018,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_axi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+	.cmd_rcgr = 0x76010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 ufs_phy_aux_clk_src = {
+	.cmd_rcgr = 0x76044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
+	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
+	F(75000000, P_GPLL0, 8, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_unipro_core_clk_src = {
+	.cmd_rcgr = 0x76028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_unipro_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+	.cmd_rcgr = 0x2f010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x2f024,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	F(133333333, P_GPLL0, 4.5, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+	.cmd_rcgr = 0xf014,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+	.cmd_rcgr = 0xf028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+	F(1200000, P_XO, 16, 0, 0),
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+	.cmd_rcgr = 0x5000c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb3_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+	.halt_reg = 0x75034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75034,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+	.halt_reg = 0xf03c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+	.halt_reg = 0x7106c,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x7106c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_hmss_axi_clk = {
+	.halt_reg = 0x48004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(22),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_hmss_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
+	.halt_reg = 0x4401c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4401c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_mss_q6_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+	.halt_reg = 0x17004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(17),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+	.halt_reg = 0x19008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+	.halt_reg = 0x19004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+	.halt_reg = 0x1b008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+	.halt_reg = 0x1b004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+	.halt_reg = 0x1d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+	.halt_reg = 0x1d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+	.halt_reg = 0x1f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+	.halt_reg = 0x1f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+	.halt_reg = 0x1a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+	.halt_reg = 0x1c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+	.halt_reg = 0x25004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(15),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+	.halt_reg = 0x26008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+	.halt_reg = 0x26004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+	.halt_reg = 0x28008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+	.halt_reg = 0x28004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+	.halt_reg = 0x2a008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+	.halt_reg = 0x2a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+	.halt_reg = 0x2c008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+	.halt_reg = 0x2c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+	.halt_reg = 0x27004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x27004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+	.halt_reg = 0x29004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x29004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+	.halt_reg = 0x38004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(10),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_boot_rom_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_axi_clk = {
+	.halt_reg = 0x5058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5058,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb2_axi_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_axi_clk = {
+	.halt_reg = 0x5018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_dcc_ahb_clk = {
+	.halt_reg = 0x84004,
+	.clkr = {
+		.enable_reg = 0x84004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_dcc_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp1_clk = {
+	.halt_reg = 0x64000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x64000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp1_clk",
+			.parent_names = (const char *[]){
+				"gp1_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp2_clk = {
+	.halt_reg = 0x65000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x65000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp2_clk",
+			.parent_names = (const char *[]){
+				"gp2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp3_clk = {
+	.halt_reg = 0x66000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x66000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp3_clk",
+			.parent_names = (const char *[]){
+				"gp3_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_bimc_gfx_clk = {
+	.halt_reg = 0x71010,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+	.halt_reg = 0x71004,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(3),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_dvm_bus_clk = {
+	.halt_reg = 0x4808c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4808c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_dvm_bus_clk",
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+	.halt_reg = 0x48008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x48008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_rbcpr_clk",
+			.parent_names = (const char *[]){
+				"hmss_rbcpr_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x9004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_noc_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_sys_noc_axi_clk = {
+	.halt_reg = 0x9000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_sys_noc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+	.halt_reg = 0x8a000,
+	.clkr = {
+		.enable_reg = 0x8a000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+	.halt_reg = 0x8a004,
+	.clkr = {
+		.enable_reg = 0x8a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_mnoc_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+	.halt_reg = 0x8a040,
+	.clkr = {
+		.enable_reg = 0x8a040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_q6_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+	.halt_reg = 0x8a03c,
+	.clkr = {
+		.enable_reg = 0x8a03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_snoc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+	.halt_reg = 0x3300c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x3300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm2_clk",
+			.parent_names = (const char *[]){
+				"pdm2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+	.halt_reg = 0x33004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x33004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+	.halt_reg = 0x34004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(13),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_prng_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+	.halt_reg = 0x4d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+	.halt_reg = 0x4d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ser_clk",
+			.parent_names = (const char *[]){
+				"qspi_ser_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx0_usb2_clkref_clk = {
+	.halt_reg = 0x88018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx0_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+	.halt_reg = 0x88014,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx1_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+	.halt_reg = 0x16008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+	.halt_reg = 0x16004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+	.halt_reg = 0x1600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ice_core_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+	.halt_reg = 0x14008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+	.halt_reg = 0x14004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+	.halt_reg = 0x7500c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7500c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+	.halt_reg = 0x75008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+	.halt_reg = 0x88008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x88008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+	.halt_reg = 0x7600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ice_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_phy_aux_clk = {
+	.halt_reg = 0x76040,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"ufs_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+	.halt_reg = 0x75014,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+	.halt_reg = 0x7605c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x7605c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+	.halt_reg = 0x75010,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+	.halt_reg = 0x76008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_unipro_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_unipro_core_clk_src",
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+	.halt_reg = 0x2f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_master_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src"
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+	.halt_reg = 0x2f00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb20_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+	.halt_reg = 0x2f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+	.halt_reg = 0xf008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_master_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+	.halt_reg = 0xf010,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb30_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+	.halt_reg = 0xf00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+	.halt_reg = 0x8800c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x8800c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+	.halt_reg = 0x50000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x50000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"usb3_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+	.halt_reg = 0x50004,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x50004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_pipe_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+	.halt_reg = 0x6a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x6a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb_phy_cfg_ahb2phy_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc ufs_gdsc = {
+	.gdscr = 0x75004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "ufs_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc usb_30_gdsc = {
+	.gdscr = 0xf004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "usb_30_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc pcie_0_gdsc = {
+	.gdscr = 0x6b004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "pcie_0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+struct clk_hw *gcc_sdm660_hws[] = {
+	[GCC_XO] = &xo.hw,
+	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
+	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,
+};
+
+static struct clk_regmap *gcc_660_clocks[] = {
+	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+	[BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+	[BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+	[BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+	[BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+	[BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+	[BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+	[BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+	[BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+	[BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+	[BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+	[GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+	[GCC_BIMC_HMSS_AXI_CLK] = &gcc_bimc_hmss_axi_clk.clkr,
+	[GCC_BIMC_MSS_Q6_AXI_CLK] = &gcc_bimc_mss_q6_axi_clk.clkr,
+	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+	[GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+	[GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+	[GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+	[GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+	[GCC_CFG_NOC_USB2_AXI_CLK] = &gcc_cfg_noc_usb2_axi_clk.clkr,
+	[GCC_CFG_NOC_USB3_AXI_CLK] = &gcc_cfg_noc_usb3_axi_clk.clkr,
+	[GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+	[GCC_GPU_BIMC_GFX_CLK] = &gcc_gpu_bimc_gfx_clk.clkr,
+	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+	[GCC_GPU_GPLL0_CLK] = &gcc_gpu_gpll0_clk.clkr,
+	[GCC_GPU_GPLL0_DIV_CLK] = &gcc_gpu_gpll0_div_clk.clkr,
+	[GCC_HMSS_DVM_BUS_CLK] = &gcc_hmss_dvm_bus_clk.clkr,
+	[GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+	[GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
+	[GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+	[GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+	[GCC_MMSS_SYS_NOC_AXI_CLK] = &gcc_mmss_sys_noc_axi_clk.clkr,
+	[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+	[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+	[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+	[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+	[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+	[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+	[GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
+	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+	[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+	[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+	[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+	[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+	[GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+	[GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+	[GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+	[GCC_UFS_PHY_AUX_CLK] = &gcc_ufs_phy_aux_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+	[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+	[GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+	[GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+	[GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+	[GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+	[GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+	[GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+	[GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+	[GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+	[GP1_CLK_SRC] = &gp1_clk_src.clkr,
+	[GP2_CLK_SRC] = &gp2_clk_src.clkr,
+	[GP3_CLK_SRC] = &gp3_clk_src.clkr,
+	[GPLL0] = &gpll0.clkr,
+	[GPLL0_EARLY] = &gpll0_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL1_EARLY] = &gpll1_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL4_EARLY] = &gpll4_early.clkr,
+	[GPLL4] = &gpll4.clkr,
+	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+	[HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
+	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+	[QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+	[SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+	[UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+	[UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+	[UFS_PHY_AUX_CLK_SRC] = &ufs_phy_aux_clk_src.clkr,
+	[UFS_UNIPRO_CORE_CLK_SRC] = &ufs_unipro_core_clk_src.clkr,
+	[USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+	[USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+	[USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+	[USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+};
+
+static struct gdsc *gcc_660_gdscs[] = {
+	[UFS_GDSC] = &ufs_gdsc,
+	[USB_30_GDSC] = &usb_30_gdsc,
+	[PCIE_0_GDSC] = &pcie_0_gdsc,
+};
+
+static const struct qcom_reset_map gcc_660_resets[] = {
+	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+	[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+	[GCC_UFS_BCR] = { 0x75000 },
+	[GCC_USB3_DP_PHY_BCR] = { 0x50028 },
+	[GCC_USB3_PHY_BCR] = { 0x50020 },
+	[GCC_USB3PHY_PHY_BCR] = { 0x50024 },
+	[GCC_USB_20_BCR] = { 0x2f000 },
+	[GCC_USB_30_BCR] = { 0xf000 },
+	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+};
+
+static const struct regmap_config gcc_660_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x94000,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc gcc_660_desc = {
+	.config = &gcc_660_regmap_config,
+	.clks = gcc_660_clocks,
+	.num_clks = ARRAY_SIZE(gcc_660_clocks),
+	.resets = gcc_660_resets,
+	.num_resets = ARRAY_SIZE(gcc_660_resets),
+	.gdscs = gcc_660_gdscs,
+	.num_gdscs = ARRAY_SIZE(gcc_660_gdscs),
+};
+
+static const struct of_device_id gcc_660_match_table[] = {
+	{ .compatible = "qcom,gcc-sdm660" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_660_match_table);
+
+static int gcc_660_probe(struct platform_device *pdev)
+{
+	int i, ret = 0;
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &gcc_660_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/*
+	 * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+	 * turned off by hardware during certain apps low power modes.
+	 */
+	ret = regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+	if (ret)
+		return ret;
+
+	/* Register the hws */
+	for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) {
+		ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]);
+		if (ret)
+			return ret;
+	}
+
+	return qcom_cc_really_probe(pdev, &gcc_660_desc, regmap);
+}
+
+static struct platform_driver gcc_660_driver = {
+	.probe		= gcc_660_probe,
+	.driver		= {
+		.name	= "gcc-sdm660",
+		.of_match_table = gcc_660_match_table,
+	},
+};
+
+static int __init gcc_660_init(void)
+{
+	return platform_driver_register(&gcc_660_driver);
+}
+core_initcall_sync(gcc_660_init);
+
+static void __exit gcc_660_exit(void)
+{
+	platform_driver_unregister(&gcc_660_driver);
+}
+module_exit(gcc_660_exit);
+
+MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
new file mode 100644
index 000000000000..76aabcc5e7e3
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_660_H
+#define _DT_BINDINGS_CLK_MSM_GCC_660_H
+
+#define GCC_XO					0
+#define GCC_GPLL0_EARLY_DIV			1
+#define GCC_GPLL1_EARLY_DIV			2
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC		3
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC		4
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC		5
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC		6
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC		7
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC		8
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC		9
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC		10
+#define BLSP1_UART1_APPS_CLK_SRC		11
+#define BLSP1_UART2_APPS_CLK_SRC		12
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC		13
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC		14
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC		15
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC		16
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC		17
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC		18
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC		19
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC		20
+#define BLSP2_UART1_APPS_CLK_SRC		21
+#define BLSP2_UART2_APPS_CLK_SRC		22
+#define GCC_AGGRE2_UFS_AXI_CLK			23
+#define GCC_AGGRE2_USB3_AXI_CLK			24
+#define GCC_BIMC_GFX_CLK			25
+#define GCC_BIMC_HMSS_AXI_CLK			26
+#define GCC_BIMC_MSS_Q6_AXI_CLK			27
+#define GCC_BLSP1_AHB_CLK			28
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK		29
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK		30
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK		31
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK		32
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK		33
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK		34
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK		35
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK		36
+#define GCC_BLSP1_UART1_APPS_CLK		37
+#define GCC_BLSP1_UART2_APPS_CLK		38
+#define GCC_BLSP2_AHB_CLK			39
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK		40
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK		41
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK		42
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK		43
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK		44
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK		46
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK		45
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK		46
+#define GCC_BLSP2_UART1_APPS_CLK		47
+#define GCC_BLSP2_UART2_APPS_CLK		48
+#define GCC_BOOT_ROM_AHB_CLK			49
+#define GCC_CFG_NOC_USB2_AXI_CLK		50
+#define GCC_CFG_NOC_USB3_AXI_CLK		51
+#define GCC_DCC_AHB_CLK				52
+#define GCC_GP1_CLK				53
+#define GCC_GP2_CLK				54
+#define GCC_GP3_CLK				55
+#define GCC_GPU_BIMC_GFX_CLK			56
+#define GCC_GPU_CFG_AHB_CLK			57
+#define GCC_GPU_GPLL0_CLK			58
+#define GCC_GPU_GPLL0_DIV_CLK			59
+#define GCC_HMSS_DVM_BUS_CLK			60
+#define GCC_HMSS_RBCPR_CLK			61
+#define GCC_MMSS_GPLL0_CLK			62
+#define GCC_MMSS_GPLL0_DIV_CLK			63
+#define GCC_MMSS_NOC_CFG_AHB_CLK		64
+#define GCC_MMSS_SYS_NOC_AXI_CLK		65
+#define GCC_MSS_CFG_AHB_CLK			66
+#define GCC_MSS_GPLL0_DIV_CLK			67
+#define GCC_MSS_MNOC_BIMC_AXI_CLK		68
+#define GCC_MSS_Q6_BIMC_AXI_CLK			69
+#define GCC_MSS_SNOC_AXI_CLK			70
+#define GCC_PDM2_CLK				71
+#define GCC_PDM_AHB_CLK				72
+#define GCC_PRNG_AHB_CLK			73
+#define GCC_QSPI_AHB_CLK			74
+#define GCC_QSPI_SER_CLK			75
+#define GCC_SDCC1_AHB_CLK			76
+#define GCC_SDCC1_APPS_CLK			77
+#define GCC_SDCC1_ICE_CORE_CLK			78
+#define GCC_SDCC2_AHB_CLK			79
+#define GCC_SDCC2_APPS_CLK			80
+#define GCC_UFS_AHB_CLK				81
+#define GCC_UFS_AXI_CLK				82
+#define GCC_UFS_CLKREF_CLK			83
+#define GCC_UFS_ICE_CORE_CLK			84
+#define GCC_UFS_PHY_AUX_CLK			85
+#define GCC_UFS_RX_SYMBOL_0_CLK			86
+#define GCC_UFS_RX_SYMBOL_1_CLK			87
+#define GCC_UFS_TX_SYMBOL_0_CLK			88
+#define GCC_UFS_UNIPRO_CORE_CLK			89
+#define GCC_USB20_MASTER_CLK			90
+#define GCC_USB20_MOCK_UTMI_CLK			91
+#define GCC_USB20_SLEEP_CLK			92
+#define GCC_USB30_MASTER_CLK			93
+#define GCC_USB30_MOCK_UTMI_CLK			94
+#define GCC_USB30_SLEEP_CLK			95
+#define GCC_USB3_CLKREF_CLK			96
+#define GCC_USB3_PHY_AUX_CLK			97
+#define GCC_USB3_PHY_PIPE_CLK			98
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK		99
+#define GP1_CLK_SRC				100
+#define GP2_CLK_SRC				101
+#define GP3_CLK_SRC				102
+#define GPLL0					103
+#define GPLL0_EARLY				104
+#define GPLL1					105
+#define GPLL1_EARLY				106
+#define GPLL4					107
+#define GPLL4_EARLY				108
+#define HMSS_GPLL0_CLK_SRC			109
+#define HMSS_GPLL4_CLK_SRC			110
+#define HMSS_RBCPR_CLK_SRC			111
+#define PDM2_CLK_SRC				112
+#define QSPI_SER_CLK_SRC			113
+#define SDCC1_APPS_CLK_SRC			114
+#define SDCC1_ICE_CORE_CLK_SRC			115
+#define SDCC2_APPS_CLK_SRC			116
+#define UFS_AXI_CLK_SRC				117
+#define UFS_ICE_CORE_CLK_SRC			118
+#define UFS_PHY_AUX_CLK_SRC			119
+#define UFS_UNIPRO_CORE_CLK_SRC			120
+#define USB20_MASTER_CLK_SRC			121
+#define USB20_MOCK_UTMI_CLK_SRC			122
+#define USB30_MASTER_CLK_SRC			123
+#define USB30_MOCK_UTMI_CLK_SRC			124
+#define USB3_PHY_AUX_CLK_SRC			125
+#define GPLL0_OUT_MSSCC				126
+#define GCC_UFS_AXI_HW_CTL_CLK			127
+#define GCC_UFS_ICE_CORE_HW_CTL_CLK		128
+#define GCC_UFS_PHY_AUX_HW_CTL_CLK		129
+#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		130
+#define GCC_RX0_USB2_CLKREF_CLK			131
+#define GCC_RX1_USB2_CLKREF_CLK			132
+
+#define PCIE_0_GDSC	0
+#define UFS_GDSC	1
+#define USB_30_GDSC	2
+
+#define GCC_QUSB2PHY_PRIM_BCR		0
+#define GCC_QUSB2PHY_SEC_BCR		1
+#define GCC_UFS_BCR			2
+#define GCC_USB3_DP_PHY_BCR		3
+#define GCC_USB3_PHY_BCR		4
+#define GCC_USB3PHY_PHY_BCR		5
+#define GCC_USB_20_BCR                  6
+#define GCC_USB_30_BCR			7
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR	8
+
+#endif
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
@ 2018-08-11 21:30   ` kbuild test robot
  2018-08-11 21:30   ` [RFC PATCH] clk: qcom: gcc_sdm660_hws[] can be static kbuild test robot
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 60+ messages in thread
From: kbuild test robot @ 2018-08-11 21:30 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: kbuild-all, ctatlor97, linux-arm-msm, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Andy Gross, David Brown,
	linux-clk, devicetree, linux-kernel, linux-soc

Hi Craig,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on agross/for-next]
[also build test WARNING on v4.18-rc8]
[cannot apply to next-20180810]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Craig-Tatlor/clk-qcom-Add-Global-Clock-controller-GCC-driver-for-SDM660/20180811-150111
base:   https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git for-next
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> drivers/clk/qcom/gcc-sdm660.c:2255:15: sparse: symbol 'gcc_sdm660_hws' was not declared. Should it be static?
   drivers/clk/qcom/gcc-sdm660.c:2304:10: sparse: Initializer entry defined twice
   drivers/clk/qcom/gcc-sdm660.c:2306:10:   also defined here

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [RFC PATCH] clk: qcom: gcc_sdm660_hws[] can be static
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
  2018-08-11 21:30   ` kbuild test robot
@ 2018-08-11 21:30   ` kbuild test robot
  2018-08-13  6:55   ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Taniya Das
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 60+ messages in thread
From: kbuild test robot @ 2018-08-11 21:30 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: kbuild-all, ctatlor97, linux-arm-msm, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Andy Gross, David Brown,
	linux-clk, devicetree, linux-kernel, linux-soc


Fixes: 851e534f5d75 ("clk: qcom: Add Global Clock controller (GCC) driver for SDM660")
Signed-off-by: kbuild test robot <fengguang.wu@intel.com>
---
 gcc-sdm660.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index bdb445a..cec8b41 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -2252,7 +2252,7 @@ static struct gdsc pcie_0_gdsc = {
 	.flags = VOTABLE,
 };
 
-struct clk_hw *gcc_sdm660_hws[] = {
+static struct clk_hw *gcc_sdm660_hws[] = {
 	[GCC_XO] = &xo.hw,
 	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
 	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,

^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
  2018-08-11 21:30   ` kbuild test robot
  2018-08-11 21:30   ` [RFC PATCH] clk: qcom: gcc_sdm660_hws[] can be static kbuild test robot
@ 2018-08-13  6:55   ` Taniya Das
  2018-08-13  7:45     ` Craig Tatlor
  2018-08-13  9:44     ` Craig Tatlor
  2018-09-25 16:35   ` [PATCH v2] " Craig Tatlor
  2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
  4 siblings, 2 replies; 60+ messages in thread
From: Taniya Das @ 2018-08-13  6:55 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Michael Turquette, Stephen Boyd, Rob Herring,
	Mark Rutland, Andy Gross, David Brown, linux-clk, devicetree,
	linux-kernel, linux-soc

Hello Craig,

Could you please correct the authorship and also provide the reference 
to code where this is picked from?

On 8/11/2018 1:51 AM, Craig Tatlor wrote:
> Add support for the global clock controller found on SDM660
> based devices. This should allow most non-multimedia device
> drivers to probe and control their clocks.
> Based on CAF implementation.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
>   .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
>   drivers/clk/qcom/Kconfig                      |    9 +
>   drivers/clk/qcom/Makefile                     |    1 +
>   drivers/clk/qcom/gcc-sdm660.c                 | 2479 +++++++++++++++++
>   include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
>   5 files changed, 2649 insertions(+)
>   create mode 100644 drivers/clk/qcom/gcc-sdm660.c
>   create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> index 664ea1fd6c76..e498ad2e8db8 100644
> --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
> @@ -19,6 +19,7 @@ Required properties :
>   			"qcom,gcc-msm8996"
>   			"qcom,gcc-msm8998"
>   			"qcom,gcc-mdm9615"
> +			"qcom,gcc-sdm660"
>   			"qcom,gcc-sdm845"
>   
>   - reg : shall contain base register location and length
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 9c3480dcc38a..c4bda6d24c1f 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -226,6 +226,15 @@ config MSM_GCC_8998
>   	  Say Y if you want to use peripheral devices such as UART, SPI,
>   	  i2c, USB, UFS, SD/eMMC, PCIe, etc.
>   
> +config SDM_GCC_660
> +	tristate "SDM660 Global Clock Controller"
> +	select QCOM_GDSC
> +	depends on COMMON_CLK_QCOM
> +	help
> +	  Support for the global clock controller on SDM660 devices.
> +	  Say Y if you want to use peripheral devices such as UART, SPI,
> +	  i2C, USB, UFS, SDDC, PCIe, etc.
> +
>   config SDM_GCC_845
>   	tristate "SDM845 Global Clock Controller"
>   	select QCOM_GDSC
> diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
> index 762c01137c2f..6e37d30d7c02 100644
> --- a/drivers/clk/qcom/Makefile
> +++ b/drivers/clk/qcom/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
>   obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
>   obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
>   obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
> +obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
>   obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
>   obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
>   obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
> diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
> new file mode 100644
> index 000000000000..bdb445aa4baa
> --- /dev/null
> +++ b/drivers/clk/qcom/gcc-sdm660.c
> @@ -0,0 +1,2479 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2018, Craig Tatlor.
> + */
> +
> +#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,gcc-sdm660.h>
> +
> +#include "common.h"
> +#include "clk-regmap.h"
> +#include "clk-alpha-pll.h"
> +#include "clk-rcg.h"
> +#include "clk-branch.h"
> +#include "reset.h"
> +#include "gdsc.h"
> +
> +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
> +
> +enum {
> +	P_XO,
> +	P_SLEEP_CLK,
> +	P_GPLL0,
> +	P_GPLL1,
> +	P_GPLL4,
> +	P_GPLL0_EARLY_DIV,
> +	P_GPLL1_EARLY_DIV,
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +	{ P_GPLL0_EARLY_DIV, 6 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
> +	"xo",
> +	"gpll0",
> +	"gpll0_early_div",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0[] = {
> +	"xo",
> +	"gpll0",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +	{ P_SLEEP_CLK, 5 },
> +	{ P_GPLL0_EARLY_DIV, 6 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
> +	"xo",
> +	"gpll0",
> +	"sleep_clk",
> +	"gpll0_early_div",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
> +	{ P_XO, 0 },
> +	{ P_SLEEP_CLK, 5 },
> +};
> +
> +static const char * const gcc_parent_names_xo_sleep_clk[] = {
> +	"xo",
> +	"sleep_clk",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll4[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL4, 5 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll4[] = {
> +	"xo",
> +	"gpll4",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +	{ P_GPLL0_EARLY_DIV, 3 },
> +	{ P_GPLL1, 4 },
> +	{ P_GPLL4, 5 },
> +	{ P_GPLL1_EARLY_DIV, 6 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
> +	"xo",
> +	"gpll0",
> +	"gpll0_early_div",
> +	"gpll1",
> +	"gpll4",
> +	"gpll1_early_div",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +	{ P_GPLL4, 5 },
> +	{ P_GPLL0_EARLY_DIV, 6 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
> +	"xo",
> +	"gpll0",
> +	"gpll4",
> +	"gpll0_early_div",
> +};
> +
> +static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
> +	{ P_XO, 0 },
> +	{ P_GPLL0, 1 },
> +	{ P_GPLL0_EARLY_DIV, 2 },
> +	{ P_GPLL4, 5 },
> +};
> +
> +static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
> +	"xo",
> +	"gpll0",
> +	"gpll0_early_div",
> +	"gpll4",
> +};
> +
> +static struct clk_fixed_factor xo = {
> +	.mult = 1,
> +	.div = 1,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "xo",
> +		.parent_names = (const char *[]){ "xo_board" },
> +		.num_parents = 1,
> +		.ops = &clk_fixed_factor_ops,
> +	},
> +};
> +
> +static struct clk_alpha_pll gpll0_early = {
> +	.offset = 0x0,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr = {
> +		.enable_reg = 0x52000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gpll0_early",
> +			.parent_names = (const char *[]){ "xo" },
> +			.num_parents = 1,
> +			.ops = &clk_alpha_pll_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_fixed_factor gpll0_early_div = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "gpll0_early_div",
> +		.parent_names = (const char *[]){ "gpll0_early" },
> +		.num_parents = 1,
> +		.ops = &clk_fixed_factor_ops,
> +	},
> +};
> +
> +static struct clk_alpha_pll_postdiv gpll0 = {
> +	.offset = 0x00000,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "gpll0",
> +		.parent_names = (const char *[]){ "gpll0_early" },
> +		.num_parents = 1,
> +		.ops = &clk_alpha_pll_postdiv_ops,
> +	},
> +};
> +
> +static struct clk_alpha_pll gpll1_early = {
> +	.offset = 0x1000,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr = {
> +		.enable_reg = 0x52000,
> +		.enable_mask = BIT(1),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gpll1_early",
> +			.parent_names = (const char *[]){ "xo" },
> +			.num_parents = 1,
> +			.ops = &clk_alpha_pll_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_fixed_factor gpll1_early_div = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = &(struct clk_init_data){
> +		.name = "gpll1_early_div",
> +		.parent_names = (const char *[]){ "gpll1_early" },
> +		.num_parents = 1,
> +		.ops = &clk_fixed_factor_ops,
> +	},
> +};
> +
> +static struct clk_alpha_pll_postdiv gpll1 = {
> +	.offset = 0x1000,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "gpll1",
> +		.parent_names = (const char *[]){ "gpll1_early" },
> +		.num_parents = 1,
> +		.ops = &clk_alpha_pll_postdiv_ops,
> +	},
> +};
> +
> +static struct clk_alpha_pll gpll4_early = {
> +	.offset = 0x77000,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr = {
> +		.enable_reg = 0x52000,
> +		.enable_mask = BIT(4),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gpll4_early",
> +			.parent_names = (const char *[]){ "xo" },
> +			.num_parents = 1,
> +			.ops = &clk_alpha_pll_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_alpha_pll_postdiv gpll4 = {
> +	.offset = 0x77000,
> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
> +	.clkr.hw.init = &(struct clk_init_data)
> +	{
> +		.name = "gpll4",
> +		.parent_names = (const char *[]) { "gpll4_early" },
> +		.num_parents = 1,
> +		.ops = &clk_alpha_pll_postdiv_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(50000000, P_GPLL0, 12, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x19020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup1_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
> +	F(960000, P_XO, 10, 1, 2),
> +	F(4800000, P_XO, 4, 0, 0),
> +	F(9600000, P_XO, 2, 0, 0),
> +	F(15000000, P_GPLL0, 10, 1, 4),
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(25000000, P_GPLL0, 12, 1, 2),
> +	F(50000000, P_GPLL0, 12, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x1900c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup1_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x1b020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup2_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x1b00c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup2_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x1d020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup3_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x1d00c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup3_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x1f020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup4_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x1f00c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_qup4_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
> +	F(3686400, P_GPLL0, 1, 96, 15625),
> +	F(7372800, P_GPLL0, 1, 192, 15625),
> +	F(14745600, P_GPLL0, 1, 384, 15625),
> +	F(16000000, P_GPLL0, 5, 2, 15),
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(24000000, P_GPLL0, 5, 1, 5),
> +	F(32000000, P_GPLL0, 1, 4, 75),
> +	F(40000000, P_GPLL0, 15, 0, 0),
> +	F(46400000, P_GPLL0, 1, 29, 375),
> +	F(48000000, P_GPLL0, 12.5, 0, 0),
> +	F(51200000, P_GPLL0, 1, 32, 375),
> +	F(56000000, P_GPLL0, 1, 7, 75),
> +	F(58982400, P_GPLL0, 1, 1536, 15625),
> +	F(60000000, P_GPLL0, 10, 0, 0),
> +	F(63157895, P_GPLL0, 9.5, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
> +	.cmd_rcgr = 0x1a00c,
> +	.mnd_width = 16,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_uart1_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
> +	.cmd_rcgr = 0x1c00c,
> +	.mnd_width = 16,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp1_uart2_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x26020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup1_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x2600c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup1_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x28020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup2_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x2800c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup2_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x2a020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup3_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x2a00c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup3_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
> +	.cmd_rcgr = 0x2c020,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup4_i2c_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
> +	.cmd_rcgr = 0x2c00c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_qup4_spi_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
> +	.cmd_rcgr = 0x2700c,
> +	.mnd_width = 16,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_uart1_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
> +	.cmd_rcgr = 0x2900c,
> +	.mnd_width = 16,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "blsp2_uart2_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_gp1_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(100000000, P_GPLL0, 6, 0, 0),
> +	F(200000000, P_GPLL0, 3, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 gp1_clk_src = {
> +	.cmd_rcgr = 0x64004,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
> +	.freq_tbl = ftbl_gp1_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "gp1_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
> +		.num_parents = 4,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 gp2_clk_src = {
> +	.cmd_rcgr = 0x65004,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
> +	.freq_tbl = ftbl_gp1_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "gp2_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
> +		.num_parents = 4,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 gp3_clk_src = {
> +	.cmd_rcgr = 0x66004,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
> +	.freq_tbl = ftbl_gp1_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "gp3_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
> +		.num_parents = 4,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
> +	F(300000000, P_GPLL0, 2, 0, 0),
> +	F(600000000, P_GPLL0, 1, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 hmss_gpll0_clk_src = {
> +	.cmd_rcgr = 0x4805c,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_hmss_gpll0_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "hmss_gpll0_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
> +	F(384000000, P_GPLL4, 4, 0, 0),
> +	F(768000000, P_GPLL4, 2, 0, 0),
> +	F(1536000000, P_GPLL4, 1, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 hmss_gpll4_clk_src = {
> +	.cmd_rcgr = 0x48074,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll4,
> +	.freq_tbl = ftbl_hmss_gpll4_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "hmss_gpll4_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll4,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 hmss_rbcpr_clk_src = {
> +	.cmd_rcgr = 0x48044,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "hmss_rbcpr_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_pdm2_clk_src[] = {
> +	F(60000000, P_GPLL0, 10, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 pdm2_clk_src = {
> +	.cmd_rcgr = 0x33010,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_pdm2_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "pdm2_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
> +	F(160400000, P_GPLL1, 5, 0, 0),
> +	F(267333333, P_GPLL1, 3, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 qspi_ser_clk_src = {
> +	.cmd_rcgr = 0x4d00c,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
> +	.freq_tbl = ftbl_qspi_ser_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "qspi_ser_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
> +		.num_parents = 6,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
> +	F(144000, P_XO, 16, 3, 25),
> +	F(400000, P_XO, 12, 1, 4),
> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
> +	F(100000000, P_GPLL0, 6, 0, 0),
> +	F(192000000, P_GPLL4, 8, 0, 0),
> +	F(384000000, P_GPLL4, 4, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 sdcc1_apps_clk_src = {
> +	.cmd_rcgr = 0x1602c,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
> +	.freq_tbl = ftbl_sdcc1_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "sdcc1_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
> +		.num_parents = 4,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
> +	F(150000000, P_GPLL0, 4, 0, 0),
> +	F(200000000, P_GPLL0, 3, 0, 0),
> +	F(300000000, P_GPLL0, 2, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 sdcc1_ice_core_clk_src = {
> +	.cmd_rcgr = 0x16010,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "sdcc1_ice_core_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
> +	F(144000, P_XO, 16, 3, 25),
> +	F(400000, P_XO, 12, 1, 4),
> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
> +	F(100000000, P_GPLL0, 6, 0, 0),
> +	F(192000000, P_GPLL4, 8, 0, 0),
> +	F(200000000, P_GPLL0, 3, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 sdcc2_apps_clk_src = {
> +	.cmd_rcgr = 0x14010,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
> +	.freq_tbl = ftbl_sdcc2_apps_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "sdcc2_apps_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
> +		.num_parents = 4,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
> +	F(100000000, P_GPLL0, 6, 0, 0),
> +	F(150000000, P_GPLL0, 4, 0, 0),
> +	F(200000000, P_GPLL0, 3, 0, 0),
> +	F(240000000, P_GPLL0, 2.5, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 ufs_axi_clk_src = {
> +	.cmd_rcgr = 0x75018,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_ufs_axi_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "ufs_axi_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
> +	F(150000000, P_GPLL0, 4, 0, 0),
> +	F(300000000, P_GPLL0, 2, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 ufs_ice_core_clk_src = {
> +	.cmd_rcgr = 0x76010,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_ufs_ice_core_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "ufs_ice_core_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_rcg2 ufs_phy_aux_clk_src = {
> +	.cmd_rcgr = 0x76044,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_sleep_clk,
> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "ufs_phy_aux_clk_src",
> +		.parent_names = gcc_parent_names_xo_sleep_clk,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
> +	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
> +	F(75000000, P_GPLL0, 8, 0, 0),
> +	F(150000000, P_GPLL0, 4, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 ufs_unipro_core_clk_src = {
> +	.cmd_rcgr = 0x76028,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "ufs_unipro_core_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(60000000, P_GPLL0, 10, 0, 0),
> +	F(120000000, P_GPLL0, 5, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 usb20_master_clk_src = {
> +	.cmd_rcgr = 0x2f010,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_usb20_master_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "usb20_master_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(60000000, P_GPLL0, 10, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 usb20_mock_utmi_clk_src = {
> +	.cmd_rcgr = 0x2f024,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "usb20_mock_utmi_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
> +	F(120000000, P_GPLL0, 5, 0, 0),
> +	F(133333333, P_GPLL0, 4.5, 0, 0),
> +	F(150000000, P_GPLL0, 4, 0, 0),
> +	F(200000000, P_GPLL0, 3, 0, 0),
> +	F(240000000, P_GPLL0, 2.5, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 usb30_master_clk_src = {
> +	.cmd_rcgr = 0xf014,
> +	.mnd_width = 8,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_usb30_master_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "usb30_master_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
> +	F(19200000, P_XO, 1, 0, 0),
> +	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
> +	F(60000000, P_GPLL0, 10, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 usb30_mock_utmi_clk_src = {
> +	.cmd_rcgr = 0xf028,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
> +	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "usb30_mock_utmi_clk_src",
> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
> +		.num_parents = 3,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
> +	F(1200000, P_XO, 16, 0, 0),
> +	F(19200000, P_XO, 1, 0, 0),
> +	{ }
> +};
> +
> +static struct clk_rcg2 usb3_phy_aux_clk_src = {
> +	.cmd_rcgr = 0x5000c,
> +	.mnd_width = 0,
> +	.hid_width = 5,
> +	.parent_map = gcc_parent_map_xo_sleep_clk,
> +	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
> +	.clkr.hw.init = &(struct clk_init_data){
> +		.name = "usb3_phy_aux_clk_src",
> +		.parent_names = gcc_parent_names_xo_sleep_clk,
> +		.num_parents = 2,
> +		.ops = &clk_rcg2_ops,
> +	},
> +};
> +
> +static struct clk_branch gcc_aggre2_ufs_axi_clk = {
> +	.halt_reg = 0x75034,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x75034,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_aggre2_ufs_axi_clk",
> +			.parent_names = (const char *[]){
> +				"ufs_axi_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_aggre2_usb3_axi_clk = {
> +	.halt_reg = 0xf03c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0xf03c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_aggre2_usb3_axi_clk",
> +			.parent_names = (const char *[]){
> +				"usb30_master_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_bimc_gfx_clk = {
> +	.halt_reg = 0x7106c,
> +	.halt_check = BRANCH_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x7106c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_bimc_gfx_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_bimc_hmss_axi_clk = {
> +	.halt_reg = 0x48004,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x52004,
> +		.enable_mask = BIT(22),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_bimc_hmss_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
> +	.halt_reg = 0x4401c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x4401c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_bimc_mss_q6_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_ahb_clk = {
> +	.halt_reg = 0x17004,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x52004,
> +		.enable_mask = BIT(17),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
> +	.halt_reg = 0x19008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x19008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup1_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup1_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
> +	.halt_reg = 0x19004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x19004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup1_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup1_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
> +	.halt_reg = 0x1b008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1b008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup2_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup2_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
> +	.halt_reg = 0x1b004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1b004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup2_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup2_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
> +	.halt_reg = 0x1d008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1d008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup3_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup3_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
> +	.halt_reg = 0x1d004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1d004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup3_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup3_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
> +	.halt_reg = 0x1f008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1f008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup4_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup4_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
> +	.halt_reg = 0x1f004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1f004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_qup4_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_qup4_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_uart1_apps_clk = {
> +	.halt_reg = 0x1a004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1a004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_uart1_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_uart1_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp1_uart2_apps_clk = {
> +	.halt_reg = 0x1c004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1c004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp1_uart2_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp1_uart2_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_ahb_clk = {
> +	.halt_reg = 0x25004,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x52004,
> +		.enable_mask = BIT(15),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
> +	.halt_reg = 0x26008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x26008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup1_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup1_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
> +	.halt_reg = 0x26004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x26004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup1_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup1_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
> +	.halt_reg = 0x28008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x28008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup2_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup2_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
> +	.halt_reg = 0x28004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x28004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup2_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup2_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
> +	.halt_reg = 0x2a008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2a008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup3_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup3_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
> +	.halt_reg = 0x2a004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2a004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup3_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup3_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
> +	.halt_reg = 0x2c008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2c008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup4_i2c_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup4_i2c_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
> +	.halt_reg = 0x2c004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2c004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_qup4_spi_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_qup4_spi_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_uart1_apps_clk = {
> +	.halt_reg = 0x27004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x27004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_uart1_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_uart1_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_blsp2_uart2_apps_clk = {
> +	.halt_reg = 0x29004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x29004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_blsp2_uart2_apps_clk",
> +			.parent_names = (const char *[]){
> +				"blsp2_uart2_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_boot_rom_ahb_clk = {
> +	.halt_reg = 0x38004,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x52004,
> +		.enable_mask = BIT(10),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_boot_rom_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_cfg_noc_usb2_axi_clk = {
> +	.halt_reg = 0x5058,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x5058,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_cfg_noc_usb2_axi_clk",
> +			.parent_names = (const char *[]){
> +				"usb20_master_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_cfg_noc_usb3_axi_clk = {
> +	.halt_reg = 0x5018,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x5018,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_cfg_noc_usb3_axi_clk",
> +			.parent_names = (const char *[]){
> +				"usb30_master_clk_src",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_dcc_ahb_clk = {
> +	.halt_reg = 0x84004,
> +	.clkr = {
> +		.enable_reg = 0x84004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_dcc_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gp1_clk = {
> +	.halt_reg = 0x64000,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x64000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gp1_clk",
> +			.parent_names = (const char *[]){
> +				"gp1_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gp2_clk = {
> +	.halt_reg = 0x65000,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x65000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gp2_clk",
> +			.parent_names = (const char *[]){
> +				"gp2_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gp3_clk = {
> +	.halt_reg = 0x66000,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x66000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gp3_clk",
> +			.parent_names = (const char *[]){
> +				"gp3_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gpu_bimc_gfx_clk = {
> +	.halt_reg = 0x71010,
> +	.halt_check = BRANCH_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x71010,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gpu_bimc_gfx_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gpu_cfg_ahb_clk = {
> +	.halt_reg = 0x71004,
> +	.halt_check = BRANCH_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x71004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gpu_cfg_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gpu_gpll0_clk = {
> +	.halt_reg = 0x5200c,
> +	.halt_check = BRANCH_HALT_DELAY,
> +	.clkr = {
> +		.enable_reg = 0x5200c,
> +		.enable_mask = BIT(4),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gpu_gpll0_clk",
> +			.parent_names = (const char *[]){
> +				"gpll0",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_gpu_gpll0_div_clk = {
> +	.halt_reg = 0x5200c,
> +	.halt_check = BRANCH_HALT_DELAY,
> +	.clkr = {
> +		.enable_reg = 0x5200c,
> +		.enable_mask = BIT(3),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_gpu_gpll0_div_clk",
> +			.parent_names = (const char *[]){
> +				"gpll0_early_div",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_hmss_dvm_bus_clk = {
> +	.halt_reg = 0x4808c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x4808c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_hmss_dvm_bus_clk",
> +			.ops = &clk_branch2_ops,
> +			.flags = CLK_IGNORE_UNUSED,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_hmss_rbcpr_clk = {
> +	.halt_reg = 0x48008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x48008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_hmss_rbcpr_clk",
> +			.parent_names = (const char *[]){
> +				"hmss_rbcpr_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mmss_gpll0_clk = {
> +	.halt_reg = 0x5200c,
> +	.halt_check = BRANCH_HALT_DELAY,
> +	.clkr = {
> +		.enable_reg = 0x5200c,
> +		.enable_mask = BIT(1),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mmss_gpll0_clk",
> +			.parent_names = (const char *[]){
> +				"gpll0",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mmss_gpll0_div_clk = {
> +	.halt_reg = 0x5200c,
> +	.halt_check = BRANCH_HALT_DELAY,
> +	.clkr = {
> +		.enable_reg = 0x5200c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mmss_gpll0_div_clk",
> +			.parent_names = (const char *[]){
> +				"gpll0_early_div",
> +			},
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
> +	.halt_reg = 0x9004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x9004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mmss_noc_cfg_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mmss_sys_noc_axi_clk = {
> +	.halt_reg = 0x9000,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x9000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mmss_sys_noc_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mss_cfg_ahb_clk = {
> +	.halt_reg = 0x8a000,
> +	.clkr = {
> +		.enable_reg = 0x8a000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mss_cfg_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
> +	.halt_reg = 0x8a004,
> +	.clkr = {
> +		.enable_reg = 0x8a004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mss_mnoc_bimc_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
> +	.halt_reg = 0x8a040,
> +	.clkr = {
> +		.enable_reg = 0x8a040,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mss_q6_bimc_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_mss_snoc_axi_clk = {
> +	.halt_reg = 0x8a03c,
> +	.clkr = {
> +		.enable_reg = 0x8a03c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_mss_snoc_axi_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_pdm2_clk = {
> +	.halt_reg = 0x3300c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x3300c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_pdm2_clk",
> +			.parent_names = (const char *[]){
> +				"pdm2_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_pdm_ahb_clk = {
> +	.halt_reg = 0x33004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x33004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_pdm_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_prng_ahb_clk = {
> +	.halt_reg = 0x34004,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x52004,
> +		.enable_mask = BIT(13),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_prng_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_qspi_ahb_clk = {
> +	.halt_reg = 0x4d004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x4d004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_qspi_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_qspi_ser_clk = {
> +	.halt_reg = 0x4d008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x4d008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_qspi_ser_clk",
> +			.parent_names = (const char *[]){
> +				"qspi_ser_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_rx0_usb2_clkref_clk = {
> +	.halt_reg = 0x88018,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x88018,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_rx0_usb2_clkref_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_rx1_usb2_clkref_clk = {
> +	.halt_reg = 0x88014,
> +	.halt_check = BRANCH_HALT_VOTED,
> +	.clkr = {
> +		.enable_reg = 0x88014,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_rx1_usb2_clkref_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_sdcc1_ahb_clk = {
> +	.halt_reg = 0x16008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x16008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_sdcc1_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_sdcc1_apps_clk = {
> +	.halt_reg = 0x16004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x16004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_sdcc1_apps_clk",
> +			.parent_names = (const char *[]){
> +				"sdcc1_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_sdcc1_ice_core_clk = {
> +	.halt_reg = 0x1600c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x1600c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_sdcc1_ice_core_clk",
> +			.parent_names = (const char *[]){
> +				"sdcc1_ice_core_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_sdcc2_ahb_clk = {
> +	.halt_reg = 0x14008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x14008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_sdcc2_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_sdcc2_apps_clk = {
> +	.halt_reg = 0x14004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x14004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_sdcc2_apps_clk",
> +			.parent_names = (const char *[]){
> +				"sdcc2_apps_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_ahb_clk = {
> +	.halt_reg = 0x7500c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x7500c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_ahb_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_axi_clk = {
> +	.halt_reg = 0x75008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x75008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_axi_clk",
> +			.parent_names = (const char *[]){
> +				"ufs_axi_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_clkref_clk = {
> +	.halt_reg = 0x88008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x88008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_clkref_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_ice_core_clk = {
> +	.halt_reg = 0x7600c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x7600c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_ice_core_clk",
> +			.parent_names = (const char *[]){
> +				"ufs_ice_core_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_phy_aux_clk = {
> +	.halt_reg = 0x76040,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x76040,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_phy_aux_clk",
> +			.parent_names = (const char *[]){
> +				"ufs_phy_aux_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
> +	.halt_reg = 0x75014,
> +	.halt_check = BRANCH_HALT_SKIP,
> +	.clkr = {
> +		.enable_reg = 0x75014,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_rx_symbol_0_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
> +	.halt_reg = 0x7605c,
> +	.halt_check = BRANCH_HALT_SKIP,
> +	.clkr = {
> +		.enable_reg = 0x7605c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_rx_symbol_1_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
> +	.halt_reg = 0x75010,
> +	.halt_check = BRANCH_HALT_SKIP,
> +	.clkr = {
> +		.enable_reg = 0x75010,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_tx_symbol_0_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_ufs_unipro_core_clk = {
> +	.halt_reg = 0x76008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x76008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_ufs_unipro_core_clk",
> +			.parent_names = (const char *[]){
> +				"ufs_unipro_core_clk_src",
> +			},
> +			.flags = CLK_SET_RATE_PARENT,
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb20_master_clk = {
> +	.halt_reg = 0x2f004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2f004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb20_master_clk",
> +			.parent_names = (const char *[]){
> +				"usb20_master_clk_src"
> +			},
> +			.flags = CLK_SET_RATE_PARENT,
> +			.num_parents = 1,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb20_mock_utmi_clk = {
> +	.halt_reg = 0x2f00c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2f00c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb20_mock_utmi_clk",
> +			.parent_names = (const char *[]){
> +				"usb20_mock_utmi_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb20_sleep_clk = {
> +	.halt_reg = 0x2f008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x2f008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb20_sleep_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb30_master_clk = {
> +	.halt_reg = 0xf008,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0xf008,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb30_master_clk",
> +			.parent_names = (const char *[]){
> +				"usb30_master_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb30_mock_utmi_clk = {
> +	.halt_reg = 0xf010,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0xf010,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb30_mock_utmi_clk",
> +			.parent_names = (const char *[]){
> +				"usb30_mock_utmi_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb30_sleep_clk = {
> +	.halt_reg = 0xf00c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0xf00c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb30_sleep_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb3_clkref_clk = {
> +	.halt_reg = 0x8800c,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x8800c,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb3_clkref_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb3_phy_aux_clk = {
> +	.halt_reg = 0x50000,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x50000,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb3_phy_aux_clk",
> +			.parent_names = (const char *[]){
> +				"usb3_phy_aux_clk_src",
> +			},
> +			.num_parents = 1,
> +			.flags = CLK_SET_RATE_PARENT,
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb3_phy_pipe_clk = {
> +	.halt_reg = 0x50004,
> +	.halt_check = BRANCH_HALT_DELAY,
> +	.clkr = {
> +		.enable_reg = 0x50004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb3_phy_pipe_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
> +	.halt_reg = 0x6a004,
> +	.halt_check = BRANCH_HALT,
> +	.clkr = {
> +		.enable_reg = 0x6a004,
> +		.enable_mask = BIT(0),
> +		.hw.init = &(struct clk_init_data){
> +			.name = "gcc_usb_phy_cfg_ahb2phy_clk",
> +			.ops = &clk_branch2_ops,
> +		},
> +	},
> +};
> +
> +static struct gdsc ufs_gdsc = {
> +	.gdscr = 0x75004,
> +	.gds_hw_ctrl = 0x0,
> +	.pd = {
> +		.name = "ufs_gdsc",
> +	},
> +	.pwrsts = PWRSTS_OFF_ON,
> +	.flags = VOTABLE,
> +};
> +
> +static struct gdsc usb_30_gdsc = {
> +	.gdscr = 0xf004,
> +	.gds_hw_ctrl = 0x0,
> +	.pd = {
> +		.name = "usb_30_gdsc",
> +	},
> +	.pwrsts = PWRSTS_OFF_ON,
> +	.flags = VOTABLE,
> +};
> +
> +static struct gdsc pcie_0_gdsc = {
> +	.gdscr = 0x6b004,
> +	.gds_hw_ctrl = 0x0,
> +	.pd = {
> +		.name = "pcie_0_gdsc",
> +	},
> +	.pwrsts = PWRSTS_OFF_ON,
> +	.flags = VOTABLE,
> +};
> +
> +struct clk_hw *gcc_sdm660_hws[] = {
> +	[GCC_XO] = &xo.hw,
> +	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
> +	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,
> +};
> +
> +static struct clk_regmap *gcc_660_clocks[] = {
> +	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
> +	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
> +	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
> +	[BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
> +	[BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
> +	[BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
> +	[BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
> +	[BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
> +	[BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
> +	[BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
> +	[BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
> +	[BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
> +	[BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
> +	[BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
> +	[BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
> +	[BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
> +	[BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
> +	[BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
> +	[BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
> +	[BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
> +	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
> +	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
> +	[GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
> +	[GCC_BIMC_HMSS_AXI_CLK] = &gcc_bimc_hmss_axi_clk.clkr,
> +	[GCC_BIMC_MSS_Q6_AXI_CLK] = &gcc_bimc_mss_q6_axi_clk.clkr,
> +	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
> +	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
> +	[GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
> +	[GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
> +	[GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
> +	[GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
> +	[GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
> +	[GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
> +	[GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
> +	[GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
> +	[GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
> +	[GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
> +	[GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
> +	[GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
> +	[GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
> +	[GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
> +	[GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
> +	[GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
> +	[GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
> +	[GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
> +	[GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
> +	[GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
> +	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
> +	[GCC_CFG_NOC_USB2_AXI_CLK] = &gcc_cfg_noc_usb2_axi_clk.clkr,
> +	[GCC_CFG_NOC_USB3_AXI_CLK] = &gcc_cfg_noc_usb3_axi_clk.clkr,
> +	[GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
> +	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
> +	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
> +	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
> +	[GCC_GPU_BIMC_GFX_CLK] = &gcc_gpu_bimc_gfx_clk.clkr,
> +	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
> +	[GCC_GPU_GPLL0_CLK] = &gcc_gpu_gpll0_clk.clkr,
> +	[GCC_GPU_GPLL0_DIV_CLK] = &gcc_gpu_gpll0_div_clk.clkr,
> +	[GCC_HMSS_DVM_BUS_CLK] = &gcc_hmss_dvm_bus_clk.clkr,
> +	[GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
> +	[GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
> +	[GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
> +	[GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
> +	[GCC_MMSS_SYS_NOC_AXI_CLK] = &gcc_mmss_sys_noc_axi_clk.clkr,
> +	[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
> +	[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
> +	[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
> +	[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
> +	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
> +	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
> +	[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
> +	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
> +	[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
> +	[GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
> +	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
> +	[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
> +	[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
> +	[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
> +	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
> +	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
> +	[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
> +	[GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
> +	[GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
> +	[GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
> +	[GCC_UFS_PHY_AUX_CLK] = &gcc_ufs_phy_aux_clk.clkr,
> +	[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
> +	[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
> +	[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
> +	[GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
> +	[GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
> +	[GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
> +	[GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
> +	[GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
> +	[GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
> +	[GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
> +	[GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
> +	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
> +	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
> +	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
> +	[GP1_CLK_SRC] = &gp1_clk_src.clkr,
> +	[GP2_CLK_SRC] = &gp2_clk_src.clkr,
> +	[GP3_CLK_SRC] = &gp3_clk_src.clkr,
> +	[GPLL0] = &gpll0.clkr,
> +	[GPLL0_EARLY] = &gpll0_early.clkr,
> +	[GPLL1] = &gpll1.clkr,
> +	[GPLL1_EARLY] = &gpll1_early.clkr,
> +	[GPLL1] = &gpll1.clkr,
> +	[GPLL4_EARLY] = &gpll4_early.clkr,
> +	[GPLL4] = &gpll4.clkr,
> +	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
> +	[HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
> +	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
> +	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
> +	[QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
> +	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
> +	[SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
> +	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
> +	[UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
> +	[UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
> +	[UFS_PHY_AUX_CLK_SRC] = &ufs_phy_aux_clk_src.clkr,
> +	[UFS_UNIPRO_CORE_CLK_SRC] = &ufs_unipro_core_clk_src.clkr,
> +	[USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
> +	[USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
> +	[USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
> +	[USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
> +	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
> +};
> +
> +static struct gdsc *gcc_660_gdscs[] = {
> +	[UFS_GDSC] = &ufs_gdsc,
> +	[USB_30_GDSC] = &usb_30_gdsc,
> +	[PCIE_0_GDSC] = &pcie_0_gdsc,
> +};
> +
> +static const struct qcom_reset_map gcc_660_resets[] = {
> +	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
> +	[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
> +	[GCC_UFS_BCR] = { 0x75000 },
> +	[GCC_USB3_DP_PHY_BCR] = { 0x50028 },
> +	[GCC_USB3_PHY_BCR] = { 0x50020 },
> +	[GCC_USB3PHY_PHY_BCR] = { 0x50024 },
> +	[GCC_USB_20_BCR] = { 0x2f000 },
> +	[GCC_USB_30_BCR] = { 0xf000 },
> +	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
> +};
> +
> +static const struct regmap_config gcc_660_regmap_config = {
> +	.reg_bits	= 32,
> +	.reg_stride	= 4,
> +	.val_bits	= 32,
> +	.max_register	= 0x94000,
> +	.fast_io	= true,
> +};
> +
> +static const struct qcom_cc_desc gcc_660_desc = {
> +	.config = &gcc_660_regmap_config,
> +	.clks = gcc_660_clocks,
> +	.num_clks = ARRAY_SIZE(gcc_660_clocks),
> +	.resets = gcc_660_resets,
> +	.num_resets = ARRAY_SIZE(gcc_660_resets),
> +	.gdscs = gcc_660_gdscs,
> +	.num_gdscs = ARRAY_SIZE(gcc_660_gdscs),
> +};
> +
> +static const struct of_device_id gcc_660_match_table[] = {
> +	{ .compatible = "qcom,gcc-sdm660" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, gcc_660_match_table);
> +
> +static int gcc_660_probe(struct platform_device *pdev)
> +{
> +	int i, ret = 0;
> +	struct regmap *regmap;
> +
> +	regmap = qcom_cc_map(pdev, &gcc_660_desc);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	/*
> +	 * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
> +	 * turned off by hardware during certain apps low power modes.
> +	 */
> +	ret = regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
> +	if (ret)
> +		return ret;
> +
> +	/* Register the hws */
> +	for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) {
> +		ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return qcom_cc_really_probe(pdev, &gcc_660_desc, regmap);
> +}
> +
> +static struct platform_driver gcc_660_driver = {
> +	.probe		= gcc_660_probe,
> +	.driver		= {
> +		.name	= "gcc-sdm660",
> +		.of_match_table = gcc_660_match_table,
> +	},
> +};
> +
> +static int __init gcc_660_init(void)
> +{
> +	return platform_driver_register(&gcc_660_driver);
> +}
> +core_initcall_sync(gcc_660_init);
> +
> +static void __exit gcc_660_exit(void)
> +{
> +	platform_driver_unregister(&gcc_660_driver);
> +}
> +module_exit(gcc_660_exit);
> +
> +MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
> diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
> new file mode 100644
> index 000000000000..76aabcc5e7e3
> --- /dev/null
> +++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
> @@ -0,0 +1,159 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2018, Craig Tatlor.
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_MSM_GCC_660_H
> +#define _DT_BINDINGS_CLK_MSM_GCC_660_H
> +
> +#define GCC_XO					0
> +#define GCC_GPLL0_EARLY_DIV			1
> +#define GCC_GPLL1_EARLY_DIV			2
> +#define BLSP1_QUP1_I2C_APPS_CLK_SRC		3
> +#define BLSP1_QUP1_SPI_APPS_CLK_SRC		4
> +#define BLSP1_QUP2_I2C_APPS_CLK_SRC		5
> +#define BLSP1_QUP2_SPI_APPS_CLK_SRC		6
> +#define BLSP1_QUP3_I2C_APPS_CLK_SRC		7
> +#define BLSP1_QUP3_SPI_APPS_CLK_SRC		8
> +#define BLSP1_QUP4_I2C_APPS_CLK_SRC		9
> +#define BLSP1_QUP4_SPI_APPS_CLK_SRC		10
> +#define BLSP1_UART1_APPS_CLK_SRC		11
> +#define BLSP1_UART2_APPS_CLK_SRC		12
> +#define BLSP2_QUP1_I2C_APPS_CLK_SRC		13
> +#define BLSP2_QUP1_SPI_APPS_CLK_SRC		14
> +#define BLSP2_QUP2_I2C_APPS_CLK_SRC		15
> +#define BLSP2_QUP2_SPI_APPS_CLK_SRC		16
> +#define BLSP2_QUP3_I2C_APPS_CLK_SRC		17
> +#define BLSP2_QUP3_SPI_APPS_CLK_SRC		18
> +#define BLSP2_QUP4_I2C_APPS_CLK_SRC		19
> +#define BLSP2_QUP4_SPI_APPS_CLK_SRC		20
> +#define BLSP2_UART1_APPS_CLK_SRC		21
> +#define BLSP2_UART2_APPS_CLK_SRC		22
> +#define GCC_AGGRE2_UFS_AXI_CLK			23
> +#define GCC_AGGRE2_USB3_AXI_CLK			24
> +#define GCC_BIMC_GFX_CLK			25
> +#define GCC_BIMC_HMSS_AXI_CLK			26
> +#define GCC_BIMC_MSS_Q6_AXI_CLK			27
> +#define GCC_BLSP1_AHB_CLK			28
> +#define GCC_BLSP1_QUP1_I2C_APPS_CLK		29
> +#define GCC_BLSP1_QUP1_SPI_APPS_CLK		30
> +#define GCC_BLSP1_QUP2_I2C_APPS_CLK		31
> +#define GCC_BLSP1_QUP2_SPI_APPS_CLK		32
> +#define GCC_BLSP1_QUP3_I2C_APPS_CLK		33
> +#define GCC_BLSP1_QUP3_SPI_APPS_CLK		34
> +#define GCC_BLSP1_QUP4_I2C_APPS_CLK		35
> +#define GCC_BLSP1_QUP4_SPI_APPS_CLK		36
> +#define GCC_BLSP1_UART1_APPS_CLK		37
> +#define GCC_BLSP1_UART2_APPS_CLK		38
> +#define GCC_BLSP2_AHB_CLK			39
> +#define GCC_BLSP2_QUP1_I2C_APPS_CLK		40
> +#define GCC_BLSP2_QUP1_SPI_APPS_CLK		41
> +#define GCC_BLSP2_QUP2_I2C_APPS_CLK		42
> +#define GCC_BLSP2_QUP2_SPI_APPS_CLK		43
> +#define GCC_BLSP2_QUP3_I2C_APPS_CLK		44
> +#define GCC_BLSP2_QUP3_SPI_APPS_CLK		46
> +#define GCC_BLSP2_QUP4_I2C_APPS_CLK		45
> +#define GCC_BLSP2_QUP4_SPI_APPS_CLK		46
> +#define GCC_BLSP2_UART1_APPS_CLK		47
> +#define GCC_BLSP2_UART2_APPS_CLK		48
> +#define GCC_BOOT_ROM_AHB_CLK			49
> +#define GCC_CFG_NOC_USB2_AXI_CLK		50
> +#define GCC_CFG_NOC_USB3_AXI_CLK		51
> +#define GCC_DCC_AHB_CLK				52
> +#define GCC_GP1_CLK				53
> +#define GCC_GP2_CLK				54
> +#define GCC_GP3_CLK				55
> +#define GCC_GPU_BIMC_GFX_CLK			56
> +#define GCC_GPU_CFG_AHB_CLK			57
> +#define GCC_GPU_GPLL0_CLK			58
> +#define GCC_GPU_GPLL0_DIV_CLK			59
> +#define GCC_HMSS_DVM_BUS_CLK			60
> +#define GCC_HMSS_RBCPR_CLK			61
> +#define GCC_MMSS_GPLL0_CLK			62
> +#define GCC_MMSS_GPLL0_DIV_CLK			63
> +#define GCC_MMSS_NOC_CFG_AHB_CLK		64
> +#define GCC_MMSS_SYS_NOC_AXI_CLK		65
> +#define GCC_MSS_CFG_AHB_CLK			66
> +#define GCC_MSS_GPLL0_DIV_CLK			67
> +#define GCC_MSS_MNOC_BIMC_AXI_CLK		68
> +#define GCC_MSS_Q6_BIMC_AXI_CLK			69
> +#define GCC_MSS_SNOC_AXI_CLK			70
> +#define GCC_PDM2_CLK				71
> +#define GCC_PDM_AHB_CLK				72
> +#define GCC_PRNG_AHB_CLK			73
> +#define GCC_QSPI_AHB_CLK			74
> +#define GCC_QSPI_SER_CLK			75
> +#define GCC_SDCC1_AHB_CLK			76
> +#define GCC_SDCC1_APPS_CLK			77
> +#define GCC_SDCC1_ICE_CORE_CLK			78
> +#define GCC_SDCC2_AHB_CLK			79
> +#define GCC_SDCC2_APPS_CLK			80
> +#define GCC_UFS_AHB_CLK				81
> +#define GCC_UFS_AXI_CLK				82
> +#define GCC_UFS_CLKREF_CLK			83
> +#define GCC_UFS_ICE_CORE_CLK			84
> +#define GCC_UFS_PHY_AUX_CLK			85
> +#define GCC_UFS_RX_SYMBOL_0_CLK			86
> +#define GCC_UFS_RX_SYMBOL_1_CLK			87
> +#define GCC_UFS_TX_SYMBOL_0_CLK			88
> +#define GCC_UFS_UNIPRO_CORE_CLK			89
> +#define GCC_USB20_MASTER_CLK			90
> +#define GCC_USB20_MOCK_UTMI_CLK			91
> +#define GCC_USB20_SLEEP_CLK			92
> +#define GCC_USB30_MASTER_CLK			93
> +#define GCC_USB30_MOCK_UTMI_CLK			94
> +#define GCC_USB30_SLEEP_CLK			95
> +#define GCC_USB3_CLKREF_CLK			96
> +#define GCC_USB3_PHY_AUX_CLK			97
> +#define GCC_USB3_PHY_PIPE_CLK			98
> +#define GCC_USB_PHY_CFG_AHB2PHY_CLK		99
> +#define GP1_CLK_SRC				100
> +#define GP2_CLK_SRC				101
> +#define GP3_CLK_SRC				102
> +#define GPLL0					103
> +#define GPLL0_EARLY				104
> +#define GPLL1					105
> +#define GPLL1_EARLY				106
> +#define GPLL4					107
> +#define GPLL4_EARLY				108
> +#define HMSS_GPLL0_CLK_SRC			109
> +#define HMSS_GPLL4_CLK_SRC			110
> +#define HMSS_RBCPR_CLK_SRC			111
> +#define PDM2_CLK_SRC				112
> +#define QSPI_SER_CLK_SRC			113
> +#define SDCC1_APPS_CLK_SRC			114
> +#define SDCC1_ICE_CORE_CLK_SRC			115
> +#define SDCC2_APPS_CLK_SRC			116
> +#define UFS_AXI_CLK_SRC				117
> +#define UFS_ICE_CORE_CLK_SRC			118
> +#define UFS_PHY_AUX_CLK_SRC			119
> +#define UFS_UNIPRO_CORE_CLK_SRC			120
> +#define USB20_MASTER_CLK_SRC			121
> +#define USB20_MOCK_UTMI_CLK_SRC			122
> +#define USB30_MASTER_CLK_SRC			123
> +#define USB30_MOCK_UTMI_CLK_SRC			124
> +#define USB3_PHY_AUX_CLK_SRC			125
> +#define GPLL0_OUT_MSSCC				126
> +#define GCC_UFS_AXI_HW_CTL_CLK			127
> +#define GCC_UFS_ICE_CORE_HW_CTL_CLK		128
> +#define GCC_UFS_PHY_AUX_HW_CTL_CLK		129
> +#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		130
> +#define GCC_RX0_USB2_CLKREF_CLK			131
> +#define GCC_RX1_USB2_CLKREF_CLK			132
> +
> +#define PCIE_0_GDSC	0
> +#define UFS_GDSC	1
> +#define USB_30_GDSC	2
> +
> +#define GCC_QUSB2PHY_PRIM_BCR		0
> +#define GCC_QUSB2PHY_SEC_BCR		1
> +#define GCC_UFS_BCR			2
> +#define GCC_USB3_DP_PHY_BCR		3
> +#define GCC_USB3_PHY_BCR		4
> +#define GCC_USB3PHY_PHY_BCR		5
> +#define GCC_USB_20_BCR                  6
> +#define GCC_USB_30_BCR			7
> +#define GCC_USB_PHY_CFG_AHB2PHY_BCR	8
> +
> +#endif
> 

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.

--

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-13  6:55   ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Taniya Das
@ 2018-08-13  7:45     ` Craig Tatlor
  2018-09-24 12:44       ` Heiko Stuebner
  2018-08-13  9:44     ` Craig Tatlor
  1 sibling, 1 reply; 60+ messages in thread
From: Craig Tatlor @ 2018-08-13  7:45 UTC (permalink / raw)
  To: Taniya Das
  Cc: linux-arm-msm, Michael Turquette, Stephen Boyd, Rob Herring,
	Mark Rutland, Andy Gross, David Brown, linux-clk, devicetree,
	linux-kernel, linux-soc



On 13 August 2018 07:55:34 BST, Taniya Das <tdas@codeaurora.org> wrote:
>Hello Craig,
>
>Could you please correct the authorship and also provide the reference 
>to code where this is picked from?
Okay, 
Got code from here https://github.com/sonyxperiadev/kernel/blob/aosp/LA.UM.6.4.r1/drivers/clk/qcom/gcc-sdm660.c
but changed it quite a bit for upstream,
Should I change the commit author and add your signed off by and say I did cleanups on my signed off by.

Also, hey, you wrote the original driver :)
>
>On 8/11/2018 1:51 AM, Craig Tatlor wrote:
>> Add support for the global clock controller found on SDM660
>> based devices. This should allow most non-multimedia device
>> drivers to probe and control their clocks.
>> Based on CAF implementation.
>> 
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> ---
>>   .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
>>   drivers/clk/qcom/Kconfig                      |    9 +
>>   drivers/clk/qcom/Makefile                     |    1 +
>>   drivers/clk/qcom/gcc-sdm660.c                 | 2479
>+++++++++++++++++
>>   include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
>>   5 files changed, 2649 insertions(+)
>>   create mode 100644 drivers/clk/qcom/gcc-sdm660.c
>>   create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h
>> 
>> diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> index 664ea1fd6c76..e498ad2e8db8 100644
>> --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> @@ -19,6 +19,7 @@ Required properties :
>>   			"qcom,gcc-msm8996"
>>   			"qcom,gcc-msm8998"
>>   			"qcom,gcc-mdm9615"
>> +			"qcom,gcc-sdm660"
>>   			"qcom,gcc-sdm845"
>>   
>>   - reg : shall contain base register location and length
>> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
>> index 9c3480dcc38a..c4bda6d24c1f 100644
>> --- a/drivers/clk/qcom/Kconfig
>> +++ b/drivers/clk/qcom/Kconfig
>> @@ -226,6 +226,15 @@ config MSM_GCC_8998
>>   	  Say Y if you want to use peripheral devices such as UART, SPI,
>>   	  i2c, USB, UFS, SD/eMMC, PCIe, etc.
>>   
>> +config SDM_GCC_660
>> +	tristate "SDM660 Global Clock Controller"
>> +	select QCOM_GDSC
>> +	depends on COMMON_CLK_QCOM
>> +	help
>> +	  Support for the global clock controller on SDM660 devices.
>> +	  Say Y if you want to use peripheral devices such as UART, SPI,
>> +	  i2C, USB, UFS, SDDC, PCIe, etc.
>> +
>>   config SDM_GCC_845
>>   	tristate "SDM845 Global Clock Controller"
>>   	select QCOM_GDSC
>> diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
>> index 762c01137c2f..6e37d30d7c02 100644
>> --- a/drivers/clk/qcom/Makefile
>> +++ b/drivers/clk/qcom/Makefile
>> @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
>>   obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
>>   obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
>>   obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
>> +obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
>>   obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
>>   obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
>>   obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
>> diff --git a/drivers/clk/qcom/gcc-sdm660.c
>b/drivers/clk/qcom/gcc-sdm660.c
>> new file mode 100644
>> index 000000000000..bdb445aa4baa
>> --- /dev/null
>> +++ b/drivers/clk/qcom/gcc-sdm660.c
>> @@ -0,0 +1,2479 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2016-2017, The Linux Foundation. All rights
>reserved.
>> + * Copyright (c) 2018, Craig Tatlor.
>> + */
>> +
>> +#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,gcc-sdm660.h>
>> +
>> +#include "common.h"
>> +#include "clk-regmap.h"
>> +#include "clk-alpha-pll.h"
>> +#include "clk-rcg.h"
>> +#include "clk-branch.h"
>> +#include "reset.h"
>> +#include "gdsc.h"
>> +
>> +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
>> +
>> +enum {
>> +	P_XO,
>> +	P_SLEEP_CLK,
>> +	P_GPLL0,
>> +	P_GPLL1,
>> +	P_GPLL4,
>> +	P_GPLL0_EARLY_DIV,
>> +	P_GPLL1_EARLY_DIV,
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_gpll0[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_gpll0[] = {
>> +	"xo",
>> +	"gpll0",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_SLEEP_CLK, 5 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"sleep_clk",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
>> +	{ P_XO, 0 },
>> +	{ P_SLEEP_CLK, 5 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_sleep_clk[] = {
>> +	"xo",
>> +	"sleep_clk",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_gpll4[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL4, 5 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_gpll4[] = {
>> +	"xo",
>> +	"gpll4",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] =
>{
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 3 },
>> +	{ P_GPLL1, 4 },
>> +	{ P_GPLL4, 5 },
>> +	{ P_GPLL1_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[]
>= {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +	"gpll1",
>> +	"gpll4",
>> +	"gpll1_early_div",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL4, 5 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll4",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 2 },
>> +	{ P_GPLL4, 5 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +	"gpll4",
>> +};
>> +
>> +static struct clk_fixed_factor xo = {
>> +	.mult = 1,
>> +	.div = 1,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "xo",
>> +		.parent_names = (const char *[]){ "xo_board" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll0_early = {
>> +	.offset = 0x0,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(0),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll0_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor gpll0_early_div = {
>> +	.mult = 1,
>> +	.div = 2,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "gpll0_early_div",
>> +		.parent_names = (const char *[]){ "gpll0_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll0 = {
>> +	.offset = 0x00000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gpll0",
>> +		.parent_names = (const char *[]){ "gpll0_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll1_early = {
>> +	.offset = 0x1000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(1),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll1_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor gpll1_early_div = {
>> +	.mult = 1,
>> +	.div = 2,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "gpll1_early_div",
>> +		.parent_names = (const char *[]){ "gpll1_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll1 = {
>> +	.offset = 0x1000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gpll1",
>> +		.parent_names = (const char *[]){ "gpll1_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll4_early = {
>> +	.offset = 0x77000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(4),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll4_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll4 = {
>> +	.offset = 0x77000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data)
>> +	{
>> +		.name = "gpll4",
>> +		.parent_names = (const char *[]) { "gpll4_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(50000000, P_GPLL0, 12, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x19020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup1_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
>> +	F(960000, P_XO, 10, 1, 2),
>> +	F(4800000, P_XO, 4, 0, 0),
>> +	F(9600000, P_XO, 2, 0, 0),
>> +	F(15000000, P_GPLL0, 10, 1, 4),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(25000000, P_GPLL0, 12, 1, 2),
>> +	F(50000000, P_GPLL0, 12, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1900c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup1_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1b020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup2_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1b00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup2_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1d020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup3_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1d00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup3_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1f020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup4_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1f00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup4_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
>> +	F(3686400, P_GPLL0, 1, 96, 15625),
>> +	F(7372800, P_GPLL0, 1, 192, 15625),
>> +	F(14745600, P_GPLL0, 1, 384, 15625),
>> +	F(16000000, P_GPLL0, 5, 2, 15),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(24000000, P_GPLL0, 5, 1, 5),
>> +	F(32000000, P_GPLL0, 1, 4, 75),
>> +	F(40000000, P_GPLL0, 15, 0, 0),
>> +	F(46400000, P_GPLL0, 1, 29, 375),
>> +	F(48000000, P_GPLL0, 12.5, 0, 0),
>> +	F(51200000, P_GPLL0, 1, 32, 375),
>> +	F(56000000, P_GPLL0, 1, 7, 75),
>> +	F(58982400, P_GPLL0, 1, 1536, 15625),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	F(63157895, P_GPLL0, 9.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
>> +	.cmd_rcgr = 0x1a00c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_uart1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
>> +	.cmd_rcgr = 0x1c00c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_uart2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x26020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup1_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2600c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup1_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x28020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup2_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2800c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup2_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x2a020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup3_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2a00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup3_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x2c020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup4_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2c00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup4_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
>> +	.cmd_rcgr = 0x2700c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_uart1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
>> +	.cmd_rcgr = 0x2900c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_uart2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_gp1_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 gp1_clk_src = {
>> +	.cmd_rcgr = 0x64004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp1_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 gp2_clk_src = {
>> +	.cmd_rcgr = 0x65004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp2_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 gp3_clk_src = {
>> +	.cmd_rcgr = 0x66004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp3_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	F(600000000, P_GPLL0, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_gpll0_clk_src = {
>> +	.cmd_rcgr = 0x4805c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_hmss_gpll0_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_gpll0_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
>> +	F(384000000, P_GPLL4, 4, 0, 0),
>> +	F(768000000, P_GPLL4, 2, 0, 0),
>> +	F(1536000000, P_GPLL4, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_gpll4_clk_src = {
>> +	.cmd_rcgr = 0x48074,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll4,
>> +	.freq_tbl = ftbl_hmss_gpll4_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_gpll4_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll4,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_rbcpr_clk_src = {
>> +	.cmd_rcgr = 0x48044,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_rbcpr_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_pdm2_clk_src[] = {
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 pdm2_clk_src = {
>> +	.cmd_rcgr = 0x33010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_pdm2_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "pdm2_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
>> +	F(160400000, P_GPLL1, 5, 0, 0),
>> +	F(267333333, P_GPLL1, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 qspi_ser_clk_src = {
>> +	.cmd_rcgr = 0x4d00c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map =
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>> +	.freq_tbl = ftbl_qspi_ser_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "qspi_ser_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>> +		.num_parents = 6,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
>> +	F(144000, P_XO, 16, 3, 25),
>> +	F(400000, P_XO, 12, 1, 4),
>> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(192000000, P_GPLL4, 8, 0, 0),
>> +	F(384000000, P_GPLL4, 4, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc1_apps_clk_src = {
>> +	.cmd_rcgr = 0x1602c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
>> +	.freq_tbl = ftbl_sdcc1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
>> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc1_ice_core_clk_src = {
>> +	.cmd_rcgr = 0x16010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc1_ice_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
>> +	F(144000, P_XO, 16, 3, 25),
>> +	F(400000, P_XO, 12, 1, 4),
>> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(192000000, P_GPLL4, 8, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc2_apps_clk_src = {
>> +	.cmd_rcgr = 0x14010,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
>> +	.freq_tbl = ftbl_sdcc2_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(240000000, P_GPLL0, 2.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_axi_clk_src = {
>> +	.cmd_rcgr = 0x75018,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_axi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_axi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
>> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_ice_core_clk_src = {
>> +	.cmd_rcgr = 0x76010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_ice_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_ice_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 ufs_phy_aux_clk_src = {
>> +	.cmd_rcgr = 0x76044,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_sleep_clk,
>> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_phy_aux_clk_src",
>> +		.parent_names = gcc_parent_names_xo_sleep_clk,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
>> +	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
>> +	F(75000000, P_GPLL0, 8, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_unipro_core_clk_src = {
>> +	.cmd_rcgr = 0x76028,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_unipro_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	F(120000000, P_GPLL0, 5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb20_master_clk_src = {
>> +	.cmd_rcgr = 0x2f010,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb20_master_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb20_master_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb20_mock_utmi_clk_src = {
>> +	.cmd_rcgr = 0x2f024,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb20_mock_utmi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
>> +	F(120000000, P_GPLL0, 5, 0, 0),
>> +	F(133333333, P_GPLL0, 4.5, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(240000000, P_GPLL0, 2.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb30_master_clk_src = {
>> +	.cmd_rcgr = 0xf014,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb30_master_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb30_master_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb30_mock_utmi_clk_src = {
>> +	.cmd_rcgr = 0xf028,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb30_mock_utmi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
>> +	F(1200000, P_XO, 16, 0, 0),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb3_phy_aux_clk_src = {
>> +	.cmd_rcgr = 0x5000c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_sleep_clk,
>> +	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb3_phy_aux_clk_src",
>> +		.parent_names = gcc_parent_names_xo_sleep_clk,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_branch gcc_aggre2_ufs_axi_clk = {
>> +	.ha

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-13  6:55   ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Taniya Das
  2018-08-13  7:45     ` Craig Tatlor
@ 2018-08-13  9:44     ` Craig Tatlor
  1 sibling, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-08-13  9:44 UTC (permalink / raw)
  To: Taniya Das
  Cc: linux-arm-msm, Michael Turquette, Stephen Boyd, Rob Herring,
	Mark Rutland, Andy Gross, David Brown, linux-clk, devicetree,
	linux-kernel, linux-soc



On 13 August 2018 07:55:34 BST, Taniya Das <tdas@codeaurora.org> wrote:
>Hello Craig,
>
>Could you please correct the authorship and also provide the reference 
>to code where this is picked from?
>
Also, don't you have a program that just spits out the clock setup?
And I did leave copyright in file.
>On 8/11/2018 1:51 AM, Craig Tatlor wrote:
>> Add support for the global clock controller found on SDM660
>> based devices. This should allow most non-multimedia device
>> drivers to probe and control their clocks.
>> Based on CAF implementation.
>> 
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> ---
>>   .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
>>   drivers/clk/qcom/Kconfig                      |    9 +
>>   drivers/clk/qcom/Makefile                     |    1 +
>>   drivers/clk/qcom/gcc-sdm660.c                 | 2479
>+++++++++++++++++
>>   include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
>>   5 files changed, 2649 insertions(+)
>>   create mode 100644 drivers/clk/qcom/gcc-sdm660.c
>>   create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h
>> 
>> diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> index 664ea1fd6c76..e498ad2e8db8 100644
>> --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>> @@ -19,6 +19,7 @@ Required properties :
>>   			"qcom,gcc-msm8996"
>>   			"qcom,gcc-msm8998"
>>   			"qcom,gcc-mdm9615"
>> +			"qcom,gcc-sdm660"
>>   			"qcom,gcc-sdm845"
>>   
>>   - reg : shall contain base register location and length
>> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
>> index 9c3480dcc38a..c4bda6d24c1f 100644
>> --- a/drivers/clk/qcom/Kconfig
>> +++ b/drivers/clk/qcom/Kconfig
>> @@ -226,6 +226,15 @@ config MSM_GCC_8998
>>   	  Say Y if you want to use peripheral devices such as UART, SPI,
>>   	  i2c, USB, UFS, SD/eMMC, PCIe, etc.
>>   
>> +config SDM_GCC_660
>> +	tristate "SDM660 Global Clock Controller"
>> +	select QCOM_GDSC
>> +	depends on COMMON_CLK_QCOM
>> +	help
>> +	  Support for the global clock controller on SDM660 devices.
>> +	  Say Y if you want to use peripheral devices such as UART, SPI,
>> +	  i2C, USB, UFS, SDDC, PCIe, etc.
>> +
>>   config SDM_GCC_845
>>   	tristate "SDM845 Global Clock Controller"
>>   	select QCOM_GDSC
>> diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
>> index 762c01137c2f..6e37d30d7c02 100644
>> --- a/drivers/clk/qcom/Makefile
>> +++ b/drivers/clk/qcom/Makefile
>> @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
>>   obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
>>   obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
>>   obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
>> +obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
>>   obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
>>   obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
>>   obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
>> diff --git a/drivers/clk/qcom/gcc-sdm660.c
>b/drivers/clk/qcom/gcc-sdm660.c
>> new file mode 100644
>> index 000000000000..bdb445aa4baa
>> --- /dev/null
>> +++ b/drivers/clk/qcom/gcc-sdm660.c
>> @@ -0,0 +1,2479 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2016-2017, The Linux Foundation. All rights
>reserved.
>> + * Copyright (c) 2018, Craig Tatlor.
>> + */
>> +
>> +#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,gcc-sdm660.h>
>> +
>> +#include "common.h"
>> +#include "clk-regmap.h"
>> +#include "clk-alpha-pll.h"
>> +#include "clk-rcg.h"
>> +#include "clk-branch.h"
>> +#include "reset.h"
>> +#include "gdsc.h"
>> +
>> +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
>> +
>> +enum {
>> +	P_XO,
>> +	P_SLEEP_CLK,
>> +	P_GPLL0,
>> +	P_GPLL1,
>> +	P_GPLL4,
>> +	P_GPLL0_EARLY_DIV,
>> +	P_GPLL1_EARLY_DIV,
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_gpll0[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_gpll0[] = {
>> +	"xo",
>> +	"gpll0",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_SLEEP_CLK, 5 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"sleep_clk",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
>> +	{ P_XO, 0 },
>> +	{ P_SLEEP_CLK, 5 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_sleep_clk[] = {
>> +	"xo",
>> +	"sleep_clk",
>> +};
>> +
>> +static const struct parent_map gcc_parent_map_xo_gpll4[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL4, 5 },
>> +};
>> +
>> +static const char * const gcc_parent_names_xo_gpll4[] = {
>> +	"xo",
>> +	"gpll4",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] =
>{
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 3 },
>> +	{ P_GPLL1, 4 },
>> +	{ P_GPLL4, 5 },
>> +	{ P_GPLL1_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[]
>= {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +	"gpll1",
>> +	"gpll4",
>> +	"gpll1_early_div",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL4, 5 },
>> +	{ P_GPLL0_EARLY_DIV, 6 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll4",
>> +	"gpll0_early_div",
>> +};
>> +
>> +static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
>> +	{ P_XO, 0 },
>> +	{ P_GPLL0, 1 },
>> +	{ P_GPLL0_EARLY_DIV, 2 },
>> +	{ P_GPLL4, 5 },
>> +};
>> +
>> +static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
>> +	"xo",
>> +	"gpll0",
>> +	"gpll0_early_div",
>> +	"gpll4",
>> +};
>> +
>> +static struct clk_fixed_factor xo = {
>> +	.mult = 1,
>> +	.div = 1,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "xo",
>> +		.parent_names = (const char *[]){ "xo_board" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll0_early = {
>> +	.offset = 0x0,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(0),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll0_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor gpll0_early_div = {
>> +	.mult = 1,
>> +	.div = 2,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "gpll0_early_div",
>> +		.parent_names = (const char *[]){ "gpll0_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll0 = {
>> +	.offset = 0x00000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gpll0",
>> +		.parent_names = (const char *[]){ "gpll0_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll1_early = {
>> +	.offset = 0x1000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(1),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll1_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_fixed_factor gpll1_early_div = {
>> +	.mult = 1,
>> +	.div = 2,
>> +	.hw.init = &(struct clk_init_data){
>> +		.name = "gpll1_early_div",
>> +		.parent_names = (const char *[]){ "gpll1_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_fixed_factor_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll1 = {
>> +	.offset = 0x1000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gpll1",
>> +		.parent_names = (const char *[]){ "gpll1_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll gpll4_early = {
>> +	.offset = 0x77000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr = {
>> +		.enable_reg = 0x52000,
>> +		.enable_mask = BIT(4),
>> +		.hw.init = &(struct clk_init_data){
>> +			.name = "gpll4_early",
>> +			.parent_names = (const char *[]){ "xo" },
>> +			.num_parents = 1,
>> +			.ops = &clk_alpha_pll_ops,
>> +		},
>> +	},
>> +};
>> +
>> +static struct clk_alpha_pll_postdiv gpll4 = {
>> +	.offset = 0x77000,
>> +	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>> +	.clkr.hw.init = &(struct clk_init_data)
>> +	{
>> +		.name = "gpll4",
>> +		.parent_names = (const char *[]) { "gpll4_early" },
>> +		.num_parents = 1,
>> +		.ops = &clk_alpha_pll_postdiv_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(50000000, P_GPLL0, 12, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x19020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup1_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
>> +	F(960000, P_XO, 10, 1, 2),
>> +	F(4800000, P_XO, 4, 0, 0),
>> +	F(9600000, P_XO, 2, 0, 0),
>> +	F(15000000, P_GPLL0, 10, 1, 4),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(25000000, P_GPLL0, 12, 1, 2),
>> +	F(50000000, P_GPLL0, 12, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1900c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup1_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1b020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup2_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1b00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup2_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1d020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup3_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1d00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup3_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x1f020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup4_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x1f00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_qup4_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
>> +	F(3686400, P_GPLL0, 1, 96, 15625),
>> +	F(7372800, P_GPLL0, 1, 192, 15625),
>> +	F(14745600, P_GPLL0, 1, 384, 15625),
>> +	F(16000000, P_GPLL0, 5, 2, 15),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(24000000, P_GPLL0, 5, 1, 5),
>> +	F(32000000, P_GPLL0, 1, 4, 75),
>> +	F(40000000, P_GPLL0, 15, 0, 0),
>> +	F(46400000, P_GPLL0, 1, 29, 375),
>> +	F(48000000, P_GPLL0, 12.5, 0, 0),
>> +	F(51200000, P_GPLL0, 1, 32, 375),
>> +	F(56000000, P_GPLL0, 1, 7, 75),
>> +	F(58982400, P_GPLL0, 1, 1536, 15625),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	F(63157895, P_GPLL0, 9.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
>> +	.cmd_rcgr = 0x1a00c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_uart1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
>> +	.cmd_rcgr = 0x1c00c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp1_uart2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x26020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup1_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2600c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup1_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x28020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup2_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2800c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup2_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x2a020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup3_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2a00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup3_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
>> +	.cmd_rcgr = 0x2c020,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup4_i2c_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
>> +	.cmd_rcgr = 0x2c00c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_qup4_spi_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
>> +	.cmd_rcgr = 0x2700c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_uart1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
>> +	.cmd_rcgr = 0x2900c,
>> +	.mnd_width = 16,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "blsp2_uart2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_gp1_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 gp1_clk_src = {
>> +	.cmd_rcgr = 0x64004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp1_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 gp2_clk_src = {
>> +	.cmd_rcgr = 0x65004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp2_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 gp3_clk_src = {
>> +	.cmd_rcgr = 0x66004,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>> +	.freq_tbl = ftbl_gp1_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "gp3_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	F(600000000, P_GPLL0, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_gpll0_clk_src = {
>> +	.cmd_rcgr = 0x4805c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_hmss_gpll0_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_gpll0_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
>> +	F(384000000, P_GPLL4, 4, 0, 0),
>> +	F(768000000, P_GPLL4, 2, 0, 0),
>> +	F(1536000000, P_GPLL4, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_gpll4_clk_src = {
>> +	.cmd_rcgr = 0x48074,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll4,
>> +	.freq_tbl = ftbl_hmss_gpll4_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_gpll4_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll4,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 hmss_rbcpr_clk_src = {
>> +	.cmd_rcgr = 0x48044,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "hmss_rbcpr_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_pdm2_clk_src[] = {
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 pdm2_clk_src = {
>> +	.cmd_rcgr = 0x33010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_pdm2_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "pdm2_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
>> +	F(160400000, P_GPLL1, 5, 0, 0),
>> +	F(267333333, P_GPLL1, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 qspi_ser_clk_src = {
>> +	.cmd_rcgr = 0x4d00c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map =
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>> +	.freq_tbl = ftbl_qspi_ser_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "qspi_ser_clk_src",
>> +		.parent_names =
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>> +		.num_parents = 6,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
>> +	F(144000, P_XO, 16, 3, 25),
>> +	F(400000, P_XO, 12, 1, 4),
>> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(192000000, P_GPLL4, 8, 0, 0),
>> +	F(384000000, P_GPLL4, 4, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc1_apps_clk_src = {
>> +	.cmd_rcgr = 0x1602c,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
>> +	.freq_tbl = ftbl_sdcc1_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc1_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
>> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc1_ice_core_clk_src = {
>> +	.cmd_rcgr = 0x16010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc1_ice_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
>> +	F(144000, P_XO, 16, 3, 25),
>> +	F(400000, P_XO, 12, 1, 4),
>> +	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>> +	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(192000000, P_GPLL4, 8, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 sdcc2_apps_clk_src = {
>> +	.cmd_rcgr = 0x14010,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
>> +	.freq_tbl = ftbl_sdcc2_apps_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "sdcc2_apps_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
>> +		.num_parents = 4,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
>> +	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>> +	F(100000000, P_GPLL0, 6, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(240000000, P_GPLL0, 2.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_axi_clk_src = {
>> +	.cmd_rcgr = 0x75018,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_axi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_axi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
>> +	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(300000000, P_GPLL0, 2, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_ice_core_clk_src = {
>> +	.cmd_rcgr = 0x76010,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_ice_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_ice_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_rcg2 ufs_phy_aux_clk_src = {
>> +	.cmd_rcgr = 0x76044,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_sleep_clk,
>> +	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_phy_aux_clk_src",
>> +		.parent_names = gcc_parent_names_xo_sleep_clk,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
>> +	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
>> +	F(75000000, P_GPLL0, 8, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 ufs_unipro_core_clk_src = {
>> +	.cmd_rcgr = 0x76028,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "ufs_unipro_core_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	F(120000000, P_GPLL0, 5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb20_master_clk_src = {
>> +	.cmd_rcgr = 0x2f010,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb20_master_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb20_master_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb20_mock_utmi_clk_src = {
>> +	.cmd_rcgr = 0x2f024,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb20_mock_utmi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
>> +	F(120000000, P_GPLL0, 5, 0, 0),
>> +	F(133333333, P_GPLL0, 4.5, 0, 0),
>> +	F(150000000, P_GPLL0, 4, 0, 0),
>> +	F(200000000, P_GPLL0, 3, 0, 0),
>> +	F(240000000, P_GPLL0, 2.5, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb30_master_clk_src = {
>> +	.cmd_rcgr = 0xf014,
>> +	.mnd_width = 8,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb30_master_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb30_master_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
>> +	F(60000000, P_GPLL0, 10, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb30_mock_utmi_clk_src = {
>> +	.cmd_rcgr = 0xf028,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>> +	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb30_mock_utmi_clk_src",
>> +		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>> +		.num_parents = 3,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
>> +	F(1200000, P_XO, 16, 0, 0),
>> +	F(19200000, P_XO, 1, 0, 0),
>> +	{ }
>> +};
>> +
>> +static struct clk_rcg2 usb3_phy_aux_clk_src = {
>> +	.cmd_rcgr = 0x5000c,
>> +	.mnd_width = 0,
>> +	.hid_width = 5,
>> +	.parent_map = gcc_parent_map_xo_sleep_clk,
>> +	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
>> +	.clkr.hw.init = &(struct clk_init_data){
>> +		.name = "usb3_phy_aux_clk_src",
>> +		.parent_names = gcc_parent_names_xo_sleep_clk,
>> +		.num_parents = 2,
>> +		.ops = &clk_rcg2_ops,
>> +	},
>> +};
>> +
>> +static struct clk_branch gcc_aggre2_ufs_axi_clk = {
>> +	.ha

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-06-14 15:14   ` [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
@ 2018-09-16 12:10     ` Sebastian Reichel
  2018-09-20 14:32       ` Craig
  0 siblings, 1 reply; 60+ messages in thread
From: Sebastian Reichel @ 2018-09-16 12:10 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
	David S. Miller, Andrew Morton, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, linux-pm, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6416 bytes --]

Hi,

Sorry for my long delay in reviewing this. I like the binding,
but the "qcom," specific properties should become common properties
in

Documentation/devicetree/bindings/power/supply/battery.txt

and referenced via monitored-battery.

-- Sebastian

On Thu, Jun 14, 2018 at 04:14:16PM +0100, Craig Tatlor wrote:
> Add bindings for the Qualcomm Battery Monitoring system.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> 
> * Changes from v6:
>   s/celcius/celsius
>   change uah to uAh.
> 
> * Changes from v5:                                                                                                                                                                                                   
>   Mentions which values are 8 bit.                                                                                                                                                                                   
>                                                                                                                                                                                                                      
> * Changes from v4:                                                                                                                                                                                                   
>   Uses proper units and expands some definitions,                                                                                                                                                                    
>   along with changing vadc@ to adc@.    
> 
>  .../bindings/power/supply/qcom_bms.txt        | 92 +++++++++++++++++++
>  1 file changed, 92 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> new file mode 100644
> index 000000000000..dc0a9ab9aa64
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
> @@ -0,0 +1,92 @@
> +Qualcomm Battery Monitoring System
> +
> +The Qualcomm Battery Monitoring System is found inside of Qualcomm PM8941
> +PMICs. It provides open circuit voltage (OCV) and coulomb counter registers
> +that allow the OS to infer a capacity level.
> +
> +Required properties:
> +- compatible:                   Should contain "qcom,pm8941-bms".
> +- reg:                          Specifies the SPMI address and length of the
> +				controller's registers.
> +- interrupts:                   OCV threshold interrupt.
> +- io-channels:                  Should contain IIO channel specifier for the
> +				ADC channel that reports battery temperature.
> +- io-channel-names:             Should contain "temp".
> +- qcom,fcc-temp-legend-celsius: An 8 bit array containing the temperature,
> +				in degC, for each column of the full charge
> +				capacity lookup table.
> +- qcom,fcc-lut-microamp-hours:  An array of full charge capacity values in uAh,
> +				one entry for each temperature defined in in
> +				qcom,fcc-temp-legend-celsius.
> +- qcom,ocv-temp-legend-celsius: An 8 bit array containing the temperature,
> +				in degC, for each column of the OCV lookup
> +				table.
> +- qcom,ocv-capacity-legend:     An 8 bit array containing the capacity for each
> +				row of the OCV lookup table.
> +- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one entry for each
> +				capacity defined in qcom,ocv-capacity-legend.
> +
> +Example:
> +		pm8941_vadc: adc@3100 {
> +			compatible = "qcom,spmi-vadc";
> +			reg = <0x3100>;
> +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			#io-channel-cells = <1>;
> +
> +			bat_temp {
> +				reg = <VADC_LR_MUX1_BAT_THERM>;
> +			};
> +		};
> +
> +		bms@4000 {
> +			compatible = "qcom,pm8941-bms";
> +			reg = <0x4000>;
> +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
> +			interrupt-names = "ocv_thr";
> +
> +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
> +			io-channel-names = "temp";
> +
> +			qcom,fcc-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
> +			qcom,fcc-lut-microamp-hours = <3230000 3260000 3380000 3410000 3360000>;
> +
> +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75
> +							     70 65 60 55 50 45
> +							     40 35 30 25 20 15
> +							     10 9 8 7 6 5 4 3 2
> +							     1 0>;
> +			qcom,ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
> +			qcom,ocv-lut-microvolt = <43050000 43050000 43030000 42990000 42950000
> +						  42770000 42570000 42550000 42510000 42310000
> +						  42180000 41980000 41970000 41920000 41720000
> +						  41590000 41390000 41450000 41400000 41200000
> +						  41010000 40810000 40920000 40890000 40690000
> +						  40480000 40280000 40440000 40420000 40220000
> +						  40040000 39840000 40010000 39980000 39780000
> +						  39620000 39420000 39550000 39560000 39360000
> +						  39210000 39010000 39090000 39160000 38960000
> +						  38830000 38630000 38740000 38790000 38590000
> +						  38550000 38350000 38440000 38430000 38230000
> +						  38310000 38110000 38230000 38180000 37980000
> +						  38190000 37990000 38040000 38000000 37800000
> +						  38060000 37860000 37900000 37840000 37640000
> +						  37890000 37690000 37770000 37660000 37460000
> +						  37720000 37520000 37560000 37450000 37250000
> +						  37480000 37280000 37290000 37250000 37050000
> +						  37240000 37040000 37020000 36990000 36790000
> +						  37030000 36830000 36730000 36700000 36500000
> +						  36940000 36740000 36670000 36640000 36440000
> +						  36850000 36650000 36600000 36590000 36390000
> +						  36750000 36550000 36520000 36550000 36350000
> +						  36690000 36490000 36380000 36400000 36200000
> +						  36460000 36260000 36180000 36120000 35920000
> +						  36080000 35880000 35680000 35640000 35440000
> +						  35510000 35310000 35050000 35020000 34820000
> +						  34730000 34530000 34300000 34250000 34050000
> +						  33870000 33670000 33040000 32820000 32620000
> +						  30000000 30000000 30000000 30000000 30000000>;
> +		};
> +	};
> +};
> -- 
> 2.17.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-06-14 15:14   ` [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
@ 2018-09-16 13:48     ` Sebastian Reichel
  2018-09-20 14:43       ` Craig
  0 siblings, 1 reply; 60+ messages in thread
From: Sebastian Reichel @ 2018-09-16 13:48 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
	David S. Miller, Andrew Morton, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, linux-pm, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 18655 bytes --]

Hi,

First of all thanks for the patch and big sorry for the long delay
in reviewing this. I did not find enough time to do it properly
until now :(

On Thu, Jun 14, 2018 at 04:14:15PM +0100, Craig Tatlor wrote:
> This patch adds a driver for the BMS (Battery Monitoring System)
> block of the PM8941 PMIC, it uses a lookup table defined in the
> device tree to generate a capacity from the BMS supplied OCV, it
> then amends the coulomb counter to that to increase the accuracy
> of the estimated capacity.
> 
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> 
> * Changes from v5:                                                                                                                                                                                                   
>   Uses select for REGMAP_SPMI.                                                                                                                                                                                       
>                                                                                                                                                                                                                      
> * Changes from v4:                                                                                                                                                                                                   
>   Cleaned up percentage interpolation function,                                                                                                                                                                      
>   uses new fixp interpolation helper,                                                                                                                                                                                
>   added some more error cases,                                                                                                                                                                                       
>   uses devm_power_supply_register(),                                                                                                                                                                                 
>   uses a DIV_ROUND_CLOSEST for division and                                                                                                                                                                          
>   uses micro(volts / amp hours) instead of                                                                                                                                                                           
>   milli (volts / amp hours).  
> 
>  drivers/power/supply/Kconfig    |   9 +
>  drivers/power/supply/Makefile   |   1 +
>  drivers/power/supply/qcom_bms.c | 487 ++++++++++++++++++++++++++++++++
>  3 files changed, 497 insertions(+)
>  create mode 100644 drivers/power/supply/qcom_bms.c
> 
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 428b426842f4..75f2f375f992 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -82,6 +82,15 @@ config BATTERY_ACT8945A
>  	  Say Y here to enable support for power supply provided by
>  	  Active-semi ActivePath ACT8945A charger.
>  
> +config BATTERY_BMS
> +	tristate "Qualcomm Battery Monitoring System driver"
> +	depends on MFD_SPMI_PMIC || COMPILE_TEST
> +	depends on OF
> +	select REGMAP_SPMI
> +	help
> +	  Say Y to include support for the Battery Monitoring hardware
> +	  found in some Qualcomm PM series PMICs.
> +
>  config BATTERY_CPCAP
>  	tristate "Motorola CPCAP PMIC battery driver"
>  	depends on MFD_CPCAP && IIO
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index e83aa843bcc6..04204174b047 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
>  obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
>  obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
>  obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
> +obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
>  obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
>  obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
>  obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
> diff --git a/drivers/power/supply/qcom_bms.c b/drivers/power/supply/qcom_bms.c
> new file mode 100644
> index 000000000000..718fd745c0f7
> --- /dev/null
> +++ b/drivers/power/supply/qcom_bms.c
> @@ -0,0 +1,487 @@
> +// SPDX-License-Identifier: GPL
> +
> +/*
> + * Qualcomm Battery Monitoring System driver
> + *
> + * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/fixp-arith.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/slab.h>
> +#include <linux/bitops.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/regmap.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/iio/consumer.h>
> +
> +#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
> +#define REG_BMS_SHDW_CC_DATA0		0xA8
> +#define REG_BMS_CC_DATA_CTL		0x42
> +#define REG_BMS_CC_CLEAR_CTL		0x4
> +
> +#define BMS_HOLD_OREG_DATA		BIT(0)
> +#define BMS_CLEAR_SHDW_CC		BIT(6)
> +
> +#define BMS_CC_READING_RESOLUTION_N	542535
> +#define BMS_CC_READING_RESOLUTION_D	10000
> +#define BMS_CC_READING_TICKS		56
> +#define BMS_SLEEP_CLK_HZ		32764
> +
> +#define SECONDS_PER_HOUR		3600
> +#define TEMPERATURE_COLS		5
> +#define MAX_CAPACITY_ROWS		50
> +
> +/* lookup table for ocv -> capacity conversion */
> +struct bms_ocv_lut {
> +	int rows;
> +	s8 temp_legend[TEMPERATURE_COLS];
> +	u8 capacity_legend[MAX_CAPACITY_ROWS];
> +	u32 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
> +};
> +
> +/* lookup table for battery temperature -> fcc conversion */
> +struct bms_fcc_lut {
> +	s8 temp_legend[TEMPERATURE_COLS];
> +	u32 lut[TEMPERATURE_COLS];
> +};
> +
> +struct bms_device_info {
> +	struct device *dev;
> +	struct regmap *regmap;
> +	struct bms_ocv_lut ocv_lut;
> +	struct power_supply_desc bat_desc;
> +	struct bms_fcc_lut fcc_lut;
> +	struct iio_channel *adc;
> +	struct mutex bms_output_lock;
> +	u32 base_addr;
> +
> +	int ocv_thr_irq;
> +	u32 ocv;
> +};
> +
> +static bool between(int left, int right, int val)
> +{
> +	if (left <= val && val <= right)
> +		return true;
> +
> +	if (left >= val && val >= right)
> +		return true;
> +
> +	return false;
> +}
> +
> +static int interpolate_capacity(int temp, u32 ocv,
> +				struct bms_ocv_lut *ocv_lut)
> +{
> +	int pcj_minus_one = 0, pcj = 0, i2 = 0, i3 = 0, i, j;
> +
> +	for (j = 0; j < TEMPERATURE_COLS; j++)
> +		if (temp <= ocv_lut->temp_legend[j])
> +			break;
> +
> +	if (ocv >= ocv_lut->lut[0][j])
> +		return ocv_lut->capacity_legend[0];
> +
> +	if (ocv <= ocv_lut->lut[ocv_lut->rows-1][j-1])
> +		return ocv_lut->capacity_legend[ocv_lut->rows-1];
> +
> +	for (i = 0; i < ocv_lut->rows-1; i++) {
> +		if (between(ocv_lut->lut[i][j],
> +			    ocv_lut->lut[i+1][j], ocv))
> +			i2 = i;
> +
> +		if (between(ocv_lut->lut[i][j-1],
> +			    ocv_lut->lut[i+1][j-1], ocv))
> +			i3 = i;
> +	}
> +
> +	/* interpolate two capacities */
> +	pcj = fixp_linear_interpolate(ocv_lut->lut[i2][j],
> +				      ocv_lut->capacity_legend[i2],
> +				      ocv_lut->lut[i2+1][j],
> +				      ocv_lut->capacity_legend[i2+1],
> +				      ocv);
> +
> +	pcj_minus_one = fixp_linear_interpolate(ocv_lut->lut[i3][j-1],
> +						ocv_lut->capacity_legend[i3],
> +						ocv_lut->lut[i3+1][j-1],
> +						ocv_lut->capacity_legend[i3+1],
> +						ocv);
> +
> +	/* interpolate them with the battery temperature */
> +	return fixp_linear_interpolate(ocv_lut->temp_legend[j-1],
> +				       pcj_minus_one,
> +				       ocv_lut->temp_legend[j],
> +				       pcj,
> +				       temp);
> +}
> +
> +static int interpolate_fcc(int temp, struct bms_fcc_lut *fcc_lut)
> +{
> +	int i;
> +
> +	for (i = 0; i < TEMPERATURE_COLS; i++)
> +		if (temp <= fcc_lut->temp_legend[i])
> +			break;
> +
> +	return fixp_linear_interpolate(fcc_lut->temp_legend[i-1],
> +			     fcc_lut->lut[i-1],
> +			     fcc_lut->temp_legend[i],
> +			     fcc_lut->lut[i],
> +			     temp);
> +}
> +
> +static int bms_lock_output_data(struct bms_device_info *di)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(di->regmap, di->base_addr +
> +				 REG_BMS_CC_DATA_CTL,
> +				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
> +	if (ret) {
> +		dev_err(di->dev, "failed to lock bms output: %d", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Sleep for at least 100 microseconds here to make sure
> +	 * there has been at least three cycles of the sleep clock
> +	 * so that the registers are correctly locked.
> +	 */
> +	usleep_range(100, 1000);
> +
> +	return 0;
> +}
> +
> +static int bms_unlock_output_data(struct bms_device_info *di)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(di->regmap, di->base_addr +
> +				 REG_BMS_CC_DATA_CTL,
> +				 BMS_HOLD_OREG_DATA, 0);
> +	if (ret) {
> +		dev_err(di->dev, "failed to unlock bms output: %d", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int bms_read_ocv(struct bms_device_info *di, u32 *ocv)
> +{
> +	int ret;
> +	u16 read_ocv;
> +
> +	mutex_lock(&di->bms_output_lock);
> +
> +	ret = bms_lock_output_data(di);
> +	if (ret)
> +		goto err_lock;
> +
> +	ret = regmap_bulk_read(di->regmap, di->base_addr+
> +			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
> +	if (ret) {
> +		dev_err(di->dev, "open circuit voltage read failed: %d", ret);
> +		goto err_read;
> +	}
> +
> +	dev_dbg(di->dev, "read open circuit voltage of: %d mv", read_ocv);
> +
> +

one empty line is enough.

> +	*ocv = read_ocv * 1000;
> +
> +err_read:
> +	bms_unlock_output_data(di);
> +
> +err_lock:
> +	mutex_unlock(&di->bms_output_lock);
> +
> +	return ret;
> +}
> +
> +static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
> +{
> +	int ret;
> +	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
> +
> +	mutex_lock(&di->bms_output_lock);
> +
> +	ret = bms_lock_output_data(di);
> +	if (ret)
> +		goto err_lock;
> +
> +	ret = regmap_bulk_read(di->regmap, di->base_addr +
> +			       REG_BMS_SHDW_CC_DATA0,
> +			       &cc_raw_s36, 5);
> +	if (ret) {
> +		dev_err(di->dev, "coulomb counter read failed: %d", ret);
> +		goto err_read;
> +	}
> +
> +	ret = bms_unlock_output_data(di);
> +	if (ret)
> +		goto err_lock;
> +
> +	mutex_unlock(&di->bms_output_lock);
> +
> +	cc_raw = sign_extend32(cc_raw_s36, 28);
> +
> +	/* convert raw to uv */
> +	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
> +			BMS_CC_READING_RESOLUTION_D);
> +
> +	/* convert uv to pvh */
> +	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
> +			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR);
> +
> +	/* divide by impedance */
> +	*cc_uah = div_s64(cc_pvh, 10000);
> +
> +	dev_dbg(di->dev, "read coulomb counter value of: %lld uah", *cc_uah);
> +
> +	return 0;
> +
> +err_read:
> +	bms_unlock_output_data(di);
> +
> +err_lock:
> +	mutex_unlock(&di->bms_output_lock);
> +
> +	return ret;
> +}
> +
> +static void bms_reset_cc(struct bms_device_info *di)
> +{
> +	int ret;
> +
> +	mutex_lock(&di->bms_output_lock);
> +
> +	ret = regmap_update_bits(di->regmap, di->base_addr +
> +				 REG_BMS_CC_CLEAR_CTL,
> +				 BMS_CLEAR_SHDW_CC,
> +				 BMS_CLEAR_SHDW_CC);
> +	if (ret) {
> +		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
> +		goto err_lock;
> +	}
> +
> +	/* wait at least three sleep cycles for cc to reset */
> +	usleep_range(100, 1000);
> +
> +	ret = regmap_update_bits(di->regmap, di->base_addr +
> +				 REG_BMS_CC_CLEAR_CTL,
> +				 BMS_CLEAR_SHDW_CC, 0);
> +	if (ret)
> +		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
> +
> +err_lock:
> +	mutex_unlock(&di->bms_output_lock);
> +}
> +
> +static int bms_calculate_capacity(struct bms_device_info *di, int *capacity)
> +{
> +	unsigned long fcc;
> +	int ret, temp, ocv_capacity, temp_degc;
> +	s64 cc = 0;
> +
> +	ret = iio_read_channel_raw(di->adc, &temp);
> +	if (ret < 0) {
> +		dev_err(di->dev, "failed to read temperature: %d", ret);
> +		return ret;
> +	}
> +
> +	temp_degc = DIV_ROUND_CLOSEST(temp, 1000);
> +
> +	ret = bms_read_cc(di, &cc);
> +	if (ret < 0) {
> +		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
> +		return ret;
> +	}
> +
> +	/* interpolate capacity from open circuit voltage */
> +	ocv_capacity = interpolate_capacity(temp_degc, di->ocv,
> +					    &di->ocv_lut);
> +
> +	/* interpolate the full charge capacity from temperature */
> +	fcc = interpolate_fcc(temp_degc, &di->fcc_lut);
> +
> +	/* append coloumb counter to capacity */
> +	*capacity = DIV_ROUND_CLOSEST(fcc * ocv_capacity, 100);
> +	*capacity = div_s64((*capacity - cc) * 100, fcc);
> +
> +	return 0;
> +}
> +
> +
> +

one empty line is enough. 

> +/*
> + * Return power_supply property
> + */
> +static int bms_get_property(struct power_supply *psy,
> +				   enum power_supply_property psp,
> +				   union power_supply_propval *val)
> +{
> +	struct bms_device_info *di = power_supply_get_drvdata(psy);
> +	int ret;
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_CAPACITY:
> +		ret = bms_calculate_capacity(di, &val->intval);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	if (val->intval == INT_MAX || val->intval == INT_MIN)
> +		ret = -EINVAL;
> +
> +	return ret;
> +}
> +
> +static enum power_supply_property bms_props[] = {
> +	POWER_SUPPLY_PROP_CAPACITY,
> +};

Why does the driver not expose the following battery information?

temperature info via POWER_SUPPLY_PROP_TEMP
ocv info via POWER_SUPPLY_PROP_VOLTAGE_OCV
CC info via POWER_SUPPLY_PROP_CHARGE_COUNTER
max current via POWER_SUPPLY_PROP_CURRENT_MAX

> +static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
> +{
> +	struct bms_device_info *di = dev_id;
> +
> +	if (bms_read_ocv(di, &di->ocv) < 0)
> +		return IRQ_HANDLED;
> +
> +	bms_reset_cc(di);
> +	return IRQ_HANDLED;
> +}

You want to call power_supply_changed() here to notify userspace.

> +static int bms_probe(struct platform_device *pdev)
> +{
> +	struct power_supply_config psy_cfg = {};
> +	struct bms_device_info *di;
> +	struct power_supply *bat;
> +	int ret;
> +
> +	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
> +	if (!di)
> +		return -ENOMEM;
> +
> +	di->dev = &pdev->dev;
> +
> +	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> +	if (!di->regmap) {
> +		dev_err(di->dev, "Unable to get regmap");
> +		return -EINVAL;
> +	}
> +
> +	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
> +	if (IS_ERR(di->adc))
> +		return PTR_ERR(di->adc);
> +
> +	ret = of_property_read_u32(di->dev->of_node, "reg", &di->base_addr);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = of_property_read_u8_array(di->dev->of_node,
> +						 "qcom,ocv-temp-legend-celsius",
> +						 (u8 *)di->ocv_lut.temp_legend,
> +						 TEMPERATURE_COLS);
> +	if (ret < 0) {
> +		dev_err(di->dev, "no open circuit voltage temperature legend found");
> +		return ret;
> +	}
> +
> +	di->ocv_lut.rows = of_property_read_variable_u8_array(di->dev->of_node,
> +						 "qcom,ocv-capacity-legend",
> +						 di->ocv_lut.capacity_legend, 0,
> +						 MAX_CAPACITY_ROWS);
> +	if (di->ocv_lut.rows < 0) {
> +		dev_err(di->dev, "no open circuit voltage capacity legend found");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_variable_u32_array(di->dev->of_node,
> +						  "qcom,ocv-lut-microvolt",
> +						  (u32 *)di->ocv_lut.lut,
> +						  TEMPERATURE_COLS,
> +						  TEMPERATURE_COLS *
> +						  MAX_CAPACITY_ROWS);
> +	if (ret < 0) {
> +		dev_err(di->dev, "no open circuit voltage lut array found");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u8_array(di->dev->of_node,
> +						 "qcom,fcc-temp-legend-celsius",
> +						 (u8 *)di->fcc_lut.temp_legend,
> +						 TEMPERATURE_COLS);
> +	if (ret < 0) {
> +		dev_err(di->dev, "no full charge capacity temperature legend found");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32_array(di->dev->of_node,
> +						  "qcom,fcc-lut-microamp-hours",
> +						  di->fcc_lut.lut,
> +						  TEMPERATURE_COLS);
> +	if (ret < 0) {
> +		dev_err(di->dev, "no full charge capacity lut array found");
> +		return ret;
> +	}
> +
> +	ret = bms_read_ocv(di, &di->ocv);
> +	if (ret < 0) {
> +		dev_err(di->dev, "failed to read initial open circuit voltage: %d",
> +			ret);
> +		return ret;
> +	}
> +
> +	mutex_init(&di->bms_output_lock);
> +
> +	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
> +
> +	ret = devm_request_threaded_irq(di->dev, di->ocv_thr_irq, NULL,
> +					bms_ocv_thr_irq_handler,
> +					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +					pdev->name, di);
> +	if (ret < 0) {
> +		dev_err(di->dev, "failed to request handler for open circuit voltage threshold IRQ");
> +		return ret;
> +	}
> +
> +

one empty line is enough.

> +	di->bat_desc.name = "bms";
> +	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
> +	di->bat_desc.properties = bms_props;
> +	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
> +	di->bat_desc.get_property = bms_get_property;
> +
> +	psy_cfg.drv_data = di;

psy_cfg.of_node = pdev->dev.of_node;

> +	bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
> +
> +	return PTR_ERR_OR_ZERO(bat);
> +}
> +
> +static const struct of_device_id bms_of_match[] = {
> +	{.compatible = "qcom,pm8941-bms", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, bms_of_match);
> +
> +static struct platform_driver bms_driver = {
> +	.probe = bms_probe,
> +	.driver = {
> +		.name = "qcom-bms",
> +		.of_match_table = of_match_ptr(bms_of_match),
> +	},
> +};
> +module_platform_driver(bms_driver);
> +
> +MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
> +MODULE_DESCRIPTION("Qualcomm BMS driver");
> +MODULE_LICENSE("GPL");

Apart from the things above I would like to see the information
about the battery cell itself being moved to 'struct
power_supply_battery_info', see also my comment in the DT bindings.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-16 12:10     ` Sebastian Reichel
@ 2018-09-20 14:32       ` Craig
  2018-09-20 16:58         ` Sebastian Reichel
  0 siblings, 1 reply; 60+ messages in thread
From: Craig @ 2018-09-20 14:32 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-arm-msm, Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
	David S. Miller, Andrew Morton, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, linux-pm, devicetree, linux-kernel



On 16 September 2018 13:10:45 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
>Hi,
>
>Sorry for my long delay in reviewing this. I like the binding,
>but the "qcom," specific properties should become common properties
>in
>
>Documentation/devicetree/bindings/power/supply/battery.txt
Thanks for the review, what bindings for ocv would you prefer? The spreadtrum ones or mine?
>and referenced via monitored-battery.
>
>-- Sebastian
>
>On Thu, Jun 14, 2018 at 04:14:16PM +0100, Craig Tatlor wrote:
>> Add bindings for the Qualcomm Battery Monitoring system.
>> 
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> Reviewed-by: Rob Herring <robh@kernel.org>
>> ---
>> 
>> * Changes from v6:
>>   s/celcius/celsius
>>   change uah to uAh.
>> 
>> * Changes from v5:                                                   
>                                                                       
>>   Mentions which values are 8 bit.                                   
>                                                                       
>>                                                                      
>                                                                       
>> * Changes from v4:                                                   
>                                                                       
>>   Uses proper units and expands some definitions,                    
>                                                                       
>>   along with changing vadc@ to adc@.    
>> 
>>  .../bindings/power/supply/qcom_bms.txt        | 92
>+++++++++++++++++++
>>  1 file changed, 92 insertions(+)
>>  create mode 100644
>Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> 
>> diff --git
>a/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> new file mode 100644
>> index 000000000000..dc0a9ab9aa64
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power/supply/qcom_bms.txt
>> @@ -0,0 +1,92 @@
>> +Qualcomm Battery Monitoring System
>> +
>> +The Qualcomm Battery Monitoring System is found inside of Qualcomm
>PM8941
>> +PMICs. It provides open circuit voltage (OCV) and coulomb counter
>registers
>> +that allow the OS to infer a capacity level.
>> +
>> +Required properties:
>> +- compatible:                   Should contain "qcom,pm8941-bms".
>> +- reg:                          Specifies the SPMI address and
>length of the
>> +				controller's registers.
>> +- interrupts:                   OCV threshold interrupt.
>> +- io-channels:                  Should contain IIO channel specifier
>for the
>> +				ADC channel that reports battery temperature.
>> +- io-channel-names:             Should contain "temp".
>> +- qcom,fcc-temp-legend-celsius: An 8 bit array containing the
>temperature,
>> +				in degC, for each column of the full charge
>> +				capacity lookup table.
>> +- qcom,fcc-lut-microamp-hours:  An array of full charge capacity
>values in uAh,
>> +				one entry for each temperature defined in in
>> +				qcom,fcc-temp-legend-celsius.
>> +- qcom,ocv-temp-legend-celsius: An 8 bit array containing the
>temperature,
>> +				in degC, for each column of the OCV lookup
>> +				table.
>> +- qcom,ocv-capacity-legend:     An 8 bit array containing the
>capacity for each
>> +				row of the OCV lookup table.
>> +- qcom,ocv-lut-microvolt:       An array of OCV values in uV, one
>entry for each
>> +				capacity defined in qcom,ocv-capacity-legend.
>> +
>> +Example:
>> +		pm8941_vadc: adc@3100 {
>> +			compatible = "qcom,spmi-vadc";
>> +			reg = <0x3100>;
>> +			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +			#io-channel-cells = <1>;
>> +
>> +			bat_temp {
>> +				reg = <VADC_LR_MUX1_BAT_THERM>;
>> +			};
>> +		};
>> +
>> +		bms@4000 {
>> +			compatible = "qcom,pm8941-bms";
>> +			reg = <0x4000>;
>> +			interrupts = <0x0 0x40 0x4 IRQ_TYPE_EDGE_RISING>;
>> +			interrupt-names = "ocv_thr";
>> +
>> +			io-channels = <&pm8941_vadc VADC_LR_MUX1_BAT_THERM>;
>> +			io-channel-names = "temp";
>> +
>> +			qcom,fcc-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
>> +			qcom,fcc-lut-microamp-hours = <3230000 3260000 3380000 3410000
>3360000>;
>> +
>> +			qcom,ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75
>> +							     70 65 60 55 50 45
>> +							     40 35 30 25 20 15
>> +							     10 9 8 7 6 5 4 3 2
>> +							     1 0>;
>> +			qcom,ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
>> +			qcom,ocv-lut-microvolt = <43050000 43050000 43030000 42990000
>42950000
>> +						  42770000 42570000 42550000 42510000 42310000
>> +						  42180000 41980000 41970000 41920000 41720000
>> +						  41590000 41390000 41450000 41400000 41200000
>> +						  41010000 40810000 40920000 40890000 40690000
>> +						  40480000 40280000 40440000 40420000 40220000
>> +						  40040000 39840000 40010000 39980000 39780000
>> +						  39620000 39420000 39550000 39560000 39360000
>> +						  39210000 39010000 39090000 39160000 38960000
>> +						  38830000 38630000 38740000 38790000 38590000
>> +						  38550000 38350000 38440000 38430000 38230000
>> +						  38310000 38110000 38230000 38180000 37980000
>> +						  38190000 37990000 38040000 38000000 37800000
>> +						  38060000 37860000 37900000 37840000 37640000
>> +						  37890000 37690000 37770000 37660000 37460000
>> +						  37720000 37520000 37560000 37450000 37250000
>> +						  37480000 37280000 37290000 37250000 37050000
>> +						  37240000 37040000 37020000 36990000 36790000
>> +						  37030000 36830000 36730000 36700000 36500000
>> +						  36940000 36740000 36670000 36640000 36440000
>> +						  36850000 36650000 36600000 36590000 36390000
>> +						  36750000 36550000 36520000 36550000 36350000
>> +						  36690000 36490000 36380000 36400000 36200000
>> +						  36460000 36260000 36180000 36120000 35920000
>> +						  36080000 35880000 35680000 35640000 35440000
>> +						  35510000 35310000 35050000 35020000 34820000
>> +						  34730000 34530000 34300000 34250000 34050000
>> +						  33870000 33670000 33040000 32820000 32620000
>> +						  30000000 30000000 30000000 30000000 30000000>;
>> +		};
>> +	};
>> +};
>> -- 
>> 2.17.0
>> 

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System
  2018-09-16 13:48     ` Sebastian Reichel
@ 2018-09-20 14:43       ` Craig
  0 siblings, 0 replies; 60+ messages in thread
From: Craig @ 2018-09-20 14:43 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: linux-arm-msm, Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
	David S. Miller, Andrew Morton, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, linux-pm, devicetree, linux-kernel

Replies inline

On 16 September 2018 14:48:36 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
>Hi,
>
>First of all thanks for the patch and big sorry for the long delay
>in reviewing this. I did not find enough time to do it properly
>until now :(
>
>On Thu, Jun 14, 2018 at 04:14:15PM +0100, Craig Tatlor wrote:
>> This patch adds a driver for the BMS (Battery Monitoring System)
>> block of the PM8941 PMIC, it uses a lookup table defined in the
>> device tree to generate a capacity from the BMS supplied OCV, it
>> then amends the coulomb counter to that to increase the accuracy
>> of the estimated capacity.
>> 
>> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>> ---
>> 
>> * Changes from v5:                                                   
>                                                                       
>>   Uses select for REGMAP_SPMI.                                       
>                                                                       
>>                                                                      
>                                                                       
>> * Changes from v4:                                                   
>                                                                       
>>   Cleaned up percentage interpolation function,                      
>                                                                       
>>   uses new fixp interpolation helper,                                
>                                                                       
>>   added some more error cases,                                       
>                                                                       
>>   uses devm_power_supply_register(),                                 
>                                                                       
>>   uses a DIV_ROUND_CLOSEST for division and                          
>                                                                       
>>   uses micro(volts / amp hours) instead of                           
>                                                                       
>>   milli (volts / amp hours).  
>> 
>>  drivers/power/supply/Kconfig    |   9 +
>>  drivers/power/supply/Makefile   |   1 +
>>  drivers/power/supply/qcom_bms.c | 487
>++++++++++++++++++++++++++++++++
>>  3 files changed, 497 insertions(+)
>>  create mode 100644 drivers/power/supply/qcom_bms.c
>> 
>> diff --git a/drivers/power/supply/Kconfig
>b/drivers/power/supply/Kconfig
>> index 428b426842f4..75f2f375f992 100644
>> --- a/drivers/power/supply/Kconfig
>> +++ b/drivers/power/supply/Kconfig
>> @@ -82,6 +82,15 @@ config BATTERY_ACT8945A
>>  	  Say Y here to enable support for power supply provided by
>>  	  Active-semi ActivePath ACT8945A charger.
>>  
>> +config BATTERY_BMS
>> +	tristate "Qualcomm Battery Monitoring System driver"
>> +	depends on MFD_SPMI_PMIC || COMPILE_TEST
>> +	depends on OF
>> +	select REGMAP_SPMI
>> +	help
>> +	  Say Y to include support for the Battery Monitoring hardware
>> +	  found in some Qualcomm PM series PMICs.
>> +
>>  config BATTERY_CPCAP
>>  	tristate "Motorola CPCAP PMIC battery driver"
>>  	depends on MFD_CPCAP && IIO
>> diff --git a/drivers/power/supply/Makefile
>b/drivers/power/supply/Makefile
>> index e83aa843bcc6..04204174b047 100644
>> --- a/drivers/power/supply/Makefile
>> +++ b/drivers/power/supply/Makefile
>> @@ -21,6 +21,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+=
>88pm860x_battery.o
>>  obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
>>  obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
>>  obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
>> +obj-$(CONFIG_BATTERY_BMS)	+= qcom_bms.o
>>  obj-$(CONFIG_BATTERY_CPCAP)	+= cpcap-battery.o
>>  obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
>>  obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
>> diff --git a/drivers/power/supply/qcom_bms.c
>b/drivers/power/supply/qcom_bms.c
>> new file mode 100644
>> index 000000000000..718fd745c0f7
>> --- /dev/null
>> +++ b/drivers/power/supply/qcom_bms.c
>> @@ -0,0 +1,487 @@
>> +// SPDX-License-Identifier: GPL
>> +
>> +/*
>> + * Qualcomm Battery Monitoring System driver
>> + *
>> + * Copyright (C) 2018 Craig Tatlor <ctatlor97@gmail.com>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/fixp-arith.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/slab.h>
>> +#include <linux/bitops.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/regmap.h>
>> +#include <linux/irq.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/iio/consumer.h>
>> +
>> +#define REG_BMS_OCV_FOR_SOC_DATA0	0x90
>> +#define REG_BMS_SHDW_CC_DATA0		0xA8
>> +#define REG_BMS_CC_DATA_CTL		0x42
>> +#define REG_BMS_CC_CLEAR_CTL		0x4
>> +
>> +#define BMS_HOLD_OREG_DATA		BIT(0)
>> +#define BMS_CLEAR_SHDW_CC		BIT(6)
>> +
>> +#define BMS_CC_READING_RESOLUTION_N	542535
>> +#define BMS_CC_READING_RESOLUTION_D	10000
>> +#define BMS_CC_READING_TICKS		56
>> +#define BMS_SLEEP_CLK_HZ		32764
>> +
>> +#define SECONDS_PER_HOUR		3600
>> +#define TEMPERATURE_COLS		5
>> +#define MAX_CAPACITY_ROWS		50
>> +
>> +/* lookup table for ocv -> capacity conversion */
>> +struct bms_ocv_lut {
>> +	int rows;
>> +	s8 temp_legend[TEMPERATURE_COLS];
>> +	u8 capacity_legend[MAX_CAPACITY_ROWS];
>> +	u32 lut[MAX_CAPACITY_ROWS][TEMPERATURE_COLS];
>> +};
>> +
>> +/* lookup table for battery temperature -> fcc conversion */
>> +struct bms_fcc_lut {
>> +	s8 temp_legend[TEMPERATURE_COLS];
>> +	u32 lut[TEMPERATURE_COLS];
>> +};
>> +
>> +struct bms_device_info {
>> +	struct device *dev;
>> +	struct regmap *regmap;
>> +	struct bms_ocv_lut ocv_lut;
>> +	struct power_supply_desc bat_desc;
>> +	struct bms_fcc_lut fcc_lut;
>> +	struct iio_channel *adc;
>> +	struct mutex bms_output_lock;
>> +	u32 base_addr;
>> +
>> +	int ocv_thr_irq;
>> +	u32 ocv;
>> +};
>> +
>> +static bool between(int left, int right, int val)
>> +{
>> +	if (left <= val && val <= right)
>> +		return true;
>> +
>> +	if (left >= val && val >= right)
>> +		return true;
>> +
>> +	return false;
>> +}
>> +
>> +static int interpolate_capacity(int temp, u32 ocv,
>> +				struct bms_ocv_lut *ocv_lut)
>> +{
>> +	int pcj_minus_one = 0, pcj = 0, i2 = 0, i3 = 0, i, j;
>> +
>> +	for (j = 0; j < TEMPERATURE_COLS; j++)
>> +		if (temp <= ocv_lut->temp_legend[j])
>> +			break;
>> +
>> +	if (ocv >= ocv_lut->lut[0][j])
>> +		return ocv_lut->capacity_legend[0];
>> +
>> +	if (ocv <= ocv_lut->lut[ocv_lut->rows-1][j-1])
>> +		return ocv_lut->capacity_legend[ocv_lut->rows-1];
>> +
>> +	for (i = 0; i < ocv_lut->rows-1; i++) {
>> +		if (between(ocv_lut->lut[i][j],
>> +			    ocv_lut->lut[i+1][j], ocv))
>> +			i2 = i;
>> +
>> +		if (between(ocv_lut->lut[i][j-1],
>> +			    ocv_lut->lut[i+1][j-1], ocv))
>> +			i3 = i;
>> +	}
>> +
>> +	/* interpolate two capacities */
>> +	pcj = fixp_linear_interpolate(ocv_lut->lut[i2][j],
>> +				      ocv_lut->capacity_legend[i2],
>> +				      ocv_lut->lut[i2+1][j],
>> +				      ocv_lut->capacity_legend[i2+1],
>> +				      ocv);
>> +
>> +	pcj_minus_one = fixp_linear_interpolate(ocv_lut->lut[i3][j-1],
>> +						ocv_lut->capacity_legend[i3],
>> +						ocv_lut->lut[i3+1][j-1],
>> +						ocv_lut->capacity_legend[i3+1],
>> +						ocv);
>> +
>> +	/* interpolate them with the battery temperature */
>> +	return fixp_linear_interpolate(ocv_lut->temp_legend[j-1],
>> +				       pcj_minus_one,
>> +				       ocv_lut->temp_legend[j],
>> +				       pcj,
>> +				       temp);
>> +}
>> +
>> +static int interpolate_fcc(int temp, struct bms_fcc_lut *fcc_lut)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < TEMPERATURE_COLS; i++)
>> +		if (temp <= fcc_lut->temp_legend[i])
>> +			break;
>> +
>> +	return fixp_linear_interpolate(fcc_lut->temp_legend[i-1],
>> +			     fcc_lut->lut[i-1],
>> +			     fcc_lut->temp_legend[i],
>> +			     fcc_lut->lut[i],
>> +			     temp);
>> +}
>> +
>> +static int bms_lock_output_data(struct bms_device_info *di)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(di->regmap, di->base_addr +
>> +				 REG_BMS_CC_DATA_CTL,
>> +				 BMS_HOLD_OREG_DATA, BMS_HOLD_OREG_DATA);
>> +	if (ret) {
>> +		dev_err(di->dev, "failed to lock bms output: %d", ret);
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * Sleep for at least 100 microseconds here to make sure
>> +	 * there has been at least three cycles of the sleep clock
>> +	 * so that the registers are correctly locked.
>> +	 */
>> +	usleep_range(100, 1000);
>> +
>> +	return 0;
>> +}
>> +
>> +static int bms_unlock_output_data(struct bms_device_info *di)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(di->regmap, di->base_addr +
>> +				 REG_BMS_CC_DATA_CTL,
>> +				 BMS_HOLD_OREG_DATA, 0);
>> +	if (ret) {
>> +		dev_err(di->dev, "failed to unlock bms output: %d", ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int bms_read_ocv(struct bms_device_info *di, u32 *ocv)
>> +{
>> +	int ret;
>> +	u16 read_ocv;
>> +
>> +	mutex_lock(&di->bms_output_lock);
>> +
>> +	ret = bms_lock_output_data(di);
>> +	if (ret)
>> +		goto err_lock;
>> +
>> +	ret = regmap_bulk_read(di->regmap, di->base_addr+
>> +			       REG_BMS_OCV_FOR_SOC_DATA0, &read_ocv, 2);
>> +	if (ret) {
>> +		dev_err(di->dev, "open circuit voltage read failed: %d", ret);
>> +		goto err_read;
>> +	}
>> +
>> +	dev_dbg(di->dev, "read open circuit voltage of: %d mv", read_ocv);
>> +
>> +
>
>one empty line is enough.
Will fix
>
>> +	*ocv = read_ocv * 1000;
>> +
>> +err_read:
>> +	bms_unlock_output_data(di);
>> +
>> +err_lock:
>> +	mutex_unlock(&di->bms_output_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static int bms_read_cc(struct bms_device_info *di, s64 *cc_uah)
>> +{
>> +	int ret;
>> +	s64 cc_raw_s36, cc_raw, cc_uv, cc_pvh;
>> +
>> +	mutex_lock(&di->bms_output_lock);
>> +
>> +	ret = bms_lock_output_data(di);
>> +	if (ret)
>> +		goto err_lock;
>> +
>> +	ret = regmap_bulk_read(di->regmap, di->base_addr +
>> +			       REG_BMS_SHDW_CC_DATA0,
>> +			       &cc_raw_s36, 5);
>> +	if (ret) {
>> +		dev_err(di->dev, "coulomb counter read failed: %d", ret);
>> +		goto err_read;
>> +	}
>> +
>> +	ret = bms_unlock_output_data(di);
>> +	if (ret)
>> +		goto err_lock;
>> +
>> +	mutex_unlock(&di->bms_output_lock);
>> +
>> +	cc_raw = sign_extend32(cc_raw_s36, 28);
>> +
>> +	/* convert raw to uv */
>> +	cc_uv = div_s64(cc_raw * BMS_CC_READING_RESOLUTION_N,
>> +			BMS_CC_READING_RESOLUTION_D);
>> +
>> +	/* convert uv to pvh */
>> +	cc_pvh = div_s64(cc_uv * BMS_CC_READING_TICKS * 100000,
>> +			 BMS_SLEEP_CLK_HZ * SECONDS_PER_HOUR);
>> +
>> +	/* divide by impedance */
>> +	*cc_uah = div_s64(cc_pvh, 10000);
>> +
>> +	dev_dbg(di->dev, "read coulomb counter value of: %lld uah",
>*cc_uah);
>> +
>> +	return 0;
>> +
>> +err_read:
>> +	bms_unlock_output_data(di);
>> +
>> +err_lock:
>> +	mutex_unlock(&di->bms_output_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static void bms_reset_cc(struct bms_device_info *di)
>> +{
>> +	int ret;
>> +
>> +	mutex_lock(&di->bms_output_lock);
>> +
>> +	ret = regmap_update_bits(di->regmap, di->base_addr +
>> +				 REG_BMS_CC_CLEAR_CTL,
>> +				 BMS_CLEAR_SHDW_CC,
>> +				 BMS_CLEAR_SHDW_CC);
>> +	if (ret) {
>> +		dev_err(di->dev, "coulomb counter reset failed: %d", ret);
>> +		goto err_lock;
>> +	}
>> +
>> +	/* wait at least three sleep cycles for cc to reset */
>> +	usleep_range(100, 1000);
>> +
>> +	ret = regmap_update_bits(di->regmap, di->base_addr +
>> +				 REG_BMS_CC_CLEAR_CTL,
>> +				 BMS_CLEAR_SHDW_CC, 0);
>> +	if (ret)
>> +		dev_err(di->dev, "coulomb counter re-enable failed: %d", ret);
>> +
>> +err_lock:
>> +	mutex_unlock(&di->bms_output_lock);
>> +}
>> +
>> +static int bms_calculate_capacity(struct bms_device_info *di, int
>*capacity)
>> +{
>> +	unsigned long fcc;
>> +	int ret, temp, ocv_capacity, temp_degc;
>> +	s64 cc = 0;
>> +
>> +	ret = iio_read_channel_raw(di->adc, &temp);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "failed to read temperature: %d", ret);
>> +		return ret;
>> +	}
>> +
>> +	temp_degc = DIV_ROUND_CLOSEST(temp, 1000);
>> +
>> +	ret = bms_read_cc(di, &cc);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "failed to read coulomb counter: %d", ret);
>> +		return ret;
>> +	}
>> +
>> +	/* interpolate capacity from open circuit voltage */
>> +	ocv_capacity = interpolate_capacity(temp_degc, di->ocv,
>> +					    &di->ocv_lut);
>> +
>> +	/* interpolate the full charge capacity from temperature */
>> +	fcc = interpolate_fcc(temp_degc, &di->fcc_lut);
>> +
>> +	/* append coloumb counter to capacity */
>> +	*capacity = DIV_ROUND_CLOSEST(fcc * ocv_capacity, 100);
>> +	*capacity = div_s64((*capacity - cc) * 100, fcc);
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +
>
>one empty line is enough. 
Will fix
>
>> +/*
>> + * Return power_supply property
>> + */
>> +static int bms_get_property(struct power_supply *psy,
>> +				   enum power_supply_property psp,
>> +				   union power_supply_propval *val)
>> +{
>> +	struct bms_device_info *di = power_supply_get_drvdata(psy);
>> +	int ret;
>> +
>> +	switch (psp) {
>> +	case POWER_SUPPLY_PROP_CAPACITY:
>> +		ret = bms_calculate_capacity(di, &val->intval);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	if (val->intval == INT_MAX || val->intval == INT_MIN)
>> +		ret = -EINVAL;
>> +
>> +	return ret;
>> +}
>> +
>> +static enum power_supply_property bms_props[] = {
>> +	POWER_SUPPLY_PROP_CAPACITY,
>> +};
>
>Why does the driver not expose the following battery information?
>
>temperature info via POWER_SUPPLY_PROP_TEMP
>ocv info via POWER_SUPPLY_PROP_VOLTAGE_OCV
>CC info via POWER_SUPPLY_PROP_CHARGE_COUNTER
>max current via POWER_SUPPLY_PROP_CURRENT_MAX

1. This is handled in the tsens driver iirc
2. Ocv is very inaccurate as it is only updated when device uses a very low amount of power (<10ma) 
3. This isn't possible (unless you want to just give out the value anyway) due to the way the driver tracks the cc (resets on every ocv update)
4.this is done in the smbb driver, the BMS is only a fuelguage and not a fully blown charging ic
>
>> +static irqreturn_t bms_ocv_thr_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct bms_device_info *di = dev_id;
>> +
>> +	if (bms_read_ocv(di, &di->ocv) < 0)
>> +		return IRQ_HANDLED;
>> +
>> +	bms_reset_cc(di);
>> +	return IRQ_HANDLED;
>> +}
>
>You want to call power_supply_changed() here to notify userspace.
This doesn't mean battery is charged, just means ocv was updated (device used < 10ma of power)
>
>> +static int bms_probe(struct platform_device *pdev)
>> +{
>> +	struct power_supply_config psy_cfg = {};
>> +	struct bms_device_info *di;
>> +	struct power_supply *bat;
>> +	int ret;
>> +
>> +	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
>> +	if (!di)
>> +		return -ENOMEM;
>> +
>> +	di->dev = &pdev->dev;
>> +
>> +	di->regmap = dev_get_regmap(pdev->dev.parent, NULL);
>> +	if (!di->regmap) {
>> +		dev_err(di->dev, "Unable to get regmap");
>> +		return -EINVAL;
>> +	}
>> +
>> +	di->adc = devm_iio_channel_get(&pdev->dev, "temp");
>> +	if (IS_ERR(di->adc))
>> +		return PTR_ERR(di->adc);
>> +
>> +	ret = of_property_read_u32(di->dev->of_node, "reg",
>&di->base_addr);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ret = of_property_read_u8_array(di->dev->of_node,
>> +						 "qcom,ocv-temp-legend-celsius",
>> +						 (u8 *)di->ocv_lut.temp_legend,
>> +						 TEMPERATURE_COLS);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "no open circuit voltage temperature legend
>found");
>> +		return ret;
>> +	}
>> +
>> +	di->ocv_lut.rows =
>of_property_read_variable_u8_array(di->dev->of_node,
>> +						 "qcom,ocv-capacity-legend",
>> +						 di->ocv_lut.capacity_legend, 0,
>> +						 MAX_CAPACITY_ROWS);
>> +	if (di->ocv_lut.rows < 0) {
>> +		dev_err(di->dev, "no open circuit voltage capacity legend found");
>> +		return ret;
>> +	}
>> +
>> +	ret = of_property_read_variable_u32_array(di->dev->of_node,
>> +						  "qcom,ocv-lut-microvolt",
>> +						  (u32 *)di->ocv_lut.lut,
>> +						  TEMPERATURE_COLS,
>> +						  TEMPERATURE_COLS *
>> +						  MAX_CAPACITY_ROWS);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "no open circuit voltage lut array found");
>> +		return ret;
>> +	}
>> +
>> +	ret = of_property_read_u8_array(di->dev->of_node,
>> +						 "qcom,fcc-temp-legend-celsius",
>> +						 (u8 *)di->fcc_lut.temp_legend,
>> +						 TEMPERATURE_COLS);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "no full charge capacity temperature legend
>found");
>> +		return ret;
>> +	}
>> +
>> +	ret = of_property_read_u32_array(di->dev->of_node,
>> +						  "qcom,fcc-lut-microamp-hours",
>> +						  di->fcc_lut.lut,
>> +						  TEMPERATURE_COLS);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "no full charge capacity lut array found");
>> +		return ret;
>> +	}
>> +
>> +	ret = bms_read_ocv(di, &di->ocv);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "failed to read initial open circuit voltage:
>%d",
>> +			ret);
>> +		return ret;
>> +	}
>> +
>> +	mutex_init(&di->bms_output_lock);
>> +
>> +	di->ocv_thr_irq = platform_get_irq_byname(pdev, "ocv_thr");
>> +
>> +	ret = devm_request_threaded_irq(di->dev, di->ocv_thr_irq, NULL,
>> +					bms_ocv_thr_irq_handler,
>> +					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
>> +					pdev->name, di);
>> +	if (ret < 0) {
>> +		dev_err(di->dev, "failed to request handler for open circuit
>voltage threshold IRQ");
>> +		return ret;
>> +	}
>> +
>> +
>
>one empty line is enough.
>
>> +	di->bat_desc.name = "bms";
>> +	di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
>> +	di->bat_desc.properties = bms_props;
>> +	di->bat_desc.num_properties = ARRAY_SIZE(bms_props);
>> +	di->bat_desc.get_property = bms_get_property;
>> +
>> +	psy_cfg.drv_data = di;
>
>psy_cfg.of_node = pdev->dev.of_node;
>
>> +	bat = devm_power_supply_register(di->dev, &di->bat_desc, &psy_cfg);
>> +
>> +	return PTR_ERR_OR_ZERO(bat);
>> +}
>> +
>> +static const struct of_device_id bms_of_match[] = {
>> +	{.compatible = "qcom,pm8941-bms", },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, bms_of_match);
>> +
>> +static struct platform_driver bms_driver = {
>> +	.probe = bms_probe,
>> +	.driver = {
>> +		.name = "qcom-bms",
>> +		.of_match_table = of_match_ptr(bms_of_match),
>> +	},
>> +};
>> +module_platform_driver(bms_driver);
>> +
>> +MODULE_AUTHOR("Craig Tatlor <ctatlor97@gmail.com>");
>> +MODULE_DESCRIPTION("Qualcomm BMS driver");
>> +MODULE_LICENSE("GPL");
>
>Apart from the things above I would like to see the information
>about the battery cell itself being moved to 'struct
>power_supply_battery_info', see also my comment in the DT bindings.
Sure, will look into it
>
>-- Sebastian

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 14:32       ` Craig
@ 2018-09-20 16:58         ` Sebastian Reichel
  2018-09-20 19:13           ` Craig
                             ` (2 more replies)
  0 siblings, 3 replies; 60+ messages in thread
From: Sebastian Reichel @ 2018-09-20 16:58 UTC (permalink / raw)
  To: Craig, Baolin Wang, Rob Herring
  Cc: linux-arm-msm, Mark Rutland, linux-pm, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1818 bytes --]

[Dropped a couple of people from CC, added Baolin]

Hi Craig, Baolin and Rob,

On Thu, Sep 20, 2018 at 03:32:29PM +0100, Craig wrote:
> On 16 September 2018 13:10:45 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
> >Sorry for my long delay in reviewing this. I like the binding,
> >but the "qcom," specific properties should become common properties
> >in
> >
> >Documentation/devicetree/bindings/power/supply/battery.txt
> >and referenced via monitored-battery.

> Thanks for the review, what bindings for ocv would you prefer? The
> spreadtrum ones or mine?

Most importantly I want to see only one generic binding supporting
both use cases. As far as I can see there are two major differences:

1. Qcom uses legend properties and SC27XX embedds this into data
2. Qcom supports temperature based mapping

The second point is easy: Not having temperature information can
be a subset of the data with temperature info. The main thing to
discuss are the legend properties. I suppose we have these
proposals:

Proposal A (from Qcom BMS binding):

ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75 70 65 60 55 50 45 ...>;
ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
ocv-lut-microvolt = <43050000 43050000 43030000 42990000

Proposal B (from SC27XX binding):

ocv-cap-table = <4185 100>, <4113 95>, <4066 90>, <4022 85> ...;

I prefer the second binding (with mV -> uV), but I think it becomes
messy when temperature is added. What do you think about the
following proposal (derived from pinctrl style):

Proposal C:

ocv-capacity-table-temperatures = <(-10) 0 10>;
ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 16:58         ` Sebastian Reichel
@ 2018-09-20 19:13           ` Craig
  2018-09-20 21:42             ` Sebastian Reichel
  2018-09-20 20:08           ` Baolin Wang
  2018-09-21 15:40           ` Linus Walleij
  2 siblings, 1 reply; 60+ messages in thread
From: Craig @ 2018-09-20 19:13 UTC (permalink / raw)
  To: Sebastian Reichel, Baolin Wang, Rob Herring
  Cc: linux-arm-msm, Mark Rutland, linux-pm, devicetree, linux-kernel



On 20 September 2018 17:58:47 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
>[Dropped a couple of people from CC, added Baolin]
>
>Hi Craig, Baolin and Rob,
>
>On Thu, Sep 20, 2018 at 03:32:29PM +0100, Craig wrote:
>> On 16 September 2018 13:10:45 BST, Sebastian Reichel
><sebastian.reichel@collabora.com> wrote:
>> >Sorry for my long delay in reviewing this. I like the binding,
>> >but the "qcom," specific properties should become common properties
>> >in
>> >
>> >Documentation/devicetree/bindings/power/supply/battery.txt
>> >and referenced via monitored-battery.
>
>> Thanks for the review, what bindings for ocv would you prefer? The
>> spreadtrum ones or mine?
>
>Most importantly I want to see only one generic binding supporting
>both use cases. As far as I can see there are two major differences:
>
>1. Qcom uses legend properties and SC27XX embedds this into data
>2. Qcom supports temperature based mapping
>
>The second point is easy: Not having temperature information can
>be a subset of the data with temperature info. The main thing to
>discuss are the legend properties. I suppose we have these
>proposals:
>
>Proposal A (from Qcom BMS binding):
>
>ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75 70 65 60 55 50 45
>...>;
>ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
>ocv-lut-microvolt = <43050000 43050000 43030000 42990000
>
>Proposal B (from SC27XX binding):
>
>ocv-cap-table = <4185 100>, <4113 95>, <4066 90>, <4022 85> ...;
>
>I prefer the second binding (with mV -> uV), but I think it becomes
>messy when temperature is added. What do you think about the
>following proposal (derived from pinctrl style):
>
>Proposal C:
>
>ocv-capacity-table-temperatures = <(-10) 0 10>;
>ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
>ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
>ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
>
>-- Sebastian

C looks good to me however I do kinda think it should be millivolts as I don't think any hardware reads in microvolts and the zeroes make it look quite ugly

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 16:58         ` Sebastian Reichel
  2018-09-20 19:13           ` Craig
@ 2018-09-20 20:08           ` Baolin Wang
  2018-09-20 22:13             ` Sebastian Reichel
  2018-09-21 15:40           ` Linus Walleij
  2 siblings, 1 reply; 60+ messages in thread
From: Baolin Wang @ 2018-09-20 20:08 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Craig, Rob Herring, linux-arm-msm, Mark Rutland, Linux PM list,
	DTML, LKML

Hi Sebastian,

On 21 September 2018 at 00:58, Sebastian Reichel
<sebastian.reichel@collabora.com> wrote:
> [Dropped a couple of people from CC, added Baolin]
>
> Hi Craig, Baolin and Rob,
>
> On Thu, Sep 20, 2018 at 03:32:29PM +0100, Craig wrote:
>> On 16 September 2018 13:10:45 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
>> >Sorry for my long delay in reviewing this. I like the binding,
>> >but the "qcom," specific properties should become common properties
>> >in
>> >
>> >Documentation/devicetree/bindings/power/supply/battery.txt
>> >and referenced via monitored-battery.
>
>> Thanks for the review, what bindings for ocv would you prefer? The
>> spreadtrum ones or mine?
>
> Most importantly I want to see only one generic binding supporting
> both use cases. As far as I can see there are two major differences:
>
> 1. Qcom uses legend properties and SC27XX embedds this into data
> 2. Qcom supports temperature based mapping
>
> The second point is easy: Not having temperature information can
> be a subset of the data with temperature info. The main thing to
> discuss are the legend properties. I suppose we have these
> proposals:
>
> Proposal A (from Qcom BMS binding):
>
> ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75 70 65 60 55 50 45 ...>;
> ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
> ocv-lut-microvolt = <43050000 43050000 43030000 42990000
>
> Proposal B (from SC27XX binding):
>
> ocv-cap-table = <4185 100>, <4113 95>, <4066 90>, <4022 85> ...;
>
> I prefer the second binding (with mV -> uV), but I think it becomes
> messy when temperature is added. What do you think about the
> following proposal (derived from pinctrl style):
>
> Proposal C:
>
> ocv-capacity-table-temperatures = <(-10) 0 10>;
> ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
> ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
> ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;

For SC27XX, we have no temperatures consideration, but I think
Proposal C can be compatible with our case.

-- 
Baolin Wang
Best Regards

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 19:13           ` Craig
@ 2018-09-20 21:42             ` Sebastian Reichel
  0 siblings, 0 replies; 60+ messages in thread
From: Sebastian Reichel @ 2018-09-20 21:42 UTC (permalink / raw)
  To: Craig
  Cc: Baolin Wang, Rob Herring, linux-arm-msm, Mark Rutland, linux-pm,
	devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2510 bytes --]

On Thu, Sep 20, 2018 at 08:13:52PM +0100, Craig wrote:
> On 20 September 2018 17:58:47 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
> >[Dropped a couple of people from CC, added Baolin]
> >
> >Hi Craig, Baolin and Rob,
> >
> >On Thu, Sep 20, 2018 at 03:32:29PM +0100, Craig wrote:
> >> On 16 September 2018 13:10:45 BST, Sebastian Reichel
> ><sebastian.reichel@collabora.com> wrote:
> >> >Sorry for my long delay in reviewing this. I like the binding,
> >> >but the "qcom," specific properties should become common properties
> >> >in
> >> >
> >> >Documentation/devicetree/bindings/power/supply/battery.txt
> >> >and referenced via monitored-battery.
> >
> >> Thanks for the review, what bindings for ocv would you prefer? The
> >> spreadtrum ones or mine?
> >
> >Most importantly I want to see only one generic binding supporting
> >both use cases. As far as I can see there are two major differences:
> >
> >1. Qcom uses legend properties and SC27XX embedds this into data
> >2. Qcom supports temperature based mapping
> >
> >The second point is easy: Not having temperature information can
> >be a subset of the data with temperature info. The main thing to
> >discuss are the legend properties. I suppose we have these
> >proposals:
> >
> >Proposal A (from Qcom BMS binding):
> >
> >ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75 70 65 60 55 50 45
> >...>;
> >ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
> >ocv-lut-microvolt = <43050000 43050000 43030000 42990000
> >
> >Proposal B (from SC27XX binding):
> >
> >ocv-cap-table = <4185 100>, <4113 95>, <4066 90>, <4022 85> ...;
> >
> >I prefer the second binding (with mV -> uV), but I think it becomes
> >messy when temperature is added. What do you think about the
> >following proposal (derived from pinctrl style):
> >
> >Proposal C:
> >
> >ocv-capacity-table-temperatures = <(-10) 0 10>;
> >ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
> >ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
> >ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
> >
> >-- Sebastian
> 
> C looks good to me however I do kinda think it should be
> millivolts as I don't think any hardware reads in microvolts and
> the zeroes make it look quite ugly

I agree, that it looks a bit ugly in the table. Nevertheless I think we
should use microvolts, since that is being used by all other properties.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 20:08           ` Baolin Wang
@ 2018-09-20 22:13             ` Sebastian Reichel
  0 siblings, 0 replies; 60+ messages in thread
From: Sebastian Reichel @ 2018-09-20 22:13 UTC (permalink / raw)
  To: Baolin Wang
  Cc: Craig, Rob Herring, linux-arm-msm, Mark Rutland, Linux PM list,
	DTML, LKML

[-- Attachment #1: Type: text/plain, Size: 2607 bytes --]

Hi,

On Fri, Sep 21, 2018 at 04:08:28AM +0800, Baolin Wang wrote:
> Hi Sebastian,
> 
> On 21 September 2018 at 00:58, Sebastian Reichel
> <sebastian.reichel@collabora.com> wrote:
> > [Dropped a couple of people from CC, added Baolin]
> >
> > Hi Craig, Baolin and Rob,
> >
> > On Thu, Sep 20, 2018 at 03:32:29PM +0100, Craig wrote:
> >> On 16 September 2018 13:10:45 BST, Sebastian Reichel <sebastian.reichel@collabora.com> wrote:
> >> >Sorry for my long delay in reviewing this. I like the binding,
> >> >but the "qcom," specific properties should become common properties
> >> >in
> >> >
> >> >Documentation/devicetree/bindings/power/supply/battery.txt
> >> >and referenced via monitored-battery.
> >
> >> Thanks for the review, what bindings for ocv would you prefer? The
> >> spreadtrum ones or mine?
> >
> > Most importantly I want to see only one generic binding supporting
> > both use cases. As far as I can see there are two major differences:
> >
> > 1. Qcom uses legend properties and SC27XX embedds this into data
> > 2. Qcom supports temperature based mapping
> >
> > The second point is easy: Not having temperature information can
> > be a subset of the data with temperature info. The main thing to
> > discuss are the legend properties. I suppose we have these
> > proposals:
> >
> > Proposal A (from Qcom BMS binding):
> >
> > ocv-capacity-legend = /bits/ 8 <100 95 90 85 80 75 70 65 60 55 50 45 ...>;
> > ocv-temp-legend-celsius = /bits/ 8 <(-10) 0 25 50 65>;
> > ocv-lut-microvolt = <43050000 43050000 43030000 42990000
> >
> > Proposal B (from SC27XX binding):
> >
> > ocv-cap-table = <4185 100>, <4113 95>, <4066 90>, <4022 85> ...;
> >
> > I prefer the second binding (with mV -> uV), but I think it becomes
> > messy when temperature is added. What do you think about the
> > following proposal (derived from pinctrl style):
> >
> > Proposal C:
> >
> > ocv-capacity-table-temperatures = <(-10) 0 10>;
> > ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
> > ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
> > ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
> 
> For SC27XX, we have no temperatures consideration, but I think
> Proposal C can be compatible with our case.

Yes. I think for SC27XX proposal C could be used like this:

ocv-capacity-table-temperatures = <20>; /* room temperature */
ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;

With only one curve defined it would be used for all temperatures.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings
  2018-09-20 16:58         ` Sebastian Reichel
  2018-09-20 19:13           ` Craig
  2018-09-20 20:08           ` Baolin Wang
@ 2018-09-21 15:40           ` Linus Walleij
  2 siblings, 0 replies; 60+ messages in thread
From: Linus Walleij @ 2018-09-21 15:40 UTC (permalink / raw)
  To: sebastian.reichel
  Cc: Craig Tatlor, Baolin Wang, Rob Herring, linux-arm-msm,
	Mark Rutland, Linux PM list,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel

On Thu, Sep 20, 2018 at 9:58 AM Sebastian Reichel
<sebastian.reichel@collabora.com> wrote:

> I prefer the second binding (with mV -> uV), but I think it becomes
> messy when temperature is added. What do you think about the
> following proposal (derived from pinctrl style):
>
> Proposal C:
>
> ocv-capacity-table-temperatures = <(-10) 0 10>;
> ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
> ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
> ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;

I think this looks very elegant. It's going to be very
easy and intuitive for people who need to maintain these
device trees and it will be easy to handle in centralized code
for all platforms. Even with the microvolt notation.

If possible could we go with this?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-13  7:45     ` Craig Tatlor
@ 2018-09-24 12:44       ` Heiko Stuebner
  2018-09-24 14:33         ` Craig
  0 siblings, 1 reply; 60+ messages in thread
From: Heiko Stuebner @ 2018-09-24 12:44 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: Taniya Das, linux-arm-msm, Michael Turquette, Stephen Boyd,
	Rob Herring, Mark Rutland, Andy Gross, David Brown, linux-clk,
	devicetree, linux-kernel, linux-soc

Hi Craig,

Am Montag, 13. August 2018, 09:45:09 CEST schrieb Craig Tatlor:
> On 13 August 2018 07:55:34 BST, Taniya Das <tdas@codeaurora.org> wrote:
> >Hello Craig,
> >
> >Could you please correct the authorship and also provide the reference 
> >to code where this is picked from?
> Okay, 
> Got code from here https://github.com/sonyxperiadev/kernel/blob/aosp/LA.UM.6.4.r1/drivers/clk/qcom/gcc-sdm660.c
> but changed it quite a bit for upstream,
> Should I change the commit author and add your signed off by and say I did cleanups on my signed off by.

yep, for something this huge it is really the correct way to keep the
original authorship intact as Taniya did the initial big work, and just
add you change-description, so something like

---- 8< ------
Add support for the global clock controller found on SDM660
based devices. This should allow most non-multimedia device
drivers to probe and control their clocks.
Based on CAF implementation.

Signed-off-by: Taniya Das <tdas@codeaurora.org>
[ description of changes ... often seen in these brackets ]
Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---- 8< ------

Also, do you plan to continue working on this, as I would be interessted
in the clock driver for a sdm660-based phone as well.


Thanks
Heiko



^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-09-24 12:44       ` Heiko Stuebner
@ 2018-09-24 14:33         ` Craig
  0 siblings, 0 replies; 60+ messages in thread
From: Craig @ 2018-09-24 14:33 UTC (permalink / raw)
  To: Heiko Stuebner
  Cc: Taniya Das, linux-arm-msm, Michael Turquette, Stephen Boyd,
	Rob Herring, Mark Rutland, Andy Gross, David Brown, linux-clk,
	devicetree, linux-kernel, linux-soc



On 24 September 2018 13:44:33 BST, Heiko Stuebner <heiko@sntech.de> wrote:
>Hi Craig,
>
>Am Montag, 13. August 2018, 09:45:09 CEST schrieb Craig Tatlor:
>> On 13 August 2018 07:55:34 BST, Taniya Das <tdas@codeaurora.org>
>wrote:
>> >Hello Craig,
>> >
>> >Could you please correct the authorship and also provide the
>reference 
>> >to code where this is picked from?
>> Okay, 
>> Got code from here
>https://github.com/sonyxperiadev/kernel/blob/aosp/LA.UM.6.4.r1/drivers/clk/qcom/gcc-sdm660.c
>> but changed it quite a bit for upstream,
>> Should I change the commit author and add your signed off by and say
>I did cleanups on my signed off by.
>
>yep, for something this huge it is really the correct way to keep the
>original authorship intact as Taniya did the initial big work, and just
>add you change-description, so something like
>
>---- 8< ------
>Add support for the global clock controller found on SDM660
>based devices. This should allow most non-multimedia device
>drivers to probe and control their clocks.
>Based on CAF implementation.
>
>Signed-off-by: Taniya Das <tdas@codeaurora.org>
>[ description of changes ... often seen in these brackets ]
>Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>---- 8< ------
>
Sure, will do, though I'm sure qcom have a program to generate the drivers :)

>Also, do you plan to continue working on this, as I would be
>interessted
>in the clock driver for a sdm660-based phone as well
Yup, was really just waiting for reply to this question,
>
>
>Thanks
>Heiko

-- 

^ permalink raw reply	[flat|nested] 60+ messages in thread

* [PATCH v2] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
                     ` (2 preceding siblings ...)
  2018-08-13  6:55   ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Taniya Das
@ 2018-09-25 16:35   ` Craig Tatlor
  2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
  4 siblings, 0 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-09-25 16:35 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Taniya Das, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Andy Gross, David Brown,
	linux-clk, devicetree, linux-kernel, linux-soc

From: Taniya Das <tdas@codeaurora.org>

Add support for the global clock controller found on SDM660
based devices. This should allow most non-multimedia device
drivers to probe and control their clocks.
Based on CAF implementation.

Signed-off-by: Taniya Das <tdas@codeaurora.org>
[craig: rename parents to fit upstream, and other cleanups]
Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
 .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
 drivers/clk/qcom/Kconfig                      |    9 +
 drivers/clk/qcom/Makefile                     |    1 +
 drivers/clk/qcom/gcc-sdm660.c                 | 2479 +++++++++++++++++
 include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
 5 files changed, 2649 insertions(+)
 create mode 100644 drivers/clk/qcom/gcc-sdm660.c
 create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 664ea1fd6c76..e498ad2e8db8 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -19,6 +19,7 @@ Required properties :
 			"qcom,gcc-msm8996"
 			"qcom,gcc-msm8998"
 			"qcom,gcc-mdm9615"
+			"qcom,gcc-sdm660"
 			"qcom,gcc-sdm845"
 
 - reg : shall contain base register location and length
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 5b181b182f40..4d478b261dfe 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -243,6 +243,15 @@ config SDM_CAMCC_845
 	  Support for the camera clock controller on SDM845 devices.
 	  Say Y if you want to support camera devices and camera functionality.
 
+config SDM_GCC_660
+	tristate "SDM660 Global Clock Controller"
+	select QCOM_GDSC
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the global clock controller on SDM660 devices.
+	  Say Y if you want to use peripheral devices such as UART, SPI,
+	  i2C, USB, UFS, SDDC, PCIe, etc.
+
 config SDM_GCC_845
 	tristate "SDM845 Global Clock Controller"
 	select QCOM_GDSC
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 935f142bc155..ab892f6d847c 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
 obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
 obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
 obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
+obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
 obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
 obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
 obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
new file mode 100644
index 000000000000..cec8b4145b71
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -0,0 +1,2479 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#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,gcc-sdm660.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "gdsc.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+	P_XO,
+	P_SLEEP_CLK,
+	P_GPLL0,
+	P_GPLL1,
+	P_GPLL4,
+	P_GPLL0_EARLY_DIV,
+	P_GPLL1_EARLY_DIV,
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0[] = {
+	"xo",
+	"gpll0",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"sleep_clk",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
+	{ P_XO, 0 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const char * const gcc_parent_names_xo_sleep_clk[] = {
+	"xo",
+	"sleep_clk",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll4[] = {
+	"xo",
+	"gpll4",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL1_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll1",
+	"gpll4",
+	"gpll1_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll4",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 2 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll4",
+};
+
+static struct clk_fixed_factor xo = {
+	.mult = 1,
+	.div = 1,
+	.hw.init = &(struct clk_init_data){
+		.name = "xo",
+		.parent_names = (const char *[]){ "xo_board" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll0_early = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll0_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll0_early_div",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+	.offset = 0x00000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll0",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll1_early = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll1_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll1_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll1_early_div",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll1 = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll1",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll4_early = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll4_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data)
+	{
+		.name = "gpll4",
+		.parent_names = (const char *[]) { "gpll4_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x19020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(960000, P_XO, 10, 1, 2),
+	F(4800000, P_XO, 4, 0, 0),
+	F(9600000, P_XO, 2, 0, 0),
+	F(15000000, P_GPLL0, 10, 1, 4),
+	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1900c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1b020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1b00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1d020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1d00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1f020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1f00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+	F(3686400, P_GPLL0, 1, 96, 15625),
+	F(7372800, P_GPLL0, 1, 192, 15625),
+	F(14745600, P_GPLL0, 1, 384, 15625),
+	F(16000000, P_GPLL0, 5, 2, 15),
+	F(19200000, P_XO, 1, 0, 0),
+	F(24000000, P_GPLL0, 5, 1, 5),
+	F(32000000, P_GPLL0, 1, 4, 75),
+	F(40000000, P_GPLL0, 15, 0, 0),
+	F(46400000, P_GPLL0, 1, 29, 375),
+	F(48000000, P_GPLL0, 12.5, 0, 0),
+	F(51200000, P_GPLL0, 1, 32, 375),
+	F(56000000, P_GPLL0, 1, 7, 75),
+	F(58982400, P_GPLL0, 1, 1536, 15625),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(63157895, P_GPLL0, 9.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x1a00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x1c00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x26020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2600c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x28020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2800c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2a020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2a00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2c020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2c00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x2700c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x2900c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+	.cmd_rcgr = 0x64004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp1_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+	.cmd_rcgr = 0x65004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+	.cmd_rcgr = 0x66004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp3_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+	F(300000000, P_GPLL0, 2, 0, 0),
+	F(600000000, P_GPLL0, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+	.cmd_rcgr = 0x4805c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_gpll0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll0_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
+	F(384000000, P_GPLL4, 4, 0, 0),
+	F(768000000, P_GPLL4, 2, 0, 0),
+	F(1536000000, P_GPLL4, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll4_clk_src = {
+	.cmd_rcgr = 0x48074,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll4,
+	.freq_tbl = ftbl_hmss_gpll4_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll4_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll4,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+	.cmd_rcgr = 0x48044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_rbcpr_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+	.cmd_rcgr = 0x33010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pdm2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
+	F(160400000, P_GPLL1, 5, 0, 0),
+	F(267333333, P_GPLL1, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+	.cmd_rcgr = 0x4d00c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+	.freq_tbl = ftbl_qspi_ser_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "qspi_ser_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+		.num_parents = 6,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(384000000, P_GPLL4, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+	.cmd_rcgr = 0x1602c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+	.cmd_rcgr = 0x16010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+	.cmd_rcgr = 0x14010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+	.cmd_rcgr = 0x75018,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_axi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+	.cmd_rcgr = 0x76010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 ufs_phy_aux_clk_src = {
+	.cmd_rcgr = 0x76044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
+	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
+	F(75000000, P_GPLL0, 8, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_unipro_core_clk_src = {
+	.cmd_rcgr = 0x76028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_unipro_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+	.cmd_rcgr = 0x2f010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x2f024,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	F(133333333, P_GPLL0, 4.5, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+	.cmd_rcgr = 0xf014,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+	.cmd_rcgr = 0xf028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+	F(1200000, P_XO, 16, 0, 0),
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+	.cmd_rcgr = 0x5000c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb3_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+	.halt_reg = 0x75034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75034,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+	.halt_reg = 0xf03c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+	.halt_reg = 0x7106c,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x7106c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_hmss_axi_clk = {
+	.halt_reg = 0x48004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(22),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_hmss_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
+	.halt_reg = 0x4401c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4401c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_mss_q6_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+	.halt_reg = 0x17004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(17),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+	.halt_reg = 0x19008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+	.halt_reg = 0x19004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+	.halt_reg = 0x1b008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+	.halt_reg = 0x1b004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+	.halt_reg = 0x1d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+	.halt_reg = 0x1d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+	.halt_reg = 0x1f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+	.halt_reg = 0x1f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+	.halt_reg = 0x1a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+	.halt_reg = 0x1c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+	.halt_reg = 0x25004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(15),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+	.halt_reg = 0x26008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+	.halt_reg = 0x26004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+	.halt_reg = 0x28008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+	.halt_reg = 0x28004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+	.halt_reg = 0x2a008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+	.halt_reg = 0x2a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+	.halt_reg = 0x2c008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+	.halt_reg = 0x2c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+	.halt_reg = 0x27004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x27004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+	.halt_reg = 0x29004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x29004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+	.halt_reg = 0x38004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(10),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_boot_rom_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_axi_clk = {
+	.halt_reg = 0x5058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5058,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb2_axi_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_axi_clk = {
+	.halt_reg = 0x5018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_dcc_ahb_clk = {
+	.halt_reg = 0x84004,
+	.clkr = {
+		.enable_reg = 0x84004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_dcc_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp1_clk = {
+	.halt_reg = 0x64000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x64000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp1_clk",
+			.parent_names = (const char *[]){
+				"gp1_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp2_clk = {
+	.halt_reg = 0x65000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x65000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp2_clk",
+			.parent_names = (const char *[]){
+				"gp2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp3_clk = {
+	.halt_reg = 0x66000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x66000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp3_clk",
+			.parent_names = (const char *[]){
+				"gp3_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_bimc_gfx_clk = {
+	.halt_reg = 0x71010,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+	.halt_reg = 0x71004,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(3),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_dvm_bus_clk = {
+	.halt_reg = 0x4808c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4808c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_dvm_bus_clk",
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+	.halt_reg = 0x48008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x48008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_rbcpr_clk",
+			.parent_names = (const char *[]){
+				"hmss_rbcpr_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x9004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_noc_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_sys_noc_axi_clk = {
+	.halt_reg = 0x9000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_sys_noc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+	.halt_reg = 0x8a000,
+	.clkr = {
+		.enable_reg = 0x8a000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+	.halt_reg = 0x8a004,
+	.clkr = {
+		.enable_reg = 0x8a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_mnoc_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+	.halt_reg = 0x8a040,
+	.clkr = {
+		.enable_reg = 0x8a040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_q6_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+	.halt_reg = 0x8a03c,
+	.clkr = {
+		.enable_reg = 0x8a03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_snoc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+	.halt_reg = 0x3300c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x3300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm2_clk",
+			.parent_names = (const char *[]){
+				"pdm2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+	.halt_reg = 0x33004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x33004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+	.halt_reg = 0x34004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(13),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_prng_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+	.halt_reg = 0x4d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+	.halt_reg = 0x4d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ser_clk",
+			.parent_names = (const char *[]){
+				"qspi_ser_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx0_usb2_clkref_clk = {
+	.halt_reg = 0x88018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx0_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+	.halt_reg = 0x88014,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx1_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+	.halt_reg = 0x16008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+	.halt_reg = 0x16004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+	.halt_reg = 0x1600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ice_core_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+	.halt_reg = 0x14008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+	.halt_reg = 0x14004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+	.halt_reg = 0x7500c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7500c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+	.halt_reg = 0x75008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+	.halt_reg = 0x88008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x88008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+	.halt_reg = 0x7600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ice_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_phy_aux_clk = {
+	.halt_reg = 0x76040,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"ufs_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+	.halt_reg = 0x75014,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+	.halt_reg = 0x7605c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x7605c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+	.halt_reg = 0x75010,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+	.halt_reg = 0x76008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_unipro_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_unipro_core_clk_src",
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+	.halt_reg = 0x2f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_master_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src"
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+	.halt_reg = 0x2f00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb20_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+	.halt_reg = 0x2f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+	.halt_reg = 0xf008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_master_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+	.halt_reg = 0xf010,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb30_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+	.halt_reg = 0xf00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+	.halt_reg = 0x8800c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x8800c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+	.halt_reg = 0x50000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x50000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"usb3_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+	.halt_reg = 0x50004,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x50004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_pipe_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+	.halt_reg = 0x6a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x6a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb_phy_cfg_ahb2phy_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc ufs_gdsc = {
+	.gdscr = 0x75004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "ufs_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc usb_30_gdsc = {
+	.gdscr = 0xf004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "usb_30_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc pcie_0_gdsc = {
+	.gdscr = 0x6b004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "pcie_0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct clk_hw *gcc_sdm660_hws[] = {
+	[GCC_XO] = &xo.hw,
+	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
+	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,
+};
+
+static struct clk_regmap *gcc_660_clocks[] = {
+	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+	[BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+	[BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+	[BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+	[BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+	[BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+	[BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+	[BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+	[BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+	[BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+	[BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+	[GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+	[GCC_BIMC_HMSS_AXI_CLK] = &gcc_bimc_hmss_axi_clk.clkr,
+	[GCC_BIMC_MSS_Q6_AXI_CLK] = &gcc_bimc_mss_q6_axi_clk.clkr,
+	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+	[GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+	[GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+	[GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+	[GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+	[GCC_CFG_NOC_USB2_AXI_CLK] = &gcc_cfg_noc_usb2_axi_clk.clkr,
+	[GCC_CFG_NOC_USB3_AXI_CLK] = &gcc_cfg_noc_usb3_axi_clk.clkr,
+	[GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+	[GCC_GPU_BIMC_GFX_CLK] = &gcc_gpu_bimc_gfx_clk.clkr,
+	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+	[GCC_GPU_GPLL0_CLK] = &gcc_gpu_gpll0_clk.clkr,
+	[GCC_GPU_GPLL0_DIV_CLK] = &gcc_gpu_gpll0_div_clk.clkr,
+	[GCC_HMSS_DVM_BUS_CLK] = &gcc_hmss_dvm_bus_clk.clkr,
+	[GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+	[GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
+	[GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+	[GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+	[GCC_MMSS_SYS_NOC_AXI_CLK] = &gcc_mmss_sys_noc_axi_clk.clkr,
+	[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+	[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+	[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+	[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+	[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+	[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+	[GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
+	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+	[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+	[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+	[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+	[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+	[GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+	[GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+	[GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+	[GCC_UFS_PHY_AUX_CLK] = &gcc_ufs_phy_aux_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+	[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+	[GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+	[GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+	[GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+	[GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+	[GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+	[GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+	[GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+	[GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+	[GP1_CLK_SRC] = &gp1_clk_src.clkr,
+	[GP2_CLK_SRC] = &gp2_clk_src.clkr,
+	[GP3_CLK_SRC] = &gp3_clk_src.clkr,
+	[GPLL0] = &gpll0.clkr,
+	[GPLL0_EARLY] = &gpll0_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL1_EARLY] = &gpll1_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL4_EARLY] = &gpll4_early.clkr,
+	[GPLL4] = &gpll4.clkr,
+	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+	[HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
+	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+	[QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+	[SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+	[UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+	[UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+	[UFS_PHY_AUX_CLK_SRC] = &ufs_phy_aux_clk_src.clkr,
+	[UFS_UNIPRO_CORE_CLK_SRC] = &ufs_unipro_core_clk_src.clkr,
+	[USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+	[USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+	[USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+	[USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+};
+
+static struct gdsc *gcc_660_gdscs[] = {
+	[UFS_GDSC] = &ufs_gdsc,
+	[USB_30_GDSC] = &usb_30_gdsc,
+	[PCIE_0_GDSC] = &pcie_0_gdsc,
+};
+
+static const struct qcom_reset_map gcc_660_resets[] = {
+	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+	[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+	[GCC_UFS_BCR] = { 0x75000 },
+	[GCC_USB3_DP_PHY_BCR] = { 0x50028 },
+	[GCC_USB3_PHY_BCR] = { 0x50020 },
+	[GCC_USB3PHY_PHY_BCR] = { 0x50024 },
+	[GCC_USB_20_BCR] = { 0x2f000 },
+	[GCC_USB_30_BCR] = { 0xf000 },
+	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+};
+
+static const struct regmap_config gcc_660_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x94000,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc gcc_660_desc = {
+	.config = &gcc_660_regmap_config,
+	.clks = gcc_660_clocks,
+	.num_clks = ARRAY_SIZE(gcc_660_clocks),
+	.resets = gcc_660_resets,
+	.num_resets = ARRAY_SIZE(gcc_660_resets),
+	.gdscs = gcc_660_gdscs,
+	.num_gdscs = ARRAY_SIZE(gcc_660_gdscs),
+};
+
+static const struct of_device_id gcc_660_match_table[] = {
+	{ .compatible = "qcom,gcc-sdm660" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_660_match_table);
+
+static int gcc_660_probe(struct platform_device *pdev)
+{
+	int i, ret = 0;
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &gcc_660_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/*
+	 * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+	 * turned off by hardware during certain apps low power modes.
+	 */
+	ret = regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+	if (ret)
+		return ret;
+
+	/* Register the hws */
+	for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) {
+		ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]);
+		if (ret)
+			return ret;
+	}
+
+	return qcom_cc_really_probe(pdev, &gcc_660_desc, regmap);
+}
+
+static struct platform_driver gcc_660_driver = {
+	.probe		= gcc_660_probe,
+	.driver		= {
+		.name	= "gcc-sdm660",
+		.of_match_table = gcc_660_match_table,
+	},
+};
+
+static int __init gcc_660_init(void)
+{
+	return platform_driver_register(&gcc_660_driver);
+}
+core_initcall_sync(gcc_660_init);
+
+static void __exit gcc_660_exit(void)
+{
+	platform_driver_unregister(&gcc_660_driver);
+}
+module_exit(gcc_660_exit);
+
+MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
new file mode 100644
index 000000000000..76aabcc5e7e3
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_660_H
+#define _DT_BINDINGS_CLK_MSM_GCC_660_H
+
+#define GCC_XO					0
+#define GCC_GPLL0_EARLY_DIV			1
+#define GCC_GPLL1_EARLY_DIV			2
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC		3
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC		4
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC		5
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC		6
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC		7
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC		8
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC		9
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC		10
+#define BLSP1_UART1_APPS_CLK_SRC		11
+#define BLSP1_UART2_APPS_CLK_SRC		12
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC		13
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC		14
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC		15
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC		16
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC		17
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC		18
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC		19
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC		20
+#define BLSP2_UART1_APPS_CLK_SRC		21
+#define BLSP2_UART2_APPS_CLK_SRC		22
+#define GCC_AGGRE2_UFS_AXI_CLK			23
+#define GCC_AGGRE2_USB3_AXI_CLK			24
+#define GCC_BIMC_GFX_CLK			25
+#define GCC_BIMC_HMSS_AXI_CLK			26
+#define GCC_BIMC_MSS_Q6_AXI_CLK			27
+#define GCC_BLSP1_AHB_CLK			28
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK		29
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK		30
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK		31
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK		32
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK		33
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK		34
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK		35
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK		36
+#define GCC_BLSP1_UART1_APPS_CLK		37
+#define GCC_BLSP1_UART2_APPS_CLK		38
+#define GCC_BLSP2_AHB_CLK			39
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK		40
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK		41
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK		42
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK		43
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK		44
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK		46
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK		45
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK		46
+#define GCC_BLSP2_UART1_APPS_CLK		47
+#define GCC_BLSP2_UART2_APPS_CLK		48
+#define GCC_BOOT_ROM_AHB_CLK			49
+#define GCC_CFG_NOC_USB2_AXI_CLK		50
+#define GCC_CFG_NOC_USB3_AXI_CLK		51
+#define GCC_DCC_AHB_CLK				52
+#define GCC_GP1_CLK				53
+#define GCC_GP2_CLK				54
+#define GCC_GP3_CLK				55
+#define GCC_GPU_BIMC_GFX_CLK			56
+#define GCC_GPU_CFG_AHB_CLK			57
+#define GCC_GPU_GPLL0_CLK			58
+#define GCC_GPU_GPLL0_DIV_CLK			59
+#define GCC_HMSS_DVM_BUS_CLK			60
+#define GCC_HMSS_RBCPR_CLK			61
+#define GCC_MMSS_GPLL0_CLK			62
+#define GCC_MMSS_GPLL0_DIV_CLK			63
+#define GCC_MMSS_NOC_CFG_AHB_CLK		64
+#define GCC_MMSS_SYS_NOC_AXI_CLK		65
+#define GCC_MSS_CFG_AHB_CLK			66
+#define GCC_MSS_GPLL0_DIV_CLK			67
+#define GCC_MSS_MNOC_BIMC_AXI_CLK		68
+#define GCC_MSS_Q6_BIMC_AXI_CLK			69
+#define GCC_MSS_SNOC_AXI_CLK			70
+#define GCC_PDM2_CLK				71
+#define GCC_PDM_AHB_CLK				72
+#define GCC_PRNG_AHB_CLK			73
+#define GCC_QSPI_AHB_CLK			74
+#define GCC_QSPI_SER_CLK			75
+#define GCC_SDCC1_AHB_CLK			76
+#define GCC_SDCC1_APPS_CLK			77
+#define GCC_SDCC1_ICE_CORE_CLK			78
+#define GCC_SDCC2_AHB_CLK			79
+#define GCC_SDCC2_APPS_CLK			80
+#define GCC_UFS_AHB_CLK				81
+#define GCC_UFS_AXI_CLK				82
+#define GCC_UFS_CLKREF_CLK			83
+#define GCC_UFS_ICE_CORE_CLK			84
+#define GCC_UFS_PHY_AUX_CLK			85
+#define GCC_UFS_RX_SYMBOL_0_CLK			86
+#define GCC_UFS_RX_SYMBOL_1_CLK			87
+#define GCC_UFS_TX_SYMBOL_0_CLK			88
+#define GCC_UFS_UNIPRO_CORE_CLK			89
+#define GCC_USB20_MASTER_CLK			90
+#define GCC_USB20_MOCK_UTMI_CLK			91
+#define GCC_USB20_SLEEP_CLK			92
+#define GCC_USB30_MASTER_CLK			93
+#define GCC_USB30_MOCK_UTMI_CLK			94
+#define GCC_USB30_SLEEP_CLK			95
+#define GCC_USB3_CLKREF_CLK			96
+#define GCC_USB3_PHY_AUX_CLK			97
+#define GCC_USB3_PHY_PIPE_CLK			98
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK		99
+#define GP1_CLK_SRC				100
+#define GP2_CLK_SRC				101
+#define GP3_CLK_SRC				102
+#define GPLL0					103
+#define GPLL0_EARLY				104
+#define GPLL1					105
+#define GPLL1_EARLY				106
+#define GPLL4					107
+#define GPLL4_EARLY				108
+#define HMSS_GPLL0_CLK_SRC			109
+#define HMSS_GPLL4_CLK_SRC			110
+#define HMSS_RBCPR_CLK_SRC			111
+#define PDM2_CLK_SRC				112
+#define QSPI_SER_CLK_SRC			113
+#define SDCC1_APPS_CLK_SRC			114
+#define SDCC1_ICE_CORE_CLK_SRC			115
+#define SDCC2_APPS_CLK_SRC			116
+#define UFS_AXI_CLK_SRC				117
+#define UFS_ICE_CORE_CLK_SRC			118
+#define UFS_PHY_AUX_CLK_SRC			119
+#define UFS_UNIPRO_CORE_CLK_SRC			120
+#define USB20_MASTER_CLK_SRC			121
+#define USB20_MOCK_UTMI_CLK_SRC			122
+#define USB30_MASTER_CLK_SRC			123
+#define USB30_MOCK_UTMI_CLK_SRC			124
+#define USB3_PHY_AUX_CLK_SRC			125
+#define GPLL0_OUT_MSSCC				126
+#define GCC_UFS_AXI_HW_CTL_CLK			127
+#define GCC_UFS_ICE_CORE_HW_CTL_CLK		128
+#define GCC_UFS_PHY_AUX_HW_CTL_CLK		129
+#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		130
+#define GCC_RX0_USB2_CLKREF_CLK			131
+#define GCC_RX1_USB2_CLKREF_CLK			132
+
+#define PCIE_0_GDSC	0
+#define UFS_GDSC	1
+#define USB_30_GDSC	2
+
+#define GCC_QUSB2PHY_PRIM_BCR		0
+#define GCC_QUSB2PHY_SEC_BCR		1
+#define GCC_UFS_BCR			2
+#define GCC_USB3_DP_PHY_BCR		3
+#define GCC_USB3_PHY_BCR		4
+#define GCC_USB3PHY_PHY_BCR		5
+#define GCC_USB_20_BCR                  6
+#define GCC_USB_30_BCR			7
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR	8
+
+#endif
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* [PATCH v3] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
                     ` (3 preceding siblings ...)
  2018-09-25 16:35   ` [PATCH v2] " Craig Tatlor
@ 2018-09-25 17:35   ` Craig Tatlor
  2018-09-27 19:51     ` Rob Herring
                       ` (2 more replies)
  4 siblings, 3 replies; 60+ messages in thread
From: Craig Tatlor @ 2018-09-25 17:35 UTC (permalink / raw)
  Cc: ctatlor97, linux-arm-msm, Taniya Das, Michael Turquette,
	Stephen Boyd, Rob Herring, Mark Rutland, Andy Gross, David Brown,
	linux-clk, devicetree, linux-kernel, linux-soc

From: Taniya Das <tdas@codeaurora.org>

Add support for the global clock controller found on SDM660
based devices. This should allow most non-multimedia device
drivers to probe and control their clocks.
Based on CAF implementation.

Signed-off-by: Taniya Das <tdas@codeaurora.org>
[craig: rename parents to fit upstream, and other cleanups]
Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
---
Changes from V1:
    Change authorship
    Add sdm630 compatible
 .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
 drivers/clk/qcom/Kconfig                      |    9 +
 drivers/clk/qcom/Makefile                     |    1 +
 drivers/clk/qcom/gcc-sdm660.c                 | 2480 +++++++++++++++++
 include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
 5 files changed, 2650 insertions(+)
 create mode 100644 drivers/clk/qcom/gcc-sdm660.c
 create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 664ea1fd6c76..e498ad2e8db8 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -38,6 +38,8 @@ Required properties :
 			"qcom,gcc-msm8996"
 			"qcom,gcc-msm8998"
 			"qcom,gcc-mdm9615"
+			"qcom,gcc-sdm630"
+			"qcom,gcc-sdm660"
 			"qcom,gcc-sdm845"
 
 - reg : shall contain base register location and length
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 5b181b182f40..4d478b261dfe 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -243,6 +243,15 @@ config SDM_CAMCC_845
 	  Support for the camera clock controller on SDM845 devices.
 	  Say Y if you want to support camera devices and camera functionality.
 
+config SDM_GCC_660
+	tristate "SDM660 Global Clock Controller"
+	select QCOM_GDSC
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the global clock controller on SDM660 devices.
+	  Say Y if you want to use peripheral devices such as UART, SPI,
+	  i2C, USB, UFS, SDDC, PCIe, etc.
+
 config SDM_GCC_845
 	tristate "SDM845 Global Clock Controller"
 	select QCOM_GDSC
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 935f142bc155..ab892f6d847c 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
 obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
 obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
 obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
+obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
 obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
 obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
 obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
new file mode 100644
index 000000000000..641bba611b5f
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -0,0 +1,2480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#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,gcc-sdm660.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "gdsc.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+
+enum {
+	P_XO,
+	P_SLEEP_CLK,
+	P_GPLL0,
+	P_GPLL1,
+	P_GPLL4,
+	P_GPLL0_EARLY_DIV,
+	P_GPLL1_EARLY_DIV,
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0[] = {
+	"xo",
+	"gpll0",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"sleep_clk",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
+	{ P_XO, 0 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const char * const gcc_parent_names_xo_sleep_clk[] = {
+	"xo",
+	"sleep_clk",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll4[] = {
+	"xo",
+	"gpll4",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 3 },
+	{ P_GPLL1, 4 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL1_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll1",
+	"gpll4",
+	"gpll1_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL4, 5 },
+	{ P_GPLL0_EARLY_DIV, 6 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
+	"xo",
+	"gpll0",
+	"gpll4",
+	"gpll0_early_div",
+};
+
+static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
+	{ P_XO, 0 },
+	{ P_GPLL0, 1 },
+	{ P_GPLL0_EARLY_DIV, 2 },
+	{ P_GPLL4, 5 },
+};
+
+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
+	"xo",
+	"gpll0",
+	"gpll0_early_div",
+	"gpll4",
+};
+
+static struct clk_fixed_factor xo = {
+	.mult = 1,
+	.div = 1,
+	.hw.init = &(struct clk_init_data){
+		.name = "xo",
+		.parent_names = (const char *[]){ "xo_board" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll0_early = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll0_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll0_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll0_early_div",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+	.offset = 0x00000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll0",
+		.parent_names = (const char *[]){ "gpll0_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll1_early = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll1_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_fixed_factor gpll1_early_div = {
+	.mult = 1,
+	.div = 2,
+	.hw.init = &(struct clk_init_data){
+		.name = "gpll1_early_div",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll1 = {
+	.offset = 0x1000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gpll1",
+		.parent_names = (const char *[]){ "gpll1_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static struct clk_alpha_pll gpll4_early = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll4_early",
+			.parent_names = (const char *[]){ "xo" },
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll_postdiv gpll4 = {
+	.offset = 0x77000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+	.clkr.hw.init = &(struct clk_init_data)
+	{
+		.name = "gpll4",
+		.parent_names = (const char *[]) { "gpll4_early" },
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x19020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
+	F(960000, P_XO, 10, 1, 2),
+	F(4800000, P_XO, 4, 0, 0),
+	F(9600000, P_XO, 2, 0, 0),
+	F(15000000, P_GPLL0, 10, 1, 4),
+	F(19200000, P_XO, 1, 0, 0),
+	F(25000000, P_GPLL0, 12, 1, 2),
+	F(50000000, P_GPLL0, 12, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1900c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1b020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1b00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1d020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1d00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x1f020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x1f00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
+	F(3686400, P_GPLL0, 1, 96, 15625),
+	F(7372800, P_GPLL0, 1, 192, 15625),
+	F(14745600, P_GPLL0, 1, 384, 15625),
+	F(16000000, P_GPLL0, 5, 2, 15),
+	F(19200000, P_XO, 1, 0, 0),
+	F(24000000, P_GPLL0, 5, 1, 5),
+	F(32000000, P_GPLL0, 1, 4, 75),
+	F(40000000, P_GPLL0, 15, 0, 0),
+	F(46400000, P_GPLL0, 1, 29, 375),
+	F(48000000, P_GPLL0, 12.5, 0, 0),
+	F(51200000, P_GPLL0, 1, 32, 375),
+	F(56000000, P_GPLL0, 1, 7, 75),
+	F(58982400, P_GPLL0, 1, 1536, 15625),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(63157895, P_GPLL0, 9.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x1a00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x1c00c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp1_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x26020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2600c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup1_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x28020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2800c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup2_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2a020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2a00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup3_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr = 0x2c020,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_i2c_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr = 0x2c00c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_qup4_spi_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr = 0x2700c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr = 0x2900c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "blsp2_uart2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gp1_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+	.cmd_rcgr = 0x64004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp1_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+	.cmd_rcgr = 0x65004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+	.cmd_rcgr = 0x66004,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
+	.freq_tbl = ftbl_gp1_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gp3_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+	F(300000000, P_GPLL0, 2, 0, 0),
+	F(600000000, P_GPLL0, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll0_clk_src = {
+	.cmd_rcgr = 0x4805c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_gpll0_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll0_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
+	F(384000000, P_GPLL4, 4, 0, 0),
+	F(768000000, P_GPLL4, 2, 0, 0),
+	F(1536000000, P_GPLL4, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_gpll4_clk_src = {
+	.cmd_rcgr = 0x48074,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll4,
+	.freq_tbl = ftbl_hmss_gpll4_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_gpll4_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll4,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 hmss_rbcpr_clk_src = {
+	.cmd_rcgr = 0x48044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "hmss_rbcpr_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+	.cmd_rcgr = 0x33010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_pdm2_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "pdm2_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
+	F(160400000, P_GPLL1, 5, 0, 0),
+	F(267333333, P_GPLL1, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 qspi_ser_clk_src = {
+	.cmd_rcgr = 0x4d00c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+	.freq_tbl = ftbl_qspi_ser_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "qspi_ser_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
+		.num_parents = 6,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(384000000, P_GPLL4, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+	.cmd_rcgr = 0x1602c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
+	.cmd_rcgr = 0x16010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc1_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
+	F(144000, P_XO, 16, 3, 25),
+	F(400000, P_XO, 12, 1, 4),
+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(192000000, P_GPLL4, 8, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+	.cmd_rcgr = 0x14010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "sdcc2_apps_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
+		.num_parents = 4,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
+	F(100000000, P_GPLL0, 6, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_axi_clk_src = {
+	.cmd_rcgr = 0x75018,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_axi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_axi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(300000000, P_GPLL0, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_ice_core_clk_src = {
+	.cmd_rcgr = 0x76010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_ice_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_ice_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_rcg2 ufs_phy_aux_clk_src = {
+	.cmd_rcgr = 0x76044,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
+	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
+	F(75000000, P_GPLL0, 8, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ufs_unipro_core_clk_src = {
+	.cmd_rcgr = 0x76028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "ufs_unipro_core_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_master_clk_src = {
+	.cmd_rcgr = 0x2f010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x2f024,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb20_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
+	F(120000000, P_GPLL0, 5, 0, 0),
+	F(133333333, P_GPLL0, 4.5, 0, 0),
+	F(150000000, P_GPLL0, 4, 0, 0),
+	F(200000000, P_GPLL0, 3, 0, 0),
+	F(240000000, P_GPLL0, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_master_clk_src = {
+	.cmd_rcgr = 0xf014,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_master_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_master_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
+	F(19200000, P_XO, 1, 0, 0),
+	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
+	F(60000000, P_GPLL0, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
+	.cmd_rcgr = 0xf028,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb30_mock_utmi_clk_src",
+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
+		.num_parents = 3,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
+	F(1200000, P_XO, 16, 0, 0),
+	F(19200000, P_XO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 usb3_phy_aux_clk_src = {
+	.cmd_rcgr = 0x5000c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_xo_sleep_clk,
+	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "usb3_phy_aux_clk_src",
+		.parent_names = gcc_parent_names_xo_sleep_clk,
+		.num_parents = 2,
+		.ops = &clk_rcg2_ops,
+	},
+};
+
+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
+	.halt_reg = 0x75034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75034,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
+	.halt_reg = 0xf03c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_aggre2_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_gfx_clk = {
+	.halt_reg = 0x7106c,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x7106c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_hmss_axi_clk = {
+	.halt_reg = 0x48004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(22),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_hmss_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
+	.halt_reg = 0x4401c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4401c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_bimc_mss_q6_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+	.halt_reg = 0x17004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(17),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+	.halt_reg = 0x19008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+	.halt_reg = 0x19004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+	.halt_reg = 0x1b008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+	.halt_reg = 0x1b004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1b004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+	.halt_reg = 0x1d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+	.halt_reg = 0x1d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+	.halt_reg = 0x1f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+	.halt_reg = 0x1f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+	.halt_reg = 0x1a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+	.halt_reg = 0x1c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp1_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp1_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_ahb_clk = {
+	.halt_reg = 0x25004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(15),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
+	.halt_reg = 0x26008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
+	.halt_reg = 0x26004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup1_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup1_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
+	.halt_reg = 0x28008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
+	.halt_reg = 0x28004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x28004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup2_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup2_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
+	.halt_reg = 0x2a008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
+	.halt_reg = 0x2a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup3_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup3_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
+	.halt_reg = 0x2c008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_i2c_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_i2c_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
+	.halt_reg = 0x2c004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_qup4_spi_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_qup4_spi_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart1_apps_clk = {
+	.halt_reg = 0x27004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x27004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart1_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_blsp2_uart2_apps_clk = {
+	.halt_reg = 0x29004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x29004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_blsp2_uart2_apps_clk",
+			.parent_names = (const char *[]){
+				"blsp2_uart2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+	.halt_reg = 0x38004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(10),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_boot_rom_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_axi_clk = {
+	.halt_reg = 0x5058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5058,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb2_axi_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_axi_clk = {
+	.halt_reg = 0x5018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_cfg_noc_usb3_axi_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_dcc_ahb_clk = {
+	.halt_reg = 0x84004,
+	.clkr = {
+		.enable_reg = 0x84004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_dcc_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp1_clk = {
+	.halt_reg = 0x64000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x64000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp1_clk",
+			.parent_names = (const char *[]){
+				"gp1_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp2_clk = {
+	.halt_reg = 0x65000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x65000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp2_clk",
+			.parent_names = (const char *[]){
+				"gp2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp3_clk = {
+	.halt_reg = 0x66000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x66000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gp3_clk",
+			.parent_names = (const char *[]){
+				"gp3_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_bimc_gfx_clk = {
+	.halt_reg = 0x71010,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_bimc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+	.halt_reg = 0x71004,
+	.halt_check = BRANCH_VOTED,
+	.clkr = {
+		.enable_reg = 0x71004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(4),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(3),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_gpu_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_dvm_bus_clk = {
+	.halt_reg = 0x4808c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4808c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_dvm_bus_clk",
+			.ops = &clk_branch2_ops,
+			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+};
+
+static struct clk_branch gcc_hmss_rbcpr_clk = {
+	.halt_reg = 0x48008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x48008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_hmss_rbcpr_clk",
+			.parent_names = (const char *[]){
+				"hmss_rbcpr_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(1),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_clk",
+			.parent_names = (const char *[]){
+				"gpll0",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+	.halt_reg = 0x5200c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x5200c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_gpll0_div_clk",
+			.parent_names = (const char *[]){
+				"gpll0_early_div",
+			},
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = {
+	.halt_reg = 0x9004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_noc_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmss_sys_noc_axi_clk = {
+	.halt_reg = 0x9000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x9000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mmss_sys_noc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+	.halt_reg = 0x8a000,
+	.clkr = {
+		.enable_reg = 0x8a000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+	.halt_reg = 0x8a004,
+	.clkr = {
+		.enable_reg = 0x8a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_mnoc_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+	.halt_reg = 0x8a040,
+	.clkr = {
+		.enable_reg = 0x8a040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_q6_bimc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+	.halt_reg = 0x8a03c,
+	.clkr = {
+		.enable_reg = 0x8a03c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_mss_snoc_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+	.halt_reg = 0x3300c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x3300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm2_clk",
+			.parent_names = (const char *[]){
+				"pdm2_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+	.halt_reg = 0x33004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x33004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pdm_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+	.halt_reg = 0x34004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x52004,
+		.enable_mask = BIT(13),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_prng_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ahb_clk = {
+	.halt_reg = 0x4d004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qspi_ser_clk = {
+	.halt_reg = 0x4d008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x4d008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_qspi_ser_clk",
+			.parent_names = (const char *[]){
+				"qspi_ser_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx0_usb2_clkref_clk = {
+	.halt_reg = 0x88018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88018,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx0_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_rx1_usb2_clkref_clk = {
+	.halt_reg = 0x88014,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x88014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_rx1_usb2_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+	.halt_reg = 0x16008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+	.halt_reg = 0x16004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x16004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+	.halt_reg = 0x1600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ice_core_clk",
+			.parent_names = (const char *[]){
+				"sdcc1_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+	.halt_reg = 0x14008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+	.halt_reg = 0x14004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x14004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc2_apps_clk",
+			.parent_names = (const char *[]){
+				"sdcc2_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ahb_clk = {
+	.halt_reg = 0x7500c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7500c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_axi_clk = {
+	.halt_reg = 0x75008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x75008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_axi_clk",
+			.parent_names = (const char *[]){
+				"ufs_axi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_clkref_clk = {
+	.halt_reg = 0x88008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x88008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_ice_core_clk = {
+	.halt_reg = 0x7600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x7600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_ice_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_phy_aux_clk = {
+	.halt_reg = 0x76040,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76040,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"ufs_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
+	.halt_reg = 0x75014,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75014,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
+	.halt_reg = 0x7605c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x7605c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_rx_symbol_1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
+	.halt_reg = 0x75010,
+	.halt_check = BRANCH_HALT_SKIP,
+	.clkr = {
+		.enable_reg = 0x75010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_tx_symbol_0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_ufs_unipro_core_clk = {
+	.halt_reg = 0x76008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x76008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_ufs_unipro_core_clk",
+			.parent_names = (const char *[]){
+				"ufs_unipro_core_clk_src",
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+	.halt_reg = 0x2f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_master_clk",
+			.parent_names = (const char *[]){
+				"usb20_master_clk_src"
+			},
+			.flags = CLK_SET_RATE_PARENT,
+			.num_parents = 1,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+	.halt_reg = 0x2f00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb20_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+	.halt_reg = 0x2f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb20_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_master_clk = {
+	.halt_reg = 0xf008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_master_clk",
+			.parent_names = (const char *[]){
+				"usb30_master_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_mock_utmi_clk = {
+	.halt_reg = 0xf010,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf010,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_mock_utmi_clk",
+			.parent_names = (const char *[]){
+				"usb30_mock_utmi_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb30_sleep_clk = {
+	.halt_reg = 0xf00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0xf00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb30_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_clkref_clk = {
+	.halt_reg = 0x8800c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x8800c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_aux_clk = {
+	.halt_reg = 0x50000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x50000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_aux_clk",
+			.parent_names = (const char *[]){
+				"usb3_phy_aux_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_phy_pipe_clk = {
+	.halt_reg = 0x50004,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x50004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_phy_pipe_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = {
+	.halt_reg = 0x6a004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x6a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb_phy_cfg_ahb2phy_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc ufs_gdsc = {
+	.gdscr = 0x75004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "ufs_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc usb_30_gdsc = {
+	.gdscr = 0xf004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "usb_30_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct gdsc pcie_0_gdsc = {
+	.gdscr = 0x6b004,
+	.gds_hw_ctrl = 0x0,
+	.pd = {
+		.name = "pcie_0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = VOTABLE,
+};
+
+static struct clk_hw *gcc_sdm660_hws[] = {
+	[GCC_XO] = &xo.hw,
+	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
+	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,
+};
+
+static struct clk_regmap *gcc_660_clocks[] = {
+	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+	[BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+	[BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+	[BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+	[BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+	[BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+	[BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr,
+	[BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr,
+	[BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr,
+	[BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr,
+	[BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr,
+	[BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr,
+	[BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr,
+	[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
+	[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
+	[GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr,
+	[GCC_BIMC_HMSS_AXI_CLK] = &gcc_bimc_hmss_axi_clk.clkr,
+	[GCC_BIMC_MSS_Q6_AXI_CLK] = &gcc_bimc_mss_q6_axi_clk.clkr,
+	[GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+	[GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+	[GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+	[GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr,
+	[GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr,
+	[GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr,
+	[GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr,
+	[GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr,
+	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+	[GCC_CFG_NOC_USB2_AXI_CLK] = &gcc_cfg_noc_usb2_axi_clk.clkr,
+	[GCC_CFG_NOC_USB3_AXI_CLK] = &gcc_cfg_noc_usb3_axi_clk.clkr,
+	[GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+	[GCC_GPU_BIMC_GFX_CLK] = &gcc_gpu_bimc_gfx_clk.clkr,
+	[GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+	[GCC_GPU_GPLL0_CLK] = &gcc_gpu_gpll0_clk.clkr,
+	[GCC_GPU_GPLL0_DIV_CLK] = &gcc_gpu_gpll0_div_clk.clkr,
+	[GCC_HMSS_DVM_BUS_CLK] = &gcc_hmss_dvm_bus_clk.clkr,
+	[GCC_HMSS_RBCPR_CLK] = &gcc_hmss_rbcpr_clk.clkr,
+	[GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
+	[GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+	[GCC_MMSS_NOC_CFG_AHB_CLK] = &gcc_mmss_noc_cfg_ahb_clk.clkr,
+	[GCC_MMSS_SYS_NOC_AXI_CLK] = &gcc_mmss_sys_noc_axi_clk.clkr,
+	[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+	[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+	[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+	[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+	[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+	[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
+	[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
+	[GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
+	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+	[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+	[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+	[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+	[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
+	[GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr,
+	[GCC_UFS_CLKREF_CLK] = &gcc_ufs_clkref_clk.clkr,
+	[GCC_UFS_ICE_CORE_CLK] = &gcc_ufs_ice_core_clk.clkr,
+	[GCC_UFS_PHY_AUX_CLK] = &gcc_ufs_phy_aux_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
+	[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
+	[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
+	[GCC_UFS_UNIPRO_CORE_CLK] = &gcc_ufs_unipro_core_clk.clkr,
+	[GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+	[GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+	[GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+	[GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr,
+	[GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr,
+	[GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr,
+	[GCC_USB3_CLKREF_CLK] = &gcc_usb3_clkref_clk.clkr,
+	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
+	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
+	[GP1_CLK_SRC] = &gp1_clk_src.clkr,
+	[GP2_CLK_SRC] = &gp2_clk_src.clkr,
+	[GP3_CLK_SRC] = &gp3_clk_src.clkr,
+	[GPLL0] = &gpll0.clkr,
+	[GPLL0_EARLY] = &gpll0_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL1_EARLY] = &gpll1_early.clkr,
+	[GPLL1] = &gpll1.clkr,
+	[GPLL4_EARLY] = &gpll4_early.clkr,
+	[GPLL4] = &gpll4.clkr,
+	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
+	[HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
+	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
+	[PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+	[QSPI_SER_CLK_SRC] = &qspi_ser_clk_src.clkr,
+	[SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+	[SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr,
+	[SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+	[UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
+	[UFS_ICE_CORE_CLK_SRC] = &ufs_ice_core_clk_src.clkr,
+	[UFS_PHY_AUX_CLK_SRC] = &ufs_phy_aux_clk_src.clkr,
+	[UFS_UNIPRO_CORE_CLK_SRC] = &ufs_unipro_core_clk_src.clkr,
+	[USB20_MASTER_CLK_SRC] = &usb20_master_clk_src.clkr,
+	[USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr,
+	[USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
+	[USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr,
+	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
+};
+
+static struct gdsc *gcc_660_gdscs[] = {
+	[UFS_GDSC] = &ufs_gdsc,
+	[USB_30_GDSC] = &usb_30_gdsc,
+	[PCIE_0_GDSC] = &pcie_0_gdsc,
+};
+
+static const struct qcom_reset_map gcc_660_resets[] = {
+	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+	[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+	[GCC_UFS_BCR] = { 0x75000 },
+	[GCC_USB3_DP_PHY_BCR] = { 0x50028 },
+	[GCC_USB3_PHY_BCR] = { 0x50020 },
+	[GCC_USB3PHY_PHY_BCR] = { 0x50024 },
+	[GCC_USB_20_BCR] = { 0x2f000 },
+	[GCC_USB_30_BCR] = { 0xf000 },
+	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+};
+
+static const struct regmap_config gcc_660_regmap_config = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register	= 0x94000,
+	.fast_io	= true,
+};
+
+static const struct qcom_cc_desc gcc_660_desc = {
+	.config = &gcc_660_regmap_config,
+	.clks = gcc_660_clocks,
+	.num_clks = ARRAY_SIZE(gcc_660_clocks),
+	.resets = gcc_660_resets,
+	.num_resets = ARRAY_SIZE(gcc_660_resets),
+	.gdscs = gcc_660_gdscs,
+	.num_gdscs = ARRAY_SIZE(gcc_660_gdscs),
+};
+
+static const struct of_device_id gcc_660_match_table[] = {
+	{ .compatible = "qcom,gcc-sdm630" },
+	{ .compatible = "qcom,gcc-sdm660" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_660_match_table);
+
+static int gcc_660_probe(struct platform_device *pdev)
+{
+	int i, ret = 0;
+	struct regmap *regmap;
+
+	regmap = qcom_cc_map(pdev, &gcc_660_desc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	/*
+	 * Set the HMSS_AHB_CLK_SLEEP_ENA bit to allow the hmss_ahb_clk to be
+	 * turned off by hardware during certain apps low power modes.
+	 */
+	ret = regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21));
+	if (ret)
+		return ret;
+
+	/* Register the hws */
+	for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) {
+		ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]);
+		if (ret)
+			return ret;
+	}
+
+	return qcom_cc_really_probe(pdev, &gcc_660_desc, regmap);
+}
+
+static struct platform_driver gcc_660_driver = {
+	.probe		= gcc_660_probe,
+	.driver		= {
+		.name	= "gcc-sdm660",
+		.of_match_table = gcc_660_match_table,
+	},
+};
+
+static int __init gcc_660_init(void)
+{
+	return platform_driver_register(&gcc_660_driver);
+}
+core_initcall_sync(gcc_660_init);
+
+static void __exit gcc_660_exit(void)
+{
+	platform_driver_unregister(&gcc_660_driver);
+}
+module_exit(gcc_660_exit);
+
+MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
new file mode 100644
index 000000000000..76aabcc5e7e3
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, Craig Tatlor.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_660_H
+#define _DT_BINDINGS_CLK_MSM_GCC_660_H
+
+#define GCC_XO					0
+#define GCC_GPLL0_EARLY_DIV			1
+#define GCC_GPLL1_EARLY_DIV			2
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC		3
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC		4
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC		5
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC		6
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC		7
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC		8
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC		9
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC		10
+#define BLSP1_UART1_APPS_CLK_SRC		11
+#define BLSP1_UART2_APPS_CLK_SRC		12
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC		13
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC		14
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC		15
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC		16
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC		17
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC		18
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC		19
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC		20
+#define BLSP2_UART1_APPS_CLK_SRC		21
+#define BLSP2_UART2_APPS_CLK_SRC		22
+#define GCC_AGGRE2_UFS_AXI_CLK			23
+#define GCC_AGGRE2_USB3_AXI_CLK			24
+#define GCC_BIMC_GFX_CLK			25
+#define GCC_BIMC_HMSS_AXI_CLK			26
+#define GCC_BIMC_MSS_Q6_AXI_CLK			27
+#define GCC_BLSP1_AHB_CLK			28
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK		29
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK		30
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK		31
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK		32
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK		33
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK		34
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK		35
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK		36
+#define GCC_BLSP1_UART1_APPS_CLK		37
+#define GCC_BLSP1_UART2_APPS_CLK		38
+#define GCC_BLSP2_AHB_CLK			39
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK		40
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK		41
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK		42
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK		43
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK		44
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK		46
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK		45
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK		46
+#define GCC_BLSP2_UART1_APPS_CLK		47
+#define GCC_BLSP2_UART2_APPS_CLK		48
+#define GCC_BOOT_ROM_AHB_CLK			49
+#define GCC_CFG_NOC_USB2_AXI_CLK		50
+#define GCC_CFG_NOC_USB3_AXI_CLK		51
+#define GCC_DCC_AHB_CLK				52
+#define GCC_GP1_CLK				53
+#define GCC_GP2_CLK				54
+#define GCC_GP3_CLK				55
+#define GCC_GPU_BIMC_GFX_CLK			56
+#define GCC_GPU_CFG_AHB_CLK			57
+#define GCC_GPU_GPLL0_CLK			58
+#define GCC_GPU_GPLL0_DIV_CLK			59
+#define GCC_HMSS_DVM_BUS_CLK			60
+#define GCC_HMSS_RBCPR_CLK			61
+#define GCC_MMSS_GPLL0_CLK			62
+#define GCC_MMSS_GPLL0_DIV_CLK			63
+#define GCC_MMSS_NOC_CFG_AHB_CLK		64
+#define GCC_MMSS_SYS_NOC_AXI_CLK		65
+#define GCC_MSS_CFG_AHB_CLK			66
+#define GCC_MSS_GPLL0_DIV_CLK			67
+#define GCC_MSS_MNOC_BIMC_AXI_CLK		68
+#define GCC_MSS_Q6_BIMC_AXI_CLK			69
+#define GCC_MSS_SNOC_AXI_CLK			70
+#define GCC_PDM2_CLK				71
+#define GCC_PDM_AHB_CLK				72
+#define GCC_PRNG_AHB_CLK			73
+#define GCC_QSPI_AHB_CLK			74
+#define GCC_QSPI_SER_CLK			75
+#define GCC_SDCC1_AHB_CLK			76
+#define GCC_SDCC1_APPS_CLK			77
+#define GCC_SDCC1_ICE_CORE_CLK			78
+#define GCC_SDCC2_AHB_CLK			79
+#define GCC_SDCC2_APPS_CLK			80
+#define GCC_UFS_AHB_CLK				81
+#define GCC_UFS_AXI_CLK				82
+#define GCC_UFS_CLKREF_CLK			83
+#define GCC_UFS_ICE_CORE_CLK			84
+#define GCC_UFS_PHY_AUX_CLK			85
+#define GCC_UFS_RX_SYMBOL_0_CLK			86
+#define GCC_UFS_RX_SYMBOL_1_CLK			87
+#define GCC_UFS_TX_SYMBOL_0_CLK			88
+#define GCC_UFS_UNIPRO_CORE_CLK			89
+#define GCC_USB20_MASTER_CLK			90
+#define GCC_USB20_MOCK_UTMI_CLK			91
+#define GCC_USB20_SLEEP_CLK			92
+#define GCC_USB30_MASTER_CLK			93
+#define GCC_USB30_MOCK_UTMI_CLK			94
+#define GCC_USB30_SLEEP_CLK			95
+#define GCC_USB3_CLKREF_CLK			96
+#define GCC_USB3_PHY_AUX_CLK			97
+#define GCC_USB3_PHY_PIPE_CLK			98
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK		99
+#define GP1_CLK_SRC				100
+#define GP2_CLK_SRC				101
+#define GP3_CLK_SRC				102
+#define GPLL0					103
+#define GPLL0_EARLY				104
+#define GPLL1					105
+#define GPLL1_EARLY				106
+#define GPLL4					107
+#define GPLL4_EARLY				108
+#define HMSS_GPLL0_CLK_SRC			109
+#define HMSS_GPLL4_CLK_SRC			110
+#define HMSS_RBCPR_CLK_SRC			111
+#define PDM2_CLK_SRC				112
+#define QSPI_SER_CLK_SRC			113
+#define SDCC1_APPS_CLK_SRC			114
+#define SDCC1_ICE_CORE_CLK_SRC			115
+#define SDCC2_APPS_CLK_SRC			116
+#define UFS_AXI_CLK_SRC				117
+#define UFS_ICE_CORE_CLK_SRC			118
+#define UFS_PHY_AUX_CLK_SRC			119
+#define UFS_UNIPRO_CORE_CLK_SRC			120
+#define USB20_MASTER_CLK_SRC			121
+#define USB20_MOCK_UTMI_CLK_SRC			122
+#define USB30_MASTER_CLK_SRC			123
+#define USB30_MOCK_UTMI_CLK_SRC			124
+#define USB3_PHY_AUX_CLK_SRC			125
+#define GPLL0_OUT_MSSCC				126
+#define GCC_UFS_AXI_HW_CTL_CLK			127
+#define GCC_UFS_ICE_CORE_HW_CTL_CLK		128
+#define GCC_UFS_PHY_AUX_HW_CTL_CLK		129
+#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		130
+#define GCC_RX0_USB2_CLKREF_CLK			131
+#define GCC_RX1_USB2_CLKREF_CLK			132
+
+#define PCIE_0_GDSC	0
+#define UFS_GDSC	1
+#define USB_30_GDSC	2
+
+#define GCC_QUSB2PHY_PRIM_BCR		0
+#define GCC_QUSB2PHY_SEC_BCR		1
+#define GCC_UFS_BCR			2
+#define GCC_USB3_DP_PHY_BCR		3
+#define GCC_USB3_PHY_BCR		4
+#define GCC_USB3PHY_PHY_BCR		5
+#define GCC_USB_20_BCR                  6
+#define GCC_USB_30_BCR			7
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR	8
+
+#endif
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 60+ messages in thread

* Re: [PATCH v3] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
@ 2018-09-27 19:51     ` Rob Herring
  2018-10-08  6:51     ` Craig
  2018-10-16 22:05     ` Stephen Boyd
  2 siblings, 0 replies; 60+ messages in thread
From: Rob Herring @ 2018-09-27 19:51 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: linux-arm-msm, Taniya Das, Michael Turquette, Stephen Boyd,
	Mark Rutland, Andy Gross, David Brown, linux-clk, devicetree,
	linux-kernel, linux-soc

On Tue, Sep 25, 2018 at 06:35:58PM +0100, Craig Tatlor wrote:
> From: Taniya Das <tdas@codeaurora.org>
> 
> Add support for the global clock controller found on SDM660
> based devices. This should allow most non-multimedia device
> drivers to probe and control their clocks.
> Based on CAF implementation.
> 
> Signed-off-by: Taniya Das <tdas@codeaurora.org>
> [craig: rename parents to fit upstream, and other cleanups]
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---
> Changes from V1:
>     Change authorship
>     Add sdm630 compatible
>  .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/qcom/Kconfig                      |    9 +
>  drivers/clk/qcom/Makefile                     |    1 +
>  drivers/clk/qcom/gcc-sdm660.c                 | 2480 +++++++++++++++++
>  include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
>  5 files changed, 2650 insertions(+)
>  create mode 100644 drivers/clk/qcom/gcc-sdm660.c
>  create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v3] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
  2018-09-27 19:51     ` Rob Herring
@ 2018-10-08  6:51     ` Craig
  2018-10-16 22:05     ` Stephen Boyd
  2 siblings, 0 replies; 60+ messages in thread
From: Craig @ 2018-10-08  6:51 UTC (permalink / raw)
  Cc: linux-arm-msm, Taniya Das, Michael Turquette, Stephen Boyd,
	Rob Herring, Mark Rutland, Andy Gross, David Brown, linux-clk,
	devicetree, linux-kernel, linux-soc

(Resend due to broken email client) any reviews for this?

On 25 September 2018 18:35:58 BST, Craig Tatlor <ctatlor97@gmail.com> wrote:
>From: Taniya Das <tdas@codeaurora.org>
>
>Add support for the global clock controller found on SDM660
>based devices. This should allow most non-multimedia device
>drivers to probe and control their clocks.
>Based on CAF implementation.
>
>Signed-off-by: Taniya Das <tdas@codeaurora.org>
>[craig: rename parents to fit upstream, and other cleanups]
>Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
>---
>Changes from V1:
>    Change authorship
>    Add sdm630 compatible
> .../devicetree/bindings/clock/qcom,gcc.txt    |    1 +
> drivers/clk/qcom/Kconfig                      |    9 +
> drivers/clk/qcom/Makefile                     |    1 +
> drivers/clk/qcom/gcc-sdm660.c                 | 2480 +++++++++++++++++
> include/dt-bindings/clock/qcom,gcc-sdm660.h   |  159 ++
> 5 files changed, 2650 insertions(+)
> create mode 100644 drivers/clk/qcom/gcc-sdm660.c
> create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h
>
>diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>index 664ea1fd6c76..e498ad2e8db8 100644
>--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
>@@ -38,6 +38,8 @@ Required properties :
> 			"qcom,gcc-msm8996"
> 			"qcom,gcc-msm8998"
> 			"qcom,gcc-mdm9615"
>+			"qcom,gcc-sdm630"
>+			"qcom,gcc-sdm660"
> 			"qcom,gcc-sdm845"
> 
> - reg : shall contain base register location and length
>diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
>index 5b181b182f40..4d478b261dfe 100644
>--- a/drivers/clk/qcom/Kconfig
>+++ b/drivers/clk/qcom/Kconfig
>@@ -243,6 +243,15 @@ config SDM_CAMCC_845
> 	  Support for the camera clock controller on SDM845 devices.
>	  Say Y if you want to support camera devices and camera
>functionality.
> 
>+config SDM_GCC_660
>+	tristate "SDM660 Global Clock Controller"
>+	select QCOM_GDSC
>+	depends on COMMON_CLK_QCOM
>+	help
>+	  Support for the global clock controller on SDM660 devices.
>+	  Say Y if you want to use peripheral devices such as UART, SPI,
>+	  i2C, USB, UFS, SDDC, PCIe, etc.
>+
> config SDM_GCC_845
> 	tristate "SDM845 Global Clock Controller"
> 	select QCOM_GDSC
>diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
>index 935f142bc155..ab892f6d847c 100644
>--- a/drivers/clk/qcom/Makefile
>+++ b/drivers/clk/qcom/Makefile
>@@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
> obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
> obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
> obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o
>+obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o
> obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
> obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
> obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
>diff --git a/drivers/clk/qcom/gcc-sdm660.c
>b/drivers/clk/qcom/gcc-sdm660.c
>new file mode 100644
>index 000000000000..641bba611b5f
>--- /dev/null
>+++ b/drivers/clk/qcom/gcc-sdm660.c
>@@ -0,0 +1,2480 @@
>+// SPDX-License-Identifier: GPL-2.0
>+/*
>+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
>+ * Copyright (c) 2018, Craig Tatlor.
>+ */
>+
>+#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,gcc-sdm660.h>
>+
>+#include "common.h"
>+#include "clk-regmap.h"
>+#include "clk-alpha-pll.h"
>+#include "clk-rcg.h"
>+#include "clk-branch.h"
>+#include "reset.h"
>+#include "gdsc.h"
>+
>+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
>+
>+enum {
>+	P_XO,
>+	P_SLEEP_CLK,
>+	P_GPLL0,
>+	P_GPLL1,
>+	P_GPLL4,
>+	P_GPLL0_EARLY_DIV,
>+	P_GPLL1_EARLY_DIV,
>+};
>+
>+static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+	{ P_GPLL0_EARLY_DIV, 6 },
>+};
>+
>+static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[]
>= {
>+	"xo",
>+	"gpll0",
>+	"gpll0_early_div",
>+};
>+
>+static const struct parent_map gcc_parent_map_xo_gpll0[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+};
>+
>+static const char * const gcc_parent_names_xo_gpll0[] = {
>+	"xo",
>+	"gpll0",
>+};
>+
>+static const struct parent_map
>gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+	{ P_SLEEP_CLK, 5 },
>+	{ P_GPLL0_EARLY_DIV, 6 },
>+};
>+
>+static const char * const
>gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = {
>+	"xo",
>+	"gpll0",
>+	"sleep_clk",
>+	"gpll0_early_div",
>+};
>+
>+static const struct parent_map gcc_parent_map_xo_sleep_clk[] = {
>+	{ P_XO, 0 },
>+	{ P_SLEEP_CLK, 5 },
>+};
>+
>+static const char * const gcc_parent_names_xo_sleep_clk[] = {
>+	"xo",
>+	"sleep_clk",
>+};
>+
>+static const struct parent_map gcc_parent_map_xo_gpll4[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL4, 5 },
>+};
>+
>+static const char * const gcc_parent_names_xo_gpll4[] = {
>+	"xo",
>+	"gpll4",
>+};
>+
>+static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[] =
>{
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+	{ P_GPLL0_EARLY_DIV, 3 },
>+	{ P_GPLL1, 4 },
>+	{ P_GPLL4, 5 },
>+	{ P_GPLL1_EARLY_DIV, 6 },
>+};
>+
>+static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div[]
>= {
>+	"xo",
>+	"gpll0",
>+	"gpll0_early_div",
>+	"gpll1",
>+	"gpll4",
>+	"gpll1_early_div",
>+};
>+
>+static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+	{ P_GPLL4, 5 },
>+	{ P_GPLL0_EARLY_DIV, 6 },
>+};
>+
>+static const char * const
>gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div[] = {
>+	"xo",
>+	"gpll0",
>+	"gpll4",
>+	"gpll0_early_div",
>+};
>+
>+static const struct parent_map
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4[] = {
>+	{ P_XO, 0 },
>+	{ P_GPLL0, 1 },
>+	{ P_GPLL0_EARLY_DIV, 2 },
>+	{ P_GPLL4, 5 },
>+};
>+
>+static const char * const
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4[] = {
>+	"xo",
>+	"gpll0",
>+	"gpll0_early_div",
>+	"gpll4",
>+};
>+
>+static struct clk_fixed_factor xo = {
>+	.mult = 1,
>+	.div = 1,
>+	.hw.init = &(struct clk_init_data){
>+		.name = "xo",
>+		.parent_names = (const char *[]){ "xo_board" },
>+		.num_parents = 1,
>+		.ops = &clk_fixed_factor_ops,
>+	},
>+};
>+
>+static struct clk_alpha_pll gpll0_early = {
>+	.offset = 0x0,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr = {
>+		.enable_reg = 0x52000,
>+		.enable_mask = BIT(0),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gpll0_early",
>+			.parent_names = (const char *[]){ "xo" },
>+			.num_parents = 1,
>+			.ops = &clk_alpha_pll_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_fixed_factor gpll0_early_div = {
>+	.mult = 1,
>+	.div = 2,
>+	.hw.init = &(struct clk_init_data){
>+		.name = "gpll0_early_div",
>+		.parent_names = (const char *[]){ "gpll0_early" },
>+		.num_parents = 1,
>+		.ops = &clk_fixed_factor_ops,
>+	},
>+};
>+
>+static struct clk_alpha_pll_postdiv gpll0 = {
>+	.offset = 0x00000,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "gpll0",
>+		.parent_names = (const char *[]){ "gpll0_early" },
>+		.num_parents = 1,
>+		.ops = &clk_alpha_pll_postdiv_ops,
>+	},
>+};
>+
>+static struct clk_alpha_pll gpll1_early = {
>+	.offset = 0x1000,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr = {
>+		.enable_reg = 0x52000,
>+		.enable_mask = BIT(1),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gpll1_early",
>+			.parent_names = (const char *[]){ "xo" },
>+			.num_parents = 1,
>+			.ops = &clk_alpha_pll_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_fixed_factor gpll1_early_div = {
>+	.mult = 1,
>+	.div = 2,
>+	.hw.init = &(struct clk_init_data){
>+		.name = "gpll1_early_div",
>+		.parent_names = (const char *[]){ "gpll1_early" },
>+		.num_parents = 1,
>+		.ops = &clk_fixed_factor_ops,
>+	},
>+};
>+
>+static struct clk_alpha_pll_postdiv gpll1 = {
>+	.offset = 0x1000,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "gpll1",
>+		.parent_names = (const char *[]){ "gpll1_early" },
>+		.num_parents = 1,
>+		.ops = &clk_alpha_pll_postdiv_ops,
>+	},
>+};
>+
>+static struct clk_alpha_pll gpll4_early = {
>+	.offset = 0x77000,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr = {
>+		.enable_reg = 0x52000,
>+		.enable_mask = BIT(4),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gpll4_early",
>+			.parent_names = (const char *[]){ "xo" },
>+			.num_parents = 1,
>+			.ops = &clk_alpha_pll_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_alpha_pll_postdiv gpll4 = {
>+	.offset = 0x77000,
>+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
>+	.clkr.hw.init = &(struct clk_init_data)
>+	{
>+		.name = "gpll4",
>+		.parent_names = (const char *[]) { "gpll4_early" },
>+		.num_parents = 1,
>+		.ops = &clk_alpha_pll_postdiv_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(50000000, P_GPLL0, 12, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x19020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup1_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_blsp1_qup1_spi_apps_clk_src[] = {
>+	F(960000, P_XO, 10, 1, 2),
>+	F(4800000, P_XO, 4, 0, 0),
>+	F(9600000, P_XO, 2, 0, 0),
>+	F(15000000, P_GPLL0, 10, 1, 4),
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(25000000, P_GPLL0, 12, 1, 2),
>+	F(50000000, P_GPLL0, 12, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x1900c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup1_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x1b020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup2_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x1b00c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup2_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x1d020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup3_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x1d00c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup3_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x1f020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup4_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x1f00c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_qup4_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_blsp1_uart1_apps_clk_src[] = {
>+	F(3686400, P_GPLL0, 1, 96, 15625),
>+	F(7372800, P_GPLL0, 1, 192, 15625),
>+	F(14745600, P_GPLL0, 1, 384, 15625),
>+	F(16000000, P_GPLL0, 5, 2, 15),
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(24000000, P_GPLL0, 5, 1, 5),
>+	F(32000000, P_GPLL0, 1, 4, 75),
>+	F(40000000, P_GPLL0, 15, 0, 0),
>+	F(46400000, P_GPLL0, 1, 29, 375),
>+	F(48000000, P_GPLL0, 12.5, 0, 0),
>+	F(51200000, P_GPLL0, 1, 32, 375),
>+	F(56000000, P_GPLL0, 1, 7, 75),
>+	F(58982400, P_GPLL0, 1, 1536, 15625),
>+	F(60000000, P_GPLL0, 10, 0, 0),
>+	F(63157895, P_GPLL0, 9.5, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
>+	.cmd_rcgr = 0x1a00c,
>+	.mnd_width = 16,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_uart1_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
>+	.cmd_rcgr = 0x1c00c,
>+	.mnd_width = 16,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp1_uart2_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x26020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup1_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x2600c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup1_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x28020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup2_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x2800c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup2_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x2a020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup3_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x2a00c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup3_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
>+	.cmd_rcgr = 0x2c020,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_i2c_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup4_i2c_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
>+	.cmd_rcgr = 0x2c00c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_qup4_spi_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
>+	.cmd_rcgr = 0x2700c,
>+	.mnd_width = 16,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_uart1_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
>+	.cmd_rcgr = 0x2900c,
>+	.mnd_width = 16,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_blsp1_uart1_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "blsp2_uart2_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_gp1_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(100000000, P_GPLL0, 6, 0, 0),
>+	F(200000000, P_GPLL0, 3, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 gp1_clk_src = {
>+	.cmd_rcgr = 0x64004,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>+	.freq_tbl = ftbl_gp1_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "gp1_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>+		.num_parents = 4,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 gp2_clk_src = {
>+	.cmd_rcgr = 0x65004,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>+	.freq_tbl = ftbl_gp1_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "gp2_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>+		.num_parents = 4,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 gp3_clk_src = {
>+	.cmd_rcgr = 0x66004,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div,
>+	.freq_tbl = ftbl_gp1_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "gp3_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div,
>+		.num_parents = 4,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
>+	F(300000000, P_GPLL0, 2, 0, 0),
>+	F(600000000, P_GPLL0, 1, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 hmss_gpll0_clk_src = {
>+	.cmd_rcgr = 0x4805c,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_hmss_gpll0_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "hmss_gpll0_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_hmss_gpll4_clk_src[] = {
>+	F(384000000, P_GPLL4, 4, 0, 0),
>+	F(768000000, P_GPLL4, 2, 0, 0),
>+	F(1536000000, P_GPLL4, 1, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 hmss_gpll4_clk_src = {
>+	.cmd_rcgr = 0x48074,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll4,
>+	.freq_tbl = ftbl_hmss_gpll4_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "hmss_gpll4_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll4,
>+		.num_parents = 2,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_hmss_rbcpr_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 hmss_rbcpr_clk_src = {
>+	.cmd_rcgr = 0x48044,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "hmss_rbcpr_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0,
>+		.num_parents = 2,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_pdm2_clk_src[] = {
>+	F(60000000, P_GPLL0, 10, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 pdm2_clk_src = {
>+	.cmd_rcgr = 0x33010,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_pdm2_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "pdm2_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_qspi_ser_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(80200000, P_GPLL1_EARLY_DIV, 5, 0, 0),
>+	F(160400000, P_GPLL1, 5, 0, 0),
>+	F(267333333, P_GPLL1, 3, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 qspi_ser_clk_src = {
>+	.cmd_rcgr = 0x4d00c,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map =
>gcc_parent_map_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>+	.freq_tbl = ftbl_qspi_ser_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "qspi_ser_clk_src",
>+		.parent_names =
>gcc_parent_names_xo_gpll0_gpll0_early_div_gpll1_gpll4_gpll1_early_div,
>+		.num_parents = 6,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = {
>+	F(144000, P_XO, 16, 3, 25),
>+	F(400000, P_XO, 12, 1, 4),
>+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>+	F(100000000, P_GPLL0, 6, 0, 0),
>+	F(192000000, P_GPLL4, 8, 0, 0),
>+	F(384000000, P_GPLL4, 4, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 sdcc1_apps_clk_src = {
>+	.cmd_rcgr = 0x1602c,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll4_gpll0_early_div,
>+	.freq_tbl = ftbl_sdcc1_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "sdcc1_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll4_gpll0_early_div,
>+		.num_parents = 4,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = {
>+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>+	F(150000000, P_GPLL0, 4, 0, 0),
>+	F(200000000, P_GPLL0, 3, 0, 0),
>+	F(300000000, P_GPLL0, 2, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 sdcc1_ice_core_clk_src = {
>+	.cmd_rcgr = 0x16010,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "sdcc1_ice_core_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = {
>+	F(144000, P_XO, 16, 3, 25),
>+	F(400000, P_XO, 12, 1, 4),
>+	F(20000000, P_GPLL0_EARLY_DIV, 5, 1, 3),
>+	F(25000000, P_GPLL0_EARLY_DIV, 6, 1, 2),
>+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>+	F(100000000, P_GPLL0, 6, 0, 0),
>+	F(192000000, P_GPLL4, 8, 0, 0),
>+	F(200000000, P_GPLL0, 3, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 sdcc2_apps_clk_src = {
>+	.cmd_rcgr = 0x14010,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div_gpll4,
>+	.freq_tbl = ftbl_sdcc2_apps_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "sdcc2_apps_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div_gpll4,
>+		.num_parents = 4,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_ufs_axi_clk_src[] = {
>+	F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0),
>+	F(100000000, P_GPLL0, 6, 0, 0),
>+	F(150000000, P_GPLL0, 4, 0, 0),
>+	F(200000000, P_GPLL0, 3, 0, 0),
>+	F(240000000, P_GPLL0, 2.5, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 ufs_axi_clk_src = {
>+	.cmd_rcgr = 0x75018,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_ufs_axi_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "ufs_axi_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = {
>+	F(75000000, P_GPLL0_EARLY_DIV, 4, 0, 0),
>+	F(150000000, P_GPLL0, 4, 0, 0),
>+	F(300000000, P_GPLL0, 2, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 ufs_ice_core_clk_src = {
>+	.cmd_rcgr = 0x76010,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_ufs_ice_core_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "ufs_ice_core_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_rcg2 ufs_phy_aux_clk_src = {
>+	.cmd_rcgr = 0x76044,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_sleep_clk,
>+	.freq_tbl = ftbl_hmss_rbcpr_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "ufs_phy_aux_clk_src",
>+		.parent_names = gcc_parent_names_xo_sleep_clk,
>+		.num_parents = 2,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_ufs_unipro_core_clk_src[] = {
>+	F(37500000, P_GPLL0_EARLY_DIV, 8, 0, 0),
>+	F(75000000, P_GPLL0, 8, 0, 0),
>+	F(150000000, P_GPLL0, 4, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 ufs_unipro_core_clk_src = {
>+	.cmd_rcgr = 0x76028,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_ufs_unipro_core_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "ufs_unipro_core_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_usb20_master_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(60000000, P_GPLL0, 10, 0, 0),
>+	F(120000000, P_GPLL0, 5, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 usb20_master_clk_src = {
>+	.cmd_rcgr = 0x2f010,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_usb20_master_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "usb20_master_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_usb20_mock_utmi_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(60000000, P_GPLL0, 10, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 usb20_mock_utmi_clk_src = {
>+	.cmd_rcgr = 0x2f024,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_usb20_mock_utmi_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "usb20_mock_utmi_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_usb30_master_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(66666667, P_GPLL0_EARLY_DIV, 4.5, 0, 0),
>+	F(120000000, P_GPLL0, 5, 0, 0),
>+	F(133333333, P_GPLL0, 4.5, 0, 0),
>+	F(150000000, P_GPLL0, 4, 0, 0),
>+	F(200000000, P_GPLL0, 3, 0, 0),
>+	F(240000000, P_GPLL0, 2.5, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 usb30_master_clk_src = {
>+	.cmd_rcgr = 0xf014,
>+	.mnd_width = 8,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_usb30_master_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "usb30_master_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = {
>+	F(19200000, P_XO, 1, 0, 0),
>+	F(40000000, P_GPLL0_EARLY_DIV, 7.5, 0, 0),
>+	F(60000000, P_GPLL0, 10, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 usb30_mock_utmi_clk_src = {
>+	.cmd_rcgr = 0xf028,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div,
>+	.freq_tbl = ftbl_usb30_mock_utmi_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "usb30_mock_utmi_clk_src",
>+		.parent_names = gcc_parent_names_xo_gpll0_gpll0_early_div,
>+		.num_parents = 3,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static const struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = {
>+	F(1200000, P_XO, 16, 0, 0),
>+	F(19200000, P_XO, 1, 0, 0),
>+	{ }
>+};
>+
>+static struct clk_rcg2 usb3_phy_aux_clk_src = {
>+	.cmd_rcgr = 0x5000c,
>+	.mnd_width = 0,
>+	.hid_width = 5,
>+	.parent_map = gcc_parent_map_xo_sleep_clk,
>+	.freq_tbl = ftbl_usb3_phy_aux_clk_src,
>+	.clkr.hw.init = &(struct clk_init_data){
>+		.name = "usb3_phy_aux_clk_src",
>+		.parent_names = gcc_parent_names_xo_sleep_clk,
>+		.num_parents = 2,
>+		.ops = &clk_rcg2_ops,
>+	},
>+};
>+
>+static struct clk_branch gcc_aggre2_ufs_axi_clk = {
>+	.halt_reg = 0x75034,
>+	.halt_check = BRANCH_HALT,
>+	.clkr = {
>+		.enable_reg = 0x75034,
>+		.enable_mask = BIT(0),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_aggre2_ufs_axi_clk",
>+			.parent_names = (const char *[]){
>+				"ufs_axi_clk_src",
>+			},
>+			.num_parents = 1,
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_aggre2_usb3_axi_clk = {
>+	.halt_reg = 0xf03c,
>+	.halt_check = BRANCH_HALT,
>+	.clkr = {
>+		.enable_reg = 0xf03c,
>+		.enable_mask = BIT(0),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_aggre2_usb3_axi_clk",
>+			.parent_names = (const char *[]){
>+				"usb30_master_clk_src",
>+			},
>+			.num_parents = 1,
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_bimc_gfx_clk = {
>+	.halt_reg = 0x7106c,
>+	.halt_check = BRANCH_VOTED,
>+	.clkr = {
>+		.enable_reg = 0x7106c,
>+		.enable_mask = BIT(0),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_bimc_gfx_clk",
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_bimc_hmss_axi_clk = {
>+	.halt_reg = 0x48004,
>+	.halt_check = BRANCH_HALT_VOTED,
>+	.clkr = {
>+		.enable_reg = 0x52004,
>+		.enable_mask = BIT(22),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_bimc_hmss_axi_clk",
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_bimc_mss_q6_axi_clk = {
>+	.halt_reg = 0x4401c,
>+	.halt_check = BRANCH_HALT,
>+	.clkr = {
>+		.enable_reg = 0x4401c,
>+		.enable_mask = BIT(0),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_bimc_mss_q6_axi_clk",
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_blsp1_ahb_clk = {
>+	.halt_reg = 0x17004,
>+	.halt_check = BRANCH_HALT_VOTED,
>+	.clkr = {
>+		.enable_reg = 0x52004,
>+		.enable_mask = BIT(17),
>+		.hw.init = &(struct clk_init_data){
>+			.name = "gcc_blsp1_ahb_clk",
>+			.ops = &clk_branch2_ops,
>+		},
>+	},
>+};
>+
>+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk

^ permalink raw reply	[flat|nested] 60+ messages in thread

* Re: [PATCH v3] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
  2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
  2018-09-27 19:51     ` Rob Herring
  2018-10-08  6:51     ` Craig
@ 2018-10-16 22:05     ` Stephen Boyd
  2 siblings, 0 replies; 60+ messages in thread
From: Stephen Boyd @ 2018-10-16 22:05 UTC (permalink / raw)
  To: Craig Tatlor
  Cc: ctatlor97, linux-arm-msm, Taniya Das, Michael Turquette,
	Rob Herring, Mark Rutland, Andy Gross, David Brown, linux-clk,
	devicetree, linux-kernel, linux-soc

Quoting Craig Tatlor (2018-09-25 10:35:58)
> From: Taniya Das <tdas@codeaurora.org>
> 
> Add support for the global clock controller found on SDM660
> based devices. This should allow most non-multimedia device
> drivers to probe and control their clocks.
> Based on CAF implementation.
> 
> Signed-off-by: Taniya Das <tdas@codeaurora.org>
> [craig: rename parents to fit upstream, and other cleanups]
> Signed-off-by: Craig Tatlor <ctatlor97@gmail.com>
> ---

Applied to clk-next

But there was some noise:

drivers/clk/qcom/gcc-sdm660.c:2304:10: warning: Initializer entry defined twice
drivers/clk/qcom/gcc-sdm660.c:2306:10: also defined here

and I didn't like seeing gcc_660, so I applied this fixup on top:

diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index 1722a9b181e2..9efb55092ebf 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -2253,12 +2253,12 @@ static struct gdsc pcie_0_gdsc = {
 };
 
 static struct clk_hw *gcc_sdm660_hws[] = {
-	[GCC_XO] = &xo.hw,
-	[GCC_GPLL0_EARLY_DIV] = &gpll0_early_div.hw,
-	[GCC_GPLL1_EARLY_DIV] = &gpll1_early_div.hw,
+	&xo.hw,
+	&gpll0_early_div.hw,
+	&gpll1_early_div.hw,
 };
 
-static struct clk_regmap *gcc_660_clocks[] = {
+static struct clk_regmap *gcc_sdm660_clocks[] = {
 	[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
 	[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
 	[BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
@@ -2365,9 +2365,8 @@ static struct clk_regmap *gcc_660_clocks[] = {
 	[GPLL0_EARLY] = &gpll0_early.clkr,
 	[GPLL1] = &gpll1.clkr,
 	[GPLL1_EARLY] = &gpll1_early.clkr,
-	[GPLL1] = &gpll1.clkr,
-	[GPLL4_EARLY] = &gpll4_early.clkr,
 	[GPLL4] = &gpll4.clkr,
+	[GPLL4_EARLY] = &gpll4_early.clkr,
 	[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
 	[HMSS_GPLL4_CLK_SRC] = &hmss_gpll4_clk_src.clkr,
 	[HMSS_RBCPR_CLK_SRC] = &hmss_rbcpr_clk_src.clkr,
@@ -2387,13 +2386,13 @@ static struct clk_regmap *gcc_660_clocks[] = {
 	[USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr,
 };
 
-static struct gdsc *gcc_660_gdscs[] = {
+static struct gdsc *gcc_sdm660_gdscs[] = {
 	[UFS_GDSC] = &ufs_gdsc,
 	[USB_30_GDSC] = &usb_30_gdsc,
 	[PCIE_0_GDSC] = &pcie_0_gdsc,
 };
 
-static const struct qcom_reset_map gcc_660_resets[] = {
+static const struct qcom_reset_map gcc_sdm660_resets[] = {
 	[GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
 	[GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
 	[GCC_UFS_BCR] = { 0x75000 },
@@ -2405,7 +2404,7 @@ static const struct qcom_reset_map gcc_660_resets[] = {
 	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
 };
 
-static const struct regmap_config gcc_660_regmap_config = {
+static const struct regmap_config gcc_sdm660_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
 	.val_bits	= 32,
@@ -2413,29 +2412,29 @@ static const struct regmap_config gcc_660_regmap_config = {
 	.fast_io	= true,
 };
 
-static const struct qcom_cc_desc gcc_660_desc = {
-	.config = &gcc_660_regmap_config,
-	.clks = gcc_660_clocks,
-	.num_clks = ARRAY_SIZE(gcc_660_clocks),
-	.resets = gcc_660_resets,
-	.num_resets = ARRAY_SIZE(gcc_660_resets),
-	.gdscs = gcc_660_gdscs,
-	.num_gdscs = ARRAY_SIZE(gcc_660_gdscs),
+static const struct qcom_cc_desc gcc_sdm660_desc = {
+	.config = &gcc_sdm660_regmap_config,
+	.clks = gcc_sdm660_clocks,
+	.num_clks = ARRAY_SIZE(gcc_sdm660_clocks),
+	.resets = gcc_sdm660_resets,
+	.num_resets = ARRAY_SIZE(gcc_sdm660_resets),
+	.gdscs = gcc_sdm660_gdscs,
+	.num_gdscs = ARRAY_SIZE(gcc_sdm660_gdscs),
 };
 
-static const struct of_device_id gcc_660_match_table[] = {
+static const struct of_device_id gcc_sdm660_match_table[] = {
 	{ .compatible = "qcom,gcc-sdm630" },
 	{ .compatible = "qcom,gcc-sdm660" },
 	{ }
 };
-MODULE_DEVICE_TABLE(of, gcc_660_match_table);
+MODULE_DEVICE_TABLE(of, gcc_sdm660_match_table);
 
-static int gcc_660_probe(struct platform_device *pdev)
+static int gcc_sdm660_probe(struct platform_device *pdev)
 {
 	int i, ret = 0;
 	struct regmap *regmap;
 
-	regmap = qcom_cc_map(pdev, &gcc_660_desc);
+	regmap = qcom_cc_map(pdev, &gcc_sdm660_desc);
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
@@ -2454,27 +2453,27 @@ static int gcc_660_probe(struct platform_device *pdev)
 			return ret;
 	}
 
-	return qcom_cc_really_probe(pdev, &gcc_660_desc, regmap);
+	return qcom_cc_really_probe(pdev, &gcc_sdm660_desc, regmap);
 }
 
-static struct platform_driver gcc_660_driver = {
-	.probe		= gcc_660_probe,
+static struct platform_driver gcc_sdm660_driver = {
+	.probe		= gcc_sdm660_probe,
 	.driver		= {
 		.name	= "gcc-sdm660",
-		.of_match_table = gcc_660_match_table,
+		.of_match_table = gcc_sdm660_match_table,
 	},
 };
 
-static int __init gcc_660_init(void)
+static int __init gcc_sdm660_init(void)
 {
-	return platform_driver_register(&gcc_660_driver);
+	return platform_driver_register(&gcc_sdm660_driver);
 }
-core_initcall_sync(gcc_660_init);
+core_initcall_sync(gcc_sdm660_init);
 
-static void __exit gcc_660_exit(void)
+static void __exit gcc_sdm660_exit(void)
 {
-	platform_driver_unregister(&gcc_660_driver);
+	platform_driver_unregister(&gcc_sdm660_driver);
 }
-module_exit(gcc_660_exit);
+module_exit(gcc_sdm660_exit);
 
 MODULE_DESCRIPTION("QCOM GCC sdm660 Driver");
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
index 76aabcc5e7e3..468302282913 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm660.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
@@ -7,140 +7,137 @@
 #ifndef _DT_BINDINGS_CLK_MSM_GCC_660_H
 #define _DT_BINDINGS_CLK_MSM_GCC_660_H
 
-#define GCC_XO					0
-#define GCC_GPLL0_EARLY_DIV			1
-#define GCC_GPLL1_EARLY_DIV			2
-#define BLSP1_QUP1_I2C_APPS_CLK_SRC		3
-#define BLSP1_QUP1_SPI_APPS_CLK_SRC		4
-#define BLSP1_QUP2_I2C_APPS_CLK_SRC		5
-#define BLSP1_QUP2_SPI_APPS_CLK_SRC		6
-#define BLSP1_QUP3_I2C_APPS_CLK_SRC		7
-#define BLSP1_QUP3_SPI_APPS_CLK_SRC		8
-#define BLSP1_QUP4_I2C_APPS_CLK_SRC		9
-#define BLSP1_QUP4_SPI_APPS_CLK_SRC		10
-#define BLSP1_UART1_APPS_CLK_SRC		11
-#define BLSP1_UART2_APPS_CLK_SRC		12
-#define BLSP2_QUP1_I2C_APPS_CLK_SRC		13
-#define BLSP2_QUP1_SPI_APPS_CLK_SRC		14
-#define BLSP2_QUP2_I2C_APPS_CLK_SRC		15
-#define BLSP2_QUP2_SPI_APPS_CLK_SRC		16
-#define BLSP2_QUP3_I2C_APPS_CLK_SRC		17
-#define BLSP2_QUP3_SPI_APPS_CLK_SRC		18
-#define BLSP2_QUP4_I2C_APPS_CLK_SRC		19
-#define BLSP2_QUP4_SPI_APPS_CLK_SRC		20
-#define BLSP2_UART1_APPS_CLK_SRC		21
-#define BLSP2_UART2_APPS_CLK_SRC		22
-#define GCC_AGGRE2_UFS_AXI_CLK			23
-#define GCC_AGGRE2_USB3_AXI_CLK			24
-#define GCC_BIMC_GFX_CLK			25
-#define GCC_BIMC_HMSS_AXI_CLK			26
-#define GCC_BIMC_MSS_Q6_AXI_CLK			27
-#define GCC_BLSP1_AHB_CLK			28
-#define GCC_BLSP1_QUP1_I2C_APPS_CLK		29
-#define GCC_BLSP1_QUP1_SPI_APPS_CLK		30
-#define GCC_BLSP1_QUP2_I2C_APPS_CLK		31
-#define GCC_BLSP1_QUP2_SPI_APPS_CLK		32
-#define GCC_BLSP1_QUP3_I2C_APPS_CLK		33
-#define GCC_BLSP1_QUP3_SPI_APPS_CLK		34
-#define GCC_BLSP1_QUP4_I2C_APPS_CLK		35
-#define GCC_BLSP1_QUP4_SPI_APPS_CLK		36
-#define GCC_BLSP1_UART1_APPS_CLK		37
-#define GCC_BLSP1_UART2_APPS_CLK		38
-#define GCC_BLSP2_AHB_CLK			39
-#define GCC_BLSP2_QUP1_I2C_APPS_CLK		40
-#define GCC_BLSP2_QUP1_SPI_APPS_CLK		41
-#define GCC_BLSP2_QUP2_I2C_APPS_CLK		42
-#define GCC_BLSP2_QUP2_SPI_APPS_CLK		43
-#define GCC_BLSP2_QUP3_I2C_APPS_CLK		44
-#define GCC_BLSP2_QUP3_SPI_APPS_CLK		46
-#define GCC_BLSP2_QUP4_I2C_APPS_CLK		45
-#define GCC_BLSP2_QUP4_SPI_APPS_CLK		46
-#define GCC_BLSP2_UART1_APPS_CLK		47
-#define GCC_BLSP2_UART2_APPS_CLK		48
-#define GCC_BOOT_ROM_AHB_CLK			49
-#define GCC_CFG_NOC_USB2_AXI_CLK		50
-#define GCC_CFG_NOC_USB3_AXI_CLK		51
-#define GCC_DCC_AHB_CLK				52
-#define GCC_GP1_CLK				53
-#define GCC_GP2_CLK				54
-#define GCC_GP3_CLK				55
-#define GCC_GPU_BIMC_GFX_CLK			56
-#define GCC_GPU_CFG_AHB_CLK			57
-#define GCC_GPU_GPLL0_CLK			58
-#define GCC_GPU_GPLL0_DIV_CLK			59
-#define GCC_HMSS_DVM_BUS_CLK			60
-#define GCC_HMSS_RBCPR_CLK			61
-#define GCC_MMSS_GPLL0_CLK			62
-#define GCC_MMSS_GPLL0_DIV_CLK			63
-#define GCC_MMSS_NOC_CFG_AHB_CLK		64
-#define GCC_MMSS_SYS_NOC_AXI_CLK		65
-#define GCC_MSS_CFG_AHB_CLK			66
-#define GCC_MSS_GPLL0_DIV_CLK			67
-#define GCC_MSS_MNOC_BIMC_AXI_CLK		68
-#define GCC_MSS_Q6_BIMC_AXI_CLK			69
-#define GCC_MSS_SNOC_AXI_CLK			70
-#define GCC_PDM2_CLK				71
-#define GCC_PDM_AHB_CLK				72
-#define GCC_PRNG_AHB_CLK			73
-#define GCC_QSPI_AHB_CLK			74
-#define GCC_QSPI_SER_CLK			75
-#define GCC_SDCC1_AHB_CLK			76
-#define GCC_SDCC1_APPS_CLK			77
-#define GCC_SDCC1_ICE_CORE_CLK			78
-#define GCC_SDCC2_AHB_CLK			79
-#define GCC_SDCC2_APPS_CLK			80
-#define GCC_UFS_AHB_CLK				81
-#define GCC_UFS_AXI_CLK				82
-#define GCC_UFS_CLKREF_CLK			83
-#define GCC_UFS_ICE_CORE_CLK			84
-#define GCC_UFS_PHY_AUX_CLK			85
-#define GCC_UFS_RX_SYMBOL_0_CLK			86
-#define GCC_UFS_RX_SYMBOL_1_CLK			87
-#define GCC_UFS_TX_SYMBOL_0_CLK			88
-#define GCC_UFS_UNIPRO_CORE_CLK			89
-#define GCC_USB20_MASTER_CLK			90
-#define GCC_USB20_MOCK_UTMI_CLK			91
-#define GCC_USB20_SLEEP_CLK			92
-#define GCC_USB30_MASTER_CLK			93
-#define GCC_USB30_MOCK_UTMI_CLK			94
-#define GCC_USB30_SLEEP_CLK			95
-#define GCC_USB3_CLKREF_CLK			96
-#define GCC_USB3_PHY_AUX_CLK			97
-#define GCC_USB3_PHY_PIPE_CLK			98
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK		99
-#define GP1_CLK_SRC				100
-#define GP2_CLK_SRC				101
-#define GP3_CLK_SRC				102
-#define GPLL0					103
-#define GPLL0_EARLY				104
-#define GPLL1					105
-#define GPLL1_EARLY				106
-#define GPLL4					107
-#define GPLL4_EARLY				108
-#define HMSS_GPLL0_CLK_SRC			109
-#define HMSS_GPLL4_CLK_SRC			110
-#define HMSS_RBCPR_CLK_SRC			111
-#define PDM2_CLK_SRC				112
-#define QSPI_SER_CLK_SRC			113
-#define SDCC1_APPS_CLK_SRC			114
-#define SDCC1_ICE_CORE_CLK_SRC			115
-#define SDCC2_APPS_CLK_SRC			116
-#define UFS_AXI_CLK_SRC				117
-#define UFS_ICE_CORE_CLK_SRC			118
-#define UFS_PHY_AUX_CLK_SRC			119
-#define UFS_UNIPRO_CORE_CLK_SRC			120
-#define USB20_MASTER_CLK_SRC			121
-#define USB20_MOCK_UTMI_CLK_SRC			122
-#define USB30_MASTER_CLK_SRC			123
-#define USB30_MOCK_UTMI_CLK_SRC			124
-#define USB3_PHY_AUX_CLK_SRC			125
-#define GPLL0_OUT_MSSCC				126
-#define GCC_UFS_AXI_HW_CTL_CLK			127
-#define GCC_UFS_ICE_CORE_HW_CTL_CLK		128
-#define GCC_UFS_PHY_AUX_HW_CTL_CLK		129
-#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		130
-#define GCC_RX0_USB2_CLKREF_CLK			131
-#define GCC_RX1_USB2_CLKREF_CLK			132
+#define BLSP1_QUP1_I2C_APPS_CLK_SRC		0
+#define BLSP1_QUP1_SPI_APPS_CLK_SRC		1
+#define BLSP1_QUP2_I2C_APPS_CLK_SRC		2
+#define BLSP1_QUP2_SPI_APPS_CLK_SRC		3
+#define BLSP1_QUP3_I2C_APPS_CLK_SRC		4
+#define BLSP1_QUP3_SPI_APPS_CLK_SRC		5
+#define BLSP1_QUP4_I2C_APPS_CLK_SRC		6
+#define BLSP1_QUP4_SPI_APPS_CLK_SRC		7
+#define BLSP1_UART1_APPS_CLK_SRC		8
+#define BLSP1_UART2_APPS_CLK_SRC		9
+#define BLSP2_QUP1_I2C_APPS_CLK_SRC		10
+#define BLSP2_QUP1_SPI_APPS_CLK_SRC		11
+#define BLSP2_QUP2_I2C_APPS_CLK_SRC		12
+#define BLSP2_QUP2_SPI_APPS_CLK_SRC		13
+#define BLSP2_QUP3_I2C_APPS_CLK_SRC		14
+#define BLSP2_QUP3_SPI_APPS_CLK_SRC		15
+#define BLSP2_QUP4_I2C_APPS_CLK_SRC		16
+#define BLSP2_QUP4_SPI_APPS_CLK_SRC		17
+#define BLSP2_UART1_APPS_CLK_SRC		18
+#define BLSP2_UART2_APPS_CLK_SRC		19
+#define GCC_AGGRE2_UFS_AXI_CLK			20
+#define GCC_AGGRE2_USB3_AXI_CLK			21
+#define GCC_BIMC_GFX_CLK			22
+#define GCC_BIMC_HMSS_AXI_CLK			23
+#define GCC_BIMC_MSS_Q6_AXI_CLK			24
+#define GCC_BLSP1_AHB_CLK			25
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK		26
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK		27
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK		28
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK		29
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK		30
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK		31
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK		32
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK		33
+#define GCC_BLSP1_UART1_APPS_CLK		34
+#define GCC_BLSP1_UART2_APPS_CLK		35
+#define GCC_BLSP2_AHB_CLK			36
+#define GCC_BLSP2_QUP1_I2C_APPS_CLK		37
+#define GCC_BLSP2_QUP1_SPI_APPS_CLK		38
+#define GCC_BLSP2_QUP2_I2C_APPS_CLK		39
+#define GCC_BLSP2_QUP2_SPI_APPS_CLK		40
+#define GCC_BLSP2_QUP3_I2C_APPS_CLK		41
+#define GCC_BLSP2_QUP3_SPI_APPS_CLK		42
+#define GCC_BLSP2_QUP4_I2C_APPS_CLK		43
+#define GCC_BLSP2_QUP4_SPI_APPS_CLK		44
+#define GCC_BLSP2_UART1_APPS_CLK		45
+#define GCC_BLSP2_UART2_APPS_CLK		46
+#define GCC_BOOT_ROM_AHB_CLK			47
+#define GCC_CFG_NOC_USB2_AXI_CLK		48
+#define GCC_CFG_NOC_USB3_AXI_CLK		49
+#define GCC_DCC_AHB_CLK				50
+#define GCC_GP1_CLK				51
+#define GCC_GP2_CLK				52
+#define GCC_GP3_CLK				53
+#define GCC_GPU_BIMC_GFX_CLK			54
+#define GCC_GPU_CFG_AHB_CLK			55
+#define GCC_GPU_GPLL0_CLK			56
+#define GCC_GPU_GPLL0_DIV_CLK			57
+#define GCC_HMSS_DVM_BUS_CLK			58
+#define GCC_HMSS_RBCPR_CLK			59
+#define GCC_MMSS_GPLL0_CLK			60
+#define GCC_MMSS_GPLL0_DIV_CLK			61
+#define GCC_MMSS_NOC_CFG_AHB_CLK		62
+#define GCC_MMSS_SYS_NOC_AXI_CLK		63
+#define GCC_MSS_CFG_AHB_CLK			64
+#define GCC_MSS_GPLL0_DIV_CLK			65
+#define GCC_MSS_MNOC_BIMC_AXI_CLK		66
+#define GCC_MSS_Q6_BIMC_AXI_CLK			67
+#define GCC_MSS_SNOC_AXI_CLK			68
+#define GCC_PDM2_CLK				69
+#define GCC_PDM_AHB_CLK				70
+#define GCC_PRNG_AHB_CLK			71
+#define GCC_QSPI_AHB_CLK			72
+#define GCC_QSPI_SER_CLK			73
+#define GCC_SDCC1_AHB_CLK			74
+#define GCC_SDCC1_APPS_CLK			75
+#define GCC_SDCC1_ICE_CORE_CLK			76
+#define GCC_SDCC2_AHB_CLK			77
+#define GCC_SDCC2_APPS_CLK			78
+#define GCC_UFS_AHB_CLK				79
+#define GCC_UFS_AXI_CLK				80
+#define GCC_UFS_CLKREF_CLK			81
+#define GCC_UFS_ICE_CORE_CLK			82
+#define GCC_UFS_PHY_AUX_CLK			83
+#define GCC_UFS_RX_SYMBOL_0_CLK			84
+#define GCC_UFS_RX_SYMBOL_1_CLK			85
+#define GCC_UFS_TX_SYMBOL_0_CLK			86
+#define GCC_UFS_UNIPRO_CORE_CLK			87
+#define GCC_USB20_MASTER_CLK			88
+#define GCC_USB20_MOCK_UTMI_CLK			89
+#define GCC_USB20_SLEEP_CLK			90
+#define GCC_USB30_MASTER_CLK			91
+#define GCC_USB30_MOCK_UTMI_CLK			92
+#define GCC_USB30_SLEEP_CLK			93
+#define GCC_USB3_CLKREF_CLK			94
+#define GCC_USB3_PHY_AUX_CLK			95
+#define GCC_USB3_PHY_PIPE_CLK			96
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK		97
+#define GP1_CLK_SRC				98
+#define GP2_CLK_SRC				99
+#define GP3_CLK_SRC				100
+#define GPLL0					101
+#define GPLL0_EARLY				102
+#define GPLL1					103
+#define GPLL1_EARLY				104
+#define GPLL4					105
+#define GPLL4_EARLY				106
+#define HMSS_GPLL0_CLK_SRC			107
+#define HMSS_GPLL4_CLK_SRC			108
+#define HMSS_RBCPR_CLK_SRC			109
+#define PDM2_CLK_SRC				110
+#define QSPI_SER_CLK_SRC			111
+#define SDCC1_APPS_CLK_SRC			112
+#define SDCC1_ICE_CORE_CLK_SRC			113
+#define SDCC2_APPS_CLK_SRC			114
+#define UFS_AXI_CLK_SRC				115
+#define UFS_ICE_CORE_CLK_SRC			116
+#define UFS_PHY_AUX_CLK_SRC			117
+#define UFS_UNIPRO_CORE_CLK_SRC			118
+#define USB20_MASTER_CLK_SRC			119
+#define USB20_MOCK_UTMI_CLK_SRC			120
+#define USB30_MASTER_CLK_SRC			121
+#define USB30_MOCK_UTMI_CLK_SRC			122
+#define USB3_PHY_AUX_CLK_SRC			123
+#define GPLL0_OUT_MSSCC				124
+#define GCC_UFS_AXI_HW_CTL_CLK			125
+#define GCC_UFS_ICE_CORE_HW_CTL_CLK		126
+#define GCC_UFS_PHY_AUX_HW_CTL_CLK		127
+#define GCC_UFS_UNIPRO_CORE_HW_CTL_CLK		128
+#define GCC_RX0_USB2_CLKREF_CLK			129
+#define GCC_RX1_USB2_CLKREF_CLK			130
 
 #define PCIE_0_GDSC	0
 #define UFS_GDSC	1

^ permalink raw reply related	[flat|nested] 60+ messages in thread

end of thread, other threads:[~2018-10-16 22:06 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-07 13:59 [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
2018-04-07 13:59 ` [PATCH v3 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
2018-04-07 13:59 ` [PATCH v3 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
2018-04-07 16:37 ` [PATCH v3 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Randy Dunlap
2018-04-07 17:40   ` Craig Tatlor
2018-04-07 17:54   ` Craig Tatlor
2018-04-07 17:57 ` [PATCH v4 " Craig Tatlor
2018-04-07 17:57   ` [PATCH v4 2/3] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
2018-04-13 16:35     ` Rob Herring
2018-04-13 17:08       ` Craig Tatlor
2018-04-13 17:10         ` Craig Tatlor
2018-04-15 12:55       ` Craig Tatlor
2018-04-18 21:16         ` Rob Herring
2018-04-07 17:57   ` [PATCH v4 3/3] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
2018-04-26 11:34   ` [PATCH v4 1/3] power: supply: Add support for the Qualcomm Battery Monitoring System Linus Walleij
2018-04-30 18:06     ` Craig Tatlor
2018-06-07 18:12 ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
2018-06-07 18:12   ` [PATCH v5 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
2018-06-07 19:08     ` Randy Dunlap
2018-06-13 15:58       ` Craig Tatlor
2018-06-07 18:12   ` [PATCH v5 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
2018-06-11 18:15     ` Rob Herring
2018-06-13 16:00       ` Craig Tatlor
2018-06-07 18:12   ` [PATCH v5 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
2018-06-13 11:06   ` [PATCH v5 1/4] fixp-arith: add a linear interpolation function Linus Walleij
2018-06-13 11:12     ` Linus Walleij
2018-06-13 16:01       ` Craig Tatlor
2018-06-13 16:06 ` [PATCH v6 " Craig Tatlor
2018-06-13 16:06   ` [PATCH v6 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
2018-06-14 14:06     ` Linus Walleij
2018-06-13 16:06   ` [PATCH v6 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
2018-06-13 22:53     ` Matthias Kaehlcke
2018-06-13 16:06   ` [PATCH v6 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
2018-06-14 15:14 ` [PATCH v7 1/4] fixp-arith: add a linear interpolation function Craig Tatlor
2018-06-14 15:14   ` [PATCH v7 2/4] power: supply: Add support for the Qualcomm Battery Monitoring System Craig Tatlor
2018-09-16 13:48     ` Sebastian Reichel
2018-09-20 14:43       ` Craig
2018-06-14 15:14   ` [PATCH v7 3/4] dt-bindings: power: supply: qcom_bms: Add bindings Craig Tatlor
2018-09-16 12:10     ` Sebastian Reichel
2018-09-20 14:32       ` Craig
2018-09-20 16:58         ` Sebastian Reichel
2018-09-20 19:13           ` Craig
2018-09-20 21:42             ` Sebastian Reichel
2018-09-20 20:08           ` Baolin Wang
2018-09-20 22:13             ` Sebastian Reichel
2018-09-21 15:40           ` Linus Walleij
2018-06-14 15:14   ` [PATCH v7 4/4] MAINTAINERS: Add entry for the Qualcomm BMS Craig Tatlor
2018-08-10 20:21 ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Craig Tatlor
2018-08-11 21:30   ` kbuild test robot
2018-08-11 21:30   ` [RFC PATCH] clk: qcom: gcc_sdm660_hws[] can be static kbuild test robot
2018-08-13  6:55   ` [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660 Taniya Das
2018-08-13  7:45     ` Craig Tatlor
2018-09-24 12:44       ` Heiko Stuebner
2018-09-24 14:33         ` Craig
2018-08-13  9:44     ` Craig Tatlor
2018-09-25 16:35   ` [PATCH v2] " Craig Tatlor
2018-09-25 17:35   ` [PATCH v3] " Craig Tatlor
2018-09-27 19:51     ` Rob Herring
2018-10-08  6:51     ` Craig
2018-10-16 22:05     ` Stephen Boyd

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).