5
5
*/
6
6
7
7
#include <linux/array_size.h>
8
+ #include <linux/auxiliary_bus.h>
8
9
#include <linux/clk-provider.h>
9
10
#include <linux/delay.h>
11
+ #include <linux/idr.h>
10
12
#include <linux/mfd/syscon.h>
11
13
#include <linux/minmax.h>
12
14
#include <linux/module.h>
13
15
#include <linux/platform_device.h>
16
+ #include <linux/slab.h>
14
17
#include <soc/spacemit/k1-syscon.h>
15
18
16
19
#include "ccu_common.h"
21
24
#include <dt-bindings/clock/spacemit,k1-syscon.h>
22
25
23
26
struct spacemit_ccu_data {
27
+ const char * reset_name ;
24
28
struct clk_hw * * hws ;
25
29
size_t num ;
26
30
};
27
31
32
+ static DEFINE_IDA (auxiliary_ids );
33
+
28
34
/* APBS clocks start, APBS region contains and only contains all PLL clocks */
29
35
30
36
/*
@@ -710,8 +716,9 @@ static struct clk_hw *k1_ccu_pll_hws[] = {
710
716
};
711
717
712
718
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 ),
715
722
};
716
723
717
724
static struct clk_hw * k1_ccu_mpmu_hws [] = {
@@ -751,8 +758,9 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = {
751
758
};
752
759
753
760
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 ),
756
764
};
757
765
758
766
static struct clk_hw * k1_ccu_apbc_hws [] = {
@@ -859,8 +867,9 @@ static struct clk_hw *k1_ccu_apbc_hws[] = {
859
867
};
860
868
861
869
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 ),
864
873
};
865
874
866
875
static struct clk_hw * k1_ccu_apmu_hws [] = {
@@ -929,8 +938,9 @@ static struct clk_hw *k1_ccu_apmu_hws[] = {
929
938
};
930
939
931
940
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 ),
934
944
};
935
945
936
946
static int spacemit_ccu_register (struct device * dev ,
@@ -941,6 +951,10 @@ static int spacemit_ccu_register(struct device *dev,
941
951
struct clk_hw_onecell_data * clk_data ;
942
952
int i , ret ;
943
953
954
+ /* Nothing to do if the CCU does not implement any clocks */
955
+ if (!data -> hws )
956
+ return 0 ;
957
+
944
958
clk_data = devm_kzalloc (dev , struct_size (clk_data , hws , data -> num ),
945
959
GFP_KERNEL );
946
960
if (!clk_data )
@@ -981,9 +995,74 @@ static int spacemit_ccu_register(struct device *dev,
981
995
return ret ;
982
996
}
983
997
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
+
984
1062
static int k1_ccu_probe (struct platform_device * pdev )
985
1063
{
986
1064
struct regmap * base_regmap , * lock_regmap = NULL ;
1065
+ const struct spacemit_ccu_data * data ;
987
1066
struct device * dev = & pdev -> dev ;
988
1067
int ret ;
989
1068
@@ -1012,11 +1091,16 @@ static int k1_ccu_probe(struct platform_device *pdev)
1012
1091
"failed to get lock regmap\n" );
1013
1092
}
1014
1093
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 );
1017
1097
if (ret )
1018
1098
return dev_err_probe (dev , ret , "failed to register clocks\n" );
1019
1099
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
+
1020
1104
return 0 ;
1021
1105
}
1022
1106
0 commit comments