From patchwork Thu Dec 2 13:59:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: manjugk manjugk X-Patchwork-Id: 374661 X-Patchwork-Delegate: paul@pwsan.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oB2DxJbV000454 for ; Thu, 2 Dec 2010 13:59:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757583Ab0LBN7S (ORCPT ); Thu, 2 Dec 2010 08:59:18 -0500 Received: from comal.ext.ti.com ([198.47.26.152]:42953 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757470Ab0LBN7R (ORCPT ); Thu, 2 Dec 2010 08:59:17 -0500 Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id oB2DxE6d015400 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 2 Dec 2010 07:59:14 -0600 Received: from legion.dal.design.ti.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id oB2DxE65026942; Thu, 2 Dec 2010 07:59:14 -0600 (CST) Received: from localhost (glpp-machine.apr.dhcp.ti.com [172.24.137.105]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id oB2DxCf25534; Thu, 2 Dec 2010 07:59:12 -0600 (CST) From: "G, Manjunath Kondaiah" To: linux-omap@vger.kernel.org Cc: "G, Manjunath Kondaiah" , Kevin Hilman , Paul Walmsley , linux-arm-kernel@lists.infradead.org Subject: [PATCH v7] OMAP2+: PM: omap device: API's for handling mstandby mode Date: Thu, 2 Dec 2010 19:29:52 +0530 Message-Id: <1291298392-28729-1-git-send-email-manjugk@ti.com> X-Mailer: git-send-email 1.7.1 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 02 Dec 2010 13:59:20 +0000 (UTC) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8a9847e..287818b 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1474,6 +1474,76 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) } /** + * omap_hwmod_set_master_standbymode - set the hwmod's OCP mstandby mode + * @oh: struct omap_hwmod * + * @midlemode: flag to set mstandby to either "no standby" or "smart standby" + * + * Sets the IP block's OCP mstandby mode in hardware, and updates our + * local copy. Intended to be used by drivers that have some erratum + * that requires direct manipulation of the MIDLEMODE bits. Returns + * -EINVAL if @oh is null, or passes along the return value from + * _set_master_standbymode(). + * + * Any users of this function should be scrutinized carefully. + */ +int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode) +{ + u32 v; + u8 sf; + int retval = -1; + unsigned int long flags; + + if (!oh) + return -EINVAL; + + if (!oh->class->sysc) + return -EINVAL; + + spin_lock_irqsave(&oh->_lock, flags); + + v = oh->_sysc_cache; + sf = oh->class->sysc->sysc_flags; + + if (!(sf & SYSC_HAS_MIDLEMODE)) { + spin_unlock_irqrestore(&oh->_lock, flags); + return -EINVAL; + } + + if (idlemode) { + if (oh->no_stdby_cnt) { + atomic_inc(oh->no_stdby_cnt); + goto in_nostandby_mode; + } + atomic_inc(oh->no_stdby_cnt); + idlemode = HWMOD_IDLEMODE_NO; + } else { + if (oh->no_stdby_cnt == 1) { + atomic_dec(oh->no_stdby_cnt); + idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? + HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + } else if (oh->no_stdby_cnt > 1) { + goto out_nostandby_mode; + } else { + goto in_nostandby_mode; + } + } + retval = _set_master_standbymode(oh, idlemode, &v); + + if (!retval) + _write_sysconfig(v, oh); + + return retval; + +out_nostandby_mode: + atomic_dec(oh->no_stdby_cnt); + +in_nostandby_mode: + spin_unlock_irqrestore(&oh->_lock, flags); + + return retval; +} + +/** * omap_hwmod_register - register a struct omap_hwmod * @oh: struct omap_hwmod * * diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h index 28e2d1a..4fbf7c1 100644 --- a/arch/arm/plat-omap/include/plat/omap_device.h +++ b/arch/arm/plat-omap/include/plat/omap_device.h @@ -116,6 +116,8 @@ int omap_device_enable_hwmods(struct omap_device *od); int omap_device_disable_clocks(struct omap_device *od); int omap_device_enable_clocks(struct omap_device *od); +int omap_device_require_no_mstandby(struct platform_device *pdev); +int omap_device_release_no_mstandby(struct platform_device *pdev); /* * Entries should be kept in latency order ascending diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 62bdb23..9d591fb 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -508,6 +508,7 @@ struct omap_hwmod { u8 masters_cnt; u8 slaves_cnt; u8 hwmods_cnt; + u8 no_stdby_cnt; u8 _int_flags; u8 _state; u8 _postsetup_state; @@ -537,6 +538,8 @@ int omap_hwmod_disable_clocks(struct omap_hwmod *oh); int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode); +int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode); + int omap_hwmod_reset(struct omap_hwmod *oh); void omap_hwmod_ocp_barrier(struct omap_hwmod *oh); diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index abe933c..2d42ab2 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -584,6 +584,66 @@ int omap_device_idle(struct platform_device *pdev) } /** + * omap_device_require_no_mstandby - set no mstandby mode of an omap_device + * @od: struct omap_device * to idle + * + * Sets the IP block's OCP master standby to no mstandby mode in hardware. + * + * Intended to be used by drivers that have some erratum that requires direct + * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the + * omap_device is not currently enabled or passes along the return value + * of omap_hwmod_set_master_standbymode(). + */ +int omap_device_require_no_mstandby(struct platform_device *pdev) +{ + int ret = 0, i; + struct omap_device *od; + + od = _find_by_pdev(pdev); + if (od->_state != OMAP_DEVICE_STATE_ENABLED) { + WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", + od->pdev.name, od->pdev.id, __func__, od->_state); + return -EINVAL; + } + + for (i = 0; i < od->hwmods_cnt; i++) + ret = omap_hwmod_set_master_standbymode(od->hwmods[i], true); + + return ret; +} + +/** + * omap_device_release_no_mstandby - releases no mstandby mode of an omap_device + * @od: struct omap_device * to idle + * + * Release no mstandby mode and sets the master standby to either no standby or + * smart standby in IP block's OCP in hardware depending on status of the flag + * HWMOD_SWSUP_MSTANDBY. + * + * Intended to be used by drivers that have some erratum that requires direct + * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the + * omap_device is not currently enabled or passes along the return value + * of omap_hwmod_set_master_standbymode(). + */ +int omap_device_release_no_mstandby(struct platform_device *pdev) +{ + int ret = 0, i; + struct omap_device *od; + + od = _find_by_pdev(pdev); + if (od->_state != OMAP_DEVICE_STATE_ENABLED) { + WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", + od->pdev.name, od->pdev.id, __func__, od->_state); + return -EINVAL; + } + + for (i = 0; i < od->hwmods_cnt; i++) + ret = omap_hwmod_set_master_standbymode(od->hwmods[i], false); + + return ret; +} + +/** * omap_device_shutdown - shut down an omap_device * @od: struct omap_device * to shut down *