537 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) Overkiz SAS 20124 *5 * Author: Boris BREZILLON <b.brezillon@overkiz.com>6 */7 8#include <linux/module.h>9#include <linux/init.h>10#include <linux/clocksource.h>11#include <linux/clockchips.h>12#include <linux/interrupt.h>13#include <linux/irq.h>14 15#include <linux/clk.h>16#include <linux/err.h>17#include <linux/ioport.h>18#include <linux/io.h>19#include <linux/mfd/syscon.h>20#include <linux/platform_device.h>21#include <linux/pwm.h>22#include <linux/of.h>23#include <linux/regmap.h>24#include <linux/slab.h>25#include <soc/at91/atmel_tcb.h>26 27#define NPWM 228 29#define ATMEL_TC_ACMR_MASK (ATMEL_TC_ACPA | ATMEL_TC_ACPC | \30 ATMEL_TC_AEEVT | ATMEL_TC_ASWTRG)31 32#define ATMEL_TC_BCMR_MASK (ATMEL_TC_BCPB | ATMEL_TC_BCPC | \33 ATMEL_TC_BEEVT | ATMEL_TC_BSWTRG)34 35struct atmel_tcb_pwm_device {36 unsigned div; /* PWM clock divider */37 unsigned duty; /* PWM duty expressed in clk cycles */38 unsigned period; /* PWM period expressed in clk cycles */39};40 41struct atmel_tcb_channel {42 u32 enabled;43 u32 cmr;44 u32 ra;45 u32 rb;46 u32 rc;47};48 49struct atmel_tcb_pwm_chip {50 spinlock_t lock;51 u8 channel;52 u8 width;53 struct regmap *regmap;54 struct clk *clk;55 struct clk *gclk;56 struct clk *slow_clk;57 struct atmel_tcb_pwm_device pwms[NPWM];58 struct atmel_tcb_channel bkup;59};60 61static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128, 0, };62 63static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip)64{65 return pwmchip_get_drvdata(chip);66}67 68static int atmel_tcb_pwm_request(struct pwm_chip *chip,69 struct pwm_device *pwm)70{71 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);72 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm];73 unsigned cmr;74 int ret;75 76 ret = clk_prepare_enable(tcbpwmc->clk);77 if (ret)78 return ret;79 80 tcbpwm->duty = 0;81 tcbpwm->period = 0;82 tcbpwm->div = 0;83 84 guard(spinlock)(&tcbpwmc->lock);85 86 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr);87 /*88 * Get init config from Timer Counter registers if89 * Timer Counter is already configured as a PWM generator.90 */91 if (cmr & ATMEL_TC_WAVE) {92 if (pwm->hwpwm == 0)93 regmap_read(tcbpwmc->regmap,94 ATMEL_TC_REG(tcbpwmc->channel, RA),95 &tcbpwm->duty);96 else97 regmap_read(tcbpwmc->regmap,98 ATMEL_TC_REG(tcbpwmc->channel, RB),99 &tcbpwm->duty);100 101 tcbpwm->div = cmr & ATMEL_TC_TCCLKS;102 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC),103 &tcbpwm->period);104 cmr &= (ATMEL_TC_TCCLKS | ATMEL_TC_ACMR_MASK |105 ATMEL_TC_BCMR_MASK);106 } else107 cmr = 0;108 109 cmr |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;110 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr);111 112 return 0;113}114 115static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)116{117 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);118 119 clk_disable_unprepare(tcbpwmc->clk);120}121 122static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm,123 enum pwm_polarity polarity)124{125 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);126 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm];127 unsigned cmr;128 129 /*130 * If duty is 0 the timer will be stopped and we have to131 * configure the output correctly on software trigger:132 * - set output to high if PWM_POLARITY_INVERSED133 * - set output to low if PWM_POLARITY_NORMAL134 *135 * This is why we're reverting polarity in this case.136 */137 if (tcbpwm->duty == 0)138 polarity = !polarity;139 140 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr);141 142 /* flush old setting and set the new one */143 if (pwm->hwpwm == 0) {144 cmr &= ~ATMEL_TC_ACMR_MASK;145 if (polarity == PWM_POLARITY_INVERSED)146 cmr |= ATMEL_TC_ASWTRG_CLEAR;147 else148 cmr |= ATMEL_TC_ASWTRG_SET;149 } else {150 cmr &= ~ATMEL_TC_BCMR_MASK;151 if (polarity == PWM_POLARITY_INVERSED)152 cmr |= ATMEL_TC_BSWTRG_CLEAR;153 else154 cmr |= ATMEL_TC_BSWTRG_SET;155 }156 157 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr);158 159 /*160 * Use software trigger to apply the new setting.161 * If both PWM devices in this group are disabled we stop the clock.162 */163 if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) {164 regmap_write(tcbpwmc->regmap,165 ATMEL_TC_REG(tcbpwmc->channel, CCR),166 ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS);167 tcbpwmc->bkup.enabled = 1;168 } else {169 regmap_write(tcbpwmc->regmap,170 ATMEL_TC_REG(tcbpwmc->channel, CCR),171 ATMEL_TC_SWTRG);172 tcbpwmc->bkup.enabled = 0;173 }174}175 176static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm,177 enum pwm_polarity polarity)178{179 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);180 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm];181 u32 cmr;182 183 /*184 * If duty is 0 the timer will be stopped and we have to185 * configure the output correctly on software trigger:186 * - set output to high if PWM_POLARITY_INVERSED187 * - set output to low if PWM_POLARITY_NORMAL188 *189 * This is why we're reverting polarity in this case.190 */191 if (tcbpwm->duty == 0)192 polarity = !polarity;193 194 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr);195 196 /* flush old setting and set the new one */197 cmr &= ~ATMEL_TC_TCCLKS;198 199 if (pwm->hwpwm == 0) {200 cmr &= ~ATMEL_TC_ACMR_MASK;201 202 /* Set CMR flags according to given polarity */203 if (polarity == PWM_POLARITY_INVERSED)204 cmr |= ATMEL_TC_ASWTRG_CLEAR;205 else206 cmr |= ATMEL_TC_ASWTRG_SET;207 } else {208 cmr &= ~ATMEL_TC_BCMR_MASK;209 if (polarity == PWM_POLARITY_INVERSED)210 cmr |= ATMEL_TC_BSWTRG_CLEAR;211 else212 cmr |= ATMEL_TC_BSWTRG_SET;213 }214 215 /*216 * If duty is 0 or equal to period there's no need to register217 * a specific action on RA/RB and RC compare.218 * The output will be configured on software trigger and keep219 * this config till next config call.220 */221 if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) {222 if (pwm->hwpwm == 0) {223 if (polarity == PWM_POLARITY_INVERSED)224 cmr |= ATMEL_TC_ACPA_SET | ATMEL_TC_ACPC_CLEAR;225 else226 cmr |= ATMEL_TC_ACPA_CLEAR | ATMEL_TC_ACPC_SET;227 } else {228 if (polarity == PWM_POLARITY_INVERSED)229 cmr |= ATMEL_TC_BCPB_SET | ATMEL_TC_BCPC_CLEAR;230 else231 cmr |= ATMEL_TC_BCPB_CLEAR | ATMEL_TC_BCPC_SET;232 }233 }234 235 cmr |= (tcbpwm->div & ATMEL_TC_TCCLKS);236 237 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr);238 239 if (pwm->hwpwm == 0)240 regmap_write(tcbpwmc->regmap,241 ATMEL_TC_REG(tcbpwmc->channel, RA),242 tcbpwm->duty);243 else244 regmap_write(tcbpwmc->regmap,245 ATMEL_TC_REG(tcbpwmc->channel, RB),246 tcbpwm->duty);247 248 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC),249 tcbpwm->period);250 251 /* Use software trigger to apply the new setting */252 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CCR),253 ATMEL_TC_SWTRG | ATMEL_TC_CLKEN);254 tcbpwmc->bkup.enabled = 1;255 return 0;256}257 258static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,259 int duty_ns, int period_ns)260{261 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);262 struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm];263 /* companion PWM sharing register values period and div */264 struct atmel_tcb_pwm_device *atcbpwm = &tcbpwmc->pwms[pwm->hwpwm ^ 1];265 int i = 0;266 int slowclk = 0;267 unsigned period;268 unsigned duty;269 unsigned rate = clk_get_rate(tcbpwmc->clk);270 unsigned long long min;271 unsigned long long max;272 273 /*274 * Find best clk divisor:275 * the smallest divisor which can fulfill the period_ns requirements.276 * If there is a gclk, the first divisor is actually the gclk selector277 */278 if (tcbpwmc->gclk)279 i = 1;280 for (; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) {281 if (atmel_tcb_divisors[i] == 0) {282 slowclk = i;283 continue;284 }285 min = div_u64((u64)NSEC_PER_SEC * atmel_tcb_divisors[i], rate);286 max = min << tcbpwmc->width;287 if (max >= period_ns)288 break;289 }290 291 /*292 * If none of the divisor are small enough to represent period_ns293 * take slow clock (32KHz).294 */295 if (i == ARRAY_SIZE(atmel_tcb_divisors)) {296 i = slowclk;297 rate = clk_get_rate(tcbpwmc->slow_clk);298 min = div_u64(NSEC_PER_SEC, rate);299 max = min << tcbpwmc->width;300 301 /* If period is too big return ERANGE error */302 if (max < period_ns)303 return -ERANGE;304 }305 306 duty = div_u64(duty_ns, min);307 period = div_u64(period_ns, min);308 309 /*310 * PWM devices provided by the TCB driver are grouped by 2.311 * PWM devices in a given group must be configured with the312 * same period_ns.313 *314 * We're checking the period value of the second PWM device315 * in this group before applying the new config.316 */317 if ((atcbpwm->duty > 0 && atcbpwm->duty != atcbpwm->period) &&318 (atcbpwm->div != i || atcbpwm->period != period)) {319 dev_err(pwmchip_parent(chip),320 "failed to configure period_ns: PWM group already configured with a different value\n");321 return -EINVAL;322 }323 324 tcbpwm->period = period;325 tcbpwm->div = i;326 tcbpwm->duty = duty;327 328 return 0;329}330 331static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,332 const struct pwm_state *state)333{334 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);335 int duty_cycle, period;336 int ret;337 338 guard(spinlock)(&tcbpwmc->lock);339 340 if (!state->enabled) {341 atmel_tcb_pwm_disable(chip, pwm, state->polarity);342 return 0;343 }344 345 period = state->period < INT_MAX ? state->period : INT_MAX;346 duty_cycle = state->duty_cycle < INT_MAX ? state->duty_cycle : INT_MAX;347 348 ret = atmel_tcb_pwm_config(chip, pwm, duty_cycle, period);349 if (ret)350 return ret;351 352 return atmel_tcb_pwm_enable(chip, pwm, state->polarity);353}354 355static const struct pwm_ops atmel_tcb_pwm_ops = {356 .request = atmel_tcb_pwm_request,357 .free = atmel_tcb_pwm_free,358 .apply = atmel_tcb_pwm_apply,359};360 361static struct atmel_tcb_config tcb_rm9200_config = {362 .counter_width = 16,363};364 365static struct atmel_tcb_config tcb_sam9x5_config = {366 .counter_width = 32,367};368 369static struct atmel_tcb_config tcb_sama5d2_config = {370 .counter_width = 32,371 .has_gclk = 1,372};373 374static const struct of_device_id atmel_tcb_of_match[] = {375 { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },376 { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },377 { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },378 { /* sentinel */ }379};380 381static int atmel_tcb_pwm_probe(struct platform_device *pdev)382{383 struct pwm_chip *chip;384 const struct of_device_id *match;385 struct atmel_tcb_pwm_chip *tcbpwmc;386 const struct atmel_tcb_config *config;387 struct device_node *np = pdev->dev.of_node;388 char clk_name[] = "t0_clk";389 int err;390 int channel;391 392 chip = devm_pwmchip_alloc(&pdev->dev, NPWM, sizeof(*tcbpwmc));393 if (IS_ERR(chip))394 return PTR_ERR(chip);395 tcbpwmc = to_tcb_chip(chip);396 397 err = of_property_read_u32(np, "reg", &channel);398 if (err < 0) {399 dev_err(&pdev->dev,400 "failed to get Timer Counter Block channel from device tree (error: %d)\n",401 err);402 return err;403 }404 405 tcbpwmc->regmap = syscon_node_to_regmap(np->parent);406 if (IS_ERR(tcbpwmc->regmap))407 return PTR_ERR(tcbpwmc->regmap);408 409 tcbpwmc->slow_clk = of_clk_get_by_name(np->parent, "slow_clk");410 if (IS_ERR(tcbpwmc->slow_clk))411 return PTR_ERR(tcbpwmc->slow_clk);412 413 clk_name[1] += channel;414 tcbpwmc->clk = of_clk_get_by_name(np->parent, clk_name);415 if (IS_ERR(tcbpwmc->clk))416 tcbpwmc->clk = of_clk_get_by_name(np->parent, "t0_clk");417 if (IS_ERR(tcbpwmc->clk)) {418 err = PTR_ERR(tcbpwmc->clk);419 goto err_slow_clk;420 }421 422 match = of_match_node(atmel_tcb_of_match, np->parent);423 config = match->data;424 425 if (config->has_gclk) {426 tcbpwmc->gclk = of_clk_get_by_name(np->parent, "gclk");427 if (IS_ERR(tcbpwmc->gclk)) {428 err = PTR_ERR(tcbpwmc->gclk);429 goto err_clk;430 }431 }432 433 chip->ops = &atmel_tcb_pwm_ops;434 tcbpwmc->channel = channel;435 tcbpwmc->width = config->counter_width;436 437 err = clk_prepare_enable(tcbpwmc->slow_clk);438 if (err)439 goto err_gclk;440 441 spin_lock_init(&tcbpwmc->lock);442 443 err = pwmchip_add(chip);444 if (err < 0)445 goto err_disable_clk;446 447 platform_set_drvdata(pdev, chip);448 449 return 0;450 451err_disable_clk:452 clk_disable_unprepare(tcbpwmc->slow_clk);453 454err_gclk:455 clk_put(tcbpwmc->gclk);456 457err_clk:458 clk_put(tcbpwmc->clk);459 460err_slow_clk:461 clk_put(tcbpwmc->slow_clk);462 463 return err;464}465 466static void atmel_tcb_pwm_remove(struct platform_device *pdev)467{468 struct pwm_chip *chip = platform_get_drvdata(pdev);469 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);470 471 pwmchip_remove(chip);472 473 clk_disable_unprepare(tcbpwmc->slow_clk);474 clk_put(tcbpwmc->gclk);475 clk_put(tcbpwmc->clk);476 clk_put(tcbpwmc->slow_clk);477}478 479static const struct of_device_id atmel_tcb_pwm_dt_ids[] = {480 { .compatible = "atmel,tcb-pwm", },481 { /* sentinel */ }482};483MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);484 485static int atmel_tcb_pwm_suspend(struct device *dev)486{487 struct pwm_chip *chip = dev_get_drvdata(dev);488 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);489 struct atmel_tcb_channel *chan = &tcbpwmc->bkup;490 unsigned int channel = tcbpwmc->channel;491 492 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, CMR), &chan->cmr);493 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RA), &chan->ra);494 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RB), &chan->rb);495 regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(channel, RC), &chan->rc);496 497 return 0;498}499 500static int atmel_tcb_pwm_resume(struct device *dev)501{502 struct pwm_chip *chip = dev_get_drvdata(dev);503 struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);504 struct atmel_tcb_channel *chan = &tcbpwmc->bkup;505 unsigned int channel = tcbpwmc->channel;506 507 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, CMR), chan->cmr);508 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RA), chan->ra);509 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RB), chan->rb);510 regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(channel, RC), chan->rc);511 512 if (chan->enabled)513 regmap_write(tcbpwmc->regmap,514 ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,515 ATMEL_TC_REG(channel, CCR));516 517 return 0;518}519 520static DEFINE_SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend,521 atmel_tcb_pwm_resume);522 523static struct platform_driver atmel_tcb_pwm_driver = {524 .driver = {525 .name = "atmel-tcb-pwm",526 .of_match_table = atmel_tcb_pwm_dt_ids,527 .pm = pm_ptr(&atmel_tcb_pwm_pm_ops),528 },529 .probe = atmel_tcb_pwm_probe,530 .remove = atmel_tcb_pwm_remove,531};532module_platform_driver(atmel_tcb_pwm_driver);533 534MODULE_AUTHOR("Boris BREZILLON <b.brezillon@overkiz.com>");535MODULE_DESCRIPTION("Atmel Timer Counter Pulse Width Modulation Driver");536MODULE_LICENSE("GPL v2");537