Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pwm: meson: Support constant and polarity bits

Newer meson PWM IPs support constant and polarity bits. Support them to
correctly implement constant and inverted output levels.

Using constant bit allows to have truly stable low or high output level.
Since hi and low regs internally increment its values by 1 just writing
zero to any of them gives 1 clock count impulse. If constant bit is set
zero value in hi and low regs is not incremented.

Using polarity bit instead of swapping hi and low reg values allows to
correctly identify inversion in .get_state().

Signed-off-by: George Stark <gnstark@salutedevices.com>
Link: https://lore.kernel.org/r/20241119125318.3492261-3-gnstark@salutedevices.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

George Stark and committed by
Uwe Kleine-König
dd4d280a 8c22e890

+54 -7
+54 -7
drivers/pwm/pwm-meson.c
··· 6 6 * PWM output is achieved by calculating a clock that permits calculating 7 7 * two periods (low and high). The counter then has to be set to switch after 8 8 * N cycles for the first half period. 9 - * The hardware has no "polarity" setting. This driver reverses the period 9 + * Partly the hardware has no "polarity" setting. This driver reverses the period 10 10 * cycles (the low length is inverted with the high length) for 11 11 * PWM_POLARITY_INVERSED. This means that .get_state cannot read the polarity 12 12 * from the hardware. ··· 56 56 #define MISC_B_CLK_SEL_SHIFT 6 57 57 #define MISC_A_CLK_SEL_SHIFT 4 58 58 #define MISC_CLK_SEL_MASK 0x3 59 + #define MISC_B_CONSTANT_EN BIT(29) 60 + #define MISC_A_CONSTANT_EN BIT(28) 61 + #define MISC_B_INVERT_EN BIT(27) 62 + #define MISC_A_INVERT_EN BIT(26) 59 63 #define MISC_B_EN BIT(1) 60 64 #define MISC_A_EN BIT(0) 61 65 ··· 72 68 u8 clk_div_shift; 73 69 u8 clk_en_shift; 74 70 u32 pwm_en_mask; 71 + u32 const_en_mask; 72 + u32 inv_en_mask; 75 73 } meson_pwm_per_channel_data[MESON_NUM_PWMS] = { 76 74 { 77 75 .reg_offset = REG_PWM_A, ··· 81 75 .clk_div_shift = MISC_A_CLK_DIV_SHIFT, 82 76 .clk_en_shift = MISC_A_CLK_EN_SHIFT, 83 77 .pwm_en_mask = MISC_A_EN, 78 + .const_en_mask = MISC_A_CONSTANT_EN, 79 + .inv_en_mask = MISC_A_INVERT_EN, 84 80 }, 85 81 { 86 82 .reg_offset = REG_PWM_B, ··· 90 82 .clk_div_shift = MISC_B_CLK_DIV_SHIFT, 91 83 .clk_en_shift = MISC_B_CLK_EN_SHIFT, 92 84 .pwm_en_mask = MISC_B_EN, 85 + .const_en_mask = MISC_B_CONSTANT_EN, 86 + .inv_en_mask = MISC_B_INVERT_EN, 93 87 } 94 88 }; 95 89 ··· 99 89 unsigned long rate; 100 90 unsigned int hi; 101 91 unsigned int lo; 92 + bool constant; 93 + bool inverted; 102 94 103 95 struct clk_mux mux; 104 96 struct clk_divider div; ··· 111 99 struct meson_pwm_data { 112 100 const char *const parent_names[MESON_NUM_MUX_PARENTS]; 113 101 int (*channels_init)(struct pwm_chip *chip); 102 + bool has_constant; 103 + bool has_polarity; 114 104 }; 115 105 116 106 struct meson_pwm { ··· 174 160 * Fixing this needs some care however as some machines might rely on 175 161 * this. 176 162 */ 177 - if (state->polarity == PWM_POLARITY_INVERSED) 163 + if (state->polarity == PWM_POLARITY_INVERSED && !meson->data->has_polarity) 178 164 duty = period - duty; 179 165 180 166 freq = div64_u64(NSEC_PER_SEC * 0xffffULL, period); ··· 201 187 if (duty == period) { 202 188 channel->hi = cnt; 203 189 channel->lo = 0; 190 + channel->constant = true; 204 191 } else if (duty == 0) { 205 192 channel->hi = 0; 206 193 channel->lo = cnt; 194 + channel->constant = true; 207 195 } else { 208 196 duty_cnt = mul_u64_u64_div_u64(fin_freq, duty, NSEC_PER_SEC); 209 197 ··· 213 197 214 198 channel->hi = duty_cnt; 215 199 channel->lo = cnt - duty_cnt; 200 + channel->constant = false; 216 201 } 217 202 218 203 channel->rate = fin_freq; ··· 244 227 245 228 value = readl(meson->base + REG_MISC_AB); 246 229 value |= channel_data->pwm_en_mask; 230 + 231 + if (meson->data->has_constant) { 232 + value &= ~channel_data->const_en_mask; 233 + if (channel->constant) 234 + value |= channel_data->const_en_mask; 235 + } 236 + 237 + if (meson->data->has_polarity) { 238 + value &= ~channel_data->inv_en_mask; 239 + if (channel->inverted) 240 + value |= channel_data->inv_en_mask; 241 + } 242 + 247 243 writel(value, meson->base + REG_MISC_AB); 248 244 249 245 spin_unlock_irqrestore(&meson->lock, flags); ··· 265 235 static void meson_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 266 236 { 267 237 struct meson_pwm *meson = to_meson_pwm(chip); 238 + struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; 239 + struct meson_pwm_channel_data *channel_data; 268 240 unsigned long flags; 269 241 u32 value; 242 + 243 + channel_data = &meson_pwm_per_channel_data[pwm->hwpwm]; 270 244 271 245 spin_lock_irqsave(&meson->lock, flags); 272 246 273 247 value = readl(meson->base + REG_MISC_AB); 274 - value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask; 248 + value &= ~channel_data->pwm_en_mask; 249 + 250 + if (meson->data->has_polarity) { 251 + value &= ~channel_data->inv_en_mask; 252 + if (channel->inverted) 253 + value |= channel_data->inv_en_mask; 254 + } 255 + 275 256 writel(value, meson->base + REG_MISC_AB); 276 257 277 258 spin_unlock_irqrestore(&meson->lock, flags); ··· 295 254 struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; 296 255 int err = 0; 297 256 257 + channel->inverted = (state->polarity == PWM_POLARITY_INVERSED); 258 + 298 259 if (!state->enabled) { 299 - if (state->polarity == PWM_POLARITY_INVERSED) { 260 + if (channel->inverted && !meson->data->has_polarity) { 300 261 /* 301 - * This IP block revision doesn't have an "always high" 262 + * Some of IP block revisions don't have an "always high" 302 263 * setting which we can use for "inverted disabled". 303 264 * Instead we achieve this by setting mux parent with 304 265 * highest rate and minimum divider value, resulting ··· 314 271 channel->rate = ULONG_MAX; 315 272 channel->hi = ~0; 316 273 channel->lo = 0; 274 + channel->constant = true; 317 275 318 276 meson_pwm_enable(chip, pwm); 319 277 } else { ··· 361 317 value = readl(meson->base + REG_MISC_AB); 362 318 state->enabled = value & channel_data->pwm_en_mask; 363 319 320 + if (meson->data->has_polarity && (value & channel_data->inv_en_mask)) 321 + state->polarity = PWM_POLARITY_INVERSED; 322 + else 323 + state->polarity = PWM_POLARITY_NORMAL; 324 + 364 325 value = readl(meson->base + channel_data->reg_offset); 365 326 lo = FIELD_GET(PWM_LOW_MASK, value); 366 327 hi = FIELD_GET(PWM_HIGH_MASK, value); 367 328 368 329 state->period = meson_pwm_cnt_to_ns(chip, pwm, lo + hi); 369 330 state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, hi); 370 - 371 - state->polarity = PWM_POLARITY_NORMAL; 372 331 373 332 return 0; 374 333 }