diff options
Diffstat (limited to 'arch/arm/mach-s3c2412')
-rw-r--r-- | arch/arm/mach-s3c2412/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/clock.c | 54 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/dma.c | 48 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/gpio.c | 60 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/irq.c | 24 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/pm.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/s3c2412.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/sleep.S | 68 |
9 files changed, 255 insertions, 23 deletions
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig index 8e8fe48ea47f..0b43431d4b75 100644 --- a/arch/arm/mach-s3c2412/Kconfig +++ b/arch/arm/mach-s3c2412/Kconfig | |||
@@ -10,6 +10,7 @@ config CPU_S3C2412 | |||
10 | select CPU_LLSERIAL_S3C2440 | 10 | select CPU_LLSERIAL_S3C2440 |
11 | select S3C2412_PM if PM | 11 | select S3C2412_PM if PM |
12 | select S3C2412_DMA if S3C2410_DMA | 12 | select S3C2412_DMA if S3C2410_DMA |
13 | select S3C2410_GPIO | ||
13 | help | 14 | help |
14 | Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line | 15 | Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line |
15 | 16 | ||
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile index f8e011691b31..267f3348301e 100644 --- a/arch/arm/mach-s3c2412/Makefile +++ b/arch/arm/mach-s3c2412/Makefile | |||
@@ -12,8 +12,9 @@ obj- := | |||
12 | obj-$(CONFIG_CPU_S3C2412) += s3c2412.o | 12 | obj-$(CONFIG_CPU_S3C2412) += s3c2412.o |
13 | obj-$(CONFIG_CPU_S3C2412) += irq.o | 13 | obj-$(CONFIG_CPU_S3C2412) += irq.o |
14 | obj-$(CONFIG_CPU_S3C2412) += clock.o | 14 | obj-$(CONFIG_CPU_S3C2412) += clock.o |
15 | obj-$(CONFIG_CPU_S3C2412) += gpio.o | ||
15 | obj-$(CONFIG_S3C2412_DMA) += dma.o | 16 | obj-$(CONFIG_S3C2412_DMA) += dma.o |
16 | obj-$(CONFIG_S3C2412_PM) += pm.o | 17 | obj-$(CONFIG_S3C2412_PM) += pm.o sleep.o |
17 | 18 | ||
18 | # Machine support | 19 | # Machine support |
19 | 20 | ||
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c index 458993601897..2697a65ba727 100644 --- a/arch/arm/mach-s3c2412/clock.c +++ b/arch/arm/mach-s3c2412/clock.c | |||
@@ -217,7 +217,7 @@ static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent) | |||
217 | 217 | ||
218 | if (parent == &clk_mdivclk) | 218 | if (parent == &clk_mdivclk) |
219 | clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL; | 219 | clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL; |
220 | else if (parent == &clk_upll) | 220 | else if (parent == &clk_mpll) |
221 | clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL; | 221 | clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL; |
222 | else | 222 | else |
223 | return -EINVAL; | 223 | return -EINVAL; |
@@ -234,6 +234,45 @@ static struct clk clk_msysclk = { | |||
234 | .set_parent = s3c2412_setparent_msysclk, | 234 | .set_parent = s3c2412_setparent_msysclk, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent) | ||
238 | { | ||
239 | unsigned long flags; | ||
240 | unsigned long clkdiv; | ||
241 | unsigned long dvs; | ||
242 | |||
243 | /* Note, we current equate fclk andf msysclk for S3C2412 */ | ||
244 | |||
245 | if (parent == &clk_msysclk || parent == &clk_f) | ||
246 | dvs = 0; | ||
247 | else if (parent == &clk_h) | ||
248 | dvs = S3C2412_CLKDIVN_DVSEN; | ||
249 | else | ||
250 | return -EINVAL; | ||
251 | |||
252 | clk->parent = parent; | ||
253 | |||
254 | /* update this under irq lockdown, clkdivn is not protected | ||
255 | * by the clock system. */ | ||
256 | |||
257 | local_irq_save(flags); | ||
258 | |||
259 | clkdiv = __raw_readl(S3C2410_CLKDIVN); | ||
260 | clkdiv &= ~S3C2412_CLKDIVN_DVSEN; | ||
261 | clkdiv |= dvs; | ||
262 | __raw_writel(clkdiv, S3C2410_CLKDIVN); | ||
263 | |||
264 | local_irq_restore(flags); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static struct clk clk_armclk = { | ||
270 | .name = "armclk", | ||
271 | .id = -1, | ||
272 | .parent = &clk_msysclk, | ||
273 | .set_parent = s3c2412_setparent_armclk, | ||
274 | }; | ||
275 | |||
237 | /* these next clocks have an divider immediately after them, | 276 | /* these next clocks have an divider immediately after them, |
238 | * so we can register them with their divider and leave out the | 277 | * so we can register them with their divider and leave out the |
239 | * intermediate clock stage | 278 | * intermediate clock stage |
@@ -630,11 +669,13 @@ static struct clk *clks[] __initdata = { | |||
630 | &clk_erefclk, | 669 | &clk_erefclk, |
631 | &clk_urefclk, | 670 | &clk_urefclk, |
632 | &clk_mrefclk, | 671 | &clk_mrefclk, |
672 | &clk_armclk, | ||
633 | }; | 673 | }; |
634 | 674 | ||
635 | int __init s3c2412_baseclk_add(void) | 675 | int __init s3c2412_baseclk_add(void) |
636 | { | 676 | { |
637 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | 677 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); |
678 | unsigned int dvs; | ||
638 | struct clk *clkp; | 679 | struct clk *clkp; |
639 | int ret; | 680 | int ret; |
640 | int ptr; | 681 | int ptr; |
@@ -643,6 +684,8 @@ int __init s3c2412_baseclk_add(void) | |||
643 | clk_usb_bus.parent = &clk_usbsrc; | 684 | clk_usb_bus.parent = &clk_usbsrc; |
644 | clk_usb_bus.rate = 0x0; | 685 | clk_usb_bus.rate = 0x0; |
645 | 686 | ||
687 | clk_f.parent = &clk_msysclk; | ||
688 | |||
646 | s3c2412_clk_initparents(); | 689 | s3c2412_clk_initparents(); |
647 | 690 | ||
648 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { | 691 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { |
@@ -655,6 +698,15 @@ int __init s3c2412_baseclk_add(void) | |||
655 | } | 698 | } |
656 | } | 699 | } |
657 | 700 | ||
701 | /* set the dvs state according to what we got at boot time */ | ||
702 | |||
703 | dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN; | ||
704 | |||
705 | if (dvs) | ||
706 | clk_armclk.parent = &clk_h; | ||
707 | |||
708 | printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off"); | ||
709 | |||
658 | /* ensure usb bus clock is within correct rate of 48MHz */ | 710 | /* ensure usb bus clock is within correct rate of 48MHz */ |
659 | 711 | ||
660 | if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { | 712 | if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { |
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c index 53c1d5bbce19..1dd864993566 100644 --- a/arch/arm/mach-s3c2412/dma.c +++ b/arch/arm/mach-s3c2412/dma.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/arch/regs-mem.h> | 30 | #include <asm/arch/regs-mem.h> |
31 | #include <asm/arch/regs-lcd.h> | 31 | #include <asm/arch/regs-lcd.h> |
32 | #include <asm/arch/regs-sdi.h> | 32 | #include <asm/arch/regs-sdi.h> |
33 | #include <asm/plat-s3c24xx/regs-s3c2412-iis.h> | ||
33 | #include <asm/plat-s3c24xx/regs-iis.h> | 34 | #include <asm/plat-s3c24xx/regs-iis.h> |
34 | #include <asm/plat-s3c24xx/regs-spi.h> | 35 | #include <asm/plat-s3c24xx/regs-spi.h> |
35 | 36 | ||
@@ -39,106 +40,141 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = { | |||
39 | [DMACH_XD0] = { | 40 | [DMACH_XD0] = { |
40 | .name = "xdreq0", | 41 | .name = "xdreq0", |
41 | .channels = MAP(S3C2412_DMAREQSEL_XDREQ0), | 42 | .channels = MAP(S3C2412_DMAREQSEL_XDREQ0), |
43 | .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ0), | ||
42 | }, | 44 | }, |
43 | [DMACH_XD1] = { | 45 | [DMACH_XD1] = { |
44 | .name = "xdreq1", | 46 | .name = "xdreq1", |
45 | .channels = MAP(S3C2412_DMAREQSEL_XDREQ1), | 47 | .channels = MAP(S3C2412_DMAREQSEL_XDREQ1), |
48 | .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ1), | ||
46 | }, | 49 | }, |
47 | [DMACH_SDI] = { | 50 | [DMACH_SDI] = { |
48 | .name = "sdi", | 51 | .name = "sdi", |
49 | .channels = MAP(S3C2412_DMAREQSEL_SDI), | 52 | .channels = MAP(S3C2412_DMAREQSEL_SDI), |
50 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | 53 | .channels_rx = MAP(S3C2412_DMAREQSEL_SDI), |
51 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | 54 | .hw_addr.to = S3C2410_PA_SDI + S3C2410_SDIDATA, |
55 | .hw_addr.from = S3C2410_PA_SDI + S3C2410_SDIDATA, | ||
52 | }, | 56 | }, |
53 | [DMACH_SPI0] = { | 57 | [DMACH_SPI0] = { |
54 | .name = "spi0", | 58 | .name = "spi0", |
55 | .channels = MAP(S3C2412_DMAREQSEL_SPI0TX), | 59 | .channels = MAP(S3C2412_DMAREQSEL_SPI0TX), |
60 | .channels_rx = MAP(S3C2412_DMAREQSEL_SPI0RX), | ||
56 | .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, | 61 | .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, |
57 | .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, | 62 | .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, |
58 | }, | 63 | }, |
59 | [DMACH_SPI1] = { | 64 | [DMACH_SPI1] = { |
60 | .name = "spi1", | 65 | .name = "spi1", |
61 | .channels = MAP(S3C2412_DMAREQSEL_SPI1TX), | 66 | .channels = MAP(S3C2412_DMAREQSEL_SPI1TX), |
67 | .channels_rx = MAP(S3C2412_DMAREQSEL_SPI1RX), | ||
62 | .hw_addr.to = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT, | 68 | .hw_addr.to = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT, |
63 | .hw_addr.from = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPRDAT, | 69 | .hw_addr.from = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPRDAT, |
64 | }, | 70 | }, |
65 | [DMACH_UART0] = { | 71 | [DMACH_UART0] = { |
66 | .name = "uart0", | 72 | .name = "uart0", |
67 | .channels = MAP(S3C2412_DMAREQSEL_UART0_0), | 73 | .channels = MAP(S3C2412_DMAREQSEL_UART0_0), |
74 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_0), | ||
68 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | 75 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, |
69 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | 76 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, |
70 | }, | 77 | }, |
71 | [DMACH_UART1] = { | 78 | [DMACH_UART1] = { |
72 | .name = "uart1", | 79 | .name = "uart1", |
73 | .channels = MAP(S3C2412_DMAREQSEL_UART1_0), | 80 | .channels = MAP(S3C2412_DMAREQSEL_UART1_0), |
81 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_0), | ||
74 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | 82 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, |
75 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | 83 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, |
76 | }, | 84 | }, |
77 | [DMACH_UART2] = { | 85 | [DMACH_UART2] = { |
78 | .name = "uart2", | 86 | .name = "uart2", |
79 | .channels = MAP(S3C2412_DMAREQSEL_UART2_0), | 87 | .channels = MAP(S3C2412_DMAREQSEL_UART2_0), |
88 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_0), | ||
80 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | 89 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, |
81 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | 90 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, |
82 | }, | 91 | }, |
83 | [DMACH_UART0_SRC2] = { | 92 | [DMACH_UART0_SRC2] = { |
84 | .name = "uart0", | 93 | .name = "uart0", |
85 | .channels = MAP(S3C2412_DMAREQSEL_UART0_1), | 94 | .channels = MAP(S3C2412_DMAREQSEL_UART0_1), |
95 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_1), | ||
86 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | 96 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, |
87 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | 97 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, |
88 | }, | 98 | }, |
89 | [DMACH_UART1_SRC2] = { | 99 | [DMACH_UART1_SRC2] = { |
90 | .name = "uart1", | 100 | .name = "uart1", |
91 | .channels = MAP(S3C2412_DMAREQSEL_UART1_1), | 101 | .channels = MAP(S3C2412_DMAREQSEL_UART1_1), |
102 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_1), | ||
92 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | 103 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, |
93 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | 104 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, |
94 | }, | 105 | }, |
95 | [DMACH_UART2_SRC2] = { | 106 | [DMACH_UART2_SRC2] = { |
96 | .name = "uart2", | 107 | .name = "uart2", |
97 | .channels = MAP(S3C2412_DMAREQSEL_UART2_1), | 108 | .channels = MAP(S3C2412_DMAREQSEL_UART2_1), |
109 | .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_1), | ||
98 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | 110 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, |
99 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | 111 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, |
100 | }, | 112 | }, |
101 | [DMACH_TIMER] = { | 113 | [DMACH_TIMER] = { |
102 | .name = "timer", | 114 | .name = "timer", |
103 | .channels = MAP(S3C2412_DMAREQSEL_TIMER), | 115 | .channels = MAP(S3C2412_DMAREQSEL_TIMER), |
116 | .channels_rx = MAP(S3C2412_DMAREQSEL_TIMER), | ||
104 | }, | 117 | }, |
105 | [DMACH_I2S_IN] = { | 118 | [DMACH_I2S_IN] = { |
106 | .name = "i2s-sdi", | 119 | .name = "i2s-sdi", |
107 | .channels = MAP(S3C2412_DMAREQSEL_I2SRX), | 120 | .channels = MAP(S3C2412_DMAREQSEL_I2SRX), |
108 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | 121 | .channels_rx = MAP(S3C2412_DMAREQSEL_I2SRX), |
122 | .hw_addr.from = S3C2410_PA_IIS + S3C2412_IISRXD, | ||
109 | }, | 123 | }, |
110 | [DMACH_I2S_OUT] = { | 124 | [DMACH_I2S_OUT] = { |
111 | .name = "i2s-sdo", | 125 | .name = "i2s-sdo", |
112 | .channels = MAP(S3C2412_DMAREQSEL_I2STX), | 126 | .channels = MAP(S3C2412_DMAREQSEL_I2STX), |
113 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | 127 | .channels_rx = MAP(S3C2412_DMAREQSEL_I2STX), |
128 | .hw_addr.to = S3C2410_PA_IIS + S3C2412_IISTXD, | ||
114 | }, | 129 | }, |
115 | [DMACH_USB_EP1] = { | 130 | [DMACH_USB_EP1] = { |
116 | .name = "usb-ep1", | 131 | .name = "usb-ep1", |
117 | .channels = MAP(S3C2412_DMAREQSEL_USBEP1), | 132 | .channels = MAP(S3C2412_DMAREQSEL_USBEP1), |
133 | .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP1), | ||
118 | }, | 134 | }, |
119 | [DMACH_USB_EP2] = { | 135 | [DMACH_USB_EP2] = { |
120 | .name = "usb-ep2", | 136 | .name = "usb-ep2", |
121 | .channels = MAP(S3C2412_DMAREQSEL_USBEP2), | 137 | .channels = MAP(S3C2412_DMAREQSEL_USBEP2), |
138 | .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP2), | ||
122 | }, | 139 | }, |
123 | [DMACH_USB_EP3] = { | 140 | [DMACH_USB_EP3] = { |
124 | .name = "usb-ep3", | 141 | .name = "usb-ep3", |
125 | .channels = MAP(S3C2412_DMAREQSEL_USBEP3), | 142 | .channels = MAP(S3C2412_DMAREQSEL_USBEP3), |
143 | .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP3), | ||
126 | }, | 144 | }, |
127 | [DMACH_USB_EP4] = { | 145 | [DMACH_USB_EP4] = { |
128 | .name = "usb-ep4", | 146 | .name = "usb-ep4", |
129 | .channels = MAP(S3C2412_DMAREQSEL_USBEP4), | 147 | .channels = MAP(S3C2412_DMAREQSEL_USBEP4), |
148 | .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP4), | ||
130 | }, | 149 | }, |
131 | }; | 150 | }; |
132 | 151 | ||
152 | static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan, | ||
153 | struct s3c24xx_dma_map *map, | ||
154 | enum s3c2410_dmasrc dir) | ||
155 | { | ||
156 | unsigned long chsel; | ||
157 | |||
158 | if (dir == S3C2410_DMASRC_HW) | ||
159 | chsel = map->channels_rx[0]; | ||
160 | else | ||
161 | chsel = map->channels[0]; | ||
162 | |||
163 | chsel &= ~DMA_CH_VALID; | ||
164 | chsel |= S3C2412_DMAREQSEL_HW; | ||
165 | |||
166 | writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL); | ||
167 | } | ||
168 | |||
133 | static void s3c2412_dma_select(struct s3c2410_dma_chan *chan, | 169 | static void s3c2412_dma_select(struct s3c2410_dma_chan *chan, |
134 | struct s3c24xx_dma_map *map) | 170 | struct s3c24xx_dma_map *map) |
135 | { | 171 | { |
136 | writel(map->channels[0] | S3C2412_DMAREQSEL_HW, | 172 | s3c2412_dma_direction(chan, map, chan->source); |
137 | chan->regs + S3C2412_DMA_DMAREQSEL); | ||
138 | } | 173 | } |
139 | 174 | ||
140 | static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { | 175 | static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { |
141 | .select = s3c2412_dma_select, | 176 | .select = s3c2412_dma_select, |
177 | .direction = s3c2412_dma_direction, | ||
142 | .dcon_mask = 0, | 178 | .dcon_mask = 0, |
143 | .map = s3c2412_dma_mappings, | 179 | .map = s3c2412_dma_mappings, |
144 | .map_size = ARRAY_SIZE(s3c2412_dma_mappings), | 180 | .map_size = ARRAY_SIZE(s3c2412_dma_mappings), |
diff --git a/arch/arm/mach-s3c2412/gpio.c b/arch/arm/mach-s3c2412/gpio.c new file mode 100644 index 000000000000..8e55c3a2eab8 --- /dev/null +++ b/arch/arm/mach-s3c2412/gpio.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* linux/arch/arm/mach-s3c2412/gpio.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * http://armlinux.simtec.co.uk/. | ||
7 | * | ||
8 | * S3C2412/S3C2413 specific GPIO support | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | |||
20 | #include <asm/mach/arch.h> | ||
21 | #include <asm/mach/map.h> | ||
22 | |||
23 | #include <asm/arch/regs-gpio.h> | ||
24 | |||
25 | #include <asm/hardware.h> | ||
26 | |||
27 | int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state) | ||
28 | { | ||
29 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
30 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
31 | unsigned long flags; | ||
32 | unsigned long slpcon; | ||
33 | |||
34 | offs *= 2; | ||
35 | |||
36 | if (pin < S3C2410_GPIO_BANKB) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (pin >= S3C2410_GPIO_BANKF && | ||
40 | pin <= S3C2410_GPIO_BANKG) | ||
41 | return -EINVAL; | ||
42 | |||
43 | if (pin > (S3C2410_GPIO_BANKH + 32)) | ||
44 | return -EINVAL; | ||
45 | |||
46 | local_irq_save(flags); | ||
47 | |||
48 | slpcon = __raw_readl(base + 0x0C); | ||
49 | |||
50 | slpcon &= ~(3 << offs); | ||
51 | slpcon |= state << offs; | ||
52 | |||
53 | __raw_writel(slpcon, base + 0x0C); | ||
54 | |||
55 | local_irq_restore(flags); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | EXPORT_SYMBOL(s3c2412_gpio_set_sleepcfg); | ||
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c index e9d0c769f5da..cc1917bf952a 100644 --- a/arch/arm/mach-s3c2412/irq.c +++ b/arch/arm/mach-s3c2412/irq.c | |||
@@ -33,6 +33,7 @@ | |||
33 | 33 | ||
34 | #include <asm/arch/regs-irq.h> | 34 | #include <asm/arch/regs-irq.h> |
35 | #include <asm/arch/regs-gpio.h> | 35 | #include <asm/arch/regs-gpio.h> |
36 | #include <asm/arch/regs-power.h> | ||
36 | 37 | ||
37 | #include <asm/plat-s3c24xx/cpu.h> | 38 | #include <asm/plat-s3c24xx/cpu.h> |
38 | #include <asm/plat-s3c24xx/irq.h> | 39 | #include <asm/plat-s3c24xx/irq.h> |
@@ -153,6 +154,22 @@ static struct irq_chip s3c2412_irq_cfsdi = { | |||
153 | .unmask = s3c2412_irq_cfsdi_unmask, | 154 | .unmask = s3c2412_irq_cfsdi_unmask, |
154 | }; | 155 | }; |
155 | 156 | ||
157 | static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state) | ||
158 | { | ||
159 | unsigned long pwrcfg; | ||
160 | |||
161 | pwrcfg = __raw_readl(S3C2412_PWRCFG); | ||
162 | if (state) | ||
163 | pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ; | ||
164 | else | ||
165 | pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ; | ||
166 | __raw_writel(pwrcfg, S3C2412_PWRCFG); | ||
167 | |||
168 | return s3c_irq_chip.set_wake(irqno, state); | ||
169 | } | ||
170 | |||
171 | static struct irq_chip s3c2412_irq_rtc_chip; | ||
172 | |||
156 | static int s3c2412_irq_add(struct sys_device *sysdev) | 173 | static int s3c2412_irq_add(struct sys_device *sysdev) |
157 | { | 174 | { |
158 | unsigned int irqno; | 175 | unsigned int irqno; |
@@ -173,6 +190,13 @@ static int s3c2412_irq_add(struct sys_device *sysdev) | |||
173 | set_irq_flags(irqno, IRQF_VALID); | 190 | set_irq_flags(irqno, IRQF_VALID); |
174 | } | 191 | } |
175 | 192 | ||
193 | /* change RTC IRQ's set wake method */ | ||
194 | |||
195 | s3c2412_irq_rtc_chip = s3c_irq_chip; | ||
196 | s3c2412_irq_rtc_chip.set_wake = s3c2412_irq_rtc_wake; | ||
197 | |||
198 | set_irq_chip(IRQ_RTC, &s3c2412_irq_rtc_chip); | ||
199 | |||
176 | return 0; | 200 | return 0; |
177 | } | 201 | } |
178 | 202 | ||
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c index 8988dac388a9..d4ffb2d98076 100644 --- a/arch/arm/mach-s3c2412/pm.c +++ b/arch/arm/mach-s3c2412/pm.c | |||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | #include <asm/plat-s3c24xx/s3c2412.h> | 34 | #include <asm/plat-s3c24xx/s3c2412.h> |
35 | 35 | ||
36 | extern void s3c2412_sleep_enter(void); | ||
37 | |||
36 | static void s3c2412_cpu_suspend(void) | 38 | static void s3c2412_cpu_suspend(void) |
37 | { | 39 | { |
38 | unsigned long tmp; | 40 | unsigned long tmp; |
@@ -43,20 +45,7 @@ static void s3c2412_cpu_suspend(void) | |||
43 | tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP; | 45 | tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP; |
44 | __raw_writel(tmp, S3C2412_PWRCFG); | 46 | __raw_writel(tmp, S3C2412_PWRCFG); |
45 | 47 | ||
46 | /* issue the standby signal into the pm unit. Note, we | 48 | s3c2412_sleep_enter(); |
47 | * issue a write-buffer drain just in case */ | ||
48 | |||
49 | tmp = 0; | ||
50 | |||
51 | asm("b 1f\n\t" | ||
52 | ".align 5\n\t" | ||
53 | "1:\n\t" | ||
54 | "mcr p15, 0, %0, c7, c10, 4\n\t" | ||
55 | "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp)); | ||
56 | |||
57 | /* we should never get past here */ | ||
58 | |||
59 | panic("sleep resumed to originator?"); | ||
60 | } | 49 | } |
61 | 50 | ||
62 | static void s3c2412_pm_prepare(void) | 51 | static void s3c2412_pm_prepare(void) |
@@ -88,7 +77,6 @@ static struct sleep_save s3c2412_sleep[] = { | |||
88 | SAVE_ITEM(S3C2412_GPBSLPCON), | 77 | SAVE_ITEM(S3C2412_GPBSLPCON), |
89 | SAVE_ITEM(S3C2412_GPCSLPCON), | 78 | SAVE_ITEM(S3C2412_GPCSLPCON), |
90 | SAVE_ITEM(S3C2412_GPDSLPCON), | 79 | SAVE_ITEM(S3C2412_GPDSLPCON), |
91 | SAVE_ITEM(S3C2412_GPESLPCON), | ||
92 | SAVE_ITEM(S3C2412_GPFSLPCON), | 80 | SAVE_ITEM(S3C2412_GPFSLPCON), |
93 | SAVE_ITEM(S3C2412_GPGSLPCON), | 81 | SAVE_ITEM(S3C2412_GPGSLPCON), |
94 | SAVE_ITEM(S3C2412_GPHSLPCON), | 82 | SAVE_ITEM(S3C2412_GPHSLPCON), |
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 265cd3f567a3..abf1599c9f97 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c | |||
@@ -168,6 +168,8 @@ void __init s3c2412_init_clocks(int xtal) | |||
168 | 168 | ||
169 | fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2); | 169 | fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2); |
170 | 170 | ||
171 | clk_mpll.rate = fclk; | ||
172 | |||
171 | tmp = __raw_readl(S3C2410_CLKDIVN); | 173 | tmp = __raw_readl(S3C2410_CLKDIVN); |
172 | 174 | ||
173 | /* work out clock scalings */ | 175 | /* work out clock scalings */ |
diff --git a/arch/arm/mach-s3c2412/sleep.S b/arch/arm/mach-s3c2412/sleep.S new file mode 100644 index 000000000000..db32cac4199a --- /dev/null +++ b/arch/arm/mach-s3c2412/sleep.S | |||
@@ -0,0 +1,68 @@ | |||
1 | /* linux/arch/arm/mach-s3c2412/sleep.S | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2412 Power Manager low-level sleep support | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/linkage.h> | ||
24 | #include <asm/assembler.h> | ||
25 | #include <asm/hardware.h> | ||
26 | #include <asm/arch/map.h> | ||
27 | |||
28 | #include <asm/arch/regs-irq.h> | ||
29 | |||
30 | .text | ||
31 | |||
32 | .global s3c2412_sleep_enter | ||
33 | |||
34 | s3c2412_sleep_enter: | ||
35 | mov r0, #0 /* argument for coprocessors */ | ||
36 | ldr r1, =S3C2410_INTPND | ||
37 | ldr r2, =S3C2410_SRCPND | ||
38 | ldr r3, =S3C2410_EINTPEND | ||
39 | |||
40 | teq r0, r0 | ||
41 | bl s3c2412_sleep_enter1 | ||
42 | teq pc, r0 | ||
43 | bl s3c2412_sleep_enter1 | ||
44 | |||
45 | .align 5 | ||
46 | |||
47 | /* this is called twice, first with the Z flag to ensure that the | ||
48 | * instructions have been loaded into the cache, and the second | ||
49 | * time to try and suspend the system. | ||
50 | */ | ||
51 | s3c2412_sleep_enter1: | ||
52 | mcr p15, 0, r0, c7, c10, 4 | ||
53 | mcrne p15, 0, r0, c7, c0, 4 | ||
54 | |||
55 | /* if we return from here, it is because an interrupt was | ||
56 | * active when we tried to shutdown. Try and ack the IRQ and | ||
57 | * retry, as simply returning causes the system to lock. | ||
58 | */ | ||
59 | |||
60 | ldrne r9, [ r1 ] | ||
61 | strne r9, [ r1 ] | ||
62 | ldrne r9, [ r2 ] | ||
63 | strne r9, [ r2 ] | ||
64 | ldrne r9, [ r3 ] | ||
65 | strne r9, [ r3 ] | ||
66 | bne s3c2412_sleep_enter1 | ||
67 | |||
68 | mov pc, r14 | ||