PageRenderTime 38ms CodeModel.GetById 25ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/sh/intc/access.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 237 lines | 194 code | 31 blank | 12 comment | 6 complexity | a30c61ddc248b5ee179e466cdd7e01e5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  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
 14unsigned 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
 39unsigned 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
 54unsigned 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
 66unsigned 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
 75static 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
 81static 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
 87static 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
 93static 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
101static 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
109static 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
117static 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
130static 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
143static 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
156static 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
166static 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
176static 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
186unsigned 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
200unsigned 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
213unsigned 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
226unsigned 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};