Skip to content

Commit 9885435

Browse files
alexelderdlan17
authored andcommitted
clk: spacemit: set up reset auxiliary devices
Add a new reset_name field to the spacemit_ccu_data structure. If it is non-null, the CCU implements a reset controller, and the name will be used in the name for the auxiliary device that implements it. Define a new type to hold an auxiliary device as well as the regmap pointer that will be needed by CCU reset controllers. Set up code to initialize and add an auxiliary device for any CCU that implements reset functionality. Make it optional for a CCU to implement a clock controller. This doesn't apply to any of the existing CCUs but will for some new ones that will be added soon. Signed-off-by: Alex Elder <[email protected]> Reviewed-by: Haylen Chu <[email protected]> Reviewed-by: Yixun Lan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Yixun Lan <[email protected]>
1 parent bf6239d commit 9885435

File tree

3 files changed

+107
-10
lines changed

3 files changed

+107
-10
lines changed

drivers/clk/spacemit/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
config SPACEMIT_CCU
44
tristate "Clock support for SpacemiT SoCs"
55
depends on ARCH_SPACEMIT || COMPILE_TEST
6+
select AUXILIARY_BUS
67
select MFD_SYSCON
78
help
89
Say Y to enable clock controller unit support for SpacemiT SoCs.

drivers/clk/spacemit/ccu-k1.c

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
*/
66

77
#include <linux/array_size.h>
8+
#include <linux/auxiliary_bus.h>
89
#include <linux/clk-provider.h>
910
#include <linux/delay.h>
11+
#include <linux/idr.h>
1012
#include <linux/mfd/syscon.h>
1113
#include <linux/minmax.h>
1214
#include <linux/module.h>
1315
#include <linux/platform_device.h>
16+
#include <linux/slab.h>
1417
#include <soc/spacemit/k1-syscon.h>
1518

1619
#include "ccu_common.h"
@@ -21,10 +24,13 @@
2124
#include <dt-bindings/clock/spacemit,k1-syscon.h>
2225

2326
struct spacemit_ccu_data {
27+
const char *reset_name;
2428
struct clk_hw **hws;
2529
size_t num;
2630
};
2731

32+
static DEFINE_IDA(auxiliary_ids);
33+
2834
/* APBS clocks start, APBS region contains and only contains all PLL clocks */
2935

3036
/*
@@ -710,8 +716,9 @@ static struct clk_hw *k1_ccu_pll_hws[] = {
710716
};
711717

712718
static const struct spacemit_ccu_data k1_ccu_pll_data = {
713-
.hws = k1_ccu_pll_hws,
714-
.num = ARRAY_SIZE(k1_ccu_pll_hws),
719+
/* The PLL CCU implements no resets */
720+
.hws = k1_ccu_pll_hws,
721+
.num = ARRAY_SIZE(k1_ccu_pll_hws),
715722
};
716723

717724
static struct clk_hw *k1_ccu_mpmu_hws[] = {
@@ -751,8 +758,9 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = {
751758
};
752759

753760
static const struct spacemit_ccu_data k1_ccu_mpmu_data = {
754-
.hws = k1_ccu_mpmu_hws,
755-
.num = ARRAY_SIZE(k1_ccu_mpmu_hws),
761+
.reset_name = "mpmu-reset",
762+
.hws = k1_ccu_mpmu_hws,
763+
.num = ARRAY_SIZE(k1_ccu_mpmu_hws),
756764
};
757765

758766
static struct clk_hw *k1_ccu_apbc_hws[] = {
@@ -859,8 +867,9 @@ static struct clk_hw *k1_ccu_apbc_hws[] = {
859867
};
860868

861869
static const struct spacemit_ccu_data k1_ccu_apbc_data = {
862-
.hws = k1_ccu_apbc_hws,
863-
.num = ARRAY_SIZE(k1_ccu_apbc_hws),
870+
.reset_name = "apbc-reset",
871+
.hws = k1_ccu_apbc_hws,
872+
.num = ARRAY_SIZE(k1_ccu_apbc_hws),
864873
};
865874

866875
static struct clk_hw *k1_ccu_apmu_hws[] = {
@@ -929,8 +938,9 @@ static struct clk_hw *k1_ccu_apmu_hws[] = {
929938
};
930939

931940
static const struct spacemit_ccu_data k1_ccu_apmu_data = {
932-
.hws = k1_ccu_apmu_hws,
933-
.num = ARRAY_SIZE(k1_ccu_apmu_hws),
941+
.reset_name = "apmu-reset",
942+
.hws = k1_ccu_apmu_hws,
943+
.num = ARRAY_SIZE(k1_ccu_apmu_hws),
934944
};
935945

936946
static int spacemit_ccu_register(struct device *dev,
@@ -941,6 +951,10 @@ static int spacemit_ccu_register(struct device *dev,
941951
struct clk_hw_onecell_data *clk_data;
942952
int i, ret;
943953

954+
/* Nothing to do if the CCU does not implement any clocks */
955+
if (!data->hws)
956+
return 0;
957+
944958
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num),
945959
GFP_KERNEL);
946960
if (!clk_data)
@@ -981,9 +995,74 @@ static int spacemit_ccu_register(struct device *dev,
981995
return ret;
982996
}
983997

998+
static void spacemit_cadev_release(struct device *dev)
999+
{
1000+
struct auxiliary_device *adev = to_auxiliary_dev(dev);
1001+
1002+
ida_free(&auxiliary_ids, adev->id);
1003+
kfree(to_spacemit_ccu_adev(adev));
1004+
}
1005+
1006+
static void spacemit_adev_unregister(void *data)
1007+
{
1008+
struct auxiliary_device *adev = data;
1009+
1010+
auxiliary_device_delete(adev);
1011+
auxiliary_device_uninit(adev);
1012+
}
1013+
1014+
static int spacemit_ccu_reset_register(struct device *dev,
1015+
struct regmap *regmap,
1016+
const char *reset_name)
1017+
{
1018+
struct spacemit_ccu_adev *cadev;
1019+
struct auxiliary_device *adev;
1020+
int ret;
1021+
1022+
/* Nothing to do if the CCU does not implement a reset controller */
1023+
if (!reset_name)
1024+
return 0;
1025+
1026+
cadev = kzalloc(sizeof(*cadev), GFP_KERNEL);
1027+
if (!cadev)
1028+
return -ENOMEM;
1029+
1030+
cadev->regmap = regmap;
1031+
1032+
adev = &cadev->adev;
1033+
adev->name = reset_name;
1034+
adev->dev.parent = dev;
1035+
adev->dev.release = spacemit_cadev_release;
1036+
adev->dev.of_node = dev->of_node;
1037+
ret = ida_alloc(&auxiliary_ids, GFP_KERNEL);
1038+
if (ret < 0)
1039+
goto err_free_cadev;
1040+
adev->id = ret;
1041+
1042+
ret = auxiliary_device_init(adev);
1043+
if (ret)
1044+
goto err_free_aux_id;
1045+
1046+
ret = auxiliary_device_add(adev);
1047+
if (ret) {
1048+
auxiliary_device_uninit(adev);
1049+
return ret;
1050+
}
1051+
1052+
return devm_add_action_or_reset(dev, spacemit_adev_unregister, adev);
1053+
1054+
err_free_aux_id:
1055+
ida_free(&auxiliary_ids, adev->id);
1056+
err_free_cadev:
1057+
kfree(cadev);
1058+
1059+
return ret;
1060+
}
1061+
9841062
static int k1_ccu_probe(struct platform_device *pdev)
9851063
{
9861064
struct regmap *base_regmap, *lock_regmap = NULL;
1065+
const struct spacemit_ccu_data *data;
9871066
struct device *dev = &pdev->dev;
9881067
int ret;
9891068

@@ -1012,11 +1091,16 @@ static int k1_ccu_probe(struct platform_device *pdev)
10121091
"failed to get lock regmap\n");
10131092
}
10141093

1015-
ret = spacemit_ccu_register(dev, base_regmap, lock_regmap,
1016-
of_device_get_match_data(dev));
1094+
data = of_device_get_match_data(dev);
1095+
1096+
ret = spacemit_ccu_register(dev, base_regmap, lock_regmap, data);
10171097
if (ret)
10181098
return dev_err_probe(dev, ret, "failed to register clocks\n");
10191099

1100+
ret = spacemit_ccu_reset_register(dev, base_regmap, data->reset_name);
1101+
if (ret)
1102+
return dev_err_probe(dev, ret, "failed to register resets\n");
1103+
10201104
return 0;
10211105
}
10221106

include/soc/spacemit/k1-syscon.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
#ifndef __SOC_K1_SYSCON_H__
66
#define __SOC_K1_SYSCON_H__
77

8+
/* Auxiliary device used to represent a CCU reset controller */
9+
struct spacemit_ccu_adev {
10+
struct auxiliary_device adev;
11+
struct regmap *regmap;
12+
};
13+
14+
static inline struct spacemit_ccu_adev *
15+
to_spacemit_ccu_adev(struct auxiliary_device *adev)
16+
{
17+
return container_of(adev, struct spacemit_ccu_adev, adev);
18+
}
19+
820
/* APBS register offset */
921
#define APBS_PLL1_SWCR1 0x100
1022
#define APBS_PLL1_SWCR2 0x104

0 commit comments

Comments
 (0)