2 * Copyright (C) 2016 Socionext Inc.
3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/clk-provider.h>
17 #include <linux/device.h>
18 #include <linux/regmap.h>
20 #include "clk-uniphier.h"
22 #define UNIPHIER_CLK_CPUGEAR_STAT 0 /* status */
23 #define UNIPHIER_CLK_CPUGEAR_SET 4 /* set */
24 #define UNIPHIER_CLK_CPUGEAR_UPD 8 /* update */
25 #define UNIPHIER_CLK_CPUGEAR_UPD_BIT BIT(0)
27 struct uniphier_clk_cpugear
{
29 struct regmap
*regmap
;
34 #define to_uniphier_clk_cpugear(_hw) \
35 container_of(_hw, struct uniphier_clk_cpugear, hw)
37 static int uniphier_clk_cpugear_set_parent(struct clk_hw
*hw
, u8 index
)
39 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
43 ret
= regmap_write_bits(gear
->regmap
,
44 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_SET
,
49 ret
= regmap_write_bits(gear
->regmap
,
50 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_UPD
,
51 UNIPHIER_CLK_CPUGEAR_UPD_BIT
,
52 UNIPHIER_CLK_CPUGEAR_UPD_BIT
);
56 return regmap_read_poll_timeout(gear
->regmap
,
57 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_UPD
,
58 val
, !(val
& UNIPHIER_CLK_CPUGEAR_UPD_BIT
),
62 static u8
uniphier_clk_cpugear_get_parent(struct clk_hw
*hw
)
64 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
65 int num_parents
= clk_hw_get_num_parents(hw
);
69 ret
= regmap_read(gear
->regmap
,
70 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_STAT
, &val
);
76 return val
< num_parents
? val
: -EINVAL
;
79 static const struct clk_ops uniphier_clk_cpugear_ops
= {
80 .determine_rate
= __clk_mux_determine_rate
,
81 .set_parent
= uniphier_clk_cpugear_set_parent
,
82 .get_parent
= uniphier_clk_cpugear_get_parent
,
85 struct clk_hw
*uniphier_clk_register_cpugear(struct device
*dev
,
86 struct regmap
*regmap
,
88 const struct uniphier_clk_cpugear_data
*data
)
90 struct uniphier_clk_cpugear
*gear
;
91 struct clk_init_data init
;
94 gear
= devm_kzalloc(dev
, sizeof(*gear
), GFP_KERNEL
);
96 return ERR_PTR(-ENOMEM
);
99 init
.ops
= &uniphier_clk_cpugear_ops
;
100 init
.flags
= CLK_SET_RATE_PARENT
;
101 init
.parent_names
= data
->parent_names
;
102 init
.num_parents
= data
->num_parents
,
104 gear
->regmap
= regmap
;
105 gear
->regbase
= data
->regbase
;
106 gear
->mask
= data
->mask
;
107 gear
->hw
.init
= &init
;
109 ret
= devm_clk_hw_register(dev
, &gear
->hw
);