aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-bcm-kona.c
diff options
context:
space:
mode:
authorJonathan Richardson <jonathar@broadcom.com>2015-06-15 17:21:01 -0400
committerThierry Reding <thierry.reding@gmail.com>2015-08-17 10:19:41 -0400
commitfe0aea7978d25d8df6c128481b8111e76d972657 (patch)
tree3ea12caf1dcce52f795951013b49709221de596f /drivers/pwm/pwm-bcm-kona.c
parent09c14459f2622ccacdff13461c5c864bff80cc07 (diff)
pwm: kona: Modify settings application sequence
Update the driver so that settings are applied in accordance with the most recent version of the hardware spec. The revised sequence clears the trigger bit, waits 400ns, writes settings, sets the trigger bit, and waits another 400ns. This corrects an issue where occasionally a requested change was not properly reflected in the PWM output. Reviewed-by: Arun Ramamurthy <arunrama@broadcom.com> Reviewed-by: Scott Branden <sbranden@broadcom.com> Tested-by: Scott Branden <sbranden@broadcom.com> Reviewed-by: Tim Kryger <tim.kryger@gmail.com> Signed-off-by: Jonathan Richardson <jonathar@broadcom.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-bcm-kona.c')
-rw-r--r--drivers/pwm/pwm-bcm-kona.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 920cd1b5aa9d..c63418322023 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -76,19 +76,36 @@ static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip)
76 return container_of(_chip, struct kona_pwmc, chip); 76 return container_of(_chip, struct kona_pwmc, chip);
77} 77}
78 78
79static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan) 79/*
80 * Clear trigger bit but set smooth bit to maintain old output.
81 */
82static void kona_pwmc_prepare_for_settings(struct kona_pwmc *kp,
83 unsigned int chan)
80{ 84{
81 unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET); 85 unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
82 86
83 /* Clear trigger bit but set smooth bit to maintain old output */
84 value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan); 87 value |= 1 << PWM_CONTROL_SMOOTH_SHIFT(chan);
85 value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan)); 88 value &= ~(1 << PWM_CONTROL_TRIGGER_SHIFT(chan));
86 writel(value, kp->base + PWM_CONTROL_OFFSET); 89 writel(value, kp->base + PWM_CONTROL_OFFSET);
87 90
91 /*
92 * There must be a min 400ns delay between clearing trigger and setting
93 * it. Failing to do this may result in no PWM signal.
94 */
95 ndelay(400);
96}
97
98static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
99{
100 unsigned int value = readl(kp->base + PWM_CONTROL_OFFSET);
101
88 /* Set trigger bit and clear smooth bit to apply new settings */ 102 /* Set trigger bit and clear smooth bit to apply new settings */
89 value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan)); 103 value &= ~(1 << PWM_CONTROL_SMOOTH_SHIFT(chan));
90 value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan); 104 value |= 1 << PWM_CONTROL_TRIGGER_SHIFT(chan);
91 writel(value, kp->base + PWM_CONTROL_OFFSET); 105 writel(value, kp->base + PWM_CONTROL_OFFSET);
106
107 /* Trigger bit must be held high for at least 400 ns. */
108 ndelay(400);
92} 109}
93 110
94static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, 111static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -133,8 +150,14 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
133 return -EINVAL; 150 return -EINVAL;
134 } 151 }
135 152
136 /* If the PWM channel is enabled, write the settings to the HW */ 153 /*
154 * Don't apply settings if disabled. The period and duty cycle are
155 * always calculated above to ensure the new values are
156 * validated immediately instead of on enable.
157 */
137 if (pwm_is_enabled(pwm)) { 158 if (pwm_is_enabled(pwm)) {
159 kona_pwmc_prepare_for_settings(kp, chan);
160
138 value = readl(kp->base + PRESCALE_OFFSET); 161 value = readl(kp->base + PRESCALE_OFFSET);
139 value &= ~PRESCALE_MASK(chan); 162 value &= ~PRESCALE_MASK(chan);
140 value |= prescale << PRESCALE_SHIFT(chan); 163 value |= prescale << PRESCALE_SHIFT(chan);
@@ -164,6 +187,8 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
164 return ret; 187 return ret;
165 } 188 }
166 189
190 kona_pwmc_prepare_for_settings(kp, chan);
191
167 value = readl(kp->base + PWM_CONTROL_OFFSET); 192 value = readl(kp->base + PWM_CONTROL_OFFSET);
168 193
169 if (polarity == PWM_POLARITY_NORMAL) 194 if (polarity == PWM_POLARITY_NORMAL)
@@ -175,9 +200,6 @@ static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
175 200
176 kona_pwmc_apply_settings(kp, chan); 201 kona_pwmc_apply_settings(kp, chan);
177 202
178 /* Wait for waveform to settle before gating off the clock */
179 ndelay(400);
180
181 clk_disable_unprepare(kp->clk); 203 clk_disable_unprepare(kp->clk);
182 204
183 return 0; 205 return 0;
@@ -208,13 +230,20 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
208{ 230{
209 struct kona_pwmc *kp = to_kona_pwmc(chip); 231 struct kona_pwmc *kp = to_kona_pwmc(chip);
210 unsigned int chan = pwm->hwpwm; 232 unsigned int chan = pwm->hwpwm;
233 unsigned int value;
234
235 kona_pwmc_prepare_for_settings(kp, chan);
211 236
212 /* Simulate a disable by configuring for zero duty */ 237 /* Simulate a disable by configuring for zero duty */
213 writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan)); 238 writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
214 kona_pwmc_apply_settings(kp, chan); 239 writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
215 240
216 /* Wait for waveform to settle before gating off the clock */ 241 /* Set prescale to 0 for this channel */
217 ndelay(400); 242 value = readl(kp->base + PRESCALE_OFFSET);
243 value &= ~PRESCALE_MASK(chan);
244 writel(value, kp->base + PRESCALE_OFFSET);
245
246 kona_pwmc_apply_settings(kp, chan);
218 247
219 clk_disable_unprepare(kp->clk); 248 clk_disable_unprepare(kp->clk);
220} 249}