Merge branch 'viafb-next' of git://github.com/schandinat/linux-2.6
This commit is contained in:
commit
dc7c0b6a6d
|
@ -15,6 +15,9 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <asm/olpc.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default port config.
|
* The default port config.
|
||||||
|
@ -28,6 +31,19 @@ static struct via_port_cfg adap_configs[] = {
|
||||||
{ 0, 0, 0, 0 }
|
{ 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
|
* We currently only support one viafb device (will there ever be
|
||||||
* more than one?), so just declare it globally here.
|
* 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,
|
static int __devinit via_pci_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *ent)
|
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);
|
ret = pci_enable_device(pdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global device initialization.
|
* Global device initialization.
|
||||||
*/
|
*/
|
||||||
|
@ -591,6 +680,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
|
||||||
global_dev.pdev = pdev;
|
global_dev.pdev = pdev;
|
||||||
global_dev.chip_type = ent->driver_data;
|
global_dev.chip_type = ent->driver_data;
|
||||||
global_dev.port_cfg = adap_configs;
|
global_dev.port_cfg = adap_configs;
|
||||||
|
if (machine_is_olpc())
|
||||||
|
global_dev.port_cfg = olpc_adap_configs;
|
||||||
|
|
||||||
spin_lock_init(&global_dev.reg_lock);
|
spin_lock_init(&global_dev.reg_lock);
|
||||||
ret = via_pci_setup_mmio(&global_dev);
|
ret = via_pci_setup_mmio(&global_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -663,8 +755,8 @@ static struct pci_driver via_driver = {
|
||||||
.probe = via_pci_probe,
|
.probe = via_pci_probe,
|
||||||
.remove = __devexit_p(via_pci_remove),
|
.remove = __devexit_p(via_pci_remove),
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = viafb_suspend,
|
.suspend = via_suspend,
|
||||||
.resume = viafb_resume,
|
.resume = via_resume,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,28 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio)
|
||||||
via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
|
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.
|
* 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);
|
printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
|
||||||
gpio_config.gpio_chip.ngpio = 0;
|
gpio_config.gpio_chip.ngpio = 0;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
viafb_pm_register(&viafb_gpio_pm_hooks);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +270,10 @@ static int viafb_gpio_remove(struct platform_device *platdev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
viafb_pm_unregister(&viafb_gpio_pm_hooks);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get unregistered.
|
* Get unregistered.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1672,31 +1672,19 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#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();
|
||||||
acquire_console_sem();
|
fb_set_suspend(viafbinfo, 1);
|
||||||
fb_set_suspend(viafbinfo, 1);
|
viafb_sync(viafbinfo);
|
||||||
|
release_console_sem();
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int viafb_resume(struct pci_dev *pdev)
|
static int viafb_resume(void *unused)
|
||||||
{
|
{
|
||||||
acquire_console_sem();
|
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)
|
if (viaparinfo->shared->vdev->engine_mmio)
|
||||||
viafb_reset_engine(viaparinfo);
|
viafb_reset_engine(viaparinfo);
|
||||||
viafb_set_par(viafbinfo);
|
viafb_set_par(viafbinfo);
|
||||||
|
@ -1704,11 +1692,15 @@ int viafb_resume(struct pci_dev *pdev)
|
||||||
viafb_set_par(viafbinfo1);
|
viafb_set_par(viafbinfo1);
|
||||||
fb_set_suspend(viafbinfo, 0);
|
fb_set_suspend(viafbinfo, 0);
|
||||||
|
|
||||||
fail:
|
|
||||||
release_console_sem();
|
release_console_sem();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct viafb_pm_hooks viafb_fb_pm_hooks = {
|
||||||
|
.suspend = viafb_suspend,
|
||||||
|
.resume = viafb_resume
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -1899,6 +1891,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
|
||||||
|
|
||||||
viafb_init_proc(viaparinfo->shared);
|
viafb_init_proc(viaparinfo->shared);
|
||||||
viafb_init_dac(IGA2);
|
viafb_init_dac(IGA2);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
viafb_pm_register(&viafb_fb_pm_hooks);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_fb_unreg:
|
out_fb_unreg:
|
||||||
|
|
|
@ -108,6 +108,4 @@ void via_fb_pci_remove(struct pci_dev *pdev);
|
||||||
/* Temporary */
|
/* Temporary */
|
||||||
int viafb_init(void);
|
int viafb_init(void);
|
||||||
void viafb_exit(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__ */
|
#endif /* __VIAFBDEV_H__ */
|
||||||
|
|
|
@ -59,6 +59,21 @@ struct via_port_cfg {
|
||||||
u8 ioport_index;
|
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
|
* This is the global viafb "device" containing stuff needed by
|
||||||
* all subdevs.
|
* all subdevs.
|
||||||
|
|
Loading…
Reference in New Issue