@@ -729,6 +729,9 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
return -EINVAL;
}
+ /* initialize the voltage change notifier chain */
+ srcu_init_notifier_head(&vdd->volt_change_notify_chain);
+
if (!strcmp(vdd->voltdm.name, "mpu")) {
if (cpu_is_omap3630()) {
vdd->volt_data = omap36xx_vddmpu_volt_data;
@@ -912,6 +915,9 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
return -EINVAL;
}
+ /* initialize the voltage change notifier chain */
+ srcu_init_notifier_head(&vdd->volt_change_notify_chain);
+
if (!strcmp(vdd->voltdm.name, "mpu")) {
vdd->volt_data = omap44xx_vdd_mpu_volt_data;
vdd->vp_reg.tranxdone_status =
@@ -1201,7 +1207,9 @@ void omap_vp_disable(struct voltagedomain *voltdm)
int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
unsigned long target_volt)
{
+ int ret;
struct omap_vdd_info *vdd;
+ struct omap_volt_change_info v_info;
if (!voltdm || IS_ERR(voltdm)) {
pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -1216,7 +1224,20 @@ int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
return -ENODATA;
}
- return vdd->volt_scale(vdd, target_volt);
+ /* load notifier chain data */
+ v_info.target_volt = target_volt;
+ v_info.vdd = vdd;
+
+ srcu_notifier_call_chain(&vdd->volt_change_notify_chain,
+ VOLTSCALE_PRECHANGE, (void *)&v_info);
+
+ ret = vdd->volt_scale(vdd, target_volt);
+
+ if (!ret)
+ srcu_notifier_call_chain(&vdd->volt_change_notify_chain,
+ VOLTSCALE_POSTCHANGE, (void *)&v_info);
+
+ return ret;
}
/**
@@ -1437,6 +1458,30 @@ struct voltagedomain *omap_voltage_domain_lookup(char *name)
return ERR_PTR(-EINVAL);
}
+int omap_voltage_register_notifier(struct omap_vdd_info *vdd,
+ struct notifier_block *nb)
+{
+ if (!vdd || IS_ERR(vdd)) {
+ pr_warning("%s: invalid VDD specified\n", __func__);
+ return -EINVAL;
+ }
+
+ return srcu_notifier_chain_register(&vdd->volt_change_notify_chain,
+ nb);
+}
+
+int omap_voltage_unregister_notifier(struct omap_vdd_info *vdd,
+ struct notifier_block *nb)
+{
+ if (!vdd || IS_ERR(vdd)) {
+ pr_warning("%s: invalid VDD specified\n", __func__);
+ return -EINVAL;
+ }
+
+ return srcu_notifier_chain_unregister(&vdd->volt_change_notify_chain,
+ nb);
+}
+
/**
* omap_voltage_late_init() - Init the various voltage parameters
*
@@ -15,10 +15,14 @@
#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
#include <linux/err.h>
+#include <linux/notifier.h>
#define VOLTSCALE_VPFORCEUPDATE 1
#define VOLTSCALE_VCBYPASS 2
+#define VOLTSCALE_PRECHANGE 0
+#define VOLTSCALE_POSTCHANGE 1
+
/*
* OMAP3 GENERIC setup times. Revisit to see if these needs to be
* passed from board or PMIC file
@@ -249,6 +253,7 @@ struct omap_vdd_info {
struct vc_reg_info vc_reg;
struct voltagedomain voltdm;
struct omap_vdd_dep_info *dep_vdd_info;
+ struct srcu_notifier_head volt_change_notify_chain;
int nr_dep_vdd;
struct dentry *debug_dir;
u32 curr_volt;
@@ -261,6 +266,17 @@ struct omap_vdd_info {
unsigned long target_volt);
};
+/**
+ * omap_volt_change_info - container used by voltage notifier chain
+ *
+ * @vdd_info : the voltage domain affected by the transition
+ * @target_volt : voltage the affected domain is transitioning to
+ */
+struct omap_volt_change_info {
+ unsigned long target_volt;
+ struct omap_vdd_info *vdd;
+};
+
unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
void omap_vp_enable(struct voltagedomain *voltdm);
void omap_vp_disable(struct voltagedomain *voltdm);
@@ -280,6 +296,10 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm,
int voltscale_method);
/* API to get the voltagedomain pointer */
struct voltagedomain *omap_voltage_domain_lookup(char *name);
+int omap_voltage_register_notifier(struct omap_vdd_info *vdd,
+ struct notifier_block *nb);
+int omap_voltage_unregister_notifier(struct omap_vdd_info *vdd,
+ struct notifier_block *nb);
int omap_voltage_late_init(void);
#else
@@ -298,6 +318,16 @@ static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
{
return ERR_PTR(-EINVAL);
}
+static inline int omap_voltage_register_notifier(struct omap_vdd_info *vdd,
+ struct notifier block *nb)
+{
+ return 0;
+}
+static inline int omap_voltage_unregister_notifier(struct omap_vdd_info *vdd,
+ struct notifier block *nb)
+{
+ return 0;
+}
#endif
#endif