1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Sophgo SG2042 PWM Controller Driver 4 * 5 * Copyright (C) 2024 Sophgo Technology Inc. 6 * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com> 7 * 8 * Limitations: 9 * - After reset, the output of the PWM channel is always high. 10 * The value of HLPERIOD/PERIOD is 0. 11 * - When HLPERIOD or PERIOD is reconfigured, PWM will start to 12 * output waveforms with the new configuration after completing 13 * the running period. 14 * - When PERIOD and HLPERIOD is set to 0, the PWM wave output will 15 * be stopped and the output is pulled to high. 16 * - SG2044 supports both polarities, SG2042 only normal polarity. 17 * See the datasheet [1] for more details. 18 * [1]:https://github.com/sophgo/sophgo-doc/tree/main/SG2042/TRM 19 */ 20 21 #include <linux/clk.h> 22 #include <linux/err.h> 23 #include <linux/io.h> 24 #include <linux/math64.h> 25 #include <linux/module.h> 26 #include <linux/platform_device.h> 27 #include <linux/pwm.h> 28 #include <linux/reset.h> 29 30 /* 31 * Offset RegisterName 32 * 0x0000 HLPERIOD0 33 * 0x0004 PERIOD0 34 * 0x0008 HLPERIOD1 35 * 0x000C PERIOD1 36 * 0x0010 HLPERIOD2 37 * 0x0014 PERIOD2 38 * 0x0018 HLPERIOD3 39 * 0x001C PERIOD3 40 * Four groups and every group is composed of HLPERIOD & PERIOD 41 */ 42 #define SG2042_PWM_HLPERIOD(chan) ((chan) * 8 + 0) 43 #define SG2042_PWM_PERIOD(chan) ((chan) * 8 + 4) 44 45 #define SG2044_PWM_POLARITY 0x40 46 #define SG2044_PWM_PWMSTART 0x44 47 #define SG2044_PWM_OE 0xd0 48 49 #define SG2042_PWM_CHANNELNUM 4 50 51 /** 52 * struct sg2042_pwm_ddata - private driver data 53 * @base: base address of mapped PWM registers 54 * @clk_rate_hz: rate of base clock in HZ 55 */ 56 struct sg2042_pwm_ddata { 57 void __iomem *base; 58 unsigned long clk_rate_hz; 59 }; 60 61 struct sg2042_chip_data { 62 const struct pwm_ops ops; 63 }; 64 65 /* 66 * period_ticks: PERIOD 67 * hlperiod_ticks: HLPERIOD 68 */ 69 static void pwm_sg2042_config(struct sg2042_pwm_ddata *ddata, unsigned int chan, 70 u32 period_ticks, u32 hlperiod_ticks) 71 { 72 void __iomem *base = ddata->base; 73 74 writel(period_ticks, base + SG2042_PWM_PERIOD(chan)); 75 writel(hlperiod_ticks, base + SG2042_PWM_HLPERIOD(chan)); 76 } 77 78 static void pwm_sg2042_set_dutycycle(struct pwm_chip *chip, struct pwm_device *pwm, 79 const struct pwm_state *state) 80 { 81 struct sg2042_pwm_ddata *ddata = pwmchip_get_drvdata(chip); 82 u32 hlperiod_ticks; 83 u32 period_ticks; 84 85 /* 86 * Duration of High level (duty_cycle) = HLPERIOD x Period_of_input_clk 87 * Duration of One Cycle (period) = PERIOD x Period_of_input_clk 88 */ 89 period_ticks = min(mul_u64_u64_div_u64(ddata->clk_rate_hz, state->period, NSEC_PER_SEC), U32_MAX); 90 hlperiod_ticks = min(mul_u64_u64_div_u64(ddata->clk_rate_hz, state->duty_cycle, NSEC_PER_SEC), U32_MAX); 91 92 dev_dbg(pwmchip_parent(chip), "chan[%u]: ENABLE=%u, PERIOD=%u, HLPERIOD=%u, POLARITY=%u\n", 93 pwm->hwpwm, state->enabled, period_ticks, hlperiod_ticks, state->polarity); 94 95 pwm_sg2042_config(ddata, pwm->hwpwm, period_ticks, hlperiod_ticks); 96 } 97 98 static int pwm_sg2042_apply(struct pwm_chip *chip, struct pwm_device *pwm, 99 const struct pwm_state *state) 100 { 101 struct sg2042_pwm_ddata *ddata = pwmchip_get_drvdata(chip); 102 103 if (state->polarity == PWM_POLARITY_INVERSED) 104 return -EINVAL; 105 106 if (!state->enabled) { 107 pwm_sg2042_config(ddata, pwm->hwpwm, 0, 0); 108 return 0; 109 } 110 111 pwm_sg2042_set_dutycycle(chip, pwm, state); 112 113 return 0; 114 } 115 116 static int pwm_sg2042_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 117 struct pwm_state *state) 118 { 119 struct sg2042_pwm_ddata *ddata = pwmchip_get_drvdata(chip); 120 unsigned int chan = pwm->hwpwm; 121 u32 hlperiod_ticks; 122 u32 period_ticks; 123 124 period_ticks = readl(ddata->base + SG2042_PWM_PERIOD(chan)); 125 hlperiod_ticks = readl(ddata->base + SG2042_PWM_HLPERIOD(chan)); 126 127 if (!period_ticks) { 128 state->enabled = false; 129 return 0; 130 } 131 132 if (hlperiod_ticks > period_ticks) 133 hlperiod_ticks = period_ticks; 134 135 state->enabled = true; 136 state->period = DIV_ROUND_UP_ULL((u64)period_ticks * NSEC_PER_SEC, ddata->clk_rate_hz); 137 state->duty_cycle = DIV_ROUND_UP_ULL((u64)hlperiod_ticks * NSEC_PER_SEC, ddata->clk_rate_hz); 138 state->polarity = PWM_POLARITY_NORMAL; 139 140 return 0; 141 } 142 143 static void pwm_sg2044_set_outputen(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 144 bool enabled) 145 { 146 u32 pwmstart; 147 148 pwmstart = readl(ddata->base + SG2044_PWM_PWMSTART); 149 150 if (enabled) 151 pwmstart |= BIT(pwm->hwpwm); 152 else 153 pwmstart &= ~BIT(pwm->hwpwm); 154 155 writel(pwmstart, ddata->base + SG2044_PWM_PWMSTART); 156 } 157 158 static void pwm_sg2044_set_outputdir(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 159 bool enabled) 160 { 161 u32 pwm_oe; 162 163 pwm_oe = readl(ddata->base + SG2044_PWM_OE); 164 165 if (enabled) 166 pwm_oe |= BIT(pwm->hwpwm); 167 else 168 pwm_oe &= ~BIT(pwm->hwpwm); 169 170 writel(pwm_oe, ddata->base + SG2044_PWM_OE); 171 } 172 173 static void pwm_sg2044_set_polarity(struct sg2042_pwm_ddata *ddata, struct pwm_device *pwm, 174 const struct pwm_state *state) 175 { 176 u32 pwm_polarity; 177 178 pwm_polarity = readl(ddata->base + SG2044_PWM_POLARITY); 179 180 if (state->polarity == PWM_POLARITY_NORMAL) 181 pwm_polarity &= ~BIT(pwm->hwpwm); 182 else 183 pwm_polarity |= BIT(pwm->hwpwm); 184 185 writel(pwm_polarity, ddata->base + SG2044_PWM_POLARITY); 186 } 187 188 static int pwm_sg2044_apply(struct pwm_chip *chip, struct pwm_device *pwm, 189 const struct pwm_state *state) 190 { 191 struct sg2042_pwm_ddata *ddata = pwmchip_get_drvdata(chip); 192 193 pwm_sg2044_set_polarity(ddata, pwm, state); 194 195 pwm_sg2042_set_dutycycle(chip, pwm, state); 196 197 /* 198 * re-enable PWMSTART to refresh the register period 199 */ 200 pwm_sg2044_set_outputen(ddata, pwm, false); 201 202 if (!state->enabled) 203 return 0; 204 205 pwm_sg2044_set_outputdir(ddata, pwm, true); 206 pwm_sg2044_set_outputen(ddata, pwm, true); 207 208 return 0; 209 } 210 211 static const struct sg2042_chip_data sg2042_chip_data = { 212 .ops = { 213 .apply = pwm_sg2042_apply, 214 .get_state = pwm_sg2042_get_state, 215 }, 216 }; 217 218 static const struct sg2042_chip_data sg2044_chip_data = { 219 .ops = { 220 .apply = pwm_sg2044_apply, 221 .get_state = pwm_sg2042_get_state, 222 }, 223 }; 224 225 static const struct of_device_id sg2042_pwm_ids[] = { 226 { 227 .compatible = "sophgo,sg2042-pwm", 228 .data = &sg2042_chip_data 229 }, 230 { 231 .compatible = "sophgo,sg2044-pwm", 232 .data = &sg2044_chip_data 233 }, 234 { } 235 }; 236 MODULE_DEVICE_TABLE(of, sg2042_pwm_ids); 237 238 static int pwm_sg2042_probe(struct platform_device *pdev) 239 { 240 struct device *dev = &pdev->dev; 241 const struct sg2042_chip_data *chip_data; 242 struct sg2042_pwm_ddata *ddata; 243 struct reset_control *rst; 244 struct pwm_chip *chip; 245 struct clk *clk; 246 int ret; 247 248 chip_data = device_get_match_data(dev); 249 if (!chip_data) 250 return -ENODEV; 251 252 chip = devm_pwmchip_alloc(dev, SG2042_PWM_CHANNELNUM, sizeof(*ddata)); 253 if (IS_ERR(chip)) 254 return PTR_ERR(chip); 255 ddata = pwmchip_get_drvdata(chip); 256 257 ddata->base = devm_platform_ioremap_resource(pdev, 0); 258 if (IS_ERR(ddata->base)) 259 return PTR_ERR(ddata->base); 260 261 clk = devm_clk_get_enabled(dev, "apb"); 262 if (IS_ERR(clk)) 263 return dev_err_probe(dev, PTR_ERR(clk), "Failed to get base clk\n"); 264 265 ret = devm_clk_rate_exclusive_get(dev, clk); 266 if (ret) 267 return dev_err_probe(dev, ret, "Failed to get exclusive rate\n"); 268 269 ddata->clk_rate_hz = clk_get_rate(clk); 270 /* period = PERIOD * NSEC_PER_SEC / clk_rate_hz */ 271 if (!ddata->clk_rate_hz || ddata->clk_rate_hz > NSEC_PER_SEC) 272 return dev_err_probe(dev, -EINVAL, 273 "Invalid clock rate: %lu\n", ddata->clk_rate_hz); 274 275 rst = devm_reset_control_get_optional_shared_deasserted(dev, NULL); 276 if (IS_ERR(rst)) 277 return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset\n"); 278 279 chip->ops = &chip_data->ops; 280 chip->atomic = true; 281 282 ret = devm_pwmchip_add(dev, chip); 283 if (ret < 0) 284 return dev_err_probe(dev, ret, "Failed to register PWM chip\n"); 285 286 return 0; 287 } 288 289 static struct platform_driver pwm_sg2042_driver = { 290 .driver = { 291 .name = "sg2042-pwm", 292 .of_match_table = sg2042_pwm_ids, 293 }, 294 .probe = pwm_sg2042_probe, 295 }; 296 module_platform_driver(pwm_sg2042_driver); 297 298 MODULE_AUTHOR("Chen Wang"); 299 MODULE_AUTHOR("Longbin Li <looong.bin@gmail.com>"); 300 MODULE_DESCRIPTION("Sophgo SG2042 PWM driver"); 301 MODULE_LICENSE("GPL"); 302