Module Name:    src
Committed By:   jmcneill
Date:           Mon Jan 25 12:18:18 UTC 2021

Modified Files:
        src/sys/dev/fdt: i2cmux_fdt.c
        src/sys/dev/i2c: i2c.c i2cmux.c i2cmuxvar.h pcai2cmux.c

Log Message:
Add support for ACPI-based I2C mux attachment.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/fdt/i2cmux_fdt.c
cvs rdiff -u -r1.76 -r1.77 src/sys/dev/i2c/i2c.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/i2c/i2cmux.c src/sys/dev/i2c/i2cmuxvar.h
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/i2c/pcai2cmux.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/fdt/i2cmux_fdt.c
diff -u src/sys/dev/fdt/i2cmux_fdt.c:1.6 src/sys/dev/fdt/i2cmux_fdt.c:1.7
--- src/sys/dev/fdt/i2cmux_fdt.c:1.6	Mon Jan 18 02:35:49 2021
+++ src/sys/dev/fdt/i2cmux_fdt.c	Mon Jan 25 12:18:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2cmux_fdt.c,v 1.6 2021/01/18 02:35:49 thorpej Exp $	*/
+/*	$NetBSD: i2cmux_fdt.c,v 1.7 2021/01/25 12:18:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2cmux_fdt.c,v 1.6 2021/01/18 02:35:49 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2cmux_fdt.c,v 1.7 2021/01/25 12:18:18 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/device.h>
@@ -63,7 +63,7 @@ iicmux_gpio_get_mux_info(struct iicmux_s
 
 	mux_data = kmem_zalloc(sizeof(*mux_data), KM_SLEEP);
 
-	mux_data->npins = fdtbus_gpio_count(sc->sc_phandle, "mux-gpios");
+	mux_data->npins = fdtbus_gpio_count(sc->sc_handle, "mux-gpios");
 	if (mux_data->npins == 0) {
 		aprint_error_dev(sc->sc_dev,
 		    "unable to get mux-gpios property\n");
@@ -73,7 +73,7 @@ iicmux_gpio_get_mux_info(struct iicmux_s
 	mux_data->pins =
 	    kmem_zalloc(sizeof(*mux_data->pins) * mux_data->npins, KM_SLEEP);
 	for (i = 0; i < mux_data->npins; i++) {
-		mux_data->pins[i] = fdtbus_gpio_acquire_index(sc->sc_phandle,
+		mux_data->pins[i] = fdtbus_gpio_acquire_index(sc->sc_handle,
 		    "mux-gpios", i, GPIO_PIN_OUTPUT);
 		if (mux_data->pins[i] == NULL) {
 			aprint_error_dev(sc->sc_dev,
@@ -83,7 +83,7 @@ iicmux_gpio_get_mux_info(struct iicmux_s
 	}
 
 	mux_data->has_idle_value =
-	    of_getprop_uint32(sc->sc_phandle, "idle-state",
+	    of_getprop_uint32(sc->sc_handle, "idle-state",
 			      &mux_data->idle_value) == 0;
 
 	return mux_data;
@@ -107,7 +107,7 @@ iicmux_gpio_get_bus_info(struct iicmux_b
 
 	bus_info = kmem_zalloc(sizeof(*bus_info), KM_SLEEP);
 
-	error = fdtbus_get_reg(bus->phandle, 0, &bus_info->value, NULL);
+	error = fdtbus_get_reg(bus->handle, 0, &bus_info->value, NULL);
 	if (error) {
 		aprint_error_dev(sc->sc_dev,
 		    "unable to get reg property for bus %d\n", bus->busidx);
@@ -177,7 +177,7 @@ iicmux_pinctrl_get_mux_info(struct iicmu
 	mux_info = kmem_alloc(sizeof(*mux_info), KM_SLEEP);
 
 	mux_info->has_idle_idx =
-	    fdtbus_get_index(sc->sc_phandle, "pinctrl-names", "idle",
+	    fdtbus_get_index(sc->sc_handle, "pinctrl-names", "idle",
 			     &mux_info->idle_idx) == 0;
 
 	return mux_info;
@@ -192,7 +192,7 @@ iicmux_pinctrl_get_bus_info(struct iicmu
 
 	bus_info = kmem_alloc(sizeof(*bus_info), KM_SLEEP);
 
-	error = fdtbus_get_reg(bus->phandle, 0, &bus_info->idx, NULL);
+	error = fdtbus_get_reg(bus->handle, 0, &bus_info->idx, NULL);
 	if (error) {
 		aprint_error_dev(sc->sc_dev,
 		    "unable to get reg property for bus %d\n", bus->busidx);
@@ -210,7 +210,7 @@ iicmux_pinctrl_acquire_bus(struct iicmux
 	struct iicmux_softc * const sc = bus->mux;
 	struct bus_info_pinctrl * const bus_info = bus->bus_data;
 
-	return fdtbus_pinctrl_set_config_index(sc->sc_phandle, bus_info->idx);
+	return fdtbus_pinctrl_set_config_index(sc->sc_handle, bus_info->idx);
 }
 
 static void
@@ -221,7 +221,7 @@ iicmux_pinctrl_release_bus(struct iicmux
 	struct mux_info_pinctrl * const mux_info = sc->sc_mux_data;
 
 	if (mux_info->has_idle_idx) {
-		(void) fdtbus_pinctrl_set_config_index(sc->sc_phandle,
+		(void) fdtbus_pinctrl_set_config_index(sc->sc_handle,
 		    mux_info->idle_idx);
 	}
 }
@@ -261,13 +261,13 @@ iicmux_fdt_attach(device_t const parent,
 	struct fdt_attach_args * const faa = aux;
 
 	sc->sc_dev = self;
-	sc->sc_phandle = faa->faa_phandle;
-	sc->sc_config = of_search_compatible(sc->sc_phandle, compat_data)->data;
+	sc->sc_handle = faa->faa_phandle;
+	sc->sc_config = of_search_compatible(sc->sc_handle, compat_data)->data;
 
 	aprint_naive("\n");
 	aprint_normal(": %s I2C mux\n", sc->sc_config->desc);
 
-	sc->sc_i2c_parent = fdtbus_i2c_acquire(sc->sc_phandle, "i2c-parent");
+	sc->sc_i2c_parent = fdtbus_i2c_acquire(sc->sc_handle, "i2c-parent");
 	if (sc->sc_i2c_parent == NULL) {
 		aprint_error_dev(sc->sc_dev, "unable to acquire i2c-parent\n");
 		return;

Index: src/sys/dev/i2c/i2c.c
diff -u src/sys/dev/i2c/i2c.c:1.76 src/sys/dev/i2c/i2c.c:1.77
--- src/sys/dev/i2c/i2c.c:1.76	Mon Jan 18 15:28:21 2021
+++ src/sys/dev/i2c/i2c.c	Mon Jan 25 12:18:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2c.c,v 1.76 2021/01/18 15:28:21 thorpej Exp $	*/
+/*	$NetBSD: i2c.c,v 1.77 2021/01/25 12:18:18 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.76 2021/01/18 15:28:21 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.77 2021/01/25 12:18:18 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -439,6 +439,7 @@ iic_attach(device_t parent, device_t sel
 		prop_data_t cdata;
 		uint32_t addr;
 		uint64_t cookie;
+		uint32_t cookietype;
 		const char *name;
 		struct i2c_attach_args ia;
 		int loc[IICCF_NLOCS];
@@ -457,6 +458,9 @@ iic_attach(device_t parent, device_t sel
 				continue;
 			if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
 				cookie = 0;
+			if (!prop_dictionary_get_uint32(dev, "cookietype",
+			    &cookietype))
+				cookietype = I2C_COOKIE_NONE;
 			loc[IICCF_ADDR] = addr;
 
 			memset(&ia, 0, sizeof ia);
@@ -464,6 +468,7 @@ iic_attach(device_t parent, device_t sel
 			ia.ia_tag = ic;
 			ia.ia_name = name;
 			ia.ia_cookie = cookie;
+			ia.ia_cookietype = cookietype;
 			ia.ia_prop = dev;
 
 			buf = NULL;

Index: src/sys/dev/i2c/i2cmux.c
diff -u src/sys/dev/i2c/i2cmux.c:1.2 src/sys/dev/i2c/i2cmux.c:1.3
--- src/sys/dev/i2c/i2cmux.c:1.2	Sun Jan 24 19:35:21 2021
+++ src/sys/dev/i2c/i2cmux.c	Mon Jan 25 12:18:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $	*/
+/*	$NetBSD: i2cmux.c,v 1.3 2021/01/25 12:18:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,8 +29,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
+#include "acpica.h"
+#endif
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.3 2021/01/25 12:18:18 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/device.h>
@@ -41,6 +45,11 @@ __KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/i2cmuxvar.h>
 
+#if NACPICA > 0
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpi_i2c.h>
+#endif
+
 /*
  * i2c mux
  *
@@ -154,13 +163,14 @@ iicmux_print(void * const aux, const cha
 
 static void
 iicmux_attach_bus(struct iicmux_softc * const sc,
-    int const phandle, int const busidx)
+    uintptr_t const handle, enum i2c_cookie_type handletype, int const busidx)
 {
 	struct iicmux_bus * const bus = &sc->sc_busses[busidx];
 
 	bus->mux = sc;
 	bus->busidx = busidx;
-	bus->phandle = phandle;
+	bus->handle = handle;
+	bus->handletype = handletype;
 
 	bus->bus_data = sc->sc_config->get_bus_info(bus);
 	if (bus->bus_data == NULL) {
@@ -175,41 +185,41 @@ iicmux_attach_bus(struct iicmux_softc * 
 	bus->controller.ic_release_bus = iicmux_release_bus;
 	bus->controller.ic_exec = iicmux_exec;
 
-	fdtbus_register_i2c_controller(&bus->controller, bus->phandle);
-
-	fdtbus_attach_i2cbus(sc->sc_dev, bus->phandle, &bus->controller,
-	    iicmux_print);
+	switch (handletype) {
+	case I2C_COOKIE_OF:
+		fdtbus_register_i2c_controller(&bus->controller,
+		    (int)bus->handle);
+
+		fdtbus_attach_i2cbus(sc->sc_dev, (int)bus->handle,
+		    &bus->controller, iicmux_print);
+		break;
+#if NACPICA > 0
+	case I2C_COOKIE_ACPI: {
+		struct acpi_devnode *ad = acpi_match_node((ACPI_HANDLE)handle);
+		KASSERT(ad != NULL);
+		struct i2cbus_attach_args iba = {
+			.iba_tag = &bus->controller,
+			.iba_child_devices = acpi_enter_i2c_devs(ad)
+		};
+		config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
+	}	break;
+#endif
+	default:
+		aprint_error_dev(sc->sc_dev, "unknown handle type\n");
+		break;
+	}
 }
 
-void
-iicmux_attach(struct iicmux_softc * const sc)
+static void
+iicmux_attach_fdt(struct iicmux_softc * const sc)
 {
-
-	/*
-	 * We expect sc->sc_phandle, sc->sc_config, and sc->sc_i2c_parent
-	 * to be initialized by the front-end.
-	 */
-	KASSERT(sc->sc_phandle > 0);
-	KASSERT(sc->sc_config != NULL);
-	KASSERT(sc->sc_i2c_parent != NULL);
-
 	/*
 	 * We start out assuming that the i2c bus nodes are children of
 	 * our own node.  We'll adjust later if we encounter an "i2c-mux"
 	 * node when counting our children.  If we encounter such a node,
 	 * then it's that node that is the parent of the i2c bus children.
 	 */
-	sc->sc_i2c_mux_phandle = sc->sc_phandle;
-
-	/*
-	 * Gather up all of the various bits of information needed
-	 * for this particular type of i2c mux.
-	 */
-	sc->sc_mux_data = sc->sc_config->get_mux_info(sc);
-	if (sc->sc_mux_data == NULL) {
-		aprint_error_dev(sc->sc_dev, "unable to get info for mux\n");
-		return;
-	}
+	sc->sc_i2c_mux_phandle = (int)sc->sc_handle;
 
 	sc->sc_nbusses = iicmux_count_children(sc);
 	if (sc->sc_nbusses == 0) {
@@ -223,6 +233,84 @@ iicmux_attach(struct iicmux_softc * cons
 	for (child = OF_child(sc->sc_i2c_mux_phandle), idx = 0; child;
 	     child = OF_peer(child), idx++) {
 		KASSERT(idx < sc->sc_nbusses);
-		iicmux_attach_bus(sc, child, idx);
+		iicmux_attach_bus(sc, child, I2C_COOKIE_OF, idx);
+	}
+}
+
+#if NACPICA > 0
+static void
+iicmux_attach_acpi(struct iicmux_softc * const sc)
+{
+	ACPI_HANDLE hdl = (ACPI_HANDLE)sc->sc_handle;
+	struct acpi_devnode *devnode, *ad;
+	int idx;
+
+	devnode = acpi_match_node(hdl);
+	KASSERT(devnode != NULL);
+
+	/* Count child busses */
+	sc->sc_nbusses = 0;
+	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
+		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
+		    !acpi_device_present(ad->ad_handle)) {
+			continue;
+		}
+		sc->sc_nbusses++;
+	}
+
+	sc->sc_busses = kmem_zalloc(sizeof(*sc->sc_busses) * sc->sc_nbusses,
+	    KM_SLEEP);
+
+	/* Attach child busses */
+	idx = 0;
+	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
+		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
+		    !acpi_device_present(ad->ad_handle)) {
+			continue;
+		}
+		iicmux_attach_bus(sc, (uintptr_t)ad->ad_handle,
+		    I2C_COOKIE_ACPI, idx);
+		idx++;
+	}
+}
+#endif
+
+void
+iicmux_attach(struct iicmux_softc * const sc)
+{
+	/*
+	 * We expect sc->sc_handle, sc->sc_config, and sc->sc_i2c_parent
+	 * to be initialized by the front-end.
+	 */
+	KASSERT(sc->sc_handle > 0);
+	KASSERT(sc->sc_config != NULL);
+	KASSERT(sc->sc_i2c_parent != NULL);
+
+	/*
+	 * Gather up all of the various bits of information needed
+	 * for this particular type of i2c mux.
+	 */
+	sc->sc_mux_data = sc->sc_config->get_mux_info(sc);
+	if (sc->sc_mux_data == NULL) {
+		aprint_error_dev(sc->sc_dev, "unable to get info for mux\n");
+		return;
+	}
+
+	/*
+	 * Do configuration method (OF, ACPI) specific setup.
+	 */
+	switch (sc->sc_handletype) {
+	case I2C_COOKIE_OF:
+		iicmux_attach_fdt(sc);
+		break;
+#if NACPICA > 0
+	case I2C_COOKIE_ACPI:
+		iicmux_attach_acpi(sc);
+		break;
+#endif
+	default:
+		aprint_error_dev(sc->sc_dev, "could not configure mux: "
+		    "handle type %u not supported\n", sc->sc_handletype);
+		break;
 	}
 }
Index: src/sys/dev/i2c/i2cmuxvar.h
diff -u src/sys/dev/i2c/i2cmuxvar.h:1.2 src/sys/dev/i2c/i2cmuxvar.h:1.3
--- src/sys/dev/i2c/i2cmuxvar.h:1.2	Sun Jan 24 19:35:45 2021
+++ src/sys/dev/i2c/i2cmuxvar.h	Mon Jan 25 12:18:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2cmuxvar.h,v 1.2 2021/01/24 19:35:45 jmcneill Exp $	*/
+/*	$NetBSD: i2cmuxvar.h,v 1.3 2021/01/25 12:18:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -48,14 +48,16 @@ struct iicmux_config {
 struct iicmux_bus {
 	struct i2c_controller controller;
 	struct iicmux_softc *mux;
-	int phandle;
+	uintptr_t handle;
+	enum i2c_cookie_type handletype;
 	int busidx;
 	void *bus_data;
 };
 
 struct iicmux_softc {
 	device_t			sc_dev;
-	int				sc_phandle;
+	enum i2c_cookie_type		sc_handletype;
+	uintptr_t			sc_handle;
 	int				sc_i2c_mux_phandle;
 	const struct iicmux_config *	sc_config;
 	i2c_tag_t			sc_i2c_parent;

Index: src/sys/dev/i2c/pcai2cmux.c
diff -u src/sys/dev/i2c/pcai2cmux.c:1.5 src/sys/dev/i2c/pcai2cmux.c:1.6
--- src/sys/dev/i2c/pcai2cmux.c:1.5	Sun Jan 24 19:38:49 2021
+++ src/sys/dev/i2c/pcai2cmux.c	Mon Jan 25 12:18:18 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: pcai2cmux.c,v 1.5 2021/01/24 19:38:49 jmcneill Exp $	*/
+/*	$NetBSD: pcai2cmux.c,v 1.6 2021/01/25 12:18:18 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,8 +29,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
+#include "acpica.h"
+#endif
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,v 1.5 2021/01/24 19:38:49 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,v 1.6 2021/01/25 12:18:18 jmcneill Exp $");
 
 /*
  * Driver for NXP PCA954x / PCA984x I2C switches and multiplexers.
@@ -59,6 +63,10 @@ __KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,
 #include <dev/fdt/fdtvar.h>
 #include <dev/i2c/i2cmuxvar.h>
 
+#if NACPICA > 0
+#include <dev/acpi/acpivar.h>
+#endif
+
 /* There are a maximum of 8 busses supported. */
 #define	PCAIICMUX_MAX_BUSSES	8
 
@@ -210,10 +218,32 @@ pcaiicmux_get_bus_info(struct iicmux_bus
 	struct pcaiicmux_bus_info * const bus_info =
 	    &sc->sc_bus_info[bus->busidx];
 
-	error = fdtbus_get_reg(bus->phandle, 0, &addr, NULL);
-	if (error) {
-		aprint_error_dev(iicmux->sc_dev,
-		    "unable to get reg property for bus %d\n", bus->busidx);
+	switch (bus->handletype) {
+	case I2C_COOKIE_OF:
+		error = fdtbus_get_reg(bus->handle, 0, &addr, NULL);
+		if (error) {
+			aprint_error_dev(iicmux->sc_dev,
+			    "unable to get reg property for bus %d\n",
+			    bus->busidx);
+			return NULL;
+		}
+		break;
+#if NACPICA > 0
+	case I2C_COOKIE_ACPI: {
+		ACPI_INTEGER val;
+		ACPI_STATUS rv;
+		rv = acpi_eval_integer((ACPI_HANDLE)bus->handle, "_ADR", &val);
+		if (ACPI_FAILURE(rv)) {
+			aprint_error_dev(iicmux->sc_dev,
+			    "unable to evaluate _ADR for bus %d: %s\n",
+			    bus->busidx, AcpiFormatException(rv));
+			return NULL;
+		}
+		addr = (bus_addr_t)val;
+	}	break;
+#endif
+	default:
+		aprint_error_dev(iicmux->sc_dev, "unsupported handle type\n");
 		return NULL;
 	}
 
@@ -302,11 +332,11 @@ pcaiicmux_attach(device_t parent, device
 {
 	struct pcaiicmux_softc * const sc = device_private(self);
 	struct i2c_attach_args * const ia = aux;
-	const int phandle = (int)ia->ia_cookie;
 	int error;
 
 	sc->sc_iicmux.sc_dev = self;
-	sc->sc_iicmux.sc_phandle = phandle;
+	sc->sc_iicmux.sc_handle = ia->ia_cookie;
+	sc->sc_iicmux.sc_handletype = ia->ia_cookietype;
 	sc->sc_iicmux.sc_config = &pcaiicmux_config;
 	sc->sc_iicmux.sc_i2c_parent = ia->ia_tag;
 	sc->sc_addr = ia->ia_addr;
@@ -318,18 +348,21 @@ pcaiicmux_attach(device_t parent, device
 	aprint_normal(": PCA954x I2C %s\n",
 	    sc->sc_type->enable_bit ? "mux" : "switch");
 
-	if (of_hasprop(phandle, "i2c-mux-idle-disconnect")) {
-		sc->sc_idle_disconnect = true;
-	}
-
-	/* Reset the mux if a reset GPIO is specified. */
-	sc->sc_reset_gpio =
-	    fdtbus_gpio_acquire(phandle, "reset-gpios", GPIO_PIN_OUTPUT);
-	if (sc->sc_reset_gpio) {
-		fdtbus_gpio_write(sc->sc_reset_gpio, 1);
-		delay(10);
-		fdtbus_gpio_write(sc->sc_reset_gpio, 0);
-		delay(10);
+	if (ia->ia_cookietype == I2C_COOKIE_OF) {
+		const int phandle = (int)ia->ia_cookie;
+		if (of_hasprop(phandle, "i2c-mux-idle-disconnect")) {
+			sc->sc_idle_disconnect = true;
+		}
+
+		/* Reset the mux if a reset GPIO is specified. */
+		sc->sc_reset_gpio = fdtbus_gpio_acquire(phandle, "reset-gpios",
+		    GPIO_PIN_OUTPUT);
+		if (sc->sc_reset_gpio) {
+			fdtbus_gpio_write(sc->sc_reset_gpio, 1);
+			delay(10);
+			fdtbus_gpio_write(sc->sc_reset_gpio, 0);
+			delay(10);
+		}
 	}
 
 	/* Force the mux into a disconnected state. */

Reply via email to