2 * Copyright (C) 2010 Broadcom
3 * Copyright (C) 2012 Stephen Warren
4 * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <linux/clk-provider.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/stringify.h>
25 #include <linux/regmap.h>
26 #include <linux/mfd/syscon.h>
28 /* Standard regmap gate clocks */
32 struct regmap
*regmap
;
36 #define CLK_STAT_REGOFFSET 0x24
37 #define CLK_SET_REGOFFSET 0x2c
38 #define CLK_CLR_REGOFFSET 0x30
40 static inline struct clk_oxnas
*to_clk_oxnas(struct clk_hw
*hw
)
42 return container_of(hw
, struct clk_oxnas
, hw
);
45 static int oxnas_clk_is_enabled(struct clk_hw
*hw
)
47 struct clk_oxnas
*std
= to_clk_oxnas(hw
);
51 ret
= regmap_read(std
->regmap
, CLK_STAT_REGOFFSET
, &val
);
55 return val
& BIT(std
->bit
);
58 static int oxnas_clk_enable(struct clk_hw
*hw
)
60 struct clk_oxnas
*std
= to_clk_oxnas(hw
);
62 regmap_write(std
->regmap
, CLK_SET_REGOFFSET
, BIT(std
->bit
));
67 static void oxnas_clk_disable(struct clk_hw
*hw
)
69 struct clk_oxnas
*std
= to_clk_oxnas(hw
);
71 regmap_write(std
->regmap
, CLK_CLR_REGOFFSET
, BIT(std
->bit
));
74 static const struct clk_ops oxnas_clk_ops
= {
75 .enable
= oxnas_clk_enable
,
76 .disable
= oxnas_clk_disable
,
77 .is_enabled
= oxnas_clk_is_enabled
,
80 static const char *const oxnas_clk_parents
[] = {
84 static const char *const eth_parents
[] = {
88 #define DECLARE_STD_CLKP(__clk, __parent) \
89 static const struct clk_init_data clk_##__clk##_init = { \
90 .name = __stringify(__clk), \
91 .ops = &oxnas_clk_ops, \
92 .parent_names = __parent, \
93 .num_parents = ARRAY_SIZE(__parent), \
96 #define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents)
98 /* Hardware Bit - Clock association */
99 struct clk_oxnas_init_data
{
101 const struct clk_init_data
*clk_init
;
104 /* Clk init data declaration */
105 DECLARE_STD_CLK(leon
);
106 DECLARE_STD_CLK(dma_sgdma
);
107 DECLARE_STD_CLK(cipher
);
108 DECLARE_STD_CLK(sata
);
109 DECLARE_STD_CLK(audio
);
110 DECLARE_STD_CLK(usbmph
);
111 DECLARE_STD_CLKP(etha
, eth_parents
);
112 DECLARE_STD_CLK(pciea
);
113 DECLARE_STD_CLK(nand
);
115 /* Table index is clock indice */
116 static const struct clk_oxnas_init_data clk_oxnas_init
[] = {
117 [0] = {0, &clk_leon_init
},
118 [1] = {1, &clk_dma_sgdma_init
},
119 [2] = {2, &clk_cipher_init
},
120 /* Skip & Do not touch to DDR clock */
121 [3] = {4, &clk_sata_init
},
122 [4] = {5, &clk_audio_init
},
123 [5] = {6, &clk_usbmph_init
},
124 [6] = {7, &clk_etha_init
},
125 [7] = {8, &clk_pciea_init
},
126 [8] = {9, &clk_nand_init
},
129 struct clk_oxnas_data
{
130 struct clk_oxnas clk_oxnas
[ARRAY_SIZE(clk_oxnas_init
)];
131 struct clk_onecell_data onecell_data
[ARRAY_SIZE(clk_oxnas_init
)];
132 struct clk
*clks
[ARRAY_SIZE(clk_oxnas_init
)];
135 static int oxnas_stdclk_probe(struct platform_device
*pdev
)
137 struct device_node
*np
= pdev
->dev
.of_node
;
138 struct clk_oxnas_data
*clk_oxnas
;
139 struct regmap
*regmap
;
142 clk_oxnas
= devm_kzalloc(&pdev
->dev
, sizeof(*clk_oxnas
), GFP_KERNEL
);
146 regmap
= syscon_node_to_regmap(of_get_parent(np
));
148 dev_err(&pdev
->dev
, "failed to have parent regmap\n");
152 for (i
= 0; i
< ARRAY_SIZE(clk_oxnas_init
); i
++) {
153 struct clk_oxnas
*_clk
;
155 _clk
= &clk_oxnas
->clk_oxnas
[i
];
156 _clk
->bit
= clk_oxnas_init
[i
].bit
;
157 _clk
->hw
.init
= clk_oxnas_init
[i
].clk_init
;
158 _clk
->regmap
= regmap
;
161 devm_clk_register(&pdev
->dev
, &_clk
->hw
);
162 if (WARN_ON(IS_ERR(clk_oxnas
->clks
[i
])))
163 return PTR_ERR(clk_oxnas
->clks
[i
]);
166 clk_oxnas
->onecell_data
->clks
= clk_oxnas
->clks
;
167 clk_oxnas
->onecell_data
->clk_num
= ARRAY_SIZE(clk_oxnas_init
);
169 return of_clk_add_provider(np
, of_clk_src_onecell_get
,
170 clk_oxnas
->onecell_data
);
173 static int oxnas_stdclk_remove(struct platform_device
*pdev
)
175 of_clk_del_provider(pdev
->dev
.of_node
);
180 static const struct of_device_id oxnas_stdclk_dt_ids
[] = {
181 { .compatible
= "oxsemi,ox810se-stdclk" },
184 MODULE_DEVICE_TABLE(of
, oxnas_stdclk_dt_ids
);
186 static struct platform_driver oxnas_stdclk_driver
= {
187 .probe
= oxnas_stdclk_probe
,
188 .remove
= oxnas_stdclk_remove
,
190 .name
= "oxnas-stdclk",
191 .of_match_table
= oxnas_stdclk_dt_ids
,
195 module_platform_driver(oxnas_stdclk_driver
);