1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2015 Maxime Ripard
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
8 #include <linux/clk-provider.h>
10 #include <linux/kernel.h>
11 #include <linux/of_address.h>
12 #include <linux/reset-controller.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
16 struct sun4i_a10_display_clk_data
{
35 struct reset_controller_dev rcdev
;
39 static DEFINE_SPINLOCK(sun4i_a10_display_lock
);
41 static inline struct reset_data
*rcdev_to_reset_data(struct reset_controller_dev
*rcdev
)
43 return container_of(rcdev
, struct reset_data
, rcdev
);
46 static int sun4i_a10_display_assert(struct reset_controller_dev
*rcdev
,
49 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
53 spin_lock_irqsave(data
->lock
, flags
);
55 reg
= readl(data
->reg
);
56 writel(reg
& ~BIT(data
->offset
+ id
), data
->reg
);
58 spin_unlock_irqrestore(data
->lock
, flags
);
63 static int sun4i_a10_display_deassert(struct reset_controller_dev
*rcdev
,
66 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
70 spin_lock_irqsave(data
->lock
, flags
);
72 reg
= readl(data
->reg
);
73 writel(reg
| BIT(data
->offset
+ id
), data
->reg
);
75 spin_unlock_irqrestore(data
->lock
, flags
);
80 static int sun4i_a10_display_status(struct reset_controller_dev
*rcdev
,
83 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
85 return !(readl(data
->reg
) & BIT(data
->offset
+ id
));
88 static const struct reset_control_ops sun4i_a10_display_reset_ops
= {
89 .assert = sun4i_a10_display_assert
,
90 .deassert
= sun4i_a10_display_deassert
,
91 .status
= sun4i_a10_display_status
,
94 static int sun4i_a10_display_reset_xlate(struct reset_controller_dev
*rcdev
,
95 const struct of_phandle_args
*spec
)
97 /* We only have a single reset signal */
101 static void __init
sun4i_a10_display_init(struct device_node
*node
,
102 const struct sun4i_a10_display_clk_data
*data
)
104 const char *parents
[4];
105 const char *clk_name
= node
->name
;
106 struct reset_data
*reset_data
;
107 struct clk_divider
*div
= NULL
;
108 struct clk_gate
*gate
;
115 of_property_read_string(node
, "clock-output-names", &clk_name
);
117 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
119 pr_err("%s: Could not map the clock registers\n", clk_name
);
123 ret
= of_clk_parent_fill(node
, parents
, data
->parents
);
124 if (ret
!= data
->parents
) {
125 pr_err("%s: Could not retrieve the parents\n", clk_name
);
129 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
134 mux
->shift
= data
->offset_mux
;
135 mux
->mask
= (1 << data
->width_mux
) - 1;
136 mux
->lock
= &sun4i_a10_display_lock
;
138 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
143 gate
->bit_idx
= data
->offset_en
;
144 gate
->lock
= &sun4i_a10_display_lock
;
147 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
152 div
->shift
= data
->offset_div
;
153 div
->width
= data
->width_div
;
154 div
->lock
= &sun4i_a10_display_lock
;
157 clk
= clk_register_composite(NULL
, clk_name
,
158 parents
, data
->parents
,
159 &mux
->hw
, &clk_mux_ops
,
160 data
->has_div
? &div
->hw
: NULL
,
161 data
->has_div
? &clk_divider_ops
: NULL
,
162 &gate
->hw
, &clk_gate_ops
,
165 pr_err("%s: Couldn't register the clock\n", clk_name
);
169 ret
= of_clk_add_provider(node
, of_clk_src_simple_get
, clk
);
171 pr_err("%s: Couldn't register DT provider\n", clk_name
);
178 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
182 reset_data
->reg
= reg
;
183 reset_data
->offset
= data
->offset_rst
;
184 reset_data
->lock
= &sun4i_a10_display_lock
;
185 reset_data
->rcdev
.nr_resets
= data
->num_rst
;
186 reset_data
->rcdev
.ops
= &sun4i_a10_display_reset_ops
;
187 reset_data
->rcdev
.of_node
= node
;
189 if (data
->num_rst
== 1) {
190 reset_data
->rcdev
.of_reset_n_cells
= 0;
191 reset_data
->rcdev
.of_xlate
= &sun4i_a10_display_reset_xlate
;
193 reset_data
->rcdev
.of_reset_n_cells
= 1;
196 if (reset_controller_register(&reset_data
->rcdev
)) {
197 pr_err("%s: Couldn't register the reset controller\n",
207 of_clk_del_provider(node
);
209 clk_unregister_composite(clk
);
218 of_address_to_resource(node
, 0, &res
);
219 release_mem_region(res
.start
, resource_size(&res
));
222 static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst
= {
229 .flags
= CLK_SET_RATE_PARENT
,
232 static void __init
sun4i_a10_tcon_ch0_setup(struct device_node
*node
)
234 sun4i_a10_display_init(node
, &sun4i_a10_tcon_ch0_data
);
236 CLK_OF_DECLARE(sun4i_a10_tcon_ch0
, "allwinner,sun4i-a10-tcon-ch0-clk",
237 sun4i_a10_tcon_ch0_setup
);
239 static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst
= {
251 static void __init
sun4i_a10_display_setup(struct device_node
*node
)
253 sun4i_a10_display_init(node
, &sun4i_a10_display_data
);
255 CLK_OF_DECLARE(sun4i_a10_display
, "allwinner,sun4i-a10-display-clk",
256 sun4i_a10_display_setup
);