gnss: add receiver type support
authorJohan Hovold <johan@kernel.org>
Fri, 1 Jun 2018 08:22:59 +0000 (10:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Jun 2018 11:32:51 +0000 (20:32 +0900)
Add a "type" device attribute and a "GNSS_TYPE" uevent variable which
can be used to determine the type of a GNSS receiver. The currently
identified types reflect the protocol(s) supported by a receiver:

"NMEA" NMEA 0183
"SiRF" SiRF Binary
"UBX" UBX

Note that both SiRF and UBX type receivers typically support a subset of
NMEA 0183 with vendor extensions (e.g. to allow switching to the vendor
protocol).

Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-class-gnss [new file with mode: 0644]
MAINTAINERS
drivers/gnss/core.c
drivers/gnss/sirf.c
drivers/gnss/ubx.c
include/linux/gnss.h

diff --git a/Documentation/ABI/testing/sysfs-class-gnss b/Documentation/ABI/testing/sysfs-class-gnss
new file mode 100644 (file)
index 0000000..2467b69
--- /dev/null
@@ -0,0 +1,15 @@
+What:          /sys/class/gnss/gnssN/type
+Date:          May 2018
+KernelVersion: 4.18
+Contact:       Johan Hovold <johan@kernel.org>
+Description:
+               The GNSS receiver type. The currently identified types reflect
+               the protocol(s) supported by the receiver:
+
+                       "NMEA"          NMEA 0183
+                       "SiRF"          SiRF Binary
+                       "UBX"           UBX
+
+               Note that also non-"NMEA" type receivers typically support a
+               subset of NMEA 0183 with vendor extensions (e.g. to allow
+               switching to a vendor protocol).
index f980c61..e01d220 100644 (file)
@@ -6041,6 +6041,7 @@ F:        include/uapi/linux/gigaset_dev.h
 GNSS SUBSYSTEM
 M:     Johan Hovold <johan@kernel.org>
 S:     Maintained
+F:     Documentation/ABI/testing/sysfs-class-gnss
 F:     Documentation/devicetree/bindings/gnss/
 F:     drivers/gnss/
 F:     include/linux/gnss.h
index 307894c..f30ef83 100644 (file)
@@ -330,6 +330,52 @@ int gnss_insert_raw(struct gnss_device *gdev, const unsigned char *buf,
 }
 EXPORT_SYMBOL_GPL(gnss_insert_raw);
 
+static const char * const gnss_type_names[GNSS_TYPE_COUNT] = {
+       [GNSS_TYPE_NMEA]        = "NMEA",
+       [GNSS_TYPE_SIRF]        = "SiRF",
+       [GNSS_TYPE_UBX]         = "UBX",
+};
+
+static const char *gnss_type_name(struct gnss_device *gdev)
+{
+       const char *name = NULL;
+
+       if (gdev->type < GNSS_TYPE_COUNT)
+               name = gnss_type_names[gdev->type];
+
+       if (!name)
+               dev_WARN(&gdev->dev, "type name not defined\n");
+
+       return name;
+}
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct gnss_device *gdev = to_gnss_device(dev);
+
+       return sprintf(buf, "%s\n", gnss_type_name(gdev));
+}
+static DEVICE_ATTR_RO(type);
+
+static struct attribute *gnss_attrs[] = {
+       &dev_attr_type.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(gnss);
+
+static int gnss_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct gnss_device *gdev = to_gnss_device(dev);
+       int ret;
+
+       ret = add_uevent_var(env, "GNSS_TYPE=%s", gnss_type_name(gdev));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int __init gnss_module_init(void)
 {
        int ret;
@@ -347,6 +393,9 @@ static int __init gnss_module_init(void)
                goto err_unregister_chrdev;
        }
 
+       gnss_class->dev_groups = gnss_groups;
+       gnss_class->dev_uevent = gnss_uevent;
+
        pr_info("GNSS driver registered with major %d\n", MAJOR(gnss_first));
 
        return 0;
index 5fb0f73..79cb989 100644 (file)
@@ -267,6 +267,7 @@ static int sirf_probe(struct serdev_device *serdev)
        if (!gdev)
                return -ENOMEM;
 
+       gdev->type = GNSS_TYPE_SIRF;
        gdev->ops = &sirf_gnss_ops;
        gnss_set_drvdata(gdev, data);
 
index ecddfb3..902b685 100644 (file)
@@ -77,6 +77,8 @@ static int ubx_probe(struct serdev_device *serdev)
 
        gserial->ops = &ubx_gserial_ops;
 
+       gserial->gdev->type = GNSS_TYPE_UBX;
+
        data = gnss_serial_get_drvdata(gserial);
 
        data->vcc = devm_regulator_get(&serdev->dev, "vcc");
index e26aeac..4354697 100644 (file)
 
 struct gnss_device;
 
+enum gnss_type {
+       GNSS_TYPE_NMEA = 0,
+       GNSS_TYPE_SIRF,
+       GNSS_TYPE_UBX,
+
+       GNSS_TYPE_COUNT
+};
+
 struct gnss_operations {
        int (*open)(struct gnss_device *gdev);
        void (*close)(struct gnss_device *gdev);
@@ -30,6 +38,7 @@ struct gnss_device {
        struct cdev cdev;
        int id;
 
+       enum gnss_type type;
        unsigned long flags;
 
        struct rw_semaphore rwsem;