malta-pm.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. * Copyright (C) 2014 Imagination Technologies
  3. * Author: Paul Burton <paul.burton@imgtec.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/init.h>
  12. #include <linux/io.h>
  13. #include <linux/pci.h>
  14. #include <asm/mach-malta/malta-pm.h>
  15. static struct pci_bus *pm_pci_bus;
  16. static resource_size_t pm_io_offset;
  17. int mips_pm_suspend(unsigned state)
  18. {
  19. int spec_devid;
  20. u16 sts;
  21. if (!pm_pci_bus || !pm_io_offset)
  22. return -ENODEV;
  23. /* Ensure the power button status is clear */
  24. while (1) {
  25. sts = inw(pm_io_offset + PIIX4_FUNC3IO_PMSTS);
  26. if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS))
  27. break;
  28. outw(sts, pm_io_offset + PIIX4_FUNC3IO_PMSTS);
  29. }
  30. /* Enable entry to suspend */
  31. outw(state | PIIX4_FUNC3IO_PMCNTRL_SUS_EN,
  32. pm_io_offset + PIIX4_FUNC3IO_PMCNTRL);
  33. /* If the special cycle occurs too soon this doesn't work... */
  34. mdelay(10);
  35. /*
  36. * The PIIX4 will enter the suspend state only after seeing a special
  37. * cycle with the correct magic data on the PCI bus. Generate that
  38. * cycle now.
  39. */
  40. spec_devid = PCI_DEVID(0, PCI_DEVFN(0x1f, 0x7));
  41. pci_bus_write_config_dword(pm_pci_bus, spec_devid, 0,
  42. PIIX4_SUSPEND_MAGIC);
  43. /* Give the system some time to power down */
  44. mdelay(1000);
  45. return 0;
  46. }
  47. static int __init malta_pm_setup(void)
  48. {
  49. struct pci_dev *dev;
  50. int res, io_region = PCI_BRIDGE_RESOURCES;
  51. /* Find a reference to the PCI bus */
  52. pm_pci_bus = pci_find_next_bus(NULL);
  53. if (!pm_pci_bus) {
  54. pr_warn("malta-pm: failed to find reference to PCI bus\n");
  55. return -ENODEV;
  56. }
  57. /* Find the PIIX4 PM device */
  58. dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
  59. PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
  60. PCI_ANY_ID, NULL);
  61. if (!dev) {
  62. pr_warn("malta-pm: failed to find PIIX4 PM\n");
  63. return -ENODEV;
  64. }
  65. /* Request access to the PIIX4 PM IO registers */
  66. res = pci_request_region(dev, io_region, "PIIX4 PM IO registers");
  67. if (res) {
  68. pr_warn("malta-pm: failed to request PM IO registers (%d)\n",
  69. res);
  70. pci_dev_put(dev);
  71. return -ENODEV;
  72. }
  73. /* Find the offset to the PIIX4 PM IO registers */
  74. pm_io_offset = pci_resource_start(dev, io_region);
  75. pci_dev_put(dev);
  76. return 0;
  77. }
  78. late_initcall(malta_pm_setup);