Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pwm: dwc: split pci out of core driver

Moving towards adding non-pci support for the driver, move the pci
parts out of the core into their own module. This is partly due to
the module_driver() code only being allowed once in a module and also
to avoid a number of #ifdef if we build a single file in a system
without pci support.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Link: https://lore.kernel.org/r/20230907161242.67190-2-ben.dooks@codethink.co.uk
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>

authored by

Ben Dooks and committed by
Thierry Reding
721ee188 6dbf23f5

+252 -194
+12 -2
drivers/pwm/Kconfig
··· 186 186 PWM driver for exposing a PWM attached to the ChromeOS Embedded 187 187 Controller. 188 188 189 + config PWM_DWC_CORE 190 + tristate 191 + depends on HAS_IOMEM 192 + help 193 + PWM driver for Synopsys DWC PWM Controller. 194 + 195 + To compile this driver as a module, build the dependecies as 196 + modules, this will be called pwm-dwc-core. 197 + 189 198 config PWM_DWC 190 - tristate "DesignWare PWM Controller" 191 - depends on PCI 199 + tristate "DesignWare PWM Controller (PCI bus)" 200 + depends on HAS_IOMEM && PCI 201 + select PWM_DWC_CORE 192 202 help 193 203 PWM driver for Synopsys DWC PWM Controller attached to a PCI bus. 194 204
+1
drivers/pwm/Makefile
··· 15 15 obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o 16 16 obj-$(CONFIG_PWM_CRC) += pwm-crc.o 17 17 obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o 18 + obj-$(CONFIG_PWM_DWC_CORE) += pwm-dwc-core.o 18 19 obj-$(CONFIG_PWM_DWC) += pwm-dwc.o 19 20 obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o 20 21 obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
+175
drivers/pwm/pwm-dwc-core.c
··· 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_PERIOD_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_PERIOD_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(chip->dev); 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(chip->dev); 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 + 126 + pm_runtime_get_sync(chip->dev); 127 + 128 + state->enabled = !!(dwc_pwm_readl(dwc, 129 + DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); 130 + 131 + duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); 132 + duty += 1; 133 + duty *= DWC_CLK_PERIOD_NS; 134 + state->duty_cycle = duty; 135 + 136 + period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); 137 + period += 1; 138 + period *= DWC_CLK_PERIOD_NS; 139 + period += duty; 140 + state->period = period; 141 + 142 + state->polarity = PWM_POLARITY_INVERSED; 143 + 144 + pm_runtime_put_sync(chip->dev); 145 + 146 + return 0; 147 + } 148 + 149 + static const struct pwm_ops dwc_pwm_ops = { 150 + .apply = dwc_pwm_apply, 151 + .get_state = dwc_pwm_get_state, 152 + }; 153 + 154 + struct dwc_pwm *dwc_pwm_alloc(struct device *dev) 155 + { 156 + struct dwc_pwm *dwc; 157 + 158 + dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); 159 + if (!dwc) 160 + return NULL; 161 + 162 + dwc->chip.dev = dev; 163 + dwc->chip.ops = &dwc_pwm_ops; 164 + dwc->chip.npwm = DWC_TIMERS_TOTAL; 165 + 166 + dev_set_drvdata(dev, dwc); 167 + return dwc; 168 + } 169 + EXPORT_SYMBOL_GPL(dwc_pwm_alloc); 170 + 171 + MODULE_AUTHOR("Felipe Balbi (Intel)"); 172 + MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); 173 + MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); 174 + MODULE_DESCRIPTION("DesignWare PWM Controller"); 175 + MODULE_LICENSE("GPL");
+4 -192
drivers/pwm/pwm-dwc.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * DesignWare PWM Controller driver 3 + * DesignWare PWM Controller driver (PCI part) 4 4 * 5 5 * Copyright (C) 2018-2020 Intel Corporation 6 6 * ··· 13 13 * periods are one or more input clock periods long. 14 14 */ 15 15 16 + #define DEFAULT_MOUDLE_NAMESPACE dwc_pwm 17 + 16 18 #include <linux/bitops.h> 17 19 #include <linux/export.h> 18 20 #include <linux/kernel.h> ··· 23 21 #include <linux/pm_runtime.h> 24 22 #include <linux/pwm.h> 25 23 26 - #define DWC_TIM_LD_CNT(n) ((n) * 0x14) 27 - #define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) 28 - #define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) 29 - #define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08) 30 - #define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c) 31 - #define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10) 32 - 33 - #define DWC_TIMERS_INT_STS 0xa0 34 - #define DWC_TIMERS_EOI 0xa4 35 - #define DWC_TIMERS_RAW_INT_STS 0xa8 36 - #define DWC_TIMERS_COMP_VERSION 0xac 37 - 38 - #define DWC_TIMERS_TOTAL 8 39 - #define DWC_CLK_PERIOD_NS 10 40 - 41 - /* Timer Control Register */ 42 - #define DWC_TIM_CTRL_EN BIT(0) 43 - #define DWC_TIM_CTRL_MODE BIT(1) 44 - #define DWC_TIM_CTRL_MODE_FREE (0 << 1) 45 - #define DWC_TIM_CTRL_MODE_USER (1 << 1) 46 - #define DWC_TIM_CTRL_INT_MASK BIT(2) 47 - #define DWC_TIM_CTRL_PWM BIT(3) 48 - 49 - struct dwc_pwm_ctx { 50 - u32 cnt; 51 - u32 cnt2; 52 - u32 ctrl; 53 - }; 54 - 55 - struct dwc_pwm { 56 - struct pwm_chip chip; 57 - void __iomem *base; 58 - struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; 59 - }; 60 - #define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) 61 - 62 - static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset) 63 - { 64 - return readl(dwc->base + offset); 65 - } 66 - 67 - static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset) 68 - { 69 - writel(value, dwc->base + offset); 70 - } 71 - 72 - static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled) 73 - { 74 - u32 reg; 75 - 76 - reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm)); 77 - 78 - if (enabled) 79 - reg |= DWC_TIM_CTRL_EN; 80 - else 81 - reg &= ~DWC_TIM_CTRL_EN; 82 - 83 - dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm)); 84 - } 85 - 86 - static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, 87 - struct pwm_device *pwm, 88 - const struct pwm_state *state) 89 - { 90 - u64 tmp; 91 - u32 ctrl; 92 - u32 high; 93 - u32 low; 94 - 95 - /* 96 - * Calculate width of low and high period in terms of input clock 97 - * periods and check are the result within HW limits between 1 and 98 - * 2^32 periods. 99 - */ 100 - tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); 101 - if (tmp < 1 || tmp > (1ULL << 32)) 102 - return -ERANGE; 103 - low = tmp - 1; 104 - 105 - tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, 106 - DWC_CLK_PERIOD_NS); 107 - if (tmp < 1 || tmp > (1ULL << 32)) 108 - return -ERANGE; 109 - high = tmp - 1; 110 - 111 - /* 112 - * Specification says timer usage flow is to disable timer, then 113 - * program it followed by enable. It also says Load Count is loaded 114 - * into timer after it is enabled - either after a disable or 115 - * a reset. Based on measurements it happens also without disable 116 - * whenever Load Count is updated. But follow the specification. 117 - */ 118 - __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); 119 - 120 - /* 121 - * Write Load Count and Load Count 2 registers. Former defines the 122 - * width of low period and latter the width of high period in terms 123 - * multiple of input clock periods: 124 - * Width = ((Count + 1) * input clock period). 125 - */ 126 - dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); 127 - dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); 128 - 129 - /* 130 - * Set user-defined mode, timer reloads from Load Count registers 131 - * when it counts down to 0. 132 - * Set PWM mode, it makes output to toggle and width of low and high 133 - * periods are set by Load Count registers. 134 - */ 135 - ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; 136 - dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); 137 - 138 - /* 139 - * Enable timer. Output starts from low period. 140 - */ 141 - __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled); 142 - 143 - return 0; 144 - } 145 - 146 - static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 147 - const struct pwm_state *state) 148 - { 149 - struct dwc_pwm *dwc = to_dwc_pwm(chip); 150 - 151 - if (state->polarity != PWM_POLARITY_INVERSED) 152 - return -EINVAL; 153 - 154 - if (state->enabled) { 155 - if (!pwm->state.enabled) 156 - pm_runtime_get_sync(chip->dev); 157 - return __dwc_pwm_configure_timer(dwc, pwm, state); 158 - } else { 159 - if (pwm->state.enabled) { 160 - __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); 161 - pm_runtime_put_sync(chip->dev); 162 - } 163 - } 164 - 165 - return 0; 166 - } 167 - 168 - static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 169 - struct pwm_state *state) 170 - { 171 - struct dwc_pwm *dwc = to_dwc_pwm(chip); 172 - u64 duty, period; 173 - 174 - pm_runtime_get_sync(chip->dev); 175 - 176 - state->enabled = !!(dwc_pwm_readl(dwc, 177 - DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); 178 - 179 - duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); 180 - duty += 1; 181 - duty *= DWC_CLK_PERIOD_NS; 182 - state->duty_cycle = duty; 183 - 184 - period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); 185 - period += 1; 186 - period *= DWC_CLK_PERIOD_NS; 187 - period += duty; 188 - state->period = period; 189 - 190 - state->polarity = PWM_POLARITY_INVERSED; 191 - 192 - pm_runtime_put_sync(chip->dev); 193 - 194 - return 0; 195 - } 196 - 197 - static const struct pwm_ops dwc_pwm_ops = { 198 - .apply = dwc_pwm_apply, 199 - .get_state = dwc_pwm_get_state, 200 - }; 201 - 202 - static struct dwc_pwm *dwc_pwm_alloc(struct device *dev) 203 - { 204 - struct dwc_pwm *dwc; 205 - 206 - dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); 207 - if (!dwc) 208 - return NULL; 209 - 210 - dwc->chip.dev = dev; 211 - dwc->chip.ops = &dwc_pwm_ops; 212 - dwc->chip.npwm = DWC_TIMERS_TOTAL; 213 - 214 - dev_set_drvdata(dev, dwc); 215 - return dwc; 216 - } 24 + #include "pwm-dwc.h" 217 25 218 26 static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id) 219 27 {
+60
drivers/pwm/pwm-dwc.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * DesignWare PWM Controller driver 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 + MODULE_IMPORT_NS(dwc_pwm); 13 + 14 + #define DWC_TIM_LD_CNT(n) ((n) * 0x14) 15 + #define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) 16 + #define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) 17 + #define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08) 18 + #define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c) 19 + #define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10) 20 + 21 + #define DWC_TIMERS_INT_STS 0xa0 22 + #define DWC_TIMERS_EOI 0xa4 23 + #define DWC_TIMERS_RAW_INT_STS 0xa8 24 + #define DWC_TIMERS_COMP_VERSION 0xac 25 + 26 + #define DWC_TIMERS_TOTAL 8 27 + #define DWC_CLK_PERIOD_NS 10 28 + 29 + /* Timer Control Register */ 30 + #define DWC_TIM_CTRL_EN BIT(0) 31 + #define DWC_TIM_CTRL_MODE BIT(1) 32 + #define DWC_TIM_CTRL_MODE_FREE (0 << 1) 33 + #define DWC_TIM_CTRL_MODE_USER (1 << 1) 34 + #define DWC_TIM_CTRL_INT_MASK BIT(2) 35 + #define DWC_TIM_CTRL_PWM BIT(3) 36 + 37 + struct dwc_pwm_ctx { 38 + u32 cnt; 39 + u32 cnt2; 40 + u32 ctrl; 41 + }; 42 + 43 + struct dwc_pwm { 44 + struct pwm_chip chip; 45 + void __iomem *base; 46 + struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; 47 + }; 48 + #define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) 49 + 50 + static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset) 51 + { 52 + return readl(dwc->base + offset); 53 + } 54 + 55 + static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset) 56 + { 57 + writel(value, dwc->base + offset); 58 + } 59 + 60 + extern struct dwc_pwm *dwc_pwm_alloc(struct device *dev);