2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / mach - pxa / pxa27x . c
*
* Author : Nicolas Pitre
* Created : Nov 05 , 2002
* Copyright : MontaVista Software Inc .
*
* Code specific to PXA27x aka Bulverde .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2011-07-26 10:53:52 +01:00
# include <linux/gpio.h>
2011-10-17 20:37:52 +08:00
# include <linux/gpio-pxa.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
2016-08-15 00:24:55 +02:00
# include <linux/irqchip.h>
2007-10-18 03:04:39 -07:00
# include <linux/suspend.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2011-04-22 22:03:11 +02:00
# include <linux/syscore_ops.h>
2010-11-03 16:29:35 +01:00
# include <linux/io.h>
2010-11-29 11:18:26 +01:00
# include <linux/irq.h>
2011-02-23 12:38:16 +01:00
# include <linux/i2c/pxa-i2c.h>
2005-04-16 15:20:36 -07:00
2010-10-11 02:20:19 +02:00
# include <asm/mach/map.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-04-16 15:20:36 -07:00
# include <asm/irq.h>
2011-06-22 17:41:48 +01:00
# include <asm/suspend.h>
2008-08-05 16:14:15 +01:00
# include <mach/irqs.h>
2015-01-30 10:45:33 +01:00
# include "pxa27x.h"
2008-08-07 11:05:25 +01:00
# include <mach/reset.h>
2012-08-24 15:16:48 +02:00
# include <linux/platform_data/usb-ohci-pxa27x.h>
2015-01-30 10:45:33 +01:00
# include "pm.h"
2008-08-05 16:14:15 +01:00
# include <mach/dma.h>
2010-11-03 16:29:35 +01:00
# include <mach/smemc.h>
2005-04-16 15:20:36 -07:00
# include "generic.h"
2007-05-15 15:39:36 +01:00
# include "devices.h"
2014-12-27 14:55:26 +01:00
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
2005-04-16 15:20:36 -07:00
2008-10-04 12:45:39 +08:00
void pxa27x_clear_otgph ( void )
{
if ( cpu_is_pxa27x ( ) & & ( PSSR & PSSR_OTGPH ) )
PSSR | = PSSR_OTGPH ;
}
EXPORT_SYMBOL ( pxa27x_clear_otgph ) ;
2010-01-04 16:30:58 +08:00
static unsigned long ac97_reset_config [ ] = {
2013-01-07 13:55:13 -08:00
GPIO113_AC97_nRESET_GPIO_HIGH ,
2010-07-13 09:41:28 +08:00
GPIO113_AC97_nRESET ,
2013-01-07 13:55:13 -08:00
GPIO95_AC97_nRESET_GPIO_HIGH ,
2010-07-13 09:41:28 +08:00
GPIO95_AC97_nRESET ,
2010-01-04 16:30:58 +08:00
} ;
2013-01-07 13:55:14 -08:00
void pxa27x_configure_ac97reset ( int reset_gpio , bool to_gpio )
2010-01-04 16:30:58 +08:00
{
2013-01-07 13:55:14 -08:00
/*
* 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
*/
2010-01-04 16:30:58 +08:00
if ( reset_gpio = = 113 )
2013-01-07 13:55:14 -08:00
pxa2xx_mfp_config ( to_gpio ? & ac97_reset_config [ 0 ] :
& ac97_reset_config [ 1 ] , 1 ) ;
2010-01-04 16:30:58 +08:00
if ( reset_gpio = = 95 )
2013-01-07 13:55:14 -08:00
pxa2xx_mfp_config ( to_gpio ? & ac97_reset_config [ 2 ] :
& ac97_reset_config [ 3 ] , 1 ) ;
2010-01-04 16:30:58 +08:00
}
2013-01-07 13:55:14 -08:00
EXPORT_SYMBOL_GPL ( pxa27x_configure_ac97reset ) ;
2010-01-04 16:30:58 +08:00
2005-06-13 22:35:41 +01:00
# ifdef CONFIG_PM
2007-07-18 11:38:45 +01:00
# define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
# define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
2009-05-26 09:10:18 +03:00
/*
* allow platforms to override default PWRMODE setting used for PM_SUSPEND_MEM
*/
static unsigned int pwrmode = PWRMODE_SLEEP ;
2015-10-12 15:46:08 +02:00
int pxa27x_set_pwrmode ( unsigned int mode )
2009-05-26 09:10:18 +03:00
{
switch ( mode ) {
case PWRMODE_SLEEP :
case PWRMODE_DEEPSLEEP :
pwrmode = mode ;
return 0 ;
}
return - EINVAL ;
}
2007-07-18 11:38:45 +01:00
/*
* 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 .
*/
2008-09-03 18:06:34 +08:00
enum {
2007-07-18 11:38:45 +01:00
SLEEP_SAVE_PSTR ,
SLEEP_SAVE_MDREFR ,
2008-09-03 18:06:34 +08:00
SLEEP_SAVE_PCFR ,
2008-05-02 21:17:06 +01:00
SLEEP_SAVE_COUNT
2007-07-18 11:38:45 +01:00
} ;
void pxa27x_cpu_pm_save ( unsigned long * sleep_save )
{
2010-11-03 16:29:35 +01:00
sleep_save [ SLEEP_SAVE_MDREFR ] = __raw_readl ( MDREFR ) ;
2008-09-03 18:06:34 +08:00
SAVE ( PCFR ) ;
2007-07-18 11:38:45 +01:00
SAVE ( PSTR ) ;
}
void pxa27x_cpu_pm_restore ( unsigned long * sleep_save )
{
2010-11-03 16:29:35 +01:00
__raw_writel ( sleep_save [ SLEEP_SAVE_MDREFR ] , MDREFR ) ;
2008-09-03 18:06:34 +08:00
RESTORE ( PCFR ) ;
2007-07-18 11:38:45 +01:00
PSSR = PSSR_RDH | PSSR_PH ;
RESTORE ( PSTR ) ;
}
void pxa27x_cpu_pm_enter ( suspend_state_t state )
2005-06-03 20:52:27 +01:00
{
extern void pxa_cpu_standby ( void ) ;
2011-06-21 16:29:30 +01:00
# ifndef CONFIG_IWMMXT
u64 acc0 ;
ARM: pxa: fix building without IWMMXT
When CONFIG_IWMMXT, the pxa3xx and pxa27x suspend/resume code
emits some xscale specific instructions, which are rejected
by the assembler, because gcc is built with -march=armv5
-mtune=xscale and passes that option to the assembler:
/tmp/cciHumzr.s:553: Error: selected processor does not support ARM mode `mra r2,r3,acc0'
/tmp/cciHumzr.s:605: Error: selected processor does not support ARM mode `mar acc0,r2,r3'
make[3]: *** [arch/arm/mach-pxa/pxa3xx.o] Error 1
/tmp/cci5MUNu.s:326: Error: selected processor does not support ARM mode `mra r2,r3,acc0'
/tmp/cci5MUNu.s:367: Error: selected processor does not support ARM mode `mar acc0,r2,r3'
make[3]: *** [arch/arm/mach-pxa/pxa27x.o] Error 1
Overriding with -Wa,-march=xscale no longer works, so instead
I'm adding an explict ".arch_extension" directive in all four inline
assembly statements, which should work even if they end up in a different
order in the assembly output.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
2016-01-29 15:06:31 +01:00
asm volatile ( " .arch_extension xscale \n \t "
" mra %Q0, %R0, acc0 " : " =r " ( acc0 ) ) ;
2011-06-21 16:29:30 +01:00
# endif
2005-06-03 20:52:27 +01:00
/* ensure voltage-change sequencer not initiated, which hangs */
PCFR & = ~ PCFR_FVC ;
/* Clear edge-detect status register. */
PEDR = 0xDF12FE1B ;
2008-05-08 16:50:39 +01:00
/* Clear reset status */
RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR ;
2005-06-03 20:52:27 +01:00
switch ( state ) {
2005-07-01 11:27:05 +01:00
case PM_SUSPEND_STANDBY :
pxa_cpu_standby ( ) ;
break ;
2005-06-03 20:52:27 +01:00
case PM_SUSPEND_MEM :
2011-06-22 17:41:48 +01:00
cpu_suspend ( pwrmode , pxa27x_finish_suspend ) ;
2011-06-21 16:29:30 +01:00
# ifndef CONFIG_IWMMXT
ARM: pxa: fix building without IWMMXT
When CONFIG_IWMMXT, the pxa3xx and pxa27x suspend/resume code
emits some xscale specific instructions, which are rejected
by the assembler, because gcc is built with -march=armv5
-mtune=xscale and passes that option to the assembler:
/tmp/cciHumzr.s:553: Error: selected processor does not support ARM mode `mra r2,r3,acc0'
/tmp/cciHumzr.s:605: Error: selected processor does not support ARM mode `mar acc0,r2,r3'
make[3]: *** [arch/arm/mach-pxa/pxa3xx.o] Error 1
/tmp/cci5MUNu.s:326: Error: selected processor does not support ARM mode `mra r2,r3,acc0'
/tmp/cci5MUNu.s:367: Error: selected processor does not support ARM mode `mar acc0,r2,r3'
make[3]: *** [arch/arm/mach-pxa/pxa27x.o] Error 1
Overriding with -Wa,-march=xscale no longer works, so instead
I'm adding an explict ".arch_extension" directive in all four inline
assembly statements, which should work even if they end up in a different
order in the assembly output.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
2016-01-29 15:06:31 +01:00
asm volatile ( " .arch_extension xscale \n \t "
" mar acc0, %Q0, %R0 " : " =r " ( acc0 ) ) ;
2011-06-21 16:29:30 +01:00
# endif
2005-06-03 20:52:27 +01:00
break ;
}
}
2005-04-16 15:20:36 -07:00
2007-07-18 11:38:45 +01:00
static int pxa27x_cpu_pm_valid ( suspend_state_t state )
2007-05-15 11:22:48 +01:00
{
return state = = PM_SUSPEND_MEM | | state = = PM_SUSPEND_STANDBY ;
}
2008-08-27 12:55:04 +01:00
static int pxa27x_cpu_pm_prepare ( void )
{
/* set resume return address */
2017-01-15 03:59:29 +01:00
PSPR = __pa_symbol ( cpu_resume ) ;
2008-08-27 12:55:04 +01:00
return 0 ;
}
static void pxa27x_cpu_pm_finish ( void )
{
/* ensure not to come back here if it wasn't intended */
PSPR = 0 ;
}
2007-07-18 11:38:45 +01:00
static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
2008-05-02 21:17:06 +01:00
. save_count = SLEEP_SAVE_COUNT ,
2007-07-18 11:38:45 +01:00
. save = pxa27x_cpu_pm_save ,
. restore = pxa27x_cpu_pm_restore ,
. valid = pxa27x_cpu_pm_valid ,
. enter = pxa27x_cpu_pm_enter ,
2008-08-27 12:55:04 +01:00
. prepare = pxa27x_cpu_pm_prepare ,
. finish = pxa27x_cpu_pm_finish ,
2007-05-15 11:16:10 +01:00
} ;
2007-07-18 11:38:45 +01:00
static void __init pxa27x_init_pm ( void )
{
pxa_cpu_pm_fns = & pxa27x_cpu_pm_fns ;
}
2008-01-02 08:24:49 +08:00
# else
static inline void pxa27x_init_pm ( void ) { }
2005-06-13 22:35:41 +01:00
# endif
2007-08-29 10:22:17 +01:00
/* PXA27x: Various gpios can issue wakeup events. This logic only
* handles the simple cases , not the WEMUX2 and WEMUX3 options
*/
2010-11-29 11:18:26 +01:00
static int pxa27x_set_wake ( struct irq_data * d , unsigned int on )
2007-08-29 10:22:17 +01:00
{
2011-10-10 16:03:51 +08:00
int gpio = pxa_irq_to_gpio ( d - > irq ) ;
2007-08-29 10:22:17 +01:00
uint32_t mask ;
2008-03-11 09:46:28 +08:00
if ( gpio > = 0 & & gpio < 128 )
return gpio_set_wake ( gpio , on ) ;
2007-08-29 10:22:17 +01:00
2010-11-29 11:18:26 +01:00
if ( d - > irq = = IRQ_KEYPAD )
2008-03-11 09:46:28 +08:00
return keypad_set_wake ( on ) ;
2007-08-29 10:22:17 +01:00
2010-11-29 11:18:26 +01:00
switch ( d - > irq ) {
2007-08-29 10:22:17 +01:00
case IRQ_RTCAlrm :
mask = PWER_RTC ;
break ;
case IRQ_USB :
mask = 1u < < 26 ;
break ;
default :
return - EINVAL ;
}
if ( on )
PWER | = mask ;
else
PWER & = ~ mask ;
return 0 ;
}
void __init pxa27x_init_irq ( void )
{
2008-03-04 14:19:58 +08:00
pxa_init_irq ( 34 , pxa27x_set_wake ) ;
2007-08-29 10:22:17 +01:00
}
2016-08-15 00:24:55 +02:00
static int __init
pxa27x_dt_init_irq ( struct device_node * node , struct device_node * parent )
2014-09-28 15:20:06 +02:00
{
2016-08-15 00:24:55 +02:00
pxa_dt_irq_init ( pxa27x_set_wake ) ;
set_handle_irq ( ichp_handle_irq ) ;
return 0 ;
2014-09-28 15:20:06 +02:00
}
2016-08-15 00:24:55 +02:00
IRQCHIP_DECLARE ( pxa27x_intc , " marvell,pxa-intc " , pxa27x_dt_init_irq ) ;
2014-09-28 15:20:06 +02:00
2010-10-11 02:20:19 +02:00
static struct map_desc pxa27x_io_desc [ ] __initdata = {
{ /* Mem Ctl */
2011-10-01 22:03:45 +02:00
. virtual = ( unsigned long ) SMEMC_VIRT ,
2010-11-03 16:29:35 +01:00
. pfn = __phys_to_pfn ( PXA2XX_SMEMC_BASE ) ,
2014-07-11 13:00:36 +02:00
. length = SMEMC_SIZE ,
2010-10-11 02:20:19 +02:00
. type = MT_DEVICE
2014-07-11 13:00:37 +02:00
} , { /* UNCACHED_PHYS_0 */
. virtual = UNCACHED_PHYS_0 ,
. pfn = __phys_to_pfn ( 0x00000000 ) ,
. length = UNCACHED_PHYS_0_SIZE ,
. type = MT_DEVICE
2010-10-11 02:20:19 +02:00
} ,
} ;
void __init pxa27x_map_io ( void )
{
pxa_map_io ( ) ;
iotable_init ( ARRAY_AND_SIZE ( pxa27x_io_desc ) ) ;
pxa27x_get_clk_frequency_khz ( 1 ) ;
}
2005-04-16 15:20:36 -07:00
/*
* device registration specific to PXA27x .
*/
2008-08-17 06:23:05 +01:00
void __init pxa27x_set_i2c_power_info ( struct i2c_pxa_platform_data * info )
2008-01-27 18:14:50 +01:00
{
2008-06-02 18:49:27 +01:00
local_irq_disable ( ) ;
PCFR | = PCFR_PI2CEN ;
local_irq_enable ( ) ;
2008-11-28 15:24:12 +08:00
pxa_register_device ( & pxa27x_device_i2c_power , info ) ;
2008-01-27 18:14:50 +01:00
}
2012-04-22 13:37:24 +02:00
static struct pxa_gpio_platform_data pxa27x_gpio_info __initdata = {
2013-04-09 18:12:04 +08:00
. irq_base = PXA_GPIO_TO_IRQ ( 0 ) ,
. gpio_set_wake = gpio_set_wake ,
2012-04-22 13:37:24 +02:00
} ;
2005-04-16 15:20:36 -07:00
static struct platform_device * devices [ ] __initdata = {
2008-06-22 23:36:39 +01:00
& pxa27x_device_udc ,
2010-06-14 00:43:00 +08:00
& pxa_device_pmu ,
2007-07-17 10:45:58 +01:00
& pxa_device_i2s ,
2010-03-17 20:15:21 +00:00
& pxa_device_asoc_ssp1 ,
& pxa_device_asoc_ssp2 ,
& pxa_device_asoc_ssp3 ,
& pxa_device_asoc_platform ,
2007-07-17 10:45:58 +01:00
& pxa_device_rtc ,
2007-12-10 17:54:36 +08:00
& pxa27x_device_ssp1 ,
& pxa27x_device_ssp2 ,
& pxa27x_device_ssp3 ,
2008-04-13 21:44:04 +01:00
& pxa27x_device_pwm0 ,
& pxa27x_device_pwm1 ,
2005-04-16 15:20:36 -07:00
} ;
static int __init pxa27x_init ( void )
{
2011-04-22 22:03:11 +02:00
int ret = 0 ;
2008-01-28 23:00:02 +00:00
2007-05-15 11:16:10 +01:00
if ( cpu_is_pxa27x ( ) ) {
2008-07-29 14:26:00 +08:00
reset_status = RCSR ;
2007-07-18 11:38:45 +01:00
pxa27x_init_pm ( ) ;
2008-01-02 08:24:49 +08:00
2011-04-22 22:03:11 +02:00
register_syscore_ops ( & pxa_irq_syscore_ops ) ;
register_syscore_ops ( & pxa2xx_mfp_syscore_ops ) ;
2008-01-28 23:00:02 +00:00
2015-02-07 22:18:34 +01:00
if ( ! of_have_populated_dt ( ) ) {
pxa_register_device ( & pxa27x_device_gpio ,
& pxa27x_gpio_info ) ;
2016-02-15 21:57:47 +01:00
pxa2xx_set_dmac_info ( 32 , 75 ) ;
2015-02-07 22:18:34 +01:00
ret = platform_add_devices ( devices ,
ARRAY_SIZE ( devices ) ) ;
}
2007-05-15 11:16:10 +01:00
}
2008-01-28 23:00:02 +00:00
2007-05-15 11:16:10 +01:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2008-04-19 10:59:24 +01:00
postcore_initcall ( pxa27x_init ) ;