Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+97 −34
Original line number Diff line number Diff line
@@ -55,14 +55,12 @@
#include <linux/rtnetlink.h>
#include <linux/dma-mapping.h>
#include <linux/pnp.h>
#include <linux/platform_device.h>

#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>

#include <linux/pm.h>
#include <linux/pm_legacy.h>

#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
@@ -74,6 +72,19 @@

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 */
static int qos_mtt_bits = 0x07;  /* 1 ms or more */
static int dongle_id;
@@ -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_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 int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);

/* Globals */
static int pnp_registered;
@@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void)
	int reg;
	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 */
	ret = pnp_register_driver(&nsc_ircc_pnp_driver);

@@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void)
	}

	if (ret) {
		platform_driver_unregister(&nsc_ircc_driver);
		pnp_unregister_driver(&nsc_ircc_pnp_driver);
		pnp_registered = 0;
	}
@@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void)
{
	int i;

	pm_unregister_all(nsc_ircc_pmproc);

	for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
		if (dev_self[i])
			nsc_ircc_close(dev_self[i]);
	}

	platform_driver_unregister(&nsc_ircc_driver);

	if (pnp_registered)
 		pnp_unregister_driver(&nsc_ircc_pnp_driver);

@@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info)
{
	struct net_device *dev;
	struct nsc_ircc_cb *self;
	struct pm_dev *pmdev;
	void *ret;
	int err, chip_index;

@@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info)
	self->io.dongle_id = 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);
        if (pmdev)
                pmdev->data = self;
 	self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
 						      self->index, NULL, 0);
 	if (IS_ERR(self->pldev)) {
 		err = PTR_ERR(self->pldev);
 		goto out5;
 	}
 	platform_set_drvdata(self->pldev, self);

	return chip_index;

 out5:
 	unregister_netdev(dev);
 out4:
	dma_free_coherent(NULL, self->tx_buff.truesize,
			  self->tx_buff.head, self->tx_buff_dma);
@@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)

        iobase = self->io.fir_base;

	platform_device_unregister(self->pldev);

	/* Remove netdevice */
	unregister_netdev(self->netdev);

@@ -2278,44 +2303,82 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
	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)
		return;
		return 0;

	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);

	nsc_ircc_net_close(self->netdev);
		/* 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;
	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)
		return;
		return 0;

	IRDA_DEBUG(1, "%s, Waking up\n", driver_name);

	rtnl_lock();
	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);

	self->io.suspended = 0;
			/*
			 * 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);
		}

static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
{
        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;
                }
	} else {
		spin_lock_irqsave(&self->lock, flags);
		nsc_ircc_change_speed(self, 9600);
		spin_unlock_irqrestore(&self->lock, flags);
	}
	self->io.suspended = 0;
	rtnl_unlock();

 	return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -269,7 +269,7 @@ struct nsc_ircc_cb {
	__u32 new_speed;
	int index;                 /* Instance index */

        struct pm_dev *dev;
	struct platform_device *pldev;
};

static inline void switch_bank(int iobase, int bank)