diff mbox

[11/16] OMAP3: PM: Configurations for Smartreflex Class 2 and Smartreflex Class 3

Message ID 1267003757-22456-12-git-send-email-thara@ti.com (mailing list archive)
State Superseded
Delegated to: Kevin Hilman
Headers show

Commit Message

Thara Gopinath Feb. 24, 2010, 9:29 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 8e3b530..aae88b6 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -43,6 +43,7 @@  static int sr_class3_disable(int id)
 struct omap_smartreflex_class_data class3_data = {
 	.enable = sr_class3_enable,
 	.disable = sr_class3_disable,
+	.class_type = SR_CLASS3,
 };
 
 static int __init sr_class3_init(void)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index f7c1182..96dc76b 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -38,6 +38,12 @@  struct omap_sr {
 	int			is_sr_reset;
 	int			is_autocomp_active;
 	u32			clk_length;
+	u32			err_weight;
+	u32			err_minlimit;
+	u32			err_maxlimit;
+	u32			accum_data;
+	u32			senn_avgweight;
+	u32			senp_avgweight;
 	void __iomem		*srbase_addr;
 	unsigned int		irq;
 	struct platform_device 	*pdev;
@@ -106,6 +112,24 @@  static void sr_clk_disable(struct omap_sr *sr)
 	sr->is_sr_reset = 1;
 }
 
+static irqreturn_t sr_omap_isr(int irq, void *data)
+{
+	struct omap_sr *sr_info = (struct omap_sr *)data;
+	u32 status;
+
+	/* Read the status bits */
+	status = sr_read_reg(sr_info, ERRCONFIG);
+
+	/* Clear them by writing back */
+	sr_write_reg(sr_info, ERRCONFIG, status);
+
+	/* Call the class driver notify function if registered*/
+	if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+		sr_class->notify(sr_info->srid, status);
+
+	return IRQ_HANDLED;
+}
+
 static void sr_set_clk_length(struct omap_sr *sr)
 {
 	struct clk *sys_ck;
@@ -137,50 +161,96 @@  static void sr_set_clk_length(struct omap_sr *sr)
 	}
 }
 
+static void sr_set_regfields(struct omap_sr *sr)
+{
+	/*
+	 * For time being these values are defined in smartreflex.h
+	 * and populated during init. May be they can be moved to board
+	 * file or pmic specific data structure. In that case these structure
+	 * fields will have to be populated using the pdata or pmic structure.
+	 */
+	if (cpu_is_omap343x()) {
+		sr->err_weight = OMAP3430_SR_ERRWEIGHT;
+		sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
+		sr->accum_data = OMAP3430_SR_ACCUMDATA;
+		if (sr->srid == SR1) {
+			sr->err_minlimit = OMAP3430_SR1_ERRMINLIMIT;
+			sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
+			sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
+		} else {
+			sr->err_minlimit = OMAP3430_SR2_ERRMINLIMIT;
+			sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
+			sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
+		}
+	}
+	/* TODO: 3630 and Omap4 specific bit field values */
+}
+
 static void sr_configure(struct omap_sr *sr)
 {
 	u32 sr_config;
 	u32 senp_en , senn_en;
 	struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data;
 
+	/* Common settings for SR Class3 and SR Class2 */
 	if (sr->clk_length == 0)
 		sr_set_clk_length(sr);
 
 	senp_en = pdata->senp_mod;
 	senn_en = pdata->senn_mod;
-	if (sr->srid == SR1) {
-		sr_config = SR1_SRCONFIG_ACCUMDATA |
-			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
-			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
-			SRCONFIG_MINMAXAVG_EN |
-			(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
-			(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
-			SRCONFIG_DELAYCTRL;
-
-		sr_write_reg(sr, SRCONFIG, sr_config);
-		sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
-					SR1_AVGWEIGHT_SENNAVGWEIGHT);
 
+	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+		SRCONFIG_SENENABLE | (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
+		(senp_en << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL;
+	sr_write_reg(sr, SRCONFIG, sr_config);
+
+	if ((sr_class->class_type == SR_CLASS3) || (sr_class->class_type ==
+		SR_CLASS2 && sr_class->mod_use == SR_USE_ERROR_MOD)) {
+		/*
+		 * SR settings if using the ERROR module inside Smartreflex.
+		 * SR CLASS 3 by default uses only the ERROR module where as
+		 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
+		 * module.
+		 */
+		u32 sr_errconfig;
+
+		sr_modify_reg(sr, SRCONFIG, SRCONFIG_ERRGEN_EN,
+			SRCONFIG_ERRGEN_EN);
+		sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
+			(sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
+			(sr->err_minlimit <<  ERRCONFIG_ERRMiNLIMIT_SHIFT);
 		sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
 			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
-			(SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
-
-	} else if (sr->srid == SR2) {
-		sr_config = SR2_SRCONFIG_ACCUMDATA |
-			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
-			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
-			SRCONFIG_MINMAXAVG_EN |
-			(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
-			(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
-			SRCONFIG_DELAYCTRL;
-
-		sr_write_reg(sr, SRCONFIG, sr_config);
-		sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
-					SR2_AVGWEIGHT_SENNAVGWEIGHT);
-		sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
-			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
-			(SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
+			sr_errconfig);
+		/* Enabling the interrupts if the ERROR module is used */
+		sr_modify_reg(sr, ERRCONFIG,
+			(ERRCONFIG_VPBOUNDINTEN),
+			(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
+	} else if ((sr_class->class_type == SR_CLASS2) &&
+			(sr_class->mod_use == SR_USE_ERROR_MOD)) {
+		/*
+		 * SR settings if using the MINMAXAVG module inside
+		 * Smartreflex. SR CLASS 3 does not use this module where as
+		 * SR CLASS 2 can choose between ERROR module and MINMAXAVG
+		 * module.
+		 */
+		u32 avgwt;
 
+		sr_modify_reg(sr, SRCONFIG, SRCONFIG_ACCUMDATA_MASK,
+			sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
+		avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
+			(sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
+		sr_write_reg(sr, AVGWEIGHT, avgwt);
+		/*
+		 * Enabling the interrupts if MINMAXAVG module is used.
+		 * TODO: check if all the interrupts are mandatory
+		 */
+		sr_modify_reg(sr, ERRCONFIG,
+			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
+			ERRCONFIG_MCUBOUNDINTEN),
+			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
+			 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
+			 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
 	}
 	sr->is_sr_reset = 0;
 }
@@ -280,12 +350,6 @@  int sr_enable(int srid, u32 target_opp_no)
 	}
 
 	sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
-
-	/* Enable the interrupt */
-	sr_modify_reg(sr, ERRCONFIG,
-			(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST),
-			(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
-
 	/* SRCONFIG - enable SR */
 	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
 	return true;
@@ -384,6 +448,8 @@  void omap_smartreflex_disable(int srid)
  */
 void omap_sr_register_class(struct omap_smartreflex_class_data *class_data)
 {
+	struct omap_sr *sr_info;
+
 	if (!class_data) {
 		pr_warning("Smartreflex class data passed is NULL\n");
 		return;
@@ -393,7 +459,44 @@  void omap_sr_register_class(struct omap_smartreflex_class_data *class_data)
 		pr_warning("Smartreflex class driver already registered\n");
 		return;
 	}
+
+	if ((class_data->class_type != SR_CLASS2) &&
+			(class_data->class_type != SR_CLASS3)) {
+		pr_warning("SR Class type passed is invalid. So cannot \
+				register the class structure\n");
+		return;
+	}
+
+	if ((class_data->class_type == SR_CLASS2) &&
+			!((class_data->mod_use == SR_USE_MINMAXAVG_MOD) ||
+			(class_data->mod_use == SR_USE_ERROR_MOD))) {
+		pr_warning("SR Class 2 specified but whether to use error \
+				module or minmaxavg module not specified\n");
+		return;
+	}
+
 	sr_class = class_data;
+	/*
+	 * Register the interrupt handler incase requested by the class driver
+	 */
+	list_for_each_entry(sr_info, &sr_list, node) {
+		if (sr_class->class_type == SR_CLASS2 &&
+				sr_class->notify_flags && sr_info->irq) {
+			char name[SMARTREFLEX_NAME_LEN];
+			int ret;
+
+			sprintf(name, "sr%d", sr_info->srid);
+			ret = request_irq(sr_info->irq, sr_omap_isr,
+					IRQF_DISABLED, name, (void *)sr_info);
+			if (ret < 0) {
+				pr_warning("ERROR in registering interrupt \
+					handler for SR%d Smartreflex will \
+					not function as desired\n",
+					sr_info->srid);
+				return;
+			}
+		}
+	}
 }
 
 /* PM Debug Fs enteries to enable disable smartreflex.*/
@@ -448,6 +551,7 @@  static int __devinit omap_smartreflex_probe(struct platform_device *pdev)
 	if (odev->hwmods[0]->mpu_irqs)
 		sr_info->irq = odev->hwmods[0]->mpu_irqs[0].irq;
 	sr_set_clk_length(sr_info);
+	sr_set_regfields(sr_info);
 
 	/* Create the debug fs enteries */
 	sprintf(name, "sr%d_autocomp", sr_info->srid);
@@ -456,8 +560,29 @@  static int __devinit omap_smartreflex_probe(struct platform_device *pdev)
 
 	odev->hwmods[0]->dev_attr = sr_info;
 	list_add(&sr_info->node, &sr_list);
-	pr_info("SmartReflex driver initialized\n");
 
+	/*
+	 * Register interrrupt handler if smartreflex class driver is already
+	 * registered and has requested for interrupts. This will be attempted
+	 * in the class driver register again if it does not happen here.
+	 */
+	if (sr_class) {
+		if (sr_class->class_type == SR_CLASS2 &&
+				sr_class->notify_flags && sr_info->irq) {
+			sprintf(name, "sr%d", sr_info->srid);
+			ret = request_irq(sr_info->irq, sr_omap_isr,
+					IRQF_DISABLED, name, (void *)sr_info);
+			if (ret < 0) {
+				pr_warning("ERROR in registering interrupt \
+					handler for SR%d. Smartreflex will \
+					not function as desired\n",
+					sr_info->srid);
+				return ret;
+			}
+		}
+	}
+
+	pr_info("SmartReflex driver initialized\n");
 	return ret;
 }
 
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
index 7a1f0c7..f8fc8a4 100644
--- a/arch/arm/mach-omap2/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -124,6 +124,24 @@  extern struct dentry *pm_dbg_main_dir;
 #endif
 
 #ifdef CONFIG_OMAP_SMARTREFLEX
+/*
+ * The smart reflex driver supports both CLASS2 and CLASS3 SR.
+ * The smartreflex class driver should pass the class type.
+ * Should be used to populate the class_type field of the
+ * omap_smartreflex_class_data structure.
+ */
+#define SR_CLASS2	0x1
+#define SR_CLASS3	0x2
+
+/*
+ * CLASS2 SR can use either the MINMAXAVG module or the ERROR module
+ * of the Smartreflex. Should be used to populate the mod_use field
+ * of omap_smartreflex_class_data structure is class_type is chosen
+ * as SR_CLASS2.
+ */
+#define SR_USE_MINMAXAVG_MOD	0x1
+#define SR_USE_ERROR_MOD	0x2
+
 /**
  * omap_smartreflex_class_data : Structure to be populated by
  * Smartreflex class driver with corresponding class enable disable API's
@@ -134,7 +152,10 @@  extern struct dentry *pm_dbg_main_dir;
  *		for class3.
  * @notify_flags - specify the events to be notified to the class driver
  * @class_type - specify which smartreflex class. Can be used by the SR driver
- * 		to tkae any class based decisions.
+ * 		to take any class based decisions.
+ * @mod_use - specify whether to use the error module or minmaxavg module for
+ *		smartreflex caliberations in case of class2 SR. In case of
+ *		class 3 SR only error module is used.
  */
 struct omap_smartreflex_class_data {
 	int (*enable)(int sr_id);
@@ -142,6 +163,7 @@  struct omap_smartreflex_class_data {
 	int (*notify)(int sr_id, u32 status);
 	u8 notify_flags;
 	u8 class_type;
+	u8 mod_use;
 };
 
 /*