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

pwm: sophgo-sg2042: Add support for SG2044

Add PWM controller for SG2044 on base of SG2042.

Reviewed-by: Chen Wang <unicorn_wang@outlook.com>
Tested-by: Chen Wang <unicorn_wang@outlook.com>
Signed-off-by: Longbin Li <looong.bin@gmail.com>
Link: https://lore.kernel.org/r/20250528101139.28702-4-looong.bin@gmail.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

Longbin Li and committed by
Uwe Kleine-König
21d5daad 8c805dfa

+87 -2
+87 -2
drivers/pwm/pwm-sophgo-sg2042.c
··· 13 13 * the running period. 14 14 * - When PERIOD and HLPERIOD is set to 0, the PWM wave output will 15 15 * be stopped and the output is pulled to high. 16 + * - SG2044 supports both polarities, SG2042 only normal polarity. 16 17 * See the datasheet [1] for more details. 17 18 * [1]:https://github.com/sophgo/sophgo-doc/tree/main/SG2042/TRM 18 19 */ ··· 41 40 */ 42 41 #define SG2042_PWM_HLPERIOD(chan) ((chan) * 8 + 0) 43 42 #define SG2042_PWM_PERIOD(chan) ((chan) * 8 + 4) 43 + 44 + #define SG2044_PWM_POLARITY 0x40 45 + #define SG2044_PWM_PWMSTART 0x44 46 + #define SG2044_PWM_OE 0xd0 44 47 45 48 #define SG2042_PWM_CHANNELNUM 4 46 49 ··· 89 84 period_ticks = min(mul_u64_u64_div_u64(ddata->clk_rate_hz, state->period, NSEC_PER_SEC), U32_MAX); 90 85 hlperiod_ticks = min(mul_u64_u64_div_u64(ddata->clk_rate_hz, state->duty_cycle, NSEC_PER_SEC), U32_MAX); 91 86 92 - dev_dbg(pwmchip_parent(chip), "chan[%u]: PERIOD=%u, HLPERIOD=%u\n", 93 - pwm->hwpwm, period_ticks, hlperiod_ticks); 87 + dev_dbg(pwmchip_parent(chip), "chan[%u]: ENABLE=%u, PERIOD=%u, HLPERIOD=%u, POLARITY=%u\n", 88 + pwm->hwpwm, state->enabled, period_ticks, hlperiod_ticks, state->polarity); 94 89 95 90 pwm_sg2042_config(ddata, pwm->hwpwm, period_ticks, hlperiod_ticks); 96 91 } ··· 140 135 return 0; 141 136 } 142 137 138 + static void pwm_sg2044_set_outputen(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 139 + bool enabled) 140 + { 141 + u32 pwmstart; 142 + 143 + pwmstart = readl(ddata->base + SG2044_PWM_PWMSTART); 144 + 145 + if (enabled) 146 + pwmstart |= BIT(pwm->hwpwm); 147 + else 148 + pwmstart &= ~BIT(pwm->hwpwm); 149 + 150 + writel(pwmstart, ddata->base + SG2044_PWM_PWMSTART); 151 + } 152 + 153 + static void pwm_sg2044_set_outputdir(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 154 + bool enabled) 155 + { 156 + u32 pwm_oe; 157 + 158 + pwm_oe = readl(ddata->base + SG2044_PWM_OE); 159 + 160 + if (enabled) 161 + pwm_oe |= BIT(pwm->hwpwm); 162 + else 163 + pwm_oe &= ~BIT(pwm->hwpwm); 164 + 165 + writel(pwm_oe, ddata->base + SG2044_PWM_OE); 166 + } 167 + 168 + static void pwm_sg2044_set_polarity(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 169 + const struct pwm_state *state) 170 + { 171 + u32 pwm_polarity; 172 + 173 + pwm_polarity = readl(ddata->base + SG2044_PWM_POLARITY); 174 + 175 + if (state->polarity == PWM_POLARITY_NORMAL) 176 + pwm_polarity &= ~BIT(pwm->hwpwm); 177 + else 178 + pwm_polarity |= BIT(pwm->hwpwm); 179 + 180 + writel(pwm_polarity, ddata->base + SG2044_PWM_POLARITY); 181 + } 182 + 183 + static int pwm_sg2044_apply(struct pwm_chip *chip, struct pwm_device *pwm, 184 + const struct pwm_state *state) 185 + { 186 + struct sg2042_pwm_ddata *ddata = pwmchip_get_drvdata(chip); 187 + 188 + pwm_sg2044_set_polarity(ddata, pwm, state); 189 + 190 + pwm_sg2042_set_dutycycle(chip, pwm, state); 191 + 192 + /* 193 + * re-enable PWMSTART to refresh the register period 194 + */ 195 + pwm_sg2044_set_outputen(ddata, pwm, false); 196 + 197 + if (!state->enabled) 198 + return 0; 199 + 200 + pwm_sg2044_set_outputdir(ddata, pwm, true); 201 + pwm_sg2044_set_outputen(ddata, pwm, true); 202 + 203 + return 0; 204 + } 205 + 143 206 static const struct sg2042_chip_data sg2042_chip_data = { 144 207 .ops = { 145 208 .apply = pwm_sg2042_apply, 209 + .get_state = pwm_sg2042_get_state, 210 + }, 211 + }; 212 + 213 + static const struct sg2042_chip_data sg2044_chip_data = { 214 + .ops = { 215 + .apply = pwm_sg2044_apply, 146 216 .get_state = pwm_sg2042_get_state, 147 217 }, 148 218 }; ··· 226 146 { 227 147 .compatible = "sophgo,sg2042-pwm", 228 148 .data = &sg2042_chip_data 149 + }, 150 + { 151 + .compatible = "sophgo,sg2044-pwm", 152 + .data = &sg2044_chip_data 229 153 }, 230 154 { } 231 155 }; ··· 296 212 module_platform_driver(pwm_sg2042_driver); 297 213 298 214 MODULE_AUTHOR("Chen Wang"); 215 + MODULE_AUTHOR("Longbin Li <looong.bin@gmail.com>"); 299 216 MODULE_DESCRIPTION("Sophgo SG2042 PWM driver"); 300 217 MODULE_LICENSE("GPL");