高通平台 支持通过uart唤醒系统, 前提是使用高速串口驱动,即msm_serial_hs.c ,这个驱动中是将rx配置成
这里简单列下高速串口的配置过程。
打开驱动宏控:
kernel/arch/arm/configs/msm8909-1gb_defconfig
+CONFIG_SERIAL_MSM_HS=y
添加 高速串口配置
修改 kernel/arch/arm/boot/dts/qcom/msm8909.dtsi
+blsp1_uart2: uart@78b0000 {
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0x78b0000 0x200>,
+ <0x7884000 0x23000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ #address-cells = <0>;
+ interrupt-parent = <&blsp1_uart2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 108 0
+ 1 &intc 0 238 0
+ 2 &msm_gpio 21 0>;
+ qcom,bam-tx-ep-pipe-index = <2>;
+ qcom,bam-rx-ep-pipe-index = <3>;
+ qcom,master-id = <86>;
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ clock-names = "core_clk", "iface_clk";
+ qcom,msm-bus,name = "blsp1_uart";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ qcom,rx-char-to-inject = <0xFD>;
+ qcom,inject-rx-on-wakeup;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&hsuart_sleep>;
+ pinctrl-1 = <&hsuart_active>;
+ status = "ok";
+};
添加pinctrl 配置:
kernel/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi
+ blsp1_uart2_active {
+ qcom,pins = <&gp 20>, <&gp 21>;
+ qcom,num-grp-pins = <2>;
+ qcom,pin-func = <3>;
+ label = "blsp1_uart2_active";
+ hsuart_active: default {
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ blsp1_uart2_sleep {
+ qcom,pins = <&gp 20>, <&gp 21>;
+ qcom,num-grp-pins = <2>;
+ qcom,pin-func = <0>;
+ label = "blsp1_uart2_sleep";
+ hsuart_sleep: sleep {
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
下面简单描述下,uart唤醒系统的实现,在上述的高速串口驱动,有如下的配置选项:
+ blsp1_uart2_active {
+ qcom,pins = <&gp 20>, <&gp 21>;
+ qcom,num-grp-pins = <2>;
+ qcom,pin-func = <3>;
+ label = "blsp1_uart2_active";
+ hsuart_active: default {
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ blsp1_uart2_sleep {
+ qcom,pins = <&gp 20>, <&gp 21>;
+ qcom,num-grp-pins = <2>;
+ qcom,pin-func = <0>;
+ label = "blsp1_uart2_sleep";
+ hsuart_sleep: sleep {
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
这里配置了gpio21(rq)可唤醒中断。
qcom,rx-char-to-inject = <0xFD>;
qcom,inject-rx-on-wakeup;
这个配置是在中断触发后,像tty上添加一个字节,内容为 0xfd, 它的作用 后面会做描述:
在驱动中对这个中断的处理:
中断申请:
static int msm_hs_startup(struct uart_port *uport)
{
if (is_use_low_power_wakeup(msm_uport)) {
ret = request_threaded_irq(msm_uport->wakeup.irq, NULL,
msm_hs_wakeup_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"msm_hs_wakeup", msm_uport);
if (unlikely(ret)) {
MSM_HS_ERR("%s():Err getting uart wakeup_irq\n",
__func__);
goto free_uart_irq;
}
msm_uport->wakeup.freed = false;
disable_irq(msm_uport->wakeup.irq);
msm_uport->wakeup.enabled = false;
ret = irq_set_irq_wake(msm_uport->wakeup.irq, 1);
if (unlikely(ret)) {
MSM_HS_ERR("%s():Err setting wakeup irq\n", __func__);
goto free_uart_irq;
}
}
中断处理函数:
static irqreturn_t msm_hs_wakeup_isr(int irq, void *dev)
{
unsigned int wakeup = 0;
unsigned long flags;
struct msm_hs_port *msm_uport = (struct msm_hs_port *)dev;
struct uart_port *uport = &msm_uport->uport;
struct tty_struct *tty = NULL;
msm_hs_resource_vote(msm_uport);
spin_lock_irqsave(&uport->lock, flags);
MSM_HS_DBG("%s(): ignore %d\n", __func__,
msm_uport->wakeup.ignore);
if (msm_uport->wakeup.ignore)
msm_uport->wakeup.ignore = 0;
else
wakeup = 1;
/* 这里根据 设备树中是否 设置了qcom,inject-rx-on-wakeup 来决定是否 插入 0xfd 这个字节*/
if (wakeup) {
/*
* Port was clocked off during rx, wake up and
* optionally inject char into tty rx
*/
if (msm_uport->wakeup.inject_rx) {
tty = uport->state->port.tty;
tty_insert_flip_char(tty->port,
msm_uport->wakeup.rx_to_inject,
TTY_NORMAL);
MSM_HS_DBG("%s(): Inject 0x%x", __func__,
msm_uport->wakeup.rx_to_inject);
}
}
spin_unlock_irqrestore(&uport->lock, flags);
msm_hs_resource_unvote(msm_uport);
if (wakeup && msm_uport->wakeup.inject_rx)
tty_flip_buffer_push(tty->port);
return IRQ_HANDLED;
}
当RX 上有数据时,有电平变化,会触发中断,在中断处理函数中,可以唤醒系统。
默认状态下,系统需要休眠时,需要关闭打开的串口进入 suspend状态,这时rx 就是一个可以唤醒系统的gpio;
如果靠从设备发过来的数据来触发中断唤醒系统,这时系统还未打开串口,当前的数据内容一定会丢失,所以在需要唤醒系统前,从设备应当与系统进行简单的握手来确保各自的状态再进行接下来的通讯内容。
高通平台上,默认支持了一种,用于uart蓝牙从设备来唤醒系统的, 默认驱动中添加的 0xfd的作用也是用作次目的。 下面是高通平台 蓝牙从设备与系统的通讯的过程框图。
Wake - This byte is used to wake up the device which has to receive the data
Wake ack - This byte is used as an acknowledgement to the wake byte, meaning I am ready to receive
Sleep - This byte is sent to the other device when it has no data to send
软件逻辑是如此,如果要使用uart唤醒系统,可以借鉴参考这个流程,从设备可编程,与主机通讯握手(可自定义细节)成功后,再收发数据。