msm: smd: Add notifier chain to generate SMSM driver state notifications
This enables drivers to register for and receive any SMSM driver state
change notifications, including the initialization of SMSM driver.
CRs-Fixed: 338264
Change-Id: I090d19140f3bc46205566cd0431ed90edf440c02
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 6d45b7d..772c9f6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#ifndef _ARCH_ARM_MACH_MSM_SMSM_H_
#define _ARCH_ARM_MACH_MSM_SMSM_H_
+#include <linux/notifier.h>
#if defined(CONFIG_MSM_N_WAY_SMSM)
enum {
SMSM_APPS_STATE,
@@ -108,6 +109,8 @@
void *data);
int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
void (*notify)(void *, uint32_t, uint32_t), void *data);
+int smsm_driver_state_notifier_register(struct notifier_block *nb);
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
void smsm_reset_modem(unsigned mode);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index a1c044e..c502bce 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -33,6 +33,7 @@
#include <linux/uaccess.h>
#include <linux/kfifo.h>
#include <linux/wakelock.h>
+#include <linux/notifier.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/system.h>
@@ -334,6 +335,9 @@
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
static int spinlocks_initialized;
+static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
+static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
+static void smsm_driver_state_notify(uint32_t state, void *data);
static inline void smd_write_intr(unsigned int val,
const void __iomem *addr)
@@ -2306,6 +2310,7 @@
return i;
wmb();
+ smsm_driver_state_notify(SMSM_INIT, NULL);
return 0;
}
@@ -2764,6 +2769,38 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
+int smsm_driver_state_notifier_register(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smsm_driver_state_notifier_lock);
+ ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
+ mutex_unlock(&smsm_driver_state_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+
+int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+{
+ int ret;
+ if (!nb)
+ return -EINVAL;
+ mutex_lock(&smsm_driver_state_notifier_lock);
+ ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+ nb);
+ mutex_unlock(&smsm_driver_state_notifier_lock);
+ return ret;
+}
+EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+
+static void smsm_driver_state_notify(uint32_t state, void *data)
+{
+ mutex_lock(&smsm_driver_state_notifier_lock);
+ raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+ state, data);
+ mutex_unlock(&smsm_driver_state_notifier_lock);
+}
int smd_core_init(void)
{