diff options
Diffstat (limited to 'drivers/pwm/pwm-tiecap.c')
| -rw-r--r-- | drivers/pwm/pwm-tiecap.c | 48 | 
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 87c091b245c..5cf016dd982 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -25,6 +25,10 @@  #include <linux/clk.h>  #include <linux/pm_runtime.h>  #include <linux/pwm.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> + +#include "pwm-tipwmss.h"  /* ECAP registers and bits definitions */  #define CAP1			0x08 @@ -184,12 +188,24 @@ static const struct pwm_ops ecap_pwm_ops = {  	.owner		= THIS_MODULE,  }; +static const struct of_device_id ecap_of_match[] = { +	{ .compatible	= "ti,am33xx-ecap" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, ecap_of_match); +  static int ecap_pwm_probe(struct platform_device *pdev)  {  	int ret;  	struct resource *r;  	struct clk *clk;  	struct ecap_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) { @@ -211,6 +227,8 @@ static int ecap_pwm_probe(struct platform_device *pdev)  	pc->chip.dev = &pdev->dev;  	pc->chip.ops = &ecap_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 = 1; @@ -231,14 +249,40 @@ static int ecap_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_ECAPCLK_EN); +	if (!(status & PWMSS_ECAPCLK_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 ecap_pwm_remove(struct platform_device *pdev)  {  	struct ecap_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_ECAPCLK_STOP_REQ); +	pm_runtime_put_sync(&pdev->dev); +  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  	return pwmchip_remove(&pc->chip); @@ -246,7 +290,9 @@ static int ecap_pwm_remove(struct platform_device *pdev)  static struct platform_driver ecap_pwm_driver = {  	.driver = { -		.name = "ecap", +		.name	= "ecap", +		.owner	= THIS_MODULE, +		.of_match_table = ecap_of_match,  	},  	.probe = ecap_pwm_probe,  	.remove = ecap_pwm_remove,  |