* PWM output is achieved by calculating a clock that permits calculating
  * two periods (low and high). The counter then has to be set to switch after
  * N cycles for the first half period.
- * The hardware has no "polarity" setting. This driver reverses the period
+ * Partly the hardware has no "polarity" setting. This driver reverses the period
  * cycles (the low length is inverted with the high length) for
  * PWM_POLARITY_INVERSED. This means that .get_state cannot read the polarity
  * from the hardware.
 #define MISC_B_CLK_SEL_SHIFT   6
 #define MISC_A_CLK_SEL_SHIFT   4
 #define MISC_CLK_SEL_MASK      0x3
+#define MISC_B_CONSTANT_EN     BIT(29)
+#define MISC_A_CONSTANT_EN     BIT(28)
+#define MISC_B_INVERT_EN       BIT(27)
+#define MISC_A_INVERT_EN       BIT(26)
 #define MISC_B_EN              BIT(1)
 #define MISC_A_EN              BIT(0)
 
        u8              clk_div_shift;
        u8              clk_en_shift;
        u32             pwm_en_mask;
+       u32             const_en_mask;
+       u32             inv_en_mask;
 } meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
        {
                .reg_offset     = REG_PWM_A,
                .clk_div_shift  = MISC_A_CLK_DIV_SHIFT,
                .clk_en_shift   = MISC_A_CLK_EN_SHIFT,
                .pwm_en_mask    = MISC_A_EN,
+               .const_en_mask  = MISC_A_CONSTANT_EN,
+               .inv_en_mask    = MISC_A_INVERT_EN,
        },
        {
                .reg_offset     = REG_PWM_B,
                .clk_div_shift  = MISC_B_CLK_DIV_SHIFT,
                .clk_en_shift   = MISC_B_CLK_EN_SHIFT,
                .pwm_en_mask    = MISC_B_EN,
+               .const_en_mask  = MISC_B_CONSTANT_EN,
+               .inv_en_mask    = MISC_B_INVERT_EN,
        }
 };
 
        unsigned long rate;
        unsigned int hi;
        unsigned int lo;
+       bool constant;
+       bool inverted;
 
        struct clk_mux mux;
        struct clk_divider div;
 struct meson_pwm_data {
        const char *const parent_names[MESON_NUM_MUX_PARENTS];
        int (*channels_init)(struct pwm_chip *chip);
+       bool has_constant;
+       bool has_polarity;
 };
 
 struct meson_pwm {
         * Fixing this needs some care however as some machines might rely on
         * this.
         */
-       if (state->polarity == PWM_POLARITY_INVERSED)
+       if (state->polarity == PWM_POLARITY_INVERSED && !meson->data->has_polarity)
                duty = period - duty;
 
        freq = div64_u64(NSEC_PER_SEC * 0xffffULL, period);
        if (duty == period) {
                channel->hi = cnt;
                channel->lo = 0;
+               channel->constant = true;
        } else if (duty == 0) {
                channel->hi = 0;
                channel->lo = cnt;
+               channel->constant = true;
        } else {
                duty_cnt = mul_u64_u64_div_u64(fin_freq, duty, NSEC_PER_SEC);
 
 
                channel->hi = duty_cnt;
                channel->lo = cnt - duty_cnt;
+               channel->constant = false;
        }
 
        channel->rate = fin_freq;
 
        value = readl(meson->base + REG_MISC_AB);
        value |= channel_data->pwm_en_mask;
+
+       if (meson->data->has_constant) {
+               value &= ~channel_data->const_en_mask;
+               if (channel->constant)
+                       value |= channel_data->const_en_mask;
+       }
+
+       if (meson->data->has_polarity) {
+               value &= ~channel_data->inv_en_mask;
+               if (channel->inverted)
+                       value |= channel_data->inv_en_mask;
+       }
+
        writel(value, meson->base + REG_MISC_AB);
 
        spin_unlock_irqrestore(&meson->lock, flags);
 static void meson_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct meson_pwm *meson = to_meson_pwm(chip);
+       struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+       struct meson_pwm_channel_data *channel_data;
        unsigned long flags;
        u32 value;
 
+       channel_data = &meson_pwm_per_channel_data[pwm->hwpwm];
+
        spin_lock_irqsave(&meson->lock, flags);
 
        value = readl(meson->base + REG_MISC_AB);
-       value &= ~meson_pwm_per_channel_data[pwm->hwpwm].pwm_en_mask;
+       value &= ~channel_data->pwm_en_mask;
+
+       if (meson->data->has_polarity) {
+               value &= ~channel_data->inv_en_mask;
+               if (channel->inverted)
+                       value |= channel_data->inv_en_mask;
+       }
+
        writel(value, meson->base + REG_MISC_AB);
 
        spin_unlock_irqrestore(&meson->lock, flags);
        struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
        int err = 0;
 
+       channel->inverted = (state->polarity == PWM_POLARITY_INVERSED);
+
        if (!state->enabled) {
-               if (state->polarity == PWM_POLARITY_INVERSED) {
+               if (channel->inverted && !meson->data->has_polarity) {
                        /*
-                        * This IP block revision doesn't have an "always high"
+                        * Some of IP block revisions don't have an "always high"
                         * setting which we can use for "inverted disabled".
                         * Instead we achieve this by setting mux parent with
                         * highest rate and minimum divider value, resulting
                        channel->rate = ULONG_MAX;
                        channel->hi = ~0;
                        channel->lo = 0;
+                       channel->constant = true;
 
                        meson_pwm_enable(chip, pwm);
                } else {
        value = readl(meson->base + REG_MISC_AB);
        state->enabled = value & channel_data->pwm_en_mask;
 
+       if (meson->data->has_polarity && (value & channel_data->inv_en_mask))
+               state->polarity = PWM_POLARITY_INVERSED;
+       else
+               state->polarity = PWM_POLARITY_NORMAL;
+
        value = readl(meson->base + channel_data->reg_offset);
        lo = FIELD_GET(PWM_LOW_MASK, value);
        hi = FIELD_GET(PWM_HIGH_MASK, value);
        state->period = meson_pwm_cnt_to_ns(chip, pwm, lo + hi);
        state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, hi);
 
-       state->polarity = PWM_POLARITY_NORMAL;
-
        return 0;
 }