1 // SPDX-License-Identifier: GPL-2.0 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 <jarkko.nikula@linux.intel.com> 9 * Author: Raymond Tan <raymond.tan@intel.com> 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 dev_set_drvdata(dev, chip); 176 return chip; 177 } 178 EXPORT_SYMBOL_GPL(dwc_pwm_alloc); 179 180 MODULE_AUTHOR("Felipe Balbi (Intel)"); 181 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); 182 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); 183 MODULE_DESCRIPTION("DesignWare PWM Controller"); 184 MODULE_LICENSE("GPL"); 185