summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/Kconfig31
-rw-r--r--arch/arm/mach-omap2/Makefile7
-rw-r--r--arch/arm/mach-omap2/board-minnow.c122
-rw-r--r--arch/arm/mach-omap2/board-omap3h1-bluetooth.c387
-rw-r--r--arch/arm/mach-omap2/board-omap3h1.c256
-rw-r--r--arch/arm/mach-omap2/board-omap3h1.h30
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c8
-rw-r--r--arch/arm/mach-omap2/control.c26
-rw-r--r--arch/arm/mach-omap2/control.h10
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c4
-rw-r--r--arch/arm/mach-omap2/devices.c27
-rw-r--r--arch/arm/mach-omap2/display.c65
-rw-r--r--arch/arm/mach-omap2/dss-common.c26
-rw-r--r--arch/arm/mach-omap2/dss-common.h2
-rw-r--r--arch/arm/mach-omap2/i2c.c19
-rw-r--r--arch/arm/mach-omap2/mux.c44
-rw-r--r--arch/arm/mach-omap2/omap-pm-noop.c29
-rw-r--r--arch/arm/mach-omap2/omap-pm.h4
-rw-r--r--arch/arm/mach-omap2/omap3-restart.c31
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c96
-rw-r--r--arch/arm/mach-omap2/opp.c4
-rw-r--r--arch/arm/mach-omap2/pad_wkup.c167
-rw-r--r--arch/arm/mach-omap2/pad_wkup.h5
-rw-r--r--arch/arm/mach-omap2/pm-debug-regs.c532
-rw-r--r--arch/arm/mach-omap2/pm-debug-regs.h35
-rw-r--r--arch/arm/mach-omap2/pm-debug.c8
-rw-r--r--arch/arm/mach-omap2/pm.c23
-rw-r--r--arch/arm/mach-omap2/pm.h2
-rw-r--r--arch/arm/mach-omap2/pm34xx.c141
-rw-r--r--arch/arm/mach-omap2/prcm-common.h1
-rw-r--r--arch/arm/mach-omap2/prm2xxx.h3
-rw-r--r--arch/arm/mach-omap2/prm_common.c8
-rw-r--r--arch/arm/mach-omap2/sdram-toshiba-hynix-numonyx.h66
-rw-r--r--arch/arm/mach-omap2/serial.c30
36 files changed, 2161 insertions, 92 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index f49cd51e162..662b2bb0921 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -207,6 +207,12 @@ config MACH_OMAP3_BEAGLE
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBB
+
+config MACH_OMAP3_H1
+ bool "OMAP3 H1 board"
+ depends on ARCH_OMAP3
+ default y
+ select OMAP_PACKAGE_CBP
config MACH_DEVKIT8000
bool "DEVKIT8000 board"
@@ -368,6 +374,12 @@ config MACH_OMAP_3630SDP
default y
select OMAP_PACKAGE_CBP
+config MACH_MINNOW
+ bool "Motorola Minnow Product"
+ depends on ARCH_OMAP3
+ default y
+ select OMAP_PACKAGE_CBP
+
config MACH_TI8168EVM
bool "TI8168 Evaluation Module"
depends on SOC_TI81XX
@@ -414,6 +426,25 @@ config OMAP3_SDRC_AC_TIMING
wish to say no. Selecting yes without understanding what is
going on could result in system crashes;
+
+config OMAP3_PAD_WKUP_IO
+ bool "Enable Generation of IRQ from pad status"
+ depends on ARCH_OMAP3
+ default n
+ help
+ For offmode, gpio (and possibly other) domains can wakeup the system
+ but will not retain their irq status internally. This function generates
+ the configured irq on each time the io irq (315) fires.
+
+config DISABLE_OMAP_ERRATA_i583
+ bool "Override errata i583"
+ depends on ARCH_OMAP3
+ default n
+ help
+ Errata i583 affects JDEC memory timing when waking from OFF mode on
+ ES 1.1 and older OMAP3. If the system clock is 26MHz or 38.4MHz and
+ there is no DDR on CS1, then it is safe to disable this errata check.
+
config OMAP4_ERRATA_I688
bool "OMAP4 errata: Async Bridge Corruption"
depends on (ARCH_OMAP4 || SOC_OMAP5) && !ARCH_MULTIPLATFORM
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 55a9d677768..8df971b821b 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -8,7 +8,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
# Common support
obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
- omap_device.o sram.o
+ omap_device.o sram.o pad_wkup.o
omap-2-3-common = irq.o
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
@@ -85,7 +85,7 @@ obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o
obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o
obj-$(CONFIG_SOC_OMAP5) += omap-mpuss-lowpower.o
-obj-$(CONFIG_PM_DEBUG) += pm-debug.o
+obj-$(CONFIG_PM_DEBUG) += pm-debug.o pm-debug-regs.o
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o
@@ -225,6 +225,8 @@ obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o
+obj-$(CONFIG_MACH_OMAP3_H1) += board-omap3h1.o \
+ board-omap3h1-bluetooth.o
obj-$(CONFIG_MACH_DEVKIT8000) += board-devkit8000.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o
obj-$(CONFIG_MACH_OMAP3530_LV_SOM) += board-omap3logic.o
@@ -253,6 +255,7 @@ obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o
obj-$(CONFIG_MACH_TOUCHBOOK) += board-omap3touchbook.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o
+obj-$(CONFIG_MACH_MINNOW) += board-minnow.o
obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
diff --git a/arch/arm/mach-omap2/board-minnow.c b/arch/arm/mach-omap2/board-minnow.c
new file mode 100644
index 00000000000..af6f13b371d
--- /dev/null
+++ b/arch/arm/mach-omap2/board-minnow.c
@@ -0,0 +1,122 @@
+/*
+ * linux/arch/arm/mach-omap2/board-minnow.c
+ *
+ * Copyright (C) 2013 Motorola Mobility, Inc.
+ *
+ * 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 <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/input/touch_platform.h>
+#include <linux/usb/musb.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/ti_wilink_st.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mux.h"
+#include "common.h"
+#include "dss-common.h"
+#include "control.h"
+
+#include "sdram-toshiba-hynix-numonyx.h"
+
+static int platform_wilink_kim_suspend(struct platform_device *pdev,
+ pm_message_t msg);
+static int platform_wilink_kim_resume(struct platform_device *pdev);
+
+static struct of_device_id omap_dt_match_table[] __initdata = {
+ { .compatible = "simple-bus", },
+ { .compatible = "ti,omap-infra", },
+ { }
+};
+
+static const char *omap3_gp_boards_compat[] __initdata = {
+ "mot,omap3-minnow",
+ NULL,
+};
+
+struct ti_st_plat_data wilink_pdata = {
+ .nshutdown_gpio = 83,
+ .dev_name = "/dev/ttyO1",
+ .port_index = 1,
+ .flow_cntrl = 1,
+ .baud_rate = 3000000,
+ .suspend = platform_wilink_kim_suspend,
+ .resume = platform_wilink_kim_resume,
+};
+
+static struct platform_device wl18xx_device = {
+ .name = "kim",
+ .id = -1,
+ .dev.platform_data = &wilink_pdata,
+};
+
+static struct platform_device hci_tty_device = {
+ .name = "hci_tty",
+ .id = -1,
+};
+
+static int platform_wilink_kim_suspend(struct platform_device *pdev,
+ pm_message_t msg)
+{
+ return 0;
+}
+
+static int platform_wilink_kim_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static inline void __init minnow_init_btwilink(void)
+{
+ platform_device_register(&wl18xx_device);
+ platform_device_register(&hci_tty_device);
+}
+
+static void __init minnow_init_gpio_clock(void)
+{
+ struct of_phandle_args clkspec;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ clkspec.np = of_find_compatible_node(NULL, NULL, "gpio-clock");
+ if (clkspec.np) {
+ of_gpio_clk_setup(clkspec.np);
+ clk = of_clk_get_from_provider(&clkspec);
+ if (!IS_ERR(clk)) {
+ cl = clkdev_alloc(clk, clkspec.np->name, NULL);
+ if (cl)
+ clkdev_add(cl);
+ }
+ }
+}
+
+static void __init minnow_init(void)
+{
+ of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
+ minnow_init_gpio_clock();
+ omap_sdrc_init(JEDEC_JESD209A_sdrc_params, JEDEC_JESD209A_sdrc_params);
+ omap3_enable_usim_buffer(); /* Needed for GPIOs in USIM block */
+ omap_minnow_display_init();
+ minnow_init_btwilink();
+}
+
+MACHINE_START(MINNOW, "minnow")
+ .atag_offset = 0x100,
+ .reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = omap3630_init_early,
+ .init_irq = omap_intc_of_init,
+ .handle_irq = omap3_intc_handle_irq,
+ .init_machine = minnow_init,
+ .init_late = omap3630_init_late,
+ .init_time = omap3_sync32k_timer_init,
+ .dt_compat = omap3_gp_boards_compat,
+ .restart = omap3xxx_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3h1-bluetooth.c b/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
new file mode 100644
index 00000000000..52bf419b549
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3h1-bluetooth.c
@@ -0,0 +1,387 @@
+/*
+ * Bluetooth Broadcomm and low power control via GPIO
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * 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
+ *
+ */
+
+ /*
+ * Adapted from board-tuna-bluetooth.c by Evan Wilson <evan@oliodevices.com
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/irq.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/wakelock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/mach-types.h>
+#include "serial.h"
+#include "board-omap3h1.h"
+#include <linux/regulator/driver.h>
+
+static void update_host_wake_locked(int);
+
+#define BT_REG_GPIO 180
+
+#define BT_WAKE_GPIO 93
+#define BT_HOST_WAKE_GPIO 11
+
+static struct rfkill *bt_rfkill;
+static struct regulator *clk32ksys_reg;
+static bool bt_enabled;
+static bool host_wake_uart_enabled;
+static bool wake_uart_enabled;
+static struct dentry *btdebugdent;
+
+struct bcm_bt_lpm {
+ int wake;
+ int host_wake;
+
+ struct hrtimer enter_lpm_timer;
+ ktime_t enter_lpm_delay;
+
+ struct uart_port *uport;
+
+ struct wake_lock wake_lock;
+ char wake_lock_name[100];
+} bt_lpm;
+
+static int bcm20702_bt_rfkill_set_power(void *data, bool blocked)
+{
+ // rfkill_ops callback. Turn transmitter on when blocked is false
+ if (!blocked) {
+ if (clk32ksys_reg && !bt_enabled)
+ regulator_enable(clk32ksys_reg);
+
+ gpio_set_value(BT_REG_GPIO, 1);
+
+ } else {
+ // Chip won't toggle host_wake after reset. Make sure
+ // we don't hold the wake_lock until chip wakes up again.
+ update_host_wake_locked(0);
+
+ gpio_set_value(BT_REG_GPIO, 0);
+ if (clk32ksys_reg && bt_enabled)
+ regulator_disable(clk32ksys_reg);
+ }
+
+ bt_enabled = !blocked;
+
+ return 0;
+}
+
+static const struct rfkill_ops bcm20702_bt_rfkill_ops = {
+ .set_block = bcm20702_bt_rfkill_set_power,
+};
+
+static void set_wake_locked(int wake)
+{
+ bt_lpm.wake = wake;
+
+ if (!wake)
+ wake_unlock(&bt_lpm.wake_lock);
+
+ if (!wake_uart_enabled && wake)
+ //omap_uart_enable(2);
+
+ gpio_set_value(BT_WAKE_GPIO, wake);
+
+ if (wake_uart_enabled && !wake)
+ //omap_uart_disable(2);
+
+ wake_uart_enabled = wake;
+}
+
+static enum hrtimer_restart enter_lpm(struct hrtimer *timer) {
+ unsigned long flags;
+ spin_lock_irqsave(&bt_lpm.uport->lock, flags);
+ set_wake_locked(0);
+ spin_unlock_irqrestore(&bt_lpm.uport->lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport) {
+ bt_lpm.uport = uport;
+
+ hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer);
+
+ set_wake_locked(1);
+
+ hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay,
+ HRTIMER_MODE_REL);
+}
+EXPORT_SYMBOL(bcm_bt_lpm_exit_lpm_locked);
+
+static void update_host_wake_locked(int host_wake)
+{
+ if (host_wake == bt_lpm.host_wake)
+ return;
+
+ bt_lpm.host_wake = host_wake;
+
+ if (host_wake) {
+ wake_lock(&bt_lpm.wake_lock);
+ if (!host_wake_uart_enabled) {
+ //omap_uart_enable(2);
+ }
+ } else {
+ if (host_wake_uart_enabled) {
+ //omap_uart_disable(2);
+ }
+ // Take a timed wakelock, so that upper layers can take it.
+ // The chipset deasserts the hostwake lock, when there is no
+ // more data to send.
+ wake_lock_timeout(&bt_lpm.wake_lock, HZ/2);
+ }
+
+ host_wake_uart_enabled = host_wake;
+
+}
+
+static irqreturn_t host_wake_isr(int irq, void *dev)
+{
+ int host_wake;
+ unsigned long flags;
+
+ host_wake = gpio_get_value(BT_HOST_WAKE_GPIO);
+ irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+
+ if (!bt_lpm.uport) {
+ bt_lpm.host_wake = host_wake;
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&bt_lpm.uport->lock, flags);
+ update_host_wake_locked(host_wake);
+ spin_unlock_irqrestore(&bt_lpm.uport->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm_bt_lpm_init(struct platform_device *pdev)
+{
+ int irq;
+ int ret;
+ int rc;
+
+ rc = gpio_request(BT_WAKE_GPIO, "bcm20702_wake_gpio");
+ if (unlikely(rc)) {
+ return rc;
+ }
+
+ rc = gpio_request(BT_HOST_WAKE_GPIO, "bcm20702_host_wake_gpio");
+ if (unlikely(rc)) {
+ gpio_free(BT_WAKE_GPIO);
+ return rc;
+ }
+
+ hrtimer_init(&bt_lpm.enter_lpm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ bt_lpm.enter_lpm_delay = ktime_set(1, 0); /* 1 sec */
+ bt_lpm.enter_lpm_timer.function = enter_lpm;
+
+ bt_lpm.host_wake = 0;
+
+ irq = gpio_to_irq(BT_HOST_WAKE_GPIO);
+ ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_HIGH,
+ "bt host_wake", NULL);
+ if (ret) {
+ gpio_free(BT_WAKE_GPIO);
+ gpio_free(BT_HOST_WAKE_GPIO);
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq, 1);
+ if (ret) {
+ gpio_free(BT_WAKE_GPIO);
+ gpio_free(BT_HOST_WAKE_GPIO);
+ return ret;
+ }
+
+ gpio_direction_output(BT_WAKE_GPIO, 0);
+ gpio_direction_input(BT_HOST_WAKE_GPIO);
+
+ snprintf(bt_lpm.wake_lock_name, sizeof(bt_lpm.wake_lock_name),
+ "BTLowPower");
+ wake_lock_init(&bt_lpm.wake_lock, WAKE_LOCK_SUSPEND,
+ bt_lpm.wake_lock_name);
+ return 0;
+}
+
+static int btdebug_dump(struct seq_file *sf, void *private)
+{
+ seq_printf(sf, "en=%d bt_wake=%d lpm.w=%d w_uart_en=%d\n",
+ bt_enabled, gpio_get_value(BT_WAKE_GPIO),
+ bt_lpm.wake, wake_uart_enabled);
+ seq_printf(sf, "bt_host_wake=%d lpm.hw=%d hw_uart_en=%d\n",
+ gpio_get_value(BT_HOST_WAKE_GPIO), bt_lpm.host_wake,
+ host_wake_uart_enabled);
+ return 0;
+}
+
+static int btdebug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, btdebug_dump, NULL);
+}
+
+static const struct file_operations btdebug_fops = {
+ .open = btdebug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int bcm20702_bluetooth_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ int ret = 0;
+
+// rc = gpio_request(BT_RESET_GPIO, "bcm20702_nreset_gpip");
+// if (unlikely(rc)) {
+// return rc;
+// }
+
+ rc = gpio_request(BT_REG_GPIO, "bcm20702_nshutdown_gpio");
+ if (unlikely(rc)) {
+ //gpio_free(BT_RESET_GPIO);
+ return rc;
+ }
+
+ clk32ksys_reg = regulator_get(0, "clk32ksys");
+ if (IS_ERR(clk32ksys_reg)) {
+ pr_err("clk32ksys reg not found!\n");
+ clk32ksys_reg = NULL;
+ }
+
+ gpio_direction_output(BT_REG_GPIO, 1);
+ //gpio_direction_output(BT_RESET_GPIO, 1);
+
+ bt_rfkill = rfkill_alloc("bcm20702 Bluetooth", &pdev->dev,
+ RFKILL_TYPE_BLUETOOTH, &bcm20702_bt_rfkill_ops,
+ NULL);
+
+ if (unlikely(!bt_rfkill)) {
+ //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_REG_GPIO);
+ return -ENOMEM;
+ }
+
+ rfkill_set_states(bt_rfkill, true, false);
+ rc = rfkill_register(bt_rfkill);
+
+ if (unlikely(rc)) {
+ rfkill_destroy(bt_rfkill);
+ //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_REG_GPIO);
+ return -1;
+ }
+
+ ret = bcm_bt_lpm_init(pdev);
+ if (ret) {
+ rfkill_unregister(bt_rfkill);
+ rfkill_destroy(bt_rfkill);
+
+ //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_REG_GPIO);
+ }
+
+ btdebugdent = debugfs_create_file("bt", S_IRUGO, NULL, NULL,
+ &btdebug_fops);
+ if (IS_ERR_OR_NULL(btdebugdent))
+ pr_err("%s: failed to create debugfs file\n", __func__);
+
+ return ret;
+}
+
+static int bcm20702_bluetooth_remove(struct platform_device *pdev)
+{
+ rfkill_unregister(bt_rfkill);
+ rfkill_destroy(bt_rfkill);
+
+ if (!IS_ERR_OR_NULL(btdebugdent))
+ debugfs_remove(btdebugdent);
+
+ gpio_free(BT_REG_GPIO);
+ //gpio_free(BT_RESET_GPIO);
+ gpio_free(BT_WAKE_GPIO);
+ gpio_free(BT_HOST_WAKE_GPIO);
+ regulator_put(clk32ksys_reg);
+
+ wake_lock_destroy(&bt_lpm.wake_lock);
+ return 0;
+}
+
+int bcm4430_bluetooth_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int irq = gpio_to_irq(BT_HOST_WAKE_GPIO);
+ int host_wake;
+
+ disable_irq(irq);
+ host_wake = gpio_get_value(BT_HOST_WAKE_GPIO);
+
+ if (host_wake) {
+ enable_irq(irq);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+int bcm4430_bluetooth_resume(struct platform_device *pdev)
+{
+ int irq = gpio_to_irq(BT_HOST_WAKE_GPIO);
+ enable_irq(irq);
+ return 0;
+}
+
+static struct platform_driver bcm20702_bluetooth_platform_driver = {
+ .probe = bcm20702_bluetooth_probe,
+ .remove = bcm20702_bluetooth_remove,
+ .suspend = bcm4430_bluetooth_suspend,
+ .resume = bcm4430_bluetooth_resume,
+ .driver = {
+ .name = "bcm20702_bluetooth",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bcm20702_bluetooth_init(void)
+{
+ bt_enabled = false;
+ return platform_driver_register(&bcm20702_bluetooth_platform_driver);
+}
+
+static void __exit bcm20702_bluetooth_exit(void)
+{
+ platform_driver_unregister(&bcm20702_bluetooth_platform_driver);
+}
+
+
+module_init(bcm20702_bluetooth_init);
+module_exit(bcm20702_bluetooth_exit);
+
+MODULE_ALIAS("platform:bcm20702");
+MODULE_DESCRIPTION("bcm20702_bluetooth");
+MODULE_AUTHOR("Jaikumar Ganesh <jaikumar@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap2/board-omap3h1.c b/arch/arm/mach-omap2/board-omap3h1.c
new file mode 100644
index 00000000000..a24b1fdda01
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3h1.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2014 Olio Devices, Inc.
+ * Authors: Evan Wilson <evan@oliodevices.com>
+ * Mattis Fjallstrom <mattis@oliodevices.com>
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Modified from the original mach-omap/omap2/board-generic.c did by Paul
+ * to support the OMAP2+ device tree boards with an unique board file.
+ *
+ * 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/io.h>
+#include <linux/opp.h>
+#include <linux/cpu.h>
+#include <linux/mpu.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/led-lm3530.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+#include <linux/platform_data/mtd-nand-omap2.h>
+
+#include "common.h"
+#include "omap_device.h"
+#include "gpmc.h"
+#include "soc.h"
+#include "mux.h"
+#include "pm.h"
+#include "board-flash.h"
+#include "common-board-devices.h"
+#include "board-omap3h1.h"
+
+#define NAND_CS 0
+#define MPUIRQ_GPIO 31
+#define LCD_RESET_GPIO 122
+
+static struct mtd_partition omap3h1_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
+ .size = 15 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot Env",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
+ .size = 1 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
+ .size = 40 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "initramfs",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0xC80000 */
+ .size = 80 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "ramdisk",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x1180000 */
+ .size = 40 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "system",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x1680000 */
+ .size = 2000 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "userdata",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x11180000 */
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct omap_dss_device omap3h1_lcd_device = {
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .name = "olio_h1_panel",
+ .driver_name = "ili9342_panel",
+ .phy.dpi.data_lines = 18,
+ .reset_gpio = LCD_RESET_GPIO,
+};
+
+static struct omap_dss_device *omap3h1_dss_devices[] = {
+ &omap3h1_lcd_device,
+};
+
+static struct omap_dss_board_info omap3h1_dss_data = {
+ .num_devices = 1,
+ .devices = omap3h1_dss_devices,
+ .default_device = &omap3h1_lcd_device,
+};
+
+static struct spi_board_info omap3h1_spi_board_info[] __initdata = {
+ {
+ .modalias = "ili9342-spi",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 375000,
+ .platform_data = &omap3h1_lcd_device,
+ .mode = SPI_MODE_0,
+ }
+};
+
+static int __init omap3h1_spi_init(void) {
+ spi_register_board_info(omap3h1_spi_board_info,
+ ARRAY_SIZE(omap3h1_spi_board_info));
+ return 0;
+}
+
+static struct mpu_platform_data mpu_data = {
+ .int_config = 0x00,
+ .level_shifter = 0,
+ .orientation = { -1, 0, 0,
+ 0, 1, 0,
+ 0, 0, -1 },
+};
+
+static struct lm3530_platform_data omap3h1_backlight_platform_data = {
+ .mode = LM3530_BL_MODE_MANUAL,
+ //.als_input_mode = LM3530_INPUT_ALS1,
+ .max_current = LM3530_FS_CURR_12mA,
+ //.pwm_pol_hi = true,
+ //.als_avrg_time = LM3530_ALS_AVRG_TIME_512ms,
+ .brt_ramp_law = 0,
+ .brt_ramp_fall = LM3530_RAMP_TIME_2s,
+ .brt_ramp_rise = LM3530_RAMP_TIME_2s,
+ //.als1_resistor_sel = LM3530_ALS_IMPD_13_53kOhm,
+ //.als2_resistor_sel = LM3530_ALS_IMPD_Z,
+ //.als_vmin = 730, /* mV */
+ //.als_vmax = 1020, /* mV */
+ .brt_val = 0x40, /* Max brightness */
+};
+
+static struct platform_device bcm20702_bluetooth_device = {
+ .name = "bcm20702_bluetooth",
+ .id = -1,
+ };
+
+static struct i2c_board_info __initdata omap3h1_i2c1_board_info[] = {
+ {
+ I2C_BOARD_INFO("mpu6515", 0x68),
+ // This is needed for the interrupt wake. IH_GPIO_BASE changed in 3.10 kernel
+ //.irq = (IH_GPIO_BASE + MPUIRQ_GPIO),
+ .platform_data = &mpu_data,
+ },
+ {
+ /* Backlight */
+ I2C_BOARD_INFO("lm3530-led", 0x38),
+ .platform_data = &omap3h1_backlight_platform_data,
+ },
+};
+
+static int __init omap3_h1_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 400, omap3h1_i2c1_board_info, ARRAY_SIZE(omap3h1_i2c1_board_info));
+ return 0;
+}
+
+static struct platform_device *omap3h1_devices[] __initdata = {
+ &bcm20702_bluetooth_device,
+};
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+ OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+ OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+
+ OMAP3_MUX(MCSPI1_CLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(MCSPI1_SIMO, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(MCSPI1_SOMI, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#endif
+
+static void __init omap3_h1_init(void)
+{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
+
+ omap3_h1_i2c_init();
+ omap_display_init(&omap3h1_dss_data);
+ omap_serial_init();
+ omap_sdrc_init(NULL, NULL);
+
+ board_nand_init(omap3h1_nand_partitions,
+ ARRAY_SIZE(omap3h1_nand_partitions), NAND_CS,
+ NAND_BUSWIDTH_16, NULL);
+
+ platform_add_devices(omap3h1_devices, ARRAY_SIZE(omap3h1_devices));
+ omap3h1_spi_init();
+ //h1_opp_init();
+}
+
+MACHINE_START(OMAP3_H1, "Olio OMAP3 H1 Board")
+ .atag_offset = 0x100,
+ .reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = omap3630_init_early,
+ .init_irq = omap3_init_irq,
+ .handle_irq = omap3_intc_handle_irq,
+ .init_machine = omap3_h1_init,
+ .init_late = omap3630_init_late,
+ .init_time = omap3_secure_sync32k_timer_init,
+ //.dt_compat = omap3_h1_boards_compat,
+ .restart = omap3xxx_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3h1.h b/arch/arm/mach-omap2/board-omap3h1.h
new file mode 100644
index 00000000000..343eaeaaf86
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3h1.h
@@ -0,0 +1,30 @@
+/*
+ * Bluetooth Broadcomm and low power control via GPIO
+ *
+ * Copyright (C) 2011 Samsung, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * 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
+ *
+ */
+
+#ifndef __BOARD_OMAP3H1__H__
+#define __BOARD_OMAP3H1__H__
+
+#include <linux/serial_core.h>
+
+extern void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport);
+
+#endif /* __BOARD_OMAP3H1_H__ */
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 45cd26430d1..e823edd05eb 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -3540,6 +3540,10 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "timer_32k_ck", &omap_32k_fck),
CLK(NULL, "timer_sys_ck", &sys_ck),
CLK(NULL, "cpufreq_ck", &dpll1_ck),
+ CLK("cpufreq-cpu0.0", NULL, &dpll1_ck),
+ CLK("48307220.vc", NULL, &osc_sys_ck),
+ CLK("483072b0.vp", NULL, &osc_sys_ck),
+ CLK("483072d0.vp", NULL, &osc_sys_ck),
};
static const char *enable_init_clks[] = {
@@ -3550,8 +3554,10 @@ static const char *enable_init_clks[] = {
int __init omap3xxx_clk_init(void)
{
- if (omap3_has_192mhz_clk())
+ if (omap3_has_192mhz_clk()) {
omap_96m_alwon_fck = omap_96m_alwon_fck_3630;
+ omap_96m_alwon_fck_3630.hw->clk = &omap_96m_alwon_fck;
+ }
if (cpu_is_omap3630()) {
dpll3_m3x2_ck = dpll3_m3x2_ck_3630;
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 2adb2683f07..ab5ec4b28ab 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -235,6 +235,32 @@ void omap3_ctrl_write_boot_mode(u8 bootmode)
__raw_writel(l, OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD + 4));
}
+/**
+ * omap3_enable_usim_IO - enable USIM block input/output buffers
+ *
+ * Enable USIM block input/output buffers. By default the buffers are
+ * not enabled. Once vdds is stable, they can be enabled. They must
+ * be enabled before using any GPIOs from this block.
+ */
+void omap3_enable_usim_buffer(void)
+{
+ u32 reg;
+ /*
+ * Configure USIM pins for 1.8V control and disable high-z state
+ * CTRL_PBIAS_LITE = 0x20b
+ */
+ reg = omap_ctrl_readl(OMAP343X_CONTROL_PBIAS_LITE);
+ reg |= (OMAP2_PBIASLITEVMODE0 | OMAP2_PBIASLITEPWRDNZ0);
+ reg |= OMAP343X_PBIASLITEPWRDNZ1;
+ reg &= ~OMAP343X_PBIASLITEVMODE1;
+ reg &= ~OMAP2_PBIASSPEEDCTRL0;
+ omap_ctrl_writel(reg, OMAP343X_CONTROL_PBIAS_LITE);
+
+ reg = omap_ctrl_readl(OMAP343X_CONTROL_WKUP_CTRL);
+ reg |= OMAP343X_USIM_IO_PWRDNZ;
+ omap_ctrl_writel(reg, OMAP343X_CONTROL_WKUP_CTRL);
+}
+
#endif
/**
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index e6c328128a0..8698aed1e84 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -243,6 +243,9 @@
#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
+/* 34xx USIM register offsets */
+#define OMAP343X_CONTROL_WKUP_CTRL (OMAP2_CONTROL_INTERFACE + 0x0A5C)
+
/* 36xx-only RTA - Retention till Access control registers and bits */
#define OMAP36XX_CONTROL_MEM_RTA_CTRL 0x40C
#define OMAP36XX_RTA_DISABLE 0x0
@@ -323,6 +326,9 @@
#define OMAP343X_SCRATCHPAD_REGADDR(reg) OMAP2_L4_IO_ADDRESS(\
OMAP343X_SCRATCHPAD + reg)
+/* CONTROL_WKUP bits */
+#define OMAP343X_USIM_IO_PWRDNZ (1 << 6)
+
/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */
#define AM35XX_USBOTG_VBUSP_CLK_SHIFT 0
#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT 1
@@ -390,6 +396,7 @@
#define FEAT_NEON_NONE 1
+
#ifndef __ASSEMBLY__
#ifdef CONFIG_ARCH_OMAP2PLUS
extern void __iomem *omap_ctrl_base_get(void);
@@ -417,6 +424,8 @@ extern void omap3630_ctrl_disable_rta(void);
extern int omap3_ctrl_save_padconf(void);
extern void omap2_set_globals_control(void __iomem *ctrl,
void __iomem *ctrl_pad);
+/* called from board-minnow.c to enable USIM GPIOs */
+extern void omap3_enable_usim_buffer(void);
#else
#define omap_ctrl_base_get() 0
#define omap_ctrl_readb(x) 0
@@ -429,6 +438,5 @@ extern void omap2_set_globals_control(void __iomem *ctrl,
#define omap4_ctrl_pad_writel(x, y) WARN_ON(1)
#endif
#endif /* __ASSEMBLY__ */
-
#endif /* __ARCH_ARM_MACH_OMAP2_CONTROL_H */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index e18709d3b95..039fe44215d 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -86,7 +86,7 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
{
.mpu_state = PWRDM_POWER_RET,
.core_state = PWRDM_POWER_RET,
- .per_min_state = PWRDM_POWER_OFF,
+ .per_min_state = PWRDM_POWER_RET,
},
{
.mpu_state = PWRDM_POWER_OFF,
@@ -131,7 +131,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
cpu_pm_enter();
/* Execute ARM wfi */
- omap_sram_idle();
+ omap_sram_idle(false);
/*
* Call idle CPU PM enter notifier chain to restore
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 4269fc14569..9017d5ea9f3 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -633,6 +633,32 @@ static void __init omap_init_ocp2scp(void)
static inline void omap_init_ocp2scp(void) { }
#endif
+#if defined(CONFIG_SGX_OMAP3630)
+static struct platform_device mapphone_omaplfb_device = {
+ .name = "omaplfb",
+ .id = -1,
+};
+static void __init omap_init_gpu(void)
+{
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ const char *oh_name = "gpu";
+ const char *name = "pvrsrvkm";
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("%s: Could not look up %s\n", __func__, oh_name);
+ return;
+ }
+
+ pdev = omap_device_build(name, -1, oh, NULL, 0);
+ WARN(IS_ERR(pdev),
+ "%s, Can't build omap_device for %s\n", __func__, name);
+ if (platform_device_register(&mapphone_omaplfb_device) < 0)
+ pr_err("%s: Could not register OMAP-LFB device\n", __func__);
+}
+#else
+static inline void omap_init_gpu(void) { }
+#endif
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
@@ -662,6 +688,7 @@ static int __init omap2_init_devices(void)
omap_init_rng();
omap_init_vout();
omap_init_ocp2scp();
+ omap_init_gpu();
return 0;
}
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index ff37be1f6f9..d22833a0f2a 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -320,6 +320,10 @@ static enum omapdss_version __init omap_display_get_version(void)
return OMAPDSS_VER_UNKNOWN;
}
+#ifdef CONFIG_OMAP2_DSS_RESET
+static int reset_omap_dss(void);
+#endif
+
int __init omap_display_init(struct omap_dss_board_info *board_data)
{
int r = 0;
@@ -415,7 +419,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
return PTR_ERR(pdev);
}
}
-
+#ifdef CONFIG_OMAP2_DSS_RESET
+ reset_omap_dss();
+#endif
return 0;
}
@@ -564,3 +570,60 @@ int omap_dss_reset(struct omap_hwmod *oh)
return r;
}
+
+#ifdef CONFIG_OMAP2_DSS_RESET
+#define DSS_CLKS 4
+static int reset_omap_dss(void)
+{
+ static const char * const clkstr[DSS_CLKS] = {
+ "dss_ick",
+ "dss1_alwon_fck",
+ "dss2_alwon_fck",
+ "dss_tv_fck"
+ };
+ struct clk *clk[DSS_CLKS];
+ int i, r = 0, c = 0;
+ struct omap_hwmod *oh_dss = omap_hwmod_lookup("dss_core");
+ struct omap_hwmod *oh_dispc = omap_hwmod_lookup("dss_dispc");
+ struct omap_hwmod *oh_dsi = omap_hwmod_lookup("dss_dsi1");
+
+ WARN((!oh_dss || !oh_dispc || !oh_dsi), "Reset lost!");
+
+ for (i = 0; i < DSS_CLKS; i++) {
+ clk[i] = clk_get(NULL, clkstr[i]);
+ if (!IS_ERR(clk[i])) {
+ r = clk_prepare_enable(clk[i]);
+ if (!r)
+ continue;
+ clk_put(clk[i]);
+ }
+ pr_warn("dss_core: failed enable %s\n", clkstr[i]);
+ clk[i] = ERR_PTR(-ENOENT);
+ }
+
+ /*
+ * clear DSS_CONTROL register to switch DSS clock sources to
+ * PRCM clock, if any
+ */
+ omap_hwmod_write(0x0, oh_dss, DSS_CONTROL);
+ dispc_disable_outputs();
+ omap_hwmod_write(0x0, oh_dss, DSS_SDI_CONTROL);
+ omap_hwmod_write(0x0, oh_dss, DSS_PLL_CONTROL);
+
+ omap_hwmod_write(0x02, oh_dss, DSS_SYSCONFIG);
+ omap_test_timeout((omap_hwmod_read(oh_dss, DSS_SYSSTATUS)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+ r = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
+ pr_warn("dss_core: reset DSS %s\n", r ? "failed" : "done");
+
+ for (i = 0; i < DSS_CLKS; i++) {
+ if (!IS_ERR(clk[i])) {
+ clk_disable_unprepare(clk[i]);
+ clk_put(clk[i]);
+ }
+ }
+
+ return r;
+}
+#endif
diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c
index 393aeefaebb..d850864aa7f 100644
--- a/arch/arm/mach-omap2/dss-common.c
+++ b/arch/arm/mach-omap2/dss-common.c
@@ -249,3 +249,29 @@ void __init omap_4430sdp_display_init_of(void)
omap_display_init(&sdp4430_dss_data);
}
+
+static struct omap_dss_device minnow_panel_lcd_device = {
+ .name = "lcd",
+ .driver_name = "minnow-panel",
+ .type = OMAP_DISPLAY_TYPE_DSI,
+ .data = NULL,
+ .phy.dsi = {
+ .module = 0,
+ },
+ .channel = OMAP_DSS_CHANNEL_LCD,
+};
+
+static struct omap_dss_device *minnow_panel_dss_devices[] = {
+ &minnow_panel_lcd_device,
+};
+
+static struct omap_dss_board_info minnow_panel_dss_data = {
+ .num_devices = ARRAY_SIZE(minnow_panel_dss_devices),
+ .devices = minnow_panel_dss_devices,
+ .default_device = &minnow_panel_lcd_device,
+};
+
+void __init omap_minnow_display_init(void)
+{
+ omap_display_init(&minnow_panel_dss_data);
+}
diff --git a/arch/arm/mach-omap2/dss-common.h b/arch/arm/mach-omap2/dss-common.h
index 915f6fff510..c8d24f42f49 100644
--- a/arch/arm/mach-omap2/dss-common.h
+++ b/arch/arm/mach-omap2/dss-common.h
@@ -11,4 +11,6 @@ void __init omap4_panda_display_init_of(void);
void __init omap_4430sdp_display_init(void);
void __init omap_4430sdp_display_init_of(void);
+void __init omap_minnow_display_init(void);
+
#endif
diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c
index d940e53dd9f..728ca6729a3 100644
--- a/arch/arm/mach-omap2/i2c.c
+++ b/arch/arm/mach-omap2/i2c.c
@@ -121,16 +121,6 @@ static int __init omap_i2c_nr_ports(void)
return ports;
}
-/*
- * XXX This function is a temporary compatibility wrapper - only
- * needed until the I2C driver can be converted to call
- * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
- */
-static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
-{
- omap_pm_set_max_mpu_wakeup_lat(dev, t);
-}
-
static const char name[] = "omap_i2c";
int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
@@ -168,15 +158,6 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
pdata->flags = dev_attr->flags;
- /*
- * When waiting for completion of a i2c transfer, we need to
- * set a wake up latency constraint for the MPU. This is to
- * ensure quick enough wakeup from idle, when transfer
- * completes.
- * Only omap3 has support for constraints
- */
- if (cpu_is_omap34xx())
- pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
pdev = omap_device_build(name, bus_id, oh, pdata,
sizeof(struct omap_i2c_bus_platform_data));
WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name);
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index f82cf878d6a..776ca198119 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -425,6 +425,35 @@ static irqreturn_t omap_hwmod_mux_handle_irq(int irq, void *unused)
return IRQ_HANDLED;
}
+/**
+ * _omap_hwmod_mux_count
+ *
+ * Increment data if given hwmod has a mux configured
+ */
+static int _omap_hwmod_mux_count(struct omap_hwmod *oh, void *data)
+{
+ int *count = (int *)data;
+
+ if (oh->mux)
+ (*count)++;
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_mux_count
+ *
+ * Count the total number of muxes configured.
+ */
+static int omap_hwmod_mux_count(void)
+{
+ int count = 0;
+
+ omap_hwmod_for_each(_omap_hwmod_mux_count, &count);
+
+ return count;
+}
+
/* Assumes the calling function takes care of locking */
void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
{
@@ -811,12 +840,17 @@ int __init omap_mux_late_init(void)
}
}
- ret = request_irq(omap_prcm_event_to_irq("io"),
- omap_hwmod_mux_handle_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
- "hwmod_io", omap_mux_late_init);
+ /* setup io interrupt handler if we have any configured mux'es */
+ if (omap_hwmod_mux_count()) {
+ ret = request_irq(omap_prcm_event_to_irq("io"),
+ omap_hwmod_mux_handle_irq,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "hwmod_io", omap_mux_late_init);
- if (ret)
- pr_warning("mux: Failed to setup hwmod io irq %d\n", ret);
+ if (ret)
+ pr_warning("mux: Failed to setup hwmod io irq %d\n",
+ ret);
+ }
omap_mux_dbg_init();
diff --git a/arch/arm/mach-omap2/omap-pm-noop.c b/arch/arm/mach-omap2/omap-pm-noop.c
index 6a3be2bebdd..aeb217bfab1 100644
--- a/arch/arm/mach-omap2/omap-pm-noop.c
+++ b/arch/arm/mach-omap2/omap-pm-noop.c
@@ -25,7 +25,6 @@
#include "omap_device.h"
#include "omap-pm.h"
-static bool off_mode_enabled;
static int dummy_context_loss_counter;
/*
@@ -281,28 +280,6 @@ unsigned long omap_pm_cpu_get_freq(void)
return 0;
}
-/**
- * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
- *
- * Intended for use only by OMAP PM core code to notify this layer
- * that off mode has been enabled.
- */
-void omap_pm_enable_off_mode(void)
-{
- off_mode_enabled = true;
-}
-
-/**
- * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled
- *
- * Intended for use only by OMAP PM core code to notify this layer
- * that off mode has been disabled.
- */
-void omap_pm_disable_off_mode(void)
-{
- off_mode_enabled = false;
-}
-
/*
* Device context loss tracking
*/
@@ -320,12 +297,14 @@ int omap_pm_get_dev_context_loss_count(struct device *dev)
if (dev->pm_domain == &omap_device_pm_domain) {
count = omap_device_get_context_loss_count(pdev);
} else {
- WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device",
+ WARN_ONCE(omap_pm_get_off_mode(),
+ "omap_pm: using dummy context loss counter; device %s "
+ "should be converted to omap_device",
dev_name(dev));
count = dummy_context_loss_counter;
- if (off_mode_enabled) {
+ if (omap_pm_get_off_mode()) {
count++;
/*
* Context loss count has to be a non-negative value.
diff --git a/arch/arm/mach-omap2/omap-pm.h b/arch/arm/mach-omap2/omap-pm.h
index 67faa7b8fe9..4511a53b8e3 100644
--- a/arch/arm/mach-omap2/omap-pm.h
+++ b/arch/arm/mach-omap2/omap-pm.h
@@ -18,6 +18,7 @@
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include <linux/opp.h>
+#include <linux/power/omap_prm.h>
/*
* agent_id values for use with omap_pm_set_min_bus_tput():
@@ -346,7 +347,4 @@ unsigned long omap_pm_cpu_get_freq(void);
*/
int omap_pm_get_dev_context_loss_count(struct device *dev);
-void omap_pm_enable_off_mode(void);
-void omap_pm_disable_off_mode(void);
-
#endif
diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c
index 923c582189e..92a177654e2 100644
--- a/arch/arm/mach-omap2/omap3-restart.c
+++ b/arch/arm/mach-omap2/omap3-restart.c
@@ -28,9 +28,40 @@
* Resets the SoC. For @cmd, see the 'reboot' syscall in
* kernel/sys.c. No return value.
*/
+
+
+static int in_panic;
+
+static int panic_prep_restart(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ in_panic = 1;
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+ .notifier_call = panic_prep_restart,
+};
+
void omap3xxx_restart(char mode, const char *cmd)
{
+ if (cmd != NULL) {
+ if ((strncmp(cmd, "bootloader", 10)) &&
+ (strncmp(cmd, "recovery", 8)))
+ cmd = NULL;
+ }
+
+ if (in_panic)
+ cmd = "panic";
+
omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0));
omap3xxx_prm_dpll3_reset(); /* never returns */
while (1);
}
+
+static int __init omap3xxx_restart_init(void)
+{
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+ return 0;
+}
+early_initcall(omap3xxx_restart_init);
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 7341eff63f5..5cc51234add 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2015,7 +2015,7 @@ static int _reset(struct omap_hwmod *oh)
* XXX When the PRM code is moved to drivers, this function can be removed,
* as the PRM infrastructure should abstract this.
*/
-static void _reconfigure_io_chain(void)
+void _reconfigure_io_chain(void)
{
unsigned long flags;
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 0c898f58ac9..dd6852ff898 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -703,4 +703,6 @@ extern int am33xx_hwmod_init(void);
extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
+void _reconfigure_io_chain(void);
+
#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 31c7126eb3b..7c5a6b81875 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -916,7 +916,8 @@ static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio1_hwmod = {
.name = "gpio1",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap2_gpio1_irqs,
.main_clk = "gpio1_ick",
.opt_clks = gpio1_opt_clks,
@@ -941,7 +942,8 @@ static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio2_hwmod = {
.name = "gpio2",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap2_gpio2_irqs,
.main_clk = "gpio2_ick",
.opt_clks = gpio2_opt_clks,
@@ -966,7 +968,8 @@ static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio3_hwmod = {
.name = "gpio3",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap2_gpio3_irqs,
.main_clk = "gpio3_ick",
.opt_clks = gpio3_opt_clks,
@@ -991,7 +994,8 @@ static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio4_hwmod = {
.name = "gpio4",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap2_gpio4_irqs,
.main_clk = "gpio4_ick",
.opt_clks = gpio4_opt_clks,
@@ -1021,7 +1025,8 @@ static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio5_hwmod = {
.name = "gpio5",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap3xxx_gpio5_irqs,
.main_clk = "gpio5_ick",
.opt_clks = gpio5_opt_clks,
@@ -1051,7 +1056,8 @@ static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
static struct omap_hwmod omap3xxx_gpio6_hwmod = {
.name = "gpio6",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .flags = (HWMOD_CONTROL_OPT_CLKS_IN_RESET |
+ HWMOD_INIT_NO_RESET),
.mpu_irqs = omap3xxx_gpio6_irqs,
.main_clk = "gpio6_ick",
.opt_clks = gpio6_opt_clks,
@@ -2181,6 +2187,80 @@ static struct omap_hwmod omap3xxx_gpmc_hwmod = {
HWMOD_NO_IDLEST),
};
+#ifdef CONFIG_SGX_OMAP3630
+/*
+ * 'gpu' class
+ * 2d/3d graphics accelerator
+ */
+
+static struct omap_hwmod_class_sysconfig omap3630_gpu_sysc = {
+ .rev_offs = 0xfe00,
+ .sysc_offs = 0xfe10,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap3630_gpu_hwmod_class = {
+ .name = "gpu",
+ .sysc = &omap3630_gpu_sysc,
+};
+
+/* gpu */
+static struct omap_hwmod_irq_info omap3630_gpu_irqs[] = {
+ { .irq = 21 + OMAP_INTC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap3630_gpu_hwmod = {
+ .name = "gpu",
+ .class = &omap3630_gpu_hwmod_class,
+ .clkdm_name = "sgx_clkdm",
+ .mpu_irqs = omap3630_gpu_irqs,
+ .main_clk = "sgx_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = OMAP3430ES2_SGX_MOD,
+ .prcm_reg_id = 1,
+ .idlest_reg_id = 1,
+ },
+ },
+ .flags = HWMOD_NO_IDLEST | HWMOD_NO_OCP_AUTOIDLE,
+};
+
+/* gpu -> l3_main */
+static struct omap_hwmod_ocp_if omap3630_gpu__l3_main = {
+ .master = &omap3630_gpu_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+
+static struct omap_hwmod_addr_space omap3630_gpu_addrs[] = {
+ {
+ .pa_start = 0x50000000,
+ .pa_end = 0x5000ffff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main -> gpu interface */
+static struct omap_hwmod_ocp_if omap3630_l3_main__gpu = {
+ .master = &omap3xxx_l3_main_hwmod,
+ .slave = &omap3630_gpu_hwmod,
+ .clk = "sgx_ick",
+ .addr = omap3630_gpu_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+
+#endif
+
+
/*
* interfaces
*/
@@ -3830,6 +3910,10 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
#ifdef CONFIG_OMAP_IOMMU_IVA2
&omap3xxx_l3_main__mmu_iva,
#endif
+#ifdef CONFIG_SGX_OMAP3630
+ &omap3630_l3_main__gpu,
+ &omap3630_gpu__l3_main,
+#endif
NULL
};
diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c
index bd41d59a7ca..82fd8c72f75 100644
--- a/arch/arm/mach-omap2/opp.c
+++ b/arch/arm/mach-omap2/opp.c
@@ -17,6 +17,7 @@
* GNU General Public License for more details.
*/
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/opp.h>
#include <linux/cpu.h>
@@ -40,6 +41,9 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def,
{
int i, r;
+ if (of_have_populated_dt())
+ return -EINVAL;
+
if (!opp_def || !opp_def_size) {
pr_err("%s: invalid params!\n", __func__);
return -EINVAL;
diff --git a/arch/arm/mach-omap2/pad_wkup.c b/arch/arm/mach-omap2/pad_wkup.c
new file mode 100644
index 00000000000..021c5ff9737
--- /dev/null
+++ b/arch/arm/mach-omap2/pad_wkup.c
@@ -0,0 +1,167 @@
+/*
+ * OMAP3 Pad Wakeup Handler
+ *
+ * Copyright (C) 2014-2008 Motorola, LLC.
+ *
+ * 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/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/wakeup_reason.h>
+
+#include "soc.h"
+#include "common.h"
+#include "mux34xx.h"
+#include "prm3xxx.h"
+#include "iomap.h"
+
+#include "pad_wkup.h"
+
+#define WAKEUPEVENT 0x8000
+struct offmode_wkup {
+ struct list_head node;
+ u32 irq;
+ u32 pad;
+ u32 pad_shift;
+ bool handle; /* if true generate irq otherwise for debug only */
+};
+LIST_HEAD(offmode_wkup_list);
+
+static void omap_register_pad_wkup(struct device *dev, u32 pad, u32 irq,
+ bool handle)
+{
+ struct offmode_wkup *wkup;
+
+ pr_info("register pad (0x%04x, %u, %d)\n", pad, irq, handle);
+
+ wkup = devm_kzalloc(dev, sizeof(struct offmode_wkup), GFP_KERNEL);
+ if (wkup) {
+ wkup->irq = irq;
+ wkup->pad = pad & 0xFFFFFFFC;
+ wkup->pad_shift = pad % 4 ? 16 : 0;
+ wkup->handle = handle;
+ list_add_tail(&wkup->node, &offmode_wkup_list);
+ }
+}
+
+static inline int is_pad_wkup(const struct offmode_wkup *wkup)
+{
+ int pad = __raw_readl(
+ OMAP2_L4_IO_ADDRESS(OMAP3_CONTROL_PADCONF_MUX_PBASE)+ wkup->pad);
+ pad = pad >> wkup->pad_shift;
+
+ return (pad & WAKEUPEVENT) ? 1 : 0;
+}
+
+/* prcm_handle_pad_wkup:
+ *
+ * map i/o pad wkup bits to interrupts. The primary function is
+ * to generate interrupts. If the handle flag is set, then generate
+ * interrupt. If the wkup bit is set on multiple pads, interrupts
+ * are generated for all. The secondary function is to log the
+ * Typically there should only be one wakeup event, but if there
+ * are multiple wakeup reasons, only the first in the list will be
+ * anointed "the" wakeup reason and logged. This means the order
+ * items are listed in the device tree will control which irq
+ * wins in the case of a tie.
+ */
+void prcm_handle_pad_wkup(void)
+{
+ struct offmode_wkup *wkup;
+ int wkup_irq = -1;
+
+ list_for_each_entry(wkup, &offmode_wkup_list, node) {
+ if (is_pad_wkup(wkup)) {
+ pr_info("%s IRQ = %d\n", __func__, wkup->irq);
+ if (wkup_irq < 0)
+ wkup_irq = wkup->irq;
+ if (wkup->handle)
+ generic_handle_irq(wkup->irq);
+ }
+ }
+ if (wkup_irq >= 0)
+ log_wakeup_reason(wkup_irq);
+
+}
+
+#ifdef CONFIG_OMAP3_PAD_WKUP_IO
+static irqreturn_t omap3_pad_wkup_handle_irq(int irq, void *unused)
+{
+ prcm_handle_pad_wkup();
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int omap3_pad_wkup_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int ndx = 0;
+ uint32_t pad, irq, handle;
+ int ret = 0;
+
+ if (!node)
+ return -ENODEV;
+
+ do {
+ if (of_property_read_u32_index(node, "ti,pad_irq", ndx, &pad))
+ break;
+ ndx++;
+ if (of_property_read_u32_index(node, "ti,pad_irq", ndx, &irq))
+ break;
+ ndx++;
+ if (of_property_read_u32_index(node, "ti,pad_irq", ndx,
+ &handle))
+ break;
+ ndx++;
+ omap_register_pad_wkup(&pdev->dev, pad, irq, handle);
+ } while (1);
+
+#ifdef CONFIG_OMAP3_PAD_WKUP_IO
+ if (ndx > 1) {
+ dev_info(&pdev->dev, "request pad_wkup_io\n");
+ ret = request_irq(omap_prcm_event_to_irq("io"),
+ omap3_pad_wkup_handle_irq,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pad_wkup_io", &pdev->dev);
+
+ if (ret)
+ pr_warning("wkup: Failed to setup pad_wkup_io irq %d\n",
+ ret);
+ }
+#endif
+
+ return ret;
+}
+
+static int omap3_pad_wkup_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id omap3_pad_wkup_table[] = {
+ { .compatible = "ti,pad-wkup", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap3_pad_wkup_table);
+
+static struct platform_driver omap3_pad_wkup_driver = {
+ .probe = omap3_pad_wkup_probe,
+ .remove = omap3_pad_wkup_remove,
+ .driver = {
+ .name = "omap3_pad_wkup",
+ .owner = THIS_MODULE,
+ .of_match_table = omap3_pad_wkup_table,
+ },
+};
+
+static int __init omap_pad_wkup_init(void)
+{
+ return platform_driver_register(&omap3_pad_wkup_driver);
+}
+omap_late_initcall(omap_pad_wkup_init);
diff --git a/arch/arm/mach-omap2/pad_wkup.h b/arch/arm/mach-omap2/pad_wkup.h
new file mode 100644
index 00000000000..9a3b402e411
--- /dev/null
+++ b/arch/arm/mach-omap2/pad_wkup.h
@@ -0,0 +1,5 @@
+#ifndef __OMAP_PADWKUP_H__
+#define __OMAP_PADWKUP_H__
+
+extern void prcm_handle_pad_wkup(void);
+#endif
diff --git a/arch/arm/mach-omap2/pm-debug-regs.c b/arch/arm/mach-omap2/pm-debug-regs.c
new file mode 100644
index 00000000000..b006ae80974
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug-regs.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2014 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * Work based on 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
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "iomap.h"
+#include "clock.h"
+#include "powerdomain.h"
+#include "clockdomain.h"
+#include "omap-pm.h"
+
+#include "soc.h"
+#include "cm2xxx_3xxx.h"
+#include "prm3xxx.h"
+#include "prm2xxx_3xxx.h"
+#include "pm.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static struct dentry *pm_dbg_dir;
+#endif
+
+struct pm_module_def {
+ char name[8]; /* Name of the module */
+ short type; /* CM or PRM */
+ unsigned short offset;
+ int low; /* First register address on this module */
+ int high; /* Last register address on this module */
+};
+
+#define MOD_CM 0
+#define MOD_PRM 1
+
+
+static const struct pm_module_def pm_dbg_reg_modules[] = {
+ { "IVA2", MOD_CM, OMAP3430_IVA2_MOD, 0, 0x4c },
+ { "OCP", MOD_CM, OCP_MOD, 0, 0x10 },
+ { "MPU", MOD_CM, MPU_MOD, 4, 0x4c },
+ { "CORE", MOD_CM, CORE_MOD, 0, 0x4c },
+ { "SGX", MOD_CM, OMAP3430ES2_SGX_MOD, 0, 0x4c },
+ { "WKUP", MOD_CM, WKUP_MOD, 0, 0x40 },
+ { "CCR", MOD_CM, PLL_MOD, 0, 0x70 },
+ { "DSS", MOD_CM, OMAP3430_DSS_MOD, 0, 0x4c },
+ { "CAM", MOD_CM, OMAP3430_CAM_MOD, 0, 0x4c },
+ { "PER", MOD_CM, OMAP3430_PER_MOD, 0, 0x4c },
+ { "EMU", MOD_CM, OMAP3430_EMU_MOD, 0x40, 0x54 },
+ { "NEON", MOD_CM, OMAP3430_NEON_MOD, 0x20, 0x48 },
+ { "USB", MOD_CM, OMAP3430ES2_USBHOST_MOD, 0, 0x4c },
+
+ { "IVA2", MOD_PRM, OMAP3430_IVA2_MOD, 0x50, 0xfc },
+ { "OCP", MOD_PRM, OCP_MOD, 4, 0x1c },
+ { "MPU", MOD_PRM, MPU_MOD, 0x58, 0xe8 },
+ { "CORE", MOD_PRM, CORE_MOD, 0x58, 0xf8 },
+ { "SGX", MOD_PRM, OMAP3430ES2_SGX_MOD, 0x58, 0xe8 },
+ { "WKUP", MOD_PRM, WKUP_MOD, 0xa0, 0xb0 },
+ { "CCR", MOD_PRM, PLL_MOD, 0x40, 0x70 },
+ { "DSS", MOD_PRM, OMAP3430_DSS_MOD, 0x58, 0xe8 },
+ { "CAM", MOD_PRM, OMAP3430_CAM_MOD, 0x58, 0xe8 },
+ { "PER", MOD_PRM, OMAP3430_PER_MOD, 0x58, 0xe8 },
+ { "EMU", MOD_PRM, OMAP3430_EMU_MOD, 0x58, 0xe4 },
+ { "GLBL", MOD_PRM, OMAP3430_GR_MOD, 0x20, 0xe4 },
+ { "NEON", MOD_PRM, OMAP3430_NEON_MOD, 0x58, 0xe8 },
+ { "USB", MOD_PRM, OMAP3430ES2_USBHOST_MOD, 0x58, 0xe8 },
+ { "", 0, 0, 0, 0 },
+};
+
+#define PM_DBG_MAX_REG_SETS 4
+
+static void *pm_dbg_reg_set[PM_DBG_MAX_REG_SETS] = {0};
+
+static int pm_dbg_get_regset_size(void)
+{
+ static int regset_size = 0;
+
+ if (regset_size == 0) {
+ int i = 0;
+ while (pm_dbg_reg_modules[i].name[0] != 0) {
+ regset_size += pm_dbg_reg_modules[i].high +
+ 4 - pm_dbg_reg_modules[i].low;
+ i++;
+ }
+ }
+ return regset_size;
+}
+
+static void pm_dbg_regset_store(u32 *ptr)
+{
+ int i = 0;
+ int j;
+ u32 val;
+
+ while (pm_dbg_reg_modules[i].name[0] != 0) {
+ for (j = pm_dbg_reg_modules[i].low;
+ j <= pm_dbg_reg_modules[i].high; j += 4) {
+ if (pm_dbg_reg_modules[i].type == MOD_CM)
+ val = omap2_cm_read_mod_reg(
+ pm_dbg_reg_modules[i].offset, j);
+ else
+ val = omap2_prm_read_mod_reg(
+ pm_dbg_reg_modules[i].offset, j);
+ *(ptr++) = val;
+ }
+ i++;
+ }
+}
+
+void pm_dbg_regs_copy(int tgt, int src)
+{
+ size_t sz = pm_dbg_get_regset_size();
+
+ pr_debug("saved reference copy %s(%d, %d) size = %u <- %pS\n",
+ __func__, tgt, src, sz, __builtin_return_address(0));
+ memcpy(pm_dbg_reg_set[tgt - 1], pm_dbg_reg_set[src - 1], sz);
+}
+
+void pm_dbg_regs_save(int reg_set)
+{
+ if (pm_dbg_reg_set[reg_set - 1] == NULL)
+ return;
+
+ pm_dbg_regset_store(pm_dbg_reg_set[reg_set - 1]);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int pm_dbg_show_regs(struct seq_file *s, void *unused)
+{
+ int i, j;
+ unsigned long val;
+ int reg_set = (int)s->private;
+ u32 *ptr;
+ void *store = NULL;
+ int regs;
+ int linefeed;
+
+ if (!cpu_is_omap34xx())
+ return -EINVAL;
+
+ if (reg_set == 0) {
+ store = kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL);
+ if (store == NULL)
+ return -ENOMEM;
+ ptr = store;
+ pm_dbg_regset_store(ptr);
+ } else {
+ ptr = pm_dbg_reg_set[reg_set - 1];
+ }
+
+ i = 0;
+
+ while (pm_dbg_reg_modules[i].name[0] != 0) {
+ regs = 0;
+ linefeed = 0;
+ if (pm_dbg_reg_modules[i].type == MOD_CM)
+ seq_printf(s, "MOD: CM_%s (%08x)\n",
+ pm_dbg_reg_modules[i].name,
+ (u32)(OMAP3430_CM_BASE +
+ pm_dbg_reg_modules[i].offset));
+ else
+ seq_printf(s, "MOD: PRM_%s (%08x)\n",
+ pm_dbg_reg_modules[i].name,
+ (u32)(OMAP3430_PRM_BASE +
+ pm_dbg_reg_modules[i].offset));
+
+ for (j = pm_dbg_reg_modules[i].low;
+ j <= pm_dbg_reg_modules[i].high; j += 4) {
+ val = *(ptr++);
+ if (val != 0) {
+ regs++;
+ if (linefeed) {
+ seq_printf(s, "\n");
+ linefeed = 0;
+ }
+ seq_printf(s, " %02x => %08lx", j, val);
+ if (regs % 4 == 0)
+ linefeed = 1;
+ }
+ }
+ seq_printf(s, "\n");
+ i++;
+ }
+
+ if (store != NULL)
+ kfree(store);
+
+ return 0;
+}
+
+#define WAKEUP_SOURCE_LEN 512
+void pm_dbg_show_wakeup_source(void)
+{
+ u32 val = 0;
+ int len = 0;
+ static char buf[WAKEUP_SOURCE_LEN];
+ char *pbuf;
+ u32 gpio_bit = 0;
+
+ /* print the real wkup sources */
+ memset(buf, 0, WAKEUP_SOURCE_LEN);
+ pbuf = buf;
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (len > 16)
+ pbuf += snprintf(pbuf, len, "WAKEDUP BY: ");
+
+ val = omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
+ val &= omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "WKUP_MOD(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(CORE_MOD, PM_WKST1);
+ val &= omap2_prm_read_mod_reg(CORE_MOD, PM_WKEN1);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "CORE_MOD(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+ val &= omap2_prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKEN3);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "CORE3_MOD(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+ val &= omap2_prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKEN);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "PER_MOD(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+ val &= omap2_prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKEN);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "USBHOST(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKST);
+ val &= omap2_prm_read_mod_reg(OMAP3430_DSS_MOD, PM_WKEN);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "DSS(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+ val &= omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "MPU_IRQSTATUS(0x%x), ", val);
+
+ val = omap2_prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PRM_IRQSTATUS_IVA2);
+ val &= omap2_prm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_PRM_IRQENABLE_IVA2);
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "IVA2_IRQSTATUS(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x009C)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ0(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00bC)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ1(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00dC)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ2(0x%x), ", val);
+
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x0098)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_IRQ0(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00B8)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_IRQ1(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00D8)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_IRQ2(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x009C)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ0(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00BC)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ1(0x%x), ", val);
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00DC)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_FIQ2(0x%x), ", val);
+
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<29)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x48310018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4831001C));
+ pbuf += snprintf(pbuf, len, "GPIO1(0x%x), ", gpio_bit);
+ }
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<30)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x49050018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4905001C));
+ pbuf += snprintf(pbuf, len, "GPIO2(0x%x), ", gpio_bit);
+ }
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<31)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x49052018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4905201C));
+ pbuf += snprintf(pbuf, len, "GPIO3(0x%x), ", gpio_bit);
+ }
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00b8)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_IRQ1(0x%x), ", val);
+
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<0)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x49054018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4905401C));
+ pbuf += snprintf(pbuf, len, "GPIO4(0x%x), ", gpio_bit);
+ }
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<1)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x49056018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4905601C));
+ pbuf += snprintf(pbuf, len, "GPIO5(0x%x), ", gpio_bit);
+ }
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if ((val & (1<<2)) && len > 20) {
+ gpio_bit = __raw_readl(OMAP2_L4_IO_ADDRESS(0x49058018)) &
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x4905801C));
+ pbuf += snprintf(pbuf, len, "GPIO6(0x%x), ", gpio_bit);
+ }
+
+ val = __raw_readl(OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE + (0x00d8)));
+ len = WAKEUP_SOURCE_LEN - (pbuf - buf);
+ if (val && len > 30)
+ pbuf += snprintf(pbuf, len, "INTC_IRQ2(0x%x)", val);
+
+ pr_debug("%s\n", buf);
+
+}
+EXPORT_SYMBOL(pm_dbg_show_wakeup_source);
+
+static int pm_dbg_reg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pm_dbg_show_regs, inode->i_private);
+}
+
+static const struct file_operations debug_reg_fops = {
+ .open = pm_dbg_reg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+int pm_dbg_regs_dump(int reg_set)
+{
+ int i, j;
+ unsigned long val;
+ u32 *ptr;
+ int regs;
+
+ if ((reg_set <= 0) || (reg_set > PM_DBG_MAX_REG_SETS))
+ return -EINVAL;
+
+ ptr = pm_dbg_reg_set[reg_set - 1];
+
+ i = 0;
+
+ while (pm_dbg_reg_modules[i].name[0] != 0) {
+ regs = 0;
+ if (pm_dbg_reg_modules[i].type == MOD_CM)
+ pr_debug("MOD: CM_%s (%08x)\n",
+ pm_dbg_reg_modules[i].name,
+ (u32)(OMAP3430_CM_BASE +
+ pm_dbg_reg_modules[i].offset));
+ else
+ pr_debug("MOD: PRM_%s (%08x)\n",
+ pm_dbg_reg_modules[i].name,
+ (u32)(OMAP3430_PRM_BASE +
+ pm_dbg_reg_modules[i].offset));
+
+ for (j = pm_dbg_reg_modules[i].low;
+ j <= pm_dbg_reg_modules[i].high; j += 4) {
+ val = *(ptr++);
+ if (val != 0) {
+ regs++;
+ pr_debug(" %02x => %08lx\n", j, val);
+ }
+ }
+ i++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pm_dbg_regs_dump);
+
+int pm_dbg_regs_dump_delta(int cur, int ref)
+{
+ int i, j;
+ unsigned long val_cur;
+ u32 *ptr_cur;
+ unsigned long val_ref;
+ u32 *ptr_ref;
+
+ if ((cur <= 0) || (cur > PM_DBG_MAX_REG_SETS) ||
+ (ref <= 0) || (ref > PM_DBG_MAX_REG_SETS)) {
+ return -EINVAL;
+ }
+
+ ptr_cur = pm_dbg_reg_set[cur - 1];
+ ptr_ref = pm_dbg_reg_set[ref - 1];
+
+ i = 0;
+
+ pr_debug(" module ( address) reg %d %d\n",
+ cur, ref);
+ while (pm_dbg_reg_modules[i].name[0] != 0) {
+ bool cm = pm_dbg_reg_modules[i].type == MOD_CM;
+ u32 base_addr = cm ? OMAP3430_CM_BASE : OMAP3430_PRM_BASE;
+
+ for (j = pm_dbg_reg_modules[i].low;
+ j <= pm_dbg_reg_modules[i].high; j += 4) {
+ u32 addr = (u32)(base_addr + pm_dbg_reg_modules[i].offset);
+
+ val_cur = *(ptr_cur++);
+ val_ref = *(ptr_ref++);
+ if (val_cur != val_ref) {
+ pr_debug("MOD: %s_%-4s %s(%08x) "
+ "%02x => 0x%08lx 0x%08lx\n",
+ cm ? "CM" : "PRM",
+ pm_dbg_reg_modules[i].name,
+ cm ? " " : "",
+ addr, j, val_cur, val_ref);
+ }
+ }
+ i++;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(pm_dbg_regs_dump_delta);
+
+static void __init pm_dbg_regset_init(void)
+{
+ int i;
+
+ for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) {
+ pm_dbg_reg_set[i] =
+ kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL);
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+int __init pm_dbg_regs_init(struct dentry *d)
+{
+ int i;
+ char name[2];
+
+ if (!cpu_is_omap34xx()) {
+ pr_err("%s: only OMAP3 supported\n", __func__);
+ return -ENODEV;
+ }
+
+ pm_dbg_dir = debugfs_create_dir("registers", d);
+ if (IS_ERR(pm_dbg_dir))
+ return PTR_ERR(pm_dbg_dir);
+
+ (void) debugfs_create_file("current", S_IRUGO,
+ pm_dbg_dir, (void *)0, &debug_reg_fops);
+
+ pm_dbg_regset_init();
+ for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) {
+ if (pm_dbg_reg_set[i] != NULL) {
+ sprintf(name, "%d", i + 1);
+ (void) debugfs_create_file(name, S_IRUGO,
+ pm_dbg_dir, (void *)(i+1), &debug_reg_fops);
+ }
+ }
+
+ return 0;
+}
+#else
+static int __init pm_dbg_regs_init(void)
+{
+ if (!cpu_is_omap34xx()) {
+ pr_err("%s: only OMAP3 supported\n", __func__);
+ return -ENODEV;
+ }
+
+ pm_dbg_regset_init();
+ return 0;
+}
+omap_arch_initcall(pm_dbg_regs_init);
+#endif
diff --git a/arch/arm/mach-omap2/pm-debug-regs.h b/arch/arm/mach-omap2/pm-debug-regs.h
new file mode 100644
index 00000000000..f70bbe5c6a8
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug-regs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Motorola Mobility LLC
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __PM_DEBUG_REGS_H__
+#define __PM_DEBUG_REGS_H__
+
+#include <linux/dcache.h>
+
+#ifdef CONFIG_PM_DEBUG
+extern int pm_dbg_regs_init(struct dentry *d);
+extern void pm_dbg_regs_save(int reg_set);
+extern void pm_dbg_regs_dump(int reg_set);
+extern void pm_dbg_regs_dump_delta(int cur, int rfr);
+extern void pm_dbg_show_wakeup_source(void);
+extern void pm_dbg_regs_copy(int tgt, int src);
+#else
+static inline int pm_dbg_regs_init(struct dentry *d) { return 0; }
+static inline void pm_dbg_regs_save(int reg_set) {};
+static inline void pm_dbg_regs_dump(int reg_set) {};
+static inline void pm_dbg_regs_dump_delta(int current, int ref) {}
+static inline void pm_dbg_show_wakeup_source(void) {};
+static inline void pm_dbg_regs_copy(int tgt, int src) {};
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 0b339861d75..b5dff42606c 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -36,6 +36,7 @@
#include "cm2xxx_3xxx.h"
#include "prm2xxx_3xxx.h"
#include "pm.h"
+#include "pm-debug-regs.h"
u32 enable_off_mode;
@@ -226,9 +227,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
static int option_get(void *data, u64 *val)
{
- u32 *option = data;
-
- *val = *option;
+ *val = omap_pm_get_off_mode();
return 0;
}
@@ -273,6 +272,9 @@ static int __init pm_dbg_init(void)
(void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
&enable_off_mode, &pm_dbg_option_fops);
+
+ pm_dbg_regs_init(d);
+
pm_dbg_init_done = 1;
return 0;
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index e742118fcfd..b06b22c3f64 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -17,6 +17,7 @@
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/cpu.h>
+#include <linux/of_platform.h>
#include <asm/system_misc.h>
@@ -227,6 +228,9 @@ static int omap_pm_begin(suspend_state_t state)
static void omap_pm_end(void)
{
cpu_idle_poll_ctrl(false);
+
+ if (cpu_is_omap34xx())
+ omap_prcm_irq_complete();
}
static void omap_pm_finish(void)
@@ -266,7 +270,12 @@ static void __init omap4_init_voltages(void)
static inline void omap_init_cpufreq(void)
{
- struct platform_device_info devinfo = { .name = "omap-cpufreq", };
+ struct platform_device_info devinfo = { };
+
+ if (!of_have_populated_dt())
+ devinfo.name = "omap-cpufreq";
+ else
+ devinfo.name = "cpufreq-cpu0";
platform_device_register_full(&devinfo);
}
@@ -300,10 +309,18 @@ int __init omap2_common_pm_late_init(void)
/* Smartreflex device init */
omap_devinit_smartreflex();
- /* cpufreq dummy device instantiation */
- omap_init_cpufreq();
+ } else {
+ struct device_node *np;
+ np = of_find_node_by_name(NULL, "omap_pimic");
+ if (np) {
+ of_platform_populate(np, NULL, NULL, NULL);
+ of_node_put(np);
+ }
}
+ /* cpufreq dummy device instantiation */
+ omap_init_cpufreq();
+
#ifdef CONFIG_SUSPEND
suspend_set_ops(&omap_pm_ops);
#endif
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 7bdd22afce6..4f6f52b5215 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -32,7 +32,7 @@ static inline int omap4_idle_init(void)
extern void *omap3_secure_ram_storage;
extern void omap3_pm_off_mode_enable(int);
-extern void omap_sram_idle(void);
+extern void omap_sram_idle(bool in_suspend);
extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
extern int (*omap_pm_suspend)(void);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 5a2d8034c8d..6f67bfa0b03 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -30,15 +30,18 @@
#include <linux/slab.h>
#include <linux/omap-dma.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/pm_runtime.h>
#include <trace/events/power.h>
#include <asm/fncpy.h>
+#include <asm/setup.h>
#include <asm/suspend.h>
#include <asm/system_misc.h>
#include "clockdomain.h"
#include "powerdomain.h"
+#include "omap-pm.h"
#include "soc.h"
#include "common.h"
#include "cm3xxx.h"
@@ -50,9 +53,17 @@
#include "sdrc.h"
#include "sram.h"
#include "control.h"
+#include "pm-debug-regs.h"
+#include "iomap.h"
+#include "omap_device.h"
+
+#include "pad_wkup.h"
/* pm34xx errata defined in pm.h */
u16 pm34xx_errata;
+bool suspend_debug;
+bool suspend_offmode_ref_saved;
+static struct timespec suspend_time_before;
struct power_state {
struct powerdomain *pwrdm;
@@ -70,6 +81,8 @@ void (*omap3_do_wfi_sram)(void);
static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
static struct powerdomain *core_pwrdm, *per_pwrdm;
+static struct powerdomain *dss_pwrdm;
+static struct omap_hwmod *wd_hwmod;
static void omap3_core_save_context(void)
{
@@ -144,6 +157,7 @@ static void omap3_save_secure_ram_context(void)
*/
static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
{
+ static struct clk *per_dpll_clk;
u32 wkst, fclk, iclk, clken;
u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
@@ -156,6 +170,16 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
wkst &= omap2_prm_read_mod_reg(module, grpsel_off);
wkst &= ~ignore_bits;
if (wkst) {
+ if (module != WKUP_MOD) {
+ if (per_dpll_clk == NULL) {
+ per_dpll_clk = clk_get(NULL, "dpll4_ck");
+ if (per_dpll_clk == NULL) {
+ pr_emerg("Unable to get dpll4_ck\n");
+ BUG();
+ }
+ }
+ clk_enable(per_dpll_clk);
+ }
iclk = omap2_cm_read_mod_reg(module, iclk_off);
fclk = omap2_cm_read_mod_reg(module, fclk_off);
while (wkst) {
@@ -172,9 +196,20 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
wkst = omap2_prm_read_mod_reg(module, wkst_off);
wkst &= ~ignore_bits;
c++;
+
+ /* Better to panic than to fade away */
+ if (c > 1000) {
+ pr_emerg("FATAL: Unable to clear wkst "
+ "wkst = 0x%08x module = 0x%04x "
+ "regs = 0x%02x\n",
+ wkst, module, regs);
+ BUG();
+ }
}
omap2_cm_write_mod_reg(iclk, module, iclk_off);
omap2_cm_write_mod_reg(fclk, module, fclk_off);
+ if (module != WKUP_MOD)
+ clk_disable(per_dpll_clk);
}
return c;
@@ -184,6 +219,7 @@ static irqreturn_t _prcm_int_handle_io(int irq, void *unused)
{
int c;
+ _reconfigure_io_chain();
c = prcm_clear_mod_irqs(WKUP_MOD, 1,
~(OMAP3430_ST_IO_MASK | OMAP3430_ST_IO_CHAIN_MASK));
@@ -228,11 +264,21 @@ static void omap34xx_save_context(u32 *save)
static int omap34xx_do_sram_idle(unsigned long save_state)
{
+ if (suspend_debug) {
+ pr_debug("OMAP3_PRM_IRQENABLE_MPU_OFFSET 0x%08x\n",
+ omap2_prm_read_mod_reg(OCP_MOD,
+ OMAP3_PRM_IRQENABLE_MPU_OFFSET));
+ omap_prcm_irq_restore();
+ pr_debug("OMAP3_PRM_IRQENABLE_MPU_OFFSET 0x%08x\n",
+ omap2_prm_read_mod_reg(OCP_MOD,
+ OMAP3_PRM_IRQENABLE_MPU_OFFSET));
+ }
+
omap34xx_cpu_suspend(save_state);
return 0;
}
-void omap_sram_idle(void)
+void omap_sram_idle(bool in_suspend)
{
/* Variable to tell what needs to be saved and restored
* in omap_sram_idle*/
@@ -276,20 +322,29 @@ void omap_sram_idle(void)
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
- per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
+ per_going_off = (per_next_state == PWRDM_POWER_OFF) ?
+ OFF_MODE : 0;
omap2_gpio_prepare_for_idle(per_going_off);
}
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
+ _reconfigure_io_chain();
+ if (!in_suspend && wd_hwmod != NULL)
+ platform_pm_suspend(&wd_hwmod->od->pdev->dev);
+
if (core_next_state == PWRDM_POWER_OFF) {
omap3_core_save_context();
omap3_cm_save_context();
- }
+
+ omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK,
+ WKUP_MOD, PM_WKEN);
+ omap_prm_configure(true);
+ } else
+ omap_prm_configure(false);
}
omap3_intc_prepare_idle();
-
/*
* On EMU/HS devices ROM code restores a SRDC value
* from scratchpad which has automatic self refresh on timeout
@@ -302,6 +357,9 @@ void omap_sram_idle(void)
core_next_state == PWRDM_POWER_OFF)
sdrc_pwr = sdrc_read_reg(SDRC_POWER);
+ if (suspend_debug)
+ pm_dbg_regs_save(1);
+
/*
* omap3_arm_context is the location where some ARM context
* get saved. The rest is placed on the stack, and restored
@@ -314,6 +372,9 @@ void omap_sram_idle(void)
else
omap34xx_do_sram_idle(save_state);
+ if (suspend_debug)
+ pm_dbg_regs_save(2);
+
/* Restore normal SDRC POWER settings */
if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 &&
(omap_type() == OMAP2_DEVICE_TYPE_EMU ||
@@ -323,17 +384,26 @@ void omap_sram_idle(void)
/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
+ if (!in_suspend && wd_hwmod != NULL)
+ platform_pm_resume(&wd_hwmod->od->pdev->dev);
+
core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
if (core_prev_state == PWRDM_POWER_OFF) {
omap3_core_restore_context();
omap3_cm_restore_context();
omap3_sram_restore_context();
omap2_sms_restore_context();
+
+ if (unlikely(!suspend_offmode_ref_saved)) {
+ suspend_offmode_ref_saved = true;
+ pm_dbg_regs_copy(3, 1);
+ pm_dbg_regs_copy(4, 2);
+ }
+ }
+ if (core_next_state == PWRDM_POWER_OFF) {
+ omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK,
+ WKUP_MOD, PM_WKEN);
}
- if (core_next_state == PWRDM_POWER_OFF)
- omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
- OMAP3430_GR_MOD,
- OMAP3_PRM_VOLTCTRL_OFFSET);
}
omap3_intc_resume_idle();
@@ -341,7 +411,8 @@ void omap_sram_idle(void)
/* PER */
if (per_next_state < PWRDM_POWER_ON)
- omap2_gpio_resume_after_idle();
+ omap2_gpio_resume_after_idle(in_suspend);
+
}
static void omap3_pm_idle(void)
@@ -351,7 +422,7 @@ static void omap3_pm_idle(void)
trace_cpu_idle(1, smp_processor_id());
- omap_sram_idle();
+ omap_sram_idle(false);
trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
}
@@ -361,6 +432,9 @@ static int omap3_pm_suspend(void)
{
struct power_state *pwrst;
int state, ret = 0;
+ struct timespec after;
+
+ suspend_debug = true;
/* Read current next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node)
@@ -373,11 +447,18 @@ static int omap3_pm_suspend(void)
goto restore;
}
+ read_persistent_clock(&suspend_time_before);
+
omap3_intc_suspend();
- omap_sram_idle();
+ omap_sram_idle(true);
+
+ prcm_handle_pad_wkup();
restore:
+ read_persistent_clock(&after);
+ after = timespec_sub(after, suspend_time_before);
+
/* Restore next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node) {
state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
@@ -388,11 +469,26 @@ restore:
}
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
}
- if (ret)
- pr_err("Could not enter target state in pm_suspend\n");
- else
- pr_info("Successfully put all powerdomains to target state\n");
+ if (ret) {
+ pr_err("Could not enter target state in pm_suspend "
+ "for %lu.%03lu seconds\n", after.tv_sec,
+ after.tv_nsec / NSEC_PER_MSEC);
+ if (suspend_offmode_ref_saved) {
+ pm_dbg_regs_dump_delta(1, 3);
+ pm_dbg_regs_dump_delta(2, 4);
+ } else {
+ pm_dbg_regs_dump(1);
+ pm_dbg_regs_dump(2);
+ }
+ } else
+ pr_info("Successfully put all powerdomains to target state "
+ "for %lu.%03lu seconds\n", after.tv_sec,
+ after.tv_nsec / NSEC_PER_MSEC);
+
+ pm_dbg_show_wakeup_source();
+
+ suspend_debug = false;
return ret;
}
@@ -644,9 +740,15 @@ static void __init pm_errata_configure(void)
pm34xx_errata |= PM_RTA_ERRATUM_i608;
/* Enable the l2 cache toggling in sleep logic */
enable_omap3630_toggle_l2_on_restore();
+
if (omap_rev() < OMAP3630_REV_ES1_2)
- pm34xx_errata |= (PM_SDRC_WAKEUP_ERRATUM_i583 |
- PM_PER_MEMORIES_ERRATUM_i582);
+ pm34xx_errata |= PM_PER_MEMORIES_ERRATUM_i582;
+#ifndef CONFIG_DISABLE_OMAP_ERRATA_i583
+ pm34xx_errata |= PM_SDRC_WAKEUP_ERRATUM_i583;
+#endif
+ if (meminfo.bank[0].size > 256 * (1024 * 1024))
+ pm34xx_errata |= PM_SDRC_WAKEUP_ERRATUM_i583;
+
} else if (cpu_is_omap34xx()) {
pm34xx_errata |= PM_PER_MEMORIES_ERRATUM_i582;
}
@@ -700,10 +802,12 @@ int __init omap3_pm_init(void)
ret = -EINVAL;
goto err3;
}
+ wd_hwmod = omap_hwmod_lookup("wd_timer2");
neon_pwrdm = pwrdm_lookup("neon_pwrdm");
per_pwrdm = pwrdm_lookup("per_pwrdm");
core_pwrdm = pwrdm_lookup("core_pwrdm");
+ dss_pwrdm = pwrdm_lookup("dss_pwrdm");
neon_clkdm = clkdm_lookup("neon_clkdm");
mpu_clkdm = clkdm_lookup("mpu_clkdm");
@@ -714,6 +818,9 @@ int __init omap3_pm_init(void)
omap_pm_suspend = omap3_pm_suspend;
#endif
+ if (omap_pm_get_off_mode())
+ omap3_pm_off_mode_enable(true);
+
arm_pm_idle = omap3_pm_idle;
omap3_idle_init();
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index c7d355fafd2..bc83da73d18 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -487,6 +487,7 @@ extern int omap_prcm_register_chain_handler(
extern int omap_prcm_event_to_irq(const char *event);
extern void omap_prcm_irq_prepare(void);
extern void omap_prcm_irq_complete(void);
+extern void omap_prcm_irq_restore(void);
# endif
diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h
index 3194dd87e0e..8f16aecf92f 100644
--- a/arch/arm/mach-omap2/prm2xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx.h
@@ -94,6 +94,9 @@
*/
/* Register offsets appearing on both OMAP2 and OMAP3 */
+#define INTC_PENDING_IRQ0 0x0098
+#define INTC_PENDING_IRQ1 0x00b8
+#define INTC_PENDING_IRQ2 0x00d8
#define OMAP2_RM_RSTCTRL 0x0050
#define OMAP2_RM_RSTTIME 0x0054
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index 228b850e632..c82aea6f358 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -216,6 +216,14 @@ void omap_prcm_irq_prepare(void)
prcm_irq_setup->suspended = true;
}
+void omap_prcm_irq_restore(void)
+{
+ if (prcm_irq_setup->suspend_save_flag) {
+ prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask);
+ prcm_irq_setup->ocp_barrier();
+ }
+}
+
void omap_prcm_irq_complete(void)
{
prcm_irq_setup->suspended = false;
diff --git a/arch/arm/mach-omap2/sdram-toshiba-hynix-numonyx.h b/arch/arm/mach-omap2/sdram-toshiba-hynix-numonyx.h
new file mode 100644
index 00000000000..c7acdb8312d
--- /dev/null
+++ b/arch/arm/mach-omap2/sdram-toshiba-hynix-numonyx.h
@@ -0,0 +1,66 @@
+/*
+ * SDRC register values for the Toshiba, Hynxi and Numonyx.
+ * These are common SDRC parameters for all vendors since we
+ * use the JEDEC JESD209A parameters.
+ *
+ * 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_TOSHIBA_HYNIX_NUMONYX
+
+#define ARCH_ARM_MACH_OMAP2_SDRAM_TOSHIBA_HYNIX_NUMONYX
+
+#include "sdrc.h"
+
+static struct omap_sdrc_params JEDEC_JESD209A_sdrc_params[] = {
+ [0] = {
+ .rate = 200000000,
+ .actim_ctrla = 0xE2E1B4C6,
+ .actim_ctrlb = 0x00022228,
+ .rfr_ctrl = 0x0005E602,
+ .mr = 0x00000032,
+ },
+ [1] = {
+ .rate = 100000000,
+ .actim_ctrla = 0x7211B485,
+ .actim_ctrlb = 0x00022214,
+ .rfr_ctrl = 0x0002DA02,
+ .mr = 0x00000032,
+ },
+ [2] = {
+ .rate = 166000000,
+ .actim_ctrla = 0xE2E1B4C6,
+ .actim_ctrlb = 0x00022228,
+ .rfr_ctrl = 0x0004DD02,
+ .mr = 0x00000032,
+ },
+ [3] = {
+ .rate = 83000000,
+ .actim_ctrla = 0x7215B485,
+ .actim_ctrlb = 0x00022214,
+ .rfr_ctrl = 0x00025602,
+ .mr = 0x00000032,
+ },
+ [4] = {
+ .rate = 160000000,
+ .actim_ctrla = 0xBA9DB4C6,
+ .actim_ctrlb = 0x00022220,
+ .rfr_ctrl = 0x0004AE02,
+ .mr = 0x00000032,
+ },
+ [5] = {
+ .rate = 80000000,
+ .actim_ctrla = 0x49512284,
+ .actim_ctrlb = 0x0001120C,
+ .rfr_ctrl = 0x23E02,
+ .mr = 0x00000032,
+ },
+ [6] = {
+ .rate = 0
+ },
+};
+
+#endif
+
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f6601563aa6..b570d93cbb7 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -81,7 +82,7 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = {
};
#ifdef CONFIG_PM
-static void omap_uart_enable_wakeup(struct device *dev, bool enable)
+void omap_uart_enable_wakeup(struct device *dev, bool enable)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
@@ -94,10 +95,35 @@ static void omap_uart_enable_wakeup(struct device *dev, bool enable)
else
omap_hwmod_disable_wakeup(od->hwmods[0]);
}
+void omap_uart_remove_wakeup(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_device *od = to_omap_device(pdev);
+ struct omap_hwmod *oh = od->hwmods[0];
+ u16 offs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oh->_lock, flags);
+ omap_hwmod_disable_wakeup(oh);
+ if (oh->class->sysc)
+ oh->class->sysc->sysc_flags &= ~SYSC_HAS_ENAWAKEUP;
+ offs = (oh->prcm.omap2.prcm_reg_id == 3) ?
+ OMAP3430ES2_PM_WKEN3 : PM_WKEN1;
+ omap2_prm_clear_mod_reg_bits((1<<oh->prcm.omap2.module_bit),
+ oh->prcm.omap2.module_offs, offs);
+ offs = (oh->prcm.omap2.prcm_reg_id == 3) ?
+ OMAP3430ES2_PM_WKST3 : PM_WKST1;
+ omap2_prm_set_mod_reg_bits((1<<oh->prcm.omap2.module_bit),
+ oh->prcm.omap2.module_offs, offs);
+ spin_unlock_irqrestore(&oh->_lock, flags);
+}
#else
-static void omap_uart_enable_wakeup(struct device *dev, bool enable)
+void omap_uart_enable_wakeup(struct device *dev, bool enable)
{}
+void omap_uart_remove_wakeup(struct device *dev)
+{
+}
#endif /* CONFIG_PM */
#ifdef CONFIG_OMAP_MUX