1 /* 2 * Copyright (C) 2014 Free Electrons 3 * Copyright (C) 2014 Atmel 4 * 5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/clk.h> 21 #include <linux/delay.h> 22 #include <linux/mfd/atmel-hlcdc.h> 23 #include <linux/module.h> 24 #include <linux/platform_device.h> 25 #include <linux/pwm.h> 26 #include <linux/regmap.h> 27 28 #define ATMEL_HLCDC_PWMCVAL_MASK GENMASK(15, 8) 29 #define ATMEL_HLCDC_PWMCVAL(x) (((x) << 8) & ATMEL_HLCDC_PWMCVAL_MASK) 30 #define ATMEL_HLCDC_PWMPOL BIT(4) 31 #define ATMEL_HLCDC_PWMPS_MASK GENMASK(2, 0) 32 #define ATMEL_HLCDC_PWMPS_MAX 0x6 33 #define ATMEL_HLCDC_PWMPS(x) ((x) & ATMEL_HLCDC_PWMPS_MASK) 34 35 struct atmel_hlcdc_pwm_errata { 36 bool slow_clk_erratum; 37 bool div1_clk_erratum; 38 }; 39 40 struct atmel_hlcdc_pwm { 41 struct pwm_chip chip; 42 struct atmel_hlcdc *hlcdc; 43 struct clk *cur_clk; 44 const struct atmel_hlcdc_pwm_errata *errata; 45 }; 46 47 static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) 48 { 49 return container_of(chip, struct atmel_hlcdc_pwm, chip); 50 } 51 52 static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, 53 struct pwm_state *state) 54 { 55 struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); 56 struct atmel_hlcdc *hlcdc = chip->hlcdc; 57 unsigned int status; 58 int ret; 59 60 if (state->enabled) { 61 struct clk *new_clk = hlcdc->slow_clk; 62 u64 pwmcval = state->duty_cycle * 256; 63 unsigned long clk_freq; 64 u64 clk_period_ns; 65 u32 pwmcfg; 66 int pres; 67 68 if (!chip->errata || !chip->errata->slow_clk_erratum) { 69 clk_freq = clk_get_rate(new_clk); 70 if (!clk_freq) 71 return -EINVAL; 72 73 clk_period_ns = (u64)NSEC_PER_SEC * 256; 74 do_div(clk_period_ns, clk_freq); 75 } 76 77 /* Errata: cannot use slow clk on some IP revisions */ 78 if ((chip->errata && chip->errata->slow_clk_erratum) || 79 clk_period_ns > state->period) { 80 new_clk = hlcdc->sys_clk; 81 clk_freq = clk_get_rate(new_clk); 82 if (!clk_freq) 83 return -EINVAL; 84 85 clk_period_ns = (u64)NSEC_PER_SEC * 256; 86 do_div(clk_period_ns, clk_freq); 87 } 88 89 for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) { 90 /* Errata: cannot divide by 1 on some IP revisions */ 91 if (!pres && chip->errata && 92 chip->errata->div1_clk_erratum) 93 continue; 94 95 if ((clk_period_ns << pres) >= state->period) 96 break; 97 } 98 99 if (pres > ATMEL_HLCDC_PWMPS_MAX) 100 return -EINVAL; 101 102 pwmcfg = ATMEL_HLCDC_PWMPS(pres); 103 104 if (new_clk != chip->cur_clk) { 105 u32 gencfg = 0; 106 int ret; 107 108 ret = clk_prepare_enable(new_clk); 109 if (ret) 110 return ret; 111 112 clk_disable_unprepare(chip->cur_clk); 113 chip->cur_clk = new_clk; 114 115 if (new_clk == hlcdc->sys_clk) 116 gencfg = ATMEL_HLCDC_CLKPWMSEL; 117 118 ret = regmap_update_bits(hlcdc->regmap, 119 ATMEL_HLCDC_CFG(0), 120 ATMEL_HLCDC_CLKPWMSEL, 121 gencfg); 122 if (ret) 123 return ret; 124 } 125 126 do_div(pwmcval, state->period); 127 128 /* 129 * The PWM duty cycle is configurable from 0/256 to 255/256 of 130 * the period cycle. Hence we can't set a duty cycle occupying 131 * the whole period cycle if we're asked to. 132 * Set it to 255 if pwmcval is greater than 256. 133 */ 134 if (pwmcval > 255) 135 pwmcval = 255; 136 137 pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval); 138 139 if (state->polarity == PWM_POLARITY_NORMAL) 140 pwmcfg |= ATMEL_HLCDC_PWMPOL; 141 142 ret = regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6), 143 ATMEL_HLCDC_PWMCVAL_MASK | 144 ATMEL_HLCDC_PWMPS_MASK | 145 ATMEL_HLCDC_PWMPOL, 146 pwmcfg); 147 if (ret) 148 return ret; 149 150 ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, 151 ATMEL_HLCDC_PWM); 152 if (ret) 153 return ret; 154 155 ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR, 156 status, 157 status & ATMEL_HLCDC_PWM, 158 10, 0); 159 if (ret) 160 return ret; 161 } else { 162 ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, 163 ATMEL_HLCDC_PWM); 164 if (ret) 165 return ret; 166 167 ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR, 168 status, 169 !(status & ATMEL_HLCDC_PWM), 170 10, 0); 171 if (ret) 172 return ret; 173 174 clk_disable_unprepare(chip->cur_clk); 175 chip->cur_clk = NULL; 176 } 177 178 return 0; 179 } 180 181 static const struct pwm_ops atmel_hlcdc_pwm_ops = { 182 .apply = atmel_hlcdc_pwm_apply, 183 .owner = THIS_MODULE, 184 }; 185 186 static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = { 187 .slow_clk_erratum = true, 188 }; 189 190 static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { 191 .div1_clk_erratum = true, 192 }; 193 194 #ifdef CONFIG_PM_SLEEP 195 static int atmel_hlcdc_pwm_suspend(struct device *dev) 196 { 197 struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); 198 199 /* Keep the periph clock enabled if the PWM is still running. */ 200 if (pwm_is_enabled(&chip->chip.pwms[0])) 201 clk_disable_unprepare(chip->hlcdc->periph_clk); 202 203 return 0; 204 } 205 206 static int atmel_hlcdc_pwm_resume(struct device *dev) 207 { 208 struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); 209 struct pwm_state state; 210 int ret; 211 212 pwm_get_state(&chip->chip.pwms[0], &state); 213 214 /* Re-enable the periph clock it was stopped during suspend. */ 215 if (!state.enabled) { 216 ret = clk_prepare_enable(chip->hlcdc->periph_clk); 217 if (ret) 218 return ret; 219 } 220 221 return atmel_hlcdc_pwm_apply(&chip->chip, &chip->chip.pwms[0], &state); 222 } 223 #endif 224 225 static SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops, 226 atmel_hlcdc_pwm_suspend, atmel_hlcdc_pwm_resume); 227 228 static const struct of_device_id atmel_hlcdc_dt_ids[] = { 229 { 230 .compatible = "atmel,at91sam9n12-hlcdc", 231 /* 9n12 has same errata as 9x5 HLCDC PWM */ 232 .data = &atmel_hlcdc_pwm_at91sam9x5_errata, 233 }, 234 { 235 .compatible = "atmel,at91sam9x5-hlcdc", 236 .data = &atmel_hlcdc_pwm_at91sam9x5_errata, 237 }, 238 { 239 .compatible = "atmel,sama5d2-hlcdc", 240 }, 241 { 242 .compatible = "atmel,sama5d3-hlcdc", 243 .data = &atmel_hlcdc_pwm_sama5d3_errata, 244 }, 245 { 246 .compatible = "atmel,sama5d4-hlcdc", 247 .data = &atmel_hlcdc_pwm_sama5d3_errata, 248 }, 249 { /* sentinel */ }, 250 }; 251 MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids); 252 253 static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) 254 { 255 const struct of_device_id *match; 256 struct device *dev = &pdev->dev; 257 struct atmel_hlcdc_pwm *chip; 258 struct atmel_hlcdc *hlcdc; 259 int ret; 260 261 hlcdc = dev_get_drvdata(dev->parent); 262 263 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 264 if (!chip) 265 return -ENOMEM; 266 267 ret = clk_prepare_enable(hlcdc->periph_clk); 268 if (ret) 269 return ret; 270 271 match = of_match_node(atmel_hlcdc_dt_ids, dev->parent->of_node); 272 if (match) 273 chip->errata = match->data; 274 275 chip->hlcdc = hlcdc; 276 chip->chip.ops = &atmel_hlcdc_pwm_ops; 277 chip->chip.dev = dev; 278 chip->chip.base = -1; 279 chip->chip.npwm = 1; 280 chip->chip.of_xlate = of_pwm_xlate_with_flags; 281 chip->chip.of_pwm_n_cells = 3; 282 283 ret = pwmchip_add_with_polarity(&chip->chip, PWM_POLARITY_INVERSED); 284 if (ret) { 285 clk_disable_unprepare(hlcdc->periph_clk); 286 return ret; 287 } 288 289 platform_set_drvdata(pdev, chip); 290 291 return 0; 292 } 293 294 static int atmel_hlcdc_pwm_remove(struct platform_device *pdev) 295 { 296 struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev); 297 int ret; 298 299 ret = pwmchip_remove(&chip->chip); 300 if (ret) 301 return ret; 302 303 clk_disable_unprepare(chip->hlcdc->periph_clk); 304 305 return 0; 306 } 307 308 static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = { 309 { .compatible = "atmel,hlcdc-pwm" }, 310 { /* sentinel */ }, 311 }; 312 313 static struct platform_driver atmel_hlcdc_pwm_driver = { 314 .driver = { 315 .name = "atmel-hlcdc-pwm", 316 .of_match_table = atmel_hlcdc_pwm_dt_ids, 317 .pm = &atmel_hlcdc_pwm_pm_ops, 318 }, 319 .probe = atmel_hlcdc_pwm_probe, 320 .remove = atmel_hlcdc_pwm_remove, 321 }; 322 module_platform_driver(atmel_hlcdc_pwm_driver); 323 324 MODULE_ALIAS("platform:atmel-hlcdc-pwm"); 325 MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>"); 326 MODULE_DESCRIPTION("Atmel HLCDC PWM driver"); 327 MODULE_LICENSE("GPL v2"); 328