导读:
Marvell-Linux研究—mfp.c/.h源代码分析
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:李先静
更新时间:2007-7-9
Multi-Function Pin是PXA3xx中的一个新概念,它可以让一个Pin具有多个功能,达到复用的效果,从而减少PIN的个数。比如说,一个Pin可以作为GPIO,可以作为时钟信号,也可以作为地址线或者数据线,完全根据软件配置决定它的实际用途。
虽然同一个Pin可以用作多种不同的用途,但在任意时刻只有一种用途,这是很容易理解的,否则就会乱套了。但是在不同时刻,它能否根据需要动态切换Pin的功能呢?我想从理论是可行的,但对硬件设计可能有特别的要求,才能保证不会互相冲突。我在代码中没有看到这种用法,不知道实际中是否有人这样用呢。同一个Pin具有相同的配置,但是用于不同设备倒是正常的,像数据线和地址线就属此类。
下面我们来看看代码:
21 struct mhn_pin_config {
22 mfp_pin_t mfp_pin;
23 unsigned int reserved:16
24 unsigned int af_sel:3
25 unsigned int edge_rise_en:1
26 unsigned int edge_fall_en:1
27 unsigned int edge_clear:1
28 unsigned int sleep_oe_n:1
29 unsigned int sleep_data:1
30 unsigned int sleep_sel:1
31 unsigned int drive:3
32 unsigned int pulldown_en:1
33 unsigned int pullup_en:1
34 unsigned int pull_sel:1
35 };
(mfp.h)
这个结构用于描述MFP的配置,它与MFPRx寄存器中的位域基本上一一对应,这里我们简单说明一下:
mfp_pin 是MFP的ID,用宏MFP_REG以mfp_pin为参数,可以计算出mfp_pin的MFPR寄存器地址。
af_sel 其中af代表alternate function,用于选择实际的功能,它最多有八种可能的选择,可参照《PXA300 and PXA310 Developers Manual 1》的4.3/4.4节。
edge_rise_en/ edge_fall_en/ edge_clear 用于控制上升沿/下降沿中断的禁用或启用。我有点疑惑的是,如果该Pin配置为GPIO,而GPIO有自己的上升沿/下降沿配置,两者是否冲突呢?
sleep_oe_n 在低功耗模式(low power mode)下,它决定Pin作为输入还是输出,1表示输入,0表示输出。
sleep_data在低功耗模式(low power mode)下,如果作为输出,它决定输出高电平还是低电平。
sleep_sel 控制在正模式和低功耗模式之间切换时的行为。可以参考《PXA300 and PXA310 Developers Manual 1》的表4.8。
drive 控制Pin的驱动能力,可以在1mA到10mA之间调整,另外可以调整slew rate,slew rate决定电平翻转的速度。
pulldown_en/ pullup_en 是否启用内部下/上拉电阻,只有作为Input Pin时才有用。我们知道下/上拉电阻的主要目的就是防止Pin悬空,悬空的Pin可以看作一个天线,它容易受外界干扰,造成Pin值的不确实性。下/上拉电阻能够给Input Pin一个默认的输入值,下拉电阻接地,默认输入低电平,上拉电阻接电源,默认输入高电平。当真正有外接输入时,它们自动无效,同时避免短路,起到限流作用。
pull_sel 用于决定pulldown_en/ pullup_en的有效性,在低功耗模式下,pull_sel的实际值不改变,但有效值相当于1。也就是说在低功耗模式下,pulldown_en/ pullup_en的值始终决定默认输入,这可以防止干扰信号唤醒CPU。
在《PXA300 and PXA310 Developers Manual 1》的表4.6中,对pulldown_en/ pullup_en的描述是自相矛盾的,比如对pullup_en的描述,前面说,1 = The internal pullup resistor of the pad is enabled,后面又说,The resistor is only enabled if PULL_SEL=1(or is effectively 1) and if PULLUP_EN is 0。前者说1启用内部上拉电阻,后者又说0启用内部上拉电阻,我想前者是对的后者是错的。
113 #define MHN_MFP_CFG(desc, pin, af, drv, rdh, lpm, edge) / 114 { /
115 .mfp_pin = pin, /
116 .af_sel = af, /
117 .reserved = 0, /
118 .drive = drv, /
119 .sleep_sel = rdh, /
120 .sleep_oe_n = ((lpm) &0x1), /
121 .sleep_data = (((lpm) &0x2) >>1), /
122 .pullup_en = (((lpm) &0x4) >>2), /
123 .pulldown_en = (((lpm) &0x8) >>3), /
124 .pull_sel = (((lpm) &0x10) >>4), /
125 .edge_clear = (!(edge)), /
126 .edge_fall_en = ((edge) &0x1), /
127 .edge_rise_en = (((edge) &0x2) >>1), /
128 }
(mfp.h)
MHN_MFP_CFG的功能很简单,但是很常用,它简化了MFP配置的初始化。
145 #define PIN2REG(pin_config) / 146 (pin_config->af_sel <
147 (pin_config->edge_rise_en <
148 (pin_config->edge_fall_en <
149 (pin_config->edge_clear <
150 (pin_config->sleep_oe_n <
151 (pin_config->sleep_data <
152 (pin_config->sleep_sel <
153 (pin_config->drive <
154 (pin_config->pulldown_en <
155 (pin_config->pullup_en <
156 (pin_config->pull_sel < (mfp.h)
这个宏也很常用,它把mhn_pin_config结构转换成MFPR寄存器的格式,这样就可以直接写入MFPR寄存器了。
44 int mhn_mfp_set_config( struct mhn_pin_config *pin_config)
45 {
46 unsigned long flags;
47 mfp_pin_t mfp_pin;
48 uint32_t mfp_reg;
49
50 spin_lock_irqsave(&mfp_spin_lock, flags);
51
52 mfp_pin = pin_config->mfp_pin;
53 mfp_reg = PIN2REG(pin_config);
54
55 #if defined(CONFIG_MONAHANS_GPIOEX)
56 if (IS_GPIO_EXP_PIN(mfp_pin)){
57 spin_unlock_irqrestore(&mfp_spin_lock, flags);
58 return 0
59 }
60 #endif
61
62 #ifdef CONFIG_MFP_DEBUG
63 if ((pin_config == NULL) ||
64 (MFP_OFFSET(mfp_pin) >MHN_MAX_MFP_OFFSET) ||
65 (MFP_OFFSET(mfp_pin)
66 spin_unlock_irqrestore(&mfp_spin_lock, flags);
67 return -1
68 }
69 #endif
70
71 MFP_REG(mfp_pin) = mfp_reg;
72 mfp_reg = MFP_REG(mfp_pin); /* read back */
73
74 spin_unlock_irqrestore(&mfp_spin_lock, flags);
75
76 return 0
77 }
该函数让配置生效,它先用PIN2REG把配置转换成寄存器的格式,然后用MFP_REG得到Pin对应的寄存器,并把值写入寄存器,最后为了确保写入操作完成,再把寄存器的值读回来。通过回读的方式确保写操作完成,在多级流水线的CPU中是常用的手法。
120 int mhn_mfp_set_afds(mfp_pin_t pin, int af, int ds)
121 {
122 unsigned long flags;
123 uint32_t mfp_reg;
124
125 #if defined(CONFIG_MONAHANS_GPIOEX)
126 if (IS_GPIO_EXP_PIN(pin))
127 return 0
128 #endif
129
130 #ifdef CONFIG_MFP_DEBUG
131 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
132 (MFP_OFFSET(pin)
133 return -1
134 #endif
135
136 spin_lock_irqsave(&mfp_spin_lock, flags);
137
138 mfp_reg = MFP_REG(pin);
139 mfp_reg &= ~(MFP_AF_MASK | MFP_DRV_MASK);
140 mfp_reg |= (((af &0x7) <
141 ((ds &0x7) <
142 MFP_REG(pin) = mfp_reg;
143 mfp_reg = MFP_REG(pin);
144
145 spin_unlock_irqrestore(&mfp_spin_lock, flags);
146
147 return 0
148 }
这里只要明白AF代表Alternate Function,而ds代表drive strength,就明白这个函数的功能了,它就是用来设置Pin的可选功能和驱动能力的。其实现与mhn_mfp_set_config类似,但它只修改部分设置,所以要先读取原来的设置,修改它并写回去,最后再读回来以确认设置完成。
150 int mhn_mfp_set_rdh(mfp_pin_t pin, int rdh)
151 {
152 unsigned long flags;
153 uint32_t mfp_reg;
154
155 #if defined(CONFIG_MONAHANS_GPIOEX)
156 if (IS_GPIO_EXP_PIN(pin))
157 return 0
158 #endif
159
160 #ifdef CONFIG_MFP_DEBUG
161 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
162 (MFP_OFFSET(pin)
163 return -1
164 #endif
165
166 spin_lock_irqsave(&mfp_spin_lock, flags);
167
168 mfp_reg = MFP_REG(pin);
169 mfp_reg &= ~MFP_RDH_MASK;
170
171 if (likely(rdh))
172 mfp_reg |= (1u <
173
174 MFP_REG(pin) = mfp_reg;
175 mfp_reg = MFP_REG(pin);
176
177 spin_unlock_irqrestore(&mfp_spin_lock, flags);
178
179 return 0
180 }
这里其实它并不是修改ASCR[RDH],而是修改SLEEP_SEL,因为SLEEP_SEL决定ASCR[RDH]的值是否有效,具体方法与前面类似。RDH意义暂时还不完全明白,以后再补充吧。
182 int mhn_mfp_set_lpm(mfp_pin_t pin, int lpm)
183 {
184 unsigned long flags;
185 uint32_t mfp_reg;
186
187 #if defined(CONFIG_MONAHANS_GPIOEX)
188 if (IS_GPIO_EXP_PIN(pin))
189 return 0
190 #endif
191
192 #ifdef CONFIG_MFP_DEBUG
193 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
194 (MFP_OFFSET(pin)
195 return -1
196 #endif
197 spin_lock_irqsave(&mfp_spin_lock, flags);
198
199 mfp_reg = MFP_REG(pin);
200 mfp_reg &= ~(MFP_LPM_MASK);
201
202 if (lpm &0x1) mfp_reg |= 1u <
203 if (lpm &0x2) mfp_reg |= 1u <
204 if (lpm &0x4) mfp_reg |= 1u <
205 if (lpm &0x8) mfp_reg |= 1u <
206 if (lpm &0x10) mfp_reg |= 1u <
207
208 MFP_REG(pin) = mfp_reg;
209 mfp_reg = MFP_REG(pin);
210
211 spin_unlock_irqrestore(&mfp_spin_lock, flags);
212
213 return 0
214 }
这里的lpm代表low power mode,它用来设置低功耗模式下的配置,包括数据方向是输出还是输入,输出的数据和输入的默认值等。
216 int mhn_mfp_set_edge(mfp_pin_t pin, int edge)
217 {
218 unsigned long flags;
219 uint32_t mfp_reg;
220
221 #if defined(CONFIG_MONAHANS_GPIOEX)
222 if (IS_GPIO_EXP_PIN(pin))
223 return 0
224 #endif
225
226 #ifdef CONFIG_MFP_DEBUG
227 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
228 (MFP_OFFSET(pin)
229 return -1
230 #endif
231 spin_lock_irqsave(&mfp_spin_lock, flags);
232
233 mfp_reg = MFP_REG(pin);
234
235 /* Clear bits - EDGE_CLEAR, EDGE_RISE_EN, EDGE_FALL_EN */
236 mfp_reg &= ~(MFP_EDGE_MASK);
237
238 switch (edge) {
239 case MFP_EDGE_RISE:
240 mfp_reg |= (1u <
241 break
242 case MFP_EDGE_FALL:
243 mfp_reg |= (1u <
244 break
245 case MFP_EDGE_BOTH:
246 mfp_reg |= (3u <
247 break
248 case MFP_EDGE_NONE:
249 mfp_reg |= (1u <
250 break
251 default:
252 spin_unlock_irqrestore(&mfp_spin_lock, flags);
253 return -EINVAL
254 }
255
256 MFP_REG(pin) = mfp_reg;
257 mfp_reg = MFP_REG(pin);
258
259 spin_unlock_irqrestore(&mfp_spin_lock, flags);
260
261 return 0
262 }
设置电平切换检查,可以在上升沿检查,可以在下降沿检查,可以两者都检查,或者都不检查,后者设置EDGE_CLEAR位。
270 int mhn_mfp_set_pull(mfp_pin_t pin, int pull)
271 {
272 unsigned long flags;
273 uint32_t mfp_reg;
274
275 #if defined(CONFIG_MONAHANS_GPIOEX)
276 if (IS_GPIO_EXP_PIN(pin))
277 return 0
278 #endif
279
280 #ifdef CONFIG_MFP_DEBUG
281 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
282 (MFP_OFFSET(pin)
283 return -1
284 #endif
285 spin_lock_irqsave(&mfp_spin_lock, flags);
286
287 mfp_reg = MFP_REG(pin);
288 mfp_reg &= ~MFP_PULL_MASK;
289
290 mfp_reg |= (pull &0x7u) <
291
292 MFP_REG(pin) = mfp_reg;
293 mfp_reg = MFP_REG(pin);
294
295 spin_unlock_irqrestore(&mfp_spin_lock, flags);
296
297 return 0
298 }
启用/禁用内部上/下拉电阻,给Input Pin设置默认值。
300 static struct mfp_regs context;
301 void mhn_mfp_save( void)
302 {
303 int i, offset;
304
305 /* specify the membase */
306 context.membase = ( unsigned char *)KSEG0(PADBASE);
307
308 for (i = 0i 309 offset = i <<2
310 context.mfp[i] = readl(context.membase + offset);
311 }
312 }
313
314 void mhn_mfp_restore( void)
315 {
316 int i, offset;
317
318 /* check the membase */
319 if (context.membase == NULL)
320 return
321
322 for (i = 0i 323 offset = i <<2
324 writel(context.mfp[i], context.membase + offset);
325 }
326 }
保存和恢复MFP的设置,供电源管理在系统Suspend和Resume时调用,因为寄存器是连接的,所以其实现很简单。
~~end~~
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1683936
本文转自
http://blog.csdn.net/absurd/archive/2007/07/09/1683936.aspx
Marvell-Linux研究—mfp.c/.h源代码分析
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:李先静
更新时间:2007-7-9
Multi-Function Pin是PXA3xx中的一个新概念,它可以让一个Pin具有多个功能,达到复用的效果,从而减少PIN的个数。比如说,一个Pin可以作为GPIO,可以作为时钟信号,也可以作为地址线或者数据线,完全根据软件配置决定它的实际用途。
虽然同一个Pin可以用作多种不同的用途,但在任意时刻只有一种用途,这是很容易理解的,否则就会乱套了。但是在不同时刻,它能否根据需要动态切换Pin的功能呢?我想从理论是可行的,但对硬件设计可能有特别的要求,才能保证不会互相冲突。我在代码中没有看到这种用法,不知道实际中是否有人这样用呢。同一个Pin具有相同的配置,但是用于不同设备倒是正常的,像数据线和地址线就属此类。
下面我们来看看代码:
21 struct mhn_pin_config {
22 mfp_pin_t mfp_pin;
23 unsigned int reserved:16
24 unsigned int af_sel:3
25 unsigned int edge_rise_en:1
26 unsigned int edge_fall_en:1
27 unsigned int edge_clear:1
28 unsigned int sleep_oe_n:1
29 unsigned int sleep_data:1
30 unsigned int sleep_sel:1
31 unsigned int drive:3
32 unsigned int pulldown_en:1
33 unsigned int pullup_en:1
34 unsigned int pull_sel:1
35 };
(mfp.h)
这个结构用于描述MFP的配置,它与MFPRx寄存器中的位域基本上一一对应,这里我们简单说明一下:
mfp_pin 是MFP的ID,用宏MFP_REG以mfp_pin为参数,可以计算出mfp_pin的MFPR寄存器地址。
af_sel 其中af代表alternate function,用于选择实际的功能,它最多有八种可能的选择,可参照《PXA300 and PXA310 Developers Manual 1》的4.3/4.4节。
edge_rise_en/ edge_fall_en/ edge_clear 用于控制上升沿/下降沿中断的禁用或启用。我有点疑惑的是,如果该Pin配置为GPIO,而GPIO有自己的上升沿/下降沿配置,两者是否冲突呢?
sleep_oe_n 在低功耗模式(low power mode)下,它决定Pin作为输入还是输出,1表示输入,0表示输出。
sleep_data在低功耗模式(low power mode)下,如果作为输出,它决定输出高电平还是低电平。
sleep_sel 控制在正模式和低功耗模式之间切换时的行为。可以参考《PXA300 and PXA310 Developers Manual 1》的表4.8。
drive 控制Pin的驱动能力,可以在1mA到10mA之间调整,另外可以调整slew rate,slew rate决定电平翻转的速度。
pulldown_en/ pullup_en 是否启用内部下/上拉电阻,只有作为Input Pin时才有用。我们知道下/上拉电阻的主要目的就是防止Pin悬空,悬空的Pin可以看作一个天线,它容易受外界干扰,造成Pin值的不确实性。下/上拉电阻能够给Input Pin一个默认的输入值,下拉电阻接地,默认输入低电平,上拉电阻接电源,默认输入高电平。当真正有外接输入时,它们自动无效,同时避免短路,起到限流作用。
pull_sel 用于决定pulldown_en/ pullup_en的有效性,在低功耗模式下,pull_sel的实际值不改变,但有效值相当于1。也就是说在低功耗模式下,pulldown_en/ pullup_en的值始终决定默认输入,这可以防止干扰信号唤醒CPU。
在《PXA300 and PXA310 Developers Manual 1》的表4.6中,对pulldown_en/ pullup_en的描述是自相矛盾的,比如对pullup_en的描述,前面说,1 = The internal pullup resistor of the pad is enabled,后面又说,The resistor is only enabled if PULL_SEL=1(or is effectively 1) and if PULLUP_EN is 0。前者说1启用内部上拉电阻,后者又说0启用内部上拉电阻,我想前者是对的后者是错的。
113 #define MHN_MFP_CFG(desc, pin, af, drv, rdh, lpm, edge) / 114 { /
115 .mfp_pin = pin, /
116 .af_sel = af, /
117 .reserved = 0, /
118 .drive = drv, /
119 .sleep_sel = rdh, /
120 .sleep_oe_n = ((lpm) &0x1), /
121 .sleep_data = (((lpm) &0x2) >>1), /
122 .pullup_en = (((lpm) &0x4) >>2), /
123 .pulldown_en = (((lpm) &0x8) >>3), /
124 .pull_sel = (((lpm) &0x10) >>4), /
125 .edge_clear = (!(edge)), /
126 .edge_fall_en = ((edge) &0x1), /
127 .edge_rise_en = (((edge) &0x2) >>1), /
128 }
(mfp.h)
MHN_MFP_CFG的功能很简单,但是很常用,它简化了MFP配置的初始化。
145 #define PIN2REG(pin_config) / 146 (pin_config->af_sel <
147 (pin_config->edge_rise_en <
148 (pin_config->edge_fall_en <
149 (pin_config->edge_clear <
150 (pin_config->sleep_oe_n <
151 (pin_config->sleep_data <
152 (pin_config->sleep_sel <
153 (pin_config->drive <
154 (pin_config->pulldown_en <
155 (pin_config->pullup_en <
156 (pin_config->pull_sel < (mfp.h)
这个宏也很常用,它把mhn_pin_config结构转换成MFPR寄存器的格式,这样就可以直接写入MFPR寄存器了。
44 int mhn_mfp_set_config( struct mhn_pin_config *pin_config)
45 {
46 unsigned long flags;
47 mfp_pin_t mfp_pin;
48 uint32_t mfp_reg;
49
50 spin_lock_irqsave(&mfp_spin_lock, flags);
51
52 mfp_pin = pin_config->mfp_pin;
53 mfp_reg = PIN2REG(pin_config);
54
55 #if defined(CONFIG_MONAHANS_GPIOEX)
56 if (IS_GPIO_EXP_PIN(mfp_pin)){
57 spin_unlock_irqrestore(&mfp_spin_lock, flags);
58 return 0
59 }
60 #endif
61
62 #ifdef CONFIG_MFP_DEBUG
63 if ((pin_config == NULL) ||
64 (MFP_OFFSET(mfp_pin) >MHN_MAX_MFP_OFFSET) ||
65 (MFP_OFFSET(mfp_pin)
66 spin_unlock_irqrestore(&mfp_spin_lock, flags);
67 return -1
68 }
69 #endif
70
71 MFP_REG(mfp_pin) = mfp_reg;
72 mfp_reg = MFP_REG(mfp_pin); /* read back */
73
74 spin_unlock_irqrestore(&mfp_spin_lock, flags);
75
76 return 0
77 }
该函数让配置生效,它先用PIN2REG把配置转换成寄存器的格式,然后用MFP_REG得到Pin对应的寄存器,并把值写入寄存器,最后为了确保写入操作完成,再把寄存器的值读回来。通过回读的方式确保写操作完成,在多级流水线的CPU中是常用的手法。
120 int mhn_mfp_set_afds(mfp_pin_t pin, int af, int ds)
121 {
122 unsigned long flags;
123 uint32_t mfp_reg;
124
125 #if defined(CONFIG_MONAHANS_GPIOEX)
126 if (IS_GPIO_EXP_PIN(pin))
127 return 0
128 #endif
129
130 #ifdef CONFIG_MFP_DEBUG
131 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
132 (MFP_OFFSET(pin)
133 return -1
134 #endif
135
136 spin_lock_irqsave(&mfp_spin_lock, flags);
137
138 mfp_reg = MFP_REG(pin);
139 mfp_reg &= ~(MFP_AF_MASK | MFP_DRV_MASK);
140 mfp_reg |= (((af &0x7) <
141 ((ds &0x7) <
142 MFP_REG(pin) = mfp_reg;
143 mfp_reg = MFP_REG(pin);
144
145 spin_unlock_irqrestore(&mfp_spin_lock, flags);
146
147 return 0
148 }
这里只要明白AF代表Alternate Function,而ds代表drive strength,就明白这个函数的功能了,它就是用来设置Pin的可选功能和驱动能力的。其实现与mhn_mfp_set_config类似,但它只修改部分设置,所以要先读取原来的设置,修改它并写回去,最后再读回来以确认设置完成。
150 int mhn_mfp_set_rdh(mfp_pin_t pin, int rdh)
151 {
152 unsigned long flags;
153 uint32_t mfp_reg;
154
155 #if defined(CONFIG_MONAHANS_GPIOEX)
156 if (IS_GPIO_EXP_PIN(pin))
157 return 0
158 #endif
159
160 #ifdef CONFIG_MFP_DEBUG
161 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
162 (MFP_OFFSET(pin)
163 return -1
164 #endif
165
166 spin_lock_irqsave(&mfp_spin_lock, flags);
167
168 mfp_reg = MFP_REG(pin);
169 mfp_reg &= ~MFP_RDH_MASK;
170
171 if (likely(rdh))
172 mfp_reg |= (1u <
173
174 MFP_REG(pin) = mfp_reg;
175 mfp_reg = MFP_REG(pin);
176
177 spin_unlock_irqrestore(&mfp_spin_lock, flags);
178
179 return 0
180 }
这里其实它并不是修改ASCR[RDH],而是修改SLEEP_SEL,因为SLEEP_SEL决定ASCR[RDH]的值是否有效,具体方法与前面类似。RDH意义暂时还不完全明白,以后再补充吧。
182 int mhn_mfp_set_lpm(mfp_pin_t pin, int lpm)
183 {
184 unsigned long flags;
185 uint32_t mfp_reg;
186
187 #if defined(CONFIG_MONAHANS_GPIOEX)
188 if (IS_GPIO_EXP_PIN(pin))
189 return 0
190 #endif
191
192 #ifdef CONFIG_MFP_DEBUG
193 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
194 (MFP_OFFSET(pin)
195 return -1
196 #endif
197 spin_lock_irqsave(&mfp_spin_lock, flags);
198
199 mfp_reg = MFP_REG(pin);
200 mfp_reg &= ~(MFP_LPM_MASK);
201
202 if (lpm &0x1) mfp_reg |= 1u <
203 if (lpm &0x2) mfp_reg |= 1u <
204 if (lpm &0x4) mfp_reg |= 1u <
205 if (lpm &0x8) mfp_reg |= 1u <
206 if (lpm &0x10) mfp_reg |= 1u <
207
208 MFP_REG(pin) = mfp_reg;
209 mfp_reg = MFP_REG(pin);
210
211 spin_unlock_irqrestore(&mfp_spin_lock, flags);
212
213 return 0
214 }
这里的lpm代表low power mode,它用来设置低功耗模式下的配置,包括数据方向是输出还是输入,输出的数据和输入的默认值等。
216 int mhn_mfp_set_edge(mfp_pin_t pin, int edge)
217 {
218 unsigned long flags;
219 uint32_t mfp_reg;
220
221 #if defined(CONFIG_MONAHANS_GPIOEX)
222 if (IS_GPIO_EXP_PIN(pin))
223 return 0
224 #endif
225
226 #ifdef CONFIG_MFP_DEBUG
227 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
228 (MFP_OFFSET(pin)
229 return -1
230 #endif
231 spin_lock_irqsave(&mfp_spin_lock, flags);
232
233 mfp_reg = MFP_REG(pin);
234
235 /* Clear bits - EDGE_CLEAR, EDGE_RISE_EN, EDGE_FALL_EN */
236 mfp_reg &= ~(MFP_EDGE_MASK);
237
238 switch (edge) {
239 case MFP_EDGE_RISE:
240 mfp_reg |= (1u <
241 break
242 case MFP_EDGE_FALL:
243 mfp_reg |= (1u <
244 break
245 case MFP_EDGE_BOTH:
246 mfp_reg |= (3u <
247 break
248 case MFP_EDGE_NONE:
249 mfp_reg |= (1u <
250 break
251 default:
252 spin_unlock_irqrestore(&mfp_spin_lock, flags);
253 return -EINVAL
254 }
255
256 MFP_REG(pin) = mfp_reg;
257 mfp_reg = MFP_REG(pin);
258
259 spin_unlock_irqrestore(&mfp_spin_lock, flags);
260
261 return 0
262 }
设置电平切换检查,可以在上升沿检查,可以在下降沿检查,可以两者都检查,或者都不检查,后者设置EDGE_CLEAR位。
270 int mhn_mfp_set_pull(mfp_pin_t pin, int pull)
271 {
272 unsigned long flags;
273 uint32_t mfp_reg;
274
275 #if defined(CONFIG_MONAHANS_GPIOEX)
276 if (IS_GPIO_EXP_PIN(pin))
277 return 0
278 #endif
279
280 #ifdef CONFIG_MFP_DEBUG
281 if ((MFP_OFFSET(pin) >MHN_MAX_MFP_OFFSET) ||
282 (MFP_OFFSET(pin)
283 return -1
284 #endif
285 spin_lock_irqsave(&mfp_spin_lock, flags);
286
287 mfp_reg = MFP_REG(pin);
288 mfp_reg &= ~MFP_PULL_MASK;
289
290 mfp_reg |= (pull &0x7u) <
291
292 MFP_REG(pin) = mfp_reg;
293 mfp_reg = MFP_REG(pin);
294
295 spin_unlock_irqrestore(&mfp_spin_lock, flags);
296
297 return 0
298 }
启用/禁用内部上/下拉电阻,给Input Pin设置默认值。
300 static struct mfp_regs context;
301 void mhn_mfp_save( void)
302 {
303 int i, offset;
304
305 /* specify the membase */
306 context.membase = ( unsigned char *)KSEG0(PADBASE);
307
308 for (i = 0i 309 offset = i <<2
310 context.mfp[i] = readl(context.membase + offset);
311 }
312 }
313
314 void mhn_mfp_restore( void)
315 {
316 int i, offset;
317
318 /* check the membase */
319 if (context.membase == NULL)
320 return
321
322 for (i = 0i 323 offset = i <<2
324 writel(context.mfp[i], context.membase + offset);
325 }
326 }
保存和恢复MFP的设置,供电源管理在系统Suspend和Resume时调用,因为寄存器是连接的,所以其实现很简单。
~~end~~
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1683936
本文转自
http://blog.csdn.net/absurd/archive/2007/07/09/1683936.aspx