svn commit: r354308 - in head/sys/dev: ichiic iicbus

Vladimir Kondratyev wulf at FreeBSD.org
Sun Nov 3 21:00:57 UTC 2019


Author: wulf
Date: Sun Nov  3 21:00:55 2019
New Revision: 354308
URL: https://svnweb.freebsd.org/changeset/base/354308

Log:
  [ig4] Add suspend/resume support
  
  That is done with re-execution of controller initialization procedure
  from resume handler.
  
  PR:		238037

Modified:
  head/sys/dev/ichiic/ig4_acpi.c
  head/sys/dev/ichiic/ig4_iic.c
  head/sys/dev/ichiic/ig4_pci.c
  head/sys/dev/ichiic/ig4_var.h
  head/sys/dev/iicbus/iicbus.c

Modified: head/sys/dev/ichiic/ig4_acpi.c
==============================================================================
--- head/sys/dev/ichiic/ig4_acpi.c	Sun Nov  3 20:59:04 2019	(r354307)
+++ head/sys/dev/ichiic/ig4_acpi.c	Sun Nov  3 21:00:55 2019	(r354308)
@@ -145,11 +145,29 @@ ig4iic_acpi_detach(device_t dev)
 	return (0);
 }
 
+static int
+ig4iic_acpi_suspend(device_t dev)
+{
+	ig4iic_softc_t *sc = device_get_softc(dev);
+
+	return (ig4iic_suspend(sc));
+}
+
+static int
+ig4iic_acpi_resume(device_t dev)
+{
+	ig4iic_softc_t *sc  = device_get_softc(dev);
+
+	return (ig4iic_resume(sc));
+}
+
 static device_method_t ig4iic_acpi_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, ig4iic_acpi_probe),
 	DEVMETHOD(device_attach, ig4iic_acpi_attach),
 	DEVMETHOD(device_detach, ig4iic_acpi_detach),
+	DEVMETHOD(device_suspend, ig4iic_acpi_suspend),
+	DEVMETHOD(device_resume, ig4iic_acpi_resume),
 
 	/* iicbus interface */
 	DEVMETHOD(iicbus_transfer, ig4iic_transfer),

Modified: head/sys/dev/ichiic/ig4_iic.c
==============================================================================
--- head/sys/dev/ichiic/ig4_iic.c	Sun Nov  3 20:59:04 2019	(r354307)
+++ head/sys/dev/ichiic/ig4_iic.c	Sun Nov  3 21:00:55 2019	(r354308)
@@ -799,20 +799,11 @@ ig4iic_get_config(ig4iic_softc_t *sc)
 	}
 }
 
-/*
- * Called from ig4iic_pci_attach/detach()
- */
-int
-ig4iic_attach(ig4iic_softc_t *sc)
+static int
+ig4iic_set_config(ig4iic_softc_t *sc)
 {
-	int error;
 	uint32_t v;
 
-	mtx_init(&sc->io_lock, "IG4 I/O lock", NULL, MTX_DEF);
-	sx_init(&sc->call_lock, "IG4 call lock");
-
-	ig4iic_get_config(sc);
-
 	v = reg_read(sc, IG4_REG_DEVIDLE_CTRL);
 	if (sc->version == IG4_SKYLAKE && (v & IG4_RESTORE_REQUIRED) ) {
 		reg_write(sc, IG4_REG_DEVIDLE_CTRL, IG4_DEVICE_IDLE | IG4_RESTORE_REQUIRED);
@@ -851,16 +842,13 @@ ig4iic_attach(ig4iic_softc_t *sc)
 
 	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
 		v = reg_read(sc, IG4_REG_COMP_VER);
-		if (v < IG4_COMP_MIN_VER) {
-			error = ENXIO;
-			goto done;
-		}
+		if (v < IG4_COMP_MIN_VER)
+			return(ENXIO);
 	}
 
 	if (set_controller(sc, 0)) {
 		device_printf(sc->dev, "controller error during attach-1\n");
-		error = ENXIO;
-		goto done;
+		return (ENXIO);
 	}
 
 	reg_read(sc, IG4_REG_CLR_INTR);
@@ -890,6 +878,26 @@ ig4iic_attach(ig4iic_softc_t *sc)
 		  IG4_CTL_RESTARTEN |
 		  (sc->cfg.bus_speed & IG4_CTL_SPEED_MASK));
 
+	return (0);
+}
+
+/*
+ * Called from ig4iic_pci_attach/detach()
+ */
+int
+ig4iic_attach(ig4iic_softc_t *sc)
+{
+	int error;
+
+	mtx_init(&sc->io_lock, "IG4 I/O lock", NULL, MTX_DEF);
+	sx_init(&sc->call_lock, "IG4 call lock");
+
+	ig4iic_get_config(sc);
+
+	error = ig4iic_set_config(sc);
+	if (error)
+		goto done;
+
 	sc->iicbus = device_add_child(sc->dev, "iicbus", -1);
 	if (sc->iicbus == NULL) {
 		device_printf(sc->dev, "iicbus driver not found\n");
@@ -965,6 +973,49 @@ ig4iic_detach(ig4iic_softc_t *sc)
 	sx_destroy(&sc->call_lock);
 
 	return (0);
+}
+
+int
+ig4iic_suspend(ig4iic_softc_t *sc)
+{
+	int error;
+
+	/* suspend all children */
+	error = bus_generic_suspend(sc->dev);
+
+	sx_xlock(&sc->call_lock);
+	set_controller(sc, 0);
+	if (sc->version == IG4_SKYLAKE) {
+		/*
+		 * Place the device in the idle state, just to be safe
+		 */
+		reg_write(sc, IG4_REG_DEVIDLE_CTRL, IG4_DEVICE_IDLE);
+		/*
+		 * Controller can become dysfunctional if I2C lines are pulled
+		 * down when suspend procedure turns off power to I2C device.
+		 * Place device in the reset state to avoid this.
+		 */
+		reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL);
+	}
+	sx_xunlock(&sc->call_lock);
+
+	return (error);
+}
+
+int ig4iic_resume(ig4iic_softc_t *sc)
+{
+	int error;
+
+	sx_xlock(&sc->call_lock);
+	if (ig4iic_set_config(sc))
+		device_printf(sc->dev, "controller error during resume\n");
+	/* Force setting of the target address on the next transfer */
+	sc->slave_valid = 0;
+	sx_xunlock(&sc->call_lock);
+
+	error = bus_generic_resume(sc->dev);
+
+	return (error);
 }
 
 /*

Modified: head/sys/dev/ichiic/ig4_pci.c
==============================================================================
--- head/sys/dev/ichiic/ig4_pci.c	Sun Nov  3 20:59:04 2019	(r354307)
+++ head/sys/dev/ichiic/ig4_pci.c	Sun Nov  3 21:00:55 2019	(r354308)
@@ -206,11 +206,29 @@ ig4iic_pci_detach(device_t dev)
 	return (0);
 }
 
+static int
+ig4iic_pci_suspend(device_t dev)
+{
+	ig4iic_softc_t *sc = device_get_softc(dev);
+
+	return (ig4iic_suspend(sc));
+}
+
+static int
+ig4iic_pci_resume(device_t dev)
+{
+	ig4iic_softc_t *sc  = device_get_softc(dev);
+
+	return (ig4iic_resume(sc));
+}
+
 static device_method_t ig4iic_pci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, ig4iic_pci_probe),
 	DEVMETHOD(device_attach, ig4iic_pci_attach),
 	DEVMETHOD(device_detach, ig4iic_pci_detach),
+	DEVMETHOD(device_suspend, ig4iic_pci_suspend),
+	DEVMETHOD(device_resume, ig4iic_pci_resume),
 
 	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
 	DEVMETHOD(iicbus_reset, ig4iic_reset),

Modified: head/sys/dev/ichiic/ig4_var.h
==============================================================================
--- head/sys/dev/ichiic/ig4_var.h	Sun Nov  3 20:59:04 2019	(r354307)
+++ head/sys/dev/ichiic/ig4_var.h	Sun Nov  3 21:00:55 2019	(r354308)
@@ -114,6 +114,8 @@ extern devclass_t ig4iic_devclass;
 /* Attach/Detach called from ig4iic_pci_*() */
 int ig4iic_attach(ig4iic_softc_t *sc);
 int ig4iic_detach(ig4iic_softc_t *sc);
+int ig4iic_suspend(ig4iic_softc_t *sc);
+int ig4iic_resume(ig4iic_softc_t *sc);
 
 /* iicbus methods */
 extern iicbus_transfer_t ig4iic_transfer;

Modified: head/sys/dev/iicbus/iicbus.c
==============================================================================
--- head/sys/dev/iicbus/iicbus.c	Sun Nov  3 20:59:04 2019	(r354307)
+++ head/sys/dev/iicbus/iicbus.c	Sun Nov  3 21:00:55 2019	(r354308)
@@ -330,6 +330,8 @@ static device_method_t iicbus_methods[] = {
 	DEVMETHOD(device_probe,		iicbus_probe),
 	DEVMETHOD(device_attach,	iicbus_attach),
 	DEVMETHOD(device_detach,	iicbus_detach),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
 
 	/* bus interface */
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),


More information about the svn-src-head mailing list