^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Test driver for GNSS. This driver requires the serdev binding and protocol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * type to be specified on the module command line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2019 Google LLC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/gnss.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/serdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "serial.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define GNSS_CMDLINE_MODULE_NAME "gnss-cmdline"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define gnss_cmdline_err(...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) pr_err(GNSS_CMDLINE_MODULE_NAME ": " __VA_ARGS__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static char *serdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) module_param(serdev, charp, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_PARM_DESC(serdev, "serial device to wrap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) module_param(type, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_PARM_DESC(serdev, "GNSS protocol type (see 'enum gnss_type')");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static struct serdev_device *serdev_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int name_match(struct device *dev, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return strstr(dev_name(dev), data) != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static int __init gnss_cmdline_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct device *serial_dev, *port_dev, *serdev_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) char *driver_name, *port_name, *serdev_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) char *serdev_dup, *serdev_dup_sep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct gnss_serial *gserial;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* User did not set the serdev module parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (!serdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (type < 0 || type >= GNSS_TYPE_COUNT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) gnss_cmdline_err("invalid gnss type '%d'\n", type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) serdev_dup = serdev_dup_sep = kstrdup(serdev, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!serdev_dup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) driver_name = strsep(&serdev_dup_sep, "/");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (!driver_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) gnss_cmdline_err("driver name missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) port_name = strsep(&serdev_dup_sep, "/");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!port_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) gnss_cmdline_err("port name missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) serdev_name = strsep(&serdev_dup_sep, "/");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (!serdev_name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) gnss_cmdline_err("serdev name missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Find the driver device instance (e.g. serial8250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) serial_dev = bus_find_device_by_name(&platform_bus_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) NULL, driver_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!serial_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) gnss_cmdline_err("no device '%s'\n", driver_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* Find the port device instance (e.g. serial0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) port_dev = device_find_child(serial_dev, port_name, name_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!port_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) gnss_cmdline_err("no port '%s'\n", port_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Find the serdev device instance (e.g. serial0-0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) serdev_dev = device_find_child(port_dev, serdev_name, name_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!serdev_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) gnss_cmdline_err("no serdev '%s'\n", serdev_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) gserial = gnss_serial_allocate(to_serdev_device(serdev_dev), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (IS_ERR(gserial)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) err = PTR_ERR(gserial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) gserial->gdev->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) err = gnss_serial_register(gserial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) gnss_serial_free(gserial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) goto err_free_serdev_dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) serdev_device = to_serdev_device(serdev_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) err_free_serdev_dup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) kfree(serdev_dup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static void __exit gnss_cmdline_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct gnss_serial *gserial;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!serdev_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) gserial = serdev_device_get_drvdata(serdev_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) gnss_serial_deregister(gserial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) gnss_serial_free(gserial);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) module_init(gnss_cmdline_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) module_exit(gnss_cmdline_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) MODULE_AUTHOR("Alistair Delva <adelva@google.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) MODULE_DESCRIPTION("GNSS command line driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) MODULE_LICENSE("GPL v2");