diff options
Diffstat (limited to 'arch/arm/mach-omap2/smartreflex.c')
| -rw-r--r-- | arch/arm/mach-omap2/smartreflex.c | 231 | 
1 files changed, 170 insertions, 61 deletions
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index 9dd93453e56..008fbd7b935 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -36,6 +36,12 @@  #define SR_DISABLE_TIMEOUT	200  struct omap_sr { +	struct list_head		node; +	struct platform_device		*pdev; +	struct omap_sr_nvalue_table	*nvalue_table; +	struct voltagedomain		*voltdm; +	struct dentry			*dbg_dir; +	unsigned int			irq;  	int				srid;  	int				ip_type;  	int				nvalue_count; @@ -49,13 +55,7 @@ struct omap_sr {  	u32				senp_avgweight;  	u32				senp_mod;  	u32				senn_mod; -	unsigned int			irq;  	void __iomem			*base; -	struct platform_device		*pdev; -	struct list_head		node; -	struct omap_sr_nvalue_table	*nvalue_table; -	struct voltagedomain		*voltdm; -	struct dentry			*dbg_dir;  };  /* sr_list contains all the instances of smartreflex module */ @@ -74,10 +74,6 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,  					u32 value)  {  	u32 reg_val; -	u32 errconfig_offs = 0, errconfig_mask = 0; - -	reg_val = __raw_readl(sr->base + offset); -	reg_val &= ~mask;  	/*  	 * Smartreflex error config register is special as it contains @@ -88,16 +84,15 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,  	 * if they are currently set, but does allow the caller to write  	 * those bits.  	 */ -	if (sr->ip_type == SR_TYPE_V1) { -		errconfig_offs = ERRCONFIG_V1; -		errconfig_mask = ERRCONFIG_STATUS_V1_MASK; -	} else if (sr->ip_type == SR_TYPE_V2) { -		errconfig_offs = ERRCONFIG_V2; -		errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2; -	} +	if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1) +		mask |= ERRCONFIG_STATUS_V1_MASK; +	else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2) +		mask |= ERRCONFIG_VPBOUNDINTST_V2; + +	reg_val = __raw_readl(sr->base + offset); +	reg_val &= ~mask; -	if (offset == errconfig_offs) -		reg_val &= ~errconfig_mask; +	value &= mask;  	reg_val |= value; @@ -128,21 +123,28 @@ static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)  static irqreturn_t sr_interrupt(int irq, void *data)  { -	struct omap_sr *sr_info = (struct omap_sr *)data; +	struct omap_sr *sr_info = data;  	u32 status = 0; -	if (sr_info->ip_type == SR_TYPE_V1) { +	switch (sr_info->ip_type) { +	case SR_TYPE_V1:  		/* Read the status bits */  		status = sr_read_reg(sr_info, ERRCONFIG_V1);  		/* Clear them by writing back */  		sr_write_reg(sr_info, ERRCONFIG_V1, status); -	} else if (sr_info->ip_type == SR_TYPE_V2) { +		break; +	case SR_TYPE_V2:  		/* Read the status bits */  		status = sr_read_reg(sr_info, IRQSTATUS);  		/* Clear them by writing back */  		sr_write_reg(sr_info, IRQSTATUS, status); +		break; +	default: +		dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n", +			sr_info->ip_type); +		return IRQ_NONE;  	}  	if (sr_class->notify) @@ -166,6 +168,7 @@ static void sr_set_clk_length(struct omap_sr *sr)  			__func__);  		return;  	} +  	sys_clk_speed = clk_get_rate(sys_ck);  	clk_put(sys_ck); @@ -267,7 +270,7 @@ static int sr_late_init(struct omap_sr *sr_info)  			goto error;  		}  		ret = request_irq(sr_info->irq, sr_interrupt, -				0, name, (void *)sr_info); +				0, name, sr_info);  		if (ret)  			goto error;  		disable_irq(sr_info->irq); @@ -288,12 +291,15 @@ error:  		"not function as desired\n", __func__);  	kfree(name);  	kfree(sr_info); +  	return ret;  }  static void sr_v1_disable(struct omap_sr *sr)  {  	int timeout = 0; +	int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | +			ERRCONFIG_MCUBOUNDINTST;  	/* Enable MCUDisableAcknowledge interrupt */  	sr_modify_reg(sr, ERRCONFIG_V1, @@ -302,13 +308,13 @@ static void sr_v1_disable(struct omap_sr *sr)  	/* SRCONFIG - disable SR */  	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); -	/* Disable all other SR interrupts and clear the status */ +	/* Disable all other SR interrupts and clear the status as needed */ +	if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1) +		errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;  	sr_modify_reg(sr, ERRCONFIG_V1,  			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |  			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1), -			(ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | -			ERRCONFIG_MCUBOUNDINTST | -			ERRCONFIG_VPBOUNDINTST_V1)); +			errconf_val);  	/*  	 * Wait for SR to be disabled. @@ -337,9 +343,17 @@ static void sr_v2_disable(struct omap_sr *sr)  	/* SRCONFIG - disable SR */  	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); -	/* Disable all other SR interrupts and clear the status */ -	sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, +	/* +	 * Disable all other SR interrupts and clear the status +	 * write to status register ONLY on need basis - only if status +	 * is set. +	 */ +	if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2) +		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,  			ERRCONFIG_VPBOUNDINTST_V2); +	else +		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, +				0x0);  	sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |  			IRQENABLE_MCUVALIDINT |  			IRQENABLE_MCUBOUNDSINT)); @@ -398,15 +412,16 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)   */  int sr_configure_errgen(struct voltagedomain *voltdm)  { -	u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en; -	u32 vpboundint_st, senp_en = 0, senn_en = 0; +	u32 sr_config, sr_errconfig, errconfig_offs; +	u32 vpboundint_en, vpboundint_st; +	u32 senp_en = 0, senn_en = 0;  	u8 senp_shift, senn_shift;  	struct omap_sr *sr = _sr_lookup(voltdm);  	if (IS_ERR(sr)) {  		pr_warning("%s: omap_sr struct for sr_%s not found\n",  			__func__, voltdm->name); -		return -EINVAL; +		return PTR_ERR(sr);  	}  	if (!sr->clk_length) @@ -418,20 +433,23 @@ int sr_configure_errgen(struct voltagedomain *voltdm)  	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |  		SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN; -	if (sr->ip_type == SR_TYPE_V1) { +	switch (sr->ip_type) { +	case SR_TYPE_V1:  		sr_config |= SRCONFIG_DELAYCTRL;  		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;  		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;  		errconfig_offs = ERRCONFIG_V1;  		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;  		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; -	} else if (sr->ip_type == SR_TYPE_V2) { +		break; +	case SR_TYPE_V2:  		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;  		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;  		errconfig_offs = ERRCONFIG_V2;  		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;  		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; -	} else { +		break; +	default:  		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"  			"module without specifying the ip\n", __func__);  		return -EINVAL; @@ -447,8 +465,55 @@ int sr_configure_errgen(struct voltagedomain *voltdm)  		sr_errconfig);  	/* Enabling the interrupts if the ERROR module is used */ -	sr_modify_reg(sr, errconfig_offs, -		vpboundint_en, (vpboundint_en | vpboundint_st)); +	sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st), +		      vpboundint_en); + +	return 0; +} + +/** + * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component + * @voltdm:	VDD pointer to which the SR module to be configured belongs to. + * + * This API is to be called from the smartreflex class driver to + * disable the error generator module inside the smartreflex module. + * + * Returns 0 on success and error value in case of failure. + */ +int sr_disable_errgen(struct voltagedomain *voltdm) +{ +	u32 errconfig_offs; +	u32 vpboundint_en, vpboundint_st; +	struct omap_sr *sr = _sr_lookup(voltdm); + +	if (IS_ERR(sr)) { +		pr_warning("%s: omap_sr struct for sr_%s not found\n", +			__func__, voltdm->name); +		return PTR_ERR(sr); +	} + +	switch (sr->ip_type) { +	case SR_TYPE_V1: +		errconfig_offs = ERRCONFIG_V1; +		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; +		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; +		break; +	case SR_TYPE_V2: +		errconfig_offs = ERRCONFIG_V2; +		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; +		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; +		break; +	default: +		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" +			"module without specifying the ip\n", __func__); +		return -EINVAL; +	} + +	/* Disable the interrupts of ERROR module */ +	sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0); + +	/* Disable the Sensor and errorgen */ +	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);  	return 0;  } @@ -475,7 +540,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)  	if (IS_ERR(sr)) {  		pr_warning("%s: omap_sr struct for sr_%s not found\n",  			__func__, voltdm->name); -		return -EINVAL; +		return PTR_ERR(sr);  	}  	if (!sr->clk_length) @@ -488,14 +553,17 @@ int sr_configure_minmax(struct voltagedomain *voltdm)  		SRCONFIG_SENENABLE |  		(sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT); -	if (sr->ip_type == SR_TYPE_V1) { +	switch (sr->ip_type) { +	case SR_TYPE_V1:  		sr_config |= SRCONFIG_DELAYCTRL;  		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;  		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; -	} else if (sr->ip_type == SR_TYPE_V2) { +		break; +	case SR_TYPE_V2:  		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;  		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; -	} else { +		break; +	default:  		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"  			"module without specifying the ip\n", __func__);  		return -EINVAL; @@ -511,20 +579,27 @@ int sr_configure_minmax(struct voltagedomain *voltdm)  	 * Enabling the interrupts if MINMAXAVG module is used.  	 * TODO: check if all the interrupts are mandatory  	 */ -	if (sr->ip_type == SR_TYPE_V1) { +	switch (sr->ip_type) { +	case SR_TYPE_V1:  		sr_modify_reg(sr, ERRCONFIG_V1,  			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |  			ERRCONFIG_MCUBOUNDINTEN),  			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |  			 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |  			 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST)); -	} else if (sr->ip_type == SR_TYPE_V2) { +		break; +	case SR_TYPE_V2:  		sr_write_reg(sr, IRQSTATUS,  			IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |  			IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);  		sr_write_reg(sr, IRQENABLE_SET,  			IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |  			IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT); +		break; +	default: +		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" +			"module without specifying the ip\n", __func__); +		return -EINVAL;  	}  	return 0; @@ -543,15 +618,15 @@ int sr_configure_minmax(struct voltagedomain *voltdm)   */  int sr_enable(struct voltagedomain *voltdm, unsigned long volt)  { -	u32 nvalue_reciprocal;  	struct omap_volt_data *volt_data;  	struct omap_sr *sr = _sr_lookup(voltdm); +	u32 nvalue_reciprocal;  	int ret;  	if (IS_ERR(sr)) {  		pr_warning("%s: omap_sr struct for sr_%s not found\n",  			__func__, voltdm->name); -		return -EINVAL; +		return PTR_ERR(sr);  	}  	volt_data = omap_voltage_get_voltdata(sr->voltdm, volt); @@ -559,7 +634,7 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)  	if (IS_ERR(volt_data)) {  		dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"  			"for nominal voltage %ld\n", __func__, volt); -		return -ENODATA; +		return PTR_ERR(volt_data);  	}  	nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs); @@ -617,10 +692,17 @@ void sr_disable(struct voltagedomain *voltdm)  	 * disable the clocks.  	 */  	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) { -		if (sr->ip_type == SR_TYPE_V1) +		switch (sr->ip_type) { +		case SR_TYPE_V1:  			sr_v1_disable(sr); -		else if (sr->ip_type == SR_TYPE_V2) +			break; +		case SR_TYPE_V2:  			sr_v2_disable(sr); +			break; +		default: +			dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n", +				sr->ip_type); +		}  	}  	pm_runtime_put_sync_suspend(&sr->pdev->dev); @@ -779,10 +861,10 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)  	sr_pmic_data = pmic_data;  } -/* PM Debug Fs enteries to enable disable smartreflex. */ +/* PM Debug FS entries to enable and disable smartreflex. */  static int omap_sr_autocomp_show(void *data, u64 *val)  { -	struct omap_sr *sr_info = (struct omap_sr *) data; +	struct omap_sr *sr_info = data;  	if (!sr_info) {  		pr_warning("%s: omap_sr struct not found\n", __func__); @@ -796,7 +878,7 @@ static int omap_sr_autocomp_show(void *data, u64 *val)  static int omap_sr_autocomp_store(void *data, u64 val)  { -	struct omap_sr *sr_info = (struct omap_sr *) data; +	struct omap_sr *sr_info = data;  	if (!sr_info) {  		pr_warning("%s: omap_sr struct not found\n", __func__); @@ -804,7 +886,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)  	}  	/* Sanity check */ -	if (val && (val != 1)) { +	if (val > 1) {  		pr_warning("%s: Invalid argument %lld\n", __func__, val);  		return -EINVAL;  	} @@ -821,11 +903,11 @@ static int omap_sr_autocomp_store(void *data, u64 val)  }  DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show, -		omap_sr_autocomp_store, "%llu\n"); +			omap_sr_autocomp_store, "%llu\n");  static int __init omap_sr_probe(struct platform_device *pdev)  { -	struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL); +	struct omap_sr *sr_info;  	struct omap_sr_data *pdata = pdev->dev.platform_data;  	struct resource *mem, *irq;  	struct dentry *nvalue_dir; @@ -833,12 +915,15 @@ static int __init omap_sr_probe(struct platform_device *pdev)  	int i, ret = 0;  	char *name; +	sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);  	if (!sr_info) {  		dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",  			__func__);  		return -ENOMEM;  	} +	platform_set_drvdata(pdev, sr_info); +  	if (!pdata) {  		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);  		ret = -EINVAL; @@ -897,14 +982,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)  		ret = sr_late_init(sr_info);  		if (ret) {  			pr_warning("%s: Error in SR late init\n", __func__); -			return ret; +			goto err_iounmap;  		}  	}  	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);  	if (!sr_dbg_dir) {  		sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); -		if (!sr_dbg_dir) { +		if (IS_ERR_OR_NULL(sr_dbg_dir)) {  			ret = PTR_ERR(sr_dbg_dir);  			pr_err("%s:sr debugfs dir creation failed(%d)\n",  				__func__, ret); @@ -921,7 +1006,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)  	}  	sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);  	kfree(name); -	if (IS_ERR(sr_info->dbg_dir)) { +	if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {  		dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",  			__func__);  		ret = PTR_ERR(sr_info->dbg_dir); @@ -938,7 +1023,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)  			&sr_info->err_minlimit);  	nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir); -	if (IS_ERR(nvalue_dir)) { +	if (IS_ERR_OR_NULL(nvalue_dir)) {  		dev_err(&pdev->dev, "%s: Unable to create debugfs directory"  			"for n-values\n", __func__);  		ret = PTR_ERR(nvalue_dir); @@ -994,7 +1079,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)  	if (IS_ERR(sr_info)) {  		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",  			__func__); -		return -EINVAL; +		return PTR_ERR(sr_info);  	}  	if (sr_info->autocomp_active) @@ -1011,8 +1096,32 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)  	return 0;  } +static void __devexit omap_sr_shutdown(struct platform_device *pdev) +{ +	struct omap_sr_data *pdata = pdev->dev.platform_data; +	struct omap_sr *sr_info; + +	if (!pdata) { +		dev_err(&pdev->dev, "%s: platform data missing\n", __func__); +		return; +	} + +	sr_info = _sr_lookup(pdata->voltdm); +	if (IS_ERR(sr_info)) { +		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", +			__func__); +		return; +	} + +	if (sr_info->autocomp_active) +		sr_stop_vddautocomp(sr_info); + +	return; +} +  static struct platform_driver smartreflex_driver = { -	.remove         = omap_sr_remove, +	.remove         = __devexit_p(omap_sr_remove), +	.shutdown	= __devexit_p(omap_sr_shutdown),  	.driver		= {  		.name	= "smartreflex",  	}, @@ -1042,12 +1151,12 @@ static int __init sr_init(void)  	return 0;  } +late_initcall(sr_init);  static void __exit sr_exit(void)  {  	platform_driver_unregister(&smartreflex_driver);  } -late_initcall(sr_init);  module_exit(sr_exit);  MODULE_DESCRIPTION("OMAP Smartreflex Driver");  |