mbox series

[PATCHv8,0/6] n_gsm serdev support and GNSS driver for droid4

Message ID 20200512214713.40501-1-tony@atomide.com
Headers show
Series n_gsm serdev support and GNSS driver for droid4 | expand

Message

Tony Lindgren May 12, 2020, 9:47 p.m. UTC
Hi all,

Here's the updated set of these patches fixed up for Johan's and
Pavel's earlier comments.

This series does the following:

1. Adds functions to n_gsm.c for serdev-ngsm.c driver to use

2. Adds a generic serdev-ngsm.c driver that brings up the TS 27.010
   TTY ports configured in devicetree with help of n_gsm.c

3. Allows the use of standard Linux device drivers for dedicated
   TS 27.010 channels for devices like GNSS and ALSA found on some
   modems for example

4. Adds a gnss-motmdm consumer driver for the GNSS device found on
   the Motorola Mapphone MDM6600 modem on devices like droid4

I've placed the serdev-ngsm.c under drivers/tty/serdev as it still
seems to make most sense with no better places available. It's no
longer an MFD driver as it really does not need to care what channel
specific consumer drivers might be configured for the generic driver.
Now serdev-ngsm just uses of_platform_populate() to probe whatever
child nodes it might find.

I'm not attached having the driver in drivers/tty/serdev. I just
don't have any better locations in mind. So using Johan's earlier
i2c example, the drivers/tty/serdev/serdev-ngsm.c driver is now a
generic protocol and bus driver, so it's getting closer to the
the drivers/i2c/busses analogy maybe :) Please do suggest better
locations other than MFD and misc if you have better ideas.

Now without the chardev support, the /dev/gsmtty* using apps need
to use "U1234AT+CFUN?" format for the packets. The advantage is
less kernel code, and we keep the existing /dev/gsmtty* interface.

If we still really need the custom chardev support, that can now
be added as needed with the channel specific consumer driver(s),
but looks like this won't be needed based on Pavel's ofono work.

Regards,

Tony


Changes since v7 (was accidentally posted as v6 again):
- Updated gsm_serdev_register_tty_port() and gsd_dlci_data() to use
  receive_buf() to have the dlci handling follow the same path as
  for gsm_serdev_register_dlci()

- Updated for Pavel's comments and acks, did not keep the ack for
  n_gsm.c as that has changed

- Moved the GNSS driver binding to serdev-ngsm.yaml as suggested
  by Rob

- Folded in a a fix from kbuild test robot <lkp@intel.com>
  to make motmdm_gnss_send_command() static

Changes since v6:
- Based on comments from Johan, moved back to using the existing
  TS 27.010 TTYs created by n_gsm.c instaed of adding custom chardev
  support to deal with the Motorola custom protocol

- Based on comments from Johan, made the serdev-ngsm driver generic
  with just minimal quirk handling for the Motorola modem

- Dropped the Motorola custom protocol on top of TS 27.010 handling
  from serdev-ngsm.c as this can now be easily handled by the channel
  specific drivers as needed

- Added few more helpers to n_gsm.c for serdev-ngsm.c to use

- Added the channel specific GNSS driver for the Motorola modem

Changes since v5:
- Cosmetic fixes for issues noted by Pavel

Changes since v4:
- Use drivers/tty/serdev/protocol directory for the driver instead of
  drivers/mfd as discussed on the lists for v3 set of patches
- Fix remove to call kfree only after removing device from the list

Changes since v3:
- Update list of folks in Cc, looks like I sent v3 only to Lee and lkml
- Init privdata before motmdm_register_dlci calls gsm_serdev_register_dlci
- Update binding based on Rob's comments for license and "allOf"

Changes since v2:
- Drop useless send_command indirection, use static motmdm_send_command

Changes since v1:

- Simplified usage and got rid of few pointless inline functions
- Added consumer MFD driver, devicetree binding, and dts changes


Tony Lindgren (6):
  tty: n_gsm: Add support for serdev drivers
  dt-bindings: serdev: ngsm: Add binding for serdev-ngsm
  dt-bindings: serdev: ngsm: Add binding for GNSS child node
  serdev: ngsm: Add generic serdev-ngsm driver
  gnss: motmdm: Add support for Motorola Mapphone MDM6600 modem
  ARM: dts: omap4-droid4: Configure modem for serdev-ngsm

 .../bindings/serdev/serdev-ngsm.yaml          |  73 +++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 .../boot/dts/motorola-mapphone-common.dtsi    |  14 +
 drivers/gnss/Kconfig                          |   8 +
 drivers/gnss/Makefile                         |   3 +
 drivers/gnss/motmdm.c                         | 419 ++++++++++++++++
 drivers/tty/n_gsm.c                           | 435 +++++++++++++++++
 drivers/tty/serdev/Kconfig                    |  10 +
 drivers/tty/serdev/Makefile                   |   1 +
 drivers/tty/serdev/serdev-ngsm.c              | 449 ++++++++++++++++++
 include/linux/serdev-gsm.h                    | 165 +++++++
 11 files changed, 1579 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serdev/serdev-ngsm.yaml
 create mode 100644 drivers/gnss/motmdm.c
 create mode 100644 drivers/tty/serdev/serdev-ngsm.c
 create mode 100644 include/linux/serdev-gsm.h

Comments

Pavel Machek Dec. 16, 2020, 10:56 p.m. UTC | #1
Hi!

> > Here's the updated set of these patches fixed up for Johan's and
> > Pavel's earlier comments.
> > 
> > This series does the following:
> > 
> > 1. Adds functions to n_gsm.c for serdev-ngsm.c driver to use
> > 
> > 2. Adds a generic serdev-ngsm.c driver that brings up the TS 27.010
> >    TTY ports configured in devicetree with help of n_gsm.c
> > 
> > 3. Allows the use of standard Linux device drivers for dedicated
> >    TS 27.010 channels for devices like GNSS and ALSA found on some
> >    modems for example
> 
> Unfortunately that does not seem to be the case just yet. Your gnss
> driver is still aware that it's using n_gsm for the transport and calls
> into the "parent" serdev-ngsm driver instead of using the serdev
> interface (e.g. as if this was still and MFD driver).

It took me a while to understand what is wrong and how to fix it, but
I seem to have something now.

You... don't want to look at patch below as it is very very much work
in progress.

Best regards,
								Pavel

diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
index f5e7ec8e1028..ce907aa40a28 100644
--- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
@@ -761,9 +761,22 @@
 		};
 
 		gnss@4 {
-			compatible = "motorola,mapphone-mdm6600-gnss";
+			compatible = "disabled-old,motorola,mapphone-mdm6600-gnss";
 			reg = <4>;
 		};
+
+		port@1 {
+			compatible = "gsmmux,port";
+			reg = <1>;
+			subdev@1 {
+				 compatible = "motorola,mapphone-mdm6600-gnss";
+			};
+		};
+
+		port@3 {
+			compatible = "disabled,gsmmux,port";
+			reg = <3>;
+		};
 	};
 };
 
diff --git a/drivers/gnss/motmdm.c b/drivers/gnss/motmdm.c
index da1d44bed899..4668754408eb 100644
--- a/drivers/gnss/motmdm.c
+++ b/drivers/gnss/motmdm.c
@@ -3,11 +3,14 @@
  * Motorola Modem TS 27.010 serdev GNSS driver
  *
  * Copyright (C) 2018 - 2020 Tony Lindgren <tony@atomide.com>
+ * Copyright (C) 2020 Pavel Machek <pavel@ucw.cz>
  *
  * Based on drivers/gnss/sirf.c driver example:
  * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
  */
 
+/* FIXME: see serial.c for good example..? */
+
 #include <linux/errno.h>
 #include <linux/gnss.h>
 #include <linux/init.h>
@@ -45,7 +48,7 @@ enum motmdm_gnss_status {
 struct motmdm_gnss_data {
 	struct gnss_device *gdev;
 	struct device *modem;
-	struct gsm_serdev_dlci dlci;
+	struct gsm_serdev_dlci_operations dlci;
 	struct delayed_work restart_work;
 	struct mutex mutex;	/* For modem commands */
 	ktime_t last_update;
@@ -76,6 +79,7 @@ int motmdm_gnss_send_command(struct motmdm_gnss_data *ddata,
 	unsigned char cmd[128];
 	int ret, cmdlen;
 
+#if 0
 	cmdlen = len + 5 + 1;
 	if (cmdlen > 128)
 		return -EINVAL;
@@ -109,6 +113,7 @@ int motmdm_gnss_send_command(struct motmdm_gnss_data *ddata,
 	mutex_unlock(&ddata->mutex);
 
 	return ret;
+#endif
 }
 
 /*
@@ -198,7 +203,7 @@ static int motmdm_gnss_finish(struct gnss_device *gdev)
 	return motmdm_gnss_send_command(ddata, cmd, strlen(cmd));
 }
 
-static int motmdm_gnss_receive_data(struct gsm_serdev_dlci *dlci,
+static int motmdm_gnss_receive_data(struct gsm_serdev_dlci_operations *dlci,
 				    const unsigned char *buf,
 				    size_t len)
 {
@@ -208,6 +213,8 @@ static int motmdm_gnss_receive_data(struct gsm_serdev_dlci *dlci,
 	size_t msglen;
 	int error = 0;
 
+	printk("motmdm_gnss_receive_data\n");
+
 	if (len <= MOTMDM_GNSS_RESP_LEN)
 		return 0;
 
@@ -283,9 +290,10 @@ static int motmdm_gnss_receive_data(struct gsm_serdev_dlci *dlci,
 static int motmdm_gnss_open(struct gnss_device *gdev)
 {
 	struct motmdm_gnss_data *ddata = gnss_get_drvdata(gdev);
-	struct gsm_serdev_dlci *dlci = &ddata->dlci;
+	struct gsm_serdev_dlci_operations *dlci = &ddata->dlci;
 	int error;
 
+#if 0
 	dlci->drvdata = gdev;
 	dlci->receive_buf = motmdm_gnss_receive_data;
 
@@ -299,16 +307,17 @@ static int motmdm_gnss_open(struct gnss_device *gdev)
 
 		return error;
 	}
-
+#endif
 	return 0;
 }
 
 static void motmdm_gnss_close(struct gnss_device *gdev)
 {
 	struct motmdm_gnss_data *ddata = gnss_get_drvdata(gdev);
-	struct gsm_serdev_dlci *dlci = &ddata->dlci;
+	struct gsm_serdev_dlci_operations *dlci = &ddata->dlci;
 	int error;
 
+#if 0
 	dlci->receive_buf = NULL;
 	error = motmdm_gnss_finish(gdev);
 	if (error < 0)
@@ -316,15 +325,18 @@ static void motmdm_gnss_close(struct gnss_device *gdev)
 			 __func__, error);
 
 	serdev_ngsm_unregister_dlci(ddata->modem, dlci);
+#endif
 }
 
 static int motmdm_gnss_write_raw(struct gnss_device *gdev,
 				 const unsigned char *buf,
 				 size_t count)
 {
+#if 0
 	struct motmdm_gnss_data *ddata = gnss_get_drvdata(gdev);
 
 	return serdev_ngsm_write(ddata->modem, &ddata->dlci, buf, count);
+#endif
 }
 
 static const struct gnss_operations motmdm_gnss_ops = {
@@ -333,7 +345,84 @@ static const struct gnss_operations motmdm_gnss_ops = {
 	.write_raw	= motmdm_gnss_write_raw,
 };
 
-static int motmdm_gnss_probe(struct platform_device *pdev)
+static int gnss_serial_receive_buf(struct serdev_device *serdev,
+                                        const unsigned char *buf, size_t count)
+{
+	printk("gnss_serial_recieve: %d bytes\n", count);
+	printk("gnss_serial_recieve: have data: %s bytes\n", buf);
+#if 0
+        struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
+	struct gnss_device *gdev = gserial->gdev;
+
+	return gnss_insert_raw(gdev, buf, count);
+#endif
+}
+
+static const struct serdev_device_ops gnss_serial_serdev_ops = {
+        .receive_buf    = gnss_serial_receive_buf,
+        .write_wakeup   = serdev_device_write_wakeup,
+};
+
+
+int motmdm_gnss_test(struct serdev_device *serdev)
+{
+	int ret;
+	if (!serdev)
+		return -EIO;
+	printk("have serdev_device: %p, nr %d\n", serdev, serdev->nr);
+
+	dev_info(&serdev->dev, "interesting line\n");
+	
+	/* HERE */
+	serdev_device_set_drvdata(serdev, NULL);
+        serdev_device_set_client_ops(serdev, &gnss_serial_serdev_ops);
+
+	dev_info(&serdev->dev, "opening serdev\n");
+	ret = serdev_device_open(serdev);
+        if (ret) {
+                return ret;
+	}
+
+//        serdev_device_set_baudrate(serdev, gserial->speed);
+//        serdev_device_set_flow_control(serdev, false);
+	dev_info(&serdev->dev, "writing\n");
+	
+	{
+		int count = 5;
+	ret = serdev_device_write(serdev, "HELLO", count, MAX_SCHEDULE_TIMEOUT);
+        if (ret < 0 || ret < count)
+                return ret;
+
+	}
+	dev_info(&serdev->dev, "waiting\n");
+	
+        serdev_device_wait_until_sent(serdev, 0);
+	dev_info(&serdev->dev, "all ok\n");
+	
+	return 0;
+}
+
+int motmdm_gnss_attach(struct device *dev, int line)
+{
+	int ret;
+	void *me = NULL; /* FIXME */
+        struct serdev_controller *ctrl = to_serdev_controller(dev);
+	struct serdev_device *serdev = ctrl->serdev;
+
+	dev_info(dev, "motmdm_gnss_attach: %d\n", line);
+	if (line != 1)
+		return 0;
+	
+	printk("have serdev_controller: %p == %p, nr %d\n", ctrl, dev, ctrl->nr);
+	printk("have serdev_device: %p %p\n", serdev, dev);
+
+	return motmdm_gnss_test(serdev);
+}
+
+
+EXPORT_SYMBOL(motmdm_gnss_attach);
+
+static int motmdm_gnss_probe(struct serdev_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct motmdm_gnss_data *ddata;
@@ -341,14 +430,22 @@ static int motmdm_gnss_probe(struct platform_device *pdev)
 	u32 line;
 	int ret;
 
+	printk("gnss_probe\n");
+
 	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
 	if (!ddata)
 		return -ENOMEM;
 
+	printk("gnss_probe: searching for reg\n");
+	motmdm_gnss_test(pdev);
+
+#if 0      
 	ret = of_property_read_u32(dev->of_node, "reg", &line);
 	if (ret)
 		return ret;
 
+	printk("gnss_probe: should not go here\n");
+
 	if (!line)
 		return -EINVAL;
 
@@ -384,16 +481,17 @@ static int motmdm_gnss_probe(struct platform_device *pdev)
 	gnss_put_device(ddata->gdev);
 
 	return ret;
+#endif
 }
 
-static int motmdm_gnss_remove(struct platform_device *pdev)
+static void motmdm_gnss_remove(struct serdev_device *pdev)
 {
+#if 0
 	struct motmdm_gnss_data *data = platform_get_drvdata(pdev);
 
 	gnss_deregister_device(data->gdev);
 	gnss_put_device(data->gdev);
-
-	return 0;
+#endif
 };
 
 #ifdef CONFIG_OF
@@ -404,7 +502,7 @@ static const struct of_device_id motmdm_gnss_of_match[] = {
 MODULE_DEVICE_TABLE(of, motmdm_gnss_of_match);
 #endif
 
-static struct platform_driver motmdm_gnss_driver = {
+static struct serdev_device_driver motmdm_gnss_driver = {
 	.driver	= {
 		.name		= "gnss-mot-mdm6600",
 		.of_match_table	= of_match_ptr(motmdm_gnss_of_match),
@@ -412,7 +510,7 @@ static struct platform_driver motmdm_gnss_driver = {
 	.probe	= motmdm_gnss_probe,
 	.remove	= motmdm_gnss_remove,
 };
-module_platform_driver(motmdm_gnss_driver);
+module_serdev_device_driver(motmdm_gnss_driver);
 
 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
 MODULE_DESCRIPTION("Motorola Mapphone MDM6600 GNSS receiver driver");
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 460123447fa1..e4d18d38fc42 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -52,14 +52,17 @@
 #include <linux/etherdevice.h>
 #include <linux/gsmmux.h>
 #include <linux/serdev-gsm.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 static int debug;
 module_param(debug, int, 0600);
 
 /* Defaults: these are from the specification */
 
-#define T1	10		/* 100mS */
-#define T2	34		/* 333mS */
+#define T1	10		/* 100ms */
+#define T2	34		/* 333ms */
 #define N2	3		/* Retry 3 times */
 
 /* Use long timers for testing at low speed with debug on */
@@ -152,7 +155,7 @@ struct gsm_dlci {
 	/* Data handling callback */
 	void (*data)(struct gsm_dlci *dlci, const u8 *data, int len);
 	void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len);
-	struct gsm_serdev_dlci *ops; /* serdev dlci ops, if used */
+	struct gsm_serdev_dlci_operations *ops; /* serdev dlci ops, if used */
 	struct net_device *net; /* network interface, if created */
 };
 
@@ -1019,7 +1022,7 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
 static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
 							u32 modem, int clen)
 {
-	int  mlines = 0;
+	int mlines = 0;
 	u8 brk = 0;
 	int fc;
 
@@ -2344,38 +2347,10 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
 }
 
 #ifdef CONFIG_SERIAL_DEV_BUS
-
-/**
- * gsm_serdev_get_config - read ts 27.010 config
- * @gsd:	serdev-gsm instance
- * @c:		ts 27.010 config data
- *
- * See gsm_copy_config_values() for more information.
- */
-int gsm_serdev_get_config(struct gsm_serdev *gsd, struct gsm_config *c)
-{
-	struct gsm_mux *gsm;
-
-	if (!gsd || !gsd->gsm)
-		return -ENODEV;
-
-	gsm = gsd->gsm;
-
-	if (!c)
-		return -EINVAL;
-
-	gsm_copy_config_values(gsm, c);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(gsm_serdev_get_config);
-
 /**
  * gsm_serdev_set_config - set ts 27.010 config
  * @gsd:	serdev-gsm instance
  * @c:		ts 27.010 config data
- *
- * See gsm_config() for more information.
  */
 int gsm_serdev_set_config(struct gsm_serdev *gsd, struct gsm_config *c)
 {
@@ -2404,7 +2379,7 @@ static struct gsm_dlci *gsd_dlci_get(struct gsm_serdev *gsd, int line,
 
 	gsm = gsd->gsm;
 
-	if (line < 1 || line >= 63)
+	if (line < 1 || line >= 62)
 		return ERR_PTR(-EINVAL);
 
 	mutex_lock(&gsm->mutex);
@@ -2431,7 +2406,7 @@ static struct gsm_dlci *gsd_dlci_get(struct gsm_serdev *gsd, int line,
 	return dlci;
 }
 
-static int gsd_dlci_receive_buf(struct gsm_serdev_dlci *ops,
+static int gsd_dlci_receive_buf(struct gsm_serdev_dlci_operations *ops,
 				const unsigned char *buf,
 				size_t len)
 {
@@ -2471,6 +2446,7 @@ static void gsd_dlci_data(struct gsm_dlci *dlci, const u8 *buf, int len)
 	}
 }
 
+/* FIXME: we should not be doing this; serdev_controller_ops->write_buf should be enough? */
 /**
  * gsm_serdev_write - write data to a ts 27.010 channel
  * @gsd:	serdev-gsm instance
@@ -2478,7 +2454,7 @@ static void gsd_dlci_data(struct gsm_dlci *dlci, const u8 *buf, int len)
  * @buf:	write buffer
  * @len:	buffer length
  */
-int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci_operations *ops,
 		     const u8 *buf, int len)
 {
 	struct gsm_mux *gsm;
@@ -2551,7 +2527,7 @@ EXPORT_SYMBOL_GPL(gsm_serdev_data_kick);
  * @ops:	channel ops
  */
 int gsm_serdev_register_dlci(struct gsm_serdev *gsd,
-			     struct gsm_serdev_dlci *ops)
+			     struct gsm_serdev_dlci_operations *ops)
 {
 	struct gsm_dlci *dlci;
 	struct gsm_mux *gsm;
@@ -2609,7 +2585,7 @@ EXPORT_SYMBOL_GPL(gsm_serdev_register_dlci);
  * @ops:	channel ops
  */
 void gsm_serdev_unregister_dlci(struct gsm_serdev *gsd,
-				struct gsm_serdev_dlci *ops)
+				struct gsm_serdev_dlci_operations *ops)
 {
 	struct gsm_mux *gsm;
 	struct gsm_dlci *dlci;
@@ -2681,12 +2657,16 @@ static struct serdev_device_ops gsd_client_ops = {
 	.write_wakeup = gsd_write_wakeup,
 };
 
+extern int motmdm_gnss_attach(struct device *dev, int line);
+
 int gsm_serdev_register_tty_port(struct gsm_serdev *gsd, int line)
 {
-	struct gsm_serdev_dlci *ops;
+	struct gsm_serdev_dlci_operations *ops;
 	unsigned int base;
 	int error;
-
+	struct device *dev;
+	struct device_node *node;
+		
 	if (line < 1)
 		return -EINVAL;
 
@@ -2704,8 +2684,83 @@ int gsm_serdev_register_tty_port(struct gsm_serdev *gsd, int line)
 		return error;
 	}
 
+
 	base = mux_num_to_base(gsd->gsm);
-	tty_register_device(gsm_tty_driver, base + ops->line, NULL);
+	printk("register_tty_port: have port: %p, %d+%d\n", &gsd->gsm->dlci[line]->port, base, ops->line);
+	dev = &gsd->serdev->dev;
+	if (line != 1)
+		return 0;
+
+	for_each_available_child_of_node(dev->of_node, node) {
+		struct platform_device_info devinfo = {};
+		static int idx;
+		struct platform_device *pdev;
+		const char *c = of_get_property(node, "compatible", NULL);
+		
+		dev_info(dev, "register_tty: child -- %pOF\n", node);
+
+		if (!c)
+			continue;
+		dev_info(dev, "register_tty: child -- %pOF -- compatible %s\n", node, c);
+		if (strcmp(c, "gsmmux,port"))
+			continue;
+
+		printk("n_gsm: Have subnode with right compatible!\n");
+		
+		devinfo.name = kasprintf(GFP_KERNEL, "gsm-mux-%d", idx++);
+		devinfo.parent = dev;
+
+		/* Thanks to core.c: serdev_device_add */
+		pdev = platform_device_register_full(&devinfo);
+		pdev->dev.of_node = node;
+
+#if 0
+		tty_register_device(gsm_tty_driver, base + ops->line, NULL);
+#else
+		{
+			struct device *dev;
+
+			dev = tty_port_register_device_serdev(&gsd->gsm->dlci[line]->port, gsm_tty_driver, base + ops->line, &pdev->dev /* FIXME: needs non-null to attempt serdev registration */ );
+			printk("register_tty_port: got %p\n", dev);
+			{
+#if 0
+				struct serdev_controller *ctrl = to_serdev_controller(dev);
+				struct serdev_device *serdev = serdev_device_alloc(ctrl);
+				int err;
+				if (!serdev)
+					dev_err(dev, "could not alloc serdev, that is bad\n");
+
+				//serdev->dev.of_node = node;
+
+				err = serdev_device_add(serdev);
+				if (err) {
+					dev_err(&serdev->dev,
+						"failure adding device. status %pe\n",
+						ERR_PTR(err));
+					//serdev_device_put(serdev);
+				}
+#endif
+#if 0
+				printk("register_tty_port: Forcing attach\n");
+				/* FIXME: Need to do of_serdev_register_devices() ? */
+				motmdm_gnss_attach(dev, ops->line);
+#endif
+			}
+
+		}
+	}
+#endif
+	/* FIXME:
+
+extern struct device *tty_register_device(struct tty_driver *driver,
+                                          unsigned index, struct device *dev);
+
+Would like tty_port_register_device_attr or better
+	   	       tty_port_register_device_attr_serdev 
+
+ale chce navic struct tty_port *.
+
+		       _attr() -- last 2 arguments can be NULL. */
 
 	return 0;
 }
@@ -2730,7 +2785,7 @@ void gsm_serdev_unregister_tty_port(struct gsm_serdev *gsd, int line)
 }
 EXPORT_SYMBOL_GPL(gsm_serdev_unregister_tty_port);
 
-struct gsm_serdev_dlci *
+struct gsm_serdev_dlci_operations *
 gsm_serdev_tty_port_get_dlci(struct gsm_serdev *gsd, int line)
 {
 	struct gsm_dlci *dlci;
@@ -3644,7 +3699,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
 				    properly */
 		encode = 0x0F;
 	else if (state > 0) {
-		encode = state / 200;	/* mS to encoding */
+		encode = state / 200;	/* ms to encoding */
 		if (encode > 0x0F)
 			encode = 0x0F;	/* Best effort */
 	}
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index c5f0d936b003..081702d5479d 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -121,7 +121,7 @@ int serdev_device_add(struct serdev_device *serdev)
 		goto err_clear_serdev;
 	}
 
-	dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev));
+	dev_info(&serdev->dev, "device %s registered, %p controller %p\n", dev_name(&serdev->dev), serdev, ctrl);
 
 	return 0;
 
@@ -509,7 +509,15 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent,
 	pm_runtime_no_callbacks(&ctrl->dev);
 	pm_suspend_ignore_children(&ctrl->dev, true);
 
-	dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);
+	/* /sys/bus/serial/drivers/serdev_ngsm/serial0-0 ?
+
+4806a000.serial:modem:audio-codec@2  modalias  subsystem
+4806a000.serial:modem:gnss@4	     of_node   supplier:phy-usb-phy@1.1
+driver				     power     uevent
+
+	*/
+	dev_info(&ctrl->dev, "allocated controller 0x%p 0x%p id %d [%d]\n",
+		 ctrl, &ctrl->dev, id, ctrl->nr);
 	return ctrl;
 
 err_free:
@@ -527,10 +535,12 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
 	bool found = false;
 
 	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		dev_info(&ctrl->dev, "of_serdev_register_device: considering %pOF\n", node);
+		
 		if (!of_get_property(node, "compatible", NULL))
 			continue;
 
-		dev_dbg(&ctrl->dev, "adding child %pOF\n", node);
+		dev_info(&ctrl->dev, "adding child %pOF\n", node);
 
 		serdev = serdev_device_alloc(ctrl);
 		if (!serdev)
@@ -740,26 +750,34 @@ int serdev_controller_add(struct serdev_controller *ctrl)
 {
 	int ret_of, ret_acpi, ret;
 
+	printk("serdev_controller_add...\n");
+
 	/* Can't register until after driver model init */
 	if (WARN_ON(!is_registered))
 		return -EAGAIN;
 
+	printk("serdev_controller_add 1... %pOF\n", ctrl->dev.of_node);
+	
 	ret = device_add(&ctrl->dev);
 	if (ret)
 		return ret;
 
+	printk("serdev_controller_add 2...\n");	
 	pm_runtime_enable(&ctrl->dev);
 
 	ret_of = of_serdev_register_devices(ctrl);
 	ret_acpi = acpi_serdev_register_devices(ctrl);
 	if (ret_of && ret_acpi) {
-		dev_dbg(&ctrl->dev, "no devices registered: of:%pe acpi:%pe\n",
+		dev_info(&ctrl->dev, "no devices registered: of:%pe acpi:%pe\n",
 			ERR_PTR(ret_of), ERR_PTR(ret_acpi));
+#if 0
 		ret = -ENODEV;
 		goto err_rpm_disable;
+#endif		
 	}
 
-	dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n",
+	printk("serdev_controller_add all ok?...\n");		
+	dev_info(&ctrl->dev, "serdev%d registered: dev:%p\n",
 		ctrl->nr, &ctrl->dev);
 	return 0;
 
diff --git a/drivers/tty/serdev/serdev-ngsm.c b/drivers/tty/serdev/serdev-ngsm.c
index a247cf36df4f..a250a3594f71 100644
--- a/drivers/tty/serdev/serdev-ngsm.c
+++ b/drivers/tty/serdev/serdev-ngsm.c
@@ -40,7 +40,7 @@ struct serdev_ngsm {
 	const struct serdev_ngsm_cfg *cfg;
 };
 
-static int serdev_ngsm_tty_init(struct serdev_ngsm *ddata)
+static int serdev_ngsm_tty_init(struct serdev_ngsm *ddata, void *node /* will need of node here ? */)
 {
 	struct gsm_serdev *gsd = &ddata->gsd;
 	struct device *dev = ddata->dev;
@@ -50,7 +50,7 @@ static int serdev_ngsm_tty_init(struct serdev_ngsm *ddata)
 		if (BIT_ULL(bit) & TS27010_RESERVED_DLCI)
 			continue;
 
-		err = gsm_serdev_register_tty_port(gsd, bit);
+		err = gsm_serdev_register_tty_port(gsd, bit /*, node FIXME */);
 		if (err) {
 			dev_err(dev, "ngsm tty init failed for dlci%i: %i\n",
 				bit, err);
@@ -80,7 +80,7 @@ static void serdev_ngsm_tty_exit(struct serdev_ngsm *ddata)
  * drivers may have already reserved.
  */
 int serdev_ngsm_register_dlci(struct device *dev,
-			      struct gsm_serdev_dlci *dlci)
+			      struct gsm_serdev_dlci_operations *dlci)
 {
 	struct serdev_ngsm *ddata = gsm_serdev_get_drvdata(dev);
 	struct gsm_serdev *gsd = &ddata->gsd;
@@ -95,7 +95,7 @@ int serdev_ngsm_register_dlci(struct device *dev,
 EXPORT_SYMBOL_GPL(serdev_ngsm_register_dlci);
 
 void serdev_ngsm_unregister_dlci(struct device *dev,
-				 struct gsm_serdev_dlci *dlci)
+				 struct gsm_serdev_dlci_operations *dlci)
 {
 	struct serdev_ngsm *ddata = gsm_serdev_get_drvdata(dev);
 	struct gsm_serdev *gsd = &ddata->gsd;
@@ -104,7 +104,7 @@ void serdev_ngsm_unregister_dlci(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(serdev_ngsm_unregister_dlci);
 
-int serdev_ngsm_write(struct device *dev, struct gsm_serdev_dlci *ops,
+int serdev_ngsm_write(struct device *dev, struct gsm_serdev_dlci_operations *ops,
 		      const u8 *buf, int len)
 {
 	struct serdev_ngsm *ddata = gsm_serdev_get_drvdata(dev);
@@ -127,7 +127,7 @@ int serdev_ngsm_write(struct device *dev, struct gsm_serdev_dlci *ops,
 }
 EXPORT_SYMBOL_GPL(serdev_ngsm_write);
 
-struct gsm_serdev_dlci *
+struct gsm_serdev_dlci_operations *
 serdev_ngsm_get_dlci(struct device *dev, int line)
 {
 	struct serdev_ngsm *ddata = gsm_serdev_get_drvdata(dev);
@@ -377,7 +377,7 @@ static int serdev_ngsm_probe(struct serdev_device *serdev)
 	if (err)
 		goto err_close;
 
-	err = serdev_ngsm_tty_init(ddata);
+	err = serdev_ngsm_tty_init(ddata, NULL /* FIXME! */);
 	if (err)
 		goto err_tty;
 
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index d367803e2044..6f02a1546560 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -272,6 +272,8 @@ struct device *serdev_tty_port_register(struct tty_port *port,
 	if (!port || !drv || !parent)
 		return ERR_PTR(-ENODEV);
 
+	printk("serdev_tty_port_register: %p, %d\n", port, idx);
+
 	ctrl = serdev_controller_alloc(parent, sizeof(struct serport));
 	if (!ctrl)
 		return ERR_PTR(-ENOMEM);
@@ -291,9 +293,12 @@ struct device *serdev_tty_port_register(struct tty_port *port,
 		goto err_reset_data;
 
 	dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx);
+	printk("serdev_tty_port_register: controller is  %p, serdev %p\n", ctrl, ctrl->serdev);
+	
 	return &ctrl->dev;
 
 err_reset_data:
+	printk("serdev_tty_port_register: error?\n");
 	port->client_data = NULL;
 	port->client_ops = &tty_port_default_client_ops;
 	serdev_controller_put(ctrl);
diff --git a/include/linux/serdev-gsm.h b/include/linux/serdev-gsm.h
index 4fa819a6e366..5bdc8143b7df 100644
--- a/include/linux/serdev-gsm.h
+++ b/include/linux/serdev-gsm.h
@@ -7,7 +7,7 @@
 #include <linux/serdev.h>
 #include <linux/types.h>
 
-struct gsm_serdev_dlci;
+struct gsm_serdev_dlci_operations;
 struct gsm_config;
 
 /**
@@ -28,16 +28,16 @@ struct gsm_serdev {
 };
 
 /**
- * struct gsm_serdev_dlci - serdev-gsm ts 27.010 channel data
+ * struct gsm_serdev_dlci_operations - serdev-gsm ts 27.010 channel data
  * @gsd:		serdev-gsm instance
  * @line:		ts 27.010 channel, control channel 0 is not available
  * @receive_buf:	function to handle data received for the channel
  * @drvdata:		dlci specific consumer driver data
  */
-struct gsm_serdev_dlci {
+struct gsm_serdev_dlci_operations {
 	struct gsm_serdev *gsd;
 	int line;
-	int (*receive_buf)(struct gsm_serdev_dlci *ops,
+	int (*receive_buf)(struct gsm_serdev_dlci_operations *ops,
 			   const unsigned char *buf,
 			   size_t len);
 	void *drvdata;
@@ -48,12 +48,12 @@ struct gsm_serdev_dlci {
 /* TS 27.010 channel specific functions for consumer drivers */
 #if IS_ENABLED(CONFIG_SERIAL_DEV_N_GSM)
 extern int
-serdev_ngsm_register_dlci(struct device *dev, struct gsm_serdev_dlci *dlci);
+serdev_ngsm_register_dlci(struct device *dev, struct gsm_serdev_dlci_operations *dlci);
 extern void serdev_ngsm_unregister_dlci(struct device *dev,
-					struct gsm_serdev_dlci *dlci);
-extern int serdev_ngsm_write(struct device *dev, struct gsm_serdev_dlci *ops,
+					struct gsm_serdev_dlci_operations *dlci);
+extern int serdev_ngsm_write(struct device *dev, struct gsm_serdev_dlci_operations *ops,
 			     const u8 *buf, int len);
-extern struct gsm_serdev_dlci *
+extern struct gsm_serdev_dlci_operations *
 serdev_ngsm_get_dlci(struct device *dev, int line);
 #endif
 
@@ -62,7 +62,7 @@ extern int gsm_serdev_register_device(struct gsm_serdev *gsd);
 extern void gsm_serdev_unregister_device(struct gsm_serdev *gsd);
 extern int gsm_serdev_register_tty_port(struct gsm_serdev *gsd, int line);
 extern void gsm_serdev_unregister_tty_port(struct gsm_serdev *gsd, int line);
-extern struct gsm_serdev_dlci *
+extern struct gsm_serdev_dlci_operations *
 gsm_serdev_tty_port_get_dlci(struct gsm_serdev *gsd, int line);
 
 static inline void *gsm_serdev_get_drvdata(struct device *dev)
@@ -88,10 +88,10 @@ static inline void gsm_serdev_set_drvdata(struct device *dev, void *drvdata)
 extern int gsm_serdev_get_config(struct gsm_serdev *gsd, struct gsm_config *c);
 extern int gsm_serdev_set_config(struct gsm_serdev *gsd, struct gsm_config *c);
 extern int
-gsm_serdev_register_dlci(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops);
+gsm_serdev_register_dlci(struct gsm_serdev *gsd, struct gsm_serdev_dlci_operations *ops);
 extern void
-gsm_serdev_unregister_dlci(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops);
-extern int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+gsm_serdev_unregister_dlci(struct gsm_serdev *gsd, struct gsm_serdev_dlci_operations *ops);
+extern int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci_operations *ops,
 			    const u8 *buf, int len);
 extern void gsm_serdev_data_kick(struct gsm_serdev *gsd);
 
@@ -118,7 +118,7 @@ void gsm_serdev_unregister_tty_port(struct gsm_serdev *gsd, int line)
 {
 }
 
-static inline struct gsm_serdev_dlci *
+static inline struct gsm_serdev_dlci_operations *
 gsm_serdev_tty_port_get_dlci(struct gsm_serdev *gsd, int line)
 {
 	return NULL;
@@ -148,19 +148,19 @@ int gsm_serdev_set_config(struct gsm_serdev *gsd, struct gsm_config *c)
 
 static inline
 int gsm_serdev_register_dlci(struct gsm_serdev *gsd,
-			     struct gsm_serdev_dlci *ops)
+			     struct gsm_serdev_dlci_operations *ops)
 {
 	return -ENODEV;
 }
 
 static inline
 void gsm_serdev_unregister_dlci(struct gsm_serdev *gsd,
-				struct gsm_serdev_dlci *ops)
+				struct gsm_serdev_dlci_operations *ops)
 {
 }
 
 static inline
-int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci *ops,
+int gsm_serdev_write(struct gsm_serdev *gsd, struct gsm_serdev_dlci_operations *ops,
 		     const u8 *buf, int len)
 {
 	return -ENODEV;
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 9f14f9c12ec4..efdffe34a9b5 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -128,6 +128,7 @@ static inline void serdev_device_set_drvdata(struct serdev_device *serdev, void
  */
 static inline void serdev_device_put(struct serdev_device *serdev)
 {
+	printk("serdev_device_put... %p\n", serdev);
 	if (serdev)
 		put_device(&serdev->dev);
 }
@@ -156,6 +157,8 @@ static inline void serdev_controller_set_drvdata(struct serdev_controller *ctrl,
  */
 static inline void serdev_controller_put(struct serdev_controller *ctrl)
 {
+	printk("serdev_controller_put... %p\n", ctrl);
+	WARN_ON(1);
 	if (ctrl)
 		put_device(&ctrl->dev);
 }
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index afb9521ddf91..530a0146893c 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -802,7 +802,7 @@ static char *ptr_to_id(char *buf, char *end, const void *ptr,
 	 * Print the real pointer value for NULL and error pointers,
 	 * as they are not actual addresses.
 	 */
-	if (IS_ERR_OR_NULL(ptr))
+//	if (IS_ERR_OR_NULL(ptr))
 		return pointer_string(buf, end, ptr, spec);
 
 	/* When debugging early boot use non-cryptographically secure hash. */
diff --git a/sound/soc/codecs/motmdm.c b/sound/soc/codecs/motmdm.c
index 325a860ef665..1528c89d9d57 100644
--- a/sound/soc/codecs/motmdm.c
+++ b/sound/soc/codecs/motmdm.c
@@ -28,7 +28,7 @@ struct motmdm_driver_data {
 	struct snd_soc_component *component;
 	struct snd_soc_dai *master_dai;
 	struct device *modem;
-	struct gsm_serdev_dlci dlci;
+	struct gsm_serdev_dlci_operations dlci;
 	struct regmap *regmap;
 	unsigned char *buf;
 	size_t len;
@@ -38,7 +38,7 @@ struct motmdm_driver_data {
 	struct mutex mutex;	/* for sending commands */
 	wait_queue_head_t read_queue;
 
-	int (*receive_buf_orig)(struct gsm_serdev_dlci *ops,
+	int (*receive_buf_orig)(struct gsm_serdev_dlci_operations *ops,
 				const unsigned char *buf,
 				size_t len);
 	unsigned int dtmf_val;
@@ -121,7 +121,7 @@ static int motmdm_send_command(struct motmdm_driver_data *ddata,
 }
 
 /* Handle U1234+XXXX= style command response */
-static int motmdm_receive_data(struct gsm_serdev_dlci *dlci,
+static int motmdm_receive_data(struct gsm_serdev_dlci_operations *dlci,
 			       const unsigned char *buf,
 			       size_t len)
 {
@@ -569,7 +569,7 @@ static void motmdm_voice_get_state(struct motmdm_driver_data *ddata,
 		motmdm_disable_primary_dai(ddata->component);
 }
 
-static int receive_buf_voice(struct gsm_serdev_dlci *ops,
+static int receive_buf_voice(struct gsm_serdev_dlci_operations *ops,
 			     const unsigned char *buf,
 			     size_t len)
 {
@@ -585,7 +585,7 @@ static int receive_buf_voice(struct gsm_serdev_dlci *ops,
 /* Read the voice status from dlci1 and let user space handle rest */
 static int motmdm_init_voice_dlci(struct motmdm_driver_data *ddata)
 {
-	struct gsm_serdev_dlci *dlci;
+	struct gsm_serdev_dlci_operations *dlci;
 
 	dlci = serdev_ngsm_get_dlci(ddata->modem, MOTMDM_VOICE_DLCI);
 	if (!dlci)
@@ -600,7 +600,7 @@ static int motmdm_init_voice_dlci(struct motmdm_driver_data *ddata)
 
 static void motmdm_free_voice_dlci(struct motmdm_driver_data *ddata)
 {
-	struct gsm_serdev_dlci *dlci;
+	struct gsm_serdev_dlci_operations *dlci;
 
 	dlci = serdev_ngsm_get_dlci(ddata->modem, MOTMDM_VOICE_DLCI);
 	if (!dlci)
@@ -613,7 +613,7 @@ static void motmdm_free_voice_dlci(struct motmdm_driver_data *ddata)
 static int motmdm_soc_probe(struct snd_soc_component *component)
 {
 	struct motmdm_driver_data *ddata;
-	struct gsm_serdev_dlci *dlci;
+	struct gsm_serdev_dlci_operations *dlci;
 	const unsigned char *cmd = "AT+CMUT=0";
 	int error;
 	u32 line;
@@ -690,7 +690,7 @@ static int motmdm_soc_probe(struct snd_soc_component *component)
 static void motmdm_soc_remove(struct snd_soc_component *component)
 {
 	struct motmdm_driver_data *ddata;
-	struct gsm_serdev_dlci *dlci;
+	struct gsm_serdev_dlci_operations *dlci;
 
 	ddata = snd_soc_component_get_drvdata(component);
 	dlci = &ddata->dlci;
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 97b4f5480a31..31ff426226ef 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -631,6 +631,8 @@ static int graph_probe(struct platform_device *pdev)
 	struct link_info li;
 	int ret;
 
+	printk("audio-graph: probe starts\n");
+
 	/* Allocate the private data and the DAI link array */
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -648,19 +650,24 @@ static int graph_probe(struct platform_device *pdev)
 	if (!li.link || !li.dais)
 		return -EINVAL;
 
+	printk("audio-graph: 2\n");
+
 	ret = asoc_simple_init_priv(priv, &li);
 	if (ret < 0)
 		return ret;
 
 	priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
 	if (IS_ERR(priv->pa_gpio)) {
+		printk("audio-graph: optional pa failed\n");
 		ret = PTR_ERR(priv->pa_gpio);
 		dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
 		return ret;
 	}
 
+	printk("audio-graph: parsing of\n");	
 	ret = graph_parse_of(priv);
 	if (ret < 0) {
+		printk("audio-graph: parsing of failed: %d\n", ret);	
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "parse error %d\n", ret);
 		goto err;
@@ -670,9 +677,13 @@ static int graph_probe(struct platform_device *pdev)
 
 	asoc_simple_debug_info(priv);
 
+		printk("audio-graph: registering card\n");	
+	
+
 	ret = devm_snd_soc_register_card(dev, card);
 	if (ret < 0)
 		goto err;
+		printk("audio-graph: all ok\n");	
 
 	return 0;
 err:
Pavel Machek March 5, 2021, 10:46 a.m. UTC | #2
Hi!

> > > For motorola modem case, we may have a GNSS device on channel 4.
> > > Let's add that to the binding and example.
> > > 
> > > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > > ---
> > >  .../devicetree/bindings/serdev/serdev-ngsm.yaml          | 9 +++++++++
> > >  1 file changed, 9 insertions(+)

> 
> And since we're describing a mux, I think you need nodes for the virtual
> ports rather than a reg property in what should be a serial client. That
> is something like
> 
> 	serial@nnn {
> 		modem {
> 			compatible = "etsi,ts27001-mux";
> 
> 			serial@4 {
> 				compatible = "etsi,ts27001-serial";
> 				reg = <4>;
> 
> 				gnss {
> 					compatible = "motorola,motmdm-gnss";
> 				};
> 			};
> 		};
> 	};
> 
> This way you can actually use serdev for the client drivers (e.g. for
> gnss), and those drivers also be used for non-muxed ports if needed
> (e.g. over USB).

I have done changes you requested, and then hit "serdev is busy
because it can have at most one child" limit in the code. You have
pretty clean driver in your inbox, and no reply. No help with serdev
core limitations, either. Can you start to communicate?

Best regards,
								Pavel
Johan Hovold March 5, 2021, 10:52 a.m. UTC | #3
On Fri, Mar 05, 2021 at 11:46:35AM +0100, Pavel Machek wrote:
> Hi!

> 

> > > > For motorola modem case, we may have a GNSS device on channel 4.

> > > > Let's add that to the binding and example.

> > > > 

> > > > Signed-off-by: Tony Lindgren <tony@atomide.com>

> > > > ---

> > > >  .../devicetree/bindings/serdev/serdev-ngsm.yaml          | 9 +++++++++

> > > >  1 file changed, 9 insertions(+)

> 

> > 

> > And since we're describing a mux, I think you need nodes for the virtual

> > ports rather than a reg property in what should be a serial client. That

> > is something like

> > 

> > 	serial@nnn {

> > 		modem {

> > 			compatible = "etsi,ts27001-mux";

> > 

> > 			serial@4 {

> > 				compatible = "etsi,ts27001-serial";

> > 				reg = <4>;

> > 

> > 				gnss {

> > 					compatible = "motorola,motmdm-gnss";

> > 				};

> > 			};

> > 		};

> > 	};

> > 

> > This way you can actually use serdev for the client drivers (e.g. for

> > gnss), and those drivers also be used for non-muxed ports if needed

> > (e.g. over USB).

> 

> I have done changes you requested, and then hit "serdev is busy

> because it can have at most one child" limit in the code. You have

> pretty clean driver in your inbox, and no reply. No help with serdev

> core limitations, either. Can you start to communicate?


It's on my list, but time is limited.

Johan
Johan Hovold April 1, 2021, 9:43 a.m. UTC | #4
On Fri, Mar 05, 2021 at 11:46:35AM +0100, Pavel Machek wrote:
> Hi!
> 
> > > > For motorola modem case, we may have a GNSS device on channel 4.
> > > > Let's add that to the binding and example.
> > > > 
> > > > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > > > ---
> > > >  .../devicetree/bindings/serdev/serdev-ngsm.yaml          | 9 +++++++++
> > > >  1 file changed, 9 insertions(+)
> 
> > 
> > And since we're describing a mux, I think you need nodes for the virtual
> > ports rather than a reg property in what should be a serial client. That
> > is something like
> > 
> > 	serial@nnn {
> > 		modem {
> > 			compatible = "etsi,ts27001-mux";
> > 
> > 			serial@4 {
> > 				compatible = "etsi,ts27001-serial";
> > 				reg = <4>;
> > 
> > 				gnss {
> > 					compatible = "motorola,motmdm-gnss";
> > 				};
> > 			};
> > 		};
> > 	};
> > 
> > This way you can actually use serdev for the client drivers (e.g. for
> > gnss), and those drivers also be used for non-muxed ports if needed
> > (e.g. over USB).
> 
> I have done changes you requested, and then hit "serdev is busy
> because it can have at most one child" limit in the code. You have
> pretty clean driver in your inbox, and no reply. No help with serdev
> core limitations, either. Can you start to communicate?

Heh, look at the devicetree example above that I gave you back in March.
It has the virtual serial ports described ("serial@4"), which you were
missing.

Johan