drivers/pcmcia/ricoh.h | 33 ++++++++++++++++---------- drivers/pcmcia/ti113x.h | 20 ++++++++++++++++ drivers/pcmcia/yenta_socket.c | 52 ++++++++++++++++++++++++++++++------------ drivers/pcmcia/yenta_socket.h | 5 ++++ 4 files changed, 83 insertions(+), 27 deletions(-) diff -puN drivers/pcmcia/ricoh.h~yenta-20030817-4-pm drivers/pcmcia/ricoh.h --- 25/drivers/pcmcia/ricoh.h~yenta-20030817-4-pm 2003-08-17 14:20:44.000000000 -0700 +++ 25-akpm/drivers/pcmcia/ricoh.h 2003-08-17 14:20:44.000000000 -0700 @@ -156,39 +156,46 @@ static void ricoh_set_zv(struct yenta_so } } -static int ricoh_init(struct yenta_socket *socket) +static void ricoh_save_state(struct yenta_socket *socket) +{ + rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); + rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL); + rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); + rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0); + rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG); +} + +static void ricoh_restore_state(struct yenta_socket *socket) { config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); config_writew(socket, RL5C4XX_CONFIG, rl_config(socket)); - - return 0; } /* - * Magic Ricoh initialization code.. Save state at - * beginning, re-initialize it after suspend. + * Magic Ricoh initialization code.. */ static int ricoh_override(struct yenta_socket *socket) { - rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); - rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL); - rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); - rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0); - rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG); + u16 config, ctl; + + config = config_readw(socket, RL5C4XX_CONFIG); /* Set the default timings, don't trust the original values */ - rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; + ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) { - rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; + ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; } else { - rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH; + config |= RL5C4XX_CONFIG_PREFETCH; } + config_writew(socket, RL5C4XX_16BIT_CTL, ctl); + config_writew(socket, RL5C4XX_CONFIG, config); + ricoh_set_zv(socket); return 0; diff -puN drivers/pcmcia/ti113x.h~yenta-20030817-4-pm drivers/pcmcia/ti113x.h --- 25/drivers/pcmcia/ti113x.h~yenta-20030817-4-pm 2003-08-17 14:20:44.000000000 -0700 +++ 25-akpm/drivers/pcmcia/ti113x.h 2003-08-17 14:20:44.000000000 -0700 @@ -145,6 +145,26 @@ #define ti_diag(socket) ((socket)->private[3]) #define ti_irqmux(socket) ((socket)->private[4]) +/* + * These are the TI specific power management handlers. + */ +static void ti_save_state(struct yenta_socket *socket) +{ + ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL); + ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX); + ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL); + ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL); + ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC); +} + +static void ti_restore_state(struct yenta_socket *socket) +{ + config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); + config_writel(socket, TI122X_IRQMUX, ti_irqmux(socket)); + config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); + config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket)); + config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); +} static int ti_intctl(struct yenta_socket *socket) { diff -puN drivers/pcmcia/yenta_socket.c~yenta-20030817-4-pm drivers/pcmcia/yenta_socket.c --- 25/drivers/pcmcia/yenta_socket.c~yenta-20030817-4-pm 2003-08-17 14:20:44.000000000 -0700 +++ 25-akpm/drivers/pcmcia/yenta_socket.c 2003-08-17 14:20:44.000000000 -0700 @@ -601,18 +601,6 @@ static int yenta_sock_suspend(struct pcm /* Disable CSC interrupts */ cb_writel(socket, CB_SOCKET_MASK, 0x0); - /* - * This does not work currently. The controller - * loses too much information during D3 to come up - * cleanly. We should probably fix yenta_sock_init() - * to update all the critical registers, notably - * the IO and MEM bridging region data.. That is - * something that pci_set_power_state() should - * probably know about bridges anyway. - * - pci_set_power_state(socket->dev, 3); - */ - return 0; } @@ -792,23 +780,32 @@ enum { struct cardbus_type cardbus_type[] = { [CARDBUS_TYPE_TI] = { .override = ti_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, .sock_init = ti_init, }, [CARDBUS_TYPE_TI113X] = { .override = ti113x_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, .sock_init = ti113x_init, }, [CARDBUS_TYPE_TI12XX] = { .override = ti12xx_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, .sock_init = ti113x_init, }, [CARDBUS_TYPE_TI1250] = { .override = ti1250_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, .sock_init = ti1250_init, }, [CARDBUS_TYPE_RICOH] = { .override = ricoh_override, - .sock_init = ricoh_init, + .save_state = ricoh_save_state, + .restore_state = ricoh_restore_state, }, }; @@ -929,12 +926,39 @@ static int __devinit yenta_probe (struct static int yenta_dev_suspend (struct pci_dev *dev, u32 state) { - return pcmcia_socket_dev_suspend(&dev->dev, state, SUSPEND_SAVE_STATE); + struct yenta_socket *socket = pci_get_drvdata(dev); + int ret; + + ret = pcmcia_socket_dev_suspend(&dev->dev, state, SUSPEND_SAVE_STATE); + + if (socket) { + if (socket->type && socket->type->save_state) + socket->type->save_state(socket); + + pci_save_state(dev, socket->saved_state); + pci_read_config_dword(dev, 16*4, &socket->saved_state[16]); + pci_read_config_dword(dev, 17*4, &socket->saved_state[17]); + pci_set_power_state(dev, 3); + } + + return ret; } static int yenta_dev_resume (struct pci_dev *dev) { + struct yenta_socket *socket = pci_get_drvdata(dev); + + if (socket) { + pci_set_power_state(dev, 0); + pci_restore_state(dev, socket->saved_state); + pci_write_config_dword(dev, 16*4, socket->saved_state[16]); + pci_write_config_dword(dev, 17*4, socket->saved_state[17]); + + if (socket->type && socket->type->restore_state) + socket->type->restore_state(socket); + } + return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); } diff -puN drivers/pcmcia/yenta_socket.h~yenta-20030817-4-pm drivers/pcmcia/yenta_socket.h --- 25/drivers/pcmcia/yenta_socket.h~yenta-20030817-4-pm 2003-08-17 14:20:44.000000000 -0700 +++ 25-akpm/drivers/pcmcia/yenta_socket.h 2003-08-17 14:20:44.000000000 -0700 @@ -99,6 +99,8 @@ struct yenta_socket; struct cardbus_type { int (*override)(struct yenta_socket *); + void (*save_state)(struct yenta_socket *); + void (*restore_state)(struct yenta_socket *); int (*sock_init)(struct yenta_socket *); }; @@ -113,6 +115,9 @@ struct yenta_socket { /* A few words of private data for special stuff of overrides... */ unsigned int private[8]; + + /* PCI saved state */ + u32 saved_state[18]; }; _