diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 184 |
1 files changed, 166 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 293fa6c..fac4aec 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -142,13 +142,16 @@ #include "powerdomain.h" #include <plat/clock.h> #include <plat/omap_hwmod.h> +#include <plat/omap_device.h> #include <plat/prcm.h> +#include <mach/emif.h> #include "cm2xxx_3xxx.h" #include "cm44xx.h" #include "prm2xxx_3xxx.h" #include "prm44xx.h" #include "mux.h" +#include "pm.h" /* Maximum microseconds to wait for OMAP module to softreset */ #define MAX_MODULE_SOFTRESET_WAIT 10000 @@ -391,7 +394,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -401,10 +405,13 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - *v |= wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v |= wakeup_mask; if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -426,7 +433,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -436,10 +444,13 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - *v &= ~wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v &= ~wakeup_mask; if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -781,8 +792,16 @@ static void _enable_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_NO; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } @@ -840,8 +859,16 @@ static void _idle_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_FORCE; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } @@ -1154,6 +1181,9 @@ static int _ocp_softreset(struct omap_hwmod *oh) goto dis_opt_clks; _write_sysconfig(v, oh); + if (oh->class->sysc->srst_udelay) + udelay(oh->class->sysc->srst_udelay); + if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs) @@ -1223,6 +1253,7 @@ static int _reset(struct omap_hwmod *oh) static int _enable(struct omap_hwmod *oh) { int r; + int hwsup = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED && oh->_state != _HWMOD_STATE_IDLE && @@ -1243,17 +1274,17 @@ static int _enable(struct omap_hwmod *oh) oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) _deassert_hardreset(oh, oh->rst_lines[0].name); - /* Mux pins for device runtime if populated */ - if (oh->mux && (!oh->mux->enabled || - ((oh->_state == _HWMOD_STATE_IDLE) && - oh->mux->pads_dynamic))) - omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); - _add_initiator_dep(oh, mpu_oh); + if (oh->_clk && oh->_clk->clkdm) { + hwsup = clkdm_is_idle(oh->_clk->clkdm); + clkdm_wakeup(oh->_clk->clkdm); + } _enable_clocks(oh); - r = _wait_target_ready(oh); if (!r) { + if (oh->_clk && oh->_clk->clkdm && hwsup) + clkdm_allow_idle(oh->_clk->clkdm); + oh->_state = _HWMOD_STATE_ENABLED; /* Access the sysconfig only if the target is ready */ @@ -1268,6 +1299,12 @@ static int _enable(struct omap_hwmod *oh) oh->name, r); } + /* Mux pins for device runtime if populated */ + if (oh->mux && (!oh->mux->enabled || + ((oh->_state == _HWMOD_STATE_ENABLED) && + oh->mux->pads_dynamic))) + omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); + return r; } @@ -1295,8 +1332,11 @@ static int _idle(struct omap_hwmod *oh) _disable_clocks(oh); /* Mux pins for device idle if populated */ - if (oh->mux && oh->mux->pads_dynamic) + if (oh->mux && oh->mux->pads_dynamic) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); + if (cpu_is_omap44xx()) + omap4_trigger_ioctrl(); + } oh->_state = _HWMOD_STATE_IDLE; @@ -1374,8 +1414,11 @@ static int _shutdown(struct omap_hwmod *oh) } } - if (oh->class->sysc) + if (oh->class->sysc) { + if (oh->_state == _HWMOD_STATE_IDLE) + _enable(oh); _shutdown_sysc(oh); + } /* * If an IP contains only one HW reset line, then assert it @@ -1507,6 +1550,7 @@ static int _setup(struct omap_hwmod *oh, void *data) * that the copy process would be relatively complex due to the large number * of substructures. */ + static int __init _register(struct omap_hwmod *oh) { int ms_id; @@ -1538,6 +1582,12 @@ static int __init _register(struct omap_hwmod *oh) */ if (!strcmp(oh->name, MPU_INITIATOR_NAME)) mpu_oh = oh; + else if (cpu_is_omap44xx()) { + if (!strcmp(oh->name, "emif1")) + emif_clear_irq(0); + else if (!strcmp(oh->name, "emif2")) + emif_clear_irq(1); + } return 0; } @@ -1770,6 +1820,34 @@ static int __init omap_hwmod_setup_all(void) core_initcall(omap_hwmod_setup_all); /** + * omap_hwmod_set_ioring_wakeup - enable io pad wakeup flag. + * @oh: struct omap_hwmod * + * @set: bool value indicating to set or clear wakeup status. + * + * Set or Clear wakeup flag for the io_pad. + */ +static int omap_hwmod_set_ioring_wakeup(struct omap_hwmod *oh, bool set_wake) +{ + struct omap_device_pad *pad; + int ret = -EINVAL, j; + + if (oh->mux && oh->mux->enabled) { + for (j = 0; j < oh->mux->nr_pads_dynamic; j++) { + pad = oh->mux->pads_dynamic[j]; + if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) { + if (set_wake) + pad->idle |= OMAP_WAKEUP_EN; + else + pad->idle &= ~OMAP_WAKEUP_EN; + ret = 0; + } + } + } + + return ret; +} + +/** * omap_hwmod_enable - enable an omap_hwmod * @oh: struct omap_hwmod * * @@ -2097,6 +2175,35 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, { return _del_initiator_dep(oh, init_oh); } +/** + * omap_hwmod_enable_ioring_wakeup - Set wakeup flag for iopad. + * @oh: struct omap_hwmod * + * + * Traverse through dynamic pads, if pad is enabled then + * set wakeup enable bit flag for the mux pin. Wakeup pad bit + * will be set during hwmod idle transistion. + * Return error if pads are not enabled or not available. + */ +int omap_hwmod_enable_ioring_wakeup(struct omap_hwmod *oh) +{ + /* Enable pad wake-up capability */ + return omap_hwmod_set_ioring_wakeup(oh, true); +} + +/** + * omap_hwmod_disable_ioring_wakeup - Clear wakeup flag for iopad. + * @oh: struct omap_hwmod * + * + * Traverse through dynamic pads, if pad is enabled then + * clear wakeup enable bit flag for the mux pin. Wakeup pad bit + * will be set during hwmod idle transistion. + * Return error if pads are not enabled or not available. + */ +int omap_hwmod_disable_ioring_wakeup(struct omap_hwmod *oh) +{ + /* Disable pad wakeup capability */ + return omap_hwmod_set_ioring_wakeup(oh, false); +} /** * omap_hwmod_enable_wakeup - allow device to wake up the system @@ -2123,6 +2230,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) v = oh->_sysc_cache; _enable_wakeup(oh, &v); _write_sysconfig(v, oh); + omap_hwmod_enable_ioring_wakeup(oh); spin_unlock_irqrestore(&oh->_lock, flags); return 0; @@ -2153,6 +2261,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) v = oh->_sysc_cache; _disable_wakeup(oh, &v); _write_sysconfig(v, oh); + omap_hwmod_disable_ioring_wakeup(oh); spin_unlock_irqrestore(&oh->_lock, flags); return 0; @@ -2332,7 +2441,7 @@ ohsps_unlock: * Returns the context loss count of the powerdomain assocated with @oh * upon success, or zero if no powerdomain exists for @oh. */ -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) { struct powerdomain *pwrdm; int ret = 0; @@ -2369,3 +2478,42 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh) return 0; } + +int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh) +{ + if (oh && oh->mux) + return omap_hwmod_mux_get_wake_status(oh->mux); + return -EINVAL; +} + +/** + * omap_hwmod_name_get_dev() - convert a hwmod name to device pointer + * @oh_name: name of the hwmod device + * + * returns back a struct device * pointer associated with a hwmod + * device represented by a hwmod_name + */ +struct device *omap_hwmod_name_get_dev(const char *oh_name) +{ + struct omap_hwmod *oh; + + if (!oh_name) { + WARN(1, "%s: no hwmod name!\n", __func__); + return ERR_PTR(-EINVAL); + } + + oh = _lookup(oh_name); + if (IS_ERR_OR_NULL(oh)) { + WARN(1, "%s: no hwmod for %s\n", __func__, + oh_name); + return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV); + } + if (IS_ERR_OR_NULL(oh->od)) { + WARN(1, "%s: no omap_device for %s\n", __func__, + oh_name); + return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV); + } + + return &oh->od->pdev.dev; +} +EXPORT_SYMBOL(omap_hwmod_name_get_dev); |