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),
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to