Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / arch / arm / mach-pxa / mfp.c
1 /*
2  * linux/arch/arm/mach-pxa/mfp.c
3  *
4  * PXA3xx Multi-Function Pin Support
5  *
6  * Copyright (C) 2007 Marvell Internation Ltd.
7  *
8  * 2007-08-21: eric miao <eric.miao@marvell.com>
9  *             initial version
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 2 as
13  *  published by the Free Software Foundation.
14  */
15
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/io.h>
20
21 #include <asm/hardware.h>
22 #include <asm/arch/mfp.h>
23
24 /* mfp_spin_lock is used to ensure that MFP register configuration
25  * (most likely a read-modify-write operation) is atomic, and that
26  * mfp_table[] is consistent
27  */
28 static DEFINE_SPINLOCK(mfp_spin_lock);
29
30 static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
31 static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
32
33 #define mfpr_readl(off)                 \
34         __raw_readl(mfpr_mmio_base + (off))
35
36 #define mfpr_writel(off, val)           \
37         __raw_writel(val, mfpr_mmio_base + (off))
38
39 /*
40  * perform a read-back of any MFPR register to make sure the
41  * previous writings are finished
42  */
43 #define mfpr_sync()     (void)__raw_readl(mfpr_mmio_base + 0)
44
45 static inline void __mfp_config(int pin, unsigned long val)
46 {
47         unsigned long off = mfp_table[pin].mfpr_off;
48
49         mfp_table[pin].mfpr_val = val;
50         mfpr_writel(off, val);
51 }
52
53 void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
54 {
55         int i, pin;
56         unsigned long val, flags;
57         mfp_cfg_t *mfp_cfg = mfp_cfgs;
58
59         spin_lock_irqsave(&mfp_spin_lock, flags);
60
61         for (i = 0; i < num; i++, mfp_cfg++) {
62                 pin = MFP_CFG_PIN(*mfp_cfg);
63                 val = MFP_CFG_VAL(*mfp_cfg);
64
65                 BUG_ON(pin >= MFP_PIN_MAX);
66
67                 __mfp_config(pin, val);
68         }
69
70         mfpr_sync();
71         spin_unlock_irqrestore(&mfp_spin_lock, flags);
72 }
73
74 unsigned long pxa3xx_mfp_read(int mfp)
75 {
76         unsigned long val, flags;
77
78         BUG_ON(mfp >= MFP_PIN_MAX);
79
80         spin_lock_irqsave(&mfp_spin_lock, flags);
81         val = mfpr_readl(mfp_table[mfp].mfpr_off);
82         spin_unlock_irqrestore(&mfp_spin_lock, flags);
83
84         return val;
85 }
86
87 void pxa3xx_mfp_write(int mfp, unsigned long val)
88 {
89         unsigned long flags;
90
91         BUG_ON(mfp >= MFP_PIN_MAX);
92
93         spin_lock_irqsave(&mfp_spin_lock, flags);
94         mfpr_writel(mfp_table[mfp].mfpr_off, val);
95         mfpr_sync();
96         spin_unlock_irqrestore(&mfp_spin_lock, flags);
97 }
98
99 void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
100 {
101         uint32_t mfpr_off, mfpr_val;
102         unsigned long flags;
103
104         BUG_ON(mfp >= MFP_PIN_MAX);
105
106         spin_lock_irqsave(&mfp_spin_lock, flags);
107         mfpr_off = mfp_table[mfp].mfpr_off;
108
109         mfpr_val = mfpr_readl(mfpr_off);
110         mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK);
111         mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) |
112                      ((ds & 0x7) << MFPR_DRV_OFFSET));
113
114         mfpr_writel(mfpr_off, mfpr_val);
115         mfpr_sync();
116
117         spin_unlock_irqrestore(&mfp_spin_lock, flags);
118 }
119
120 void pxa3xx_mfp_set_rdh(int mfp, int rdh)
121 {
122         uint32_t mfpr_off, mfpr_val;
123         unsigned long flags;
124
125         BUG_ON(mfp >= MFP_PIN_MAX);
126
127         spin_lock_irqsave(&mfp_spin_lock, flags);
128
129         mfpr_off = mfp_table[mfp].mfpr_off;
130
131         mfpr_val = mfpr_readl(mfpr_off);
132         mfpr_val &= ~MFPR_RDH_MASK;
133
134         if (likely(rdh))
135                 mfpr_val |= (1u << MFPR_SS_OFFSET);
136
137         mfpr_writel(mfpr_off, mfpr_val);
138         mfpr_sync();
139
140         spin_unlock_irqrestore(&mfp_spin_lock, flags);
141 }
142
143 void pxa3xx_mfp_set_lpm(int mfp, int lpm)
144 {
145         uint32_t mfpr_off, mfpr_val;
146         unsigned long flags;
147
148         BUG_ON(mfp >= MFP_PIN_MAX);
149
150         spin_lock_irqsave(&mfp_spin_lock, flags);
151
152         mfpr_off = mfp_table[mfp].mfpr_off;
153         mfpr_val = mfpr_readl(mfpr_off);
154         mfpr_val &= ~MFPR_LPM_MASK;
155
156         if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET;
157         if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET;
158         if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET;
159         if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET;
160         if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET;
161
162         mfpr_writel(mfpr_off, mfpr_val);
163         mfpr_sync();
164
165         spin_unlock_irqrestore(&mfp_spin_lock, flags);
166 }
167
168 void pxa3xx_mfp_set_pull(int mfp, int pull)
169 {
170         uint32_t mfpr_off, mfpr_val;
171         unsigned long flags;
172
173         BUG_ON(mfp >= MFP_PIN_MAX);
174
175         spin_lock_irqsave(&mfp_spin_lock, flags);
176
177         mfpr_off = mfp_table[mfp].mfpr_off;
178         mfpr_val = mfpr_readl(mfpr_off);
179         mfpr_val &= ~MFPR_PULL_MASK;
180         mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET);
181
182         mfpr_writel(mfpr_off, mfpr_val);
183         mfpr_sync();
184
185         spin_unlock_irqrestore(&mfp_spin_lock, flags);
186 }
187
188 void pxa3xx_mfp_set_edge(int mfp, int edge)
189 {
190         uint32_t mfpr_off, mfpr_val;
191         unsigned long flags;
192
193         BUG_ON(mfp >= MFP_PIN_MAX);
194
195         spin_lock_irqsave(&mfp_spin_lock, flags);
196
197         mfpr_off = mfp_table[mfp].mfpr_off;
198         mfpr_val = mfpr_readl(mfpr_off);
199
200         mfpr_val &= ~MFPR_EDGE_MASK;
201         mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
202         mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
203
204         mfpr_writel(mfpr_off, mfpr_val);
205         mfpr_sync();
206
207         spin_unlock_irqrestore(&mfp_spin_lock, flags);
208 }
209
210 void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
211 {
212         struct pxa3xx_mfp_addr_map *p;
213         unsigned long offset, flags;
214         int i;
215
216         spin_lock_irqsave(&mfp_spin_lock, flags);
217
218         for (p = map; p->start != MFP_PIN_INVALID; p++) {
219                 offset = p->offset;
220                 i = p->start;
221
222                 do {
223                         mfp_table[i].mfpr_off = offset;
224                         mfp_table[i].mfpr_val = 0;
225                         offset += 4; i++;
226                 } while ((i <= p->end) && (p->end != -1));
227         }
228
229         spin_unlock_irqrestore(&mfp_spin_lock, flags);
230 }
231
232 void __init pxa3xx_init_mfp(void)
233 {
234         memset(mfp_table, 0, sizeof(mfp_table));
235 }