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"
2124#include <dt-bindings/clock/spacemit,k1-syscon.h>
2225
2326struct 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
712718static 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
717724static struct clk_hw * k1_ccu_mpmu_hws [] = {
@@ -751,8 +758,9 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = {
751758};
752759
753760static 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
758766static struct clk_hw * k1_ccu_apbc_hws [] = {
@@ -859,8 +867,9 @@ static struct clk_hw *k1_ccu_apbc_hws[] = {
859867};
860868
861869static 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
866875static struct clk_hw * k1_ccu_apmu_hws [] = {
@@ -929,8 +938,9 @@ static struct clk_hw *k1_ccu_apmu_hws[] = {
929938};
930939
931940static 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
936946static 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+
9841062static 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
0 commit comments