2 * linux/arch/arm/mach-pxa/mfp.c
4 * PXA3xx Multi-Function Pin Support
6 * Copyright (C) 2007 Marvell Internation Ltd.
8 * 2007-08-21: eric miao <eric.miao@marvell.com>
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.
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
21 #include <asm/hardware.h>
22 #include <asm/arch/mfp.h>
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
28 static DEFINE_SPINLOCK(mfp_spin_lock
);
30 static void __iomem
*mfpr_mmio_base
= (void __iomem
*)&__REG(MFPR_BASE
);
31 static struct pxa3xx_mfp_pin mfp_table
[MFP_PIN_MAX
];
33 #define mfpr_readl(off) \
34 __raw_readl(mfpr_mmio_base + (off))
36 #define mfpr_writel(off, val) \
37 __raw_writel(val, mfpr_mmio_base + (off))
40 * perform a read-back of any MFPR register to make sure the
41 * previous writings are finished
43 #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)
45 static inline void __mfp_config(int pin
, unsigned long val
)
47 unsigned long off
= mfp_table
[pin
].mfpr_off
;
49 mfp_table
[pin
].mfpr_val
= val
;
50 mfpr_writel(off
, val
);
53 void pxa3xx_mfp_config(mfp_cfg_t
*mfp_cfgs
, int num
)
56 unsigned long val
, flags
;
57 mfp_cfg_t
*mfp_cfg
= mfp_cfgs
;
59 spin_lock_irqsave(&mfp_spin_lock
, flags
);
61 for (i
= 0; i
< num
; i
++, mfp_cfg
++) {
62 pin
= MFP_CFG_PIN(*mfp_cfg
);
63 val
= MFP_CFG_VAL(*mfp_cfg
);
65 BUG_ON(pin
>= MFP_PIN_MAX
);
67 __mfp_config(pin
, val
);
71 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
74 unsigned long pxa3xx_mfp_read(int mfp
)
76 unsigned long val
, flags
;
78 BUG_ON(mfp
>= MFP_PIN_MAX
);
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
);
87 void pxa3xx_mfp_write(int mfp
, unsigned long val
)
91 BUG_ON(mfp
>= MFP_PIN_MAX
);
93 spin_lock_irqsave(&mfp_spin_lock
, flags
);
94 mfpr_writel(mfp_table
[mfp
].mfpr_off
, val
);
96 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
99 void pxa3xx_mfp_set_afds(int mfp
, int af
, int ds
)
101 uint32_t mfpr_off
, mfpr_val
;
104 BUG_ON(mfp
>= MFP_PIN_MAX
);
106 spin_lock_irqsave(&mfp_spin_lock
, flags
);
107 mfpr_off
= mfp_table
[mfp
].mfpr_off
;
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
));
114 mfpr_writel(mfpr_off
, mfpr_val
);
117 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
120 void pxa3xx_mfp_set_rdh(int mfp
, int rdh
)
122 uint32_t mfpr_off
, mfpr_val
;
125 BUG_ON(mfp
>= MFP_PIN_MAX
);
127 spin_lock_irqsave(&mfp_spin_lock
, flags
);
129 mfpr_off
= mfp_table
[mfp
].mfpr_off
;
131 mfpr_val
= mfpr_readl(mfpr_off
);
132 mfpr_val
&= ~MFPR_RDH_MASK
;
135 mfpr_val
|= (1u << MFPR_SS_OFFSET
);
137 mfpr_writel(mfpr_off
, mfpr_val
);
140 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
143 void pxa3xx_mfp_set_lpm(int mfp
, int lpm
)
145 uint32_t mfpr_off
, mfpr_val
;
148 BUG_ON(mfp
>= MFP_PIN_MAX
);
150 spin_lock_irqsave(&mfp_spin_lock
, flags
);
152 mfpr_off
= mfp_table
[mfp
].mfpr_off
;
153 mfpr_val
= mfpr_readl(mfpr_off
);
154 mfpr_val
&= ~MFPR_LPM_MASK
;
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
;
162 mfpr_writel(mfpr_off
, mfpr_val
);
165 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
168 void pxa3xx_mfp_set_pull(int mfp
, int pull
)
170 uint32_t mfpr_off
, mfpr_val
;
173 BUG_ON(mfp
>= MFP_PIN_MAX
);
175 spin_lock_irqsave(&mfp_spin_lock
, flags
);
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
);
182 mfpr_writel(mfpr_off
, mfpr_val
);
185 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
188 void pxa3xx_mfp_set_edge(int mfp
, int edge
)
190 uint32_t mfpr_off
, mfpr_val
;
193 BUG_ON(mfp
>= MFP_PIN_MAX
);
195 spin_lock_irqsave(&mfp_spin_lock
, flags
);
197 mfpr_off
= mfp_table
[mfp
].mfpr_off
;
198 mfpr_val
= mfpr_readl(mfpr_off
);
200 mfpr_val
&= ~MFPR_EDGE_MASK
;
201 mfpr_val
|= (edge
& 0x3u
) << MFPR_ERE_OFFSET
;
202 mfpr_val
|= (!edge
& 0x1) << MFPR_EC_OFFSET
;
204 mfpr_writel(mfpr_off
, mfpr_val
);
207 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
210 void __init
pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map
*map
)
212 struct pxa3xx_mfp_addr_map
*p
;
213 unsigned long offset
, flags
;
216 spin_lock_irqsave(&mfp_spin_lock
, flags
);
218 for (p
= map
; p
->start
!= MFP_PIN_INVALID
; p
++) {
223 mfp_table
[i
].mfpr_off
= offset
;
224 mfp_table
[i
].mfpr_val
= 0;
226 } while ((i
<= p
->end
) && (p
->end
!= -1));
229 spin_unlock_irqrestore(&mfp_spin_lock
, flags
);
232 void __init
pxa3xx_init_mfp(void)
234 memset(mfp_table
, 0, sizeof(mfp_table
));