diff options
Diffstat (limited to 'arch/arm/mach-pxa/pxa25x.c')
| -rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 334 |
1 files changed, 242 insertions, 92 deletions
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 6dfcca72e90..f2c28972084 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -16,20 +16,29 @@ * initialization stuff for PXA machines which can be overridden later if * need be. */ +#include <linux/gpio.h> +#include <linux/gpio-pxa.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> -#include <linux/pm.h> - -#include <asm/hardware.h> -#include <asm/arch/irqs.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/pm.h> -#include <asm/arch/dma.h> +#include <linux/suspend.h> +#include <linux/syscore_ops.h> +#include <linux/irq.h> + +#include <asm/mach/map.h> +#include <asm/suspend.h> +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/pxa25x.h> +#include <mach/reset.h> +#include <mach/pm.h> +#include <mach/dma.h> +#include <mach/smemc.h> #include "generic.h" #include "devices.h" +#include "clock.h" /* * Various clock factors driven by the CCCR register. @@ -53,7 +62,7 @@ static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; * We assume these values have been applied via a fcs. * If info is not 0 we also display the current settings. */ -unsigned int get_clk_frequency_khz(int info) +unsigned int pxa25x_get_clk_frequency_khz(int info) { unsigned long cccr, turbo; unsigned int l, L, m, M, n2, N; @@ -86,162 +95,303 @@ unsigned int get_clk_frequency_khz(int info) return (turbo & 1) ? (N/1000) : (M/1000); } -EXPORT_SYMBOL(get_clk_frequency_khz); +static unsigned long clk_pxa25x_mem_getrate(struct clk *clk) +{ + return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK; +} -/* - * Return the current memory clock frequency in units of 10kHz - */ -unsigned int get_memclk_frequency_10khz(void) +static const struct clkops clk_pxa25x_mem_ops = { + .enable = clk_dummy_enable, + .disable = clk_dummy_disable, + .getrate = clk_pxa25x_mem_getrate, +}; + +static const struct clkops clk_pxa25x_lcd_ops = { + .enable = clk_pxa2xx_cken_enable, + .disable = clk_pxa2xx_cken_disable, + .getrate = clk_pxa25x_mem_getrate, +}; + +static unsigned long gpio12_config_32k[] = { + GPIO12_32KHz, +}; + +static unsigned long gpio12_config_gpio[] = { + GPIO12_GPIO, +}; + +static void clk_gpio12_enable(struct clk *clk) { - return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; + pxa2xx_mfp_config(gpio12_config_32k, 1); } -EXPORT_SYMBOL(get_memclk_frequency_10khz); +static void clk_gpio12_disable(struct clk *clk) +{ + pxa2xx_mfp_config(gpio12_config_gpio, 1); +} -/* - * Return the current LCD clock frequency in units of 10kHz - */ -unsigned int get_lcdclk_frequency_10khz(void) +static const struct clkops clk_pxa25x_gpio12_ops = { + .enable = clk_gpio12_enable, + .disable = clk_gpio12_disable, +}; + +static unsigned long gpio11_config_3m6[] = { + GPIO11_3_6MHz, +}; + +static unsigned long gpio11_config_gpio[] = { + GPIO11_GPIO, +}; + +static void clk_gpio11_enable(struct clk *clk) +{ + pxa2xx_mfp_config(gpio11_config_3m6, 1); +} + +static void clk_gpio11_disable(struct clk *clk) { - return get_memclk_frequency_10khz(); + pxa2xx_mfp_config(gpio11_config_gpio, 1); } -EXPORT_SYMBOL(get_lcdclk_frequency_10khz); +static const struct clkops clk_pxa25x_gpio11_ops = { + .enable = clk_gpio11_enable, + .disable = clk_gpio11_disable, +}; + +/* + * 3.6864MHz -> OST, GPIO, SSP, PWM, PLLs (95.842MHz, 147.456MHz) + * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz + * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly) + */ + +/* + * PXA 2xx clock declarations. + */ +static DEFINE_PXA2_CKEN(pxa25x_hwuart, HWUART, 14745600, 1); +static DEFINE_PXA2_CKEN(pxa25x_ffuart, FFUART, 14745600, 1); +static DEFINE_PXA2_CKEN(pxa25x_btuart, BTUART, 14745600, 1); +static DEFINE_PXA2_CKEN(pxa25x_stuart, STUART, 14745600, 1); +static DEFINE_PXA2_CKEN(pxa25x_usb, USB, 47923000, 5); +static DEFINE_PXA2_CKEN(pxa25x_mmc, MMC, 19169000, 0); +static DEFINE_PXA2_CKEN(pxa25x_i2c, I2C, 31949000, 0); +static DEFINE_PXA2_CKEN(pxa25x_ssp, SSP, 3686400, 0); +static DEFINE_PXA2_CKEN(pxa25x_nssp, NSSP, 3686400, 0); +static DEFINE_PXA2_CKEN(pxa25x_assp, ASSP, 3686400, 0); +static DEFINE_PXA2_CKEN(pxa25x_pwm0, PWM0, 3686400, 0); +static DEFINE_PXA2_CKEN(pxa25x_pwm1, PWM1, 3686400, 0); +static DEFINE_PXA2_CKEN(pxa25x_ac97, AC97, 24576000, 0); +static DEFINE_PXA2_CKEN(pxa25x_i2s, I2S, 14745600, 0); +static DEFINE_PXA2_CKEN(pxa25x_ficp, FICP, 47923000, 0); + +static DEFINE_CK(pxa25x_lcd, LCD, &clk_pxa25x_lcd_ops); +static DEFINE_CLK(pxa25x_gpio11, &clk_pxa25x_gpio11_ops, 3686400, 0); +static DEFINE_CLK(pxa25x_gpio12, &clk_pxa25x_gpio12_ops, 32768, 0); +static DEFINE_CLK(pxa25x_mem, &clk_pxa25x_mem_ops, 0, 0); + +static struct clk_lookup pxa25x_clkregs[] = { + INIT_CLKREG(&clk_pxa25x_lcd, "pxa2xx-fb", NULL), + INIT_CLKREG(&clk_pxa25x_ffuart, "pxa2xx-uart.0", NULL), + INIT_CLKREG(&clk_pxa25x_btuart, "pxa2xx-uart.1", NULL), + INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-uart.2", NULL), + INIT_CLKREG(&clk_pxa25x_usb, "pxa25x-udc", NULL), + INIT_CLKREG(&clk_pxa25x_mmc, "pxa2xx-mci.0", NULL), + INIT_CLKREG(&clk_pxa25x_i2c, "pxa2xx-i2c.0", NULL), + INIT_CLKREG(&clk_pxa25x_ssp, "pxa25x-ssp.0", NULL), + INIT_CLKREG(&clk_pxa25x_nssp, "pxa25x-nssp.1", NULL), + INIT_CLKREG(&clk_pxa25x_assp, "pxa25x-nssp.2", NULL), + INIT_CLKREG(&clk_pxa25x_pwm0, "pxa25x-pwm.0", NULL), + INIT_CLKREG(&clk_pxa25x_pwm1, "pxa25x-pwm.1", NULL), + INIT_CLKREG(&clk_pxa25x_i2s, "pxa2xx-i2s", NULL), + INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-ir", "UARTCLK"), + INIT_CLKREG(&clk_pxa25x_ficp, "pxa2xx-ir", "FICPCLK"), + INIT_CLKREG(&clk_pxa25x_ac97, NULL, "AC97CLK"), + INIT_CLKREG(&clk_pxa25x_gpio11, NULL, "GPIO11_CLK"), + INIT_CLKREG(&clk_pxa25x_gpio12, NULL, "GPIO12_CLK"), + INIT_CLKREG(&clk_pxa25x_mem, "pxa2xx-pcmcia", NULL), +#ifdef CONFIG_CPU_PXA26x + INIT_CLKREG(&clk_dummy, "pxa26x-gpio", NULL), +#else + INIT_CLKREG(&clk_dummy, "pxa25x-gpio", NULL), +#endif + INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL), +}; + +static struct clk_lookup pxa25x_hwuart_clkreg = + INIT_CLKREG(&clk_pxa25x_hwuart, "pxa2xx-uart.3", NULL); #ifdef CONFIG_PM #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] -#define RESTORE_GPLEVEL(n) do { \ - GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ - GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ -} while (0) - /* * 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_START = 0, - - SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, - SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, - SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, - SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, - SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, - - SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, - SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, - SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, - +enum { SLEEP_SAVE_PSTR, - - SLEEP_SAVE_ICMR, - SLEEP_SAVE_CKEN, - - SLEEP_SAVE_SIZE + SLEEP_SAVE_COUNT }; static void pxa25x_cpu_pm_save(unsigned long *sleep_save) { - SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); - SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); - SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); - SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); - SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); - - SAVE(GAFR0_L); SAVE(GAFR0_U); - SAVE(GAFR1_L); SAVE(GAFR1_U); - SAVE(GAFR2_L); SAVE(GAFR2_U); - - SAVE(ICMR); - SAVE(CKEN); SAVE(PSTR); } static void pxa25x_cpu_pm_restore(unsigned long *sleep_save) { - /* restore registers */ - RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); - RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); - RESTORE(GAFR0_L); RESTORE(GAFR0_U); - RESTORE(GAFR1_L); RESTORE(GAFR1_U); - RESTORE(GAFR2_L); RESTORE(GAFR2_U); - RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); - RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); - RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); - - RESTORE(CKEN); - RESTORE(ICMR); RESTORE(PSTR); } static void pxa25x_cpu_pm_enter(suspend_state_t state) { - CKEN = 0; + /* Clear reset status */ + RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR; switch (state) { case PM_SUSPEND_MEM: - /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); - pxa25x_cpu_suspend(PWRMODE_SLEEP); + cpu_suspend(PWRMODE_SLEEP, pxa25x_finish_suspend); break; } } +static int pxa25x_cpu_pm_prepare(void) +{ + /* set resume return address */ + PSPR = virt_to_phys(cpu_resume); + return 0; +} + +static void pxa25x_cpu_pm_finish(void) +{ + /* ensure not to come back here if it wasn't intended */ + PSPR = 0; +} + static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = { - .save_size = SLEEP_SAVE_SIZE, - .valid = pm_valid_only_mem, + .save_count = SLEEP_SAVE_COUNT, + .valid = suspend_valid_only_mem, .save = pxa25x_cpu_pm_save, .restore = pxa25x_cpu_pm_restore, .enter = pxa25x_cpu_pm_enter, + .prepare = pxa25x_cpu_pm_prepare, + .finish = pxa25x_cpu_pm_finish, }; static void __init pxa25x_init_pm(void) { pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns; } +#else +static inline void pxa25x_init_pm(void) {} #endif +/* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm + */ + +static int pxa25x_set_wake(struct irq_data *d, unsigned int on) +{ + int gpio = pxa_irq_to_gpio(d->irq); + uint32_t mask = 0; + + if (gpio >= 0 && gpio < 85) + return gpio_set_wake(gpio, on); + + if (d->irq == IRQ_RTCAlrm) { + mask = PWER_RTC; + goto set_pwer; + } + + return -EINVAL; + +set_pwer: + if (on) + PWER |= mask; + else + PWER &=~mask; + + return 0; +} + void __init pxa25x_init_irq(void) { - pxa_init_irq_low(); - pxa_init_irq_gpio(85); + pxa_init_irq(32, pxa25x_set_wake); } +#ifdef CONFIG_CPU_PXA26x +void __init pxa26x_init_irq(void) +{ + pxa_init_irq(32, pxa25x_set_wake); +} +#endif + +static struct map_desc pxa25x_io_desc[] __initdata = { + { /* Mem Ctl */ + .virtual = (unsigned long)SMEMC_VIRT, + .pfn = __phys_to_pfn(PXA2XX_SMEMC_BASE), + .length = 0x00200000, + .type = MT_DEVICE + }, +}; + +void __init pxa25x_map_io(void) +{ + pxa_map_io(); + iotable_init(ARRAY_AND_SIZE(pxa25x_io_desc)); + pxa25x_get_clk_frequency_khz(1); +} + +static struct pxa_gpio_platform_data pxa25x_gpio_info __initdata = { + .irq_base = PXA_GPIO_TO_IRQ(0), + .gpio_set_wake = gpio_set_wake, +}; + static struct platform_device *pxa25x_devices[] __initdata = { - &pxa_device_mci, - &pxa_device_udc, - &pxa_device_fb, - &pxa_device_ffuart, - &pxa_device_btuart, - &pxa_device_stuart, - &pxa_device_i2c, + &pxa25x_device_udc, + &pxa_device_pmu, &pxa_device_i2s, - &pxa_device_ficp, - &pxa_device_rtc, + &sa1100_device_rtc, + &pxa25x_device_ssp, + &pxa25x_device_nssp, + &pxa25x_device_assp, + &pxa25x_device_pwm0, + &pxa25x_device_pwm1, + &pxa_device_asoc_platform, }; static int __init pxa25x_init(void) { int ret = 0; - if (cpu_is_pxa21x() || cpu_is_pxa25x()) { - if ((ret = pxa_init_dma(16))) + if (cpu_is_pxa25x()) { + + reset_status = RCSR; + + clkdev_add_table(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs)); + + if ((ret = pxa_init_dma(IRQ_DMA, 16))) return ret; -#ifdef CONFIG_PM + pxa25x_init_pm(); -#endif + + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); + + pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info); ret = platform_add_devices(pxa25x_devices, ARRAY_SIZE(pxa25x_devices)); + if (ret) + return ret; } - /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ - if (cpu_is_pxa25x()) - ret = platform_device_register(&pxa_device_hwuart); + + /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */ + if (cpu_is_pxa255()) + clkdev_add(&pxa25x_hwuart_clkreg); return ret; } -subsys_initcall(pxa25x_init); +postcore_initcall(pxa25x_init); |
