1 // SPDX-License-Identifier: GPL-2.0
3 * BCM63268 Timer Clock and Reset Controller Driver
5 * Copyright (C) 2023 Álvaro Fernández Rojas <noltari@gmail.com>
8 #include <linux/clk-provider.h>
9 #include <linux/container_of.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
13 #include <linux/platform_device.h>
14 #include <linux/reset-controller.h>
15 #include <linux/spinlock.h>
17 #include <dt-bindings/clock/bcm63268-clock.h>
19 #define BCM63268_TIMER_RESET_SLEEP_MIN_US 10000
20 #define BCM63268_TIMER_RESET_SLEEP_MAX_US 20000
22 struct bcm63268_tclkrst_hw
{
26 struct reset_controller_dev rcdev
;
27 struct clk_hw_onecell_data data
;
30 struct bcm63268_tclk_table_entry
{
31 const char * const name
;
35 static const struct bcm63268_tclk_table_entry bcm63268_timer_clocks
[] = {
38 .bit
= BCM63268_TCLK_EPHY1
,
41 .bit
= BCM63268_TCLK_EPHY2
,
44 .bit
= BCM63268_TCLK_EPHY3
,
47 .bit
= BCM63268_TCLK_GPHY1
,
50 .bit
= BCM63268_TCLK_DSL
,
52 .name
= "wakeon_ephy",
53 .bit
= BCM63268_TCLK_WAKEON_EPHY
,
56 .bit
= BCM63268_TCLK_WAKEON_DSL
,
59 .bit
= BCM63268_TCLK_FAP1
,
62 .bit
= BCM63268_TCLK_FAP2
,
65 .bit
= BCM63268_TCLK_UTO_50
,
68 .bit
= BCM63268_TCLK_UTO_EXTIN
,
71 .bit
= BCM63268_TCLK_USB_REF
,
77 static inline struct bcm63268_tclkrst_hw
*
78 to_bcm63268_timer_reset(struct reset_controller_dev
*rcdev
)
80 return container_of(rcdev
, struct bcm63268_tclkrst_hw
, rcdev
);
83 static int bcm63268_timer_reset_update(struct reset_controller_dev
*rcdev
,
84 unsigned long id
, bool assert)
86 struct bcm63268_tclkrst_hw
*reset
= to_bcm63268_timer_reset(rcdev
);
90 spin_lock_irqsave(&reset
->lock
, flags
);
91 val
= __raw_readl(reset
->regs
);
96 __raw_writel(val
, reset
->regs
);
97 spin_unlock_irqrestore(&reset
->lock
, flags
);
102 static int bcm63268_timer_reset_assert(struct reset_controller_dev
*rcdev
,
105 return bcm63268_timer_reset_update(rcdev
, id
, true);
108 static int bcm63268_timer_reset_deassert(struct reset_controller_dev
*rcdev
,
111 return bcm63268_timer_reset_update(rcdev
, id
, false);
114 static int bcm63268_timer_reset_reset(struct reset_controller_dev
*rcdev
,
117 bcm63268_timer_reset_update(rcdev
, id
, true);
118 usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US
,
119 BCM63268_TIMER_RESET_SLEEP_MAX_US
);
121 bcm63268_timer_reset_update(rcdev
, id
, false);
123 * Ensure component is taken out reset state by sleeping also after
124 * deasserting the reset. Otherwise, the component may not be ready
127 usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US
,
128 BCM63268_TIMER_RESET_SLEEP_MAX_US
);
133 static int bcm63268_timer_reset_status(struct reset_controller_dev
*rcdev
,
136 struct bcm63268_tclkrst_hw
*reset
= to_bcm63268_timer_reset(rcdev
);
138 return !(__raw_readl(reset
->regs
) & BIT(id
));
141 static const struct reset_control_ops bcm63268_timer_reset_ops
= {
142 .assert = bcm63268_timer_reset_assert
,
143 .deassert
= bcm63268_timer_reset_deassert
,
144 .reset
= bcm63268_timer_reset_reset
,
145 .status
= bcm63268_timer_reset_status
,
148 static int bcm63268_tclk_probe(struct platform_device
*pdev
)
150 struct device
*dev
= &pdev
->dev
;
151 const struct bcm63268_tclk_table_entry
*entry
;
152 struct bcm63268_tclkrst_hw
*hw
;
157 for (entry
= bcm63268_timer_clocks
; entry
->name
; entry
++)
158 maxbit
= max(maxbit
, entry
->bit
);
161 hw
= devm_kzalloc(&pdev
->dev
, struct_size(hw
, data
.hws
, maxbit
),
166 platform_set_drvdata(pdev
, hw
);
168 spin_lock_init(&hw
->lock
);
170 hw
->data
.num
= maxbit
;
171 for (i
= 0; i
< maxbit
; i
++)
172 hw
->data
.hws
[i
] = ERR_PTR(-ENODEV
);
174 hw
->regs
= devm_platform_ioremap_resource(pdev
, 0);
175 if (IS_ERR(hw
->regs
))
176 return PTR_ERR(hw
->regs
);
178 for (entry
= bcm63268_timer_clocks
; entry
->name
; entry
++) {
179 clk
= devm_clk_hw_register_gate(dev
, entry
->name
, NULL
, 0,
180 hw
->regs
, entry
->bit
,
186 hw
->data
.hws
[entry
->bit
] = clk
;
189 ret
= devm_of_clk_add_hw_provider(dev
, of_clk_hw_onecell_get
,
194 hw
->rcdev
.of_node
= dev
->of_node
;
195 hw
->rcdev
.ops
= &bcm63268_timer_reset_ops
;
197 ret
= devm_reset_controller_register(dev
, &hw
->rcdev
);
199 dev_err(dev
, "Failed to register reset controller\n");
204 static const struct of_device_id bcm63268_tclk_dt_ids
[] = {
205 { .compatible
= "brcm,bcm63268-timer-clocks" },
209 static struct platform_driver bcm63268_tclk
= {
210 .probe
= bcm63268_tclk_probe
,
212 .name
= "bcm63268-timer-clock",
213 .of_match_table
= bcm63268_tclk_dt_ids
,
216 builtin_platform_driver(bcm63268_tclk
);