summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Kondratyev <wulf@FreeBSD.org>2019-11-03 21:00:55 +0000
committerVladimir Kondratyev <wulf@FreeBSD.org>2019-11-03 21:00:55 +0000
commitdb7caa2ea7a06c9aa0bcdf8d8e5cc3a855ac939b (patch)
treec3545bbc61b06258904dcaddfcf1afd71fac8015
parent83a66b9bdae42b9daf3c6198a5ba3b2583973029 (diff)
Notes
-rw-r--r--sys/dev/ichiic/ig4_acpi.c18
-rw-r--r--sys/dev/ichiic/ig4_iic.c85
-rw-r--r--sys/dev/ichiic/ig4_pci.c18
-rw-r--r--sys/dev/ichiic/ig4_var.h2
-rw-r--r--sys/dev/iicbus/iicbus.c2
5 files changed, 108 insertions, 17 deletions
diff --git a/sys/dev/ichiic/ig4_acpi.c b/sys/dev/ichiic/ig4_acpi.c
index 2e306505c608..4b389c62def9 100644
--- a/sys/dev/ichiic/ig4_acpi.c
+++ b/sys/dev/ichiic/ig4_acpi.c
@@ -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),
diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c
index a3b274fcce08..58bbe2157c1e 100644
--- a/sys/dev/ichiic/ig4_iic.c
+++ b/sys/dev/ichiic/ig4_iic.c
@@ -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");
@@ -967,6 +975,49 @@ ig4iic_detach(ig4iic_softc_t *sc)
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);
+}
+
/*
* Interrupt Operation, see ig4_var.h for locking semantics.
*/
diff --git a/sys/dev/ichiic/ig4_pci.c b/sys/dev/ichiic/ig4_pci.c
index 64e6e994fc78..5e3db6ed4c80 100644
--- a/sys/dev/ichiic/ig4_pci.c
+++ b/sys/dev/ichiic/ig4_pci.c
@@ -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),
diff --git a/sys/dev/ichiic/ig4_var.h b/sys/dev/ichiic/ig4_var.h
index be242445c3d2..2274e4fc9d5e 100644
--- a/sys/dev/ichiic/ig4_var.h
+++ b/sys/dev/ichiic/ig4_var.h
@@ -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;
diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c
index 0795b99dcd69..c4c2ee8d0ada 100644
--- a/sys/dev/iicbus/iicbus.c
+++ b/sys/dev/iicbus/iicbus.c
@@ -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),