diff options
author | Vladimir Kondratyev <wulf@FreeBSD.org> | 2019-11-03 21:00:55 +0000 |
---|---|---|
committer | Vladimir Kondratyev <wulf@FreeBSD.org> | 2019-11-03 21:00:55 +0000 |
commit | db7caa2ea7a06c9aa0bcdf8d8e5cc3a855ac939b (patch) | |
tree | c3545bbc61b06258904dcaddfcf1afd71fac8015 | |
parent | 83a66b9bdae42b9daf3c6198a5ba3b2583973029 (diff) |
Notes
-rw-r--r-- | sys/dev/ichiic/ig4_acpi.c | 18 | ||||
-rw-r--r-- | sys/dev/ichiic/ig4_iic.c | 85 | ||||
-rw-r--r-- | sys/dev/ichiic/ig4_pci.c | 18 | ||||
-rw-r--r-- | sys/dev/ichiic/ig4_var.h | 2 | ||||
-rw-r--r-- | sys/dev/iicbus/iicbus.c | 2 |
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), |