diff options
-rw-r--r-- | arch/arm/mach-omap1/mailbox.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/dpll3xxx.c | 58 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mailbox.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 49 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mux.h | 20 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm24xx.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prcm-debug.c | 11 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/gpio.h | 6 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 192 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 4 | ||||
-rw-r--r-- | drivers/mfd/twl6030-madc.c | 44 | ||||
-rw-r--r-- | drivers/mfd/twl6030-power.c | 111 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/dss/fifothreshold.c | 25 | ||||
-rw-r--r-- | include/linux/i2c/twl.h | 8 |
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, ®_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) }; |