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/delay.h>
18 #include <linux/device.h>
19 #include <linux/regmap.h>
21 #include "clk-uniphier.h"
23 #define UNIPHIER_CLK_CPUGEAR_STAT 0 /* status */
24 #define UNIPHIER_CLK_CPUGEAR_SET 4 /* set */
25 #define UNIPHIER_CLK_CPUGEAR_UPD 8 /* update */
26 #define UNIPHIER_CLK_CPUGEAR_UPD_BIT BIT(0)
28 struct uniphier_clk_cpugear
{
30 struct regmap
*regmap
;
35 #define to_uniphier_clk_cpugear(_hw) \
36 container_of(_hw, struct uniphier_clk_cpugear, hw)
38 static int uniphier_clk_cpugear_set_parent(struct clk_hw
*hw
, u8 index
)
40 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
44 ret
= regmap_write_bits(gear
->regmap
,
45 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_SET
,
50 ret
= regmap_write_bits(gear
->regmap
,
51 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_SET
,
52 UNIPHIER_CLK_CPUGEAR_UPD_BIT
,
53 UNIPHIER_CLK_CPUGEAR_UPD_BIT
);
57 return regmap_read_poll_timeout(gear
->regmap
,
58 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_UPD
,
59 val
, !(val
& UNIPHIER_CLK_CPUGEAR_UPD_BIT
),
63 static u8
uniphier_clk_cpugear_get_parent(struct clk_hw
*hw
)
65 struct uniphier_clk_cpugear
*gear
= to_uniphier_clk_cpugear(hw
);
66 int num_parents
= clk_hw_get_num_parents(hw
);
70 ret
= regmap_read(gear
->regmap
,
71 gear
->regbase
+ UNIPHIER_CLK_CPUGEAR_STAT
, &val
);
77 return val
< num_parents
? val
: -EINVAL
;
80 static const struct clk_ops uniphier_clk_cpugear_ops
= {
81 .determine_rate
= __clk_mux_determine_rate
,
82 .set_parent
= uniphier_clk_cpugear_set_parent
,
83 .get_parent
= uniphier_clk_cpugear_get_parent
,
86 struct clk_hw
*uniphier_clk_register_cpugear(struct device
*dev
,
87 struct regmap
*regmap
,
89 const struct uniphier_clk_cpugear_data
*data
)
91 struct uniphier_clk_cpugear
*gear
;
92 struct clk_init_data init
;
95 gear
= devm_kzalloc(dev
, sizeof(*gear
), GFP_KERNEL
);
97 return ERR_PTR(-ENOMEM
);
100 init
.ops
= &uniphier_clk_cpugear_ops
;
101 init
.flags
= CLK_SET_RATE_PARENT
;
102 init
.parent_names
= data
->parent_names
;
103 init
.num_parents
= data
->num_parents
,
105 gear
->regmap
= regmap
;
106 gear
->regbase
= data
->regbase
;
107 gear
->mask
= data
->mask
;
108 gear
->hw
.init
= &init
;
110 ret
= devm_clk_hw_register(dev
, &gear
->hw
);