]> Git Repo - J-linux.git/blob - drivers/clocksource/timer-of.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / clocksource / timer-of.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2017, Linaro Ltd.  All rights reserved.
4  *
5  * Author: Daniel Lezcano <[email protected]>
6  */
7 #include <linux/clk.h>
8 #include <linux/interrupt.h>
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/of_irq.h>
12 #include <linux/slab.h>
13
14 #include "timer-of.h"
15
16 /**
17  * timer_of_irq_exit - Release the interrupt
18  * @of_irq: an of_timer_irq structure pointer
19  *
20  * Free the irq resource
21  */
22 static __init void timer_of_irq_exit(struct of_timer_irq *of_irq)
23 {
24         struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
25
26         struct clock_event_device *clkevt = &to->clkevt;
27
28         free_irq(of_irq->irq, clkevt);
29 }
30
31 /**
32  * timer_of_irq_init - Request the interrupt
33  * @np: a device tree node pointer
34  * @of_irq: an of_timer_irq structure pointer
35  *
36  * Get the interrupt number from the DT from its definition and
37  * request it. The interrupt is gotten by falling back the following way:
38  *
39  * - Get interrupt number by name
40  * - Get interrupt number by index
41  *
42  * Returns 0 on success, < 0 otherwise
43  */
44 static __init int timer_of_irq_init(struct device_node *np,
45                                     struct of_timer_irq *of_irq)
46 {
47         int ret;
48         struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
49         struct clock_event_device *clkevt = &to->clkevt;
50
51         if (of_irq->name) {
52                 of_irq->irq = ret = of_irq_get_byname(np, of_irq->name);
53                 if (ret < 0) {
54                         pr_err("Failed to get interrupt %s for %pOF\n",
55                                of_irq->name, np);
56                         return ret;
57                 }
58         } else  {
59                 of_irq->irq = irq_of_parse_and_map(np, of_irq->index);
60         }
61         if (!of_irq->irq) {
62                 pr_err("Failed to map interrupt for %pOF\n", np);
63                 return -EINVAL;
64         }
65
66         ret = request_irq(of_irq->irq, of_irq->handler,
67                           of_irq->flags ? of_irq->flags : IRQF_TIMER,
68                           np->full_name, clkevt);
69         if (ret) {
70                 pr_err("Failed to request irq %d for %pOF\n", of_irq->irq, np);
71                 return ret;
72         }
73
74         clkevt->irq = of_irq->irq;
75
76         return 0;
77 }
78
79 /**
80  * timer_of_clk_exit - Release the clock resources
81  * @of_clk: a of_timer_clk structure pointer
82  *
83  * Disables and releases the refcount on the clk
84  */
85 static __init void timer_of_clk_exit(struct of_timer_clk *of_clk)
86 {
87         of_clk->rate = 0;
88         clk_disable_unprepare(of_clk->clk);
89         clk_put(of_clk->clk);
90 }
91
92 /**
93  * timer_of_clk_init - Initialize the clock resources
94  * @np: a device tree node pointer
95  * @of_clk: a of_timer_clk structure pointer
96  *
97  * Get the clock by name or by index, enable it and get the rate
98  *
99  * Returns 0 on success, < 0 otherwise
100  */
101 static __init int timer_of_clk_init(struct device_node *np,
102                                     struct of_timer_clk *of_clk)
103 {
104         int ret;
105
106         of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) :
107                 of_clk_get(np, of_clk->index);
108         if (IS_ERR(of_clk->clk)) {
109                 ret = PTR_ERR(of_clk->clk);
110                 if (ret != -EPROBE_DEFER)
111                         pr_err("Failed to get clock for %pOF\n", np);
112                 goto out;
113         }
114
115         ret = clk_prepare_enable(of_clk->clk);
116         if (ret) {
117                 pr_err("Failed for enable clock for %pOF\n", np);
118                 goto out_clk_put;
119         }
120
121         of_clk->rate = clk_get_rate(of_clk->clk);
122         if (!of_clk->rate) {
123                 ret = -EINVAL;
124                 pr_err("Failed to get clock rate for %pOF\n", np);
125                 goto out_clk_disable;
126         }
127
128         of_clk->period = DIV_ROUND_UP(of_clk->rate, HZ);
129 out:
130         return ret;
131
132 out_clk_disable:
133         clk_disable_unprepare(of_clk->clk);
134 out_clk_put:
135         clk_put(of_clk->clk);
136
137         goto out;
138 }
139
140 static __init void timer_of_base_exit(struct of_timer_base *of_base)
141 {
142         iounmap(of_base->base);
143 }
144
145 static __init int timer_of_base_init(struct device_node *np,
146                                      struct of_timer_base *of_base)
147 {
148         of_base->base = of_base->name ?
149                 of_io_request_and_map(np, of_base->index, of_base->name) :
150                 of_iomap(np, of_base->index);
151         if (IS_ERR_OR_NULL(of_base->base)) {
152                 pr_err("Failed to iomap (%s:%s)\n", np->name, of_base->name);
153                 return of_base->base ? PTR_ERR(of_base->base) : -ENOMEM;
154         }
155
156         return 0;
157 }
158
159 int __init timer_of_init(struct device_node *np, struct timer_of *to)
160 {
161         int ret = -EINVAL;
162         int flags = 0;
163
164         if (to->flags & TIMER_OF_BASE) {
165                 ret = timer_of_base_init(np, &to->of_base);
166                 if (ret)
167                         goto out_fail;
168                 flags |= TIMER_OF_BASE;
169         }
170
171         if (to->flags & TIMER_OF_CLOCK) {
172                 ret = timer_of_clk_init(np, &to->of_clk);
173                 if (ret)
174                         goto out_fail;
175                 flags |= TIMER_OF_CLOCK;
176         }
177
178         if (to->flags & TIMER_OF_IRQ) {
179                 ret = timer_of_irq_init(np, &to->of_irq);
180                 if (ret)
181                         goto out_fail;
182                 flags |= TIMER_OF_IRQ;
183         }
184
185         if (!to->clkevt.name)
186                 to->clkevt.name = np->full_name;
187
188         to->np = np;
189
190         return ret;
191
192 out_fail:
193         if (flags & TIMER_OF_IRQ)
194                 timer_of_irq_exit(&to->of_irq);
195
196         if (flags & TIMER_OF_CLOCK)
197                 timer_of_clk_exit(&to->of_clk);
198
199         if (flags & TIMER_OF_BASE)
200                 timer_of_base_exit(&to->of_base);
201         return ret;
202 }
203
204 /**
205  * timer_of_cleanup - release timer_of resources
206  * @to: timer_of structure
207  *
208  * Release the resources that has been used in timer_of_init().
209  * This function should be called in init error cases
210  */
211 void __init timer_of_cleanup(struct timer_of *to)
212 {
213         if (to->flags & TIMER_OF_IRQ)
214                 timer_of_irq_exit(&to->of_irq);
215
216         if (to->flags & TIMER_OF_CLOCK)
217                 timer_of_clk_exit(&to->of_clk);
218
219         if (to->flags & TIMER_OF_BASE)
220                 timer_of_base_exit(&to->of_base);
221 }
This page took 0.038081 seconds and 4 git commands to generate.