View | Details | Raw Unified | Return to bug 238037 | Differences between
and this patch

Collapse All | Expand All

(-)sys/dev/ichiic/ig4_acpi.c (+2 lines)
Lines 153-158 Link Here
153
	DEVMETHOD(device_probe, ig4iic_acpi_probe),
153
	DEVMETHOD(device_probe, ig4iic_acpi_probe),
154
	DEVMETHOD(device_attach, ig4iic_acpi_attach),
154
	DEVMETHOD(device_attach, ig4iic_acpi_attach),
155
	DEVMETHOD(device_detach, ig4iic_acpi_detach),
155
	DEVMETHOD(device_detach, ig4iic_acpi_detach),
156
	DEVMETHOD(device_suspend, bus_generic_suspend),
157
	DEVMETHOD(device_resume, bus_generic_resume),
156
158
157
	/* iicbus interface */
159
	/* iicbus interface */
158
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
160
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
(-)sys/dev/ichiic/ig4_pci.c (+94 lines)
Lines 206-216 Link Here
206
	return (0);
206
	return (0);
207
}
207
}
208
208
209
/*
210
 * During suspend we save registers and re-initialize them
211
 * during resume. This is a list of the registers to save.
212
 *
213
 * IG4_REGS_CONTEXT_SIZE is the length of this array.
214
 *   It must be updated if this list is.
215
 *
216
 * The regs_context field of struct ig4iic_softc holds the
217
 * values of the saved registers.
218
 */
219
uint32_t regs_context_ids[IG4_REGS_CONTEXT_SIZE] = {
220
	IG4_REG_CTL,
221
	IG4_REG_TAR_ADD,
222
	IG4_REG_DATA_CMD,
223
	IG4_REG_SS_SCL_HCNT,
224
	IG4_REG_SS_SCL_LCNT,
225
	IG4_REG_FS_SCL_HCNT,
226
	IG4_REG_FS_SCL_LCNT,
227
	IG4_REG_INTR_MASK,
228
	IG4_REG_RX_TL,
229
	IG4_REG_TX_TL,
230
	IG4_REG_I2C_EN,
231
	IG4_REG_SDA_HOLD,
232
	IG4_REG_SLV_DATA_NACK,
233
	IG4_REG_DMA_CTRL,
234
	IG4_REG_DMA_TDLR,
235
	IG4_REG_DMA_RDLR,
236
	IG4_REG_SDA_SETUP,
237
	IG4_REG_GENERAL,
238
	IG4_REG_ACK_GENERAL_CALL,
239
	IG4_REG_SW_LTR_VALUE,
240
	IG4_REG_AUTO_LTR_VALUE,
241
};
242
243
static int
244
ig4iic_pci_suspend(device_t dev)
245
{
246
	ig4iic_softc_t *sc;
247
248
	sc = device_get_softc(dev);
249
250
	/* RESETS spec (22.2.36) recommends saving and re-initializing registers */
251
	for (int i = 0; i < IG4_REGS_CONTEXT_SIZE; i++) {
252
		bus_barrier(sc->regs_res, regs_context_ids[i], 4, BUS_SPACE_BARRIER_READ);
253
		sc->regs_context[i] = bus_read_4(sc->regs_res, regs_context_ids[i]);
254
	}
255
256
	/* 
257
	 * reset the controller before we suspend 
258
	 * Haswell and Skylake apparently have different RESET methods
259
	 */
260
	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
261
		bus_write_4(sc->regs_res, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW);
262
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_READ);
263
	} else if (sc->version == IG4_SKYLAKE) {
264
		bus_write_4(sc->regs_res, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL);
265
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_READ);
266
	} else {
267
		device_printf(dev, "Unable to assert reset, reset register unavailable\n");
268
	}
269
270
	/* suspend all children */
271
	return bus_generic_suspend(dev);
272
}
273
274
static int
275
ig4iic_pci_resume(device_t dev)
276
{
277
	ig4iic_softc_t *sc;
278
279
	sc = device_get_softc(dev);
280
281
	/* wake the controller before its children */
282
	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
283
		bus_write_4(sc->regs_res, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW);
284
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_READ);
285
	} else if (sc->version == IG4_SKYLAKE) {
286
		bus_write_4(sc->regs_res, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL);
287
		bus_barrier(sc->regs_res, IG4_REG_RESETS_HSW, 4, BUS_SPACE_BARRIER_READ);
288
	} else {
289
		device_printf(dev, "Unable to deassert reset, reset register unavailable\n");
290
	}
291
	
292
	/* set registers to values previously saved in regs_context */
293
	for (int i = 0; i < IG4_REGS_CONTEXT_SIZE; i++) {
294
		bus_write_4(sc->regs_res, regs_context_ids[i], sc->regs_context[i]);
295
		bus_barrier(sc->regs_res, regs_context_ids[i], 4, BUS_SPACE_BARRIER_WRITE);
296
	}
297
298
	return bus_generic_resume(dev);
299
}
300
209
static device_method_t ig4iic_pci_methods[] = {
301
static device_method_t ig4iic_pci_methods[] = {
210
	/* Device interface */
302
	/* Device interface */
211
	DEVMETHOD(device_probe, ig4iic_pci_probe),
303
	DEVMETHOD(device_probe, ig4iic_pci_probe),
212
	DEVMETHOD(device_attach, ig4iic_pci_attach),
304
	DEVMETHOD(device_attach, ig4iic_pci_attach),
213
	DEVMETHOD(device_detach, ig4iic_pci_detach),
305
	DEVMETHOD(device_detach, ig4iic_pci_detach),
306
	DEVMETHOD(device_suspend, ig4iic_pci_suspend),
307
	DEVMETHOD(device_resume, ig4iic_pci_resume),
214
308
215
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
309
	DEVMETHOD(iicbus_transfer, ig4iic_transfer),
216
	DEVMETHOD(iicbus_reset, ig4iic_reset),
310
	DEVMETHOD(iicbus_reset, ig4iic_reset),
(-)sys/dev/ichiic/ig4_var.h (+4 lines)
Lines 49-54 Link Here
49
enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
49
enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
50
enum ig4_vers { IG4_HASWELL, IG4_ATOM, IG4_SKYLAKE, IG4_APL };
50
enum ig4_vers { IG4_HASWELL, IG4_ATOM, IG4_SKYLAKE, IG4_APL };
51
51
52
/* length of the register context array (regs_context_ids) */
53
#define IG4_REGS_CONTEXT_SIZE 21
54
52
struct ig4iic_softc {
55
struct ig4iic_softc {
53
	device_t	dev;
56
	device_t	dev;
54
	struct		intr_config_hook enum_hook;
57
	struct		intr_config_hook enum_hook;
Lines 55-60 Link Here
55
	device_t	iicbus;
58
	device_t	iicbus;
56
	struct resource	*regs_res;
59
	struct resource	*regs_res;
57
	int		regs_rid;
60
	int		regs_rid;
61
	uint32_t	regs_context[IG4_REGS_CONTEXT_SIZE];
58
	struct resource	*intr_res;
62
	struct resource	*intr_res;
59
	int		intr_rid;
63
	int		intr_rid;
60
	void		*intr_handle;
64
	void		*intr_handle;

Return to bug 238037