/*
 * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

/*============================================================================
  FILE:         vos_lock.c

  OVERVIEW:     This source file contains definitions for vOS lock APIs
                The four APIs mentioned in this file are used for
                initializing , acquiring, releasing and destroying a lock.
                the lock are implemented using critical sections

  DEPENDENCIES:
============================================================================*/

/*============================================================================
  EDIT HISTORY FOR MODULE

============================================================================*/

/*----------------------------------------------------------------------------
 * Include Files
 * -------------------------------------------------------------------------*/

#include "vos_lock.h"
#include "vos_memory.h"
#include "vos_trace.h"
#include "vos_api.h"
#include "hif.h"
#include "i_vos_diag_core_event.h"
#include "vos_cnss.h"
#include "vos_api.h"
#include "aniGlobal.h"

/*----------------------------------------------------------------------------
 * Preprocessor Definitions and Constants
 * -------------------------------------------------------------------------*/
#define WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT 0
#define WIFI_POWER_EVENT_WAKELOCK_TAKEN 0
#define WIFI_POWER_EVENT_WAKELOCK_RELEASED 1

/*----------------------------------------------------------------------------
 * Type Declarations
 * -------------------------------------------------------------------------*/

#define LINUX_LOCK_COOKIE 0x12345678
enum
{
   LOCK_RELEASED = 0x11223344,
   LOCK_ACQUIRED,
   LOCK_DESTROYED
};

/*----------------------------------------------------------------------------
 * Global Data Definitions
 * -------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
 * Static Variable Definitions
 * -------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
   Function Definitions and Documentation
 * -------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------

  \brief vos_lock_init() - initializes a vOSS lock

  The vos_lock_init() function initializes the specified lock. Upon
  successful initialization, the state of the lock becomes initialized
  and unlocked.

  A lock must be initialized by calling vos_lock_init() before it
  may be used in any other lock functions.

  Attempting to initialize an already initialized lock results in
  a failure.

  \param lock - pointer to the opaque lock object to initialize

  \return VOS_STATUS_SUCCESS - lock was successfully initialized and
          is ready to be used.

          VOS_STATUS_E_NOMEM - insufficient memory exists to initialize
          the lock

          VOS_STATUS_E_BUSY - The implementation has detected an attempt
          to reinitialize the object referenced by lock, a previously
          initialized, but not yet destroyed, lock.

          VOS_STATUS_E_FAULT  - lock is an invalid pointer.

          VOS_STATUS_E_FAILURE - default return value if it fails due to
          unknown reasons

       ***VOS_STATUS_E_RESOURCES - System resources (other than memory)
          are unavailable to initilize the lock
  \sa

    ( *** return value not considered yet )
  --------------------------------------------------------------------------*/
VOS_STATUS vos_lock_init ( vos_lock_t *lock )
{

   //check for invalid pointer
   if ( lock == NULL)
   {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: NULL pointer passed in",__func__);
       return VOS_STATUS_E_FAULT;
   }
   // check for 'already initialized' lock
   if ( LINUX_LOCK_COOKIE == lock->cookie )
   {
       VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: already initialized lock",__func__);
       return VOS_STATUS_E_BUSY;
   }

   if (in_interrupt())
   {
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);
      return VOS_STATUS_E_FAULT;
   }

   // initialize new lock
   mutex_init( &lock->m_lock );
   lock->cookie = LINUX_LOCK_COOKIE;
   lock->state  = LOCK_RELEASED;
   lock->processID = 0;
   lock->refcount = 0;

   return VOS_STATUS_SUCCESS;
}

/*--------------------------------------------------------------------------

  \brief vos_lock_acquire() - acquires a lock

  A lock object is acquired by calling \a vos_lock_acquire().  If the lock
  is already locked, the calling thread shall block   until the lock becomes
  available. This operation shall return with the lock object referenced by
  lock in the locked state with the calling thread as its owner.

  \param lock - the lock object to acquire

  \return VOS_STATUS_SUCCESS - the lock was successfully acquired by
          the calling thread.

          VOS_STATUS_E_INVAL - The value specified by lock does not refer
          to an initialized lock object.

          VOS_STATUS_E_FAULT  - lock is an invalid pointer.

          VOS_STATUS_E_FAILURE - default return value if it fails due to
          unknown reasons

  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_lock_acquire ( vos_lock_t* lock )
{
      int rc;
      //Check for invalid pointer
      if ( lock == NULL )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: NULL pointer passed in",__func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAULT;
      }
      // check if lock refers to an initialized object
      if ( LINUX_LOCK_COOKIE != lock->cookie )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: uninitialized lock",__func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_INVAL;
      }

      if (in_interrupt())
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAULT;
      }
      if ((lock->processID == current->pid) &&
          (lock->state == LOCK_ACQUIRED))
      {
         lock->refcount++;
#ifdef VOS_NESTED_LOCK_DEBUG
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,"%s: %x %d %d", __func__, lock, current->pid, lock->refcount);
#endif
         return VOS_STATUS_SUCCESS;
      }
      // Acquire a Lock
      mutex_lock( &lock->m_lock );
      rc = mutex_is_locked( &lock->m_lock );
      if (rc == 0)
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
                "%s: unable to lock mutex (rc = %d)", __func__, rc);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAILURE;
      }


#ifdef VOS_NESTED_LOCK_DEBUG
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,"%s: %x %d", __func__, lock, current->pid);
#endif
      if ( LOCK_DESTROYED != lock->state )
      {
         lock->processID = current->pid;
         lock->refcount++;
         lock->state    = LOCK_ACQUIRED;
         return VOS_STATUS_SUCCESS;
      }
      else
      {
         // lock is already destroyed
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: Lock is already destroyed", __func__);
         mutex_unlock(&lock->m_lock);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAILURE;
      }
}


/*--------------------------------------------------------------------------

  \brief vos_lock_release() - releases a lock

  The \a vos_lock_release() function shall release the lock object
  referenced by 'lock'.

  If a thread attempts to release a lock that it unlocked or is not
  initialized, an error is returned.

  \param lock - the lock to release

  \return VOS_STATUS_SUCCESS - the lock was successfully released

          VOS_STATUS_E_INVAL - The value specified by lock does not refer
          to an initialized lock object.

          VOS_STATUS_E_FAULT - The value specified by lock does not refer
          to an initialized lock object.

          VOS_STATUS_E_PERM - Operation is not permitted.  The calling
          thread does not own the lock.

          VOS_STATUS_E_FAILURE - default return value if it fails due to
          unknown reasons

  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_lock_release ( vos_lock_t *lock )
{
      //Check for invalid pointer
      if ( lock == NULL )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: NULL pointer passed in",__func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAULT;
      }

      // check if lock refers to an uninitialized object
      if ( LINUX_LOCK_COOKIE != lock->cookie )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: uninitialized lock",__func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_INVAL;
      }

      if (in_interrupt())
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);
         VOS_ASSERT(0);
         return VOS_STATUS_E_FAULT;
      }

      // CurrentThread = GetCurrentThreadId();
      // Check thread ID of caller against thread ID
      // of the thread which acquire the lock
      if ( lock->processID != current->pid )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: current task pid does not match original task pid!!",__func__);
#ifdef VOS_NESTED_LOCK_DEBUG
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,"%s: Lock held by=%d being released by=%d", __func__, lock->processID, current->pid);
#endif

         VOS_ASSERT(0);
         return VOS_STATUS_E_PERM;
      }
      if ((lock->processID == current->pid) &&
          (lock->state == LOCK_ACQUIRED))
      {
         if (lock->refcount > 0) lock->refcount--;
      }
#ifdef VOS_NESTED_LOCK_DEBUG
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,"%s: %x %d %d", __func__, lock, lock->processID, lock->refcount);
#endif
      if (lock->refcount) return VOS_STATUS_SUCCESS;

      lock->processID = 0;
      lock->refcount = 0;
      lock->state = LOCK_RELEASED;
      // Release a Lock
      mutex_unlock( &lock->m_lock );
#ifdef VOS_NESTED_LOCK_DEBUG
      VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,"%s: Freeing lock %x %d %d", lock, lock->processID, lock->refcount);
#endif
      return VOS_STATUS_SUCCESS;
}

/*--------------------------------------------------------------------------

  \brief vos_lock_destroy() - Destroys a vOSS Lock - probably not required
  for Linux. It may not be required for the caller to destroy a lock after
  usage.

  The \a vos_lock_destroy() function shall destroy the lock object
  referenced by lock.  After a successful return from \a vos_lock_destroy()
  the lock object becomes, in effect, uninitialized.

  A destroyed lock object can be reinitialized using vos_lock_init();
  the results of otherwise referencing the object after it has been destroyed
  are undefined.  Calls to vOSS lock functions to manipulate the lock such
  as vos_lock_acquire() will fail if the lock is destroyed.  Therefore,
  don't use the lock after it has been destroyed until it has
  been re-initialized.

  \param lock - the lock object to be destroyed.

  \return VOS_STATUS_SUCCESS - lock was successfully destroyed.

          VOS_STATUS_E_BUSY - The implementation has detected an attempt
          to destroy the object referenced by lock while it is locked
          or still referenced.

          VOS_STATUS_E_INVAL - The value specified by lock is invalid.

          VOS_STATUS_E_FAULT  - lock is an invalid pointer.

          VOS_STATUS_E_FAILURE - default return value if it fails due to
          unknown reasons
  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_lock_destroy( vos_lock_t *lock )
{
      //Check for invalid pointer
      if ( NULL == lock )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: NULL pointer passed in", __func__);
         return VOS_STATUS_E_FAULT;
      }

      if ( LINUX_LOCK_COOKIE != lock->cookie )
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: uninitialized lock", __func__);
         return VOS_STATUS_E_INVAL;
      }

      if (in_interrupt())
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__);
         return VOS_STATUS_E_FAULT;
      }

      // check if lock is released
      if (!mutex_trylock(&lock->m_lock))
      {
         VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: lock is not released", __func__);
         return VOS_STATUS_E_BUSY;
      }
      lock->cookie = 0;
      lock->state = LOCK_DESTROYED;
      lock->processID = 0;
      lock->refcount = 0;

      mutex_unlock(&lock->m_lock);


      return VOS_STATUS_SUCCESS;
}


/*--------------------------------------------------------------------------

  \brief vos_spin_lock_init() - initializes a vOSS spin lock

  The vos_spin_lock_init() function initializes the specified spin lock. Upon
  successful initialization, the state of the lock becomes initialized
  and unlocked.

  A lock must be initialized by calling vos_spin_lock_init() before it
  may be used in any other lock functions.

  Attempting to initialize an already initialized lock results in
  a failure.

  \param pLock - pointer to the opaque lock object to initialize

  \return VOS_STATUS_SUCCESS - spin lock was successfully initialized and
          is ready to be used.
  --------------------------------------------------------------------------*/

VOS_STATUS vos_spin_lock_init(vos_spin_lock_t *pLock)
{
   spin_lock_init(pLock);

   return VOS_STATUS_SUCCESS;
}

/*--------------------------------------------------------------------------

  \brief vos_spin_lock_acquire() - acquires a spin lock

  A lock object is acquired by calling \a vos_spin_lock_acquire().  If the lock
  is already locked, the calling thread shall spin until the lock becomes
  available. This operation shall return with the lock object referenced by
  lock in the locked state with the calling thread as its owner.

  \param pLock - the lock object to acquire

  \return VOS_STATUS_SUCCESS - the lock was successfully acquired by
          the calling thread.

  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_spin_lock_acquire(vos_spin_lock_t *pLock)
{
   spin_lock(pLock);
   return VOS_STATUS_SUCCESS;
}
/*--------------------------------------------------------------------------

  \brief vos_spin_lock_release() - releases a lock

  The \a vos_lock_release() function shall release the spin lock object
  referenced by 'lock'.

  If a thread attempts to release a lock that it unlocked or is not
  initialized, an error is returned.

  \param pLock - the lock to release

  \return VOS_STATUS_SUCCESS - the lock was successfully released

  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_spin_lock_release(vos_spin_lock_t *pLock)
{
   spin_unlock(pLock);
   return VOS_STATUS_SUCCESS;
}


/*--------------------------------------------------------------------------

  \brief vos_spin_lock_destroy() - releases resource of a lock

  \param pLock - the pointer to a lock to release

  \return VOS_STATUS_SUCCESS - the lock was successfully released

  \sa
  ------------------------------------------------------------------------*/
VOS_STATUS vos_spin_lock_destroy(vos_spin_lock_t *pLock)
{

   return VOS_STATUS_SUCCESS;
}

/*--------------------------------------------------------------------------

  \brief vos_wake_lock_init() - initializes a vOSS wake lock

  \param pLock - the wake lock to initialize
              name - wakelock name

  \return VOS_STATUS_SUCCESS - wake lock was successfully initialized and
          is ready to be used.
  --------------------------------------------------------------------------*/
VOS_STATUS vos_wake_lock_init(vos_wake_lock_t *pLock, const char *name)
{
	if (!pLock->is_initialized) {
		vos_pm_wake_lock_init(pLock, name);
		pLock->is_initialized = true;

		return VOS_STATUS_SUCCESS;
	} else {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
			FL("wakelock is already intialized"));
		return VOS_STATUS_E_INVAL;
	}
}

/**
 * vos_wake_lock_name() - This function returns the name of the wakelock
 * @pLock: Pointer to the wakelock
 *
 * This function returns the name of the wakelock
 *
 * Return: Pointer to the name if it is valid or a default string
 *
 */

static const char* vos_wake_lock_name(vos_wake_lock_t *pLock)
{
	if ((pLock->is_initialized) && (pLock->lock.name))
		return pLock->lock.name;
	else
		return "UNNAMED_WAKELOCK";
}

/*--------------------------------------------------------------------------

  \brief vos_wake_lock_acquire() - acquires a wake lock

  \param pLock - the wake lock to acquire

  \return VOS_STATUS_SUCCESS - the wake lock was successfully acquired

  ------------------------------------------------------------------------*/
VOS_STATUS vos_wake_lock_acquire(vos_wake_lock_t *pLock,
                                 uint32_t reason)
{
	if (pLock->is_initialized) {
		vos_log_wlock_diag(reason, vos_wake_lock_name(pLock),
				WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
				WIFI_POWER_EVENT_WAKELOCK_TAKEN);
		vos_pm_wake_lock(pLock);
		return VOS_STATUS_SUCCESS;
        } else {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
			FL("wakelock is not intialized yet"));
		return VOS_STATUS_E_INVAL;
        }
}

/*--------------------------------------------------------------------------

  \brief vos_wake_lock_timeout_acquire() - acquires a wake lock with a timeout

  \param pLock - the wake lock to acquire

  \return VOS_STATUS_SUCCESS - the wake lock was successfully acquired

  ------------------------------------------------------------------------*/
VOS_STATUS vos_wake_lock_timeout_acquire(vos_wake_lock_t *pLock, v_U32_t msec,
                                         uint32_t reason)
{

	/* Wakelock for Rx is frequent.
	* It is reported only during active debug
	*/
	if (pLock->is_initialized) {
		if (((vos_get_ring_log_level(RING_ID_WAKELOCK) >=
			WLAN_LOG_LEVEL_ACTIVE)
			&& (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX == reason)) ||
			(WIFI_POWER_EVENT_WAKELOCK_HOLD_RX != reason)) {
			vos_log_wlock_diag(reason,
				vos_wake_lock_name(pLock), msec,
				WIFI_POWER_EVENT_WAKELOCK_TAKEN);
		}
		vos_pm_wake_lock_timeout(pLock, msec);
		return VOS_STATUS_SUCCESS;
        } else {
			VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
				FL("wakelock is not intialized yet"));
			return VOS_STATUS_E_INVAL;
        }
}

/*--------------------------------------------------------------------------

  \brief vos_wake_lock_release() - releases a wake lock

  \param pLock - the wake lock to release

  \return VOS_STATUS_SUCCESS - the lock was successfully released

  ------------------------------------------------------------------------*/
VOS_STATUS vos_wake_lock_release(vos_wake_lock_t *pLock, uint32_t reason)
{
	if (pLock->is_initialized) {
		vos_log_wlock_diag(reason, vos_wake_lock_name(pLock),
			WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT,
			WIFI_POWER_EVENT_WAKELOCK_RELEASED);
		vos_pm_wake_lock_release(pLock);
		return VOS_STATUS_SUCCESS;
	} else {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
			FL("wakelock is not intialized yet"));
		return VOS_STATUS_E_INVAL;
        }
}

/*--------------------------------------------------------------------------

  \brief vos_wake_lock_destroy() - destroys a wake lock

  \param pLock - the wake lock to destroy

  \return VOS_STATUS_SUCCESS - the lock was successfully destroyed

  ------------------------------------------------------------------------*/
VOS_STATUS vos_wake_lock_destroy(vos_wake_lock_t *pLock)
{
	if (pLock->is_initialized) {
		vos_pm_wake_lock_destroy(pLock);
		pLock->is_initialized = false;
		return VOS_STATUS_SUCCESS;
	}
	else {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
			FL("wakelock is not intialized yet"));
		return VOS_STATUS_E_INVAL;
	}
}

VOS_STATUS vos_runtime_pm_prevent_suspend(runtime_pm_context_t runtime_pm_ctx)
{
	void *ol_sc;
	int ret = 0;

	ol_sc = vos_get_context(VOS_MODULE_ID_HIF,
			vos_get_global_context(VOS_MODULE_ID_SYS, NULL));

	if (ol_sc == NULL) {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
				"%s: HIF context is null!", __func__);
		return VOS_STATUS_E_INVAL;
	}

	ret = hif_pm_runtime_prevent_suspend(ol_sc, runtime_pm_ctx);

	if (ret)
		return VOS_STATUS_E_FAILURE;

	return VOS_STATUS_SUCCESS;
}

VOS_STATUS vos_runtime_pm_allow_suspend(runtime_pm_context_t runtime_pm_ctx)
{
	void *ol_sc;
	int ret = 0;

	ol_sc = vos_get_context(VOS_MODULE_ID_HIF,
			vos_get_global_context(VOS_MODULE_ID_SYS, NULL));

	if (ol_sc == NULL) {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
				"%s: HIF context is null!", __func__);
		return VOS_STATUS_E_INVAL;
	}

	ret = hif_pm_runtime_allow_suspend(ol_sc, runtime_pm_ctx);

	if (ret)
		return VOS_STATUS_E_FAILURE;

	return VOS_STATUS_SUCCESS;
}

/**
 * vos_runtime_pm_prevent_suspend_timeout() - Prevent runtime suspend timeout
 * msec:	Timeout in milliseconds
 *
 * Prevent runtime suspend with a timeout after which runtime suspend would be
 * allowed. This API uses a single timer to allow the suspend and timer is
 * modified if the timeout is changed before timer fires.
 * If the timeout is less than autosuspend_delay then use mark_last_busy instead
 * of starting the timer.
 *
 * It is wise to try not to use this API and correct the design if possible.
 *
 * Return: VOS_STATUS
 */
VOS_STATUS vos_runtime_pm_prevent_suspend_timeout(runtime_pm_context_t context,
						unsigned int msec)
{
	void *ol_sc;
	int ret = 0;

	ol_sc = vos_get_context(VOS_MODULE_ID_HIF,
			vos_get_global_context(VOS_MODULE_ID_SYS, NULL));

	if (ol_sc == NULL) {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
				"%s: HIF context is null!", __func__);
		return VOS_STATUS_E_INVAL;
	}

        ret = hif_pm_runtime_prevent_suspend_timeout(ol_sc, context, msec);
	if (ret)
		return VOS_STATUS_E_FAILURE;

	return VOS_STATUS_SUCCESS;
}

/**
 * vos_runtime_pm_prevent_suspend_init() - Runtime PM Prevent Suspend Ctx init
 * @name: name of the context
 *
 * Through out driver this API should be called to initialize the runtime pm
 * instance.
 *
 * Return: void*
 */
void *vos_runtime_pm_prevent_suspend_init(const char *name)
{
	return hif_runtime_pm_prevent_suspend_init(name);
}

/**
 * vos_runtime_pm_prevent_suspend_deinit() - Runtime PM Prevent context deinit
 * @data: Runtime PM context pointer
 *
 * This API should be called to release the Runtime PM context.
 *
 * Return: void
 */
void vos_runtime_pm_prevent_suspend_deinit(runtime_pm_context_t data)
{
	hif_runtime_pm_prevent_suspend_deinit(data);
}

/**
 * vos_request_runtime_pm_resume() - API to ensure driver is runtime pm active
 *
 * Driver modules can use this API to ensure driver is runtime pm active
 *
 * Return: VOS_STATUS
 */
VOS_STATUS vos_request_runtime_pm_resume(void)
{
	void *ol_sc;
	v_CONTEXT_t gContext;

	gContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);

	ol_sc = vos_get_context(VOS_MODULE_ID_HIF, gContext);

	if (ol_sc == NULL) {
		VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
				"%s: HIF context is null!", __func__);
		return VOS_STATUS_E_INVAL;
	}

	hif_request_runtime_pm_resume(ol_sc);

	return VOS_STATUS_SUCCESS;
}
