1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas R-Car USB2.0 clock selector
5 * Copyright (C) 2017 Renesas Electronics Corp.
7 * Based on renesas-cpg-mssr.c
9 * Copyright (C) 2015 Glider bvba
12 #include <linux/clk.h>
13 #include <linux/clk-provider.h>
14 #include <linux/device.h>
15 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/of_device.h>
19 #include <linux/platform_device.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/reset.h>
23 #include <linux/slab.h>
25 #define USB20_CLKSET0 0x00
26 #define CLKSET0_INTCLK_EN BIT(11)
27 #define CLKSET0_PRIVATE BIT(0)
28 #define CLKSET0_EXTAL_ONLY (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE)
30 static const struct clk_bulk_data rcar_usb2_clocks
[] = {
31 { .id
= "ehci_ohci", },
32 { .id
= "hs-usb-if", },
35 struct usb2_clock_sel_priv
{
38 struct clk_bulk_data clks
[ARRAY_SIZE(rcar_usb2_clocks
)];
39 struct reset_control
*rsts
;
43 #define to_priv(_hw) container_of(_hw, struct usb2_clock_sel_priv, hw)
45 static void usb2_clock_sel_enable_extal_only(struct usb2_clock_sel_priv
*priv
)
47 u16 val
= readw(priv
->base
+ USB20_CLKSET0
);
49 pr_debug("%s: enter %d %d %x\n", __func__
,
50 priv
->extal
, priv
->xtal
, val
);
52 if (priv
->extal
&& !priv
->xtal
&& val
!= CLKSET0_EXTAL_ONLY
)
53 writew(CLKSET0_EXTAL_ONLY
, priv
->base
+ USB20_CLKSET0
);
56 static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv
*priv
)
58 if (priv
->extal
&& !priv
->xtal
)
59 writew(CLKSET0_PRIVATE
, priv
->base
+ USB20_CLKSET0
);
62 static int usb2_clock_sel_enable(struct clk_hw
*hw
)
64 struct usb2_clock_sel_priv
*priv
= to_priv(hw
);
67 ret
= reset_control_deassert(priv
->rsts
);
71 ret
= clk_bulk_prepare_enable(ARRAY_SIZE(priv
->clks
), priv
->clks
);
73 reset_control_assert(priv
->rsts
);
77 usb2_clock_sel_enable_extal_only(priv
);
82 static void usb2_clock_sel_disable(struct clk_hw
*hw
)
84 struct usb2_clock_sel_priv
*priv
= to_priv(hw
);
86 usb2_clock_sel_disable_extal_only(priv
);
88 clk_bulk_disable_unprepare(ARRAY_SIZE(priv
->clks
), priv
->clks
);
89 reset_control_assert(priv
->rsts
);
93 * This module seems a mux, but this driver assumes a gate because
94 * ehci/ohci platform drivers don't support clk_set_parent() for now.
95 * If this driver acts as a gate, ehci/ohci-platform drivers don't need
98 static const struct clk_ops usb2_clock_sel_clock_ops
= {
99 .enable
= usb2_clock_sel_enable
,
100 .disable
= usb2_clock_sel_disable
,
103 static const struct of_device_id rcar_usb2_clock_sel_match
[] = {
104 { .compatible
= "renesas,rcar-gen3-usb2-clock-sel" },
108 static int rcar_usb2_clock_sel_suspend(struct device
*dev
)
110 struct usb2_clock_sel_priv
*priv
= dev_get_drvdata(dev
);
112 usb2_clock_sel_disable_extal_only(priv
);
118 static int rcar_usb2_clock_sel_resume(struct device
*dev
)
120 struct usb2_clock_sel_priv
*priv
= dev_get_drvdata(dev
);
122 pm_runtime_get_sync(dev
);
123 usb2_clock_sel_enable_extal_only(priv
);
128 static int rcar_usb2_clock_sel_remove(struct platform_device
*pdev
)
130 struct device
*dev
= &pdev
->dev
;
131 struct usb2_clock_sel_priv
*priv
= platform_get_drvdata(pdev
);
133 of_clk_del_provider(dev
->of_node
);
134 clk_hw_unregister(&priv
->hw
);
136 pm_runtime_disable(dev
);
141 static int rcar_usb2_clock_sel_probe(struct platform_device
*pdev
)
143 struct device
*dev
= &pdev
->dev
;
144 struct device_node
*np
= dev
->of_node
;
145 struct usb2_clock_sel_priv
*priv
;
147 struct clk_init_data init
;
150 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
154 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
155 if (IS_ERR(priv
->base
))
156 return PTR_ERR(priv
->base
);
158 memcpy(priv
->clks
, rcar_usb2_clocks
, sizeof(priv
->clks
));
159 ret
= devm_clk_bulk_get(dev
, ARRAY_SIZE(priv
->clks
), priv
->clks
);
163 priv
->rsts
= devm_reset_control_array_get_shared(dev
);
164 if (IS_ERR(priv
->rsts
))
165 return PTR_ERR(priv
->rsts
);
167 pm_runtime_enable(dev
);
168 pm_runtime_get_sync(dev
);
170 clk
= devm_clk_get(dev
, "usb_extal");
171 if (!IS_ERR(clk
) && !clk_prepare_enable(clk
)) {
172 priv
->extal
= !!clk_get_rate(clk
);
173 clk_disable_unprepare(clk
);
175 clk
= devm_clk_get(dev
, "usb_xtal");
176 if (!IS_ERR(clk
) && !clk_prepare_enable(clk
)) {
177 priv
->xtal
= !!clk_get_rate(clk
);
178 clk_disable_unprepare(clk
);
181 if (!priv
->extal
&& !priv
->xtal
) {
182 dev_err(dev
, "This driver needs usb_extal or usb_xtal\n");
186 platform_set_drvdata(pdev
, priv
);
187 dev_set_drvdata(dev
, priv
);
189 init
.name
= "rcar_usb2_clock_sel";
190 init
.ops
= &usb2_clock_sel_clock_ops
;
192 init
.parent_names
= NULL
;
193 init
.num_parents
= 0;
194 priv
->hw
.init
= &init
;
196 clk
= clk_register(NULL
, &priv
->hw
);
200 return of_clk_add_hw_provider(np
, of_clk_hw_simple_get
, &priv
->hw
);
203 static const struct dev_pm_ops rcar_usb2_clock_sel_pm_ops
= {
204 .suspend
= rcar_usb2_clock_sel_suspend
,
205 .resume
= rcar_usb2_clock_sel_resume
,
208 static struct platform_driver rcar_usb2_clock_sel_driver
= {
210 .name
= "rcar-usb2-clock-sel",
211 .of_match_table
= rcar_usb2_clock_sel_match
,
212 .pm
= &rcar_usb2_clock_sel_pm_ops
,
214 .probe
= rcar_usb2_clock_sel_probe
,
215 .remove
= rcar_usb2_clock_sel_remove
,
217 builtin_platform_driver(rcar_usb2_clock_sel_driver
);
219 MODULE_DESCRIPTION("Renesas R-Car USB2 clock selector Driver");
220 MODULE_LICENSE("GPL v2");