2 * Copyright 2015 Maxime Ripard
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/clk-provider.h>
18 #include <linux/kernel.h>
19 #include <linux/of_address.h>
20 #include <linux/reset-controller.h>
21 #include <linux/slab.h>
22 #include <linux/spinlock.h>
24 struct sun4i_a10_display_clk_data
{
43 struct reset_controller_dev rcdev
;
47 static DEFINE_SPINLOCK(sun4i_a10_display_lock
);
49 static inline struct reset_data
*rcdev_to_reset_data(struct reset_controller_dev
*rcdev
)
51 return container_of(rcdev
, struct reset_data
, rcdev
);
54 static int sun4i_a10_display_assert(struct reset_controller_dev
*rcdev
,
57 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
61 spin_lock_irqsave(data
->lock
, flags
);
63 reg
= readl(data
->reg
);
64 writel(reg
& ~BIT(data
->offset
+ id
), data
->reg
);
66 spin_unlock_irqrestore(data
->lock
, flags
);
71 static int sun4i_a10_display_deassert(struct reset_controller_dev
*rcdev
,
74 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
78 spin_lock_irqsave(data
->lock
, flags
);
80 reg
= readl(data
->reg
);
81 writel(reg
| BIT(data
->offset
+ id
), data
->reg
);
83 spin_unlock_irqrestore(data
->lock
, flags
);
88 static int sun4i_a10_display_status(struct reset_controller_dev
*rcdev
,
91 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
93 return !(readl(data
->reg
) & BIT(data
->offset
+ id
));
96 static const struct reset_control_ops sun4i_a10_display_reset_ops
= {
97 .assert = sun4i_a10_display_assert
,
98 .deassert
= sun4i_a10_display_deassert
,
99 .status
= sun4i_a10_display_status
,
102 static int sun4i_a10_display_reset_xlate(struct reset_controller_dev
*rcdev
,
103 const struct of_phandle_args
*spec
)
105 /* We only have a single reset signal */
109 static void __init
sun4i_a10_display_init(struct device_node
*node
,
110 const struct sun4i_a10_display_clk_data
*data
)
112 const char *parents
[4];
113 const char *clk_name
= node
->name
;
114 struct reset_data
*reset_data
;
115 struct clk_divider
*div
= NULL
;
116 struct clk_gate
*gate
;
123 of_property_read_string(node
, "clock-output-names", &clk_name
);
125 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
127 pr_err("%s: Could not map the clock registers\n", clk_name
);
131 ret
= of_clk_parent_fill(node
, parents
, data
->parents
);
132 if (ret
!= data
->parents
) {
133 pr_err("%s: Could not retrieve the parents\n", clk_name
);
137 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
142 mux
->shift
= data
->offset_mux
;
143 mux
->mask
= (1 << data
->width_mux
) - 1;
144 mux
->lock
= &sun4i_a10_display_lock
;
146 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
151 gate
->bit_idx
= data
->offset_en
;
152 gate
->lock
= &sun4i_a10_display_lock
;
155 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
160 div
->shift
= data
->offset_div
;
161 div
->width
= data
->width_div
;
162 div
->lock
= &sun4i_a10_display_lock
;
165 clk
= clk_register_composite(NULL
, clk_name
,
166 parents
, data
->parents
,
167 &mux
->hw
, &clk_mux_ops
,
168 data
->has_div
? &div
->hw
: NULL
,
169 data
->has_div
? &clk_divider_ops
: NULL
,
170 &gate
->hw
, &clk_gate_ops
,
173 pr_err("%s: Couldn't register the clock\n", clk_name
);
177 ret
= of_clk_add_provider(node
, of_clk_src_simple_get
, clk
);
179 pr_err("%s: Couldn't register DT provider\n", clk_name
);
186 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
190 reset_data
->reg
= reg
;
191 reset_data
->offset
= data
->offset_rst
;
192 reset_data
->lock
= &sun4i_a10_display_lock
;
193 reset_data
->rcdev
.nr_resets
= data
->num_rst
;
194 reset_data
->rcdev
.ops
= &sun4i_a10_display_reset_ops
;
195 reset_data
->rcdev
.of_node
= node
;
197 if (data
->num_rst
== 1) {
198 reset_data
->rcdev
.of_reset_n_cells
= 0;
199 reset_data
->rcdev
.of_xlate
= &sun4i_a10_display_reset_xlate
;
201 reset_data
->rcdev
.of_reset_n_cells
= 1;
204 if (reset_controller_register(&reset_data
->rcdev
)) {
205 pr_err("%s: Couldn't register the reset controller\n",
215 of_clk_del_provider(node
);
217 clk_unregister_composite(clk
);
226 of_address_to_resource(node
, 0, &res
);
227 release_mem_region(res
.start
, resource_size(&res
));
230 static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst
= {
237 .flags
= CLK_SET_RATE_PARENT
,
240 static void __init
sun4i_a10_tcon_ch0_setup(struct device_node
*node
)
242 sun4i_a10_display_init(node
, &sun4i_a10_tcon_ch0_data
);
244 CLK_OF_DECLARE(sun4i_a10_tcon_ch0
, "allwinner,sun4i-a10-tcon-ch0-clk",
245 sun4i_a10_tcon_ch0_setup
);
247 static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst
= {
259 static void __init
sun4i_a10_display_setup(struct device_node
*node
)
261 sun4i_a10_display_init(node
, &sun4i_a10_display_data
);
263 CLK_OF_DECLARE(sun4i_a10_display
, "allwinner,sun4i-a10-display-clk",
264 sun4i_a10_display_setup
);