Commit dc7c0b6a authored by Paul Mundt's avatar Paul Mundt
Browse files

Merge branch 'viafb-next' of git://github.com/schandinat/linux-2.6

parents d6ff7d0f b884a94e
Loading
Loading
Loading
Loading
+94 −2
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <asm/olpc.h>

/*
 * The default port config.
@@ -28,6 +31,19 @@ static struct via_port_cfg adap_configs[] = {
	{ 0, 0, 0, 0 }
};

/*
 * The OLPC XO-1.5 puts the camera power and reset lines onto
 * GPIO 2C.
 */
static const struct via_port_cfg olpc_adap_configs[] = {
	[VIA_PORT_26]	= { VIA_PORT_I2C,  VIA_MODE_I2C, VIASR, 0x26 },
	[VIA_PORT_31]	= { VIA_PORT_I2C,  VIA_MODE_I2C, VIASR, 0x31 },
	[VIA_PORT_25]	= { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
	[VIA_PORT_2C]	= { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x2c },
	[VIA_PORT_3D]	= { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
	{ 0, 0, 0, 0 }
};

/*
 * We currently only support one viafb device (will there ever be
 * more than one?), so just declare it globally here.
@@ -575,6 +591,78 @@ static void via_teardown_subdevs(void)
		}
}

/*
 * Power management functions
 */
#ifdef CONFIG_PM
static LIST_HEAD(viafb_pm_hooks);
static DEFINE_MUTEX(viafb_pm_hooks_lock);

void viafb_pm_register(struct viafb_pm_hooks *hooks)
{
	INIT_LIST_HEAD(&hooks->list);

	mutex_lock(&viafb_pm_hooks_lock);
	list_add_tail(&hooks->list, &viafb_pm_hooks);
	mutex_unlock(&viafb_pm_hooks_lock);
}
EXPORT_SYMBOL_GPL(viafb_pm_register);

void viafb_pm_unregister(struct viafb_pm_hooks *hooks)
{
	mutex_lock(&viafb_pm_hooks_lock);
	list_del(&hooks->list);
	mutex_unlock(&viafb_pm_hooks_lock);
}
EXPORT_SYMBOL_GPL(viafb_pm_unregister);

static int via_suspend(struct pci_dev *pdev, pm_message_t state)
{
	struct viafb_pm_hooks *hooks;

	if (state.event != PM_EVENT_SUSPEND)
		return 0;
	/*
	 * "I've occasionally hit a few drivers that caused suspend
	 * failures, and each and every time it was a driver bug, and
	 * the right thing to do was to just ignore the error and suspend
	 * anyway - returning an error code and trying to undo the suspend
	 * is not what anybody ever really wants, even if our model
	 *_allows_ for it."
	 * -- Linus Torvalds, Dec. 7, 2009
	 */
	mutex_lock(&viafb_pm_hooks_lock);
	list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list)
		hooks->suspend(hooks->private);
	mutex_unlock(&viafb_pm_hooks_lock);

	pci_save_state(pdev);
	pci_disable_device(pdev);
	pci_set_power_state(pdev, pci_choose_state(pdev, state));
	return 0;
}

static int via_resume(struct pci_dev *pdev)
{
	struct viafb_pm_hooks *hooks;

	/* Get the bus side powered up */
	pci_set_power_state(pdev, PCI_D0);
	pci_restore_state(pdev);
	if (pci_enable_device(pdev))
		return 0;

	pci_set_master(pdev);

	/* Now bring back any subdevs */
	mutex_lock(&viafb_pm_hooks_lock);
	list_for_each_entry(hooks, &viafb_pm_hooks, list)
		hooks->resume(hooks->private);
	mutex_unlock(&viafb_pm_hooks_lock);

	return 0;
}
#endif /* CONFIG_PM */

static int __devinit via_pci_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent)
@@ -584,6 +672,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
	ret = pci_enable_device(pdev);
	if (ret)
		return ret;

	/*
	 * Global device initialization.
	 */
@@ -591,6 +680,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
	global_dev.pdev = pdev;
	global_dev.chip_type = ent->driver_data;
	global_dev.port_cfg = adap_configs;
	if (machine_is_olpc())
		global_dev.port_cfg = olpc_adap_configs;

	spin_lock_init(&global_dev.reg_lock);
	ret = via_pci_setup_mmio(&global_dev);
	if (ret)
@@ -663,8 +755,8 @@ static struct pci_driver via_driver = {
	.probe		= via_pci_probe,
	.remove		= __devexit_p(via_pci_remove),
#ifdef CONFIG_PM
	.suspend	= viafb_suspend,
	.resume		= viafb_resume,
	.suspend	= via_suspend,
	.resume		= via_resume,
#endif
};

+29 −0
Original line number Diff line number Diff line
@@ -172,6 +172,28 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio)
	via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
}

#ifdef CONFIG_PM

static int viafb_gpio_suspend(void *private)
{
	return 0;
}

static int viafb_gpio_resume(void *private)
{
	int i;

	for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
		viafb_gpio_enable(gpio_config.active_gpios[i]);
	return 0;
}

static struct viafb_pm_hooks viafb_gpio_pm_hooks = {
	.suspend = viafb_gpio_suspend,
	.resume = viafb_gpio_resume
};
#endif /* CONFIG_PM */

/*
 * Look up a specific gpio and return the number it was assigned.
 */
@@ -236,6 +258,9 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev)
		printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
		gpio_config.gpio_chip.ngpio = 0;
	}
#ifdef CONFIG_PM
	viafb_pm_register(&viafb_gpio_pm_hooks);
#endif
	return ret;
}

@@ -245,6 +270,10 @@ static int viafb_gpio_remove(struct platform_device *platdev)
	unsigned long flags;
	int ret = 0, i;

#ifdef CONFIG_PM
	viafb_pm_unregister(&viafb_gpio_pm_hooks);
#endif

	/*
	 * Get unregistered.
	 */
+15 −19
Original line number Diff line number Diff line
@@ -1672,31 +1672,19 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)


#ifdef CONFIG_PM
int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
static int viafb_suspend(void *unused)
{
	if (state.event == PM_EVENT_SUSPEND) {
	acquire_console_sem();
	fb_set_suspend(viafbinfo, 1);

	viafb_sync(viafbinfo);

		pci_save_state(pdev);
		pci_disable_device(pdev);
		pci_set_power_state(pdev, pci_choose_state(pdev, state));
	release_console_sem();
	}

	return 0;
}

int viafb_resume(struct pci_dev *pdev)
static int viafb_resume(void *unused)
{
	acquire_console_sem();
	pci_set_power_state(pdev, PCI_D0);
	pci_restore_state(pdev);
	if (pci_enable_device(pdev))
		goto fail;
	pci_set_master(pdev);
	if (viaparinfo->shared->vdev->engine_mmio)
		viafb_reset_engine(viaparinfo);
	viafb_set_par(viafbinfo);
@@ -1704,11 +1692,15 @@ int viafb_resume(struct pci_dev *pdev)
		viafb_set_par(viafbinfo1);
	fb_set_suspend(viafbinfo, 0);

fail:
	release_console_sem();
	return 0;
}

static struct viafb_pm_hooks viafb_fb_pm_hooks = {
	.suspend = viafb_suspend,
	.resume = viafb_resume
};

#endif


@@ -1899,6 +1891,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)

	viafb_init_proc(viaparinfo->shared);
	viafb_init_dac(IGA2);

#ifdef CONFIG_PM
	viafb_pm_register(&viafb_fb_pm_hooks);
#endif
	return 0;

out_fb_unreg:
+0 −2
Original line number Diff line number Diff line
@@ -108,6 +108,4 @@ void via_fb_pci_remove(struct pci_dev *pdev);
/* Temporary */
int viafb_init(void);
void viafb_exit(void);
int viafb_suspend(struct pci_dev *pdev, pm_message_t state);
int viafb_resume(struct pci_dev *pdev);
#endif /* __VIAFBDEV_H__ */
+15 −0
Original line number Diff line number Diff line
@@ -59,6 +59,21 @@ struct via_port_cfg {
	u8			ioport_index;
};

/*
 * Allow subdevs to register suspend/resume hooks.
 */
#ifdef CONFIG_PM
struct viafb_pm_hooks {
	struct list_head list;
	int (*suspend)(void *private);
	int (*resume)(void *private);
	void *private;
};

void viafb_pm_register(struct viafb_pm_hooks *hooks);
void viafb_pm_unregister(struct viafb_pm_hooks *hooks);
#endif /* CONFIG_PM */

/*
 * This is the global viafb "device" containing stuff needed by
 * all subdevs.