diff options
Diffstat (limited to 'drivers/pwm/pwm-rockchip.c')
| -rw-r--r-- | drivers/pwm/pwm-rockchip.c | 57 | 
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index bdd8644c01cf..9442df244101 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -24,7 +24,9 @@  #define PWM_ENABLE		(1 << 0)  #define PWM_CONTINUOUS		(1 << 1)  #define PWM_DUTY_POSITIVE	(1 << 3) +#define PWM_DUTY_NEGATIVE	(0 << 3)  #define PWM_INACTIVE_NEGATIVE	(0 << 4) +#define PWM_INACTIVE_POSITIVE	(1 << 4)  #define PWM_OUTPUT_LEFT		(0 << 5)  #define PWM_LP_DISABLE		(0 << 8) @@ -45,8 +47,10 @@ struct rockchip_pwm_regs {  struct rockchip_pwm_data {  	struct rockchip_pwm_regs regs;  	unsigned int prescaler; +	const struct pwm_ops *ops; -	void (*set_enable)(struct pwm_chip *chip, bool enable); +	void (*set_enable)(struct pwm_chip *chip, +			   struct pwm_device *pwm, bool enable);  };  static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) @@ -54,7 +58,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)  	return container_of(c, struct rockchip_pwm_chip, chip);  } -static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) +static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, +				       struct pwm_device *pwm, bool enable)  {  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);  	u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN; @@ -70,14 +75,19 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)  	writel_relaxed(val, pc->base + pc->data->regs.ctrl);  } -static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) +static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, +				       struct pwm_device *pwm, bool enable)  {  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);  	u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | -			  PWM_CONTINUOUS | PWM_DUTY_POSITIVE | -			  PWM_INACTIVE_NEGATIVE; +			  PWM_CONTINUOUS;  	u32 val; +	if (pwm->polarity == PWM_POLARITY_INVERSED) +		enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; +	else +		enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; +  	val = readl_relaxed(pc->base + pc->data->regs.ctrl);  	if (enable) @@ -124,6 +134,19 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,  	return 0;  } +static int rockchip_pwm_set_polarity(struct pwm_chip *chip, +				     struct pwm_device *pwm, +				     enum pwm_polarity polarity) +{ +	/* +	 * No action needed here because pwm->polarity will be set by the core +	 * and the core will only change polarity when the PWM is not enabled. +	 * We'll handle things in set_enable(). +	 */ + +	return 0; +} +  static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)  {  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); @@ -133,7 +156,7 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)  	if (ret)  		return ret; -	pc->data->set_enable(chip, true); +	pc->data->set_enable(chip, pwm, true);  	return 0;  } @@ -142,18 +165,26 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)  {  	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); -	pc->data->set_enable(chip, false); +	pc->data->set_enable(chip, pwm, false);  	clk_disable(pc->clk);  } -static const struct pwm_ops rockchip_pwm_ops = { +static const struct pwm_ops rockchip_pwm_ops_v1 = {  	.config = rockchip_pwm_config,  	.enable = rockchip_pwm_enable,  	.disable = rockchip_pwm_disable,  	.owner = THIS_MODULE,  }; +static const struct pwm_ops rockchip_pwm_ops_v2 = { +	.config = rockchip_pwm_config, +	.set_polarity = rockchip_pwm_set_polarity, +	.enable = rockchip_pwm_enable, +	.disable = rockchip_pwm_disable, +	.owner = THIS_MODULE, +}; +  static const struct rockchip_pwm_data pwm_data_v1 = {  	.regs = {  		.duty = 0x04, @@ -162,6 +193,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {  		.ctrl = 0x0c,  	},  	.prescaler = 2, +	.ops = &rockchip_pwm_ops_v1,  	.set_enable = rockchip_pwm_set_enable_v1,  }; @@ -173,6 +205,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = {  		.ctrl = 0x0c,  	},  	.prescaler = 1, +	.ops = &rockchip_pwm_ops_v2,  	.set_enable = rockchip_pwm_set_enable_v2,  }; @@ -184,6 +217,7 @@ static const struct rockchip_pwm_data pwm_data_vop = {  		.ctrl = 0x00,  	},  	.prescaler = 1, +	.ops = &rockchip_pwm_ops_v2,  	.set_enable = rockchip_pwm_set_enable_v2,  }; @@ -227,10 +261,15 @@ static int rockchip_pwm_probe(struct platform_device *pdev)  	pc->data = id->data;  	pc->chip.dev = &pdev->dev; -	pc->chip.ops = &rockchip_pwm_ops; +	pc->chip.ops = pc->data->ops;  	pc->chip.base = -1;  	pc->chip.npwm = 1; +	if (pc->data->ops->set_polarity) { +		pc->chip.of_xlate = of_pwm_xlate_with_flags; +		pc->chip.of_pwm_n_cells = 3; +	} +  	ret = pwmchip_add(&pc->chip);  	if (ret < 0) {  		clk_unprepare(pc->clk);  |