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-all
mailing list