Commit | Line | Data |
---|---|---|
47dd7a54 GC |
1 | /******************************************************************************* |
2 | STMMAC external timer support. | |
3 | ||
4 | Copyright (C) 2007-2009 STMicroelectronics Ltd | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify it | |
7 | under the terms and conditions of the GNU General Public License, | |
8 | version 2, as published by the Free Software Foundation. | |
9 | ||
10 | This program is distributed in the hope it will be useful, but WITHOUT | |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License along with | |
16 | this program; if not, write to the Free Software Foundation, Inc., | |
17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | ||
19 | The full GNU General Public License is included in this distribution in | |
20 | the file called "COPYING". | |
21 | ||
22 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> | |
23 | *******************************************************************************/ | |
24 | ||
25 | #include <linux/kernel.h> | |
26 | #include <linux/etherdevice.h> | |
27 | #include "stmmac_timer.h" | |
28 | ||
29 | static void stmmac_timer_handler(void *data) | |
30 | { | |
31 | struct net_device *dev = (struct net_device *)data; | |
32 | ||
33 | stmmac_schedule(dev); | |
47dd7a54 GC |
34 | } |
35 | ||
36 | #define STMMAC_TIMER_MSG(timer, freq) \ | |
37 | printk(KERN_INFO "stmmac_timer: %s Timer ON (freq %dHz)\n", timer, freq); | |
38 | ||
39 | #if defined(CONFIG_STMMAC_RTC_TIMER) | |
40 | #include <linux/rtc.h> | |
41 | static struct rtc_device *stmmac_rtc; | |
42 | static rtc_task_t stmmac_task; | |
43 | ||
44 | static void stmmac_rtc_start(unsigned int new_freq) | |
45 | { | |
46 | rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq); | |
47 | rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1); | |
47dd7a54 GC |
48 | } |
49 | ||
50 | static void stmmac_rtc_stop(void) | |
51 | { | |
52 | rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0); | |
47dd7a54 GC |
53 | } |
54 | ||
55 | int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) | |
56 | { | |
57 | stmmac_task.private_data = dev; | |
58 | stmmac_task.func = stmmac_timer_handler; | |
59 | ||
60 | stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); | |
61 | if (stmmac_rtc == NULL) { | |
e6e3625f | 62 | pr_err("open rtc device failed\n"); |
47dd7a54 GC |
63 | return -ENODEV; |
64 | } | |
65 | ||
66 | rtc_irq_register(stmmac_rtc, &stmmac_task); | |
67 | ||
68 | /* Periodic mode is not supported */ | |
69 | if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) { | |
e6e3625f | 70 | pr_err("set periodic failed\n"); |
47dd7a54 GC |
71 | rtc_irq_unregister(stmmac_rtc, &stmmac_task); |
72 | rtc_class_close(stmmac_rtc); | |
73 | return -1; | |
74 | } | |
75 | ||
76 | STMMAC_TIMER_MSG(CONFIG_RTC_HCTOSYS_DEVICE, tm->freq); | |
77 | ||
78 | tm->timer_start = stmmac_rtc_start; | |
79 | tm->timer_stop = stmmac_rtc_stop; | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | int stmmac_close_ext_timer(void) | |
85 | { | |
86 | rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0); | |
87 | rtc_irq_unregister(stmmac_rtc, &stmmac_task); | |
88 | rtc_class_close(stmmac_rtc); | |
89 | return 0; | |
90 | } | |
91 | ||
92 | #elif defined(CONFIG_STMMAC_TMU_TIMER) | |
93 | #include <linux/clk.h> | |
94 | #define TMU_CHANNEL "tmu2_clk" | |
95 | static struct clk *timer_clock; | |
96 | ||
97 | static void stmmac_tmu_start(unsigned int new_freq) | |
98 | { | |
99 | clk_set_rate(timer_clock, new_freq); | |
100 | clk_enable(timer_clock); | |
47dd7a54 GC |
101 | } |
102 | ||
103 | static void stmmac_tmu_stop(void) | |
104 | { | |
105 | clk_disable(timer_clock); | |
47dd7a54 GC |
106 | } |
107 | ||
108 | int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) | |
109 | { | |
110 | timer_clock = clk_get(NULL, TMU_CHANNEL); | |
111 | ||
112 | if (timer_clock == NULL) | |
113 | return -1; | |
114 | ||
115 | if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) { | |
116 | timer_clock = NULL; | |
117 | return -1; | |
118 | } | |
119 | ||
120 | STMMAC_TIMER_MSG("TMU2", tm->freq); | |
121 | tm->timer_start = stmmac_tmu_start; | |
122 | tm->timer_stop = stmmac_tmu_stop; | |
123 | ||
124 | return 0; | |
125 | } | |
126 | ||
127 | int stmmac_close_ext_timer(void) | |
128 | { | |
129 | clk_disable(timer_clock); | |
130 | tmu2_unregister_user(); | |
131 | clk_put(timer_clock); | |
132 | return 0; | |
133 | } | |
134 | #endif |