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

Commit 8fe2b65a authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

ssb: Turn suspend/resume upside down



Turn the SSB bus suspend mechanism upside down.
Instead of deciding by an internal reference count when to suspend/resume,
let the parent bus call us in their suspend/resume routine.

Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5100d5ac
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
#ifdef CONFIG_PM
static int b43_pcmcia_suspend(struct pcmcia_device *dev)
{
	//TODO
	return 0;
	struct ssb_bus *ssb = dev->priv;

	return ssb_bus_suspend(ssb);
}

static int b43_pcmcia_resume(struct pcmcia_device *dev)
{
	//TODO
	return 0;
	struct ssb_bus *ssb = dev->priv;

	return ssb_bus_resume(ssb);
}
#else /* CONFIG_PM */
# define b43_pcmcia_suspend		NULL
+1 −1
Original line number Diff line number Diff line
@@ -251,7 +251,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
	calc_fast_powerup_delay(cc);
}

void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
void ssb_chipco_suspend(struct ssb_chipcommon *cc)
{
	if (!cc->dev)
		return;
+34 −47
Original line number Diff line number Diff line
@@ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev)
		put_device(dev->dev);
}

static int ssb_bus_resume(struct ssb_bus *bus)
{
	int err;

	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
	err = ssb_pcmcia_init(bus);
	if (err) {
		/* No need to disable XTAL, as we don't have one on PCMCIA. */
		return err;
	}
	ssb_chipco_resume(&bus->chipco);

	return 0;
}

static int ssb_device_resume(struct device *dev)
{
	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
	struct ssb_driver *ssb_drv;
	struct ssb_bus *bus;
	int err = 0;

	bus = ssb_dev->bus;
	if (bus->suspend_cnt == bus->nr_devices) {
		err = ssb_bus_resume(bus);
		if (err)
			return err;
	}
	bus->suspend_cnt--;
	if (dev->driver) {
		ssb_drv = drv_to_ssb_drv(dev->driver);
		if (ssb_drv && ssb_drv->resume)
@@ -160,27 +137,10 @@ static int ssb_device_resume(struct device *dev)
	return err;
}

static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)
{
	ssb_chipco_suspend(&bus->chipco, state);
	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);

	/* Reset HW state information in memory, so that HW is
	 * completely reinitialized on resume. */
	bus->mapped_device = NULL;
#ifdef CONFIG_SSB_DRIVER_PCICORE
	bus->pcicore.setup_done = 0;
#endif
#ifdef CONFIG_SSB_DEBUG
	bus->powered_up = 0;
#endif
}

static int ssb_device_suspend(struct device *dev, pm_message_t state)
{
	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
	struct ssb_driver *ssb_drv;
	struct ssb_bus *bus;
	int err = 0;

	if (dev->driver) {
@@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state)
		if (err)
			goto out;
	}

	bus = ssb_dev->bus;
	bus->suspend_cnt++;
	if (bus->suspend_cnt == bus->nr_devices) {
		/* All devices suspended. Shutdown the bus. */
		ssb_bus_suspend(bus, state);
out:
	return err;
}

out:
int ssb_bus_resume(struct ssb_bus *bus)
{
	int err;

	/* Reset HW state information in memory, so that HW is
	 * completely reinitialized. */
	bus->mapped_device = NULL;
#ifdef CONFIG_SSB_DRIVER_PCICORE
	bus->pcicore.setup_done = 0;
#endif

	err = ssb_bus_powerup(bus, 0);
	if (err)
		return err;
	err = ssb_pcmcia_hardware_setup(bus);
	if (err) {
		ssb_bus_may_powerdown(bus);
		return err;
	}
	ssb_chipco_resume(&bus->chipco);
	ssb_bus_may_powerdown(bus);

	return 0;
}
EXPORT_SYMBOL(ssb_bus_resume);

int ssb_bus_suspend(struct ssb_bus *bus)
{
	ssb_chipco_suspend(&bus->chipco);
	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);

	return 0;
}
EXPORT_SYMBOL(ssb_bus_suspend);

#ifdef CONFIG_SSB_PCIHOST
int ssb_devices_freeze(struct ssb_bus *bus)
+10 −0
Original line number Diff line number Diff line
@@ -18,6 +18,12 @@
#ifdef CONFIG_PM
static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
{
	struct ssb_bus *ssb = pci_get_drvdata(dev);
	int err;

	err = ssb_bus_suspend(ssb);
	if (err)
		return err;
	pci_save_state(dev);
	pci_disable_device(dev);
	pci_set_power_state(dev, pci_choose_state(dev, state));
@@ -27,6 +33,7 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)

static int ssb_pcihost_resume(struct pci_dev *dev)
{
	struct ssb_bus *ssb = pci_get_drvdata(dev);
	int err;

	pci_set_power_state(dev, 0);
@@ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
	if (err)
		return err;
	pci_restore_state(dev);
	err = ssb_bus_resume(ssb);
	if (err)
		return err;

	return 0;
}
+24 −10
Original line number Diff line number Diff line
@@ -684,6 +684,29 @@ static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)
	return 0;
}

/* Initialize the PCMCIA hardware. This is called on Init and Resume. */
int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
{
	int err;

	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
		return 0;

	/* Switch segment to a known state and sync
	 * bus->mapped_pcmcia_seg with hardware state. */
	ssb_pcmcia_switch_segment(bus, 0);
	/* Init the COR register. */
	err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
	if (err)
		return err;
	/* Some cards also need this register to get poked. */
	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
	if (err)
		return err;

	return 0;
}

void ssb_pcmcia_exit(struct ssb_bus *bus)
{
	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
@@ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus)
	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
		return 0;

	/* Switch segment to a known state and sync
	 * bus->mapped_pcmcia_seg with hardware state. */
	ssb_pcmcia_switch_segment(bus, 0);

	/* Init the COR register. */
	err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
	if (err)
		goto error;
	/* Some cards also need this register to get poked. */
	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
	err = ssb_pcmcia_hardware_setup(bus);
	if (err)
		goto error;

Loading