测试冷热启动定位

对于GNSS模组,产品测试中需要测试冷启动定位和热启动定位。
测试工程师问我怎么设置冷热启动,一时还真不知道。

GNSS模组驱动

推测复位就能实现冷启动

查看原理,看到模组有复位引脚,复位引脚是GPIO255。
尝试操作gpio255复位GNSS模组。
查看gpio255的状态:

[rsu7012: ~]$ cat /sys/kernel/debug/gpio
GPIOs 0-255, gpio:
 gpio-0   (sd card detect      ) in  lo
 gpio-45  (comip-otg           ) in  lo
 gpio-72  (ver3                ) in  lo
 gpio-73  (ver2                ) in  lo
 gpio-74  (led upd             ) out lo
 gpio-75  (ver1                ) in  hi
 gpio-99  ( LC1160 irq         ) in  lo
 gpio-153 (system run          ) out lo
 gpio-154 (led err             ) out hi
 gpio-185 (wifi_reset          ) out hi
 gpio-255 (GPS reset GPIO      ) out hi

gpio255引脚已经被导出,直接操作gpio,发现/sys/class/gpio/下没有gpio255目录,说gpio255已经被某个驱动占用。

通过gpio-255 (GPS reset GPIO ) out hi可以知道gpio255的名字是GPS reset GPIO

在内核中搜索GPS reset GPIO,最后找到相应的驱动kernel/linux-3.10.79/drivers/comip/wireless/ublox-gps.c

static int __init gps_gpio_probe(struct platform_device *pdev)
{
	int retval = 0;
	struct proc_dir_entry *ent;
#ifndef CONFIG_GPS_UBLOX_NODTS
	struct ublox_gps_platform_data *pdata = NULL;

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata) {
		dev_err(&pdev->dev,
				"allocate memory for platform data failed\n");
		return -ENOMEM;
	}

	g_gps_data = pdata;

	printk("%s, %s\n", __func__, pdev->dev.kobj.name);
	comip_mfp_config(MFP_PIN_GPIO(255), MFP_PIN_MODE_GPIO);
	/*pdata->gpio_d1v8_ctrl = of_get_named_gpio(pdev->dev.of_node, "gps_d1v8_ctrl", 0);
        if (pdata->gpio_d1v8_ctrl < 0) {
                dev_err(&pdev->dev, "get gps_d1v8_ctrl failed\n");
                return -EINVAL;
        }
	gpio_request(pdata->gpio_d1v8_ctrl, "GPS d1v8 ctrl GPIO");
	gpio_direction_output(pdata->gpio_d1v8_ctrl, GPS_D1V8_OFF);*/

	pdata->gpio_reset = of_get_named_gpio(pdev->dev.of_node, "gps_rst", 0);
	if (pdata->gpio_reset < 0) {
		dev_err(&pdev->dev, "get gps_rst failed\n");
		return -EINVAL;
	}
	gpio_request(pdata->gpio_reset, "GPS reset GPIO");
	gpio_direction_output(pdata->gpio_reset, GPS_RESET_OFF);

	comip_mfp_config(MFP_PIN_GPIO(34), MFP_PIN_MODE_GPIO);
	pdata->gpio_pps = of_get_named_gpio(pdev->dev.of_node, "gps_pps", 0);
	if (pdata->gpio_pps < 0) {
		dev_err(&pdev->dev, "get gps_pps failed\n");
		return -EINVAL;
	}
	gpio_request(pdata->gpio_pps, "GPS pps GPIO");
	gpio_direction_input(pdata->gpio_pps);
	comip_mfp_config_pull(pdata->gpio_pps, MFP_PULL_DISABLE);
	gpio_free(pdata->gpio_pps);

#else
	struct ublox_gps_platform_data *pdata = pdev->dev.platform_data;

	printk("ublox gps_gpio_probe\n");
	gpio_request(pdata->gpio_reset, "GPS Reset GPIO");
	gpio_direction_output(pdata->gpio_reset, GPS_RESET_OFF);
#endif

	gps_gpio_dir = proc_mkdir("ublox-gps", NULL);
	if (gps_gpio_dir == NULL) {
		printk("Unable to create /proc/ublox-gps directory");
		return -ENOMEM;
	}

	/* Creating read/write "powerctrl" entry */
	ent = proc_create_data("powerctrl", 0, gps_gpio_dir, &file_ops_proc_powerctrl, pdata);
	if (ent == NULL) {
		printk("Unable to create /proc/ublox-gps/powerctrl entry");
		remove_proc_entry("powerctrl", gps_gpio_dir);
		retval = -ENOMEM;
		goto fail;
	}

	/* Creating write "reset" entry */
	ent = proc_create_data("reset", 0, gps_gpio_dir, &file_ops_proc_reset, pdata);
	if (ent == NULL) {
		printk("Unable to create /proc/ublox-gps/reset entry");
		remove_proc_entry("reset", gps_gpio_dir);
		retval = -ENOMEM;
		goto fail;
	}

	/* Creating write "ppsacc" entry */
	ent = proc_create_data("ppsacc", 0, gps_gpio_dir, &file_ops_proc_ppsacc, pdata);
	if (ent == NULL) {
		printk("Unable to create /proc/ublox-gps/reset entry");
		remove_proc_entry("ppsacc", gps_gpio_dir);
		retval = -ENOMEM;
		goto fail;
	}

	comip_devinfo_register(gps_info_attributes, ARRAY_SIZE(gps_info_attributes));
#ifndef CONFIG_GPS_UBLOX_NODTS
	pdata->power = comip_gps_power_ctrl;
#endif
	GPS_DBG("%s END\n", __func__);
	return retval;

fail:
	remove_proc_entry("ublox-gps", 0);
	return retval;
}

static int __exit gps_gpio_remove(struct platform_device *pdev)
{
	struct ublox_gps_platform_data *pdata = pdev->dev.platform_data;

	remove_proc_entry("powerctrl", gps_gpio_dir);
	remove_proc_entry("reset", gps_gpio_dir);
	remove_proc_entry("gps", 0);
	gpio_direction_output(pdata->gpio_reset, GPS_RESET_OFF);
	gpio_free(pdata->gpio_reset);
#ifndef CONFIG_GPS_UBLOX_NODTS
	gpio_direction_output(pdata->gpio_d1v8_ctrl, GPS_D1V8_OFF);
	gpio_free(pdata->gpio_d1v8_ctrl);
#endif
	return 0;
}

#ifndef CONFIG_GPS_UBLOX_NODTS
static struct of_device_id of_ublox_gps_match[] = {
	{ .compatible = "morningcore,ublox-gps", },
	{}
};
#endif

static struct platform_driver gps_gpio_driver = {
	.remove = __exit_p(gps_gpio_remove),
	.driver = {
		.name = "ublox-gps",
		.owner = THIS_MODULE,
#ifndef CONFIG_GPS_UBLOX_NODTS
		.of_match_table = of_ublox_gps_match,
#endif
	},
};

/**
 * Initializes the module.
 * @return On success, 0. On error, -1, and <code>errno</code> is set
 * appropriately.
 */
static int __init gps_gpio_init(void)
{
	return platform_driver_probe(&gps_gpio_driver, gps_gpio_probe);
}

/**
 * Cleans up the module.
 */
static void __exit gps_gpio_exit(void)
{
	platform_driver_unregister(&gps_gpio_driver);
}

late_initcall(gps_gpio_init);
module_exit(gps_gpio_exit);

MODULE_DESCRIPTION("GPS gpio Driver ver %s " VERSION);

分析驱动代码可以发现,驱动在proc文件系统创建路径ublox-gps

gps_gpio_dir = proc_mkdir("ublox-gps", NULL);

然后创建了几个proc文件系统属性

ent = proc_create_data("powerctrl", 0, gps_gpio_dir, &file_ops_proc_powerctrl, pdata);
ent = proc_create_data("reset", 0, gps_gpio_dir, &file_ops_proc_reset, pdata);
ent = proc_create_data("ppsacc", 0, gps_gpio_dir, &file_ops_proc_ppsacc, pdata);

从上述驱动分析中就可以知道操作GNSS模组的方法了。

GNSS冷启动测试

看原理图可以知道给复位引脚写0实现复位。

echo 0 > /proc/ublox-gps/reset

经过测试,复位后的GNSS模组会清除星历,实现控制冷启动。

GNSS热启动测试

/**
 * <code>gps power control </code> via the proc interface.
 * @param file  the ublox gps data included.
 * @param buffer The buffer to read from.
 * @param count The number of bytes to be read.
 * @param data power on/off cmd.
 * @return On success, the number of bytes written. On error, -1, and
 * <code>errno</code> is set appropriately.
 */
static int gps_write_proc_powerctrl(struct file *file, const char *buffer,
					size_t count, loff_t *data)
{
	char *buf;
	struct ublox_gps_platform_data *pdata = PDE_DATA(file_inode(file));

	if (count < 1)
		return -EINVAL;

	if(!pdata->power)
		return EPERM;

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	if (copy_from_user(buf, buffer, count)) {
		kfree(buf);
		return -EFAULT;
	}

	GPS_DBG("%s, buf[0] %c\n", __func__, buf[0]);
	if (buf[0] == '0') {
		if(pdata->power_state){
			pdata->power(0);
			pdata->power_state = 0;
		}
	} else if (buf[0] == '1') {
		if(!pdata->power_state){
			pdata->power(1);
			pdata->power_state = 1;
		}
	} else {
		kfree(buf);
		return -EINVAL;
	}

	kfree(buf);
	return count;
}

看驱动代码可以知道,往powerctrl属性写入’1’或’0’就可以控制模组上下电。
经过测试,这样就实现可以控制的GNSS热启动测试。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐