ublox-M8Q GNSS模组驱动与冷热启动定位设置
测试冷热启动定位
对于GNSS模组,产品测试中需要测试冷启动定位和热启动定位。
测试工程师问我怎么设置冷热启动,一时还真不知道。
GNSS模组驱动
推测复位就能实现冷启动
查看原理,看到模组有复位引脚,复位引脚是GPIO255。
尝试操作gpio255复位GNSS模组。
查看gpio255的状态:
[rsu7012: ~]$ cat /sys/kernel/debug/gpio
GPIOs 0-255, gpio:gpio-0 (sd card detect ) in logpio-45 (comip-otg ) in logpio-72 (ver3 ) in logpio-73 (ver2 ) in logpio-74 (led upd ) out logpio-75 (ver1 ) in higpio-99 ( LC1160 irq ) in logpio-153 (system run ) out logpio-154 (led err ) out higpio-185 (wifi_reset ) out higpio-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_NODTSstruct 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);#elsestruct 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);
#endifgps_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_NODTSpdata->power = comip_gps_power_ctrl;
#endifGPS_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_NODTSgpio_direction_output(pdata->gpio_d1v8_ctrl, GPS_D1V8_OFF);gpio_free(pdata->gpio_d1v8_ctrl);
#endifreturn 0;
}#ifndef CONFIG_GPS_UBLOX_NODTS
static struct of_device_id of_ublox_gps_match[] = {{ .compatible = "morningcore,ublox-gps", },{}
};
#endifstatic 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属性写入on或off就可以控制模组上下电。
经过测试,这样就实现可以控制的GNSS热启动测试。
