blob: b5abdeb5bb2d17d6e63e4bc844047e0ea1928b05 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/mach-pxa/pxa27x.c
3 *
4 * Author: Nicolas Pitre
5 * Created: Nov 05, 2002
6 * Copyright: MontaVista Software Inc.
7 *
8 * Code specific to PXA27x aka Bulverde.
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 */
Russell King2f8163b2011-07-26 10:53:52 +010014#include <linux/gpio.h>
Haojian Zhuang157d2642011-10-17 20:37:52 +080015#include <linux/gpio-pxa.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
Rafael J. Wysocki95d9ffb2007-10-18 03:04:39 -070019#include <linux/suspend.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010020#include <linux/platform_device.h>
Rafael J. Wysocki2eaa03b2011-04-22 22:03:11 +020021#include <linux/syscore_ops.h>
Marek Vasutad68bb92010-11-03 16:29:35 +010022#include <linux/io.h>
Lennert Buytenheka3f4c922010-11-29 11:18:26 +010023#include <linux/irq.h>
Sebastian Andrzej Siewiorb4593962011-02-23 12:38:16 +010024#include <linux/i2c/pxa-i2c.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Marek Vasut851982c2010-10-11 02:20:19 +020026#include <asm/mach/map.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010027#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/irq.h>
Russell King2c74a0c2011-06-22 17:41:48 +010029#include <asm/suspend.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010030#include <mach/irqs.h>
Eric Miao51c62982009-01-02 23:17:22 +080031#include <mach/pxa27x.h>
Russell Kingafd2fc02008-08-07 11:05:25 +010032#include <mach/reset.h>
Arnd Bergmann293b2da2012-08-24 15:16:48 +020033#include <linux/platform_data/usb-ohci-pxa27x.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010034#include <mach/pm.h>
35#include <mach/dma.h>
Marek Vasutad68bb92010-11-03 16:29:35 +010036#include <mach/smemc.h>
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "generic.h"
Russell King46c41e62007-05-15 15:39:36 +010039#include "devices.h"
Robert Jarzmik48a17db2014-12-27 14:55:26 +010040#include <linux/clk-provider.h>
41#include <linux/clkdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Eric Miao0cb0b0d2008-10-04 12:45:39 +080043void pxa27x_clear_otgph(void)
44{
45 if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH))
46 PSSR |= PSSR_OTGPH;
47}
48EXPORT_SYMBOL(pxa27x_clear_otgph);
49
Eric Miaofb1bf8c2010-01-04 16:30:58 +080050static unsigned long ac97_reset_config[] = {
Mike Dunn3b4bc7b2013-01-07 13:55:13 -080051 GPIO113_AC97_nRESET_GPIO_HIGH,
Eric Miao5e16e3c2010-07-13 09:41:28 +080052 GPIO113_AC97_nRESET,
Mike Dunn3b4bc7b2013-01-07 13:55:13 -080053 GPIO95_AC97_nRESET_GPIO_HIGH,
Eric Miao5e16e3c2010-07-13 09:41:28 +080054 GPIO95_AC97_nRESET,
Eric Miaofb1bf8c2010-01-04 16:30:58 +080055};
56
Mike Dunn053fe0f2013-01-07 13:55:14 -080057void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
Eric Miaofb1bf8c2010-01-04 16:30:58 +080058{
Mike Dunn053fe0f2013-01-07 13:55:14 -080059 /*
60 * This helper function is used to work around a bug in the pxa27x's
61 * ac97 controller during a warm reset. The configuration of the
62 * reset_gpio is changed as follows:
63 * to_gpio == true: configured to generic output gpio and driven high
64 * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET
65 */
66
Eric Miaofb1bf8c2010-01-04 16:30:58 +080067 if (reset_gpio == 113)
Mike Dunn053fe0f2013-01-07 13:55:14 -080068 pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] :
69 &ac97_reset_config[1], 1);
Eric Miaofb1bf8c2010-01-04 16:30:58 +080070
71 if (reset_gpio == 95)
Mike Dunn053fe0f2013-01-07 13:55:14 -080072 pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] :
73 &ac97_reset_config[3], 1);
Eric Miaofb1bf8c2010-01-04 16:30:58 +080074}
Mike Dunn053fe0f2013-01-07 13:55:14 -080075EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
Eric Miaofb1bf8c2010-01-04 16:30:58 +080076
Nicolas Pitrea8fa3f02005-06-13 22:35:41 +010077#ifdef CONFIG_PM
78
Eric Miao711be5c2007-07-18 11:38:45 +010079#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
80#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
81
Eric Miao711be5c2007-07-18 11:38:45 +010082/*
Mike Rapoportd082d362009-05-26 09:10:18 +030083 * allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM
84 */
85static unsigned int pwrmode = PWRMODE_SLEEP;
86
87int __init pxa27x_set_pwrmode(unsigned int mode)
88{
89 switch (mode) {
90 case PWRMODE_SLEEP:
91 case PWRMODE_DEEPSLEEP:
92 pwrmode = mode;
93 return 0;
94 }
95
96 return -EINVAL;
97}
98
99/*
Eric Miao711be5c2007-07-18 11:38:45 +0100100 * List of global PXA peripheral registers to preserve.
101 * More ones like CP and general purpose register values are preserved
102 * with the stack pointer in sleep.S.
103 */
Eric Miao5a3d9652008-09-03 18:06:34 +0800104enum {
Eric Miao711be5c2007-07-18 11:38:45 +0100105 SLEEP_SAVE_PSTR,
Eric Miao711be5c2007-07-18 11:38:45 +0100106 SLEEP_SAVE_MDREFR,
Eric Miao5a3d9652008-09-03 18:06:34 +0800107 SLEEP_SAVE_PCFR,
Robert Jarzmik649de512008-05-02 21:17:06 +0100108 SLEEP_SAVE_COUNT
Eric Miao711be5c2007-07-18 11:38:45 +0100109};
110
111void pxa27x_cpu_pm_save(unsigned long *sleep_save)
112{
Marek Vasutad68bb92010-11-03 16:29:35 +0100113 sleep_save[SLEEP_SAVE_MDREFR] = __raw_readl(MDREFR);
Eric Miao5a3d9652008-09-03 18:06:34 +0800114 SAVE(PCFR);
Eric Miao711be5c2007-07-18 11:38:45 +0100115
Eric Miao711be5c2007-07-18 11:38:45 +0100116 SAVE(PSTR);
Eric Miao711be5c2007-07-18 11:38:45 +0100117}
118
119void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
120{
Marek Vasutad68bb92010-11-03 16:29:35 +0100121 __raw_writel(sleep_save[SLEEP_SAVE_MDREFR], MDREFR);
Eric Miao5a3d9652008-09-03 18:06:34 +0800122 RESTORE(PCFR);
Eric Miao711be5c2007-07-18 11:38:45 +0100123
124 PSSR = PSSR_RDH | PSSR_PH;
125
Eric Miao711be5c2007-07-18 11:38:45 +0100126 RESTORE(PSTR);
127}
128
129void pxa27x_cpu_pm_enter(suspend_state_t state)
Todd Poynor87754202005-06-03 20:52:27 +0100130{
131 extern void pxa_cpu_standby(void);
Russell Kinga9503d22011-06-21 16:29:30 +0100132#ifndef CONFIG_IWMMXT
133 u64 acc0;
134
135 asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0));
136#endif
Todd Poynor87754202005-06-03 20:52:27 +0100137
Todd Poynor87754202005-06-03 20:52:27 +0100138 /* ensure voltage-change sequencer not initiated, which hangs */
139 PCFR &= ~PCFR_FVC;
140
141 /* Clear edge-detect status register. */
142 PEDR = 0xDF12FE1B;
143
Russell Kingdc38e2a2008-05-08 16:50:39 +0100144 /* Clear reset status */
145 RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
146
Todd Poynor87754202005-06-03 20:52:27 +0100147 switch (state) {
Todd Poynor26705ca2005-07-01 11:27:05 +0100148 case PM_SUSPEND_STANDBY:
149 pxa_cpu_standby();
150 break;
Todd Poynor87754202005-06-03 20:52:27 +0100151 case PM_SUSPEND_MEM:
Russell King2c74a0c2011-06-22 17:41:48 +0100152 cpu_suspend(pwrmode, pxa27x_finish_suspend);
Russell Kinga9503d22011-06-21 16:29:30 +0100153#ifndef CONFIG_IWMMXT
154 asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0));
155#endif
Todd Poynor87754202005-06-03 20:52:27 +0100156 break;
157 }
158}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Eric Miao711be5c2007-07-18 11:38:45 +0100160static int pxa27x_cpu_pm_valid(suspend_state_t state)
Russell King88dfe982007-05-15 11:22:48 +0100161{
162 return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
163}
164
Russell King41049802008-08-27 12:55:04 +0100165static int pxa27x_cpu_pm_prepare(void)
166{
167 /* set resume return address */
Russell King4f5ad992011-02-06 17:41:26 +0000168 PSPR = virt_to_phys(cpu_resume);
Russell King41049802008-08-27 12:55:04 +0100169 return 0;
170}
171
172static void pxa27x_cpu_pm_finish(void)
173{
174 /* ensure not to come back here if it wasn't intended */
175 PSPR = 0;
176}
177
Eric Miao711be5c2007-07-18 11:38:45 +0100178static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
Robert Jarzmik649de512008-05-02 21:17:06 +0100179 .save_count = SLEEP_SAVE_COUNT,
Eric Miao711be5c2007-07-18 11:38:45 +0100180 .save = pxa27x_cpu_pm_save,
181 .restore = pxa27x_cpu_pm_restore,
182 .valid = pxa27x_cpu_pm_valid,
183 .enter = pxa27x_cpu_pm_enter,
Russell King41049802008-08-27 12:55:04 +0100184 .prepare = pxa27x_cpu_pm_prepare,
185 .finish = pxa27x_cpu_pm_finish,
Russell Kinge176bb02007-05-15 11:16:10 +0100186};
Eric Miao711be5c2007-07-18 11:38:45 +0100187
188static void __init pxa27x_init_pm(void)
189{
190 pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
191}
eric miaof79299c2008-01-02 08:24:49 +0800192#else
193static inline void pxa27x_init_pm(void) {}
Nicolas Pitrea8fa3f02005-06-13 22:35:41 +0100194#endif
195
eric miaoc95530c2007-08-29 10:22:17 +0100196/* PXA27x: Various gpios can issue wakeup events. This logic only
197 * handles the simple cases, not the WEMUX2 and WEMUX3 options
198 */
Lennert Buytenheka3f4c922010-11-29 11:18:26 +0100199static int pxa27x_set_wake(struct irq_data *d, unsigned int on)
eric miaoc95530c2007-08-29 10:22:17 +0100200{
Haojian Zhuang4929f5a2011-10-10 16:03:51 +0800201 int gpio = pxa_irq_to_gpio(d->irq);
eric miaoc95530c2007-08-29 10:22:17 +0100202 uint32_t mask;
203
eric miaoc0a596d2008-03-11 09:46:28 +0800204 if (gpio >= 0 && gpio < 128)
205 return gpio_set_wake(gpio, on);
eric miaoc95530c2007-08-29 10:22:17 +0100206
Lennert Buytenheka3f4c922010-11-29 11:18:26 +0100207 if (d->irq == IRQ_KEYPAD)
eric miaoc0a596d2008-03-11 09:46:28 +0800208 return keypad_set_wake(on);
eric miaoc95530c2007-08-29 10:22:17 +0100209
Lennert Buytenheka3f4c922010-11-29 11:18:26 +0100210 switch (d->irq) {
eric miaoc95530c2007-08-29 10:22:17 +0100211 case IRQ_RTCAlrm:
212 mask = PWER_RTC;
213 break;
214 case IRQ_USB:
215 mask = 1u << 26;
216 break;
217 default:
218 return -EINVAL;
219 }
220
eric miaoc95530c2007-08-29 10:22:17 +0100221 if (on)
222 PWER |= mask;
223 else
224 PWER &=~mask;
225
226 return 0;
227}
228
229void __init pxa27x_init_irq(void)
230{
eric miaob9e25ac2008-03-04 14:19:58 +0800231 pxa_init_irq(34, pxa27x_set_wake);
eric miaoc95530c2007-08-29 10:22:17 +0100232}
233
Robert Jarzmikef6dbda2014-09-28 15:20:06 +0200234void __init pxa27x_dt_init_irq(void)
235{
236 if (IS_ENABLED(CONFIG_OF))
237 pxa_dt_irq_init(pxa27x_set_wake);
238}
239
Marek Vasut851982c2010-10-11 02:20:19 +0200240static struct map_desc pxa27x_io_desc[] __initdata = {
241 { /* Mem Ctl */
Arnd Bergmann97b09da2011-10-01 22:03:45 +0200242 .virtual = (unsigned long)SMEMC_VIRT,
Marek Vasutad68bb92010-11-03 16:29:35 +0100243 .pfn = __phys_to_pfn(PXA2XX_SMEMC_BASE),
Laurent Pinchart0e329862014-07-11 13:00:36 +0200244 .length = SMEMC_SIZE,
Marek Vasut851982c2010-10-11 02:20:19 +0200245 .type = MT_DEVICE
Laurent Pinchartb10f1c82014-07-11 13:00:37 +0200246 }, { /* UNCACHED_PHYS_0 */
247 .virtual = UNCACHED_PHYS_0,
248 .pfn = __phys_to_pfn(0x00000000),
249 .length = UNCACHED_PHYS_0_SIZE,
250 .type = MT_DEVICE
Marek Vasut851982c2010-10-11 02:20:19 +0200251 },
252};
253
254void __init pxa27x_map_io(void)
255{
256 pxa_map_io();
257 iotable_init(ARRAY_AND_SIZE(pxa27x_io_desc));
258 pxa27x_get_clk_frequency_khz(1);
259}
260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261/*
262 * device registration specific to PXA27x.
263 */
Mike Rapoport9ba63c42008-08-17 06:23:05 +0100264void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info)
Mike Rapoportb7a36702008-01-27 18:14:50 +0100265{
Philipp Zabelbc3a5952008-06-02 18:49:27 +0100266 local_irq_disable();
267 PCFR |= PCFR_PI2CEN;
268 local_irq_enable();
Eric Miao14758222008-11-28 15:24:12 +0800269 pxa_register_device(&pxa27x_device_i2c_power, info);
Mike Rapoportb7a36702008-01-27 18:14:50 +0100270}
271
Robert Jarzmikb95ace52012-04-22 13:37:24 +0200272static struct pxa_gpio_platform_data pxa27x_gpio_info __initdata = {
Haojian Zhuangb8f649f2013-04-09 18:12:04 +0800273 .irq_base = PXA_GPIO_TO_IRQ(0),
274 .gpio_set_wake = gpio_set_wake,
Robert Jarzmikb95ace52012-04-22 13:37:24 +0200275};
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277static struct platform_device *devices[] __initdata = {
Philipp Zabel7a857622008-06-22 23:36:39 +0100278 &pxa27x_device_udc,
Eric Miao09a53582010-06-14 00:43:00 +0800279 &pxa_device_pmu,
Eric Miaoe09d02e2007-07-17 10:45:58 +0100280 &pxa_device_i2s,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000281 &pxa_device_asoc_ssp1,
282 &pxa_device_asoc_ssp2,
283 &pxa_device_asoc_ssp3,
284 &pxa_device_asoc_platform,
Robert Jarzmik72493142008-11-13 23:50:56 +0100285 &sa1100_device_rtc,
Eric Miaoe09d02e2007-07-17 10:45:58 +0100286 &pxa_device_rtc,
eric miaod8e0db12007-12-10 17:54:36 +0800287 &pxa27x_device_ssp1,
288 &pxa27x_device_ssp2,
289 &pxa27x_device_ssp3,
eric miao75540c12008-04-13 21:44:04 +0100290 &pxa27x_device_pwm0,
291 &pxa27x_device_pwm1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292};
293
294static int __init pxa27x_init(void)
295{
Rafael J. Wysocki2eaa03b2011-04-22 22:03:11 +0200296 int ret = 0;
eric miaoc01655042008-01-28 23:00:02 +0000297
Russell Kinge176bb02007-05-15 11:16:10 +0100298 if (cpu_is_pxa27x()) {
Eric Miao04fef222008-07-29 14:26:00 +0800299
300 reset_status = RCSR;
301
Eric Miaofef1f992009-01-02 16:26:33 +0800302 if ((ret = pxa_init_dma(IRQ_DMA, 32)))
Eric Miaof53f0662007-06-22 05:40:17 +0100303 return ret;
eric miaof79299c2008-01-02 08:24:49 +0800304
Eric Miao711be5c2007-07-18 11:38:45 +0100305 pxa27x_init_pm();
eric miaof79299c2008-01-02 08:24:49 +0800306
Rafael J. Wysocki2eaa03b2011-04-22 22:03:11 +0200307 register_syscore_ops(&pxa_irq_syscore_ops);
308 register_syscore_ops(&pxa2xx_mfp_syscore_ops);
eric miaoc01655042008-01-28 23:00:02 +0000309
Robert Jarzmik24e32a52015-02-07 22:18:34 +0100310 if (!of_have_populated_dt()) {
311 pxa_register_device(&pxa27x_device_gpio,
312 &pxa27x_gpio_info);
313 ret = platform_add_devices(devices,
314 ARRAY_SIZE(devices));
315 }
Russell Kinge176bb02007-05-15 11:16:10 +0100316 }
eric miaoc01655042008-01-28 23:00:02 +0000317
Russell Kinge176bb02007-05-15 11:16:10 +0100318 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
Russell King1c104e02008-04-19 10:59:24 +0100321postcore_initcall(pxa27x_init);