Date: Sun, 3 Nov 2019 21:00:56 +0000 (UTC) From: Vladimir Kondratyev <wulf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354308 - in head/sys/dev: ichiic iicbus Message-ID: <201911032100.xA3L0uoM066509@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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),
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911032100.xA3L0uoM066509>