#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
-
-#include <asm/hardware.h>
-#include <asm/arch/pxa3xx-regs.h>
-#include <asm/arch/ohci.h>
-#include <asm/arch/pm.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/ssp.h>
+#include <linux/sysdev.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/pxa3xx-regs.h>
+#include <mach/reset.h>
+#include <mach/ohci.h>
+#include <mach/pm.h>
+#include <mach/dma.h>
+#include <mach/ssp.h>
+#include <mach/i2c.h>
#include "generic.h"
#include "devices.h"
#define RO_CLK 60000000
#define ACCR_D0CS (1 << 26)
+#define ACCR_PCCE (1 << 11)
/* crystal frequency to static memory controller multiplier (SMCFS) */
static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
HSS / 1000000, (HSS % 1000000) / 10000);
}
- return CLK;
+ return CLK / 1000;
}
/*
return (clk / 10000);
}
+void pxa3xx_clear_reset_status(unsigned int mask)
+{
+ /* RESET_STATUS_* has a 1:1 mapping with ARSR */
+ ARSR = mask;
+}
+
+/*
+ * Return the current AC97 clock frequency.
+ */
+static unsigned long clk_pxa3xx_ac97_getrate(struct clk *clk)
+{
+ unsigned long rate = 312000000;
+ unsigned long ac97_div;
+
+ ac97_div = AC97_DIV;
+
+ /* This may loose precision for some rates but won't for the
+ * standard 24.576MHz.
+ */
+ rate /= (ac97_div >> 12) & 0x7fff;
+ rate *= (ac97_div & 0xfff);
+
+ return rate;
+}
+
/*
* Return the current HSIO bus clock frequency
*/
return hsio_clk;
}
-static void clk_pxa3xx_cken_enable(struct clk *clk)
+void clk_pxa3xx_cken_enable(struct clk *clk)
{
unsigned long mask = 1ul << (clk->cken & 0x1f);
- local_irq_disable();
-
if (clk->cken < 32)
CKENA |= mask;
else
CKENB |= mask;
-
- local_irq_enable();
}
-static void clk_pxa3xx_cken_disable(struct clk *clk)
+void clk_pxa3xx_cken_disable(struct clk *clk)
{
unsigned long mask = 1ul << (clk->cken & 0x1f);
- local_irq_disable();
-
if (clk->cken < 32)
CKENA &= ~mask;
else
CKENB &= ~mask;
-
- local_irq_enable();
}
-static const struct clkops clk_pxa3xx_cken_ops = {
+const struct clkops clk_pxa3xx_cken_ops = {
.enable = clk_pxa3xx_cken_enable,
.disable = clk_pxa3xx_cken_disable,
};
.getrate = clk_pxa3xx_hsio_getrate,
};
-#define PXA3xx_CKEN(_name, _cken, _rate, _delay, _dev) \
- { \
- .name = _name, \
- .dev = _dev, \
- .ops = &clk_pxa3xx_cken_ops, \
- .rate = _rate, \
- .cken = CKEN_##_cken, \
- .delay = _delay, \
- }
+static const struct clkops clk_pxa3xx_ac97_ops = {
+ .enable = clk_pxa3xx_cken_enable,
+ .disable = clk_pxa3xx_cken_disable,
+ .getrate = clk_pxa3xx_ac97_getrate,
+};
-#define PXA3xx_CK(_name, _cken, _ops, _dev) \
- { \
- .name = _name, \
- .dev = _dev, \
- .ops = _ops, \
- .cken = CKEN_##_cken, \
- }
+static void clk_pout_enable(struct clk *clk)
+{
+ OSCC |= OSCC_PEN;
+}
-static struct clk pxa3xx_clks[] = {
- PXA3xx_CK("LCDCLK", LCD, &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
- PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
+static void clk_pout_disable(struct clk *clk)
+{
+ OSCC &= ~OSCC_PEN;
+}
- PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
- PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
- PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
+static const struct clkops clk_pout_ops = {
+ .enable = clk_pout_enable,
+ .disable = clk_pout_disable,
+};
- PXA3xx_CKEN("I2CCLK", I2C, 32842000, 0, &pxa_device_i2c.dev),
- PXA3xx_CKEN("UDCCLK", UDC, 48000000, 5, &pxa_device_udc.dev),
- PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev),
+static void clk_dummy_enable(struct clk *clk)
+{
+}
- PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
- PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
- PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
- PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev),
+static void clk_dummy_disable(struct clk *clk)
+{
+}
+
+static const struct clkops clk_dummy_ops = {
+ .enable = clk_dummy_enable,
+ .disable = clk_dummy_disable,
+};
+
+static struct clk clk_pxa3xx_pout = {
+ .ops = &clk_pout_ops,
+ .rate = 13000000,
+ .delay = 70,
+};
- PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev),
- PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev),
- PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
+static struct clk clk_dummy = {
+ .ops = &clk_dummy_ops,
+};
+
+static DEFINE_PXA3_CK(pxa3xx_lcd, LCD, &clk_pxa3xx_hsio_ops);
+static DEFINE_PXA3_CK(pxa3xx_camera, CAMERA, &clk_pxa3xx_hsio_ops);
+static DEFINE_PXA3_CK(pxa3xx_ac97, AC97, &clk_pxa3xx_ac97_ops);
+static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_i2c, I2C, 32842000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_udc, UDC, 48000000, 5);
+static DEFINE_PXA3_CKEN(pxa3xx_usbh, USBH, 48000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_keypad, KEYPAD, 32768, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp3, SSP3, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp4, SSP4, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_pwm0, PWM0, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_pwm1, PWM1, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_mmc1, MMC1, 19500000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_mmc2, MMC2, 19500000, 0);
+
+static struct clk_lookup pxa3xx_clkregs[] = {
+ INIT_CLKREG(&clk_pxa3xx_pout, NULL, "CLK_POUT"),
+ /* Power I2C clock is always on */
+ INIT_CLKREG(&clk_dummy, "pxa2xx-i2c.1", NULL),
+ INIT_CLKREG(&clk_pxa3xx_lcd, "pxa2xx-fb", NULL),
+ INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"),
+ INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"),
+ INIT_CLKREG(&clk_pxa3xx_ffuart, "pxa2xx-uart.0", NULL),
+ INIT_CLKREG(&clk_pxa3xx_btuart, "pxa2xx-uart.1", NULL),
+ INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-uart.2", NULL),
+ INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-ir", "UARTCLK"),
+ INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
+ INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
+ INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
+ INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
+ INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
+ INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
+ INIT_CLKREG(&clk_pxa3xx_ssp3, "pxa27x-ssp.2", NULL),
+ INIT_CLKREG(&clk_pxa3xx_ssp4, "pxa27x-ssp.3", NULL),
+ INIT_CLKREG(&clk_pxa3xx_pwm0, "pxa27x-pwm.0", NULL),
+ INIT_CLKREG(&clk_pxa3xx_pwm1, "pxa27x-pwm.1", NULL),
+ INIT_CLKREG(&clk_pxa3xx_mmc1, "pxa2xx-mci.0", NULL),
+ INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL),
};
#ifdef CONFIG_PM
-#define SLEEP_SAVE_SIZE 4
#define ISRAM_START 0x5c000000
#define ISRAM_SIZE SZ_256K
static void __iomem *sram;
static unsigned long wakeup_src;
-static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
-{
- pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
+#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
- if (CKENA & (1 << CKEN_USBH)) {
- printk(KERN_ERR "PM: USB host clock not stopped?\n");
- CKENA &= ~(1 << CKEN_USBH);
- }
-// CKENA |= 1 << (CKEN_ISC & 31);
+enum { SLEEP_SAVE_CKENA,
+ SLEEP_SAVE_CKENB,
+ SLEEP_SAVE_ACCR,
- /*
- * Low power modes require the HSIO2 clock to be enabled.
- */
- CKENB |= 1 << (CKEN_HSIO2 & 31);
+ SLEEP_SAVE_COUNT,
+};
+
+static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
+{
+ SAVE(CKENA);
+ SAVE(CKENB);
+ SAVE(ACCR);
}
static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
{
- CKENB &= ~(1 << (CKEN_HSIO2 & 31));
+ RESTORE(ACCR);
+ RESTORE(CKENA);
+ RESTORE(CKENB);
}
/*
AD2D0ER = 0;
AD2D1ER = 0;
+}
+
+/*
+ * NOTE: currently, the OBM (OEM Boot Module) binary comes along with
+ * PXA3xx development kits assumes that the resuming process continues
+ * with the address stored within the first 4 bytes of SDRAM. The PSPR
+ * register is used privately by BootROM and OBM, and _must_ be set to
+ * 0x5c014000 for the moment.
+ */
+static void pxa3xx_cpu_pm_suspend(void)
+{
+ volatile unsigned long *p = (volatile void *)0xc0000000;
+ unsigned long saved_data = *p;
+
+ extern void pxa3xx_cpu_suspend(void);
+ extern void pxa3xx_cpu_resume(void);
+
+ /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
+ CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+ CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
+
+ /* clear and setup wakeup source */
+ AD3SR = ~0;
+ AD3ER = wakeup_src;
+ ASCR = ASCR;
+ ARSR = ARSR;
+
+ PCFR |= (1u << 13); /* L1_DIS */
+ PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */
+
+ PSPR = 0x5c014000;
+
+ /* overwrite with the resume address */
+ *p = virt_to_phys(pxa3xx_cpu_resume);
- printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
+ pxa3xx_cpu_suspend();
+
+ *p = saved_data;
+
+ AD3ER = 0;
}
static void pxa3xx_cpu_pm_enter(suspend_state_t state)
/*
* Don't sleep if no wakeup sources are defined
*/
- if (wakeup_src == 0)
+ if (wakeup_src == 0) {
+ printk(KERN_ERR "Not suspending: no wakeup sources\n");
return;
+ }
switch (state) {
case PM_SUSPEND_STANDBY:
break;
case PM_SUSPEND_MEM:
+ pxa3xx_cpu_pm_suspend();
break;
}
}
}
static struct pxa_cpu_pm_fns pxa3xx_cpu_pm_fns = {
- .save_size = SLEEP_SAVE_SIZE,
+ .save_count = SLEEP_SAVE_COUNT,
.save = pxa3xx_cpu_pm_save,
.restore = pxa3xx_cpu_pm_restore,
.valid = pxa3xx_cpu_pm_valid,
case IRQ_MMC3:
mask = ADXER_MFP_GEN12;
break;
+ default:
+ return -EINVAL;
}
local_irq_save(flags);
return 0;
}
-
-static void pxa3xx_init_irq_pm(void)
-{
- pxa_init_irq_set_wake(pxa3xx_set_wake);
-}
-
#else
static inline void pxa3xx_init_pm(void) {}
-static inline void pxa3xx_init_irq_pm(void) {}
+#define pxa3xx_set_wake NULL
#endif
void __init pxa3xx_init_irq(void)
value |= (1 << 6);
__asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
- pxa_init_irq_low();
- pxa_init_irq_high();
- pxa_init_irq_gpio(128);
- pxa3xx_init_irq_pm();
+ pxa_init_irq(56, pxa3xx_set_wake);
+ pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
}
/*
* device registration specific to PXA3xx.
*/
+void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info)
+{
+ pxa_register_device(&pxa3xx_device_i2c_power, info);
+}
+
static struct platform_device *devices[] __initdata = {
- &pxa_device_udc,
+/* &pxa_device_udc, The UDC driver is PXA25x only */
&pxa_device_ffuart,
&pxa_device_btuart,
&pxa_device_stuart,
&pxa_device_i2s,
+ &sa1100_device_rtc,
&pxa_device_rtc,
&pxa27x_device_ssp1,
&pxa27x_device_ssp2,
&pxa27x_device_ssp3,
&pxa3xx_device_ssp4,
+ &pxa27x_device_pwm0,
+ &pxa27x_device_pwm1,
+};
+
+static struct sys_device pxa3xx_sysdev[] = {
+ {
+ .cls = &pxa_irq_sysclass,
+ }, {
+ .cls = &pxa3xx_mfp_sysclass,
+ }, {
+ .cls = &pxa_gpio_sysclass,
+ },
};
static int __init pxa3xx_init(void)
{
- int ret = 0;
+ int i, ret = 0;
if (cpu_is_pxa3xx()) {
- clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
- if ((ret = pxa_init_dma(32)))
+ reset_status = ARSR;
+
+ /*
+ * clear RDH bit every time after reset
+ *
+ * Note: the last 3 bits DxS are write-1-to-clear so carefully
+ * preserve them here in case they will be referenced later
+ */
+ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
+
+ clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
+
+ if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
pxa3xx_init_pm();
- return platform_add_devices(devices, ARRAY_SIZE(devices));
+ for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
+ ret = sysdev_register(&pxa3xx_sysdev[i]);
+ if (ret)
+ pr_err("failed to register sysdev[%d]\n", i);
+ }
+
+ ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
- return 0;
+
+ return ret;
}
-subsys_initcall(pxa3xx_init);
+postcore_initcall(pxa3xx_init);