| 1 | |
| 2 | |
| 3 | * DesignWare PWM Controller driver core
|
| 4 | *
|
| 5 | * Copyright (C) 2018-2020 Intel Corporation
|
| 6 | *
|
| 7 | * Author: Felipe Balbi (Intel)
|
| 8 | * Author: Jarkko Nikula <[email protected]>
|
| 9 | * Author: Raymond Tan <[email protected]>
|
| 10 |
|
| 11 |
|
| 12 | #define DEFAULT_SYMBOL_NAMESPACE "dwc_pwm"
|
| 13 |
|
| 14 | #include <linux/bitops.h>
|
| 15 | #include <linux/export.h>
|
| 16 | #include <linux/kernel.h>
|
| 17 | #include <linux/module.h>
|
| 18 | #include <linux/pci.h>
|
| 19 | #include <linux/pm_runtime.h>
|
| 20 | #include <linux/pwm.h>
|
| 21 |
|
| 22 | #include "pwm-dwc.h"
|
| 23 |
|
| 24 | static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
|
| 25 | {
|
| 26 | u32 reg;
|
| 27 |
|
| 28 | reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm));
|
| 29 |
|
| 30 | if (enabled)
|
| 31 | reg |= DWC_TIM_CTRL_EN;
|
| 32 | else
|
| 33 | reg &= ~DWC_TIM_CTRL_EN;
|
| 34 |
|
| 35 | dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm));
|
| 36 | }
|
| 37 |
|
| 38 | static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
|
| 39 | struct pwm_device *pwm,
|
| 40 | const struct pwm_state *state)
|
| 41 | {
|
| 42 | u64 tmp;
|
| 43 | u32 ctrl;
|
| 44 | u32 high;
|
| 45 | u32 low;
|
| 46 |
|
| 47 | |
| 48 | * Calculate width of low and high period in terms of input clock
|
| 49 | * periods and check are the result within HW limits between 1 and
|
| 50 | * 2^32 periods.
|
| 51 |
|
| 52 | tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
|
| 53 | if (tmp < 1 || tmp > (1ULL << 32))
|
| 54 | return -ERANGE;
|
| 55 | low = tmp - 1;
|
| 56 |
|
| 57 | tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
|
| 58 | dwc->clk_ns);
|
| 59 | if (tmp < 1 || tmp > (1ULL << 32))
|
| 60 | return -ERANGE;
|
| 61 | high = tmp - 1;
|
| 62 |
|
| 63 | |
| 64 | * Specification says timer usage flow is to disable timer, then
|
| 65 | * program it followed by enable. It also says Load Count is loaded
|
| 66 | * into timer after it is enabled - either after a disable or
|
| 67 | * a reset. Based on measurements it happens also without disable
|
| 68 | * whenever Load Count is updated. But follow the specification.
|
| 69 |
|
| 70 | __dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
| 71 |
|
| 72 | |
| 73 | * Write Load Count and Load Count 2 registers. Former defines the
|
| 74 | * width of low period and latter the width of high period in terms
|
| 75 | * multiple of input clock periods:
|
| 76 | * Width = ((Count + 1) * input clock period).
|
| 77 |
|
| 78 | dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm));
|
| 79 | dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
| 80 |
|
| 81 | |
| 82 | * Set user-defined mode, timer reloads from Load Count registers
|
| 83 | * when it counts down to 0.
|
| 84 | * Set PWM mode, it makes output to toggle and width of low and high
|
| 85 | * periods are set by Load Count registers.
|
| 86 |
|
| 87 | ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM;
|
| 88 | dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm));
|
| 89 |
|
| 90 | |
| 91 | * Enable timer. Output starts from low period.
|
| 92 |
|
| 93 | __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled);
|
| 94 |
|
| 95 | return 0;
|
| 96 | }
|
| 97 |
|
| 98 | static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
| 99 | const struct pwm_state *state)
|
| 100 | {
|
| 101 | struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
| 102 |
|
| 103 | if (state->polarity != PWM_POLARITY_INVERSED)
|
| 104 | return -EINVAL;
|
| 105 |
|
| 106 | if (state->enabled) {
|
| 107 | if (!pwm->state.enabled)
|
| 108 | pm_runtime_get_sync(pwmchip_parent(chip));
|
| 109 | return __dwc_pwm_configure_timer(dwc, pwm, state);
|
| 110 | } else {
|
| 111 | if (pwm->state.enabled) {
|
| 112 | __dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
| 113 | pm_runtime_put_sync(pwmchip_parent(chip));
|
| 114 | }
|
| 115 | }
|
| 116 |
|
| 117 | return 0;
|
| 118 | }
|
| 119 |
|
| 120 | static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
| 121 | struct pwm_state *state)
|
| 122 | {
|
| 123 | struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
| 124 | u64 duty, period;
|
| 125 | u32 ctrl, ld, ld2;
|
| 126 |
|
| 127 | pm_runtime_get_sync(pwmchip_parent(chip));
|
| 128 |
|
| 129 | ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm));
|
| 130 | ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
|
| 131 | ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
| 132 |
|
| 133 | state->enabled = !!(ctrl & DWC_TIM_CTRL_EN);
|
| 134 |
|
| 135 | |
| 136 | * If we're not in PWM, technically the output is a 50-50
|
| 137 | * based on the timer load-count only.
|
| 138 |
|
| 139 | if (ctrl & DWC_TIM_CTRL_PWM) {
|
| 140 | duty = (ld + 1) * dwc->clk_ns;
|
| 141 | period = (ld2 + 1) * dwc->clk_ns;
|
| 142 | period += duty;
|
| 143 | } else {
|
| 144 | duty = (ld + 1) * dwc->clk_ns;
|
| 145 | period = duty * 2;
|
| 146 | }
|
| 147 |
|
| 148 | state->polarity = PWM_POLARITY_INVERSED;
|
| 149 | state->period = period;
|
| 150 | state->duty_cycle = duty;
|
| 151 |
|
| 152 | pm_runtime_put_sync(pwmchip_parent(chip));
|
| 153 |
|
| 154 | return 0;
|
| 155 | }
|
| 156 |
|
| 157 | static const struct pwm_ops dwc_pwm_ops = {
|
| 158 | .apply = dwc_pwm_apply,
|
| 159 | .get_state = dwc_pwm_get_state,
|
| 160 | };
|
| 161 |
|
| 162 | struct pwm_chip *dwc_pwm_alloc(struct device *dev)
|
| 163 | {
|
| 164 | struct pwm_chip *chip;
|
| 165 | struct dwc_pwm *dwc;
|
| 166 |
|
| 167 | chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(*dwc));
|
| 168 | if (IS_ERR(chip))
|
| 169 | return chip;
|
| 170 | dwc = to_dwc_pwm(chip);
|
| 171 |
|
| 172 | dwc->clk_ns = 10;
|
| 173 | chip->ops = &dwc_pwm_ops;
|
| 174 |
|
| 175 | return chip;
|
| 176 | }
|
| 177 | EXPORT_SYMBOL_GPL(dwc_pwm_alloc);
|
| 178 |
|
| 179 | MODULE_AUTHOR("Felipe Balbi (Intel)");
|
| 180 | MODULE_AUTHOR("Jarkko Nikula <[email protected]>");
|
| 181 | MODULE_AUTHOR("Raymond Tan <[email protected]>");
|
| 182 | MODULE_DESCRIPTION("DesignWare PWM Controller");
|
| 183 | MODULE_LICENSE("GPL");
|