pm-rcar.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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 "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. static void __iomem *rcar_sysc_base;
  29. static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */
  30. static int rcar_sysc_pwr_on_off(struct rcar_sysc_ch *sysc_ch,
  31. int sr_bit, int reg_offs)
  32. {
  33. int k;
  34. for (k = 0; k < SYSCSR_RETRIES; k++) {
  35. if (ioread32(rcar_sysc_base + SYSCSR) & (1 << sr_bit))
  36. break;
  37. udelay(SYSCSR_DELAY_US);
  38. }
  39. if (k == SYSCSR_RETRIES)
  40. return -EAGAIN;
  41. iowrite32(1 << sysc_ch->chan_bit,
  42. rcar_sysc_base + sysc_ch->chan_offs + reg_offs);
  43. return 0;
  44. }
  45. static int rcar_sysc_pwr_off(struct rcar_sysc_ch *sysc_ch)
  46. {
  47. return rcar_sysc_pwr_on_off(sysc_ch, 0, PWROFFCR_OFFS);
  48. }
  49. static int rcar_sysc_pwr_on(struct rcar_sysc_ch *sysc_ch)
  50. {
  51. return rcar_sysc_pwr_on_off(sysc_ch, 1, PWRONCR_OFFS);
  52. }
  53. static int rcar_sysc_update(struct rcar_sysc_ch *sysc_ch,
  54. int (*on_off_fn)(struct rcar_sysc_ch *))
  55. {
  56. unsigned int isr_mask = 1 << sysc_ch->isr_bit;
  57. unsigned int chan_mask = 1 << sysc_ch->chan_bit;
  58. unsigned int status;
  59. unsigned long flags;
  60. int ret = 0;
  61. int k;
  62. spin_lock_irqsave(&rcar_sysc_lock, flags);
  63. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  64. do {
  65. ret = on_off_fn(sysc_ch);
  66. if (ret)
  67. goto out;
  68. status = ioread32(rcar_sysc_base +
  69. sysc_ch->chan_offs + PWRER_OFFS);
  70. } while (status & chan_mask);
  71. for (k = 0; k < SYSCISR_RETRIES; k++) {
  72. if (ioread32(rcar_sysc_base + SYSCISR) & isr_mask)
  73. break;
  74. udelay(SYSCISR_DELAY_US);
  75. }
  76. if (k == SYSCISR_RETRIES)
  77. ret = -EIO;
  78. iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
  79. out:
  80. spin_unlock_irqrestore(&rcar_sysc_lock, flags);
  81. pr_debug("sysc power domain %d: %08x -> %d\n",
  82. sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret);
  83. return ret;
  84. }
  85. int rcar_sysc_power_down(struct rcar_sysc_ch *sysc_ch)
  86. {
  87. return rcar_sysc_update(sysc_ch, rcar_sysc_pwr_off);
  88. }
  89. int rcar_sysc_power_up(struct rcar_sysc_ch *sysc_ch)
  90. {
  91. return rcar_sysc_update(sysc_ch, rcar_sysc_pwr_on);
  92. }
  93. bool rcar_sysc_power_is_off(struct rcar_sysc_ch *sysc_ch)
  94. {
  95. unsigned int st;
  96. st = ioread32(rcar_sysc_base + sysc_ch->chan_offs + PWRSR_OFFS);
  97. if (st & (1 << sysc_ch->chan_bit))
  98. return true;
  99. return false;
  100. }
  101. void __iomem *rcar_sysc_init(phys_addr_t base)
  102. {
  103. rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE);
  104. if (!rcar_sysc_base)
  105. panic("unable to ioremap R-Car SYSC hardware block\n");
  106. return rcar_sysc_base;
  107. }