Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6 into devel

Conflicts:
	arch/arm/Makefile
This commit is contained in:
Russell King
2009-05-29 20:03:43 +01:00
committed by Russell King
99 changed files with 9462 additions and 1129 deletions

View File

@@ -25,7 +25,7 @@ config ARCH_OMAP3430
select ARCH_OMAP_OTG
comment "OMAP Board Type"
depends on ARCH_OMAP2 || ARCH_OMAP3
depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
config MACH_OMAP_GENERIC
bool "Generic OMAP board"
@@ -56,6 +56,10 @@ config MACH_OVERO
bool "Gumstix Overo board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
config MACH_OMAP3EVM
bool "OMAP 3530 EVM board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
config MACH_OMAP3_PANDORA
bool "OMAP3 Pandora"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
@@ -67,3 +71,11 @@ config MACH_OMAP_3430SDP
config MACH_NOKIA_RX51
bool "Nokia RX-51 board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
config MACH_OMAP_ZOOM2
bool "OMAP3 Zoom2 board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
config MACH_OMAP_4430SDP
bool "OMAP 4430 SDP board"
depends on ARCH_OMAP4

View File

@@ -3,9 +3,14 @@
#
# Common support
obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \
devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
clockdomain.o
obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o
omap-2-3-common = irq.o sdrc.o
prcm-common = prcm.o powerdomain.o
clock-common = clock.o clockdomain.o
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common)
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common)
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
@@ -20,8 +25,10 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o
# Power Management
ifeq ($(CONFIG_PM),y)
obj-y += pm.o
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o
obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
endif
# Clock framework
@@ -45,6 +52,8 @@ obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OVERO) += board-overo.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \
@@ -53,8 +62,17 @@ obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \
board-rx51-peripherals.o \
mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \
mmc-twl4030.o \
board-zoom-debugboard.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o
# Platform specific device init code
ifeq ($(CONFIG_USB_MUSB_SOC),y)
obj-y += usb-musb.o
endif
onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o
obj-y += $(onenand-m) $(onenand-y)
smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
obj-y += $(smc91x-m) $(smc91x-y)

View File

@@ -36,14 +36,12 @@
#include <mach/common.h>
#include <mach/gpmc.h>
#include <mach/usb.h>
#include <mach/gpmc-smc91x.h>
#include "mmc-twl4030.h"
#define SDP2430_CS0_BASE 0x04000000
#define SDP2430_FLASH_CS 0
#define SDP2430_SMC91X_CS 5
#define SDP2430_ETHR_GPIO_IRQ 149
#define SECONDARY_LCD_GPIO 147
static struct mtd_partition sdp2430_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
@@ -99,100 +97,53 @@ static struct platform_device sdp2430_flash_device = {
.resource = &sdp2430_flash_resource,
};
static struct resource sdp2430_smc91x_resources[] = {
[0] = {
.start = SDP2430_CS0_BASE,
.end = SDP2430_CS0_BASE + SZ_64M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
.end = OMAP_GPIO_IRQ(SDP2430_ETHR_GPIO_IRQ),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
static struct platform_device sdp2430_smc91x_device = {
.name = "smc91x",
static struct platform_device sdp2430_lcd_device = {
.name = "sdp2430_lcd",
.id = -1,
.num_resources = ARRAY_SIZE(sdp2430_smc91x_resources),
.resource = sdp2430_smc91x_resources,
};
static struct platform_device *sdp2430_devices[] __initdata = {
&sdp2430_smc91x_device,
&sdp2430_flash_device,
&sdp2430_lcd_device,
};
static inline void __init sdp2430_init_smc91x(void)
static struct omap_lcd_config sdp2430_lcd_config __initdata = {
.ctrl_name = "internal",
};
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE)
static struct omap_smc91x_platform_data board_smc91x_data = {
.cs = 5,
.gpio_irq = 149,
.flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
IORESOURCE_IRQ_LOWLEVEL,
};
static void __init board_smc91x_init(void)
{
int eth_cs;
unsigned long cs_mem_base;
unsigned int rate;
struct clk *gpmc_fck;
if (omap_rev() > OMAP3430_REV_ES1_0)
board_smc91x_data.gpio_irq = 6;
else
board_smc91x_data.gpio_irq = 29;
eth_cs = SDP2430_SMC91X_CS;
gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(gpmc_fck)) {
WARN_ON(1);
return;
}
clk_enable(gpmc_fck);
rate = clk_get_rate(gpmc_fck);
/* Make sure CS1 timings are correct, for 2430 always muxed */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
if (rate >= 160000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else if (rate >= 130000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else { /* rate = 100000000 */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
goto out;
}
sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300;
sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f;
udelay(100);
if (gpio_request(SDP2430_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
SDP2430_ETHR_GPIO_IRQ);
gpmc_cs_free(eth_cs);
goto out;
}
gpio_direction_input(SDP2430_ETHR_GPIO_IRQ);
out:
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
gpmc_smc91x_init(&board_smc91x_data);
}
#else
static inline void board_smc91x_init(void)
{
}
#endif
static void __init omap_2430sdp_init_irq(void)
{
omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
sdp2430_init_smc91x();
}
static struct omap_uart_config sdp2430_uart_config __initdata = {
@@ -201,6 +152,7 @@ static struct omap_uart_config sdp2430_uart_config __initdata = {
static struct omap_board_config_kernel sdp2430_config[] = {
{OMAP_TAG_UART, &sdp2430_uart_config},
{OMAP_TAG_LCD, &sdp2430_lcd_config},
};
@@ -248,6 +200,8 @@ static struct twl4030_hsmmc_info mmc[] __initdata = {
static void __init omap_2430sdp_init(void)
{
int ret;
omap2430_i2c_init();
platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
@@ -256,6 +210,12 @@ static void __init omap_2430sdp_init(void)
omap_serial_init();
twl4030_mmc_init(mmc);
usb_musb_init();
board_smc91x_init();
/* Turn off secondary LCD backlight */
ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight");
if (ret == 0)
gpio_direction_output(SECONDARY_LCD_GPIO, 0);
}
static void __init omap_2430sdp_map_io(void)

View File

@@ -39,15 +39,13 @@
#include <mach/control.h>
#include <mach/keypad.h>
#include <mach/gpmc-smc91x.h>
#include "sdram-qimonda-hyb18m512160af-6.h"
#include "mmc-twl4030.h"
#define CONFIG_DISABLE_HFCLK 1
#define SDP3430_ETHR_GPIO_IRQ_SDPV1 29
#define SDP3430_ETHR_GPIO_IRQ_SDPV2 6
#define SDP3430_SMC91X_CS 3
#define SDP3430_TS_GPIO_IRQ_SDPV1 3
#define SDP3430_TS_GPIO_IRQ_SDPV2 2
@@ -56,24 +54,6 @@
#define TWL4030_MSECURE_GPIO 22
static struct resource sdp3430_smc91x_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
static struct platform_device sdp3430_smc91x_device = {
.name = "smc91x",
.id = -1,
.num_resources = ARRAY_SIZE(sdp3430_smc91x_resources),
.resource = sdp3430_smc91x_resources,
};
static int sdp3430_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
@@ -184,48 +164,14 @@ static struct regulator_consumer_supply sdp3430_vdvi_supply = {
};
static struct platform_device *sdp3430_devices[] __initdata = {
&sdp3430_smc91x_device,
&sdp3430_lcd_device,
};
static inline void __init sdp3430_init_smc91x(void)
{
int eth_cs;
unsigned long cs_mem_base;
int eth_gpio = 0;
eth_cs = SDP3430_SMC91X_CS;
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
return;
}
sdp3430_smc91x_resources[0].start = cs_mem_base + 0x300;
sdp3430_smc91x_resources[0].end = cs_mem_base + 0x30f;
udelay(100);
if (omap_rev() > OMAP3430_REV_ES1_0)
eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV2;
else
eth_gpio = SDP3430_ETHR_GPIO_IRQ_SDPV1;
sdp3430_smc91x_resources[1].start = gpio_to_irq(eth_gpio);
if (gpio_request(eth_gpio, "SMC91x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
eth_gpio);
return;
}
gpio_direction_input(eth_gpio);
}
static void __init omap_3430sdp_init_irq(void)
{
omap2_init_common_hw(NULL);
omap2_init_common_hw(hyb18m512160af6_sdrc_params);
omap_init_irq();
omap_gpio_init();
sdp3430_init_smc91x();
}
static struct omap_uart_config sdp3430_uart_config __initdata = {
@@ -506,6 +452,32 @@ static int __init omap3430_i2c_init(void)
return 0;
}
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
static struct omap_smc91x_platform_data board_smc91x_data = {
.cs = 3,
.flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
IORESOURCE_IRQ_LOWLEVEL,
};
static void __init board_smc91x_init(void)
{
if (omap_rev() > OMAP3430_REV_ES1_0)
board_smc91x_data.gpio_irq = 6;
else
board_smc91x_data.gpio_irq = 29;
gpmc_smc91x_init(&board_smc91x_data);
}
#else
static inline void board_smc91x_init(void)
{
}
#endif
static void __init omap_3430sdp_init(void)
{
omap3430_i2c_init();
@@ -522,6 +494,7 @@ static void __init omap_3430sdp_init(void)
ads7846_dev_init();
omap_serial_init();
usb_musb_init();
board_smc91x_init();
}
static void __init omap_3430sdp_map_io(void)

View File

@@ -0,0 +1,94 @@
/*
* Board support file for OMAP4430 SDP.
*
* Copyright (C) 2009 Texas Instruments
*
* Author: Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* Based on mach-omap2/board-3430sdp.c
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/board.h>
#include <mach/common.h>
#include <mach/control.h>
#include <mach/timer-gp.h>
#include <asm/hardware/gic.h>
static struct platform_device sdp4430_lcd_device = {
.name = "sdp4430_lcd",
.id = -1,
};
static struct platform_device *sdp4430_devices[] __initdata = {
&sdp4430_lcd_device,
};
static struct omap_uart_config sdp4430_uart_config __initdata = {
.enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2),
};
static struct omap_lcd_config sdp4430_lcd_config __initdata = {
.ctrl_name = "internal",
};
static struct omap_board_config_kernel sdp4430_config[] __initdata = {
{ OMAP_TAG_UART, &sdp4430_uart_config },
{ OMAP_TAG_LCD, &sdp4430_lcd_config },
};
static void __init gic_init_irq(void)
{
gic_dist_init(0, IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29);
gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
}
static void __init omap_4430sdp_init_irq(void)
{
omap2_init_common_hw(NULL);
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(1);
#endif
gic_init_irq();
omap_gpio_init();
}
static void __init omap_4430sdp_init(void)
{
platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
omap_board_config = sdp4430_config;
omap_board_config_size = ARRAY_SIZE(sdp4430_config);
omap_serial_init();
}
static void __init omap_4430sdp_map_io(void)
{
omap2_set_globals_443x();
omap2_map_common_io();
}
MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
/* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
.phys_io = 0x48000000,
.io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_4430sdp_map_io,
.init_irq = omap_4430sdp_init_irq,
.init_machine = omap_4430sdp_init,
.timer = &omap_timer,
MACHINE_END

View File

@@ -16,11 +16,13 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <linux/io.h>
#include <linux/smsc911x.h>
@@ -39,6 +41,7 @@
#include <asm/delay.h>
#include <mach/control.h>
#include <mach/usb.h>
#include <mach/keypad.h>
#include "mmc-twl4030.h"
@@ -77,8 +80,163 @@ static struct platform_device ldp_smsc911x_device = {
},
};
static struct platform_device *ldp_devices[] __initdata = {
&ldp_smsc911x_device,
static int ldp_twl4030_keymap[] = {
KEY(0, 0, KEY_1),
KEY(1, 0, KEY_2),
KEY(2, 0, KEY_3),
KEY(0, 1, KEY_4),
KEY(1, 1, KEY_5),
KEY(2, 1, KEY_6),
KEY(3, 1, KEY_F5),
KEY(0, 2, KEY_7),
KEY(1, 2, KEY_8),
KEY(2, 2, KEY_9),
KEY(3, 2, KEY_F6),
KEY(0, 3, KEY_F7),
KEY(1, 3, KEY_0),
KEY(2, 3, KEY_F8),
PERSISTENT_KEY(4, 5),
KEY(4, 4, KEY_VOLUMEUP),
KEY(5, 5, KEY_VOLUMEDOWN),
0
};
static struct twl4030_keypad_data ldp_kp_twl4030_data = {
.rows = 6,
.cols = 6,
.keymap = ldp_twl4030_keymap,
.keymapsize = ARRAY_SIZE(ldp_twl4030_keymap),
.rep = 1,
};
static struct gpio_keys_button ldp_gpio_keys_buttons[] = {
[0] = {
.code = KEY_ENTER,
.gpio = 101,
.desc = "enter sw",
.active_low = 1,
.debounce_interval = 30,
},
[1] = {
.code = KEY_F1,
.gpio = 102,
.desc = "func 1",
.active_low = 1,
.debounce_interval = 30,
},
[2] = {
.code = KEY_F2,
.gpio = 103,
.desc = "func 2",
.active_low = 1,
.debounce_interval = 30,
},
[3] = {
.code = KEY_F3,
.gpio = 104,
.desc = "func 3",
.active_low = 1,
.debounce_interval = 30,
},
[4] = {
.code = KEY_F4,
.gpio = 105,
.desc = "func 4",
.active_low = 1,
.debounce_interval = 30,
},
[5] = {
.code = KEY_LEFT,
.gpio = 106,
.desc = "left sw",
.active_low = 1,
.debounce_interval = 30,
},
[6] = {
.code = KEY_RIGHT,
.gpio = 107,
.desc = "right sw",
.active_low = 1,
.debounce_interval = 30,
},
[7] = {
.code = KEY_UP,
.gpio = 108,
.desc = "up sw",
.active_low = 1,
.debounce_interval = 30,
},
[8] = {
.code = KEY_DOWN,
.gpio = 109,
.desc = "down sw",
.active_low = 1,
.debounce_interval = 30,
},
};
static struct gpio_keys_platform_data ldp_gpio_keys = {
.buttons = ldp_gpio_keys_buttons,
.nbuttons = ARRAY_SIZE(ldp_gpio_keys_buttons),
.rep = 1,
};
static struct platform_device ldp_gpio_keys_device = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &ldp_gpio_keys,
},
};
static int ts_gpio;
/**
* @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
*
* @return - void. If request gpio fails then Flag KERN_ERR.
*/
static void ads7846_dev_init(void)
{
if (gpio_request(ts_gpio, "ads7846 irq") < 0) {
printk(KERN_ERR "can't get ads746 pen down GPIO\n");
return;
}
gpio_direction_input(ts_gpio);
omap_set_gpio_debounce(ts_gpio, 1);
omap_set_gpio_debounce_time(ts_gpio, 0xa);
}
static int ads7846_get_pendown_state(void)
{
return !gpio_get_value(ts_gpio);
}
static struct ads7846_platform_data tsc2046_config __initdata = {
.get_pendown_state = ads7846_get_pendown_state,
.keep_vref_on = 1,
};
static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
};
static struct spi_board_info ldp_spi_board_info[] __initdata = {
[0] = {
/*
* TSC2046 operates at a max freqency of 2MHz, so
* operate slightly below at 1.5MHz
*/
.modalias = "ads7846",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 1500000,
.controller_data = &tsc2046_mcspi_config,
.irq = 0,
.platform_data = &tsc2046_config,
},
};
static inline void __init ldp_init_smsc911x(void)
@@ -122,8 +280,22 @@ static struct omap_uart_config ldp_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct platform_device ldp_lcd_device = {
.name = "ldp_lcd",
.id = -1,
};
static struct omap_lcd_config ldp_lcd_config __initdata = {
.ctrl_name = "internal",
};
static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_UART, &ldp_uart_config },
{ OMAP_TAG_LCD, &ldp_lcd_config },
};
static struct twl4030_usb_data ldp_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
static struct twl4030_gpio_platform_data ldp_gpio_data = {
@@ -132,12 +304,39 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = {
.irq_end = TWL4030_GPIO_IRQ_END,
};
static struct twl4030_madc_platform_data ldp_madc_data = {
.irq_line = 1,
};
static struct regulator_consumer_supply ldp_vmmc1_supply = {
.supply = "vmmc",
};
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data ldp_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &ldp_vmmc1_supply,
};
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.madc = &ldp_madc_data,
.usb = &ldp_usb_data,
.vmmc1 = &ldp_vmmc1,
.gpio = &ldp_gpio_data,
.keypad = &ldp_kp_twl4030_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
@@ -168,15 +367,29 @@ static struct twl4030_hsmmc_info mmc[] __initdata = {
{} /* Terminator */
};
static struct platform_device *ldp_devices[] __initdata = {
&ldp_smsc911x_device,
&ldp_lcd_device,
&ldp_gpio_keys_device,
};
static void __init omap_ldp_init(void)
{
omap_i2c_init();
platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
omap_board_config = ldp_config;
omap_board_config_size = ARRAY_SIZE(ldp_config);
ts_gpio = 54;
ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
spi_register_board_info(ldp_spi_board_info,
ARRAY_SIZE(ldp_spi_board_info));
ads7846_dev_init();
omap_serial_init();
twl4030_mmc_init(mmc);
usb_musb_init();
twl4030_mmc_init(mmc);
/* link regulators to MMC adapters */
ldp_vmmc1_supply.dev = mmc[0].dev;
}
static void __init omap_ldp_map_io(void)

View File

@@ -28,6 +28,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <mach/hardware.h>
@@ -105,6 +106,8 @@ static struct platform_device omap3beagle_nand_device = {
.resource = &omap3beagle_nand_resource,
};
#include "sdram-micron-mt46h32m32lf-6.h"
static struct omap_uart_config omap3_beagle_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
@@ -118,6 +121,23 @@ static struct twl4030_hsmmc_info mmc[] = {
{} /* Terminator */
};
static struct platform_device omap3_beagle_lcd_device = {
.name = "omap3beagle_lcd",
.id = -1,
};
static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
.ctrl_name = "internal",
};
static struct regulator_consumer_supply beagle_vmmc1_supply = {
.supply = "vmmc",
};
static struct regulator_consumer_supply beagle_vsim_supply = {
.supply = "vmmc_aux",
};
static struct gpio_led gpio_leds[];
static int beagle_twl_gpio_setup(struct device *dev,
@@ -128,6 +148,10 @@ static int beagle_twl_gpio_setup(struct device *dev,
mmc[0].gpio_cd = gpio + 0;
twl4030_mmc_init(mmc);
/* link regulators to MMC adapters */
beagle_vmmc1_supply.dev = mmc[0].dev;
beagle_vsim_supply.dev = mmc[0].dev;
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
*/
@@ -156,12 +180,85 @@ static struct twl4030_gpio_platform_data beagle_gpio_data = {
.setup = beagle_twl_gpio_setup,
};
static struct regulator_consumer_supply beagle_vdac_supply = {
.supply = "vdac",
.dev = &omap3_beagle_lcd_device.dev,
};
static struct regulator_consumer_supply beagle_vdvi_supply = {
.supply = "vdvi",
.dev = &omap3_beagle_lcd_device.dev,
};
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data beagle_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &beagle_vmmc1_supply,
};
/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
static struct regulator_init_data beagle_vsim = {
.constraints = {
.min_uV = 1800000,
.max_uV = 3000000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &beagle_vsim_supply,
};
/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
static struct regulator_init_data beagle_vdac = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &beagle_vdac_supply,
};
/* VPLL2 for digital video outputs */
static struct regulator_init_data beagle_vpll2 = {
.constraints = {
.name = "VDVI",
.min_uV = 1800000,
.max_uV = 1800000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &beagle_vdvi_supply,
};
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &beagle_gpio_data,
.vmmc1 = &beagle_vmmc1,
.vsim = &beagle_vsim,
.vdac = &beagle_vdac,
.vpll2 = &beagle_vpll2,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
@@ -185,7 +282,7 @@ static int __init omap3_beagle_i2c_init(void)
static void __init omap3_beagle_init_irq(void)
{
omap2_init_common_hw(NULL);
omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(12);
@@ -193,15 +290,6 @@ static void __init omap3_beagle_init_irq(void)
omap_gpio_init();
}
static struct platform_device omap3_beagle_lcd_device = {
.name = "omap3beagle_lcd",
.id = -1,
};
static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
.ctrl_name = "internal",
};
static struct gpio_led gpio_leds[] = {
{
.name = "beagleboard::usr0",

View File

@@ -0,0 +1,329 @@
/*
* linux/arch/arm/mach-omap2/board-omap3evm.c
*
* Copyright (C) 2008 Texas Instruments
*
* Modified from mach-omap2/board-3430sdp.c
*
* Initial code: Syed Mohammed Khasim
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/i2c/twl4030.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/board.h>
#include <mach/mux.h>
#include <mach/usb.h>
#include <mach/common.h>
#include <mach/mcspi.h>
#include <mach/keypad.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
#define OMAP3_EVM_TS_GPIO 175
#define OMAP3EVM_ETHR_START 0x2c000000
#define OMAP3EVM_ETHR_SIZE 1024
#define OMAP3EVM_ETHR_GPIO_IRQ 176
#define OMAP3EVM_SMC911X_CS 5
static struct resource omap3evm_smc911x_resources[] = {
[0] = {
.start = OMAP3EVM_ETHR_START,
.end = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
.flags = IORESOURCE_MEM,
},
[1] = {
.start = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
.end = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device omap3evm_smc911x_device = {
.name = "smc911x",
.id = -1,
.num_resources = ARRAY_SIZE(omap3evm_smc911x_resources),
.resource = &omap3evm_smc911x_resources[0],
};
static inline void __init omap3evm_init_smc911x(void)
{
int eth_cs;
struct clk *l3ck;
unsigned int rate;
eth_cs = OMAP3EVM_SMC911X_CS;
l3ck = clk_get(NULL, "l3_ck");
if (IS_ERR(l3ck))
rate = 100000000;
else
rate = clk_get_rate(l3ck);
if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
OMAP3EVM_ETHR_GPIO_IRQ);
return;
}
gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
}
static struct omap_uart_config omap3_evm_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct twl4030_hsmmc_info mmc[] = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = 63,
},
{} /* Terminator */
};
static struct gpio_led gpio_leds[] = {
{
.name = "omap3evm::ledb",
/* normally not visible (board underside) */
.default_trigger = "default-on",
.gpio = -EINVAL, /* gets replaced */
.active_low = true,
},
};
static struct gpio_led_platform_data gpio_led_info = {
.leds = gpio_leds,
.num_leds = ARRAY_SIZE(gpio_leds),
};
static struct platform_device leds_gpio = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &gpio_led_info,
},
};
static int omap3evm_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
omap_cfg_reg(L8_34XX_GPIO63);
mmc[0].gpio_cd = gpio + 0;
twl4030_mmc_init(mmc);
/*
* Most GPIOs are for USB OTG. Some are mostly sent to
* the P2 connector; notably LEDA for the LCD backlight.
*/
/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
platform_device_register(&leds_gpio);
return 0;
}
static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.use_leds = true,
.setup = omap3evm_twl_gpio_setup,
};
static struct twl4030_usb_data omap3evm_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
static int omap3evm_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_A),
KEY(0, 3, KEY_B),
KEY(1, 0, KEY_DOWN),
KEY(1, 1, KEY_UP),
KEY(1, 2, KEY_E),
KEY(1, 3, KEY_F),
KEY(2, 0, KEY_ENTER),
KEY(2, 1, KEY_I),
KEY(2, 2, KEY_J),
KEY(2, 3, KEY_K),
KEY(3, 0, KEY_M),
KEY(3, 1, KEY_N),
KEY(3, 2, KEY_O),
KEY(3, 3, KEY_P)
};
static struct twl4030_keypad_data omap3evm_kp_data = {
.rows = 4,
.cols = 4,
.keymap = omap3evm_keymap,
.keymapsize = ARRAY_SIZE(omap3evm_keymap),
.rep = 1,
};
static struct twl4030_madc_platform_data omap3evm_madc_data = {
.irq_line = 1,
};
static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &omap3evm_kp_data,
.madc = &omap3evm_madc_data,
.usb = &omap3evm_usb_data,
.gpio = &omap3evm_gpio_data,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &omap3evm_twldata,
},
};
static int __init omap3_evm_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
ARRAY_SIZE(omap3evm_i2c_boardinfo));
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static struct platform_device omap3_evm_lcd_device = {
.name = "omap3evm_lcd",
.id = -1,
};
static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
.ctrl_name = "internal",
};
static void ads7846_dev_init(void)
{
if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
gpio_direction_input(OMAP3_EVM_TS_GPIO);
omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
}
static int ads7846_get_pendown_state(void)
{
return !gpio_get_value(OMAP3_EVM_TS_GPIO);
}
struct ads7846_platform_data ads7846_config = {
.x_max = 0x0fff,
.y_max = 0x0fff,
.x_plate_ohms = 180,
.pressure_max = 255,
.debounce_max = 10,
.debounce_tol = 3,
.debounce_rep = 1,
.get_pendown_state = ads7846_get_pendown_state,
.keep_vref_on = 1,
.settle_delay_usecs = 150,
};
static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
};
struct spi_board_info omap3evm_spi_board_info[] = {
[0] = {
.modalias = "ads7846",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 1500000,
.controller_data = &ads7846_mcspi_config,
.irq = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
.platform_data = &ads7846_config,
},
};
static void __init omap3_evm_init_irq(void)
{
omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
omap3evm_init_smc911x();
}
static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
{ OMAP_TAG_UART, &omap3_evm_uart_config },
{ OMAP_TAG_LCD, &omap3_evm_lcd_config },
};
static struct platform_device *omap3_evm_devices[] __initdata = {
&omap3_evm_lcd_device,
&omap3evm_smc911x_device,
};
static void __init omap3_evm_init(void)
{
omap3_evm_i2c_init();
platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
omap_board_config = omap3_evm_config;
omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
spi_register_board_info(omap3evm_spi_board_info,
ARRAY_SIZE(omap3evm_spi_board_info));
omap_serial_init();
usb_musb_init();
ads7846_dev_init();
}
static void __init omap3_evm_map_io(void)
{
omap2_set_globals_343x();
omap2_map_common_io();
}
MACHINE_START(OMAP3EVM, "OMAP3 EVM")
/* Maintainer: Syed Mohammed Khasim - Texas Instruments */
.phys_io = 0x48000000,
.io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap3_evm_map_io,
.init_irq = omap3_evm_init_irq,
.init_machine = omap3_evm_init,
.timer = &omap_timer,
MACHINE_END

View File

@@ -23,7 +23,11 @@
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
#include <linux/leds.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -35,11 +39,154 @@
#include <mach/hardware.h>
#include <mach/mcspi.h>
#include <mach/usb.h>
#include <mach/keypad.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
#define OMAP3_PANDORA_TS_GPIO 94
/* hardware debounce: (value + 1) * 31us */
#define GPIO_DEBOUNCE_TIME 127
static struct gpio_led pandora_gpio_leds[] = {
{
.name = "pandora::sd1",
.default_trigger = "mmc0",
.gpio = 128,
}, {
.name = "pandora::sd2",
.default_trigger = "mmc1",
.gpio = 129,
}, {
.name = "pandora::bluetooth",
.gpio = 158,
}, {
.name = "pandora::wifi",
.gpio = 159,
},
};
static struct gpio_led_platform_data pandora_gpio_led_data = {
.leds = pandora_gpio_leds,
.num_leds = ARRAY_SIZE(pandora_gpio_leds),
};
static struct platform_device pandora_leds_gpio = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &pandora_gpio_led_data,
},
};
#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \
{ \
.gpio = gpio_num, \
.type = ev_type, \
.code = ev_code, \
.active_low = act_low, \
.desc = "btn " descr, \
}
#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \
GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description)
static struct gpio_keys_button pandora_gpio_keys[] = {
GPIO_BUTTON_LOW(110, KEY_UP, "up"),
GPIO_BUTTON_LOW(103, KEY_DOWN, "down"),
GPIO_BUTTON_LOW(96, KEY_LEFT, "left"),
GPIO_BUTTON_LOW(98, KEY_RIGHT, "right"),
GPIO_BUTTON_LOW(111, BTN_A, "a"),
GPIO_BUTTON_LOW(106, BTN_B, "b"),
GPIO_BUTTON_LOW(109, BTN_X, "x"),
GPIO_BUTTON_LOW(101, BTN_Y, "y"),
GPIO_BUTTON_LOW(102, BTN_TL, "l"),
GPIO_BUTTON_LOW(97, BTN_TL2, "l2"),
GPIO_BUTTON_LOW(105, BTN_TR, "r"),
GPIO_BUTTON_LOW(107, BTN_TR2, "r2"),
GPIO_BUTTON_LOW(104, KEY_LEFTCTRL, "ctrl"),
GPIO_BUTTON_LOW(99, KEY_MENU, "menu"),
GPIO_BUTTON_LOW(176, KEY_COFFEE, "hold"),
GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"),
GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"),
};
static struct gpio_keys_platform_data pandora_gpio_key_info = {
.buttons = pandora_gpio_keys,
.nbuttons = ARRAY_SIZE(pandora_gpio_keys),
};
static struct platform_device pandora_keys_gpio = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &pandora_gpio_key_info,
},
};
static void __init pandora_keys_gpio_init(void)
{
/* set debounce time for GPIO banks 4 and 6 */
omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME);
omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME);
}
static int pandora_keypad_map[] = {
/* col, row, code */
KEY(0, 0, KEY_9),
KEY(0, 1, KEY_0),
KEY(0, 2, KEY_BACKSPACE),
KEY(0, 3, KEY_O),
KEY(0, 4, KEY_P),
KEY(0, 5, KEY_K),
KEY(0, 6, KEY_L),
KEY(0, 7, KEY_ENTER),
KEY(1, 0, KEY_8),
KEY(1, 1, KEY_7),
KEY(1, 2, KEY_6),
KEY(1, 3, KEY_5),
KEY(1, 4, KEY_4),
KEY(1, 5, KEY_3),
KEY(1, 6, KEY_2),
KEY(1, 7, KEY_1),
KEY(2, 0, KEY_I),
KEY(2, 1, KEY_U),
KEY(2, 2, KEY_Y),
KEY(2, 3, KEY_T),
KEY(2, 4, KEY_R),
KEY(2, 5, KEY_E),
KEY(2, 6, KEY_W),
KEY(2, 7, KEY_Q),
KEY(3, 0, KEY_J),
KEY(3, 1, KEY_H),
KEY(3, 2, KEY_G),
KEY(3, 3, KEY_F),
KEY(3, 4, KEY_D),
KEY(3, 5, KEY_S),
KEY(3, 6, KEY_A),
KEY(3, 7, KEY_LEFTSHIFT),
KEY(4, 0, KEY_N),
KEY(4, 1, KEY_B),
KEY(4, 2, KEY_V),
KEY(4, 3, KEY_C),
KEY(4, 4, KEY_X),
KEY(4, 5, KEY_Z),
KEY(4, 6, KEY_DOT),
KEY(4, 7, KEY_COMMA),
KEY(5, 0, KEY_M),
KEY(5, 1, KEY_SPACE),
KEY(5, 2, KEY_FN),
};
static struct twl4030_keypad_data pandora_kp_data = {
.rows = 8,
.cols = 6,
.keymap = pandora_keypad_map,
.keymapsize = ARRAY_SIZE(pandora_keypad_map),
.rep = 1,
};
static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
{
.mmc = 1,
@@ -69,6 +216,14 @@ static struct omap_uart_config omap3pandora_uart_config __initdata = {
.enabled_uarts = (1 << 2), /* UART3 */
};
static struct regulator_consumer_supply pandora_vmmc1_supply = {
.supply = "vmmc",
};
static struct regulator_consumer_supply pandora_vmmc2_supply = {
.supply = "vmmc",
};
static int omap3pandora_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
@@ -77,6 +232,10 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
omap3pandora_mmc[1].gpio_cd = gpio + 1;
twl4030_mmc_init(omap3pandora_mmc);
/* link regulators to MMC adapters */
pandora_vmmc1_supply.dev = omap3pandora_mmc[0].dev;
pandora_vmmc2_supply.dev = omap3pandora_mmc[1].dev;
return 0;
}
@@ -87,6 +246,36 @@ static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
.setup = omap3pandora_twl_gpio_setup,
};
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data pandora_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &pandora_vmmc1_supply,
};
/* VMMC2 for MMC2 pins CMD, CLK, DAT0..DAT3 (max 100 mA) */
static struct regulator_init_data pandora_vmmc2 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &pandora_vmmc2_supply,
};
static struct twl4030_usb_data omap3pandora_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -96,6 +285,9 @@ static struct twl4030_platform_data omap3pandora_twldata = {
.irq_end = TWL4030_IRQ_END,
.gpio = &omap3pandora_gpio_data,
.usb = &omap3pandora_usb_data,
.vmmc1 = &pandora_vmmc1,
.vmmc2 = &pandora_vmmc2,
.keypad = &pandora_kp_data,
};
static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -118,7 +310,7 @@ static int __init omap3pandora_i2c_init(void)
static void __init omap3pandora_init_irq(void)
{
omap2_init_common_hw(NULL);
omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
@@ -188,6 +380,8 @@ static struct omap_board_config_kernel omap3pandora_config[] __initdata = {
static struct platform_device *omap3pandora_devices[] __initdata = {
&omap3pandora_lcd_device,
&pandora_leds_gpio,
&pandora_keys_gpio,
};
static void __init omap3pandora_init(void)
@@ -201,6 +395,7 @@ static void __init omap3pandora_init(void)
spi_register_board_info(omap3pandora_spi_board_info,
ARRAY_SIZE(omap3pandora_spi_board_info));
omap3pandora_ads7846_init();
pandora_keys_gpio_init();
usb_musb_init();
}

View File

@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030.h>
#include <linux/regulator/machine.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -45,6 +46,7 @@
#include <mach/nand.h>
#include <mach/usb.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
#define OVERO_GPIO_BT_XGATE 15
@@ -271,21 +273,76 @@ static struct omap_uart_config overo_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct twl4030_hsmmc_info mmc[] = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.transceiver = true,
.ocr_mask = 0x00100000, /* 3.3V */
},
{} /* Terminator */
};
static struct regulator_consumer_supply overo_vmmc1_supply = {
.supply = "vmmc",
};
static int overo_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
twl4030_mmc_init(mmc);
overo_vmmc1_supply.dev = mmc[0].dev;
return 0;
}
static struct twl4030_gpio_platform_data overo_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.setup = overo_twl_gpio_setup,
};
static struct twl4030_usb_data overo_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
static struct regulator_init_data overo_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &overo_vmmc1_supply,
};
/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
static struct twl4030_platform_data overo_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
.gpio = &overo_gpio_data,
.usb = &overo_usb_data,
.vmmc1 = &overo_vmmc1,
};
static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
I2C_BOARD_INFO("tps65950", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &overo_twldata,
@@ -303,7 +360,7 @@ static int __init overo_i2c_init(void)
static void __init overo_init_irq(void)
{
omap2_init_common_hw(NULL);
omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
@@ -326,23 +383,6 @@ static struct platform_device *overo_devices[] __initdata = {
&overo_lcd_device,
};
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{
.mmc = 2,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.transceiver = true,
},
{} /* Terminator */
};
static void __init overo_init(void)
{
overo_i2c_init();
@@ -350,7 +390,6 @@ static void __init overo_init(void)
omap_board_config = overo_config;
omap_board_config_size = ARRAY_SIZE(overo_config);
omap_serial_init();
twl4030_mmc_init(mmc);
overo_flash_init();
usb_musb_init();
overo_ads7846_init();

View File

@@ -27,30 +27,13 @@
#include <mach/dma.h>
#include <mach/gpmc.h>
#include <mach/keypad.h>
#include <mach/onenand.h>
#include <mach/gpmc-smc91x.h>
#include "mmc-twl4030.h"
#define SMC91X_CS 1
#define SMC91X_GPIO_IRQ 54
#define SMC91X_GPIO_RESET 164
#define SMC91X_GPIO_PWRDWN 86
static struct resource rx51_smc91x_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
};
static struct platform_device rx51_smc91x_device = {
.name = "smc91x",
.id = -1,
.num_resources = ARRAY_SIZE(rx51_smc91x_resources),
.resource = rx51_smc91x_resources,
};
#define SYSTEM_REV_B_USES_VAUX3 0x1699
#define SYSTEM_REV_S_USES_VAUX3 0x8
static int rx51_keymap[] = {
KEY(0, 0, KEY_Q),
@@ -107,98 +90,6 @@ static struct twl4030_keypad_data rx51_kp_data = {
.rep = 1,
};
static struct platform_device *rx51_peripherals_devices[] = {
&rx51_smc91x_device,
};
/*
* Timings are taken from smsc-lan91c96-ms.pdf
*/
static int smc91x_init_gpmc(int cs)
{
struct gpmc_timings t;
const int t2_r = 45; /* t2 in Figure 12.10 */
const int t2_w = 30; /* t2 in Figure 12.11 */
const int t3 = 15; /* t3 in Figure 12.10 */
const int t5_r = 0; /* t5 in Figure 12.10 */
const int t6_r = 45; /* t6 in Figure 12.10 */
const int t6_w = 0; /* t6 in Figure 12.11 */
const int t7_w = 15; /* t7 in Figure 12.11 */
const int t15 = 12; /* t15 in Figure 12.2 */
const int t20 = 185; /* t20 in Figure 12.2 */
memset(&t, 0, sizeof(t));
t.cs_on = t15;
t.cs_rd_off = t3 + t2_r + t5_r; /* Figure 12.10 */
t.cs_wr_off = t3 + t2_w + t6_w; /* Figure 12.11 */
t.adv_on = t3; /* Figure 12.10 */
t.adv_rd_off = t3 + t2_r; /* Figure 12.10 */
t.adv_wr_off = t3 + t2_w; /* Figure 12.11 */
t.oe_off = t3 + t2_r + t5_r; /* Figure 12.10 */
t.oe_on = t.oe_off - t6_r; /* Figure 12.10 */
t.we_off = t3 + t2_w + t6_w; /* Figure 12.11 */
t.we_on = t.we_off - t7_w; /* Figure 12.11 */
t.rd_cycle = t20; /* Figure 12.2 */
t.wr_cycle = t20; /* Figure 12.4 */
t.access = t3 + t2_r + t5_r; /* Figure 12.10 */
t.wr_access = t3 + t2_w + t6_w; /* Figure 12.11 */
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_DEVICESIZE_16);
return gpmc_cs_set_timings(cs, &t);
}
static void __init rx51_init_smc91x(void)
{
unsigned long cs_mem_base;
int ret;
omap_cfg_reg(U8_34XX_GPIO54_DOWN);
omap_cfg_reg(G25_34XX_GPIO86_OUT);
omap_cfg_reg(H19_34XX_GPIO164_OUT);
if (gpmc_cs_request(SMC91X_CS, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
return;
}
rx51_smc91x_resources[0].start = cs_mem_base + 0x300;
rx51_smc91x_resources[0].end = cs_mem_base + 0x30f;
smc91x_init_gpmc(SMC91X_CS);
if (gpio_request(SMC91X_GPIO_IRQ, "SMC91X irq") < 0)
goto free1;
gpio_direction_input(SMC91X_GPIO_IRQ);
rx51_smc91x_resources[1].start = gpio_to_irq(SMC91X_GPIO_IRQ);
ret = gpio_request(SMC91X_GPIO_PWRDWN, "SMC91X powerdown");
if (ret)
goto free2;
gpio_direction_output(SMC91X_GPIO_PWRDWN, 0);
ret = gpio_request(SMC91X_GPIO_RESET, "SMC91X reset");
if (ret)
goto free3;
gpio_direction_output(SMC91X_GPIO_RESET, 0);
gpio_set_value(SMC91X_GPIO_RESET, 1);
msleep(100);
gpio_set_value(SMC91X_GPIO_RESET, 0);
return;
free3:
gpio_free(SMC91X_GPIO_PWRDWN);
free2:
gpio_free(SMC91X_GPIO_IRQ);
free1:
gpmc_cs_free(SMC91X_CS);
printk(KERN_ERR "Could not initialize smc91x\n");
}
static struct twl4030_madc_platform_data rx51_madc_data = {
.irq_line = 1,
};
@@ -259,7 +150,7 @@ static struct regulator_init_data rx51_vaux2 = {
};
/* VAUX3 - adds more power to VIO_18 rail */
static struct regulator_init_data rx51_vaux3 = {
static struct regulator_init_data rx51_vaux3_cam = {
.constraints = {
.name = "VCAM_DIG_18",
.min_uV = 1800000,
@@ -272,6 +163,22 @@ static struct regulator_init_data rx51_vaux3 = {
},
};
static struct regulator_init_data rx51_vaux3_mmc = {
.constraints = {
.name = "VMMC2_30",
.min_uV = 2800000,
.max_uV = 3000000,
.apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &rx51_vmmc2_supply,
};
static struct regulator_init_data rx51_vaux4 = {
.constraints = {
.name = "VCAM_ANA_28",
@@ -382,10 +289,8 @@ static struct twl4030_platform_data rx51_twldata = {
.vaux1 = &rx51_vaux1,
.vaux2 = &rx51_vaux2,
.vaux3 = &rx51_vaux3,
.vaux4 = &rx51_vaux4,
.vmmc1 = &rx51_vmmc1,
.vmmc2 = &rx51_vmmc2,
.vsim = &rx51_vsim,
.vdac = &rx51_vdac,
};
@@ -401,6 +306,13 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
static int __init rx51_i2c_init(void)
{
if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
system_rev >= SYSTEM_REV_B_USES_VAUX3)
rx51_twldata.vaux3 = &rx51_vaux3_mmc;
else {
rx51_twldata.vaux3 = &rx51_vaux3_cam;
rx51_twldata.vmmc2 = &rx51_vmmc2;
}
omap_register_i2c_bus(1, 2600, rx51_peripherals_i2c_board_info_1,
ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
omap_register_i2c_bus(2, 100, NULL, 0);
@@ -408,12 +320,94 @@ static int __init rx51_i2c_init(void)
return 0;
}
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
static struct mtd_partition onenand_partitions[] = {
{
.name = "bootloader",
.offset = 0,
.size = 0x20000,
.mask_flags = MTD_WRITEABLE, /* Force read-only */
},
{
.name = "config",
.offset = MTDPART_OFS_APPEND,
.size = 0x60000,
},
{
.name = "log",
.offset = MTDPART_OFS_APPEND,
.size = 0x40000,
},
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0x200000,
},
{
.name = "initfs",
.offset = MTDPART_OFS_APPEND,
.size = 0x200000,
},
{
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
static struct omap_onenand_platform_data board_onenand_data = {
.cs = 0,
.gpio_irq = 65,
.parts = onenand_partitions,
.nr_parts = ARRAY_SIZE(onenand_partitions),
};
static void __init board_onenand_init(void)
{
gpmc_onenand_init(&board_onenand_data);
}
#else
static inline void board_onenand_init(void)
{
}
#endif
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
static struct omap_smc91x_platform_data board_smc91x_data = {
.cs = 1,
.gpio_irq = 54,
.gpio_pwrdwn = 86,
.gpio_reset = 164,
.flags = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL,
};
static void __init board_smc91x_init(void)
{
omap_cfg_reg(U8_34XX_GPIO54_DOWN);
omap_cfg_reg(G25_34XX_GPIO86_OUT);
omap_cfg_reg(H19_34XX_GPIO164_OUT);
gpmc_smc91x_init(&board_smc91x_data);
}
#else
static inline void board_smc91x_init(void)
{
}
#endif
void __init rx51_peripherals_init(void)
{
platform_add_devices(rx51_peripherals_devices,
ARRAY_SIZE(rx51_peripherals_devices));
rx51_i2c_init();
rx51_init_smc91x();
board_onenand_init();
board_smc91x_init();
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2009 Texas Instruments Inc.
* Mikkel Christensen <mlc@ti.com>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/serial_8250.h>
#include <linux/smsc911x.h>
#include <mach/gpmc.h>
#define ZOOM2_SMSC911X_CS 7
#define ZOOM2_SMSC911X_GPIO 158
#define ZOOM2_QUADUART_CS 3
#define ZOOM2_QUADUART_GPIO 102
#define QUART_CLK 1843200
#define DEBUG_BASE 0x08000000
#define ZOOM2_ETHR_START DEBUG_BASE
static struct resource zoom2_smsc911x_resources[] = {
[0] = {
.start = ZOOM2_ETHR_START,
.end = ZOOM2_ETHR_START + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
static struct smsc911x_platform_config zoom2_smsc911x_config = {
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
.irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
.flags = SMSC911X_USE_32BIT,
.phy_interface = PHY_INTERFACE_MODE_MII,
};
static struct platform_device zoom2_smsc911x_device = {
.name = "smsc911x",
.id = -1,
.num_resources = ARRAY_SIZE(zoom2_smsc911x_resources),
.resource = zoom2_smsc911x_resources,
.dev = {
.platform_data = &zoom2_smsc911x_config,
},
};
static inline void __init zoom2_init_smsc911x(void)
{
int eth_cs;
unsigned long cs_mem_base;
int eth_gpio = 0;
eth_cs = ZOOM2_SMSC911X_CS;
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
return;
}
zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0;
zoom2_smsc911x_resources[0].end = cs_mem_base + 0xff;
eth_gpio = ZOOM2_SMSC911X_GPIO;
zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
eth_gpio);
return;
}
gpio_direction_input(eth_gpio);
}
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = 0x10000000,
.irq = OMAP_GPIO_IRQ(102),
.flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ,
.iotype = UPIO_MEM,
.regshift = 1,
.uartclk = QUART_CLK,
}, {
.flags = 0
}
};
static struct platform_device zoom2_debugboard_serial_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM1,
.dev = {
.platform_data = serial_platform_data,
},
};
static inline void __init zoom2_init_quaduart(void)
{
int quart_cs;
unsigned long cs_mem_base;
int quart_gpio = 0;
quart_cs = ZOOM2_QUADUART_CS;
if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem"
"for Quad UART(TL16CP754C)\n");
return;
}
quart_gpio = ZOOM2_QUADUART_GPIO;
if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
quart_gpio);
return;
}
gpio_direction_input(quart_gpio);
}
static inline int omap_zoom2_debugboard_detect(void)
{
int debug_board_detect = 0;
debug_board_detect = ZOOM2_SMSC911X_GPIO;
if (gpio_request(debug_board_detect, "Zoom2 debug board detect") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for Zoom2 debug"
"board detect\n", debug_board_detect);
return 0;
}
gpio_direction_input(debug_board_detect);
if (!gpio_get_value(debug_board_detect)) {
gpio_free(debug_board_detect);
return 0;
}
return 1;
}
static struct platform_device *zoom2_devices[] __initdata = {
&zoom2_smsc911x_device,
&zoom2_debugboard_serial_device,
};
int __init omap_zoom2_debugboard_init(void)
{
if (!omap_zoom2_debugboard_detect())
return 0;
zoom2_init_smsc911x();
zoom2_init_quaduart();
return platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2009 Texas Instruments Inc.
* Mikkel Christensen <mlc@ti.com>
*
* Modified from mach-omap2/board-ldp.c
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/common.h>
#include <mach/usb.h>
#include "mmc-twl4030.h"
static void __init omap_zoom2_init_irq(void)
{
omap2_init_common_hw(NULL);
omap_init_irq();
omap_gpio_init();
}
static struct omap_uart_config zoom2_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
static struct omap_board_config_kernel zoom2_config[] __initdata = {
{ OMAP_TAG_UART, &zoom2_uart_config },
};
static struct twl4030_gpio_platform_data zoom2_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
};
static struct twl4030_platform_data zoom2_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.gpio = &zoom2_gpio_data,
};
static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
.irq = INT_34XX_SYS_NIRQ,
.platform_data = &zoom2_twldata,
},
};
static int __init omap_i2c_init(void)
{
omap_register_i2c_bus(1, 2600, zoom2_i2c_boardinfo,
ARRAY_SIZE(zoom2_i2c_boardinfo));
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static struct twl4030_hsmmc_info mmc[] __initdata = {
{
.mmc = 1,
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
},
{} /* Terminator */
};
extern int __init omap_zoom2_debugboard_init(void);
static void __init omap_zoom2_init(void)
{
omap_i2c_init();
omap_board_config = zoom2_config;
omap_board_config_size = ARRAY_SIZE(zoom2_config);
omap_serial_init();
omap_zoom2_debugboard_init();
twl4030_mmc_init(mmc);
usb_musb_init();
}
static void __init omap_zoom2_map_io(void)
{
omap2_set_globals_343x();
omap2_map_common_io();
}
MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
.phys_io = 0x48000000,
.io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_zoom2_map_io,
.init_irq = omap_zoom2_init_irq,
.init_machine = omap_zoom2_init,
.timer = &omap_timer,
MACHINE_END

View File

@@ -91,9 +91,9 @@ static void _omap2xxx_clk_commit(struct clk *clk)
return;
prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
/* OCP barrier */
prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
}
/*
@@ -547,8 +547,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
const struct clksel_rate *clkr;
u32 last_div = 0;
printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n",
clk->name, target_rate);
pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
clk->name, target_rate);
*new_div = 1;
@@ -562,7 +562,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
/* Sanity check */
if (clkr->div <= last_div)
printk(KERN_ERR "clock: clksel_rate table not sorted "
pr_err("clock: clksel_rate table not sorted "
"for clock %s", clk->name);
last_div = clkr->div;
@@ -574,7 +574,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
}
if (!clkr->div) {
printk(KERN_ERR "clock: Could not find divisor for target "
pr_err("clock: Could not find divisor for target "
"rate %ld for clock %s parent %s\n", target_rate,
clk->name, clk->parent->name);
return ~0;
@@ -582,8 +582,8 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
*new_div = clkr->div;
printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div,
(clk->parent->rate / clkr->div));
pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
(clk->parent->rate / clkr->div));
return (clk->parent->rate / clkr->div);
}
@@ -1035,7 +1035,7 @@ void omap2_clk_disable_unused(struct clk *clk)
if ((regval32 & (1 << clk->enable_bit)) == v)
return;
printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
if (cpu_is_omap34xx()) {
omap2_clk_enable(clk);
omap2_clk_disable(clk);

View File

@@ -233,6 +233,8 @@ static struct prcm_config *curr_prcm_set;
static struct clk *vclk;
static struct clk *sclk;
static void __iomem *prcm_clksrc_ctrl;
/*-------------------------------------------------------------------------
* Omap24xx specific clock functions
*-------------------------------------------------------------------------*/
@@ -269,10 +271,9 @@ static int omap2_enable_osc_ck(struct clk *clk)
{
u32 pcc;
pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
pcc = __raw_readl(prcm_clksrc_ctrl);
__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
OMAP24XX_PRCM_CLKSRC_CTRL);
__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
return 0;
}
@@ -281,10 +282,9 @@ static void omap2_disable_osc_ck(struct clk *clk)
{
u32 pcc;
pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
pcc = __raw_readl(prcm_clksrc_ctrl);
__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
OMAP24XX_PRCM_CLKSRC_CTRL);
__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl);
}
static const struct clkops clkops_oscck = {
@@ -654,7 +654,7 @@ static u32 omap2_get_sysclkdiv(void)
{
u32 div;
div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
div = __raw_readl(prcm_clksrc_ctrl);
div &= OMAP_SYSCLKDIV_MASK;
div >>= OMAP_SYSCLKDIV_SHIFT;
@@ -714,15 +714,18 @@ int __init omap2_clk_init(void)
struct omap_clk *c;
u32 clkrate;
if (cpu_is_omap242x())
if (cpu_is_omap242x()) {
prcm_clksrc_ctrl = OMAP2420_PRCM_CLKSRC_CTRL;
cpu_mask = RATE_IN_242X;
else if (cpu_is_omap2430())
} else if (cpu_is_omap2430()) {
prcm_clksrc_ctrl = OMAP2430_PRCM_CLKSRC_CTRL;
cpu_mask = RATE_IN_243X;
}
clk_init(&omap2_clk_functions);
for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
clk_init_one(c->lk.clk);
clk_preinit(c->lk.clk);
osc_ck.rate = omap2_osc_clk_recalc(&osc_ck);
propagate_rate(&osc_ck);

View File

@@ -24,6 +24,17 @@
#include "cm-regbits-24xx.h"
#include "sdrc.h"
/* REVISIT: These should be set dynamically for CONFIG_MULTI_OMAP2 */
#ifdef CONFIG_ARCH_OMAP2420
#define OMAP_CM_REGADDR OMAP2420_CM_REGADDR
#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP2420_PRCM_CLKOUT_CTRL
#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP2420_PRCM_CLKEMUL_CTRL
#else
#define OMAP_CM_REGADDR OMAP2430_CM_REGADDR
#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP2430_PRCM_CLKOUT_CTRL
#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP2430_PRCM_CLKEMUL_CTRL
#endif
static unsigned long omap2_table_mpu_recalc(struct clk *clk);
static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);

View File

@@ -129,6 +129,9 @@ static struct omap_clk omap34xx_clks[] = {
CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2),
CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2),
CLK(NULL, "d2d_26m_fck", &d2d_26m_fck, CK_3430ES1),
CLK(NULL, "modem_fck", &modem_fck, CK_343X),
CLK(NULL, "sad2d_ick", &sad2d_ick, CK_343X),
CLK(NULL, "mad2d_ick", &mad2d_ick, CK_343X),
CLK(NULL, "gpt10_fck", &gpt10_fck, CK_343X),
CLK(NULL, "gpt11_fck", &gpt11_fck, CK_343X),
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2),
@@ -281,6 +284,8 @@ static struct omap_clk omap34xx_clks[] = {
#define MAX_DPLL_WAIT_TRIES 1000000
#define MIN_SDRC_DLL_LOCK_FREQ 83000000
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
@@ -703,6 +708,7 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
{
u32 new_div = 0;
u32 unlock_dll = 0;
unsigned long validrate, sdrcrate;
struct omap_sdrc_params *sp;
@@ -729,17 +735,22 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
if (!sp)
return -EINVAL;
pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
validrate);
pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) {
pr_debug("clock: will unlock SDRC DLL\n");
unlock_dll = 1;
}
pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
validrate);
pr_debug("clock: SDRC timing params used: %08x %08x %08x\n",
sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
/* REVISIT: SRAM code doesn't support other M2 divisors yet */
WARN_ON(new_div != 1 && new_div != 2);
/* REVISIT: Add SDRC_MR changing to this code also */
omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
sp->actim_ctrlb, new_div);
sp->actim_ctrlb, new_div, unlock_dll);
return 0;
}
@@ -956,7 +967,7 @@ int __init omap2_clk_init(void)
clk_init(&omap2_clk_functions);
for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
clk_init_one(c->lk.clk);
clk_preinit(c->lk.clk);
for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
if (c->cpu & cpu_clkflg) {

View File

@@ -27,6 +27,8 @@
#include "prm.h"
#include "prm-regbits-34xx.h"
#define OMAP_CM_REGADDR OMAP34XX_CM_REGADDR
static unsigned long omap3_dpll_recalc(struct clk *clk);
static unsigned long omap3_clkoutx2_recalc(struct clk *clk);
static void omap3_dpll_allow_idle(struct clk *clk);
@@ -1228,6 +1230,37 @@ static struct clk d2d_26m_fck = {
.recalc = &followparent_recalc,
};
static struct clk modem_fck = {
.name = "modem_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &sys_ck,
.init = &omap2_init_clk_clkdm,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_MODEM_SHIFT,
.clkdm_name = "d2d_clkdm",
.recalc = &followparent_recalc,
};
static struct clk sad2d_ick = {
.name = "sad2d_ick",
.ops = &clkops_omap2_dflt_wait,
.parent = &l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SAD2D_SHIFT,
.clkdm_name = "d2d_clkdm",
.recalc = &followparent_recalc,
};
static struct clk mad2d_ick = {
.name = "mad2d_ick",
.ops = &clkops_omap2_dflt_wait,
.parent = &l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
.enable_bit = OMAP3430_EN_MAD2D_SHIFT,
.clkdm_name = "d2d_clkdm",
.recalc = &followparent_recalc,
};
static const struct clksel omap343x_gpt_clksel[] = {
{ .parent = &omap_32k_fck, .rates = gpt_32k_rates },
{ .parent = &sys_ck, .rates = gpt_sys_rates },
@@ -1945,8 +1978,6 @@ static struct clk usb_l4_ick = {
.recalc = &omap2_clksel_recalc,
};
/* XXX MDM_INTC_ICK, SAD2D_ICK ?? */
/* SECURITY_L4_ICK2 based clocks */
static struct clk security_l4_ick2 = {

View File

@@ -195,7 +195,7 @@ static struct clockdomain sgx_clkdm = {
static struct clockdomain d2d_clkdm = {
.name = "d2d_clkdm",
.pwrdm = { .name = "core_pwrdm" },
.flags = CLKDM_CAN_HWSUP,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};

View File

@@ -145,6 +145,8 @@
#define OMAP3430_CLKACTIVITY_MPU_MASK (1 << 0)
/* CM_FCLKEN1_CORE specific bits */
#define OMAP3430_EN_MODEM (1 << 31)
#define OMAP3430_EN_MODEM_SHIFT 31
/* CM_ICLKEN1_CORE specific bits */
#define OMAP3430_EN_ICR (1 << 29)
@@ -161,6 +163,8 @@
#define OMAP3430_EN_MAILBOXES_SHIFT 7
#define OMAP3430_EN_OMAPCTRL (1 << 6)
#define OMAP3430_EN_OMAPCTRL_SHIFT 6
#define OMAP3430_EN_SAD2D (1 << 3)
#define OMAP3430_EN_SAD2D_SHIFT 3
#define OMAP3430_EN_SDRC (1 << 1)
#define OMAP3430_EN_SDRC_SHIFT 1
@@ -176,6 +180,10 @@
#define OMAP3430_EN_DES1 (1 << 0)
#define OMAP3430_EN_DES1_SHIFT 0
/* CM_ICLKEN3_CORE */
#define OMAP3430_EN_MAD2D_SHIFT 3
#define OMAP3430_EN_MAD2D (1 << 3)
/* CM_FCLKEN3_CORE specific bits */
#define OMAP3430ES2_EN_TS_SHIFT 1
#define OMAP3430ES2_EN_TS_MASK (1 << 1)
@@ -231,6 +239,8 @@
#define OMAP3430ES2_ST_CPEFUSE_MASK (1 << 0)
/* CM_AUTOIDLE1_CORE */
#define OMAP3430_AUTO_MODEM (1 << 31)
#define OMAP3430_AUTO_MODEM_SHIFT 31
#define OMAP3430ES2_AUTO_MMC3 (1 << 30)
#define OMAP3430ES2_AUTO_MMC3_SHIFT 30
#define OMAP3430ES2_AUTO_ICR (1 << 29)
@@ -287,6 +297,8 @@
#define OMAP3430_AUTO_HSOTGUSB_SHIFT 4
#define OMAP3430ES1_AUTO_D2D (1 << 3)
#define OMAP3430ES1_AUTO_D2D_SHIFT 3
#define OMAP3430_AUTO_SAD2D (1 << 3)
#define OMAP3430_AUTO_SAD2D_SHIFT 3
#define OMAP3430_AUTO_SSI (1 << 0)
#define OMAP3430_AUTO_SSI_SHIFT 0
@@ -308,6 +320,8 @@
#define OMAP3430ES2_AUTO_USBTLL (1 << 2)
#define OMAP3430ES2_AUTO_USBTLL_SHIFT 2
#define OMAP3430ES2_AUTO_USBTLL_MASK (1 << 2)
#define OMAP3430_AUTO_MAD2D_SHIFT 3
#define OMAP3430_AUTO_MAD2D (1 << 3)
/* CM_CLKSEL_CORE */
#define OMAP3430_CLKSEL_SSI_SHIFT 8

View File

@@ -16,17 +16,12 @@
#include "prcm-common.h"
#ifndef __ASSEMBLER__
#define OMAP_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
#else
#define OMAP2420_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
#define OMAP2430_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
#define OMAP34XX_CM_REGADDR(module, reg) \
IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
#endif
/*
* Architecture-specific global CM registers
@@ -38,6 +33,7 @@
#define OMAP3430_CM_SYSCONFIG OMAP_CM_REGADDR(OCP_MOD, 0x0010)
#define OMAP3430_CM_POLCTRL OMAP_CM_REGADDR(OCP_MOD, 0x009c)
#define OMAP3_CM_CLKOUT_CTRL_OFFSET 0x0070
#define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
/*

View File

@@ -0,0 +1,330 @@
/*
* linux/arch/arm/mach-omap2/gpmc-onenand.c
*
* Copyright (C) 2006 - 2009 Nokia Corporation
* Contacts: Juha Yrjola
* Tony Lindgren
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/io.h>
#include <asm/mach/flash.h>
#include <mach/onenand.h>
#include <mach/board.h>
#include <mach/gpmc.h>
static struct omap_onenand_platform_data *gpmc_onenand_data;
static struct platform_device gpmc_onenand_device = {
.name = "omap2-onenand",
.id = -1,
};
static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
{
struct gpmc_timings t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_aavdh = 7;
const int t_ce = 76;
const int t_aa = 76;
const int t_oe = 20;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_ds = 30;
const int t_wpl = 40;
const int t_wph = 30;
memset(&t, 0, sizeof(t));
t.sync_clk = 0;
t.cs_on = 0;
t.adv_on = 0;
/* Read */
t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
t.cs_rd_off = t.oe_off;
t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
/* Write */
t.adv_wr_off = t.adv_rd_off;
t.we_on = t.oe_on;
if (cpu_is_omap34xx()) {
t.wr_data_mux_bus = t.we_on;
t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
}
t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
/* Configure GPMC for asynchronous read */
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
GPMC_CONFIG1_DEVICESIZE_16 |
GPMC_CONFIG1_MUXADDDATA);
return gpmc_cs_set_timings(cs, &t);
}
static void set_onenand_cfg(void __iomem *onenand_base, int latency,
int sync_read, int sync_write, int hf)
{
u32 reg;
reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
ONENAND_SYS_CFG1_BL_16;
if (sync_read)
reg |= ONENAND_SYS_CFG1_SYNC_READ;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
if (sync_write)
reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
if (hf)
reg |= ONENAND_SYS_CFG1_HF;
else
reg &= ~ONENAND_SYS_CFG1_HF;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}
static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
void __iomem *onenand_base,
int freq)
{
struct gpmc_timings t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_ds = 30;
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
int first_time = 0, hf = 0, sync_read = 0, sync_write = 0;
int err, ticks_cez;
int cs = cfg->cs;
u32 reg;
if (cfg->flags & ONENAND_SYNC_READ) {
sync_read = 1;
} else if (cfg->flags & ONENAND_SYNC_READWRITE) {
sync_read = 1;
sync_write = 1;
}
if (!freq) {
/* Very first call freq is not known */
err = omap2_onenand_set_async_mode(cs, onenand_base);
if (err)
return err;
reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
switch ((reg >> 4) & 0xf) {
case 0:
freq = 40;
break;
case 1:
freq = 54;
break;
case 2:
freq = 66;
break;
case 3:
freq = 83;
break;
case 4:
freq = 104;
break;
default:
freq = 54;
break;
}
first_time = 1;
}
switch (freq) {
case 83:
min_gpmc_clk_period = 12; /* 83 MHz */
t_ces = 5;
t_avds = 4;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 9;
break;
case 66:
min_gpmc_clk_period = 15; /* 66 MHz */
t_ces = 6;
t_avds = 5;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 11;
break;
default:
min_gpmc_clk_period = 18; /* 54 MHz */
t_ces = 7;
t_avds = 7;
t_avdh = 7;
t_ach = 9;
t_aavdh = 7;
t_rdyo = 15;
sync_write = 0;
break;
}
tick_ns = gpmc_ticks_to_ns(1);
div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
gpmc_clk_ns = gpmc_ticks_to_ns(div);
if (gpmc_clk_ns < 15) /* >66Mhz */
hf = 1;
if (hf)
latency = 6;
else if (gpmc_clk_ns >= 25) /* 40 MHz*/
latency = 3;
else
latency = 4;
if (first_time)
set_onenand_cfg(onenand_base, latency,
sync_read, sync_write, hf);
if (div == 1) {
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
reg |= (1 << 7);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
reg |= (1 << 7);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
reg |= (1 << 7);
reg |= (1 << 23);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
} else {
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
reg &= ~(1 << 7);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
reg &= ~(1 << 7);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
reg &= ~(1 << 7);
reg &= ~(1 << 23);
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
}
/* Set synchronous read timings */
memset(&t, 0, sizeof(t));
t.sync_clk = min_gpmc_clk_period;
t.cs_on = 0;
t.adv_on = 0;
fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
t.page_burst_access = gpmc_clk_ns;
/* Read */
t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
t.cs_rd_off = t.oe_off;
ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
ticks_cez);
/* Write */
if (sync_write) {
t.adv_wr_off = t.adv_rd_off;
t.we_on = 0;
t.we_off = t.cs_rd_off;
t.cs_wr_off = t.cs_rd_off;
t.wr_cycle = t.rd_cycle;
if (cpu_is_omap34xx()) {
t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
gpmc_ns_to_ticks(min_gpmc_clk_period +
t_rdyo));
t.wr_access = t.access;
}
} else {
t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
t_avdp, t_cer));
t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
if (cpu_is_omap34xx()) {
t.wr_data_mux_bus = t.we_on;
t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
}
}
/* Configure GPMC for synchronous read */
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
GPMC_CONFIG1_WRAPBURST_SUPP |
GPMC_CONFIG1_READMULTIPLE_SUPP |
(sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
(sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
(sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
GPMC_CONFIG1_PAGE_LEN(2) |
(cpu_is_omap34xx() ? 0 :
(GPMC_CONFIG1_WAIT_READ_MON |
GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
GPMC_CONFIG1_DEVICESIZE_16 |
GPMC_CONFIG1_DEVICETYPE_NOR |
GPMC_CONFIG1_MUXADDDATA);
err = gpmc_cs_set_timings(cs, &t);
if (err)
return err;
set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf);
return 0;
}
static int gpmc_onenand_setup(void __iomem *onenand_base, int freq)
{
struct device *dev = &gpmc_onenand_device.dev;
/* Set sync timings in GPMC */
if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
freq) < 0) {
dev_err(dev, "Unable to set synchronous mode\n");
return -EINVAL;
}
return 0;
}
void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
{
gpmc_onenand_data = _onenand_data;
gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
if (cpu_is_omap24xx() &&
(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
}
if (platform_device_register(&gpmc_onenand_device) < 0) {
printk(KERN_ERR "Unable to register OneNAND device\n");
return;
}
}

View File

@@ -0,0 +1,189 @@
/*
* linux/arch/arm/mach-omap2/gpmc-smc91x.c
*
* Copyright (C) 2009 Nokia Corporation
* Contact: Tony Lindgren
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/smc91x.h>
#include <mach/board.h>
#include <mach/gpmc.h>
#include <mach/gpmc-smc91x.h>
static struct omap_smc91x_platform_data *gpmc_cfg;
static struct resource gpmc_smc91x_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.flags = IORESOURCE_IRQ,
},
};
static struct smc91x_platdata gpmc_smc91x_info = {
.flags = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0,
};
static struct platform_device gpmc_smc91x_device = {
.name = "smc91x",
.id = -1,
.num_resources = ARRAY_SIZE(gpmc_smc91x_resources),
.resource = gpmc_smc91x_resources,
.dev = {
.platform_data = &gpmc_smc91x_info,
},
};
/*
* Set the gpmc timings for smc91c96. The timings are taken
* from the data sheet available at:
* http://www.smsc.com/main/catalog/lan91c96.html
* REVISIT: Level shifters can add at least to the access latency.
*/
static int smc91c96_gpmc_retime(void)
{
struct gpmc_timings t;
const int t3 = 10; /* Figure 12.2 read and 12.4 write */
const int t4_r = 20; /* Figure 12.2 read */
const int t4_w = 5; /* Figure 12.4 write */
const int t5 = 25; /* Figure 12.2 read */
const int t6 = 15; /* Figure 12.2 read */
const int t7 = 5; /* Figure 12.4 write */
const int t8 = 5; /* Figure 12.4 write */
const int t20 = 185; /* Figure 12.2 read and 12.4 write */
u32 l;
memset(&t, 0, sizeof(t));
/* Read timings */
t.cs_on = 0;
t.adv_on = t.cs_on;
t.oe_on = t.adv_on + t3;
t.access = t.oe_on + t5;
t.oe_off = t.access;
t.adv_rd_off = t.oe_off + max(t4_r, t6);
t.cs_rd_off = t.oe_off;
t.rd_cycle = t20 - t.oe_on;
/* Write timings */
t.we_on = t.adv_on + t3;
if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) {
t.wr_data_mux_bus = t.we_on;
t.we_off = t.wr_data_mux_bus + t7;
} else
t.we_off = t.we_on + t7;
if (cpu_is_omap34xx())
t.wr_access = t.we_off;
t.adv_wr_off = t.we_off + max(t4_w, t8);
t.cs_wr_off = t.we_off + t4_w;
t.wr_cycle = t20 - t.we_on;
l = GPMC_CONFIG1_DEVICESIZE_16;
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
l |= GPMC_CONFIG1_MUXADDDATA;
if (gpmc_cfg->flags & GPMC_READ_MON)
l |= GPMC_CONFIG1_WAIT_READ_MON;
if (gpmc_cfg->flags & GPMC_WRITE_MON)
l |= GPMC_CONFIG1_WAIT_WRITE_MON;
if (gpmc_cfg->wait_pin)
l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin);
gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l);
/*
* FIXME: Calculate the address and data bus muxed timings.
* Note that at least adv_rd_off needs to be changed according
* to omap3430 TRM Figure 11-11. Are the sdp boards using the
* FPGA in between smc91x and omap as the timings are different
* from above?
*/
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
return 0;
return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
}
/*
* Initialize smc91x device connected to the GPMC. Note that we
* assume that pin multiplexing is done in the board-*.c file,
* or in the bootloader.
*/
void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
{
unsigned long cs_mem_base;
int ret;
gpmc_cfg = board_data;
if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
gpmc_cfg->retime = smc91c96_gpmc_retime;
if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
return;
}
gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
if (gpmc_cfg->retime) {
ret = gpmc_cfg->retime();
if (ret != 0)
goto free1;
}
if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0)
goto free1;
gpio_direction_input(gpmc_cfg->gpio_irq);
gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
if (gpmc_cfg->gpio_pwrdwn) {
ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown");
if (ret)
goto free2;
gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0);
}
if (gpmc_cfg->gpio_reset) {
ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset");
if (ret)
goto free3;
gpio_direction_output(gpmc_cfg->gpio_reset, 0);
gpio_set_value(gpmc_cfg->gpio_reset, 1);
msleep(100);
gpio_set_value(gpmc_cfg->gpio_reset, 0);
}
if (platform_device_register(&gpmc_smc91x_device) < 0) {
printk(KERN_ERR "Unable to register smc91x device\n");
gpio_free(gpmc_cfg->gpio_reset);
goto free3;
}
return;
free3:
if (gpmc_cfg->gpio_pwrdwn)
gpio_free(gpmc_cfg->gpio_pwrdwn);
free2:
gpio_free(gpmc_cfg->gpio_irq);
free1:
gpmc_cs_free(gpmc_cfg->cs);
printk(KERN_ERR "Could not initialize smc91x\n");
}

View File

@@ -5,6 +5,9 @@
*
* Author: Juha Yrjola
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* 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.
@@ -424,6 +427,9 @@ void __init gpmc_init(void)
} else if (cpu_is_omap34xx()) {
ck = "gpmc_fck";
l = OMAP34XX_GPMC_BASE;
} else if (cpu_is_omap44xx()) {
ck = "gpmc_fck";
l = OMAP44XX_GPMC_BASE;
}
gpmc_l3_clk = clk_get(NULL, ck);

View File

@@ -6,6 +6,9 @@
* Copyright (C) 2005 Nokia Corporation
* Written by Tony Lindgren <tony@atomide.com>
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* 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.
@@ -200,7 +203,10 @@ void __init omap2_check_revision(void)
omap24xx_check_revision();
else if (cpu_is_omap34xx())
omap34xx_check_revision();
else
else if (cpu_is_omap44xx()) {
printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n");
return;
} else
pr_err("OMAP revision unknown, please fix!\n");
/*

View File

@@ -4,12 +4,14 @@
* OMAP2 I/O mapping code
*
* Copyright (C) 2005 Nokia Corporation
* Copyright (C) 2007 Texas Instruments
* Copyright (C) 2007-2009 Texas Instruments
*
* Author:
* Juha Yrjola <juha.yrjola@nokia.com>
* Syed Khasim <x0khasim@ti.com>
*
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* 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.
@@ -30,6 +32,7 @@
#include <mach/sdrc.h>
#include <mach/gpmc.h>
#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
#include "clock.h"
#include <mach/powerdomain.h>
@@ -38,7 +41,7 @@
#include <mach/clockdomain.h>
#include "clockdomains.h"
#endif
/*
* The machine specific code may provide the extra mapping besides the
* default mapping provided here.
@@ -166,6 +169,46 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
},
};
#endif
#ifdef CONFIG_ARCH_OMAP4
static struct map_desc omap44xx_io_desc[] __initdata = {
{
.virtual = L3_44XX_VIRT,
.pfn = __phys_to_pfn(L3_44XX_PHYS),
.length = L3_44XX_SIZE,
.type = MT_DEVICE,
},
{
.virtual = L4_44XX_VIRT,
.pfn = __phys_to_pfn(L4_44XX_PHYS),
.length = L4_44XX_SIZE,
.type = MT_DEVICE,
},
{
.virtual = L4_WK_44XX_VIRT,
.pfn = __phys_to_pfn(L4_WK_44XX_PHYS),
.length = L4_WK_44XX_SIZE,
.type = MT_DEVICE,
},
{
.virtual = OMAP44XX_GPMC_VIRT,
.pfn = __phys_to_pfn(OMAP44XX_GPMC_PHYS),
.length = OMAP44XX_GPMC_SIZE,
.type = MT_DEVICE,
},
{
.virtual = L4_PER_44XX_VIRT,
.pfn = __phys_to_pfn(L4_PER_44XX_PHYS),
.length = L4_PER_44XX_SIZE,
.type = MT_DEVICE,
},
{
.virtual = L4_EMU_44XX_VIRT,
.pfn = __phys_to_pfn(L4_EMU_44XX_PHYS),
.length = L4_EMU_44XX_SIZE,
.type = MT_DEVICE,
},
};
#endif
void __init omap2_map_common_io(void)
{
@@ -183,6 +226,9 @@ void __init omap2_map_common_io(void)
iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
#endif
#if defined(CONFIG_ARCH_OMAP4)
iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc));
#endif
/* Normally devicemaps_init() would flush caches and tlb after
* mdesc->map_io(), but we must also do it here because of the CPU
* revision check below.
@@ -198,9 +244,11 @@ void __init omap2_map_common_io(void)
void __init omap2_init_common_hw(struct omap_sdrc_params *sp)
{
omap2_mux_init();
#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */
pwrdm_init(powerdomains_omap);
clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
omap2_clk_init();
omap2_sdrc_init(sp);
#endif
gpmc_init();
}

View File

@@ -28,7 +28,6 @@
#define INTC_MIR_CLEAR0 0x0088
#define INTC_MIR_SET0 0x008c
#define INTC_PENDING_IRQ0 0x0098
/* Number of IRQ state bits in each MIR register */
#define IRQ_BITS_PER_REG 32
@@ -134,7 +133,6 @@ static struct irq_chip omap_irq_chip = {
.ack = omap_mask_ack_irq,
.mask = omap_mask_irq,
.unmask = omap_unmask_irq,
.disable = omap_mask_irq,
};
static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
@@ -157,6 +155,22 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
}
int omap_irq_pending(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
struct omap_irq_bank *bank = irq_banks + i;
int irq;
for (irq = 0; irq < bank->nr_irqs; irq += 32)
if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
((irq >> 5) << 5)))
return 1;
}
return 0;
}
void __init omap_init_irq(void)
{
unsigned long nr_of_irqs = 0;

View File

@@ -16,8 +16,8 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
#include <linux/regulator/consumer.h>
#include <mach/hardware.h>
#include <mach/control.h>
@@ -26,32 +26,10 @@
#include "mmc-twl4030.h"
#if defined(CONFIG_TWL4030_CORE) && \
#if defined(CONFIG_REGULATOR) && \
(defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
#define LDO_CLR 0x00
#define VSEL_S2_CLR 0x40
#define VMMC1_DEV_GRP 0x27
#define VMMC1_CLR 0x00
#define VMMC1_315V 0x03
#define VMMC1_300V 0x02
#define VMMC1_285V 0x01
#define VMMC1_185V 0x00
#define VMMC1_DEDICATED 0x2A
#define VMMC2_DEV_GRP 0x2B
#define VMMC2_CLR 0x40
#define VMMC2_315V 0x0c
#define VMMC2_300V 0x0b
#define VMMC2_285V 0x0a
#define VMMC2_280V 0x09
#define VMMC2_260V 0x08
#define VMMC2_185V 0x06
#define VMMC2_DEDICATED 0x2E
#define VMMC_DEV_GRP_P1 0x20
static u16 control_pbias_offset;
static u16 control_devconf1_offset;
@@ -59,19 +37,16 @@ static u16 control_devconf1_offset;
static struct twl_mmc_controller {
struct omap_mmc_platform_data *mmc;
u8 twl_vmmc_dev_grp;
u8 twl_mmc_dedicated;
char name[HSMMC_NAME_LEN + 1];
} hsmmc[OMAP34XX_NR_MMC] = {
{
.twl_vmmc_dev_grp = VMMC1_DEV_GRP,
.twl_mmc_dedicated = VMMC1_DEDICATED,
},
{
.twl_vmmc_dev_grp = VMMC2_DEV_GRP,
.twl_mmc_dedicated = VMMC2_DEDICATED,
},
};
/* Vcc == configured supply
* Vcc_alt == optional
* - MMC1, supply for DAT4..DAT7
* - MMC2/MMC2, external level shifter voltage supply, for
* chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
*/
struct regulator *vcc;
struct regulator *vcc_aux;
char name[HSMMC_NAME_LEN + 1];
} hsmmc[OMAP34XX_NR_MMC];
static int twl_mmc_card_detect(int irq)
{
@@ -117,16 +92,60 @@ static int twl_mmc_late_init(struct device *dev)
int ret = 0;
int i;
ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
if (ret)
goto done;
ret = gpio_direction_input(mmc->slots[0].switch_pin);
if (ret)
goto err;
/* MMC/SD/SDIO doesn't require a card detect switch */
if (gpio_is_valid(mmc->slots[0].switch_pin)) {
ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
if (ret)
goto done;
ret = gpio_direction_input(mmc->slots[0].switch_pin);
if (ret)
goto err;
}
/* require at least main regulator */
for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
if (hsmmc[i].name == mmc->slots[0].name) {
struct regulator *reg;
hsmmc[i].mmc = mmc;
reg = regulator_get(dev, "vmmc");
if (IS_ERR(reg)) {
dev_dbg(dev, "vmmc regulator missing\n");
/* HACK: until fixed.c regulator is usable,
* we don't require a main regulator
* for MMC2 or MMC3
*/
if (i != 0)
break;
ret = PTR_ERR(reg);
goto err;
}
hsmmc[i].vcc = reg;
mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg);
/* allow an aux regulator */
reg = regulator_get(dev, "vmmc_aux");
hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg;
/* UGLY HACK: workaround regulator framework bugs.
* When the bootloader leaves a supply active, it's
* initialized with zero usecount ... and we can't
* disable it without first enabling it. Until the
* framework is fixed, we need a workaround like this
* (which is safe for MMC, but not in general).
*/
if (regulator_is_enabled(hsmmc[i].vcc) > 0) {
regulator_enable(hsmmc[i].vcc);
regulator_disable(hsmmc[i].vcc);
}
if (hsmmc[i].vcc_aux) {
if (regulator_is_enabled(reg) > 0) {
regulator_enable(reg);
regulator_disable(reg);
}
}
break;
}
}
@@ -173,96 +192,6 @@ static int twl_mmc_resume(struct device *dev, int slot)
#define twl_mmc_resume NULL
#endif
/*
* Sets the MMC voltage in twl4030
*/
#define MMC1_OCR (MMC_VDD_165_195 \
|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
#define MMC2_OCR (MMC_VDD_165_195 \
|MMC_VDD_25_26|MMC_VDD_26_27|MMC_VDD_27_28 \
|MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32)
static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd)
{
int ret;
u8 vmmc = 0, dev_grp_val;
if (!vdd)
goto doit;
if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) {
/* VMMC1: max 220 mA. And for 8-bit mode,
* VSIM: max 50 mA
*/
switch (1 << vdd) {
case MMC_VDD_165_195:
vmmc = VMMC1_185V;
/* and VSIM_180V */
break;
case MMC_VDD_28_29:
vmmc = VMMC1_285V;
/* and VSIM_280V */
break;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
vmmc = VMMC1_300V;
/* and VSIM_300V */
break;
case MMC_VDD_31_32:
vmmc = VMMC1_315V;
/* error if VSIM needed */
break;
default:
return -EINVAL;
}
} else if (c->twl_vmmc_dev_grp == VMMC2_DEV_GRP) {
/* VMMC2: max 100 mA */
switch (1 << vdd) {
case MMC_VDD_165_195:
vmmc = VMMC2_185V;
break;
case MMC_VDD_25_26:
case MMC_VDD_26_27:
vmmc = VMMC2_260V;
break;
case MMC_VDD_27_28:
vmmc = VMMC2_280V;
break;
case MMC_VDD_28_29:
vmmc = VMMC2_285V;
break;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
vmmc = VMMC2_300V;
break;
case MMC_VDD_31_32:
vmmc = VMMC2_315V;
break;
default:
return -EINVAL;
}
} else {
return -EINVAL;
}
doit:
if (vdd)
dev_grp_val = VMMC_DEV_GRP_P1; /* Power up */
else
dev_grp_val = LDO_CLR; /* Power down */
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
dev_grp_val, c->twl_vmmc_dev_grp);
if (ret || !vdd)
return ret;
ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
vmmc, c->twl_mmc_dedicated);
return ret;
}
static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
@@ -273,11 +202,13 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
/*
* Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
* card using the same TWL VMMC1 supply (hsmmc[0]); OMAP has both
* card with Vcc regulator (from twl4030 or whatever). OMAP has both
* 1.8V and 3.0V modes, controlled by the PBIAS register.
*
* In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which
* is most naturally TWL VSIM; those pins also use PBIAS.
*
* FIXME handle VMMC1A as needed ...
*/
if (power_on) {
if (cpu_is_omap2430()) {
@@ -300,7 +231,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
ret = twl_mmc_set_voltage(c, vdd);
ret = mmc_regulator_set_ocr(c->vcc, vdd);
/* 100ms delay required for PBIAS configuration */
msleep(100);
@@ -316,7 +247,7 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
reg &= ~OMAP2_PBIASLITEPWRDNZ0;
omap_ctrl_writel(reg, control_pbias_offset);
ret = twl_mmc_set_voltage(c, 0);
ret = mmc_regulator_set_ocr(c->vcc, 0);
/* 100ms delay required for PBIAS configuration */
msleep(100);
@@ -329,19 +260,33 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
return ret;
}
static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd)
static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd)
{
int ret;
int ret = 0;
struct twl_mmc_controller *c = &hsmmc[1];
struct omap_mmc_platform_data *mmc = dev->platform_data;
/* If we don't see a Vcc regulator, assume it's a fixed
* voltage always-on regulator.
*/
if (!c->vcc)
return 0;
/*
* Assume TWL VMMC2 (hsmmc[1]) is used only to power the card ... OMAP
* Assume Vcc regulator is used only to power the card ... OMAP
* VDDS is used to power the pins, optionally with a transceiver to
* support cards using voltages other than VDDS (1.8V nominal). When a
* transceiver is used, DAT3..7 are muxed as transceiver control pins.
*
* In some cases this regulator won't support enable/disable;
* e.g. it's a fixed rail for a WLAN chip.
*
* In other cases vcc_aux switches interface power. Example, for
* eMMC cards it represents VccQ. Sometimes transceivers or SDIO
* chips/cards need an interface voltage rail too.
*/
if (power_on) {
/* only MMC2 supports a CLKIN */
if (mmc->slots[0].internal_clock) {
u32 reg;
@@ -349,24 +294,23 @@ static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vd
reg |= OMAP2_MMCSDIO2ADPCLKISEL;
omap_ctrl_writel(reg, control_devconf1_offset);
}
ret = twl_mmc_set_voltage(c, vdd);
ret = mmc_regulator_set_ocr(c->vcc, vdd);
/* enable interface voltage rail, if needed */
if (ret == 0 && c->vcc_aux) {
ret = regulator_enable(c->vcc_aux);
if (ret < 0)
ret = mmc_regulator_set_ocr(c->vcc, 0);
}
} else {
ret = twl_mmc_set_voltage(c, 0);
if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0)
ret = regulator_disable(c->vcc_aux);
if (ret == 0)
ret = mmc_regulator_set_ocr(c->vcc, 0);
}
return ret;
}
static int twl_mmc3_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
/*
* Assume MMC3 has self-powered device connected, for example on-board
* chip with external power source.
*/
return 0;
}
static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
@@ -412,10 +356,10 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
mmc->slots[0].wires = c->wires;
mmc->slots[0].internal_clock = !c->ext_clock;
mmc->dma_mask = 0xffffffff;
mmc->init = twl_mmc_late_init;
/* note: twl4030 card detect GPIOs normally switch VMMCx ... */
/* note: twl4030 card detect GPIOs can disable VMMCx ... */
if (gpio_is_valid(c->gpio_cd)) {
mmc->init = twl_mmc_late_init;
mmc->cleanup = twl_mmc_cleanup;
mmc->suspend = twl_mmc_suspend;
mmc->resume = twl_mmc_resume;
@@ -439,26 +383,28 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
} else
mmc->slots[0].gpio_wp = -EINVAL;
/* NOTE: we assume OMAP's MMC1 and MMC2 use
* the TWL4030's VMMC1 and VMMC2, respectively;
* and that MMC3 device has it's own power source.
/* NOTE: MMC slots should have a Vcc regulator set up.
* This may be from a TWL4030-family chip, another
* controllable regulator, or a fixed supply.
*
* temporary HACK: ocr_mask instead of fixed supply
*/
mmc->slots[0].ocr_mask = c->ocr_mask;
switch (c->mmc) {
case 1:
/* on-chip level shifting via PBIAS0/PBIAS1 */
mmc->slots[0].set_power = twl_mmc1_set_power;
mmc->slots[0].ocr_mask = MMC1_OCR;
break;
case 2:
mmc->slots[0].set_power = twl_mmc2_set_power;
if (c->transceiver)
mmc->slots[0].ocr_mask = MMC2_OCR;
else
mmc->slots[0].ocr_mask = MMC_VDD_165_195;
break;
if (c->ext_clock)
c->transceiver = 1;
if (c->transceiver && c->wires > 4)
c->wires = 4;
/* FALLTHROUGH */
case 3:
mmc->slots[0].set_power = twl_mmc3_set_power;
mmc->slots[0].ocr_mask = MMC_VDD_165_195;
/* off-chip level shifting, or none */
mmc->slots[0].set_power = twl_mmc23_set_power;
break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);

View File

@@ -16,9 +16,10 @@ struct twl4030_hsmmc_info {
int gpio_wp; /* or -EINVAL */
char *name; /* or NULL for default */
struct device *dev; /* returned: pointer to mmc adapter */
int ocr_mask; /* temporary HACK */
};
#if defined(CONFIG_TWL4030_CORE) && \
#if defined(CONFIG_REGULATOR) && \
(defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))

View File

@@ -0,0 +1,152 @@
/*
* OMAP Power Management debug routines
*
* Copyright (C) 2005 Texas Instruments, Inc.
* Copyright (C) 2006-2008 Nokia Corporation
*
* Written by:
* Richard Woodruff <r-woodruff2@ti.com>
* Tony Lindgren
* Juha Yrjola
* Amit Kucheria <amit.kucheria@nokia.com>
* Igor Stoppa <igor.stoppa@nokia.com>
* Jouni Hogander
*
* Based on pm.c for omap2
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <mach/clock.h>
#include <mach/board.h>
#include "prm.h"
#include "cm.h"
#include "pm.h"
int omap2_pm_debug;
#define DUMP_PRM_MOD_REG(mod, reg) \
regs[reg_count].name = #mod "." #reg; \
regs[reg_count++].val = prm_read_mod_reg(mod, reg)
#define DUMP_CM_MOD_REG(mod, reg) \
regs[reg_count].name = #mod "." #reg; \
regs[reg_count++].val = cm_read_mod_reg(mod, reg)
#define DUMP_PRM_REG(reg) \
regs[reg_count].name = #reg; \
regs[reg_count++].val = __raw_readl(reg)
#define DUMP_CM_REG(reg) \
regs[reg_count].name = #reg; \
regs[reg_count++].val = __raw_readl(reg)
#define DUMP_INTC_REG(reg, off) \
regs[reg_count].name = #reg; \
regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
void omap2_pm_dump(int mode, int resume, unsigned int us)
{
struct reg {
const char *name;
u32 val;
} regs[32];
int reg_count = 0, i;
const char *s1 = NULL, *s2 = NULL;
if (!resume) {
#if 0
/* MPU */
DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
#endif
#if 0
/* INTC */
DUMP_INTC_REG(INTC_MIR0, 0x0084);
DUMP_INTC_REG(INTC_MIR1, 0x00a4);
DUMP_INTC_REG(INTC_MIR2, 0x00c4);
#endif
#if 0
DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
if (cpu_is_omap24xx()) {
DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
OMAP2_PRCM_CLKEMUL_CTRL_OFFSET);
DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
}
DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
#endif
#if 0
/* DSP */
if (cpu_is_omap24xx()) {
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
}
#endif
} else {
DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
if (cpu_is_omap24xx())
DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
#if 1
DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
#endif
}
switch (mode) {
case 0:
s1 = "full";
s2 = "retention";
break;
case 1:
s1 = "MPU";
s2 = "retention";
break;
case 2:
s1 = "MPU";
s2 = "idle";
break;
}
if (!resume)
#ifdef CONFIG_NO_HZ
printk(KERN_INFO
"--- Going to %s %s (next timer after %u ms)\n", s1, s2,
jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
jiffies));
#else
printk(KERN_INFO "--- Going to %s %s\n", s1, s2);
#endif
else
printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n",
us / 1000, us % 1000);
for (i = 0; i < reg_count; i++)
printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
}

View File

@@ -1,111 +0,0 @@
/*
* linux/arch/arm/mach-omap2/pm.c
*
* OMAP2 Power Management Routines
*
* Copyright (C) 2006 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
*
* Copyright (C) 2005 Texas Instruments, Inc.
* Richard Woodruff <r-woodruff2@ti.com>
*
* Based on pm.c for omap1
*
* 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.
*/
#include <linux/suspend.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/atomic.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <mach/irqs.h>
#include <mach/clock.h>
#include <mach/sram.h>
#include <mach/pm.h>
static struct clk *vclk;
static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
static void (*saved_idle)(void);
extern void __init pmdomain_init(void);
extern void pmdomain_set_autoidle(void);
static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
void omap2_pm_idle(void)
{
local_irq_disable();
local_fiq_disable();
if (need_resched()) {
local_fiq_enable();
local_irq_enable();
return;
}
omap2_sram_idle();
local_fiq_enable();
local_irq_enable();
}
static int omap2_pm_prepare(void)
{
/* We cannot sleep in idle until we have resumed */
saved_idle = pm_idle;
pm_idle = NULL;
return 0;
}
static int omap2_pm_suspend(void)
{
return 0;
}
static int omap2_pm_enter(suspend_state_t state)
{
int ret = 0;
switch (state)
{
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
ret = omap2_pm_suspend();
break;
default:
ret = -EINVAL;
}
return ret;
}
static void omap2_pm_finish(void)
{
pm_idle = saved_idle;
}
static struct platform_suspend_ops omap_pm_ops = {
.prepare = omap2_pm_prepare,
.enter = omap2_pm_enter,
.finish = omap2_pm_finish,
.valid = suspend_valid_only_mem,
};
static int __init omap2_pm_init(void)
{
return 0;
}
__initcall(omap2_pm_init);

38
arch/arm/mach-omap2/pm.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* OMAP2/3 Power Management Routines
*
* Copyright (C) 2008 Nokia Corporation
* Jouni Hogander
*
* 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.
*/
#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
#define __ARCH_ARM_MACH_OMAP2_PM_H
extern int omap2_pm_init(void);
extern int omap3_pm_init(void);
#ifdef CONFIG_PM_DEBUG
extern void omap2_pm_dump(int mode, int resume, unsigned int us);
extern int omap2_pm_debug;
#else
#define omap2_pm_dump(mode, resume, us) do {} while (0);
#define omap2_pm_debug 0
#endif /* CONFIG_PM_DEBUG */
extern void omap24xx_idle_loop_suspend(void);
extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
void __iomem *sdrc_power);
extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
extern void save_secure_ram_context(u32 *addr);
extern unsigned int omap24xx_idle_loop_suspend_sz;
extern unsigned int omap34xx_suspend_sz;
extern unsigned int save_secure_ram_context_sz;
extern unsigned int omap24xx_cpu_suspend_sz;
extern unsigned int omap34xx_cpu_suspend_sz;
#endif

View File

@@ -0,0 +1,549 @@
/*
* OMAP2 Power Management Routines
*
* Copyright (C) 2005 Texas Instruments, Inc.
* Copyright (C) 2006-2008 Nokia Corporation
*
* Written by:
* Richard Woodruff <r-woodruff2@ti.com>
* Tony Lindgren
* Juha Yrjola
* Amit Kucheria <amit.kucheria@nokia.com>
* Igor Stoppa <igor.stoppa@nokia.com>
*
* Based on pm.c for omap1
*
* 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.
*/
#include <linux/suspend.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/gpio.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <asm/mach-types.h>
#include <mach/irqs.h>
#include <mach/clock.h>
#include <mach/sram.h>
#include <mach/control.h>
#include <mach/mux.h>
#include <mach/dma.h>
#include <mach/board.h>
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "cm.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "pm.h"
#include <mach/powerdomain.h>
#include <mach/clockdomain.h>
static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
void __iomem *sdrc_power);
static struct powerdomain *mpu_pwrdm;
static struct powerdomain *core_pwrdm;
static struct clockdomain *dsp_clkdm;
static struct clockdomain *gfx_clkdm;
static struct clk *osc_ck, *emul_ck;
static int omap2_fclks_active(void)
{
u32 f1, f2;
f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
/* Ignore UART clocks. These are handled by UART core (serial.c) */
f1 &= ~(OMAP24XX_EN_UART1 | OMAP24XX_EN_UART2);
f2 &= ~OMAP24XX_EN_UART3;
if (f1 | f2)
return 1;
return 0;
}
static void omap2_enter_full_retention(void)
{
u32 l;
struct timespec ts_preidle, ts_postidle, ts_idle;
/* There is 1 reference hold for all children of the oscillator
* clock, the following will remove it. If no one else uses the
* oscillator itself it will be disabled if/when we enter retention
* mode.
*/
clk_disable(osc_ck);
/* Clear old wake-up events */
/* REVISIT: These write to reserved bits? */
prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
/*
* Set MPU powerdomain's next power state to RETENTION;
* preserve logic state during retention
*/
pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
/* Workaround to kill USB */
l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
omap2_gpio_prepare_for_retention();
if (omap2_pm_debug) {
omap2_pm_dump(0, 0, 0);
getnstimeofday(&ts_preidle);
}
/* One last check for pending IRQs to avoid extra latency due
* to sleeping unnecessarily. */
if (omap_irq_pending())
goto no_sleep;
omap_uart_prepare_idle(0);
omap_uart_prepare_idle(1);
omap_uart_prepare_idle(2);
/* Jump to SRAM suspend code */
omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
OMAP_SDRC_REGADDR(SDRC_POWER));
omap_uart_resume_idle(2);
omap_uart_resume_idle(1);
omap_uart_resume_idle(0);
no_sleep:
if (omap2_pm_debug) {
unsigned long long tmp;
getnstimeofday(&ts_postidle);
ts_idle = timespec_sub(ts_postidle, ts_preidle);
tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
omap2_pm_dump(0, 1, tmp);
}
omap2_gpio_resume_after_retention();
clk_enable(osc_ck);
/* clear CORE wake-up events */
prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
/* MPU domain wake events */
l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
if (l & 0x01)
prm_write_mod_reg(0x01, OCP_MOD,
OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
if (l & 0x20)
prm_write_mod_reg(0x20, OCP_MOD,
OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
/* Mask future PRCM-to-MPU interrupts */
prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
}
static int omap2_i2c_active(void)
{
u32 l;
l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
}
static int sti_console_enabled;
static int omap2_allow_mpu_retention(void)
{
u32 l;
/* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
return 0;
/* Check for UART3. */
l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
if (l & OMAP24XX_EN_UART3)
return 0;
if (sti_console_enabled)
return 0;
return 1;
}
static void omap2_enter_mpu_retention(void)
{
int only_idle = 0;
struct timespec ts_preidle, ts_postidle, ts_idle;
/* Putting MPU into the WFI state while a transfer is active
* seems to cause the I2C block to timeout. Why? Good question. */
if (omap2_i2c_active())
return;
/* The peripherals seem not to be able to wake up the MPU when
* it is in retention mode. */
if (omap2_allow_mpu_retention()) {
/* REVISIT: These write to reserved bits? */
prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
/* Try to enter MPU retention */
prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
OMAP_LOGICRETSTATE,
MPU_MOD, PM_PWSTCTRL);
} else {
/* Block MPU retention */
prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
only_idle = 1;
}
if (omap2_pm_debug) {
omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
getnstimeofday(&ts_preidle);
}
omap2_sram_idle();
if (omap2_pm_debug) {
unsigned long long tmp;
getnstimeofday(&ts_postidle);
ts_idle = timespec_sub(ts_postidle, ts_preidle);
tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
}
}
static int omap2_can_sleep(void)
{
if (omap2_fclks_active())
return 0;
if (osc_ck->usecount > 1)
return 0;
if (omap_dma_running())
return 0;
return 1;
}
static void omap2_pm_idle(void)
{
local_irq_disable();
local_fiq_disable();
if (!omap2_can_sleep()) {
if (omap_irq_pending())
goto out;
omap2_enter_mpu_retention();
goto out;
}
if (omap_irq_pending())
goto out;
omap2_enter_full_retention();
out:
local_fiq_enable();
local_irq_enable();
}
static int omap2_pm_prepare(void)
{
/* We cannot sleep in idle until we have resumed */
disable_hlt();
return 0;
}
static int omap2_pm_suspend(void)
{
u32 wken_wkup, mir1;
wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
/* Mask GPT1 */
mir1 = omap_readl(0x480fe0a4);
omap_writel(1 << 5, 0x480fe0ac);
omap_uart_prepare_suspend();
omap2_enter_full_retention();
omap_writel(mir1, 0x480fe0a4);
prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
return 0;
}
static int omap2_pm_enter(suspend_state_t state)
{
int ret = 0;
switch (state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
ret = omap2_pm_suspend();
break;
default:
ret = -EINVAL;
}
return ret;
}
static void omap2_pm_finish(void)
{
enable_hlt();
}
static struct platform_suspend_ops omap_pm_ops = {
.prepare = omap2_pm_prepare,
.enter = omap2_pm_enter,
.finish = omap2_pm_finish,
.valid = suspend_valid_only_mem,
};
static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
{
omap2_clkdm_allow_idle(clkdm);
return 0;
}
static void __init prcm_setup_regs(void)
{
int i, num_mem_banks;
struct powerdomain *pwrdm;
/* Enable autoidle */
prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
OMAP2_PRCM_SYSCONFIG_OFFSET);
/* Set all domain wakeup dependencies */
prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
if (cpu_is_omap2430())
prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
/*
* Set CORE powerdomain memory banks to retain their contents
* during RETENTION
*/
num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
for (i = 0; i < num_mem_banks; i++)
pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
/* Set CORE powerdomain's next power state to RETENTION */
pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
/*
* Set MPU powerdomain's next power state to RETENTION;
* preserve logic state during retention
*/
pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
/* Force-power down DSP, GFX powerdomains */
pwrdm = clkdm_get_pwrdm(dsp_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
omap2_clkdm_sleep(dsp_clkdm);
pwrdm = clkdm_get_pwrdm(gfx_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
omap2_clkdm_sleep(gfx_clkdm);
/* Enable clockdomain hardware-supervised control for all clkdms */
clkdm_for_each(_pm_clkdm_enable_hwsup);
/* Enable clock autoidle for all domains */
cm_write_mod_reg(OMAP24XX_AUTO_CAM |
OMAP24XX_AUTO_MAILBOXES |
OMAP24XX_AUTO_WDT4 |
OMAP2420_AUTO_WDT3 |
OMAP24XX_AUTO_MSPRO |
OMAP2420_AUTO_MMC |
OMAP24XX_AUTO_FAC |
OMAP2420_AUTO_EAC |
OMAP24XX_AUTO_HDQ |
OMAP24XX_AUTO_UART2 |
OMAP24XX_AUTO_UART1 |
OMAP24XX_AUTO_I2C2 |
OMAP24XX_AUTO_I2C1 |
OMAP24XX_AUTO_MCSPI2 |
OMAP24XX_AUTO_MCSPI1 |
OMAP24XX_AUTO_MCBSP2 |
OMAP24XX_AUTO_MCBSP1 |
OMAP24XX_AUTO_GPT12 |
OMAP24XX_AUTO_GPT11 |
OMAP24XX_AUTO_GPT10 |
OMAP24XX_AUTO_GPT9 |
OMAP24XX_AUTO_GPT8 |
OMAP24XX_AUTO_GPT7 |
OMAP24XX_AUTO_GPT6 |
OMAP24XX_AUTO_GPT5 |
OMAP24XX_AUTO_GPT4 |
OMAP24XX_AUTO_GPT3 |
OMAP24XX_AUTO_GPT2 |
OMAP2420_AUTO_VLYNQ |
OMAP24XX_AUTO_DSS,
CORE_MOD, CM_AUTOIDLE1);
cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
OMAP24XX_AUTO_SSI |
OMAP24XX_AUTO_USB,
CORE_MOD, CM_AUTOIDLE2);
cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
OMAP24XX_AUTO_GPMC |
OMAP24XX_AUTO_SDMA,
CORE_MOD, CM_AUTOIDLE3);
cm_write_mod_reg(OMAP24XX_AUTO_PKA |
OMAP24XX_AUTO_AES |
OMAP24XX_AUTO_RNG |
OMAP24XX_AUTO_SHA |
OMAP24XX_AUTO_DES,
CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
/* Put DPLL and both APLLs into autoidle mode */
cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
(0x03 << OMAP24XX_AUTO_96M_SHIFT) |
(0x03 << OMAP24XX_AUTO_54M_SHIFT),
PLL_MOD, CM_AUTOIDLE);
cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
OMAP24XX_AUTO_WDT1 |
OMAP24XX_AUTO_MPU_WDT |
OMAP24XX_AUTO_GPIOS |
OMAP24XX_AUTO_32KSYNC |
OMAP24XX_AUTO_GPT1,
WKUP_MOD, CM_AUTOIDLE);
/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
* stabilisation */
prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
OMAP2_PRCM_CLKSSETUP_OFFSET);
/* Configure automatic voltage transition */
prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
OMAP2_PRCM_VOLTSETUP_OFFSET);
prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
(0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
OMAP24XX_MEMRETCTRL |
(0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
(0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
/* Enable wake-up events */
prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
WKUP_MOD, PM_WKEN);
}
int __init omap2_pm_init(void)
{
u32 l;
if (!cpu_is_omap24xx())
return -ENODEV;
printk(KERN_INFO "Power Management for OMAP2 initializing\n");
l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
/* Look up important powerdomains, clockdomains */
mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
if (!mpu_pwrdm)
pr_err("PM: mpu_pwrdm not found\n");
core_pwrdm = pwrdm_lookup("core_pwrdm");
if (!core_pwrdm)
pr_err("PM: core_pwrdm not found\n");
dsp_clkdm = clkdm_lookup("dsp_clkdm");
if (!dsp_clkdm)
pr_err("PM: mpu_clkdm not found\n");
gfx_clkdm = clkdm_lookup("gfx_clkdm");
if (!gfx_clkdm)
pr_err("PM: gfx_clkdm not found\n");
osc_ck = clk_get(NULL, "osc_ck");
if (IS_ERR(osc_ck)) {
printk(KERN_ERR "could not get osc_ck\n");
return -ENODEV;
}
if (cpu_is_omap242x()) {
emul_ck = clk_get(NULL, "emul_ck");
if (IS_ERR(emul_ck)) {
printk(KERN_ERR "could not get emul_ck\n");
clk_put(osc_ck);
return -ENODEV;
}
}
prcm_setup_regs();
/* Hack to prevent MPU retention when STI console is enabled. */
{
const struct omap_sti_console_config *sti;
sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
struct omap_sti_console_config);
if (sti != NULL && sti->enable)
sti_console_enabled = 1;
}
/*
* We copy the assembler sleep/wakeup routines to SRAM.
* These routines need to be in SRAM as that's the only
* memory the MPU can see when it wakes up.
*/
if (cpu_is_omap24xx()) {
omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
omap24xx_idle_loop_suspend_sz);
omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
omap24xx_cpu_suspend_sz);
}
suspend_set_ops(&omap_pm_ops);
pm_idle = omap2_pm_idle;
return 0;
}
late_initcall(omap2_pm_init);

View File

@@ -0,0 +1,710 @@
/*
* OMAP3 Power Management Routines
*
* Copyright (C) 2006-2008 Nokia Corporation
* Tony Lindgren <tony@atomide.com>
* Jouni Hogander
*
* Copyright (C) 2005 Texas Instruments, Inc.
* Richard Woodruff <r-woodruff2@ti.com>
*
* Based on pm.c for omap1
*
* 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.
*/
#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <mach/sram.h>
#include <mach/clockdomain.h>
#include <mach/powerdomain.h>
#include <mach/control.h>
#include <mach/serial.h>
#include "cm.h"
#include "cm-regbits-34xx.h"
#include "prm-regbits-34xx.h"
#include "prm.h"
#include "pm.h"
struct power_state {
struct powerdomain *pwrdm;
u32 next_state;
u32 saved_state;
struct list_head node;
};
static LIST_HEAD(pwrst_list);
static void (*_omap_sram_idle)(u32 *addr, int save_state);
static struct powerdomain *mpu_pwrdm;
/* PRCM Interrupt Handler for wakeups */
static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
{
u32 wkst, irqstatus_mpu;
u32 fclk, iclk;
/* WKUP */
wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
if (wkst) {
iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
cpu_relax();
cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
}
/* CORE */
wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
if (wkst) {
iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
cpu_relax();
cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
}
wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
if (wkst) {
iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
cpu_relax();
cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
}
/* PER */
wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
if (wkst) {
iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
cpu_relax();
cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
}
if (omap_rev() > OMAP3430_REV_ES1_0) {
/* USBHOST */
wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
if (wkst) {
iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
CM_ICLKEN);
fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
CM_FCLKEN);
cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
CM_ICLKEN);
cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
CM_FCLKEN);
prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
PM_WKST);
while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
PM_WKST))
cpu_relax();
cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
CM_ICLKEN);
cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
CM_FCLKEN);
}
}
irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
cpu_relax();
return IRQ_HANDLED;
}
static void omap_sram_idle(void)
{
/* Variable to tell what needs to be saved and restored
* in omap_sram_idle*/
/* save_state = 0 => Nothing to save and restored */
/* save_state = 1 => Only L1 and logic lost */
/* save_state = 2 => Only L2 lost */
/* save_state = 3 => L1, L2 and logic lost */
int save_state = 0, mpu_next_state;
if (!_omap_sram_idle)
return;
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
switch (mpu_next_state) {
case PWRDM_POWER_RET:
/* No need to save context */
save_state = 0;
break;
default:
/* Invalid state */
printk(KERN_ERR "Invalid mpu state in sram_idle\n");
return;
}
omap2_gpio_prepare_for_retention();
omap_uart_prepare_idle(0);
omap_uart_prepare_idle(1);
omap_uart_prepare_idle(2);
_omap_sram_idle(NULL, save_state);
cpu_init();
omap_uart_resume_idle(2);
omap_uart_resume_idle(1);
omap_uart_resume_idle(0);
omap2_gpio_resume_after_retention();
}
/*
* Check if functional clocks are enabled before entering
* sleep. This function could be behind CONFIG_PM_DEBUG
* when all drivers are configuring their sysconfig registers
* properly and using their clocks properly.
*/
static int omap3_fclks_active(void)
{
u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
fck_cam = 0, fck_per = 0, fck_usbhost = 0;
fck_core1 = cm_read_mod_reg(CORE_MOD,
CM_FCLKEN1);
if (omap_rev() > OMAP3430_REV_ES1_0) {
fck_core3 = cm_read_mod_reg(CORE_MOD,
OMAP3430ES2_CM_FCLKEN3);
fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
CM_FCLKEN);
fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
CM_FCLKEN);
} else
fck_sgx = cm_read_mod_reg(GFX_MOD,
OMAP3430ES2_CM_FCLKEN3);
fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
CM_FCLKEN);
fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
CM_FCLKEN);
fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
CM_FCLKEN);
/* Ignore UART clocks. These are handled by UART core (serial.c) */
fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
fck_per &= ~OMAP3430_EN_UART3;
if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
fck_cam | fck_per | fck_usbhost)
return 1;
return 0;
}
static int omap3_can_sleep(void)
{
if (!omap_uart_can_sleep())
return 0;
if (omap3_fclks_active())
return 0;
return 1;
}
/* This sets pwrdm state (other than mpu & core. Currently only ON &
* RET are supported. Function is assuming that clkdm doesn't have
* hw_sup mode enabled. */
static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
u32 cur_state;
int sleep_switch = 0;
int ret = 0;
if (pwrdm == NULL || IS_ERR(pwrdm))
return -EINVAL;
while (!(pwrdm->pwrsts & (1 << state))) {
if (state == PWRDM_POWER_OFF)
return ret;
state--;
}
cur_state = pwrdm_read_next_pwrst(pwrdm);
if (cur_state == state)
return ret;
if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
sleep_switch = 1;
pwrdm_wait_transition(pwrdm);
}
ret = pwrdm_set_next_pwrst(pwrdm, state);
if (ret) {
printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
pwrdm->name);
goto err;
}
if (sleep_switch) {
omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
pwrdm_wait_transition(pwrdm);
}
err:
return ret;
}
static void omap3_pm_idle(void)
{
local_irq_disable();
local_fiq_disable();
if (!omap3_can_sleep())
goto out;
if (omap_irq_pending())
goto out;
omap_sram_idle();
out:
local_fiq_enable();
local_irq_enable();
}
static int omap3_pm_prepare(void)
{
disable_hlt();
return 0;
}
static int omap3_pm_suspend(void)
{
struct power_state *pwrst;
int state, ret = 0;
/* Read current next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node)
pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
/* Set ones wanted by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
goto restore;
if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
goto restore;
}
omap_uart_prepare_suspend();
omap_sram_idle();
restore:
/* Restore next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node) {
set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
if (state > pwrst->next_state) {
printk(KERN_INFO "Powerdomain (%s) didn't enter "
"target state %d\n",
pwrst->pwrdm->name, pwrst->next_state);
ret = -1;
}
}
if (ret)
printk(KERN_ERR "Could not enter target state in pm_suspend\n");
else
printk(KERN_INFO "Successfully put all powerdomains "
"to target state\n");
return ret;
}
static int omap3_pm_enter(suspend_state_t state)
{
int ret = 0;
switch (state) {
case PM_SUSPEND_STANDBY:
case PM_SUSPEND_MEM:
ret = omap3_pm_suspend();
break;
default:
ret = -EINVAL;
}
return ret;
}
static void omap3_pm_finish(void)
{
enable_hlt();
}
static struct platform_suspend_ops omap_pm_ops = {
.prepare = omap3_pm_prepare,
.enter = omap3_pm_enter,
.finish = omap3_pm_finish,
.valid = suspend_valid_only_mem,
};
/**
* omap3_iva_idle(): ensure IVA is in idle so it can be put into
* retention
*
* In cases where IVA2 is activated by bootcode, it may prevent
* full-chip retention or off-mode because it is not idle. This
* function forces the IVA2 into idle state so it can go
* into retention/off and thus allow full-chip retention/off.
*
**/
static void __init omap3_iva_idle(void)
{
/* ensure IVA2 clock is disabled */
cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* if no clock activity, nothing else to do */
if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
OMAP3430_CLKACTIVITY_IVA2_MASK))
return;
/* Reset IVA2 */
prm_write_mod_reg(OMAP3430_RST1_IVA2 |
OMAP3430_RST2_IVA2 |
OMAP3430_RST3_IVA2,
OMAP3430_IVA2_MOD, RM_RSTCTRL);
/* Enable IVA2 clock */
cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Set IVA2 boot mode to 'idle' */
omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
OMAP343X_CONTROL_IVA2_BOOTMOD);
/* Un-reset IVA2 */
prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
/* Disable IVA2 clock */
cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
/* Reset IVA2 */
prm_write_mod_reg(OMAP3430_RST1_IVA2 |
OMAP3430_RST2_IVA2 |
OMAP3430_RST3_IVA2,
OMAP3430_IVA2_MOD, RM_RSTCTRL);
}
static void __init omap3_d2d_idle(void)
{
u16 mask, padconf;
/* In a stand alone OMAP3430 where there is not a stacked
* modem for the D2D Idle Ack and D2D MStandby must be pulled
* high. S CONTROL_PADCONF_SAD2D_IDLEACK and
* CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
padconf |= mask;
omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
/* reset modem */
prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
CORE_MOD, RM_RSTCTRL);
prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
}
static void __init prcm_setup_regs(void)
{
/* XXX Reset all wkdeps. This should be done when initializing
* powerdomains */
prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
if (omap_rev() > OMAP3430_REV_ES1_0) {
prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
} else
prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
/*
* Enable interface clock autoidle for all modules.
* Note that in the long run this should be done by clockfw
*/
cm_write_mod_reg(
OMAP3430_AUTO_MODEM |
OMAP3430ES2_AUTO_MMC3 |
OMAP3430ES2_AUTO_ICR |
OMAP3430_AUTO_AES2 |
OMAP3430_AUTO_SHA12 |
OMAP3430_AUTO_DES2 |
OMAP3430_AUTO_MMC2 |
OMAP3430_AUTO_MMC1 |
OMAP3430_AUTO_MSPRO |
OMAP3430_AUTO_HDQ |
OMAP3430_AUTO_MCSPI4 |
OMAP3430_AUTO_MCSPI3 |
OMAP3430_AUTO_MCSPI2 |
OMAP3430_AUTO_MCSPI1 |
OMAP3430_AUTO_I2C3 |
OMAP3430_AUTO_I2C2 |
OMAP3430_AUTO_I2C1 |
OMAP3430_AUTO_UART2 |
OMAP3430_AUTO_UART1 |
OMAP3430_AUTO_GPT11 |
OMAP3430_AUTO_GPT10 |
OMAP3430_AUTO_MCBSP5 |
OMAP3430_AUTO_MCBSP1 |
OMAP3430ES1_AUTO_FAC | /* This is es1 only */
OMAP3430_AUTO_MAILBOXES |
OMAP3430_AUTO_OMAPCTRL |
OMAP3430ES1_AUTO_FSHOSTUSB |
OMAP3430_AUTO_HSOTGUSB |
OMAP3430_AUTO_SAD2D |
OMAP3430_AUTO_SSI,
CORE_MOD, CM_AUTOIDLE1);
cm_write_mod_reg(
OMAP3430_AUTO_PKA |
OMAP3430_AUTO_AES1 |
OMAP3430_AUTO_RNG |
OMAP3430_AUTO_SHA11 |
OMAP3430_AUTO_DES1,
CORE_MOD, CM_AUTOIDLE2);
if (omap_rev() > OMAP3430_REV_ES1_0) {
cm_write_mod_reg(
OMAP3430_AUTO_MAD2D |
OMAP3430ES2_AUTO_USBTLL,
CORE_MOD, CM_AUTOIDLE3);
}
cm_write_mod_reg(
OMAP3430_AUTO_WDT2 |
OMAP3430_AUTO_WDT1 |
OMAP3430_AUTO_GPIO1 |
OMAP3430_AUTO_32KSYNC |
OMAP3430_AUTO_GPT12 |
OMAP3430_AUTO_GPT1 ,
WKUP_MOD, CM_AUTOIDLE);
cm_write_mod_reg(
OMAP3430_AUTO_DSS,
OMAP3430_DSS_MOD,
CM_AUTOIDLE);
cm_write_mod_reg(
OMAP3430_AUTO_CAM,
OMAP3430_CAM_MOD,
CM_AUTOIDLE);
cm_write_mod_reg(
OMAP3430_AUTO_GPIO6 |
OMAP3430_AUTO_GPIO5 |
OMAP3430_AUTO_GPIO4 |
OMAP3430_AUTO_GPIO3 |
OMAP3430_AUTO_GPIO2 |
OMAP3430_AUTO_WDT3 |
OMAP3430_AUTO_UART3 |
OMAP3430_AUTO_GPT9 |
OMAP3430_AUTO_GPT8 |
OMAP3430_AUTO_GPT7 |
OMAP3430_AUTO_GPT6 |
OMAP3430_AUTO_GPT5 |
OMAP3430_AUTO_GPT4 |
OMAP3430_AUTO_GPT3 |
OMAP3430_AUTO_GPT2 |
OMAP3430_AUTO_MCBSP4 |
OMAP3430_AUTO_MCBSP3 |
OMAP3430_AUTO_MCBSP2,
OMAP3430_PER_MOD,
CM_AUTOIDLE);
if (omap_rev() > OMAP3430_REV_ES1_0) {
cm_write_mod_reg(
OMAP3430ES2_AUTO_USBHOST,
OMAP3430ES2_USBHOST_MOD,
CM_AUTOIDLE);
}
/*
* Set all plls to autoidle. This is needed until autoidle is
* enabled by clockfw
*/
cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
MPU_MOD,
CM_AUTOIDLE2);
cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
(1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
PLL_MOD,
CM_AUTOIDLE);
cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
PLL_MOD,
CM_AUTOIDLE2);
/*
* Enable control of expternal oscillator through
* sys_clkreq. In the long run clock framework should
* take care of this.
*/
prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
1 << OMAP_AUTOEXTCLKMODE_SHIFT,
OMAP3430_GR_MOD,
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
/* setup wakup source */
prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
WKUP_MOD, PM_WKEN);
/* No need to write EN_IO, that is always enabled */
prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
OMAP3430_EN_GPT12,
WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
/* For some reason IO doesn't generate wakeup event even if
* it is selected to mpu wakeup goup */
prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
/* Don't attach IVA interrupts */
prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
/* Clear any pending 'reset' flags */
prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
/* Clear any pending PRCM interrupts */
prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
omap3_iva_idle();
omap3_d2d_idle();
}
static int __init pwrdms_setup(struct powerdomain *pwrdm)
{
struct power_state *pwrst;
if (!pwrdm->pwrsts)
return 0;
pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
if (!pwrst)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
pwrst->next_state = PWRDM_POWER_RET;
list_add(&pwrst->node, &pwrst_list);
if (pwrdm_has_hdwr_sar(pwrdm))
pwrdm_enable_hdwr_sar(pwrdm);
return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
}
/*
* Enable hw supervised mode for all clockdomains if it's
* supported. Initiate sleep transition for other clockdomains, if
* they are not used
*/
static int __init clkdms_setup(struct clockdomain *clkdm)
{
if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
omap2_clkdm_allow_idle(clkdm);
else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
atomic_read(&clkdm->usecount) == 0)
omap2_clkdm_sleep(clkdm);
return 0;
}
int __init omap3_pm_init(void)
{
struct power_state *pwrst, *tmp;
int ret;
if (!cpu_is_omap34xx())
return -ENODEV;
printk(KERN_ERR "Power Management for TI OMAP3.\n");
/* XXX prcm_setup_regs needs to be before enabling hw
* supervised mode for powerdomains */
prcm_setup_regs();
ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
(irq_handler_t)prcm_interrupt_handler,
IRQF_DISABLED, "prcm", NULL);
if (ret) {
printk(KERN_ERR "request_irq failed to register for 0x%x\n",
INT_34XX_PRCM_MPU_IRQ);
goto err1;
}
ret = pwrdm_for_each(pwrdms_setup);
if (ret) {
printk(KERN_ERR "Failed to setup powerdomains\n");
goto err2;
}
(void) clkdm_for_each(clkdms_setup);
mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
if (mpu_pwrdm == NULL) {
printk(KERN_ERR "Failed to get mpu_pwrdm\n");
goto err2;
}
_omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
omap34xx_cpu_suspend_sz);
suspend_set_ops(&omap_pm_ops);
pm_idle = omap3_pm_idle;
err1:
return ret;
err2:
free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
list_del(&pwrst->node);
kfree(pwrst);
}
return ret;
}
late_initcall(omap3_pm_init);

View File

@@ -276,6 +276,8 @@
/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP3430_EN_GPIO1 (1 << 3)
#define OMAP3430_EN_GPIO1_SHIFT 3
#define OMAP3430_EN_GPT12 (1 << 1)
#define OMAP3430_EN_GPT12_SHIFT 1
#define OMAP3430_EN_GPT1 (1 << 0)
#define OMAP3430_EN_GPT1_SHIFT 0

View File

@@ -16,17 +16,12 @@
#include "prcm-common.h"
#ifndef __ASSEMBLER__
#define OMAP_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
#else
#define OMAP2420_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
#define OMAP2430_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
#define OMAP34XX_PRM_REGADDR(module, reg) \
IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
#endif
/*
* Architecture-specific global PRM registers
@@ -38,80 +33,132 @@
*
*/
/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */
#define OMAP24XX_PRCM_VOLTCTRL_OFFSET 0x0050
#define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET 0x0080
#define OMAP2_PRCM_REVISION_OFFSET 0x0000
#define OMAP2420_PRCM_REVISION OMAP2420_PRM_REGADDR(OCP_MOD, 0x0000)
#define OMAP2_PRCM_SYSCONFIG_OFFSET 0x0010
#define OMAP2420_PRCM_SYSCONFIG OMAP2420_PRM_REGADDR(OCP_MOD, 0x0010)
/* 242x GR_MOD registers, use these only for assembly code */
#define OMAP242X_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
OMAP24XX_PRCM_VOLTCTRL_OFFSET)
#define OMAP242X_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD, \
OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
#define OMAP2_PRCM_IRQSTATUS_MPU_OFFSET 0x0018
#define OMAP2420_PRCM_IRQSTATUS_MPU OMAP2420_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP2_PRCM_IRQENABLE_MPU_OFFSET 0x001c
#define OMAP2420_PRCM_IRQENABLE_MPU OMAP2420_PRM_REGADDR(OCP_MOD, 0x001c)
/* 243x GR_MOD registers, use these only for assembly code */
#define OMAP243X_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
OMAP24XX_PRCM_VOLTCTRL_OFFSET)
#define OMAP243X_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD, \
OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
#define OMAP2_PRCM_VOLTCTRL_OFFSET 0x0050
#define OMAP2420_PRCM_VOLTCTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0050)
#define OMAP2_PRCM_VOLTST_OFFSET 0x0054
#define OMAP2420_PRCM_VOLTST OMAP2420_PRM_REGADDR(OCP_MOD, 0x0054)
#define OMAP2_PRCM_CLKSRC_CTRL_OFFSET 0x0060
#define OMAP2420_PRCM_CLKSRC_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0060)
#define OMAP2_PRCM_CLKOUT_CTRL_OFFSET 0x0070
#define OMAP2420_PRCM_CLKOUT_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0070)
#define OMAP2_PRCM_CLKEMUL_CTRL_OFFSET 0x0078
#define OMAP2420_PRCM_CLKEMUL_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0078)
#define OMAP2_PRCM_CLKCFG_CTRL_OFFSET 0x0080
#define OMAP2420_PRCM_CLKCFG_CTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0080)
#define OMAP2_PRCM_CLKCFG_STATUS_OFFSET 0x0084
#define OMAP2420_PRCM_CLKCFG_STATUS OMAP2420_PRM_REGADDR(OCP_MOD, 0x0084)
#define OMAP2_PRCM_VOLTSETUP_OFFSET 0x0090
#define OMAP2420_PRCM_VOLTSETUP OMAP2420_PRM_REGADDR(OCP_MOD, 0x0090)
#define OMAP2_PRCM_CLKSSETUP_OFFSET 0x0094
#define OMAP2420_PRCM_CLKSSETUP OMAP2420_PRM_REGADDR(OCP_MOD, 0x0094)
#define OMAP2_PRCM_POLCTRL_OFFSET 0x0098
#define OMAP2420_PRCM_POLCTRL OMAP2420_PRM_REGADDR(OCP_MOD, 0x0098)
/* These will disappear */
#define OMAP24XX_PRCM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0000)
#define OMAP24XX_PRCM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0010)
#define OMAP2430_PRCM_REVISION OMAP2430_PRM_REGADDR(OCP_MOD, 0x0000)
#define OMAP2430_PRCM_SYSCONFIG OMAP2430_PRM_REGADDR(OCP_MOD, 0x0010)
#define OMAP24XX_PRCM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP24XX_PRCM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
#define OMAP2430_PRCM_IRQSTATUS_MPU OMAP2430_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP2430_PRCM_IRQENABLE_MPU OMAP2430_PRM_REGADDR(OCP_MOD, 0x001c)
#define OMAP24XX_PRCM_VOLTST OMAP_PRM_REGADDR(OCP_MOD, 0x0054)
#define OMAP24XX_PRCM_CLKSRC_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0060)
#define OMAP24XX_PRCM_CLKOUT_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0070)
#define OMAP24XX_PRCM_CLKEMUL_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0078)
#define OMAP24XX_PRCM_CLKCFG_CTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0080)
#define OMAP24XX_PRCM_CLKCFG_STATUS OMAP_PRM_REGADDR(OCP_MOD, 0x0084)
#define OMAP24XX_PRCM_VOLTSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0090)
#define OMAP24XX_PRCM_CLKSSETUP OMAP_PRM_REGADDR(OCP_MOD, 0x0094)
#define OMAP24XX_PRCM_POLCTRL OMAP_PRM_REGADDR(OCP_MOD, 0x0098)
#define OMAP2430_PRCM_VOLTCTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0050)
#define OMAP2430_PRCM_VOLTST OMAP2430_PRM_REGADDR(OCP_MOD, 0x0054)
#define OMAP2430_PRCM_CLKSRC_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0060)
#define OMAP2430_PRCM_CLKOUT_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0070)
#define OMAP2430_PRCM_CLKEMUL_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0078)
#define OMAP2430_PRCM_CLKCFG_CTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0080)
#define OMAP2430_PRCM_CLKCFG_STATUS OMAP2430_PRM_REGADDR(OCP_MOD, 0x0084)
#define OMAP2430_PRCM_VOLTSETUP OMAP2430_PRM_REGADDR(OCP_MOD, 0x0090)
#define OMAP2430_PRCM_CLKSSETUP OMAP2430_PRM_REGADDR(OCP_MOD, 0x0094)
#define OMAP2430_PRCM_POLCTRL OMAP2430_PRM_REGADDR(OCP_MOD, 0x0098)
#define OMAP3430_PRM_REVISION OMAP_PRM_REGADDR(OCP_MOD, 0x0004)
#define OMAP3430_PRM_SYSCONFIG OMAP_PRM_REGADDR(OCP_MOD, 0x0014)
#define OMAP3_PRM_REVISION_OFFSET 0x0004
#define OMAP3430_PRM_REVISION OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0004)
#define OMAP3_PRM_SYSCONFIG_OFFSET 0x0014
#define OMAP3430_PRM_SYSCONFIG OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0014)
#define OMAP3430_PRM_IRQSTATUS_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP3430_PRM_IRQENABLE_MPU OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
#define OMAP3_PRM_IRQSTATUS_MPU_OFFSET 0x0018
#define OMAP3430_PRM_IRQSTATUS_MPU OMAP34XX_PRM_REGADDR(OCP_MOD, 0x0018)
#define OMAP3_PRM_IRQENABLE_MPU_OFFSET 0x001c
#define OMAP3430_PRM_IRQENABLE_MPU OMAP34XX_PRM_REGADDR(OCP_MOD, 0x001c)
#define OMAP3430_PRM_VC_SMPS_SA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
#define OMAP3430_PRM_VC_SMPS_VOL_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
#define OMAP3430_PRM_VC_SMPS_CMD_RA OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
#define OMAP3430_PRM_VC_CMD_VAL_0 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
#define OMAP3430_PRM_VC_CMD_VAL_1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
#define OMAP3430_PRM_VC_CH_CONF OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
#define OMAP3430_PRM_VC_I2C_CFG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
#define OMAP3430_PRM_VC_BYPASS_VAL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
#define OMAP3430_PRM_RSTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
#define OMAP3430_PRM_RSTTIME OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
#define OMAP3430_PRM_RSTST OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
#define OMAP3430_PRM_VOLTCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
#define OMAP3430_PRM_SRAM_PCHARGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
#define OMAP3430_PRM_CLKSRC_CTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
#define OMAP3430_PRM_VOLTSETUP1 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
#define OMAP3430_PRM_VOLTOFFSET OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
#define OMAP3430_PRM_CLKSETUP OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
#define OMAP3430_PRM_POLCTRL OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
#define OMAP3430_PRM_VOLTSETUP2 OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
#define OMAP3430_PRM_VP1_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
#define OMAP3430_PRM_VP1_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
#define OMAP3430_PRM_VP1_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
#define OMAP3430_PRM_VP1_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
#define OMAP3430_PRM_VP1_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
#define OMAP3430_PRM_VP1_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
#define OMAP3430_PRM_VP2_CONFIG OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
#define OMAP3430_PRM_VP2_VSTEPMIN OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
#define OMAP3430_PRM_VP2_VSTEPMAX OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
#define OMAP3430_PRM_VP2_VLIMITTO OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
#define OMAP3430_PRM_VP2_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
#define OMAP3430_PRM_VP2_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
#define OMAP3_PRM_VC_SMPS_SA_OFFSET 0x0020
#define OMAP3430_PRM_VC_SMPS_SA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET 0x0024
#define OMAP3430_PRM_VC_SMPS_VOL_RA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET 0x0028
#define OMAP3430_PRM_VC_SMPS_CMD_RA OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET 0x002c
#define OMAP3430_PRM_VC_CMD_VAL_0 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET 0x0030
#define OMAP3430_PRM_VC_CMD_VAL_1 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
#define OMAP3_PRM_VC_CH_CONF_OFFSET 0x0034
#define OMAP3430_PRM_VC_CH_CONF OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
#define OMAP3_PRM_VC_I2C_CFG_OFFSET 0x0038
#define OMAP3430_PRM_VC_I2C_CFG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET 0x003c
#define OMAP3430_PRM_VC_BYPASS_VAL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
#define OMAP3_PRM_RSTCTRL_OFFSET 0x0050
#define OMAP3430_PRM_RSTCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
#define OMAP3_PRM_RSTTIME_OFFSET 0x0054
#define OMAP3430_PRM_RSTTIME OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
#define OMAP3_PRM_RSTST_OFFSET 0x0058
#define OMAP3430_PRM_RSTST OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
#define OMAP3_PRM_VOLTCTRL_OFFSET 0x0060
#define OMAP3430_PRM_VOLTCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
#define OMAP3_PRM_SRAM_PCHARGE_OFFSET 0x0064
#define OMAP3430_PRM_SRAM_PCHARGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
#define OMAP3_PRM_CLKSRC_CTRL_OFFSET 0x0070
#define OMAP3430_PRM_CLKSRC_CTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
#define OMAP3_PRM_VOLTSETUP1_OFFSET 0x0090
#define OMAP3430_PRM_VOLTSETUP1 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
#define OMAP3_PRM_VOLTOFFSET_OFFSET 0x0094
#define OMAP3430_PRM_VOLTOFFSET OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
#define OMAP3_PRM_CLKSETUP_OFFSET 0x0098
#define OMAP3430_PRM_CLKSETUP OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
#define OMAP3_PRM_POLCTRL_OFFSET 0x009c
#define OMAP3430_PRM_POLCTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
#define OMAP3_PRM_VOLTSETUP2_OFFSET 0x00a0
#define OMAP3430_PRM_VOLTSETUP2 OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
#define OMAP3_PRM_VP1_CONFIG_OFFSET 0x00b0
#define OMAP3430_PRM_VP1_CONFIG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET 0x00b4
#define OMAP3430_PRM_VP1_VSTEPMIN OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET 0x00b8
#define OMAP3430_PRM_VP1_VSTEPMAX OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
#define OMAP3_PRM_VP1_VLIMITTO_OFFSET 0x00bc
#define OMAP3430_PRM_VP1_VLIMITTO OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
#define OMAP3_PRM_VP1_VOLTAGE_OFFSET 0x00c0
#define OMAP3430_PRM_VP1_VOLTAGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
#define OMAP3_PRM_VP1_STATUS_OFFSET 0x00c4
#define OMAP3430_PRM_VP1_STATUS OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
#define OMAP3_PRM_VP2_CONFIG_OFFSET 0x00d0
#define OMAP3430_PRM_VP2_CONFIG OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET 0x00d4
#define OMAP3430_PRM_VP2_VSTEPMIN OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET 0x00d8
#define OMAP3430_PRM_VP2_VSTEPMAX OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
#define OMAP3_PRM_VP2_VLIMITTO_OFFSET 0x00dc
#define OMAP3430_PRM_VP2_VLIMITTO OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
#define OMAP3_PRM_VP2_VOLTAGE_OFFSET 0x00e0
#define OMAP3430_PRM_VP2_VOLTAGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
#define OMAP3_PRM_VP2_STATUS_OFFSET 0x00e4
#define OMAP3430_PRM_VP2_STATUS OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
#define OMAP3430_PRM_CLKSEL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
#define OMAP3430_PRM_CLKOUT_CTRL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
#define OMAP3_PRM_CLKSEL_OFFSET 0x0040
#define OMAP3430_PRM_CLKSEL OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
#define OMAP3_PRM_CLKOUT_CTRL_OFFSET 0x0070
#define OMAP3430_PRM_CLKOUT_CTRL OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
/*
* Module specific PRM registers from PRM_BASE + domain offset
@@ -156,9 +203,11 @@
#define OMAP3430_PM_MPUGRPSEL 0x00a4
#define OMAP3430_PM_MPUGRPSEL1 OMAP3430_PM_MPUGRPSEL
#define OMAP3430ES2_PM_MPUGRPSEL3 0x00f8
#define OMAP3430_PM_IVAGRPSEL 0x00a8
#define OMAP3430_PM_IVAGRPSEL1 OMAP3430_PM_IVAGRPSEL
#define OMAP3430ES2_PM_IVAGRPSEL3 0x00f4
#define OMAP3430_PM_PREPWSTST 0x00e8

View File

@@ -0,0 +1,55 @@
/*
* SDRC register values for the Micron MT46H32M32LF-6
*
* Copyright (C) 2008 Texas Instruments, Inc.
* Copyright (C) 2008-2009 Nokia Corporation
*
* Paul Walmsley
*
* 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.
*/
#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
#include <mach/sdrc.h>
/* Micron MT46H32M32LF-6 */
/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = {
[0] = {
.rate = 166000000,
.actim_ctrla = 0x9a9db4c6,
.actim_ctrlb = 0x00011217,
.rfr_ctrl = 0x0004dc01,
.mr = 0x00000032,
},
[1] = {
.rate = 165941176,
.actim_ctrla = 0x9a9db4c6,
.actim_ctrlb = 0x00011217,
.rfr_ctrl = 0x0004dc01,
.mr = 0x00000032,
},
[2] = {
.rate = 83000000,
.actim_ctrla = 0x51512283,
.actim_ctrlb = 0x0001120c,
.rfr_ctrl = 0x00025501,
.mr = 0x00000032,
},
[3] = {
.rate = 82970588,
.actim_ctrla = 0x51512283,
.actim_ctrlb = 0x0001120c,
.rfr_ctrl = 0x00025501,
.mr = 0x00000032,
},
[4] = {
.rate = 0
},
};
#endif

View File

@@ -0,0 +1,54 @@
/*
* SDRC register values for the Qimonda HYB18M512160AF-6
*
* Copyright (C) 2008-2009 Texas Instruments, Inc.
* Copyright (C) 2008-2009 Nokia Corporation
*
* Paul Walmsley
*
* 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.
*/
#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
#include <mach/sdrc.h>
/* Qimonda HYB18M512160AF-6 */
static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
[0] = {
.rate = 166000000,
.actim_ctrla = 0x629db4c6,
.actim_ctrlb = 0x00012214,
.rfr_ctrl = 0x0004dc01,
.mr = 0x00000032,
},
[1] = {
.rate = 165941176,
.actim_ctrla = 0x629db4c6,
.actim_ctrlb = 0x00012214,
.rfr_ctrl = 0x0004dc01,
.mr = 0x00000032,
},
[2] = {
.rate = 83000000,
.actim_ctrla = 0x31512283,
.actim_ctrlb = 0x0001220a,
.rfr_ctrl = 0x00025501,
.mr = 0x00000022,
},
[3] = {
.rate = 82970588,
.actim_ctrla = 0x31512283,
.actim_ctrlb = 0x0001220a,
.rfr_ctrl = 0x00025501,
.mr = 0x00000022,
},
[4] = {
.rate = 0
},
};
#endif

View File

@@ -37,6 +37,10 @@ static struct omap_sdrc_params *sdrc_init_params;
void __iomem *omap2_sdrc_base;
void __iomem *omap2_sms_base;
/* SDRC_POWER register bits */
#define SDRC_POWER_EXTCLKDIS_SHIFT 3
#define SDRC_POWER_PWDENA_SHIFT 2
#define SDRC_POWER_PAGEPOLICY_SHIFT 0
/**
* omap2_sdrc_get_params - return SDRC register values for a given clock rate
@@ -56,9 +60,12 @@ struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
{
struct omap_sdrc_params *sp;
if (!sdrc_init_params)
return NULL;
sp = sdrc_init_params;
while (sp->rate != r)
while (sp->rate && sp->rate != r)
sp++;
if (!sp->rate)
@@ -74,7 +81,14 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals)
omap2_sms_base = omap2_globals->sms;
}
/* turn on smart idle modes for SDRAM scheduler and controller */
/**
* omap2_sdrc_init - initialize SMS, SDRC devices on boot
* @sp: pointer to a null-terminated list of struct omap_sdrc_params
*
* Turn on smart idle modes for SDRAM scheduler and controller.
* Program a known-good configuration for the SDRC to deal with buggy
* bootloaders.
*/
void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
{
u32 l;
@@ -90,4 +104,10 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
sdrc_write_reg(l, SDRC_SYSCONFIG);
sdrc_init_params = sp;
/* XXX Enable SRFRONIDLEREQ here also? */
l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
(1 << SDRC_POWER_PWDENA_SHIFT) |
(1 << SDRC_POWER_PAGEPOLICY_SHIFT);
sdrc_write_reg(l, SDRC_POWER);
}

View File

@@ -99,7 +99,10 @@ u32 omap2xxx_sdrc_reprogram(u32 level, u32 force)
m_type = omap2xxx_sdrc_get_type();
local_irq_save(flags);
__raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP);
if (cpu_is_omap2420())
__raw_writel(0xffff, OMAP2420_PRCM_VOLTSETUP);
else
__raw_writel(0xffff, OMAP2430_PRCM_VOLTSETUP);
omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
curr_perf_level = level;
local_irq_restore(flags);

View File

@@ -6,8 +6,13 @@
* Copyright (C) 2005-2008 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
*
* Major rework for PM support by Kevin Hilman
*
* Based off of arch/arm/mach-omap/omap1/serial.c
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
@@ -21,9 +26,50 @@
#include <mach/common.h>
#include <mach/board.h>
#include <mach/clock.h>
#include <mach/control.h>
static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
#include "prm.h"
#include "pm.h"
#include "prm-regbits-34xx.h"
#define UART_OMAP_WER 0x17 /* Wake-up enable register */
#define DEFAULT_TIMEOUT (5 * HZ)
struct omap_uart_state {
int num;
int can_sleep;
struct timer_list timer;
u32 timeout;
void __iomem *wk_st;
void __iomem *wk_en;
u32 wk_mask;
u32 padconf;
struct clk *ick;
struct clk *fck;
int clocked;
struct plat_serial8250_port *p;
struct list_head node;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
int context_valid;
/* Registers to be saved/restored for OFF-mode */
u16 dll;
u16 dlh;
u16 ier;
u16 sysc;
u16 scr;
u16 wer;
#endif
};
static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
static LIST_HEAD(uart_list);
static struct plat_serial8250_port serial_platform_data[] = {
{
@@ -74,33 +120,369 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
* properly. Note that the TX watermark initialization may not be needed
* once the 8250.c watermark handling code is merged.
*/
static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
static inline void __init omap_uart_reset(struct omap_uart_state *uart)
{
struct plat_serial8250_port *p = uart->p;
serial_write_reg(p, UART_OMAP_MDR1, 0x07);
serial_write_reg(p, UART_OMAP_SCR, 0x08);
serial_write_reg(p, UART_OMAP_MDR1, 0x00);
serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
}
void omap_serial_enable_clocks(int enable)
#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
static int enable_off_mode; /* to be removed by full off-mode patches */
static void omap_uart_save_context(struct omap_uart_state *uart)
{
int i;
for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
if (uart_ick[i] && uart_fck[i]) {
if (enable) {
clk_enable(uart_ick[i]);
clk_enable(uart_fck[i]);
} else {
clk_disable(uart_ick[i]);
clk_disable(uart_fck[i]);
}
u16 lcr = 0;
struct plat_serial8250_port *p = uart->p;
if (!enable_off_mode)
return;
lcr = serial_read_reg(p, UART_LCR);
serial_write_reg(p, UART_LCR, 0xBF);
uart->dll = serial_read_reg(p, UART_DLL);
uart->dlh = serial_read_reg(p, UART_DLM);
serial_write_reg(p, UART_LCR, lcr);
uart->ier = serial_read_reg(p, UART_IER);
uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
uart->scr = serial_read_reg(p, UART_OMAP_SCR);
uart->wer = serial_read_reg(p, UART_OMAP_WER);
uart->context_valid = 1;
}
static void omap_uart_restore_context(struct omap_uart_state *uart)
{
u16 efr = 0;
struct plat_serial8250_port *p = uart->p;
if (!enable_off_mode)
return;
if (!uart->context_valid)
return;
uart->context_valid = 0;
serial_write_reg(p, UART_OMAP_MDR1, 0x7);
serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
efr = serial_read_reg(p, UART_EFR);
serial_write_reg(p, UART_EFR, UART_EFR_ECB);
serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
serial_write_reg(p, UART_IER, 0x0);
serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
serial_write_reg(p, UART_DLL, uart->dll);
serial_write_reg(p, UART_DLM, uart->dlh);
serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
serial_write_reg(p, UART_IER, uart->ier);
serial_write_reg(p, UART_FCR, 0xA1);
serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
serial_write_reg(p, UART_EFR, efr);
serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
serial_write_reg(p, UART_OMAP_SCR, uart->scr);
serial_write_reg(p, UART_OMAP_WER, uart->wer);
serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
}
#else
static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */
static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
{
if (uart->clocked)
return;
clk_enable(uart->ick);
clk_enable(uart->fck);
uart->clocked = 1;
omap_uart_restore_context(uart);
}
#ifdef CONFIG_PM
static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
{
if (!uart->clocked)
return;
omap_uart_save_context(uart);
uart->clocked = 0;
clk_disable(uart->ick);
clk_disable(uart->fck);
}
static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
int enable)
{
struct plat_serial8250_port *p = uart->p;
u16 sysc;
sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
if (enable)
sysc |= 0x2 << 3;
else
sysc |= 0x1 << 3;
serial_write_reg(p, UART_OMAP_SYSC, sysc);
}
static void omap_uart_block_sleep(struct omap_uart_state *uart)
{
omap_uart_enable_clocks(uart);
omap_uart_smart_idle_enable(uart, 0);
uart->can_sleep = 0;
if (uart->timeout)
mod_timer(&uart->timer, jiffies + uart->timeout);
else
del_timer(&uart->timer);
}
static void omap_uart_allow_sleep(struct omap_uart_state *uart)
{
if (!uart->clocked)
return;
omap_uart_smart_idle_enable(uart, 1);
uart->can_sleep = 1;
del_timer(&uart->timer);
}
static void omap_uart_idle_timer(unsigned long data)
{
struct omap_uart_state *uart = (struct omap_uart_state *)data;
omap_uart_allow_sleep(uart);
}
void omap_uart_prepare_idle(int num)
{
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
if (num == uart->num && uart->can_sleep) {
omap_uart_disable_clocks(uart);
return;
}
}
}
void omap_uart_resume_idle(int num)
{
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
if (num == uart->num) {
omap_uart_enable_clocks(uart);
/* Check for IO pad wakeup */
if (cpu_is_omap34xx() && uart->padconf) {
u16 p = omap_ctrl_readw(uart->padconf);
if (p & OMAP3_PADCONF_WAKEUPEVENT0)
omap_uart_block_sleep(uart);
}
/* Check for normal UART wakeup */
if (__raw_readl(uart->wk_st) & uart->wk_mask)
omap_uart_block_sleep(uart);
return;
}
}
}
void omap_uart_prepare_suspend(void)
{
struct omap_uart_state *uart;
list_for_each_entry(uart, &uart_list, node) {
omap_uart_allow_sleep(uart);
}
}
int omap_uart_can_sleep(void)
{
struct omap_uart_state *uart;
int can_sleep = 1;
list_for_each_entry(uart, &uart_list, node) {
if (!uart->clocked)
continue;
if (!uart->can_sleep) {
can_sleep = 0;
continue;
}
/* This UART can now safely sleep. */
omap_uart_allow_sleep(uart);
}
return can_sleep;
}
/**
* omap_uart_interrupt()
*
* This handler is used only to detect that *any* UART interrupt has
* occurred. It does _nothing_ to handle the interrupt. Rather,
* any UART interrupt will trigger the inactivity timer so the
* UART will not idle or sleep for its timeout period.
*
**/
static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
{
struct omap_uart_state *uart = dev_id;
omap_uart_block_sleep(uart);
return IRQ_NONE;
}
static u32 sleep_timeout = DEFAULT_TIMEOUT;
static void omap_uart_idle_init(struct omap_uart_state *uart)
{
u32 v;
struct plat_serial8250_port *p = uart->p;
int ret;
uart->can_sleep = 0;
uart->timeout = sleep_timeout;
setup_timer(&uart->timer, omap_uart_idle_timer,
(unsigned long) uart);
mod_timer(&uart->timer, jiffies + uart->timeout);
omap_uart_smart_idle_enable(uart, 0);
if (cpu_is_omap34xx()) {
u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
u32 wk_mask = 0;
u32 padconf = 0;
uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1);
uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1);
switch (uart->num) {
case 0:
wk_mask = OMAP3430_ST_UART1_MASK;
padconf = 0x182;
break;
case 1:
wk_mask = OMAP3430_ST_UART2_MASK;
padconf = 0x17a;
break;
case 2:
wk_mask = OMAP3430_ST_UART3_MASK;
padconf = 0x19e;
break;
}
uart->wk_mask = wk_mask;
uart->padconf = padconf;
} else if (cpu_is_omap24xx()) {
u32 wk_mask = 0;
if (cpu_is_omap2430()) {
uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
} else if (cpu_is_omap2420()) {
uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
}
switch (uart->num) {
case 0:
wk_mask = OMAP24XX_ST_UART1_MASK;
break;
case 1:
wk_mask = OMAP24XX_ST_UART2_MASK;
break;
case 2:
wk_mask = OMAP24XX_ST_UART3_MASK;
break;
}
uart->wk_mask = wk_mask;
} else {
uart->wk_en = 0;
uart->wk_st = 0;
uart->wk_mask = 0;
uart->padconf = 0;
}
/* Set wake-enable bit */
if (uart->wk_en && uart->wk_mask) {
v = __raw_readl(uart->wk_en);
v |= uart->wk_mask;
__raw_writel(v, uart->wk_en);
}
/* Ensure IOPAD wake-enables are set */
if (cpu_is_omap34xx() && uart->padconf) {
u16 v;
v = omap_ctrl_readw(uart->padconf);
v |= OMAP3_PADCONF_WAKEUPENABLE0;
omap_ctrl_writew(v, uart->padconf);
}
p->flags |= UPF_SHARE_IRQ;
ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
"serial idle", (void *)uart);
WARN_ON(ret);
}
static ssize_t sleep_timeout_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%u\n", sleep_timeout / HZ);
}
static ssize_t sleep_timeout_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
struct omap_uart_state *uart;
unsigned int value;
if (sscanf(buf, "%u", &value) != 1) {
printk(KERN_ERR "sleep_timeout_store: Invalid value\n");
return -EINVAL;
}
sleep_timeout = value * HZ;
list_for_each_entry(uart, &uart_list, node) {
uart->timeout = sleep_timeout;
if (uart->timeout)
mod_timer(&uart->timer, jiffies + uart->timeout);
else
/* A zero value means disable timeout feature */
omap_uart_block_sleep(uart);
}
return n;
}
static struct kobj_attribute sleep_timeout_attr =
__ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store);
#else
static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
#endif /* CONFIG_PM */
static struct platform_device serial_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = serial_platform_data,
},
};
void __init omap_serial_init(void)
{
int i;
int i, err;
const struct omap_uart_config *info;
char name[16];
@@ -114,9 +496,14 @@ void __init omap_serial_init(void)
if (info == NULL)
return;
if (cpu_is_omap44xx()) {
for (i = 0; i < OMAP_MAX_NR_PORTS; i++)
serial_platform_data[i].irq += 32;
}
for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
struct plat_serial8250_port *p = serial_platform_data + i;
struct omap_uart_state *uart = &omap_uart[i];
if (!(info->enabled_uarts & (1 << i))) {
p->membase = NULL;
@@ -125,35 +512,39 @@ void __init omap_serial_init(void)
}
sprintf(name, "uart%d_ick", i+1);
uart_ick[i] = clk_get(NULL, name);
if (IS_ERR(uart_ick[i])) {
uart->ick = clk_get(NULL, name);
if (IS_ERR(uart->ick)) {
printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
uart_ick[i] = NULL;
} else
clk_enable(uart_ick[i]);
uart->ick = NULL;
}
sprintf(name, "uart%d_fck", i+1);
uart_fck[i] = clk_get(NULL, name);
if (IS_ERR(uart_fck[i])) {
uart->fck = clk_get(NULL, name);
if (IS_ERR(uart->fck)) {
printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
uart_fck[i] = NULL;
} else
clk_enable(uart_fck[i]);
uart->fck = NULL;
}
omap_serial_reset(p);
if (!uart->ick || !uart->fck)
continue;
uart->num = i;
p->private_data = uart;
uart->p = p;
list_add(&uart->node, &uart_list);
omap_uart_enable_clocks(uart);
omap_uart_reset(uart);
omap_uart_idle_init(uart);
}
err = platform_device_register(&serial_device);
#ifdef CONFIG_PM
if (!err)
err = sysfs_create_file(&serial_device.dev.kobj,
&sleep_timeout_attr.attr);
#endif
}
static struct platform_device serial_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init omap_init(void)
{
return platform_device_register(&serial_device);
}
arch_initcall(omap_init);

View File

@@ -28,7 +28,6 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/io.h>
#include <mach/pm.h>
#include <mach/omap24xx.h>

View File

@@ -0,0 +1,436 @@
/*
* linux/arch/arm/mach-omap2/sleep.S
*
* (C) Copyright 2007
* Texas Instruments
* Karthik Dasu <karthik-dp@ti.com>
*
* (C) Copyright 2004
* Texas Instruments, <www.ti.com>
* Richard Woodruff <r-woodruff2@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/io.h>
#include <mach/control.h>
#include "prm.h"
#include "sdrc.h"
#define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \
OMAP3430_PM_PREPWSTST)
#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \
OMAP3430_PM_PREPWSTST)
#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
#define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is
* available */
#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\
OMAP343X_CONTROL_MEM_WKUP +\
SCRATCHPAD_MEM_OFFS)
#define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER)
.text
/* Function call to get the restore pointer for resume from OFF */
ENTRY(get_restore_pointer)
stmfd sp!, {lr} @ save registers on stack
adr r0, restore
ldmfd sp!, {pc} @ restore regs and return
ENTRY(get_restore_pointer_sz)
.word . - get_restore_pointer_sz
/*
* Forces OMAP into idle state
*
* omap34xx_suspend() - This bit of code just executes the WFI
* for normal idles.
*
* Note: This code get's copied to internal SRAM at boot. When the OMAP
* wakes up it continues execution at the point it went to sleep.
*/
ENTRY(omap34xx_cpu_suspend)
stmfd sp!, {r0-r12, lr} @ save registers on stack
loop:
/*b loop*/ @Enable to debug by stepping through code
/* r0 contains restore pointer in sdram */
/* r1 contains information about saving context */
ldr r4, sdrc_power @ read the SDRC_POWER register
ldr r5, [r4] @ read the contents of SDRC_POWER
orr r5, r5, #0x40 @ enable self refresh on idle req
str r5, [r4] @ write back to SDRC_POWER register
cmp r1, #0x0
/* If context save is required, do that and execute wfi */
bne save_context_wfi
/* Data memory barrier and Data sync barrier */
mov r1, #0
mcr p15, 0, r1, c7, c10, 4
mcr p15, 0, r1, c7, c10, 5
wfi @ wait for interrupt
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
bl i_dll_wait
ldmfd sp!, {r0-r12, pc} @ restore regs and return
restore:
/* b restore*/ @ Enable to debug restore code
/* Check what was the reason for mpu reset and store the reason in r9*/
/* 1 - Only L1 and logic lost */
/* 2 - Only L2 lost - In this case, we wont be here */
/* 3 - Both L1 and L2 lost */
ldr r1, pm_pwstctrl_mpu
ldr r2, [r1]
and r2, r2, #0x3
cmp r2, #0x0 @ Check if target power state was OFF or RET
moveq r9, #0x3 @ MPU OFF => L1 and L2 lost
movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation
bne logic_l1_restore
/* Execute smi to invalidate L2 cache */
mov r12, #0x1 @ set up to invalide L2
smi: .word 0xE1600070 @ Call SMI monitor (smieq)
logic_l1_restore:
mov r1, #0
/* Invalidate all instruction caches to PoU
* and flush branch target cache */
mcr p15, 0, r1, c7, c5, 0
ldr r4, scratchpad_base
ldr r3, [r4,#0xBC]
ldmia r3!, {r4-r6}
mov sp, r4
msr spsr_cxsf, r5
mov lr, r6
ldmia r3!, {r4-r9}
/* Coprocessor access Control Register */
mcr p15, 0, r4, c1, c0, 2
/* TTBR0 */
MCR p15, 0, r5, c2, c0, 0
/* TTBR1 */
MCR p15, 0, r6, c2, c0, 1
/* Translation table base control register */
MCR p15, 0, r7, c2, c0, 2
/*domain access Control Register */
MCR p15, 0, r8, c3, c0, 0
/* data fault status Register */
MCR p15, 0, r9, c5, c0, 0
ldmia r3!,{r4-r8}
/* instruction fault status Register */
MCR p15, 0, r4, c5, c0, 1
/*Data Auxiliary Fault Status Register */
MCR p15, 0, r5, c5, c1, 0
/*Instruction Auxiliary Fault Status Register*/
MCR p15, 0, r6, c5, c1, 1
/*Data Fault Address Register */
MCR p15, 0, r7, c6, c0, 0
/*Instruction Fault Address Register*/
MCR p15, 0, r8, c6, c0, 2
ldmia r3!,{r4-r7}
/* user r/w thread and process ID */
MCR p15, 0, r4, c13, c0, 2
/* user ro thread and process ID */
MCR p15, 0, r5, c13, c0, 3
/*Privileged only thread and process ID */
MCR p15, 0, r6, c13, c0, 4
/* cache size selection */
MCR p15, 2, r7, c0, c0, 0
ldmia r3!,{r4-r8}
/* Data TLB lockdown registers */
MCR p15, 0, r4, c10, c0, 0
/* Instruction TLB lockdown registers */
MCR p15, 0, r5, c10, c0, 1
/* Secure or Nonsecure Vector Base Address */
MCR p15, 0, r6, c12, c0, 0
/* FCSE PID */
MCR p15, 0, r7, c13, c0, 0
/* Context PID */
MCR p15, 0, r8, c13, c0, 1
ldmia r3!,{r4-r5}
/* primary memory remap register */
MCR p15, 0, r4, c10, c2, 0
/*normal memory remap register */
MCR p15, 0, r5, c10, c2, 1
/* Restore cpsr */
ldmia r3!,{r4} /*load CPSR from SDRAM*/
msr cpsr, r4 /*store cpsr */
/* Enabling MMU here */
mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
/* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
and r7, #0x7
cmp r7, #0x0
beq usettbr0
ttbr_error:
/* More work needs to be done to support N[0:2] value other than 0
* So looping here so that the error can be detected
*/
b ttbr_error
usettbr0:
mrc p15, 0, r2, c2, c0, 0
ldr r5, ttbrbit_mask
and r2, r5
mov r4, pc
ldr r5, table_index_mask
and r4, r5 /* r4 = 31 to 20 bits of pc */
/* Extract the value to be written to table entry */
ldr r1, table_entry
add r1, r1, r4 /* r1 has value to be written to table entry*/
/* Getting the address of table entry to modify */
lsr r4, #18
add r2, r4 /* r2 has the location which needs to be modified */
/* Storing previous entry of location being modified */
ldr r5, scratchpad_base
ldr r4, [r2]
str r4, [r5, #0xC0]
/* Modify the table entry */
str r1, [r2]
/* Storing address of entry being modified
* - will be restored after enabling MMU */
ldr r5, scratchpad_base
str r2, [r5, #0xC4]
mov r0, #0
mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
/* Restore control register but dont enable caches here*/
/* Caches will be enabled after restoring MMU table entry */
ldmia r3!, {r4}
/* Store previous value of control register in scratchpad */
str r4, [r5, #0xC8]
ldr r2, cache_pred_disable_mask
and r4, r2
mcr p15, 0, r4, c1, c0, 0
ldmfd sp!, {r0-r12, pc} @ restore regs and return
save_context_wfi:
/*b save_context_wfi*/ @ enable to debug save code
mov r8, r0 /* Store SDRAM address in r8 */
/* Check what that target sleep state is:stored in r1*/
/* 1 - Only L1 and logic lost */
/* 2 - Only L2 lost */
/* 3 - Both L1 and L2 lost */
cmp r1, #0x2 /* Only L2 lost */
beq clean_l2
cmp r1, #0x1 /* L2 retained */
/* r9 stores whether to clean L2 or not*/
moveq r9, #0x0 /* Dont Clean L2 */
movne r9, #0x1 /* Clean L2 */
l1_logic_lost:
/* Store sp and spsr to SDRAM */
mov r4, sp
mrs r5, spsr
mov r6, lr
stmia r8!, {r4-r6}
/* Save all ARM registers */
/* Coprocessor access control register */
mrc p15, 0, r6, c1, c0, 2
stmia r8!, {r6}
/* TTBR0, TTBR1 and Translation table base control */
mrc p15, 0, r4, c2, c0, 0
mrc p15, 0, r5, c2, c0, 1
mrc p15, 0, r6, c2, c0, 2
stmia r8!, {r4-r6}
/* Domain access control register, data fault status register,
and instruction fault status register */
mrc p15, 0, r4, c3, c0, 0
mrc p15, 0, r5, c5, c0, 0
mrc p15, 0, r6, c5, c0, 1
stmia r8!, {r4-r6}
/* Data aux fault status register, instruction aux fault status,
datat fault address register and instruction fault address register*/
mrc p15, 0, r4, c5, c1, 0
mrc p15, 0, r5, c5, c1, 1
mrc p15, 0, r6, c6, c0, 0
mrc p15, 0, r7, c6, c0, 2
stmia r8!, {r4-r7}
/* user r/w thread and process ID, user r/o thread and process ID,
priv only thread and process ID, cache size selection */
mrc p15, 0, r4, c13, c0, 2
mrc p15, 0, r5, c13, c0, 3
mrc p15, 0, r6, c13, c0, 4
mrc p15, 2, r7, c0, c0, 0
stmia r8!, {r4-r7}
/* Data TLB lockdown, instruction TLB lockdown registers */
mrc p15, 0, r5, c10, c0, 0
mrc p15, 0, r6, c10, c0, 1
stmia r8!, {r5-r6}
/* Secure or non secure vector base address, FCSE PID, Context PID*/
mrc p15, 0, r4, c12, c0, 0
mrc p15, 0, r5, c13, c0, 0
mrc p15, 0, r6, c13, c0, 1
stmia r8!, {r4-r6}
/* Primary remap, normal remap registers */
mrc p15, 0, r4, c10, c2, 0
mrc p15, 0, r5, c10, c2, 1
stmia r8!,{r4-r5}
/* Store current cpsr*/
mrs r2, cpsr
stmia r8!, {r2}
mrc p15, 0, r4, c1, c0, 0
/* save control register */
stmia r8!, {r4}
clean_caches:
/* Clean Data or unified cache to POU*/
/* How to invalidate only L1 cache???? - #FIX_ME# */
/* mcr p15, 0, r11, c7, c11, 1 */
cmp r9, #1 /* Check whether L2 inval is required or not*/
bne skip_l2_inval
clean_l2:
/* read clidr */
mrc p15, 1, r0, c0, c0, 1
/* extract loc from clidr */
ands r3, r0, #0x7000000
/* left align loc bit field */
mov r3, r3, lsr #23
/* if loc is 0, then no need to clean */
beq finished
/* start clean at cache level 0 */
mov r10, #0
loop1:
/* work out 3x current cache level */
add r2, r10, r10, lsr #1
/* extract cache type bits from clidr*/
mov r1, r0, lsr r2
/* mask of the bits for current cache only */
and r1, r1, #7
/* see what cache we have at this level */
cmp r1, #2
/* skip if no cache, or just i-cache */
blt skip
/* select current cache level in cssr */
mcr p15, 2, r10, c0, c0, 0
/* isb to sych the new cssr&csidr */
isb
/* read the new csidr */
mrc p15, 1, r1, c0, c0, 0
/* extract the length of the cache lines */
and r2, r1, #7
/* add 4 (line length offset) */
add r2, r2, #4
ldr r4, assoc_mask
/* find maximum number on the way size */
ands r4, r4, r1, lsr #3
/* find bit position of way size increment */
clz r5, r4
ldr r7, numset_mask
/* extract max number of the index size*/
ands r7, r7, r1, lsr #13
loop2:
mov r9, r4
/* create working copy of max way size*/
loop3:
/* factor way and cache number into r11 */
orr r11, r10, r9, lsl r5
/* factor index number into r11 */
orr r11, r11, r7, lsl r2
/*clean & invalidate by set/way */
mcr p15, 0, r11, c7, c10, 2
/* decrement the way*/
subs r9, r9, #1
bge loop3
/*decrement the index */
subs r7, r7, #1
bge loop2
skip:
add r10, r10, #2
/* increment cache number */
cmp r3, r10
bgt loop1
finished:
/*swith back to cache level 0 */
mov r10, #0
/* select current cache level in cssr */
mcr p15, 2, r10, c0, c0, 0
isb
skip_l2_inval:
/* Data memory barrier and Data sync barrier */
mov r1, #0
mcr p15, 0, r1, c7, c10, 4
mcr p15, 0, r1, c7, c10, 5
wfi @ wait for interrupt
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
bl i_dll_wait
/* restore regs and return */
ldmfd sp!, {r0-r12, pc}
i_dll_wait:
ldr r4, clk_stabilize_delay
i_dll_delay:
subs r4, r4, #0x1
bne i_dll_delay
ldr r4, sdrc_power
ldr r5, [r4]
bic r5, r5, #0x40
str r5, [r4]
bx lr
pm_prepwstst_core:
.word PM_PREPWSTST_CORE_V
pm_prepwstst_mpu:
.word PM_PREPWSTST_MPU_V
pm_pwstctrl_mpu:
.word PM_PWSTCTRL_MPU_P
scratchpad_base:
.word SCRATCHPAD_BASE_P
sdrc_power:
.word SDRC_POWER_V
context_mem:
.word 0x803E3E14
clk_stabilize_delay:
.word 0x000001FF
assoc_mask:
.word 0x3ff
numset_mask:
.word 0x7fff
ttbrbit_mask:
.word 0xFFFFC000
table_index_mask:
.word 0xFFF00000
table_entry:
.word 0x00000C02
cache_pred_disable_mask:
.word 0xFFFFE7FB
ENTRY(omap34xx_cpu_suspend_sz)
.word . - omap34xx_cpu_suspend

View File

@@ -124,11 +124,11 @@ omap242x_sdi_cm_clksel2_pll:
omap242x_sdi_sdrc_dlla_ctrl:
.word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
omap242x_sdi_prcm_voltctrl:
.word OMAP242X_PRCM_VOLTCTRL
.word OMAP2420_PRCM_VOLTCTRL
prcm_mask_val:
.word 0xFFFF3FFC
omap242x_sdi_timer_32ksynct_cr:
.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
.word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
ENTRY(omap242x_sram_ddr_init_sz)
.word . - omap242x_sram_ddr_init
@@ -220,11 +220,11 @@ omap242x_srs_sdrc_dlla_ctrl:
omap242x_srs_sdrc_rfr_ctrl:
.word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
omap242x_srs_prcm_voltctrl:
.word OMAP242X_PRCM_VOLTCTRL
.word OMAP2420_PRCM_VOLTCTRL
ddr_prcm_mask_val:
.word 0xFFFF3FFC
omap242x_srs_timer_32ksynct:
.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
.word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
ENTRY(omap242x_sram_reprogram_sdrc_sz)
.word . - omap242x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@ wait_dll_lock:
ldmfd sp!, {r0-r12, pc} @ restore regs and return
omap242x_ssp_set_config:
.word OMAP242X_PRCM_CLKCFG_CTRL
.word OMAP2420_PRCM_CLKCFG_CTRL
omap242x_ssp_pll_ctl:
.word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN)
omap242x_ssp_pll_stat:

View File

@@ -124,11 +124,11 @@ omap243x_sdi_cm_clksel2_pll:
omap243x_sdi_sdrc_dlla_ctrl:
.word OMAP243X_SDRC_REGADDR(SDRC_DLLA_CTRL)
omap243x_sdi_prcm_voltctrl:
.word OMAP243X_PRCM_VOLTCTRL
.word OMAP2430_PRCM_VOLTCTRL
prcm_mask_val:
.word 0xFFFF3FFC
omap243x_sdi_timer_32ksynct_cr:
.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
.word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
ENTRY(omap243x_sram_ddr_init_sz)
.word . - omap243x_sram_ddr_init
@@ -220,11 +220,11 @@ omap243x_srs_sdrc_dlla_ctrl:
omap243x_srs_sdrc_rfr_ctrl:
.word OMAP243X_SDRC_REGADDR(SDRC_RFR_CTRL_0)
omap243x_srs_prcm_voltctrl:
.word OMAP243X_PRCM_VOLTCTRL
.word OMAP2430_PRCM_VOLTCTRL
ddr_prcm_mask_val:
.word 0xFFFF3FFC
omap243x_srs_timer_32ksynct:
.word IO_ADDRESS(OMAP2_32KSYNCT_BASE + 0x010)
.word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
ENTRY(omap243x_sram_reprogram_sdrc_sz)
.word . - omap243x_sram_reprogram_sdrc
@@ -305,7 +305,7 @@ wait_dll_lock:
ldmfd sp!, {r0-r12, pc} @ restore regs and return
omap243x_ssp_set_config:
.word OMAP243X_PRCM_CLKCFG_CTRL
.word OMAP2430_PRCM_CLKCFG_CTRL
omap243x_ssp_pll_ctl:
.word OMAP2430_CM_REGADDR(PLL_MOD, CM_CLKEN)
omap243x_ssp_pll_stat:

View File

@@ -40,69 +40,74 @@
/*
* Change frequency of core dpll
* r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
* r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for
* SDRC rates < 83MHz
*/
ENTRY(omap3_sram_configure_core_dpll)
stmfd sp!, {r1-r12, lr} @ store regs to stack
ldr r4, [sp, #52] @ pull extra args off the stack
dsb @ flush buffered writes to interconnect
cmp r3, #0x2
blne configure_sdrc
cmp r3, #0x2
cmp r4, #0x1
bleq unlock_dll
blne lock_dll
cmp r3, #0x1
blne unlock_dll
bl sdram_in_selfrefresh @ put the SDRAM in self refresh
bl configure_core_dpll
bl enable_sdrc
cmp r3, #0x1
blne wait_dll_unlock
cmp r3, #0x2
cmp r4, #0x1
bleq wait_dll_unlock
blne wait_dll_lock
cmp r3, #0x1
blne configure_sdrc
isb @ prevent speculative exec past here
mov r0, #0 @ return value
ldmfd sp!, {r1-r12, pc} @ restore regs and return
unlock_dll:
ldr r4, omap3_sdrc_dlla_ctrl
ldr r5, [r4]
orr r5, r5, #0x4
str r5, [r4]
ldr r11, omap3_sdrc_dlla_ctrl
ldr r12, [r11]
orr r12, r12, #0x4
str r12, [r11] @ (no OCP barrier needed)
bx lr
lock_dll:
ldr r4, omap3_sdrc_dlla_ctrl
ldr r5, [r4]
bic r5, r5, #0x4
str r5, [r4]
ldr r11, omap3_sdrc_dlla_ctrl
ldr r12, [r11]
bic r12, r12, #0x4
str r12, [r11] @ (no OCP barrier needed)
bx lr
sdram_in_selfrefresh:
mov r5, #0x0 @ Move 0 to R5
mcr p15, 0, r5, c7, c10, 5 @ memory barrier
ldr r4, omap3_sdrc_power @ read the SDRC_POWER register
ldr r5, [r4] @ read the contents of SDRC_POWER
orr r5, r5, #0x40 @ enable self refresh on idle req
str r5, [r4] @ write back to SDRC_POWER register
ldr r4, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg
ldr r5, [r4]
bic r5, r5, #0x2 @ disable iclk bit for SRDC
str r5, [r4]
ldr r11, omap3_sdrc_power @ read the SDRC_POWER register
ldr r12, [r11] @ read the contents of SDRC_POWER
mov r9, r12 @ keep a copy of SDRC_POWER bits
orr r12, r12, #0x40 @ enable self refresh on idle req
bic r12, r12, #0x4 @ clear PWDENA
str r12, [r11] @ write back to SDRC_POWER register
ldr r12, [r11] @ posted-write barrier for SDRC
ldr r11, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg
ldr r12, [r11]
bic r12, r12, #0x2 @ disable iclk bit for SDRC
str r12, [r11]
wait_sdrc_idle:
ldr r4, omap3_cm_idlest1_core
ldr r5, [r4]
and r5, r5, #0x2 @ check for SDRC idle
cmp r5, #2
ldr r11, omap3_cm_idlest1_core
ldr r12, [r11]
and r12, r12, #0x2 @ check for SDRC idle
cmp r12, #2
bne wait_sdrc_idle
bx lr
configure_core_dpll:
ldr r4, omap3_cm_clksel1_pll
ldr r5, [r4]
ldr r6, core_m2_mask_val @ modify m2 for core dpll
and r5, r5, r6
orr r5, r5, r3, lsl #0x1B @ r3 contains the M2 val
str r5, [r4]
mov r5, #0x800 @ wait for the clock to stabilise
ldr r11, omap3_cm_clksel1_pll
ldr r12, [r11]
ldr r10, core_m2_mask_val @ modify m2 for core dpll
and r12, r12, r10
orr r12, r12, r3, lsl #0x1B @ r3 contains the M2 val
str r12, [r11]
ldr r12, [r11] @ posted-write barrier for CM
mov r12, #0x800 @ wait for the clock to stabilise
cmp r3, #2
bne wait_clk_stable
bx lr
wait_clk_stable:
subs r5, r5, #1
subs r12, r12, #1
bne wait_clk_stable
nop
nop
@@ -116,42 +121,42 @@ wait_clk_stable:
nop
bx lr
enable_sdrc:
ldr r4, omap3_cm_iclken1_core
ldr r5, [r4]
orr r5, r5, #0x2 @ enable iclk bit for SDRC
str r5, [r4]
ldr r11, omap3_cm_iclken1_core
ldr r12, [r11]
orr r12, r12, #0x2 @ enable iclk bit for SDRC
str r12, [r11]
wait_sdrc_idle1:
ldr r4, omap3_cm_idlest1_core
ldr r5, [r4]
and r5, r5, #0x2
cmp r5, #0
ldr r11, omap3_cm_idlest1_core
ldr r12, [r11]
and r12, r12, #0x2
cmp r12, #0
bne wait_sdrc_idle1
ldr r4, omap3_sdrc_power
ldr r5, [r4]
bic r5, r5, #0x40
str r5, [r4]
restore_sdrc_power_val:
ldr r11, omap3_sdrc_power
str r9, [r11] @ restore SDRC_POWER, no barrier needed
bx lr
wait_dll_lock:
ldr r4, omap3_sdrc_dlla_status
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x4
ldr r11, omap3_sdrc_dlla_status
ldr r12, [r11]
and r12, r12, #0x4
cmp r12, #0x4
bne wait_dll_lock
bx lr
wait_dll_unlock:
ldr r4, omap3_sdrc_dlla_status
ldr r5, [r4]
and r5, r5, #0x4
cmp r5, #0x0
ldr r11, omap3_sdrc_dlla_status
ldr r12, [r11]
and r12, r12, #0x4
cmp r12, #0x0
bne wait_dll_unlock
bx lr
configure_sdrc:
ldr r4, omap3_sdrc_rfr_ctrl
str r0, [r4]
ldr r4, omap3_sdrc_actim_ctrla
str r1, [r4]
ldr r4, omap3_sdrc_actim_ctrlb
str r2, [r4]
ldr r11, omap3_sdrc_rfr_ctrl
str r0, [r11]
ldr r11, omap3_sdrc_actim_ctrla
str r1, [r11]
ldr r11, omap3_sdrc_actim_ctrlb
str r2, [r11]
ldr r2, [r11] @ posted-write barrier for SDRC
bx lr
omap3_sdrc_power:

View File

@@ -17,9 +17,10 @@
*
* Some parts based off of TI's 24xx code:
*
* Copyright (C) 2004 Texas Instruments, Inc.
* Copyright (C) 2004-2009 Texas Instruments, Inc.
*
* Roughly modelled after the OMAP1 MPU timer code.
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -82,7 +83,8 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_PERIODIC:
period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
period -= 1;
if (cpu_is_omap44xx())
period = 0xff; /* FIXME: */
omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
break;
case CLOCK_EVT_MODE_ONESHOT:
@@ -145,6 +147,9 @@ static void __init omap2_gp_clockevent_init(void)
"timer-gp: omap_dm_timer_set_source() failed\n");
tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
if (cpu_is_omap44xx())
/* Assuming 32kHz clk is driving GPT1 */
tick_rate = 32768; /* FIXME: */
pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
gptimer_id, tick_rate);

View File

@@ -28,10 +28,20 @@
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/pm.h>
#include <mach/mux.h>
#include <mach/usb.h>
#define OTG_SYSCONFIG (OMAP34XX_HSUSB_OTG_BASE + 0x404)
static void __init usb_musb_pm_init(void)
{
/* Ensure force-idle mode for OTG controller */
if (cpu_is_omap34xx())
omap_writel(0, OTG_SYSCONFIG);
}
#ifdef CONFIG_USB_MUSB_SOC
static struct resource musb_resources[] = {
[0] = { /* start and end set dynamically */
.flags = IORESOURCE_MEM,
@@ -184,4 +194,13 @@ void __init usb_musb_init(void)
printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
return;
}
usb_musb_pm_init();
}
#else
void __init usb_musb_init(void)
{
usb_musb_pm_init();
}
#endif /* CONFIG_USB_MUSB_SOC */