diff options
| author | Tejun Heo <tj@kernel.org> | 2013-01-23 09:31:01 -0800 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2013-01-23 09:31:01 -0800 | 
| commit | c14afb82ffff5903a701a9fb737ac20f36d1f755 (patch) | |
| tree | 304dcc7b1d7b9a5f564f7e978228e61ef41fbef2 /drivers/pwm/pwm-tiehrpwm.c | |
| parent | 0fdff3ec6d87856cdcc99e69cf42143fdd6c56b4 (diff) | |
| parent | 1d8549085377674224bf30a368284c391a3ce40e (diff) | |
| download | olio-linux-3.10-c14afb82ffff5903a701a9fb737ac20f36d1f755.tar.xz olio-linux-3.10-c14afb82ffff5903a701a9fb737ac20f36d1f755.zip  | |
Merge branch 'master' into for-3.9-async
To receive f56c3196f251012de9b3ebaff55732a9074fdaae ("async: fix
__lowest_in_progress()").
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/pwm/pwm-tiehrpwm.c')
| -rw-r--r-- | drivers/pwm/pwm-tiehrpwm.c | 62 | 
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 9ffd389d0c8..72a6dd40c9e 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -25,6 +25,10 @@  #include <linux/err.h>  #include <linux/clk.h>  #include <linux/pm_runtime.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> + +#include "pwm-tipwmss.h"  /* EHRPWM registers and bits definitions */ @@ -115,6 +119,7 @@ struct ehrpwm_pwm_chip {  	void __iomem	*mmio_base;  	unsigned long period_cycles[NUM_PWM_CHANNEL];  	enum pwm_polarity polarity[NUM_PWM_CHANNEL]; +	struct	clk	*tbclk;  };  static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) @@ -335,6 +340,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)  	/* Channels polarity can be configured from action qualifier module */  	configure_polarity(pc, pwm->hwpwm); +	/* Enable TBCLK before enabling PWM device */ +	clk_enable(pc->tbclk); +  	/* Enable time counter for free_run */  	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);  	return 0; @@ -363,6 +371,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)  	ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); +	/* Disabling TBCLK on PWM disable */ +	clk_disable(pc->tbclk); +  	/* Stop Time base counter */  	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); @@ -392,12 +403,24 @@ static const struct pwm_ops ehrpwm_pwm_ops = {  	.owner		= THIS_MODULE,  }; +static const struct of_device_id ehrpwm_of_match[] = { +	{ .compatible	= "ti,am33xx-ehrpwm" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, ehrpwm_of_match); +  static int ehrpwm_pwm_probe(struct platform_device *pdev)  {  	int ret;  	struct resource *r;  	struct clk *clk;  	struct ehrpwm_pwm_chip *pc; +	u16 status; +	struct pinctrl *pinctrl; + +	pinctrl = devm_pinctrl_get_select_default(&pdev->dev); +	if (IS_ERR(pinctrl)) +		dev_warn(&pdev->dev, "unable to select pin group\n");  	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);  	if (!pc) { @@ -419,6 +442,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)  	pc->chip.dev = &pdev->dev;  	pc->chip.ops = &ehrpwm_pwm_ops; +	pc->chip.of_xlate = of_pwm_xlate_with_flags; +	pc->chip.of_pwm_n_cells = 3;  	pc->chip.base = -1;  	pc->chip.npwm = NUM_PWM_CHANNEL; @@ -432,6 +457,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)  	if (!pc->mmio_base)  		return  -EADDRNOTAVAIL; +	/* Acquire tbclk for Time Base EHRPWM submodule */ +	pc->tbclk = devm_clk_get(&pdev->dev, "tbclk"); +	if (IS_ERR(pc->tbclk)) { +		dev_err(&pdev->dev, "Failed to get tbclk\n"); +		return PTR_ERR(pc->tbclk); +	} +  	ret = pwmchip_add(&pc->chip);  	if (ret < 0) {  		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); @@ -439,14 +471,40 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)  	}  	pm_runtime_enable(&pdev->dev); +	pm_runtime_get_sync(&pdev->dev); + +	status = pwmss_submodule_state_change(pdev->dev.parent, +			PWMSS_EPWMCLK_EN); +	if (!(status & PWMSS_EPWMCLK_EN_ACK)) { +		dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); +		ret = -EINVAL; +		goto pwmss_clk_failure; +	} + +	pm_runtime_put_sync(&pdev->dev); +  	platform_set_drvdata(pdev, pc);  	return 0; + +pwmss_clk_failure: +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev); +	pwmchip_remove(&pc->chip); +	return ret;  }  static int ehrpwm_pwm_remove(struct platform_device *pdev)  {  	struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); +	pm_runtime_get_sync(&pdev->dev); +	/* +	 * Due to hardware misbehaviour, acknowledge of the stop_req +	 * is missing. Hence checking of the status bit skipped. +	 */ +	pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ); +	pm_runtime_put_sync(&pdev->dev); +  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  	return pwmchip_remove(&pc->chip); @@ -454,7 +512,9 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)  static struct platform_driver ehrpwm_pwm_driver = {  	.driver = { -		.name = "ehrpwm", +		.name	= "ehrpwm", +		.owner	= THIS_MODULE, +		.of_match_table = ehrpwm_of_match,  	},  	.probe = ehrpwm_pwm_probe,  	.remove = ehrpwm_pwm_remove,  |