/* * ST Microelectronics SPEAr Pulse Width Modulator driver * * Copyright (C) 2012 ST Microelectronics * Shiraz Hashim <shiraz.linux.kernel@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied.
*/
/* * Find pv, dc and prescale to suit duty_ns and period_ns. This is done * according to formulas described below: * * period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE * * PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1)) * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
*/
clk_rate = clk_get_rate(pc->clk); while (1) {
div = 1000000000;
div *= 1 + prescale;
val = clk_rate * period_ns;
pv = div64_u64(val, div);
val = clk_rate * duty_ns;
dc = div64_u64(val, div);
/* if duty_ns and period_ns are not achievable then return */ if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY) return -EINVAL;
/* * if pv and dc have crossed their upper limit, then increase * prescale and recalculate pv and dc.
*/ if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) { if (++prescale > PWMCR_MAX_PRESCALE) return -EINVAL; continue;
} break;
}
/* * NOTE: the clock to PWM has to be enabled first before writing to the * registers.
*/
ret = clk_enable(pc->clk); if (ret) return ret;
chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM, sizeof(*pc)); if (IS_ERR(chip)) return PTR_ERR(chip);
pc = to_spear_pwm_chip(chip);
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio_base)) return PTR_ERR(pc->mmio_base);
pc->clk = devm_clk_get_prepared(&pdev->dev, NULL); if (IS_ERR(pc->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), "Failed to get clock\n");
chip->ops = &spear_pwm_ops;
if (of_device_is_compatible(np, "st,spear1340-pwm")) {
ret = clk_enable(pc->clk); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to enable clk\n");
/* * Following enables PWM chip, channels would still be * enabled individually through their control register
*/
val = readl_relaxed(pc->mmio_base + PWMMCR);
val |= PWMMCR_PWM_ENABLE;
writel_relaxed(val, pc->mmio_base + PWMMCR);
clk_disable(pc->clk);
}
ret = devm_pwmchip_add(&pdev->dev, chip); if (ret < 0) return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.