drivers: sh: late disabling of clocks V2
[linux-3.10.git] / drivers / sh / intc / access.c
1 /*
2  * Common INTC2 register accessors
3  *
4  * Copyright (C) 2007, 2008 Magnus Damm
5  * Copyright (C) 2009, 2010 Paul Mundt
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/io.h>
12 #include "internals.h"
13
14 unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
15 {
16         struct intc_window *window;
17         int k;
18
19         /* scan through physical windows and convert address */
20         for (k = 0; k < d->nr_windows; k++) {
21                 window = d->window + k;
22
23                 if (address < window->phys)
24                         continue;
25
26                 if (address >= (window->phys + window->size))
27                         continue;
28
29                 address -= window->phys;
30                 address += (unsigned long)window->virt;
31
32                 return address;
33         }
34
35         /* no windows defined, register must be 1:1 mapped virt:phys */
36         return address;
37 }
38
39 unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
40 {
41         unsigned int k;
42
43         address = intc_phys_to_virt(d, address);
44
45         for (k = 0; k < d->nr_reg; k++) {
46                 if (d->reg[k] == address)
47                         return k;
48         }
49
50         BUG();
51         return 0;
52 }
53
54 unsigned int intc_set_field_from_handle(unsigned int value,
55                                         unsigned int field_value,
56                                         unsigned int handle)
57 {
58         unsigned int width = _INTC_WIDTH(handle);
59         unsigned int shift = _INTC_SHIFT(handle);
60
61         value &= ~(((1 << width) - 1) << shift);
62         value |= field_value << shift;
63         return value;
64 }
65
66 unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
67 {
68         unsigned int width = _INTC_WIDTH(handle);
69         unsigned int shift = _INTC_SHIFT(handle);
70         unsigned int mask = ((1 << width) - 1) << shift;
71
72         return (value & mask) >> shift;
73 }
74
75 static unsigned long test_8(unsigned long addr, unsigned long h,
76                             unsigned long ignore)
77 {
78         return intc_get_field_from_handle(__raw_readb(addr), h);
79 }
80
81 static unsigned long test_16(unsigned long addr, unsigned long h,
82                              unsigned long ignore)
83 {
84         return intc_get_field_from_handle(__raw_readw(addr), h);
85 }
86
87 static unsigned long test_32(unsigned long addr, unsigned long h,
88                              unsigned long ignore)
89 {
90         return intc_get_field_from_handle(__raw_readl(addr), h);
91 }
92
93 static unsigned long write_8(unsigned long addr, unsigned long h,
94                              unsigned long data)
95 {
96         __raw_writeb(intc_set_field_from_handle(0, data, h), addr);
97         (void)__raw_readb(addr);        /* Defeat write posting */
98         return 0;
99 }
100
101 static unsigned long write_16(unsigned long addr, unsigned long h,
102                               unsigned long data)
103 {
104         __raw_writew(intc_set_field_from_handle(0, data, h), addr);
105         (void)__raw_readw(addr);        /* Defeat write posting */
106         return 0;
107 }
108
109 static unsigned long write_32(unsigned long addr, unsigned long h,
110                               unsigned long data)
111 {
112         __raw_writel(intc_set_field_from_handle(0, data, h), addr);
113         (void)__raw_readl(addr);        /* Defeat write posting */
114         return 0;
115 }
116
117 static unsigned long modify_8(unsigned long addr, unsigned long h,
118                               unsigned long data)
119 {
120         unsigned long flags;
121         unsigned int value;
122         local_irq_save(flags);
123         value = intc_set_field_from_handle(__raw_readb(addr), data, h);
124         __raw_writeb(value, addr);
125         (void)__raw_readb(addr);        /* Defeat write posting */
126         local_irq_restore(flags);
127         return 0;
128 }
129
130 static unsigned long modify_16(unsigned long addr, unsigned long h,
131                                unsigned long data)
132 {
133         unsigned long flags;
134         unsigned int value;
135         local_irq_save(flags);
136         value = intc_set_field_from_handle(__raw_readw(addr), data, h);
137         __raw_writew(value, addr);
138         (void)__raw_readw(addr);        /* Defeat write posting */
139         local_irq_restore(flags);
140         return 0;
141 }
142
143 static unsigned long modify_32(unsigned long addr, unsigned long h,
144                                unsigned long data)
145 {
146         unsigned long flags;
147         unsigned int value;
148         local_irq_save(flags);
149         value = intc_set_field_from_handle(__raw_readl(addr), data, h);
150         __raw_writel(value, addr);
151         (void)__raw_readl(addr);        /* Defeat write posting */
152         local_irq_restore(flags);
153         return 0;
154 }
155
156 static unsigned long intc_mode_field(unsigned long addr,
157                                      unsigned long handle,
158                                      unsigned long (*fn)(unsigned long,
159                                                 unsigned long,
160                                                 unsigned long),
161                                      unsigned int irq)
162 {
163         return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
164 }
165
166 static unsigned long intc_mode_zero(unsigned long addr,
167                                     unsigned long handle,
168                                     unsigned long (*fn)(unsigned long,
169                                                unsigned long,
170                                                unsigned long),
171                                     unsigned int irq)
172 {
173         return fn(addr, handle, 0);
174 }
175
176 static unsigned long intc_mode_prio(unsigned long addr,
177                                     unsigned long handle,
178                                     unsigned long (*fn)(unsigned long,
179                                                unsigned long,
180                                                unsigned long),
181                                     unsigned int irq)
182 {
183         return fn(addr, handle, intc_get_prio_level(irq));
184 }
185
186 unsigned long (*intc_reg_fns[])(unsigned long addr,
187                                 unsigned long h,
188                                 unsigned long data) = {
189         [REG_FN_TEST_BASE + 0] = test_8,
190         [REG_FN_TEST_BASE + 1] = test_16,
191         [REG_FN_TEST_BASE + 3] = test_32,
192         [REG_FN_WRITE_BASE + 0] = write_8,
193         [REG_FN_WRITE_BASE + 1] = write_16,
194         [REG_FN_WRITE_BASE + 3] = write_32,
195         [REG_FN_MODIFY_BASE + 0] = modify_8,
196         [REG_FN_MODIFY_BASE + 1] = modify_16,
197         [REG_FN_MODIFY_BASE + 3] = modify_32,
198 };
199
200 unsigned long (*intc_enable_fns[])(unsigned long addr,
201                                    unsigned long handle,
202                                    unsigned long (*fn)(unsigned long,
203                                             unsigned long,
204                                             unsigned long),
205                                    unsigned int irq) = {
206         [MODE_ENABLE_REG] = intc_mode_field,
207         [MODE_MASK_REG] = intc_mode_zero,
208         [MODE_DUAL_REG] = intc_mode_field,
209         [MODE_PRIO_REG] = intc_mode_prio,
210         [MODE_PCLR_REG] = intc_mode_prio,
211 };
212
213 unsigned long (*intc_disable_fns[])(unsigned long addr,
214                                     unsigned long handle,
215                                     unsigned long (*fn)(unsigned long,
216                                              unsigned long,
217                                              unsigned long),
218                                     unsigned int irq) = {
219         [MODE_ENABLE_REG] = intc_mode_zero,
220         [MODE_MASK_REG] = intc_mode_field,
221         [MODE_DUAL_REG] = intc_mode_field,
222         [MODE_PRIO_REG] = intc_mode_zero,
223         [MODE_PCLR_REG] = intc_mode_field,
224 };
225
226 unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
227                                           unsigned long handle,
228                                           unsigned long (*fn)(unsigned long,
229                                                 unsigned long,
230                                                 unsigned long),
231                                           unsigned int irq) = {
232         [MODE_ENABLE_REG] = intc_mode_field,
233         [MODE_MASK_REG] = intc_mode_zero,
234         [MODE_DUAL_REG] = intc_mode_field,
235         [MODE_PRIO_REG] = intc_mode_field,
236         [MODE_PCLR_REG] = intc_mode_field,
237 };