Commit 3b99b93b authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by David S. Miller

[IRDA]: nsc-ircc: PM update

This patch brings the nsc-ircc code to a more up to date power
management scheme, following the current device model.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarRudolf Marek <r.marek@sh.cvut.cz>
Signed-off-by: default avatarSamuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ec4f32d5
...@@ -55,14 +55,12 @@ ...@@ -55,14 +55,12 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/pnp.h> #include <linux/pnp.h>
#include <linux/platform_device.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/pm.h>
#include <linux/pm_legacy.h>
#include <net/irda/wrapper.h> #include <net/irda/wrapper.h>
#include <net/irda/irda.h> #include <net/irda/irda.h>
#include <net/irda/irda_device.h> #include <net/irda/irda_device.h>
...@@ -74,6 +72,19 @@ ...@@ -74,6 +72,19 @@
static char *driver_name = "nsc-ircc"; static char *driver_name = "nsc-ircc";
/* Power Management */
#define NSC_IRCC_DRIVER_NAME "nsc-ircc"
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
static int nsc_ircc_resume(struct platform_device *dev);
static struct platform_driver nsc_ircc_driver = {
.suspend = nsc_ircc_suspend,
.resume = nsc_ircc_resume,
.driver = {
.name = NSC_IRCC_DRIVER_NAME,
},
};
/* Module parameters */ /* Module parameters */
static int qos_mtt_bits = 0x07; /* 1 ms or more */ static int qos_mtt_bits = 0x07; /* 1 ms or more */
static int dongle_id; static int dongle_id;
...@@ -164,7 +175,6 @@ static int nsc_ircc_net_open(struct net_device *dev); ...@@ -164,7 +175,6 @@ static int nsc_ircc_net_open(struct net_device *dev);
static int nsc_ircc_net_close(struct net_device *dev); static int nsc_ircc_net_close(struct net_device *dev);
static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
/* Globals */ /* Globals */
static int pnp_registered; static int pnp_registered;
...@@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void) ...@@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void)
int reg; int reg;
int i = 0; int i = 0;
ret = platform_driver_register(&nsc_ircc_driver);
if (ret) {
IRDA_ERROR("%s, Can't register driver!\n", driver_name);
return ret;
}
/* Register with PnP subsystem to detect disable ports */ /* Register with PnP subsystem to detect disable ports */
ret = pnp_register_driver(&nsc_ircc_pnp_driver); ret = pnp_register_driver(&nsc_ircc_pnp_driver);
...@@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void) ...@@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void)
} }
if (ret) { if (ret) {
platform_driver_unregister(&nsc_ircc_driver);
pnp_unregister_driver(&nsc_ircc_pnp_driver); pnp_unregister_driver(&nsc_ircc_pnp_driver);
pnp_registered = 0; pnp_registered = 0;
} }
...@@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void) ...@@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void)
{ {
int i; int i;
pm_unregister_all(nsc_ircc_pmproc);
for (i = 0; i < ARRAY_SIZE(dev_self); i++) { for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i]) if (dev_self[i])
nsc_ircc_close(dev_self[i]); nsc_ircc_close(dev_self[i]);
} }
platform_driver_unregister(&nsc_ircc_driver);
if (pnp_registered) if (pnp_registered)
pnp_unregister_driver(&nsc_ircc_pnp_driver); pnp_unregister_driver(&nsc_ircc_pnp_driver);
...@@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info) ...@@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info)
{ {
struct net_device *dev; struct net_device *dev;
struct nsc_ircc_cb *self; struct nsc_ircc_cb *self;
struct pm_dev *pmdev;
void *ret; void *ret;
int err, chip_index; int err, chip_index;
...@@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info) ...@@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info)
self->io.dongle_id = dongle_id; self->io.dongle_id = dongle_id;
nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc); self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
if (pmdev) self->index, NULL, 0);
pmdev->data = self; if (IS_ERR(self->pldev)) {
err = PTR_ERR(self->pldev);
goto out5;
}
platform_set_drvdata(self->pldev, self);
return chip_index; return chip_index;
out5:
unregister_netdev(dev);
out4: out4:
dma_free_coherent(NULL, self->tx_buff.truesize, dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma); self->tx_buff.head, self->tx_buff_dma);
...@@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) ...@@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
iobase = self->io.fir_base; iobase = self->io.fir_base;
platform_device_unregister(self->pldev);
/* Remove netdevice */ /* Remove netdevice */
unregister_netdev(self->netdev); unregister_netdev(self->netdev);
...@@ -2278,45 +2303,83 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) ...@@ -2278,45 +2303,83 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
return &self->stats; return &self->stats;
} }
static void nsc_ircc_suspend(struct nsc_ircc_cb *self) static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
{ {
IRDA_MESSAGE("%s, Suspending\n", driver_name); struct nsc_ircc_cb *self = platform_get_drvdata(dev);
int bank;
unsigned long flags;
int iobase = self->io.fir_base;
if (self->io.suspended) if (self->io.suspended)
return; return 0;
nsc_ircc_net_close(self->netdev); IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
rtnl_lock();
if (netif_running(self->netdev)) {
netif_device_detach(self->netdev);
spin_lock_irqsave(&self->lock, flags);
/* Save current bank */
bank = inb(iobase+BSR);
/* Disable interrupts */
switch_bank(iobase, BANK0);
outb(0, iobase+IER);
/* Restore bank register */
outb(bank, iobase+BSR);
spin_unlock_irqrestore(&self->lock, flags);
free_irq(self->io.irq, self->netdev);
disable_dma(self->io.dma);
}
self->io.suspended = 1; self->io.suspended = 1;
rtnl_unlock();
return 0;
} }
static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) static int nsc_ircc_resume(struct platform_device *dev)
{ {
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
unsigned long flags;
if (!self->io.suspended) if (!self->io.suspended)
return; return 0;
IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
rtnl_lock();
nsc_ircc_setup(&self->io); nsc_ircc_setup(&self->io);
nsc_ircc_net_open(self->netdev); nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
IRDA_MESSAGE("%s, Waking up\n", driver_name);
if (netif_running(self->netdev)) {
if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
self->netdev->name, self->netdev)) {
IRDA_WARNING("%s, unable to allocate irq=%d\n",
driver_name, self->io.irq);
/*
* Don't fail resume process, just kill this
* network interface
*/
unregister_netdevice(self->netdev);
} else {
spin_lock_irqsave(&self->lock, flags);
nsc_ircc_change_speed(self, self->io.speed);
spin_unlock_irqrestore(&self->lock, flags);
netif_device_attach(self->netdev);
}
} else {
spin_lock_irqsave(&self->lock, flags);
nsc_ircc_change_speed(self, 9600);
spin_unlock_irqrestore(&self->lock, flags);
}
self->io.suspended = 0; self->io.suspended = 0;
} rtnl_unlock();
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) return 0;
{
struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data;
if (self) {
switch (rqst) {
case PM_SUSPEND:
nsc_ircc_suspend(self);
break;
case PM_RESUME:
nsc_ircc_wakeup(self);
break;
}
}
return 0;
} }
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
......
...@@ -269,7 +269,7 @@ struct nsc_ircc_cb { ...@@ -269,7 +269,7 @@ struct nsc_ircc_cb {
__u32 new_speed; __u32 new_speed;
int index; /* Instance index */ int index; /* Instance index */
struct pm_dev *dev; struct platform_device *pldev;
}; };
static inline void switch_bank(int iobase, int bank) static inline void switch_bank(int iobase, int bank)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment