Unverified Commit 6294bb8e authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'spacemit-clk-for-6.20-1' of https://github.com/spacemit-com/linux into clk-spacemit

Pull SpacemiT clock driver updates from Yixun Lan:

 - Allow SpacemiT driver to be built as module
 - Refactor SpacemiT driver to extract common code
 - Add support for SpacemiT K3 SoC clk hardware

* tag 'spacemit-clk-for-6.20-1' of https://github.com/spacemit-com/linux:
  clk: spacemit: k3: add the clock tree
  clk: spacemit: k3: extract common header
  clk: spacemit: ccu_pll: add plla type clock
  clk: spacemit: ccu_mix: add inverted enable gate clock
  dt-bindings: soc: spacemit: k3: add clock support
  clk: spacemit: add platform SoC prefix to reset name
  clk: spacemit: extract common ccu functions
  reset: spacemit: fix auxiliary device id
  clk: spacemit: prepare common ccu header
  clk: spacemit: Hide common clock driver from user controller
  clk: spacemit: Respect Kconfig setting when building modules
parents 8f0b4cce e371a772
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -4,14 +4,16 @@
$id: http://devicetree.org/schemas/clock/spacemit,k1-pll.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: SpacemiT K1 PLL
title: SpacemiT K1/K3 PLL

maintainers:
  - Haylen Chu <heylenay@4d2.org>

properties:
  compatible:
    const: spacemit,k1-pll
    enum:
      - spacemit,k1-pll
      - spacemit,k3-pll

  reg:
    maxItems: 1
@@ -28,7 +30,8 @@ properties:
  "#clock-cells":
    const: 1
    description:
      See <dt-bindings/clock/spacemit,k1-syscon.h> for valid indices.
      For K1 SoC, check <dt-bindings/clock/spacemit,k1-syscon.h> for valid indices.
      For K3 SoC, check <dt-bindings/clock/spacemit,k3-clocks.h> for valid indices.

required:
  - compatible
+12 −2
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/soc/spacemit/spacemit,k1-syscon.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: SpacemiT K1 SoC System Controller
title: SpacemiT K1/K3 SoC System Controller

maintainers:
  - Haylen Chu <heylenay@4d2.org>
@@ -22,6 +22,10 @@ properties:
      - spacemit,k1-syscon-rcpu
      - spacemit,k1-syscon-rcpu2
      - spacemit,k1-syscon-apbc2
      - spacemit,k3-syscon-apbc
      - spacemit,k3-syscon-apmu
      - spacemit,k3-syscon-dciu
      - spacemit,k3-syscon-mpmu

  reg:
    maxItems: 1
@@ -39,7 +43,8 @@ properties:
  "#clock-cells":
    const: 1
    description:
      See <dt-bindings/clock/spacemit,k1-syscon.h> for valid indices.
      For K1 SoC, check <dt-bindings/clock/spacemit,k1-syscon.h> for valid indices.
      For K3 SoC, check <dt-bindings/clock/spacemit,k3-clocks.h> for valid indices.

  "#power-domain-cells":
    const: 1
@@ -60,6 +65,8 @@ allOf:
            enum:
              - spacemit,k1-syscon-apmu
              - spacemit,k1-syscon-mpmu
              - spacemit,k3-syscon-apmu
              - spacemit,k3-syscon-mpmu
    then:
      required:
        - "#power-domain-cells"
@@ -74,6 +81,9 @@ allOf:
              - spacemit,k1-syscon-apbc
              - spacemit,k1-syscon-apmu
              - spacemit,k1-syscon-mpmu
              - spacemit,k3-syscon-apbc
              - spacemit,k3-syscon-apmu
              - spacemit,k3-syscon-mpmu
    then:
      required:
        - clocks
+12 −8
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only

config SPACEMIT_CCU
	tristate "Clock support for SpacemiT SoCs"
menu "Clock support for SpacemiT platforms"
	depends on ARCH_SPACEMIT || COMPILE_TEST

config SPACEMIT_CCU
	tristate
	select AUXILIARY_BUS
	select MFD_SYSCON
	help
	  Say Y to enable clock controller unit support for SpacemiT SoCs.

if SPACEMIT_CCU

config SPACEMIT_K1_CCU
	tristate "Support for SpacemiT K1 SoC"
	depends on ARCH_SPACEMIT || COMPILE_TEST
	select SPACEMIT_CCU
	help
	  Support for clock controller unit in SpacemiT K1 SoC.

endif
config SPACEMIT_K3_CCU
	tristate "Support for SpacemiT K3 SoC"
	select SPACEMIT_CCU
	help
	  Support for clock controller unit in SpacemiT K3 SoC.

endmenu
+10 −2
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

obj-$(CONFIG_SPACEMIT_K1_CCU)	= spacemit-ccu-k1.o
spacemit-ccu-k1-y		= ccu_pll.o ccu_mix.o ccu_ddn.o
obj-$(CONFIG_SPACEMIT_CCU)	+= spacemit-ccu.o
spacemit-ccu-y			+= ccu_common.o
spacemit-ccu-y			+= ccu_pll.o
spacemit-ccu-y			+= ccu_mix.o
spacemit-ccu-y			+= ccu_ddn.o

obj-$(CONFIG_SPACEMIT_K1_CCU)	+= spacemit-ccu-k1.o
spacemit-ccu-k1-y		+= ccu-k1.o

obj-$(CONFIG_SPACEMIT_K3_CCU)	+= spacemit-ccu-k3.o
spacemit-ccu-k3-y		+= ccu-k3.o
+12 −180
Original line number Diff line number Diff line
@@ -5,15 +5,10 @@
 */

#include <linux/array_size.h>
#include <linux/auxiliary_bus.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/mfd/syscon.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <soc/spacemit/k1-syscon.h>

#include "ccu_common.h"
@@ -23,14 +18,6 @@

#include <dt-bindings/clock/spacemit,k1-syscon.h>

struct spacemit_ccu_data {
	const char *reset_name;
	struct clk_hw **hws;
	size_t num;
};

static DEFINE_IDA(auxiliary_ids);

/* APBS clocks start, APBS region contains and only contains all PLL clocks */

/*
@@ -802,7 +789,7 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = {
};

static const struct spacemit_ccu_data k1_ccu_mpmu_data = {
	.reset_name	= "mpmu-reset",
	.reset_name	= "k1-mpmu-reset",
	.hws		= k1_ccu_mpmu_hws,
	.num		= ARRAY_SIZE(k1_ccu_mpmu_hws),
};
@@ -913,7 +900,7 @@ static struct clk_hw *k1_ccu_apbc_hws[] = {
};

static const struct spacemit_ccu_data k1_ccu_apbc_data = {
	.reset_name	= "apbc-reset",
	.reset_name	= "k1-apbc-reset",
	.hws		= k1_ccu_apbc_hws,
	.num		= ARRAY_SIZE(k1_ccu_apbc_hws),
};
@@ -984,184 +971,23 @@ static struct clk_hw *k1_ccu_apmu_hws[] = {
};

static const struct spacemit_ccu_data k1_ccu_apmu_data = {
	.reset_name	= "apmu-reset",
	.reset_name	= "k1-apmu-reset",
	.hws		= k1_ccu_apmu_hws,
	.num		= ARRAY_SIZE(k1_ccu_apmu_hws),
};

static const struct spacemit_ccu_data k1_ccu_rcpu_data = {
	.reset_name	= "rcpu-reset",
	.reset_name	= "k1-rcpu-reset",
};

static const struct spacemit_ccu_data k1_ccu_rcpu2_data = {
	.reset_name	= "rcpu2-reset",
	.reset_name	= "k1-rcpu2-reset",
};

static const struct spacemit_ccu_data k1_ccu_apbc2_data = {
	.reset_name	= "apbc2-reset",
	.reset_name	= "k1-apbc2-reset",
};

static int spacemit_ccu_register(struct device *dev,
				 struct regmap *regmap,
				 struct regmap *lock_regmap,
				 const struct spacemit_ccu_data *data)
{
	struct clk_hw_onecell_data *clk_data;
	int i, ret;

	/* Nothing to do if the CCU does not implement any clocks */
	if (!data->hws)
		return 0;

	clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num),
				GFP_KERNEL);
	if (!clk_data)
		return -ENOMEM;

	clk_data->num = data->num;

	for (i = 0; i < data->num; i++) {
		struct clk_hw *hw = data->hws[i];
		struct ccu_common *common;
		const char *name;

		if (!hw) {
			clk_data->hws[i] = ERR_PTR(-ENOENT);
			continue;
		}

		name = hw->init->name;

		common = hw_to_ccu_common(hw);
		common->regmap		= regmap;
		common->lock_regmap	= lock_regmap;

		ret = devm_clk_hw_register(dev, hw);
		if (ret) {
			dev_err(dev, "Cannot register clock %d - %s\n",
				i, name);
			return ret;
		}

		clk_data->hws[i] = hw;
	}

	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
	if (ret)
		dev_err(dev, "failed to add clock hardware provider (%d)\n", ret);

	return ret;
}

static void spacemit_cadev_release(struct device *dev)
{
	struct auxiliary_device *adev = to_auxiliary_dev(dev);

	ida_free(&auxiliary_ids, adev->id);
	kfree(to_spacemit_ccu_adev(adev));
}

static void spacemit_adev_unregister(void *data)
{
	struct auxiliary_device *adev = data;

	auxiliary_device_delete(adev);
	auxiliary_device_uninit(adev);
}

static int spacemit_ccu_reset_register(struct device *dev,
				       struct regmap *regmap,
				       const char *reset_name)
{
	struct spacemit_ccu_adev *cadev;
	struct auxiliary_device *adev;
	int ret;

	/* Nothing to do if the CCU does not implement a reset controller */
	if (!reset_name)
		return 0;

	cadev = kzalloc(sizeof(*cadev), GFP_KERNEL);
	if (!cadev)
		return -ENOMEM;

	cadev->regmap = regmap;

	adev = &cadev->adev;
	adev->name = reset_name;
	adev->dev.parent = dev;
	adev->dev.release = spacemit_cadev_release;
	adev->dev.of_node = dev->of_node;
	ret = ida_alloc(&auxiliary_ids, GFP_KERNEL);
	if (ret < 0)
		goto err_free_cadev;
	adev->id = ret;

	ret = auxiliary_device_init(adev);
	if (ret)
		goto err_free_aux_id;

	ret = auxiliary_device_add(adev);
	if (ret) {
		auxiliary_device_uninit(adev);
		return ret;
	}

	return devm_add_action_or_reset(dev, spacemit_adev_unregister, adev);

err_free_aux_id:
	ida_free(&auxiliary_ids, adev->id);
err_free_cadev:
	kfree(cadev);

	return ret;
}

static int k1_ccu_probe(struct platform_device *pdev)
{
	struct regmap *base_regmap, *lock_regmap = NULL;
	const struct spacemit_ccu_data *data;
	struct device *dev = &pdev->dev;
	int ret;

	base_regmap = device_node_to_regmap(dev->of_node);
	if (IS_ERR(base_regmap))
		return dev_err_probe(dev, PTR_ERR(base_regmap),
				     "failed to get regmap\n");

	/*
	 * The lock status of PLLs locate in MPMU region, while PLLs themselves
	 * are in APBS region. Reference to MPMU syscon is required to check PLL
	 * status.
	 */
	if (of_device_is_compatible(dev->of_node, "spacemit,k1-pll")) {
		struct device_node *mpmu = of_parse_phandle(dev->of_node,
							    "spacemit,mpmu", 0);
		if (!mpmu)
			return dev_err_probe(dev, -ENODEV,
					     "Cannot parse MPMU region\n");

		lock_regmap = device_node_to_regmap(mpmu);
		of_node_put(mpmu);

		if (IS_ERR(lock_regmap))
			return dev_err_probe(dev, PTR_ERR(lock_regmap),
					     "failed to get lock regmap\n");
	}

	data = of_device_get_match_data(dev);

	ret = spacemit_ccu_register(dev, base_regmap, lock_regmap, data);
	if (ret)
		return dev_err_probe(dev, ret, "failed to register clocks\n");

	ret = spacemit_ccu_reset_register(dev, base_regmap, data->reset_name);
	if (ret)
		return dev_err_probe(dev, ret, "failed to register resets\n");

	return 0;
}

static const struct of_device_id of_k1_ccu_match[] = {
	{
		.compatible	= "spacemit,k1-pll",
@@ -1195,6 +1021,11 @@ static const struct of_device_id of_k1_ccu_match[] = {
};
MODULE_DEVICE_TABLE(of, of_k1_ccu_match);

static int k1_ccu_probe(struct platform_device *pdev)
{
	return spacemit_ccu_probe(pdev, "spacemit,k1-pll");
}

static struct platform_driver k1_ccu_driver = {
	.driver = {
		.name		= "spacemit,k1-ccu",
@@ -1204,6 +1035,7 @@ static struct platform_driver k1_ccu_driver = {
};
module_platform_driver(k1_ccu_driver);

MODULE_IMPORT_NS("CLK_SPACEMIT");
MODULE_DESCRIPTION("SpacemiT K1 CCU driver");
MODULE_AUTHOR("Haylen Chu <heylenay@4d2.org>");
MODULE_LICENSE("GPL");
Loading