Android9电源键驱动分析

一、概述

在现在的Android手机中,物理按键虽然逐渐被取代,但是对于电源键这种命脉型的功能键不可能会取消的,但是对于各家单板,硬件的IO连接都是不相同的,所以需要定制电源键的功能。

二、power-key驱动分析

2.1、dts配置power-key

snvs_pwrkey: snvs-powerkey { compatible = "fsl,sec-v4.0-pwrkey";
	regmap = <&snvs>;
	interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
	linux,keycode = <KEY_POWER>;
	wakeup-source; 
};

上述dts中,使用linux,keycode 来表述按键码,使用GIC_SPI 来作为按键输入中断方式,并且高电平触发。

2.2、使用input子系统上报

代码路径:drivers/input/keyboard/snvs_pwrkey.c
/设备树匹配dts/

static const struct of_device_id imx_snvs_pwrkey_ids[] = {
	{ .compatible = "fsl,sec-v4.0-pwrkey" },
	{ /* sentinel */ }
};

匹配成功后probe调用

static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
{
	struct pwrkey_drv_data *pdata = NULL;
	struct input_dev *input = NULL;
	struct device_node *np;
	int error;
	struct device_node *sp;
	struct platform_device * pd;

	/* Get SNVS register Page */
	np = pdev->dev.of_node;
	if (!np)
		return -ENODEV;

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;
	//查找trust dts信息
	sp = of_find_node_by_name(NULL, "trusty");

	if (sp != NULL) {
		pd = of_find_device_by_node(sp);
		if (pd != NULL) {
			pdata->trusty_dev = &(pd->dev);
			dev_err(&pdev->dev, "snvs pwkey: get trusty_dev node, use Trusty mode.\n");
		} else
			dev_err(&pdev->dev, "snvs pwkey: failed to get trusty_dev node\n");
	} else {
		dev_err(&pdev->dev, "snvs pwkey: failed to find trusty node. Use normal mode.\n");
		pdata->trusty_dev = NULL;
	}

	pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
	if (IS_ERR(pdata->snvs)) {
		dev_err(&pdev->dev, "Can't get snvs syscon\n");
		return PTR_ERR(pdata->snvs);
	}

	if (pdata->trusty_dev) {
		error = trusty_fast_call32(pdata->trusty_dev, SMC_SNVS_PROBE, 0, 0, 0);
		if (error < 0) {
			dev_err(&pdev->dev, "snvs pwkey trusty dev failed to probe!nr=0x%x error=%d\n", SMC_SNVS_PROBE, error);
			pdata->trusty_dev = NULL;
		}
	}
	//读取dts中配置的按键码
	if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
		pdata->keycode = KEY_POWER;
		dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
	}

	pdata->wakeup = of_property_read_bool(np, "wakeup-source");
    //获取中断
	pdata->irq = platform_get_irq(pdev, 0);
	if (pdata->irq < 0) {
		dev_err(&pdev->dev, "no irq defined in platform data\n");
		return -EINVAL;
	}

	if (pdata->trusty_dev != NULL)
		trusty_snvs_update_lpcr(pdata->trusty_dev, SNVS_LPCR_DEP_EN, 1);
	else
		regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);

	/* 清除中断标志位 */
	if (pdata->trusty_dev != NULL)
		trusty_snvs_write(pdata->trusty_dev, SNVS_LPSR_REG, SNVS_LPSR_SPO);
	else
		regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
    /*设置定时器,用于识别长按与短按*/
	setup_timer(&pdata->check_timer,
		    imx_imx_snvs_check_for_events, (unsigned long) pdata);
	/*分配input子系统数据信息*/
	input = devm_input_allocate_device(&pdev->dev);
	if (!input) {
		dev_err(&pdev->dev, "failed to allocate the input device\n");
		return -ENOMEM;
	}
    /*设置input节点中的信息*/
	input->name = pdev->name;
	input->phys = "snvs-pwrkey/input0";
	input->id.bustype = BUS_HOST;
    /*将keycode附加到EV_KEY下*/
	input_set_capability(input, EV_KEY, pdata->keycode);

	/* 添加按键定时器释放函数*/
	error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
	if (error) {
		dev_err(&pdev->dev, "failed to register remove action\n");
		return error;
	}
    /*注册input系统*/
	error = input_register_device(input);
	if (error < 0) {
		dev_err(&pdev->dev, "failed to register input device\n");
		return error;
	}

	pdata->input = input;
	platform_set_drvdata(pdev, pdata);

	device_init_wakeup(&pdev->dev, pdata->wakeup);
   /*申请irq资源,当power-key被按下时候,这个cb就会被调用*/
	error = devm_request_irq(&pdev->dev, pdata->irq,
			       imx_snvs_pwrkey_interrupt,
			       0, pdev->name, pdev);

	if (error) {
		dev_err(&pdev->dev, "interrupt not available.\n");
		input_unregister_device(input);
		return error;
	}

	return 0;
}

/按键被按下后,中断函数被执行/

static void imx_imx_snvs_check_for_events(unsigned long data)
{
	struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
	struct input_dev *input = pdata->input;
	u32 state;

	if (pdata->trusty_dev)
		state = trusty_snvs_read(pdata->trusty_dev, SNVS_HPSR_REG);
	else
		regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
	state = state & SNVS_HPSR_BTN ? 1 : 0;

	/* only report new event if status changed */
	if (state ^ pdata->keystate) {
		pdata->keystate = state;
		input_event(input, EV_KEY, pdata->keycode, state);
		input_sync(input);
		pm_relax(pdata->input->dev.parent);
	}

	/*启动定时器,用于识别短按与长按*/
	if (state) {
		mod_timer(&pdata->check_timer,
			  jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
	}
}

/定时器回调函数,这个回调函数会上报按键信息/

static void imx_imx_snvs_check_for_events(unsigned long data)
{
	struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
	struct input_dev *input = pdata->input;
	u32 state;

	if (pdata->trusty_dev)
		state = trusty_snvs_read(pdata->trusty_dev, SNVS_HPSR_REG);
	else
		regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
	state = state & SNVS_HPSR_BTN ? 1 : 0;

	/* only report new event if status changed */
	if (state ^ pdata->keystate) {
		pdata->keystate = state;
		input_event(input, EV_KEY, pdata->keycode, state);//上报power-key事件
		input_sync(input);
		pm_relax(pdata->input->dev.parent);
	}

	/* repeat check if pressed long */
	if (state) {
		mod_timer(&pdata->check_timer,
			  jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
	}
}

总结:配置dts支持pwrkey即可完成自定义IO来开机动作

下一篇:Android会将power-key值进行转换为相应的运用层统一的功能码

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要刷机所需的Android 9 GMS刷机教程可以分为以下几个步骤: 1.备份数据:在开始刷机之前,请务必备份手机中重要的数据,如联系人、短信、照片等。这是为了防止数据丢失或损坏。 2.解锁Bootloader:在刷机之前,需要先解锁手机的Bootloader。这可以通过在开发者选项中启用OEM解锁和USB调试,然后在电脑上使用ADB和Fastboot工具来完成。 3.安装刷机工具和驱动程序:下载适用于Android 9的刷机工具和驱动程序,如ADB和Fastboot。安装这些工具可以让您在刷机过程中进行操作和调试。 4.下载适用于您的设备的Android 9 GMS固件文件:在刷机之前,请确保您下载并准备好正确的Android 9 GMS固件文件。这些固件文件可以从官方网站或第三方提供商的论坛上获取。 5.进入刷机模式:将您的设备关机,然后按下特定的硬件组合(通常是音量下+电源)进入刷机模式。 6.使用Fastboot刷入固件:打开命令提示符或终端窗口,使用Fastboot命令将Android 9 GMS固件刷入设备。例如,使用"fastboot flash system system.img"命令来刷入系统分区。 7.清除缓存和重启:完成刷机后,使用Fastboot命令清除缓存分区,然后重新启动设备。这确保了设备能够正常启动到新的Android 9 GMS固件。 请注意,刷机有一定的风险,可能会导致设备损坏或失去保修。在进行刷机之前,请确保您了解并理解此过程,并小心操作。最好在刷机之前参考相关的刷机教程和论坛,以获得更详细的指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值