您的位置:首页 > 其它

TWL6030 电源管理芯片中断注册,处理过程

2012-05-10 20:23 309 查看
TI TWL6030 是一款功能强大的电源管理芯片。集成了很多功能,可以对整个板卡上的各设备进行供电和电源管理,功能大致和PC上的电源类似,就是一端插上电源,另一端

分出来好多电源线,分别给处理器,内存,硬盘等供电。只不过有了电源管理芯片,各个电压可以配置。

本文主要讲TWL6030上各设备中断处理过程。为什么用这个来讲,主要是它很特殊,我们知道,普通的设备只有一根中断线接到CPU的引脚上(或PIC PIN),6030也是这样,只有一根INT连接到CPU的中断引脚,但是因为它功能很多,要处理很多中断。比如:电源按下,USB插入,电量计的检测等,那么这么多的中断怎么报给处理器呢?

由于只有一根INT线,在这根INT线上注册一个中断处理函数,当有中断发生时(这个是自动的,6030会做处理,比如你按下电源,或者插入USB,6030会自动在INT上报一个中断给CPU),在中断处理函数中读取寄存器,看看到底是哪个功能模块上报的中断,然后调用这个模块的处理函数。然而实现方法却不是这样。

且看代码

[cpp] view
plaincopy

247 /*

248 * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt.

249 * This is a chained interrupt, so there is no desc->action method for it.

250 * Now we need to query the interrupt controller in the twl6030 to determine

251 * which module is generating the interrupt request. <span style="background-color: rgb(255, 255, 255);"><span style="color:#ff0000;"> However, we can't do i2c

252 * transactions in interrupt context, so we must defer that work to a kernel

253 * thread. All we do here is acknowledge and mask the interrupt and wakeup

254 * the kernel thread.</span></span>

255 */

256 static irqreturn_t handle_twl6030_pih(int irq, void *devid)

257 {

258 disable_irq_nosync(irq);

259 complete(devid);

260 return IRQ_HANDLED;

261 }

看到红色部分了吧,在注册中断的同时,开启一个内核线程,这个内核线程是个死循环,不停的进行等待中断的发生(这里是等待devid, 被唤醒后继续),

[cpp] view
plaincopy

task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");//这里创建了一个内核线程,看看<pre name="code" class="cpp">twl6030_irq_thread都干了些什么事情吧

[cpp] view
plaincopy

</pre>



[cpp] view
plaincopy

165 /*

166 * This thread processes interrupts reported by the Primary Interrupt Handler.

167 */

168 static int twl6030_irq_thread(void *data)

169 {

170 long irq = (long)data;

171 static unsigned i2c_errors;

172 static const unsigned max_i2c_errors = 100;

173 int ret;

174

175 current->flags |= PF_NOFREEZE;

176

177 while (!kthread_should_stop()) {

178 int i;

179 union {

180 u8 bytes[4];

181 u32 int_sts;

182 } sts;

183 u32 int_sts; /* sts.int_sts converted to CPU endianness */

184

185 /* Wait for IRQ, then read PIH irq status (also blocking) */

186 wait_for_completion_interruptible(&irq_event);

187

188 /* read INT_STS_A, B and C in one shot using a burst read */

189 ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes,

190 REG_INT_STS_A, 3);

191 if (ret) {

192 pr_warning("twl6030: I2C error %d reading PIH ISR\n",

193 ret);

194 if (++i2c_errors >= max_i2c_errors) {

195 printk(KERN_ERR "Maximum I2C error count"

196 " exceeded. Terminating %s.\n",

197 __func__);

198 break;

199 }

200 complete(&irq_event);

201 continue;

202 }

203

204

205

206 sts.bytes[3] = 0; /* Only 24 bits are valid*/

207

208 /*

209 * Since VBUS status bit is not reliable for VBUS disconnect

210 * use CHARGER VBUS detection status bit instead.

211 */

212 if (sts.bytes[2] & 0x10)

213 sts.bytes[2] |= 0x08;

214

215 int_sts = le32_to_cpu(sts.int_sts);

216 for (i = 0; int_sts; int_sts >>= 1, i++) {

217 local_irq_disable();

218 if (int_sts & 0x1) {

219 int module_irq = twl6030_irq_base +

220 twl6030_interrupt_mapping[i];

221 <span style="color:#ff0000;"> generic_handle_irq(module_irq);</span>

222

223 }

224 local_irq_enable();

225 }

226

227 /*

228 * NOTE:

229 * Simulation confirms that documentation is wrong w.r.t the

230 * interrupt status clear operation. A single *byte* write to

231 * any one of STS_A to STS_C register results in all three

232 * STS registers being reset. Since it does not matter which

233 * value is written, all three registers are cleared on a

234 * single byte write, so we just use 0x0 to clear.

235 */

236 ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);

237 if (ret)

238 pr_warning("twl6030: I2C error in clearing PIH ISR\n");

239

240 enable_irq(irq);

241 }

242

243 return 0;

244 }

红色部分是关键点,在该中断处理函数(确切的说是内核线程了,不在是中断处理函数了),又调用了中断处理函数,这些函数是其他模块注册的(就是刚才说的power键,USB等注册进内核的)。比如,检测到是电源键按下或抬起,这个时候,module_irq就是电源键中断申请时申请的irq号。

看看系统中有哪些6030中断和内核线程

root@android:/ # cat /proc/interrupts |grep 6030

39: 12 0 GIC TWL6030-PIH

368: 0 4 twl6030 twl6030_pwrbutton

369: 0 0 twl6030 twl6030_gpadc

370: 2 0 twl6030 twl_bci_ctrl

371: 0 0 twl6030 twl6030_gpadc

372: 0 0 twl6030 twl6030_usb

374: 0 0 twl6030 TWL6030-VLOW

378: 2 0 twl6030 twl6030_usb

379: 0 0 twl6030 rtc0

384: 0 0 twl6030 mmc1

root@android:/ # ps |grep 6030

root 17 2 0 0 c025c410 00000000 S twl6030-irq

root 18 2 0 0 c0103838 00000000 S irq/374-TWL6030

root 19 2 0 0 c0103838 00000000 S irq/372-twl6030

root 20 2 0 0 c0103838 00000000 S irq/378-twl6030

root 31 2 0 0 c0103838 00000000 S irq/371-twl6030

root 32 2 0 0 c0103838 00000000 S irq/369-twl6030

root 34 2 0 0 c0103838 00000000 S irq/368-twl6030

看到了吧,是不是有很多个。其中,能直接中断CPU的只有

39: 12 0 GIC TWL6030-PIH

当这个中断发生时,内核线程twl6030-irq会进行查看具体是哪个中断产生了(这点有点想PIC掩码机制了),然后直接调用这个中断相应的处理函数。

也就是说,

368: 0 4 twl6030 twl6030_pwrbutton

369: 0 0 twl6030 twl6030_gpadc

370: 2 0 twl6030 twl_bci_ctrl

371: 0 0 twl6030 twl6030_gpadc

372: 0 0 twl6030 twl6030_usb

374: 0 0 twl6030 TWL6030-VLOW

378: 2 0 twl6030 twl6030_usb

这些注册进内核的中断,仅仅是在内核中断全局描述表中占个位子,其被调用的过程不像普通的中断处理函数,而是仅仅类似

一个普通的函数,被另一个内核线程调用而已!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: