1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Socionext Inc.
4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
7 #include <linux/clk-provider.h>
8 #include <linux/device.h>
9 #include <linux/regmap.h>
11 #include "clk-uniphier.h"
13 #define UNIPHIER_CLK_CPUGEAR_STAT 0 /* status */
14 #define UNIPHIER_CLK_CPUGEAR_SET 4 /* set */
15 #define UNIPHIER_CLK_CPUGEAR_UPD 8 /* update */
16 #define UNIPHIER_CLK_CPUGEAR_UPD_BIT BIT(0)
18 struct uniphier_clk_cpugear
{
20 struct regmap
*regmap
;
25 #define to_uniphier_clk_cpugear(_hw) \
26 container_of(_hw, struct uniphier_clk_cpugear, hw)
28 static int uniphier_clk_cpugear_set_parent(struct clk_hw
*hw
, u8 index
)
30 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
34 ret
= regmap_write_bits(gear
->regmap
,
35 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_SET
,
40 ret
= regmap_write_bits(gear
->regmap
,
41 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_UPD
,
42 UNIPHIER_CLK_CPUGEAR_UPD_BIT
,
43 UNIPHIER_CLK_CPUGEAR_UPD_BIT
);
47 return regmap_read_poll_timeout(gear
->regmap
,
48 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_UPD
,
49 val
, !(val
& UNIPHIER_CLK_CPUGEAR_UPD_BIT
),
53 static u8
uniphier_clk_cpugear_get_parent(struct clk_hw
*hw
)
55 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
56 int num_parents
= clk_hw_get_num_parents(hw
);
60 ret
= regmap_read(gear
->regmap
,
61 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_STAT
, &val
);
67 return val
< num_parents
? val
: -EINVAL
;
70 static const struct clk_ops uniphier_clk_cpugear_ops
= {
71 .determine_rate
= __clk_mux_determine_rate
,
72 .set_parent
= uniphier_clk_cpugear_set_parent
,
73 .get_parent
= uniphier_clk_cpugear_get_parent
,
76 struct clk_hw
*uniphier_clk_register_cpugear(struct device
*dev
,
77 struct regmap
*regmap
,
79 const struct uniphier_clk_cpugear_data
*data
)
81 struct uniphier_clk_cpugear
*gear
;
82 struct clk_init_data init
;
85 gear
= devm_kzalloc(dev
, sizeof(*gear
), GFP_KERNEL
);
87 return ERR_PTR(-ENOMEM
);
90 init
.ops
= &uniphier_clk_cpugear_ops
;
91 init
.flags
= CLK_SET_RATE_PARENT
;
92 init
.parent_names
= data
->parent_names
;
93 init
.num_parents
= data
->num_parents
;
95 gear
->regmap
= regmap
;
96 gear
->regbase
= data
->regbase
;
97 gear
->mask
= data
->mask
;
98 gear
->hw
.init
= &init
;
100 ret
= devm_clk_hw_register(dev
, &gear
->hw
);