pm-rcar.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * R-Car SYSC Power management support
  3. *
  4. * Copyright (C) 2014 Magnus Damm
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/err.h>
  12. #include <linux/mm.h>
  13. #include <linux/spinlock.h>
  14. #include <asm/io.h>
  15. #include <mach/pm-rcar.h>
  16. /* SYSC */
  17. #define SYSCSR 0x00
  18. #define SYSCISR 0x04
  19. #define SYSCISCR 0x08
  20. #define PWRSR_OFFS 0x00
  21. #define PWROFFCR_OFFS 0x04
  22. #define PWRONCR_OFFS 0x0c
  23. #define PWRER_OFFS 0x14
  24. #define SYSCSR_RETRIES 100
  25. #define SYSCSR_DELAY_US 1
  26. #define SYSCISR_RETRIES 1000
  27. #define SYSCISR_DELAY_US 1
  28. #if defined(CONFIG_PM) || defined(CONFIG_SMP)
  29. static void __iomem *rcar_sysc_base;
  30. static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
  31. static int rcar_sysc_pwr_on_off(struct rcar_sysc_ch *sysc_ch,
  32. int sr_bit, int reg_offs)
  33. {
  34. int k;
  35. for (k = 0; k < SYSCSR_RETRIES; k++) {
  36. if (ioread32(rcar_sysc_base + SYSCSR) & (1 << sr_bit))
  37. break;
  38. udelay(SYSCSR_DELAY_US);
  39. }
  40. if (k == SYSCSR_RETRIES)
  41. return -EAGAIN;
  42. iowrite32(1 << sysc_ch->chan_bit,
  43. rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
  44. return 0;
  45. }
  46. static int rcar_sysc_pwr_off(struct rcar_sysc_ch *sysc_ch)
  47. {
  48. return rcar_sysc_pwr_on_off(sysc_ch, 0, PWROFFCR_OFFS);
  49. }
  50. static int rcar_sysc_pwr_on(struct rcar_sysc_ch *sysc_ch)
  51. {
  52. return rcar_sysc_pwr_on_off(sysc_ch, 1, PWRONCR_OFFS);
  53. }
  54. static int rcar_sysc_update(struct rcar_sysc_ch *sysc_ch,
  55. int (*on_off_fn)(struct rcar_sysc_ch *))
  56. {
  57. unsigned int isr_mask = 1 << sysc_ch->isr_bit;
  58. unsigned int chan_mask = 1 << sysc_ch->chan_bit;
  59. unsigned int status;
  60. unsigned long flags;
  61. int ret = 0;
  62. int k;
  63. spin_lock_irqsave(&rcar_sysc_lock, flags);
  64. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  65. do {
  66. ret = on_off_fn(sysc_ch);
  67. if (ret)
  68. goto out;
  69. status = ioread32(rcar_sysc_base +
  70. sysc_ch->chan_offs + PWRER_OFFS);
  71. } while (status & chan_mask);
  72. for (k = 0; k < SYSCISR_RETRIES; k++) {
  73. if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask)
  74. break;
  75. udelay(SYSCISR_DELAY_US);
  76. }
  77. if (k == SYSCISR_RETRIES)
  78. ret = -EIO;
  79. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  80. out:
  81. spin_unlock_irqrestore(&rcar_sysc_lock, flags);
  82. pr_debug("sysc power domain %d: %08x -> %d\n",
  83. sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
  84. return ret;
  85. }
  86. int rcar_sysc_power_down(struct rcar_sysc_ch *sysc_ch)
  87. {
  88. return rcar_sysc_update(sysc_ch, rcar_sysc_pwr_off);
  89. }
  90. int rcar_sysc_power_up(struct rcar_sysc_ch *sysc_ch)
  91. {
  92. return rcar_sysc_update(sysc_ch, rcar_sysc_pwr_on);
  93. }
  94. bool rcar_sysc_power_is_off(struct rcar_sysc_ch *sysc_ch)
  95. {
  96. unsigned int st;
  97. st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
  98. if (st & (1 << sysc_ch->chan_bit))
  99. return true;
  100. return false;
  101. }
  102. void __iomem *rcar_sysc_init(phys_addr_t base)
  103. {
  104. rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
  105. if (!rcar_sysc_base)
  106. panic("unable to ioremap R-Car SYSC hardware block\n");
  107. return rcar_sysc_base;
  108. }
  109. #endif /* CONFIG_PM || CONFIG_SMP */