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
{
41 struct reset_controller_dev rcdev
;
45 static DEFINE_SPINLOCK(sun4i_a10_display_lock
);
47 static inline struct reset_data
*rcdev_to_reset_data(struct reset_controller_dev
*rcdev
)
49 return container_of(rcdev
, struct reset_data
, rcdev
);
52 static int sun4i_a10_display_assert(struct reset_controller_dev
*rcdev
,
55 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
59 spin_lock_irqsave(data
->lock
, flags
);
61 reg
= readl(data
->reg
);
62 writel(reg
& ~BIT(data
->offset
+ id
), data
->reg
);
64 spin_unlock_irqrestore(data
->lock
, flags
);
69 static int sun4i_a10_display_deassert(struct reset_controller_dev
*rcdev
,
72 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
76 spin_lock_irqsave(data
->lock
, flags
);
78 reg
= readl(data
->reg
);
79 writel(reg
| BIT(data
->offset
+ id
), data
->reg
);
81 spin_unlock_irqrestore(data
->lock
, flags
);
86 static int sun4i_a10_display_status(struct reset_controller_dev
*rcdev
,
89 struct reset_data
*data
= rcdev_to_reset_data(rcdev
);
91 return !(readl(data
->reg
) & BIT(data
->offset
+ id
));
94 static const struct reset_control_ops sun4i_a10_display_reset_ops
= {
95 .assert = sun4i_a10_display_assert
,
96 .deassert
= sun4i_a10_display_deassert
,
97 .status
= sun4i_a10_display_status
,
100 static int sun4i_a10_display_reset_xlate(struct reset_controller_dev
*rcdev
,
101 const struct of_phandle_args
*spec
)
103 /* We only have a single reset signal */
107 static void __init
sun4i_a10_display_init(struct device_node
*node
,
108 const struct sun4i_a10_display_clk_data
*data
)
110 const char *parents
[4];
111 const char *clk_name
= node
->name
;
112 struct reset_data
*reset_data
;
113 struct clk_divider
*div
= NULL
;
114 struct clk_gate
*gate
;
121 of_property_read_string(node
, "clock-output-names", &clk_name
);
123 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
125 pr_err("%s: Could not map the clock registers\n", clk_name
);
129 ret
= of_clk_parent_fill(node
, parents
, data
->parents
);
130 if (ret
!= data
->parents
) {
131 pr_err("%s: Could not retrieve the parents\n", clk_name
);
135 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
140 mux
->shift
= data
->offset_mux
;
141 mux
->mask
= (1 << data
->width_mux
) - 1;
142 mux
->lock
= &sun4i_a10_display_lock
;
144 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
149 gate
->bit_idx
= data
->offset_en
;
150 gate
->lock
= &sun4i_a10_display_lock
;
153 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
158 div
->shift
= data
->offset_div
;
159 div
->width
= data
->width_div
;
160 div
->lock
= &sun4i_a10_display_lock
;
163 clk
= clk_register_composite(NULL
, clk_name
,
164 parents
, data
->parents
,
165 &mux
->hw
, &clk_mux_ops
,
166 data
->has_div
? &div
->hw
: NULL
,
167 data
->has_div
? &clk_divider_ops
: NULL
,
168 &gate
->hw
, &clk_gate_ops
,
171 pr_err("%s: Couldn't register the clock\n", clk_name
);
175 ret
= of_clk_add_provider(node
, of_clk_src_simple_get
, clk
);
177 pr_err("%s: Couldn't register DT provider\n", clk_name
);
184 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
188 reset_data
->reg
= reg
;
189 reset_data
->offset
= data
->offset_rst
;
190 reset_data
->lock
= &sun4i_a10_display_lock
;
191 reset_data
->rcdev
.nr_resets
= data
->num_rst
;
192 reset_data
->rcdev
.ops
= &sun4i_a10_display_reset_ops
;
193 reset_data
->rcdev
.of_node
= node
;
195 if (data
->num_rst
== 1) {
196 reset_data
->rcdev
.of_reset_n_cells
= 0;
197 reset_data
->rcdev
.of_xlate
= &sun4i_a10_display_reset_xlate
;
199 reset_data
->rcdev
.of_reset_n_cells
= 1;
202 if (reset_controller_register(&reset_data
->rcdev
)) {
203 pr_err("%s: Couldn't register the reset controller\n",
213 of_clk_del_provider(node
);
215 clk_unregister_composite(clk
);
224 of_address_to_resource(node
, 0, &res
);
225 release_mem_region(res
.start
, resource_size(&res
));
228 static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst
= {
237 static void __init
sun4i_a10_tcon_ch0_setup(struct device_node
*node
)
239 sun4i_a10_display_init(node
, &sun4i_a10_tcon_ch0_data
);
241 CLK_OF_DECLARE(sun4i_a10_tcon_ch0
, "allwinner,sun4i-a10-tcon-ch0-clk",
242 sun4i_a10_tcon_ch0_setup
);
244 static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst
= {
256 static void __init
sun4i_a10_display_setup(struct device_node
*node
)
258 sun4i_a10_display_init(node
, &sun4i_a10_display_data
);
260 CLK_OF_DECLARE(sun4i_a10_display
, "allwinner,sun4i-a10-display-clk",
261 sun4i_a10_display_setup
);