aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap1/mailbox.c3
-rw-r--r--arch/arm/mach-omap2/clock.h1
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c58
-rw-r--r--arch/arm/mach-omap2/mailbox.c3
-rw-r--r--arch/arm/mach-omap2/mux.c49
-rw-r--r--arch/arm/mach-omap2/mux.h20
-rw-r--r--arch/arm/mach-omap2/pm24xx.c2
-rw-r--r--arch/arm/mach-omap2/pm34xx.c2
-rw-r--r--arch/arm/mach-omap2/pm44xx.c19
-rw-r--r--arch/arm/mach-omap2/prcm-debug.c11
-rw-r--r--arch/arm/plat-omap/include/plat/gpio.h6
-rw-r--r--drivers/gpio/gpio-omap.c192
-rw-r--r--drivers/i2c/busses/i2c-omap.c4
-rw-r--r--drivers/mfd/twl6030-madc.c44
-rw-r--r--drivers/mfd/twl6030-power.c111
-rw-r--r--drivers/mmc/host/omap_hsmmc.c6
-rw-r--r--drivers/video/omap2/dss/fifothreshold.c25
-rw-r--r--include/linux/i2c/twl.h8
18 files changed, 452 insertions, 112 deletions
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
index c0e1f48..99971bf 100644
--- a/arch/arm/mach-omap1/mailbox.c
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -151,6 +151,9 @@ static int __devinit omap1_mbox_probe(struct platform_device *pdev)
list[0]->irq = platform_get_irq_byname(pdev, "dsp");
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
mbox_base = ioremap(mem->start, resource_size(mem));
if (!mbox_base)
return -ENOMEM;
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index da332d2..450aabf 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -41,6 +41,7 @@
/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
#define DPLL_LOW_POWER_STOP 0x1
+#define DPLL_MN_BYPASS 0x4
#define DPLL_LOW_POWER_BYPASS 0x5
#define DPLL_LOCKED 0x7
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index 73a1595..2dad3c9 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -32,8 +32,10 @@
#include <plat/clock.h>
#include "clock.h"
+#include "cm2_44xx.h"
#include "cm2xxx_3xxx.h"
#include "cm-regbits-34xx.h"
+#include "cm-regbits-44xx.h"
/* CM_AUTOIDLE_PLL*.AUTO_* bit values */
#define DPLL_AUTOIDLE_DISABLE 0x0
@@ -61,22 +63,76 @@ static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
{
const struct dpll_data *dd;
- int i = 0;
+ int i;
int ret = -EINVAL;
+ bool first_time = true;
+ u32 reg;
+ u32 orig_cm_div_m2_dpll_usb;
+ u32 orig_cm_clkdcoldo_dpll_usb;
+retry:
dd = clk->dpll_data;
state <<= __ffs(dd->idlest_mask);
+ i = 0;
while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
i < MAX_DPLL_WAIT_TRIES) {
i++;
udelay(1);
}
+ /* restore back old values if hit work-around */
+ if (!first_time) {
+ __raw_writel(orig_cm_div_m2_dpll_usb,
+ OMAP4430_CM_DIV_M2_DPLL_USB);
+ __raw_writel(orig_cm_clkdcoldo_dpll_usb,
+ OMAP4430_CM_CLKDCOLDO_DPLL_USB);
+ }
+
if (i == MAX_DPLL_WAIT_TRIES) {
printk(KERN_ERR "clock: %s failed transition to '%s'\n",
clk->name, (state) ? "locked" : "bypassed");
+
+ /* Try Error Recovery: for failing usbdpll locking */
+ if (!strcmp(clk->name, "dpll_usb_ck")) {
+
+ reg = __raw_readl(dd->mult_div1_reg);
+
+ /* Put in MN bypass */
+ _omap3_dpll_write_clken(clk, DPLL_MN_BYPASS);
+ i = 0;
+ while (!(__raw_readl(dd->idlest_reg) & (1 << OMAP4430_ST_MN_BYPASS_SHIFT)) &&
+ i < MAX_DPLL_WAIT_TRIES) {
+ i++;
+ udelay(1);
+ }
+
+ /* MN bypass looses contents of CM_CLKSEL_DPLL_USB */
+ __raw_writel(reg, dd->mult_div1_reg);
+
+ /* Force generate request to PRCM: put in Force mode */
+
+ /* a) CM_DIV_M2_DPLL_USB.DPLL_CLKOUT_GATE_CTRL = 1 */
+ orig_cm_div_m2_dpll_usb = __raw_readl(OMAP4430_CM_DIV_M2_DPLL_USB);
+ __raw_writel(orig_cm_div_m2_dpll_usb |
+ (1 << OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT),
+ OMAP4430_CM_DIV_M2_DPLL_USB);
+
+ /* b) CM_CLKDCOLDO_DPLL_USB.DPLL_CLKDCOLDO_GATE_CTRL = 1 */
+ orig_cm_clkdcoldo_dpll_usb = __raw_readl(OMAP4430_CM_CLKDCOLDO_DPLL_USB);
+ __raw_writel(orig_cm_clkdcoldo_dpll_usb |
+ (1 << OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT),
+ OMAP4430_CM_CLKDCOLDO_DPLL_USB);
+
+ /* Put back to locked mode */
+ _omap3_dpll_write_clken(clk, DPLL_LOCKED);
+
+ if (first_time) {
+ first_time = false;
+ goto retry;
+ }
+ }
} else {
pr_debug("clock: %s transition to '%s' in %d loops\n",
clk->name, (state) ? "locked" : "bypassed", i);
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index d94205d..74750bf 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -397,6 +397,9 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
mbox_base = ioremap(mem->start, resource_size(mem));
if (!mbox_base)
return -ENOMEM;
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index c3caae2..a2ed524 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -936,7 +936,7 @@ static struct omap_mux *omap_mux_get_by_gpio(
}
/* Needed for dynamic muxing of GPIO pins for off-idle */
-u16 omap_mux_get_gpio(int gpio)
+struct omap_mux *omap_mux_get_gpio(int gpio)
{
struct omap_mux_partition *partition;
struct omap_mux *m = NULL;
@@ -944,13 +944,10 @@ u16 omap_mux_get_gpio(int gpio)
list_for_each_entry(partition, &mux_partitions, node) {
m = omap_mux_get_by_gpio(partition, gpio);
if (m)
- return omap_mux_read(partition, m->reg_offset);
+ return m;
}
- if (!m || m->reg_offset == OMAP_MUX_TERMINATOR)
- pr_err("%s: Could not get gpio%i\n", __func__, gpio);
-
- return OMAP_MUX_TERMINATOR;
+ return NULL;
}
/* Needed for dynamic muxing of GPIO pins for off-idle */
@@ -971,6 +968,45 @@ void omap_mux_set_gpio(u16 val, int gpio)
pr_err("%s: Could not set gpio%i\n", __func__, gpio);
}
+/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */
+bool omap_mux_get_wakeupenable(struct omap_mux *m)
+{
+ u16 val;
+ if (IS_ERR_OR_NULL(m))
+ return false;
+
+ val = omap_mux_read(m->partition, m->reg_offset);
+ return val & OMAP_PIN_OFF_WAKEUPENABLE;
+}
+
+/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */
+int omap_mux_set_wakeupenable(struct omap_mux *m)
+{
+ u16 val;
+ if (IS_ERR_OR_NULL(m))
+ return -EINVAL;
+
+ val = omap_mux_read(m->partition, m->reg_offset);
+ val |= OMAP_PIN_OFF_WAKEUPENABLE;
+ omap_mux_write(m->partition, val, m->reg_offset);
+
+ return 0;
+}
+
+/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */
+int omap_mux_clear_wakeupenable(struct omap_mux *m)
+{
+ u16 val;
+ if (IS_ERR_OR_NULL(m))
+ return -EINVAL;
+
+ val = omap_mux_read(m->partition, m->reg_offset);
+ val &= ~OMAP_PIN_OFF_WAKEUPENABLE;
+ omap_mux_write(m->partition, val, m->reg_offset);
+
+ return 0;
+}
+
static struct omap_mux * __init omap_mux_list_add(
struct omap_mux_partition *partition,
struct omap_mux *src)
@@ -984,6 +1020,7 @@ static struct omap_mux * __init omap_mux_list_add(
m = &entry->mux;
entry->mux = *src;
+ m->partition = partition;
#ifdef CONFIG_OMAP_MUX
if (omap_mux_copy_names(src, m)) {
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index 47c47d1..87bf022 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -131,6 +131,7 @@ struct omap_mux_partition {
struct omap_mux {
u16 reg_offset;
u16 gpio;
+ struct omap_mux_partition *partition;
#ifdef CONFIG_OMAP_MUX
char *muxnames[OMAP_MUX_NR_MODES];
#ifdef CONFIG_DEBUG_FS
@@ -264,11 +265,26 @@ static struct omap_board_mux *board_mux __initdata __maybe_unused;
#endif
/**
- * omap_mux_get_gpio() - get mux register value based on GPIO number
+ * omap_mux_get_gpio() - get mux struct based on GPIO number
* @gpio: GPIO number
*
*/
-u16 omap_mux_get_gpio(int gpio);
+struct omap_mux *omap_mux_get_gpio(int gpio);
+
+/** omap_mux_set_wakeupenable() - set the wakeupenable bit on a mux struct
+ * @m: mux struct
+ */
+int omap_mux_set_wakeupenable(struct omap_mux *m);
+
+/** omap_mux_clear_wakeupenable() - clear the wakeupenable bit on a mux struct
+ * @m: mux struct
+ */
+int omap_mux_clear_wakeupenable(struct omap_mux *m);
+
+/** omap_mux_get_wakeupenable() - get the wakeupenable bit from a mux struct
+ * @m: mux struct
+ */
+bool omap_mux_get_wakeupenable(struct omap_mux *m);
/**
* omap_mux_set_gpio() - set mux register value based on GPIO number
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index fb999bc..faa8463 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -148,7 +148,7 @@ no_sleep:
tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
omap2_pm_dump(0, 1, tmp);
}
- omap2_gpio_resume_after_idle();
+ omap2_gpio_resume_after_idle(0);
clk_enable(osc_ck);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 321a7e6..535480f 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -449,7 +449,7 @@ void omap_sram_idle(void)
/* PER */
if (per_next_state < PWRDM_POWER_ON) {
per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
- omap2_gpio_resume_after_idle();
+ omap2_gpio_resume_after_idle(per_going_off);
}
/* Disable IO-PAD and IO-CHAIN wakeup */
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 3593411..5303595 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -119,6 +119,7 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend)
int per_next_state = PWRDM_POWER_ON;
int core_next_state = PWRDM_POWER_ON;
int mpu_next_state = PWRDM_POWER_ON;
+ int ret;
pwrdm_clear_all_prev_pwrst(cpu0_pwrdm);
pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
@@ -131,6 +132,10 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend)
core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+ ret = omap2_gpio_prepare_for_idle(omap4_device_next_state_off());
+ if (ret)
+ goto abort_gpio;
+
if (mpu_next_state < PWRDM_POWER_INACTIVE) {
if (omap_dvfs_is_scaling(mpu_voltdm)) {
mpu_next_state = PWRDM_POWER_INACTIVE;
@@ -167,10 +172,7 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend)
}
}
- omap2_gpio_set_edge_wakeup();
-
if (omap4_device_next_state_off()) {
- omap2_gpio_prepare_for_idle(true);
omap_gpmc_save_context();
omap_dma_global_context_save();
}
@@ -225,26 +227,21 @@ abort_device_off:
}
if (omap4_device_next_state_off()) {
- /*
- * GPIO: since we have put_synced clks, we need to resume
- * even if OFF was not really achieved
- */
- omap2_gpio_resume_after_idle();
-
/* Disable the extension of Non-EMIF I/O isolation */
omap4_prminst_rmw_inst_reg_bits(OMAP4430_ISOOVR_EXTEND_MASK,
0, OMAP4430_PRM_PARTITION,
OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET);
}
- omap2_gpio_restore_edge_wakeup();
-
if (mpu_next_state < PWRDM_POWER_INACTIVE) {
omap_vc_set_auto_trans(mpu_voltdm,
OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE);
omap_sr_enable(mpu_voltdm);
}
+ omap2_gpio_resume_after_idle(omap4_device_next_state_off());
+
+abort_gpio:
return;
}
diff --git a/arch/arm/mach-omap2/prcm-debug.c b/arch/arm/mach-omap2/prcm-debug.c
index 12e3e55..ab638c2 100644
--- a/arch/arm/mach-omap2/prcm-debug.c
+++ b/arch/arm/mach-omap2/prcm-debug.c
@@ -1480,6 +1480,8 @@ static void prcmdebug_dump_real_cd(struct seq_file *sf, struct d_clkd_info *cd,
u32 clktrctrl =
omap4_cminst_read_inst_reg(cd->prcm_partition, cd->cm_inst,
cd->clkdm_offs + OMAP4_CM_CLKSTCTRL);
+ u32 mode = (clktrctrl & OMAP4430_CLKTRCTRL_MASK) >>
+ OMAP4430_CLKTRCTRL_SHIFT;
u32 activity = clktrctrl & cd->activity;
#if 0
u32 staticdep =
@@ -1492,9 +1494,10 @@ static void prcmdebug_dump_real_cd(struct seq_file *sf, struct d_clkd_info *cd,
int i;
#endif
- d_pr(sf, " %s mode=%s", cd->name,
- cmtrctrl_s[(clktrctrl & OMAP4430_CLKTRCTRL_MASK) >>
- OMAP4430_CLKTRCTRL_SHIFT]);
+ if (flags & PRCMDEBUG_LASTSLEEP && mode == 3 /* HW_AUTO */)
+ return;
+
+ d_pr(sf, " %s mode=%s", cd->name, cmtrctrl_s[mode]);
d_pr_ctd(sf, " activity=0x%x", activity);
@@ -1525,7 +1528,7 @@ static void prcmdebug_dump_cd(struct seq_file *sf, struct d_clkd_info *cd,
if (cd->cm_inst != -1) {
prcmdebug_dump_real_cd(sf, cd, flags);
- } else {
+ } else if (!(flags & PRCMDEBUG_LASTSLEEP)) {
d_pr(sf, " %s\n", cd->name);
}
diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 89af4ad..0b1f7c5 100644
--- a/arch/arm/plat-omap/include/plat/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
@@ -213,12 +213,10 @@ struct omap_gpio_platform_data {
struct omap_gpio_reg_offs *regs;
};
-extern void omap2_gpio_prepare_for_idle(int off_mode);
-extern void omap2_gpio_resume_after_idle(void);
+extern int omap2_gpio_prepare_for_idle(int off_mode);
+extern void omap2_gpio_resume_after_idle(int off_mode);
extern void omap_set_gpio_debounce(int gpio, int enable);
extern void omap_set_gpio_debounce_time(int gpio, int enable);
-extern void omap2_gpio_set_edge_wakeup(void);
-extern void omap2_gpio_restore_edge_wakeup(void);
/*-------------------------------------------------------------------------*/
/* Wrappers for "new style" GPIO calls, using the new infrastructure
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index d91a5aa..5b45bc1 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/bitops.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -29,6 +30,8 @@
#include <asm/mach/irq.h>
#include <plat/omap-pm.h>
+#include "../mux.h"
+
static LIST_HEAD(omap_gpio_list);
struct gpio_regs {
@@ -46,6 +49,7 @@ struct gpio_regs {
u32 debounce_en;
u32 edge_falling;
u32 edge_rising;
+ u32 pad_set_wakeupenable;
};
struct gpio_bank {
@@ -81,6 +85,8 @@ struct gpio_bank {
void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
struct omap_gpio_reg_offs *regs;
+
+ struct omap_mux *mux[32];
};
static void omap_gpio_mod_init(struct gpio_bank *bank);
@@ -761,6 +767,7 @@ static struct irq_chip gpio_irq_chip = {
.irq_unmask = gpio_unmask_irq,
.irq_set_type = gpio_irq_type,
.irq_set_wake = gpio_wake_enable,
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
};
/*---------------------------------------------------------------------*/
@@ -941,6 +948,8 @@ static struct lock_class_key gpio_lock_class;
static void omap_gpio_mod_init(struct gpio_bank *bank)
{
+ int i;
+
if (bank->width == 32) {
u32 clr_all = 0; /* clear all the bits */
u32 set_all = 0xFFFFFFFF; /* set all the bits */
@@ -1036,6 +1045,11 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
ULPD_CAM_CLK_CTRL);
}
}
+
+ for (i = 0; i < bank->width; i++) {
+ int gpio = irq_to_gpio(bank->virtual_irq_start + i);
+ bank->mux[i] = omap_mux_get_gpio(gpio);
+ }
}
static __init void
@@ -1271,6 +1285,35 @@ static int omap_gpio_resume(struct device *dev)
#ifdef CONFIG_ARCH_OMAP2PLUS
static void omap_gpio_save_context(struct gpio_bank *bank);
static void omap_gpio_restore_context(struct gpio_bank *bank);
+
+static void omap2_gpio_set_wakeupenables(struct gpio_bank *bank)
+{
+ unsigned long pad_wakeup;
+ int i;
+
+ bank->context.pad_set_wakeupenable = 0;
+
+ pad_wakeup = __raw_readl(bank->base + bank->regs->irqenable);
+
+ for_each_set_bit(i, &pad_wakeup, bank->width) {
+ if (!omap_mux_get_wakeupenable(bank->mux[i])) {
+ bank->context.pad_set_wakeupenable |= BIT(i);
+ omap_mux_set_wakeupenable(bank->mux[i]);
+ }
+ }
+}
+
+static void omap2_gpio_clear_wakeupenables(struct gpio_bank *bank)
+{
+ unsigned long pad_wakeup;
+ int i;
+
+ pad_wakeup = bank->context.pad_set_wakeupenable;
+
+ for_each_set_bit(i, &pad_wakeup, bank->width)
+ omap_mux_clear_wakeupenable(bank->mux[i]);
+}
+
#endif
static int omap_gpio_pm_runtime_suspend(struct device *dev)
@@ -1385,100 +1428,125 @@ static int omap_gpio_pm_runtime_resume(struct device *dev)
}
#ifdef CONFIG_ARCH_OMAP2PLUS
-void omap2_gpio_set_edge_wakeup(void)
+static int omap2_gpio_set_edge_wakeup(struct gpio_bank *bank)
{
- struct gpio_bank *bank;
+ int ret = 0;
+ u32 wkup_status = 0;
+ u32 datain;
- list_for_each_entry(bank, &omap_gpio_list, node) {
- u32 level_low = 0;
- u32 level_high = 0;
- u32 wkup_status = 0;
+ if (pm_runtime_get_sync(bank->dev) < 0) {
+ dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
+ "failed\n", __func__, bank->id);
+ return -EINVAL;
+ }
- if (pm_runtime_get_sync(bank->dev) < 0) {
- dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
- "failed\n", __func__, bank->id);
- return;
- }
+ bank->context.leveldetect0 = __raw_readl(bank->base +
+ bank->regs->leveldetect0);
+ bank->context.leveldetect1 = __raw_readl(bank->base +
+ bank->regs->leveldetect1);
+ wkup_status = __raw_readl(bank->base +
+ bank->regs->wkup_status);
+ bank->context.edge_falling = __raw_readl(bank->base +
+ bank->regs->fallingdetect);
+ bank->context.edge_rising = __raw_readl(bank->base +
+ bank->regs->risingdetect);
- level_low = __raw_readl(bank->base +
- bank->regs->leveldetect0);
- level_high = __raw_readl(bank->base +
- bank->regs->leveldetect1);
- wkup_status = __raw_readl(bank->base +
- bank->regs->wkup_status);
- bank->context.edge_falling = __raw_readl(bank->base +
- bank->regs->fallingdetect);
- bank->context.edge_rising = __raw_readl(bank->base +
- bank->regs->risingdetect);
+ /*
+ * Set edge trigger for all gpio's that are
+ * expected to produce wakeup from low power.
+ * even if they are set for level detection only.
+ */
+ __raw_writel(bank->context.edge_falling |
+ (bank->context.leveldetect0 & wkup_status),
+ (bank->base + bank->regs->fallingdetect));
+ __raw_writel(bank->context.edge_rising |
+ (bank->context.leveldetect1 & wkup_status),
+ (bank->base + bank->regs->risingdetect));
+ __raw_writel(0, bank->base + bank->regs->leveldetect0);
+ __raw_writel(0, bank->base + bank->regs->leveldetect1);
- /*
- * Set edge trigger for all gpio's that are
- * expected to produce wakeup from low power.
- * even if they are set for level detection only.
- */
- __raw_writel(bank->context.edge_falling | (level_low & wkup_status),
- (bank->base + bank->regs->fallingdetect));
- __raw_writel(bank->context.edge_rising | (level_high & wkup_status),
- (bank->base + bank->regs->risingdetect));
-
- if (pm_runtime_put_sync_suspend(bank->dev) < 0) {
- dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
- "failed\n", __func__, bank->id);
- return;
- }
+ /*
+ * If a level interrupt is pending it will be lost since
+ * we just cleared it's enable bit. Detect and abort,
+ * the interrupt will be delivered when
+ * omap2_gpio_restore_edge_wakeup restores the level
+ * interrupt mask.
+ */
+ datain = __raw_readl(bank->base + bank->regs->datain);
+ if ((datain & bank->context.leveldetect1) ||
+ (~datain & bank->context.leveldetect0))
+ ret = -EBUSY;
+
+ if (pm_runtime_put_sync_suspend(bank->dev) < 0) {
+ dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
+ "failed\n", __func__, bank->id);
+ return -EINVAL;
}
+
+ return ret;
}
-void omap2_gpio_restore_edge_wakeup(void)
+static void omap2_gpio_restore_edge_wakeup(struct gpio_bank *bank)
{
- struct gpio_bank *bank;
-
- list_for_each_entry(bank, &omap_gpio_list, node) {
- /* restore edge setting */
- if (pm_runtime_get_sync(bank->dev) < 0) {
- dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
- "failed\n", __func__, bank->id);
- return;
- }
+ if (pm_runtime_get_sync(bank->dev) < 0) {
+ dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
+ "failed\n", __func__, bank->id);
+ return;
+ }
- __raw_writel(bank->context.edge_falling,
- (bank->base + bank->regs->fallingdetect));
- __raw_writel(bank->context.edge_rising,
- (bank->base + bank->regs->risingdetect));
+ __raw_writel(bank->context.edge_falling,
+ (bank->base + bank->regs->fallingdetect));
+ __raw_writel(bank->context.edge_rising,
+ (bank->base + bank->regs->risingdetect));
+ __raw_writel(bank->context.leveldetect0,
+ (bank->base + bank->regs->leveldetect0));
+ __raw_writel(bank->context.leveldetect1,
+ (bank->base + bank->regs->leveldetect1));
- if (pm_runtime_put_sync_suspend(bank->dev) < 0) {
- dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
- "failed\n", __func__, bank->id);
- return;
- }
+ if (pm_runtime_put_sync_suspend(bank->dev) < 0) {
+ dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
+ "failed\n", __func__, bank->id);
+ return;
}
}
-void omap2_gpio_prepare_for_idle(int off_mode)
+int omap2_gpio_prepare_for_idle(int off_mode)
{
+ int ret = 0;
struct gpio_bank *bank;
- if (!off_mode)
- return;
-
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!bank->mod_usage || !bank->loses_context)
+ omap2_gpio_set_wakeupenables(bank);
+
+ if (!bank->mod_usage || !bank->loses_context || !off_mode) {
+ if (omap2_gpio_set_edge_wakeup(bank))
+ ret = -EBUSY;
continue;
+ }
if (pm_runtime_put_sync_suspend(bank->dev) < 0)
dev_err(bank->dev, "%s: GPIO bank %d "
"pm_runtime_put_sync failed\n",
__func__, bank->id);
}
+
+ if (ret)
+ omap2_gpio_resume_after_idle(off_mode);
+
+ return ret;
}
-void omap2_gpio_resume_after_idle(void)
+void omap2_gpio_resume_after_idle(int off_mode)
{
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!bank->mod_usage || !bank->loses_context)
+ omap2_gpio_clear_wakeupenables(bank);
+
+ if (!bank->mod_usage || !bank->loses_context || !off_mode) {
+ omap2_gpio_restore_edge_wakeup(bank);
continue;
+ }
if (pm_runtime_get_sync(bank->dev) < 0)
dev_err(bank->dev, "%s: GPIO bank %d "
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 5f2f56a..ead17f9 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -288,7 +288,7 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
}
dev->idle = 0;
- if (dev->rev >= OMAP_I2C_REV_ON_4430) {
+ if (cpu_is_omap44xx() && dev->rev >= OMAP_I2C_REV_ON_4430) {
omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR,0x6FFF);
omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_SET, dev->iestate);
} else {
@@ -307,7 +307,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
pdev = to_platform_device(dev->dev);
pdata = pdev->dev.platform_data;
- if (dev->rev >= OMAP_I2C_REV_ON_4430)
+ if (cpu_is_omap44xx() && dev->rev >= OMAP_I2C_REV_ON_4430)
omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 0x6FFF);
else
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
diff --git a/drivers/mfd/twl6030-madc.c b/drivers/mfd/twl6030-madc.c
index c7a9e55..f537ba5 100644
--- a/drivers/mfd/twl6030-madc.c
+++ b/drivers/mfd/twl6030-madc.c
@@ -68,6 +68,7 @@ struct twl6030_madc_data {
};
static struct twl6030_madc_data *twl6030_madc;
+static u8 gpadc_ctrl_reg;
static inline int twl6030_madc_start_conversion(struct twl6030_madc_data *madc)
{
@@ -281,12 +282,55 @@ static int __devexit twl6030_madc_remove(struct platform_device *pdev)
return 0;
}
+static int twl6030_madc_suspend(struct device *pdev)
+{
+ int ret;
+ u8 reg_val;
+
+ ret = twl_i2c_read_u8(TWL_MODULE_MADC, &reg_val, TWL6030_MADC_CTRL);
+ if (!ret) {
+ reg_val &= ~(TWL6030_MADC_TEMP1_EN);
+ ret = twl_i2c_write_u8(TWL_MODULE_MADC, reg_val,
+ TWL6030_MADC_CTRL);
+ }
+
+ if (ret) {
+ dev_err(twl6030_madc->dev, "unable to disable madc temp1!\n");
+ gpadc_ctrl_reg = TWL6030_MADC_TEMP1_EN;
+ } else
+ gpadc_ctrl_reg = reg_val;
+
+ return 0;
+};
+
+static int twl6030_madc_resume(struct device *pdev)
+{
+ int ret;
+
+ if (!(gpadc_ctrl_reg & TWL6030_MADC_TEMP1_EN)) {
+ gpadc_ctrl_reg |= TWL6030_MADC_TEMP1_EN;
+ ret = twl_i2c_write_u8(TWL_MODULE_MADC, gpadc_ctrl_reg,
+ TWL6030_MADC_CTRL);
+ if (ret)
+ dev_err(twl6030_madc->dev,
+ "unable to enable madc temp1!\n");
+ }
+
+ return 0;
+};
+
+static const struct dev_pm_ops twl6030_madc_pm_ops = {
+ .suspend = twl6030_madc_suspend,
+ .resume = twl6030_madc_resume,
+};
+
static struct platform_driver twl6030_madc_driver = {
.probe = twl6030_madc_probe,
.remove = __exit_p(twl6030_madc_remove),
.driver = {
.name = "twl6030_madc",
.owner = THIS_MODULE,
+ .pm = &twl6030_madc_pm_ops,
},
};
diff --git a/drivers/mfd/twl6030-power.c b/drivers/mfd/twl6030-power.c
index 84a8a22..2bbea1a 100644
--- a/drivers/mfd/twl6030-power.c
+++ b/drivers/mfd/twl6030-power.c
@@ -18,11 +18,14 @@
#include <linux/pm.h>
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
+#include <linux/suspend.h>
#include <asm/mach-types.h>
#define VREG_GRP 0
+static u8 dev_on_group;
+
/**
* struct twl6030_resource_map - describe the resource mapping for TWL6030
* @name: name of the resource
@@ -70,11 +73,60 @@ static __initdata struct twl6030_resource_map twl6030_res_map[] = {
/* TEMP cannot be modified */
};
+static struct twl4030_system_config twl6030_sys_config[] = {
+ {.name = "DEV_ON", .group = DEV_GRP_P1,},
+};
+
/* Actual power groups that TWL understands */
#define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */
#define P2_GRP_6030 BIT(1) /* "peripherals" */
#define P1_GRP_6030 BIT(0) /* CPU/Linux */
+static __init void twl6030_process_system_config(void)
+{
+ u8 grp;
+ int r;
+ bool i = false;
+
+ struct twl4030_system_config *sys_config;
+ sys_config = twl6030_sys_config;
+
+ while (sys_config && sys_config->name) {
+ if (!strcmp(sys_config->name, "DEV_ON")) {
+ dev_on_group = sys_config->group;
+ i = true;
+ break;
+ }
+ sys_config++;
+ }
+ if (!i)
+ pr_err("%s: Couldn't find DEV_ON resource configuration!"
+ " MOD & CON group would be kept active.\n", __func__);
+
+ if (dev_on_group) {
+ r = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &grp,
+ TWL6030_PHOENIX_DEV_ON);
+ if (r) {
+ pr_err("%s: Error(%d) reading {addr=0x%02x}",
+ __func__, r, TWL6030_PHOENIX_DEV_ON);
+ /*
+ * On error resetting to 0, so that all the process
+ * groups are kept active.
+ */
+ dev_on_group = 0;
+ } else {
+ /*
+ * Unmapped processor groups are disabled by writing
+ * 1 to corresponding group in DEV_ON.
+ */
+ grp |= (dev_on_group & DEV_GRP_P1) ? 0 : P1_GRP_6030;
+ grp |= (dev_on_group & DEV_GRP_P2) ? 0 : P2_GRP_6030;
+ grp |= (dev_on_group & DEV_GRP_P3) ? 0 : P3_GRP_6030;
+ dev_on_group = grp;
+ }
+ }
+}
+
static __init void twl6030_program_map(void)
{
struct twl6030_resource_map *res = twl6030_res_map;
@@ -98,6 +150,24 @@ static __init void twl6030_program_map(void)
}
}
+static __init void twl6030_update_system_map
+ (struct twl4030_system_config *sys_list)
+{
+ int i;
+ struct twl4030_system_config *sys_res;
+
+ while (sys_list && sys_list->name) {
+ sys_res = twl6030_sys_config;
+ for (i = 0; i < ARRAY_SIZE(twl6030_sys_config); i++) {
+ if (!strcmp(sys_res->name, sys_list->name))
+ sys_res->group = sys_list->group &
+ (DEV_GRP_P1 | DEV_GRP_P2 | DEV_GRP_P3);
+ sys_res++;
+ }
+ sys_list++;
+ }
+}
+
static __init void twl6030_update_map(struct twl4030_resconfig *res_list)
{
int i, res_idx = 0;
@@ -124,6 +194,29 @@ static __init void twl6030_update_map(struct twl4030_resconfig *res_list)
}
}
+
+static int twl6030_power_notifier_cb(struct notifier_block *notifier,
+ unsigned long pm_event, void *unused)
+{
+ int r = 0;
+
+ switch (pm_event) {
+ case PM_SUSPEND_PREPARE:
+ r = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, dev_on_group,
+ TWL6030_PHOENIX_DEV_ON);
+ if (r)
+ pr_err("%s: Error(%d) programming {addr=0x%02x}",
+ __func__, r, TWL6030_PHOENIX_DEV_ON);
+ break;
+ }
+
+ return notifier_from_errno(r);
+}
+
+static struct notifier_block twl6030_power_pm_notifier = {
+ .notifier_call = twl6030_power_notifier_cb,
+};
+
/**
* twl6030_power_init() - Update the power map to reflect connectivity of board
* @power_data: power resource map to update (OPTIONAL) - use this if a resource
@@ -131,16 +224,28 @@ static __init void twl6030_update_map(struct twl4030_resconfig *res_list)
*/
void __init twl6030_power_init(struct twl4030_power_data *power_data)
{
- if (power_data && !power_data->resource_config) {
- pr_err("%s: power data from platform without resources!\n",
+ int r;
+
+ if (power_data && (!power_data->resource_config &&
+ !power_data->sys_config)) {
+ pr_err("%s: power data from platform without configuration!\n",
__func__);
return;
}
- if (power_data)
+ if (power_data && power_data->resource_config)
twl6030_update_map(power_data->resource_config);
+ if (power_data && power_data->sys_config)
+ twl6030_update_system_map(power_data->sys_config);
+
+ twl6030_process_system_config();
+
twl6030_program_map();
+ r = register_pm_notifier(&twl6030_power_pm_notifier);
+ if (r)
+ pr_err("%s: twl6030 power registration failed!\n", __func__);
+
return;
}
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index b7ed408..c89c45c 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -2347,8 +2347,7 @@ static int omap_hsmmc_suspend(struct device *dev)
cancel_work_sync(&host->mmc_carddetect_work);
if (mmc_slot(host).mmc_data.built_in)
host->mmc->pm_flags |= MMC_PM_KEEP_POWER;
- if (host->mmc->card && (host->mmc->card->type != MMC_TYPE_SDIO))
- ret = mmc_suspend_host(host->mmc);
+ ret = mmc_suspend_host(host->mmc);
mmc_host_enable(host->mmc);
if (ret == 0) {
omap_hsmmc_disable_irq(host);
@@ -2410,8 +2409,7 @@ static int omap_hsmmc_resume(struct device *dev)
omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */
- if (host->mmc->card && (host->mmc->card->type != MMC_TYPE_SDIO))
- ret = mmc_resume_host(host->mmc);
+ ret = mmc_resume_host(host->mmc);
if (ret == 0)
host->suspended = 0;
diff --git a/drivers/video/omap2/dss/fifothreshold.c b/drivers/video/omap2/dss/fifothreshold.c
index e82e0e0..7435956 100644
--- a/drivers/video/omap2/dss/fifothreshold.c
+++ b/drivers/video/omap2/dss/fifothreshold.c
@@ -358,7 +358,6 @@ static void sa_calc(struct dispc_config *dispc_reg_config, u32 channel_no,
* buffers allocated.
*/
i = Tot_mem / pict_16word_ceil;
- Tot_mem -= pict_16word_ceil * i;
if (i == 0) {
/* LineSize > MemoryLineBufferSize (Valid only for 1D) */
@@ -368,22 +367,26 @@ static void sa_calc(struct dispc_config *dispc_reg_config, u32 channel_no,
* When MemoryLineBufferSize > LineSize >
* (MemoryLineBufferSize/2)
*/
-
- /* HACK: we multiplied pict_16word by 2 as we hit underflow */
- sa_info->min_sa = 2 * pict_16word + C2 * (Tot_mem - 8);
+ sa_info->min_sa = pict_16word + C2 * (Tot_mem -
+ pict_16word_ceil - 8);
} else {
/* All other cases */
- sa_info->min_sa = (4 * (i - 2) + C1) * pict_16word +
- C2 * (Tot_mem - 8);
+ sa_info->min_sa = 4 * pict_16word_ceil;
}
/* C2=0:: no partialy filed lines:: Then minLT = 0 */
- if (C2 == 0)
+ if (C2 == 0) {
sa_info->min_lt = 0;
- else if (bh_config.antifckr == 1 && (C1 == 3 || C1 == 4))
- sa_info->min_lt = (6 - C1) * pict_16word_ceil + C2 * Tot_mem;
- else
- sa_info->min_lt = (C2 - 1) * Tot_mem;
+ } else if (bh_config.antifckr == 1) {
+ if (C1 == 3)
+ sa_info->min_lt = 3 * pict_16word_ceil + C2 * (Tot_mem -
+ (pict_16word_ceil*i));
+ else if (C1 == 4)
+ sa_info->min_lt = 2 * pict_16word_ceil + C2 * (Tot_mem -
+ (pict_16word_ceil*i));
+ } else {
+ sa_info->min_lt = (C2 - 1) * (Tot_mem - (pict_16word_ceil*i));
+ }
sa_info->max_lt = max(sa_info->min_sa - 8, sa_info->min_lt + 1);
}
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 57e0857..85fbcb5 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -455,6 +455,8 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
#define TWL4030_PM_MASTER_GLOBAL_TST 0xb6
+#define TWL6030_PHOENIX_DEV_ON 0x06
+
/*
* PM Slave resource module register offsets (use TWL6030_MODULE_SLAVE_RES)
*/
@@ -681,10 +683,16 @@ struct twl4030_resconfig {
u8 remap_sleep; /* sleep state remapping */
};
+struct twl4030_system_config {
+ char *name;
+ u8 group;
+};
+
struct twl4030_power_data {
struct twl4030_script **scripts; /* used in TWL4030 only */
unsigned num; /* used in TWL4030 only */
struct twl4030_resconfig *resource_config;
+ struct twl4030_system_config *sys_config; /*system resources*/
#define TWL4030_RESCONFIG_UNDEF ((u8)-1)
};