diff options
Diffstat (limited to 'arch/arm/mach-pxa/pxa27x.c')
| -rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 400 |
1 files changed, 229 insertions, 171 deletions
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 46a951c3e5a..301471a07a1 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -11,27 +11,68 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/gpio.h> +#include <linux/gpio-pxa.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/suspend.h> #include <linux/platform_device.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/i2c/pxa-i2c.h> -#include <asm/hardware.h> +#include <asm/mach/map.h> +#include <mach/hardware.h> #include <asm/irq.h> -#include <asm/arch/irqs.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/pxa2xx-regs.h> -#include <asm/arch/ohci.h> -#include <asm/arch/pm.h> -#include <asm/arch/dma.h> -#include <asm/arch/i2c.h> +#include <asm/suspend.h> +#include <mach/irqs.h> +#include <mach/pxa27x.h> +#include <mach/reset.h> +#include <linux/platform_data/usb-ohci-pxa27x.h> +#include <mach/pm.h> +#include <mach/dma.h> +#include <mach/smemc.h> #include "generic.h" #include "devices.h" #include "clock.h" +void pxa27x_clear_otgph(void) +{ + if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH)) + PSSR |= PSSR_OTGPH; +} +EXPORT_SYMBOL(pxa27x_clear_otgph); + +static unsigned long ac97_reset_config[] = { + GPIO113_AC97_nRESET_GPIO_HIGH, + GPIO113_AC97_nRESET, + GPIO95_AC97_nRESET_GPIO_HIGH, + GPIO95_AC97_nRESET, +}; + +void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio) +{ + /* + * This helper function is used to work around a bug in the pxa27x's + * ac97 controller during a warm reset. The configuration of the + * reset_gpio is changed as follows: + * to_gpio == true: configured to generic output gpio and driven high + * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET + */ + + if (reset_gpio == 113) + pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] : + &ac97_reset_config[1], 1); + + if (reset_gpio == 95) + pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] : + &ac97_reset_config[3], 1); +} +EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset); + /* Crystal clock: 13MHz */ #define BASE_CLK 13000000 @@ -80,10 +121,9 @@ unsigned int pxa27x_get_clk_frequency_khz(int info) } /* - * Return the current mem clock frequency in units of 10kHz as - * reflected by CCCR[A], B, and L + * Return the current mem clock frequency as reflected by CCCR[A], B, and L */ -unsigned int pxa27x_get_memclk_frequency_10khz(void) +static unsigned long clk_pxa27x_mem_getrate(struct clk *clk) { unsigned long ccsr, clkcfg; unsigned int l, L, m, M; @@ -102,9 +142,15 @@ unsigned int pxa27x_get_memclk_frequency_10khz(void) L = l * BASE_CLK; M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2)); - return (M / 10000); + return M; } +static const struct clkops clk_pxa27x_mem_ops = { + .enable = clk_dummy_enable, + .disable = clk_dummy_disable, + .getrate = clk_pxa27x_mem_getrate, +}; + /* * Return the current LCD clock frequency in units of 10kHz as */ @@ -130,41 +176,69 @@ static unsigned long clk_pxa27x_lcd_getrate(struct clk *clk) } static const struct clkops clk_pxa27x_lcd_ops = { - .enable = clk_cken_enable, - .disable = clk_cken_disable, + .enable = clk_pxa2xx_cken_enable, + .disable = clk_pxa2xx_cken_disable, .getrate = clk_pxa27x_lcd_getrate, }; -static struct clk pxa27x_clks[] = { - INIT_CK("LCDCLK", LCD, &clk_pxa27x_lcd_ops, &pxa_device_fb.dev), - INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_ops, NULL), - - INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev), - INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev), - INIT_CKEN("UARTCLK", STUART, 14857000, 1, NULL), - - INIT_CKEN("I2SCLK", I2S, 14682000, 0, &pxa_device_i2s.dev), - INIT_CKEN("I2CCLK", I2C, 32842000, 0, &pxa_device_i2c.dev), - INIT_CKEN("UDCCLK", USB, 48000000, 5, &pxa_device_udc.dev), - INIT_CKEN("MMCCLK", MMC, 19500000, 0, &pxa_device_mci.dev), - INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev), - - INIT_CKEN("USBCLK", USBHOST, 48000000, 0, &pxa27x_device_ohci.dev), - INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev), - INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL), - - INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev), - INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev), - INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev), - - /* - INIT_CKEN("PWMCLK", PWM0, 13000000, 0, NULL), - INIT_CKEN("MSLCLK", MSL, 48000000, 0, NULL), - INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL), - INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL), - INIT_CKEN("IMCLK", IM, 0, 0, NULL), - INIT_CKEN("MEMCLK", MEMC, 0, 0, NULL), - */ +static DEFINE_PXA2_CKEN(pxa27x_ffuart, FFUART, 14857000, 1); +static DEFINE_PXA2_CKEN(pxa27x_btuart, BTUART, 14857000, 1); +static DEFINE_PXA2_CKEN(pxa27x_stuart, STUART, 14857000, 1); +static DEFINE_PXA2_CKEN(pxa27x_i2s, I2S, 14682000, 0); +static DEFINE_PXA2_CKEN(pxa27x_i2c, I2C, 32842000, 0); +static DEFINE_PXA2_CKEN(pxa27x_usb, USB, 48000000, 5); +static DEFINE_PXA2_CKEN(pxa27x_mmc, MMC, 19500000, 0); +static DEFINE_PXA2_CKEN(pxa27x_ficp, FICP, 48000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_usbhost, USBHOST, 48000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_pwri2c, PWRI2C, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_keypad, KEYPAD, 32768, 0); +static DEFINE_PXA2_CKEN(pxa27x_ssp1, SSP1, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_ssp2, SSP2, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_ssp3, SSP3, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_pwm0, PWM0, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_pwm1, PWM1, 13000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_ac97, AC97, 24576000, 0); +static DEFINE_PXA2_CKEN(pxa27x_ac97conf, AC97CONF, 24576000, 0); +static DEFINE_PXA2_CKEN(pxa27x_msl, MSL, 48000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_usim, USIM, 48000000, 0); +static DEFINE_PXA2_CKEN(pxa27x_memstk, MEMSTK, 19500000, 0); +static DEFINE_PXA2_CKEN(pxa27x_im, IM, 0, 0); +static DEFINE_PXA2_CKEN(pxa27x_memc, MEMC, 0, 0); + +static DEFINE_CK(pxa27x_lcd, LCD, &clk_pxa27x_lcd_ops); +static DEFINE_CK(pxa27x_camera, CAMERA, &clk_pxa27x_lcd_ops); +static DEFINE_CLK(pxa27x_mem, &clk_pxa27x_mem_ops, 0, 0); + +static struct clk_lookup pxa27x_clkregs[] = { + INIT_CLKREG(&clk_pxa27x_lcd, "pxa2xx-fb", NULL), + INIT_CLKREG(&clk_pxa27x_camera, "pxa27x-camera.0", NULL), + INIT_CLKREG(&clk_pxa27x_ffuart, "pxa2xx-uart.0", NULL), + INIT_CLKREG(&clk_pxa27x_btuart, "pxa2xx-uart.1", NULL), + INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-uart.2", NULL), + INIT_CLKREG(&clk_pxa27x_i2s, "pxa2xx-i2s", NULL), + INIT_CLKREG(&clk_pxa27x_i2c, "pxa2xx-i2c.0", NULL), + INIT_CLKREG(&clk_pxa27x_usb, "pxa27x-udc", NULL), + INIT_CLKREG(&clk_pxa27x_mmc, "pxa2xx-mci.0", NULL), + INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-ir", "UARTCLK"), + INIT_CLKREG(&clk_pxa27x_ficp, "pxa2xx-ir", "FICPCLK"), + INIT_CLKREG(&clk_pxa27x_usbhost, "pxa27x-ohci", NULL), + INIT_CLKREG(&clk_pxa27x_pwri2c, "pxa2xx-i2c.1", NULL), + INIT_CLKREG(&clk_pxa27x_keypad, "pxa27x-keypad", NULL), + INIT_CLKREG(&clk_pxa27x_ssp1, "pxa27x-ssp.0", NULL), + INIT_CLKREG(&clk_pxa27x_ssp2, "pxa27x-ssp.1", NULL), + INIT_CLKREG(&clk_pxa27x_ssp3, "pxa27x-ssp.2", NULL), + INIT_CLKREG(&clk_pxa27x_pwm0, "pxa27x-pwm.0", NULL), + INIT_CLKREG(&clk_pxa27x_pwm1, "pxa27x-pwm.1", NULL), + INIT_CLKREG(&clk_pxa27x_ac97, NULL, "AC97CLK"), + INIT_CLKREG(&clk_pxa27x_ac97conf, NULL, "AC97CONFCLK"), + INIT_CLKREG(&clk_pxa27x_msl, NULL, "MSLCLK"), + INIT_CLKREG(&clk_pxa27x_usim, NULL, "USIMCLK"), + INIT_CLKREG(&clk_pxa27x_memstk, NULL, "MSTKCLK"), + INIT_CLKREG(&clk_pxa27x_im, NULL, "IMCLK"), + INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"), + INIT_CLKREG(&clk_pxa27x_mem, "pxa2xx-pcmcia", NULL), + INIT_CLKREG(&clk_dummy, "pxa27x-gpio", NULL), + INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL), }; #ifdef CONFIG_PM @@ -173,73 +247,60 @@ static struct clk pxa27x_clks[] = { #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] /* - * List of global PXA peripheral registers to preserve. - * More ones like CP and general purpose register values are preserved - * with the stack pointer in sleep.S. + * allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM */ -enum { SLEEP_SAVE_START = 0, +static unsigned int pwrmode = PWRMODE_SLEEP; - SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, +int __init pxa27x_set_pwrmode(unsigned int mode) +{ + switch (mode) { + case PWRMODE_SLEEP: + case PWRMODE_DEEPSLEEP: + pwrmode = mode; + return 0; + } - SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, - SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, - SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, - SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, + return -EINVAL; +} +/* + * List of global PXA peripheral registers to preserve. + * More ones like CP and general purpose register values are preserved + * with the stack pointer in sleep.S. + */ +enum { SLEEP_SAVE_PSTR, - - SLEEP_SAVE_CKEN, - SLEEP_SAVE_MDREFR, - SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, - SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, - - SLEEP_SAVE_SIZE + SLEEP_SAVE_PCFR, + SLEEP_SAVE_COUNT }; void pxa27x_cpu_pm_save(unsigned long *sleep_save) { - SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3); - - SAVE(GAFR0_L); SAVE(GAFR0_U); - SAVE(GAFR1_L); SAVE(GAFR1_U); - SAVE(GAFR2_L); SAVE(GAFR2_U); - SAVE(GAFR3_L); SAVE(GAFR3_U); + sleep_save[SLEEP_SAVE_MDREFR] = __raw_readl(MDREFR); + SAVE(PCFR); - SAVE(MDREFR); - SAVE(PWER); SAVE(PCFR); SAVE(PRER); - SAVE(PFER); SAVE(PKWR); - - SAVE(CKEN); SAVE(PSTR); } void pxa27x_cpu_pm_restore(unsigned long *sleep_save) { - /* ensure not to come back here if it wasn't intended */ - PSPR = 0; - - /* restore registers */ - RESTORE(GAFR0_L); RESTORE(GAFR0_U); - RESTORE(GAFR1_L); RESTORE(GAFR1_U); - RESTORE(GAFR2_L); RESTORE(GAFR2_U); - RESTORE(GAFR3_L); RESTORE(GAFR3_U); - RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3); - - RESTORE(MDREFR); - RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); - RESTORE(PFER); RESTORE(PKWR); + __raw_writel(sleep_save[SLEEP_SAVE_MDREFR], MDREFR); + RESTORE(PCFR); PSSR = PSSR_RDH | PSSR_PH; - RESTORE(CKEN); - RESTORE(PSTR); } void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); +#ifndef CONFIG_IWMMXT + u64 acc0; + + asm volatile("mra %Q0, %R0, acc0" : "=r" (acc0)); +#endif /* ensure voltage-change sequencer not initiated, which hangs */ PCFR &= ~PCFR_FVC; @@ -247,14 +308,18 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) /* Clear edge-detect status register. */ PEDR = 0xDF12FE1B; + /* Clear reset status */ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; + switch (state) { case PM_SUSPEND_STANDBY: pxa_cpu_standby(); break; case PM_SUSPEND_MEM: - /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); - pxa27x_cpu_suspend(PWRMODE_SLEEP); + cpu_suspend(pwrmode, pxa27x_finish_suspend); +#ifndef CONFIG_IWMMXT + asm volatile("mar acc0, %Q0, %R0" : "=r" (acc0)); +#endif break; } } @@ -264,12 +329,27 @@ static int pxa27x_cpu_pm_valid(suspend_state_t state) return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; } +static int pxa27x_cpu_pm_prepare(void) +{ + /* set resume return address */ + PSPR = virt_to_phys(cpu_resume); + return 0; +} + +static void pxa27x_cpu_pm_finish(void) +{ + /* ensure not to come back here if it wasn't intended */ + PSPR = 0; +} + static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = { - .save_size = SLEEP_SAVE_SIZE, + .save_count = SLEEP_SAVE_COUNT, .save = pxa27x_cpu_pm_save, .restore = pxa27x_cpu_pm_restore, .valid = pxa27x_cpu_pm_valid, .enter = pxa27x_cpu_pm_enter, + .prepare = pxa27x_cpu_pm_prepare, + .finish = pxa27x_cpu_pm_finish, }; static void __init pxa27x_init_pm(void) @@ -283,39 +363,18 @@ static inline void pxa27x_init_pm(void) {} /* PXA27x: Various gpios can issue wakeup events. This logic only * handles the simple cases, not the WEMUX2 and WEMUX3 options */ -#define PXA27x_GPIO_NOWAKE_MASK \ - ((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)) -#define WAKEMASK(gpio) \ - (((gpio) <= 15) \ - ? ((1 << (gpio)) & ~PXA27x_GPIO_NOWAKE_MASK) \ - : ((gpio == 35) ? (1 << 24) : 0)) - -static int pxa27x_set_wake(unsigned int irq, unsigned int on) +static int pxa27x_set_wake(struct irq_data *d, unsigned int on) { - int gpio = IRQ_TO_GPIO(irq); + int gpio = pxa_irq_to_gpio(d->irq); uint32_t mask; - if ((gpio >= 0 && gpio <= 15) || (gpio == 35)) { - if (WAKEMASK(gpio) == 0) - return -EINVAL; - - mask = WAKEMASK(gpio); + if (gpio >= 0 && gpio < 128) + return gpio_set_wake(gpio, on); - if (on) { - if (GRER(gpio) | GPIO_bit(gpio)) - PRER |= mask; - else - PRER &= ~mask; - - if (GFER(gpio) | GPIO_bit(gpio)) - PFER |= mask; - else - PFER &= ~mask; - } - goto set_pwer; - } + if (d->irq == IRQ_KEYPAD) + return keypad_set_wake(on); - switch (irq) { + switch (d->irq) { case IRQ_RTCAlrm: mask = PWER_RTC; break; @@ -326,7 +385,6 @@ static int pxa27x_set_wake(unsigned int irq, unsigned int on) return -EINVAL; } -set_pwer: if (on) PWER |= mask; else @@ -337,87 +395,87 @@ set_pwer: void __init pxa27x_init_irq(void) { - pxa_init_irq_low(); - pxa_init_irq_high(); - pxa_init_irq_gpio(128); - pxa_init_irq_set_wake(pxa27x_set_wake); + pxa_init_irq(34, pxa27x_set_wake); } -/* - * device registration specific to PXA27x. - */ - -static struct resource i2c_power_resources[] = { - { - .start = 0x40f00180, - .end = 0x40f001a3, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_PWRI2C, - .end = IRQ_PWRI2C, - .flags = IORESOURCE_IRQ, +static struct map_desc pxa27x_io_desc[] __initdata = { + { /* Mem Ctl */ + .virtual = (unsigned long)SMEMC_VIRT, + .pfn = __phys_to_pfn(PXA2XX_SMEMC_BASE), + .length = 0x00200000, + .type = MT_DEVICE + }, { /* IMem ctl */ + .virtual = 0xfe000000, + .pfn = __phys_to_pfn(0x58000000), + .length = 0x00100000, + .type = MT_DEVICE }, }; -struct platform_device pxa27x_device_i2c_power = { - .name = "pxa2xx-i2c", - .id = 1, - .resource = i2c_power_resources, - .num_resources = ARRAY_SIZE(i2c_power_resources), -}; +void __init pxa27x_map_io(void) +{ + pxa_map_io(); + iotable_init(ARRAY_AND_SIZE(pxa27x_io_desc)); + pxa27x_get_clk_frequency_khz(1); +} -void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info) +/* + * device registration specific to PXA27x. + */ +void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info) { - pxa27x_device_i2c_power.dev.platform_data = info; + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); + pxa_register_device(&pxa27x_device_i2c_power, info); } +static struct pxa_gpio_platform_data pxa27x_gpio_info __initdata = { + .irq_base = PXA_GPIO_TO_IRQ(0), + .gpio_set_wake = gpio_set_wake, +}; + static struct platform_device *devices[] __initdata = { - &pxa_device_udc, - &pxa_device_ffuart, - &pxa_device_btuart, - &pxa_device_stuart, + &pxa27x_device_udc, + &pxa_device_pmu, &pxa_device_i2s, + &pxa_device_asoc_ssp1, + &pxa_device_asoc_ssp2, + &pxa_device_asoc_ssp3, + &pxa_device_asoc_platform, + &sa1100_device_rtc, &pxa_device_rtc, - &pxa27x_device_i2c_power, &pxa27x_device_ssp1, &pxa27x_device_ssp2, &pxa27x_device_ssp3, -}; - -static struct sys_device pxa27x_sysdev[] = { - { - .id = 0, - .cls = &pxa_irq_sysclass, - }, { - .id = 1, - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, + &pxa27x_device_pwm0, + &pxa27x_device_pwm1, }; static int __init pxa27x_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa27x()) { - clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks)); - if ((ret = pxa_init_dma(32))) + reset_status = RCSR; + + clkdev_add_table(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs)); + + if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; pxa27x_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) { - ret = sysdev_register(&pxa27x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); + pxa_register_device(&pxa27x_device_gpio, &pxa27x_gpio_info); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } return ret; } -subsys_initcall(pxa27x_init); +postcore_initcall(pxa27x_init); |
