Pull pwm updates from Thierry Reding: "The ZTE ZX platform is being removed, so the PWM driver is no longer needed and removed as well. Other than that this contains a small set of fixes and cleanups across a couple of drivers" * tag 'pwm/for-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: pwm: lpc18xx-sct: remove unneeded semicolon pwm: iqs620a: Correct a stale state variable pwm: iqs620a: Fix overflow and optimize calculations pwm: rockchip: Enable clock before calling clk_get_rate() pwm: rockchip: Eliminate potential race condition when probing pwm: rockchip: Replace "bus clk" with "PWM clk" pwm: rockchip: rockchip_pwm_probe(): Remove superfluous clk_unprepare() pwm: rockchip: Enable APB clock during register access while probing pwm: Remove ZTE ZX driver
Unified · Split
| @@ -1,22 +0,0 @@ | ||
| 1 | −ZTE ZX PWM controller | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | − - compatible: Should be "zte,zx296718-pwm". | |
| 5 | − - reg: Physical base address and length of the controller's registers. | |
| 6 | − - clocks : The phandle and specifier referencing the controller's clocks. | |
| 7 | − - clock-names: "pclk" for PCLK, "wclk" for WCLK to the PWM controller. The | |
| 8 | − PCLK is for register access, while WCLK is the reference clock for | |
| 9 | − calculating period and duty cycles. | |
| 10 | − - #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of | |
| 11 | − the cells format. | |
| 12 | − | |
| 13 | −Example: | |
| 14 | − | |
| 15 | − pwm: pwm@1439000 { | |
| 16 | − compatible = "zte,zx296718-pwm"; | |
| 17 | − reg = <0x1439000 0x1000>; | |
| 18 | − clocks = <&lsp1crm LSP1_PWM_PCLK>, | |
| 19 | − <&lsp1crm LSP1_PWM_WCLK>; | |
| 20 | − clock-names = "pclk", "wclk"; | |
| 21 | − #pwm-cells = <3>; | |
| 22 | − }; | |
| @@ -611,14 +611,4 @@ config PWM_VT8500 · 610 unmodified lines | ||
| 611 | 611 | To compile this driver as a module, choose M here: the module |
| 612 | 612 | will be called pwm-vt8500. |
| 613 | 613 | |
| 614 | −config PWM_ZX | |
| 615 | − tristate "ZTE ZX PWM support" | |
| 616 | − depends on ARCH_ZX || COMPILE_TEST | |
| 617 | − depends on HAS_IOMEM | |
| 618 | − help | |
| 619 | − Generic PWM framework driver for ZTE ZX family SoCs. | |
| 620 | − | |
| 621 | − To compile this driver as a module, choose M here: the module | |
| 622 | − will be called pwm-zx. | |
| 623 | − | |
| 624 | 614 | endif |
| @@ -57,4 +57,3 @@ obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o · 56 unmodified lines | ||
| 57 | 57 | obj-$(CONFIG_PWM_TWL) += pwm-twl.o |
| 58 | 58 | obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o |
| 59 | 59 | obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o |
| 60 | −obj-$(CONFIG_PWM_ZX) += pwm-zx.o | |
| @@ -37,16 +37,34 @@ struct iqs620_pwm_private { · 36 unmodified lines | ||
| 37 | 37 | struct pwm_chip chip; |
| 38 | 38 | struct notifier_block notifier; |
| 39 | 39 | struct mutex lock; |
| 40 | − bool out_en; | |
| 41 | − u8 duty_val; | |
| 40 | + unsigned int duty_scale; | |
| 42 | 41 | }; |
| 43 | 42 | |
| 43 | +static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm, | |
| 44 | + unsigned int duty_scale) | |
| 45 | +{ | |
| 46 | + struct iqs62x_core *iqs62x = iqs620_pwm->iqs62x; | |
| 47 | + int ret; | |
| 48 | + | |
| 49 | + if (!duty_scale) | |
| 50 | + return regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, | |
| 51 | + IQS620_PWR_SETTINGS_PWM_OUT, 0); | |
| 52 | + | |
| 53 | + ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, | |
| 54 | + duty_scale - 1); | |
| 55 | + if (ret) | |
| 56 | + return ret; | |
| 57 | + | |
| 58 | + return regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, | |
| 59 | + IQS620_PWR_SETTINGS_PWM_OUT, 0xff); | |
| 60 | +} | |
| 61 | + | |
| 44 | 62 | static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
| 45 | 63 | const struct pwm_state *state) |
| 46 | 64 | { |
| 47 | 65 | struct iqs620_pwm_private *iqs620_pwm; |
| 48 | − struct iqs62x_core *iqs62x; | |
| 49 | − u64 duty_scale; | |
| 66 | + unsigned int duty_cycle; | |
| 67 | + unsigned int duty_scale; | |
| 50 | 68 | int ret; |
| 51 | 69 | |
| 52 | 70 | if (state->polarity != PWM_POLARITY_NORMAL) |
| @@ -56,7 +74,6 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 3 unmodified lines | ||
| 56 | 74 | return -EINVAL; |
| 57 | 75 | |
| 58 | 76 | iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip); |
| 59 | − iqs62x = iqs620_pwm->iqs62x; | |
| 60 | 77 | |
| 61 | 78 | /* |
| 62 | 79 | * The duty cycle generated by the device is calculated as follows: |
| @@ -70,38 +87,18 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 7 unmodified lines | ||
| 70 | 87 | * For lower duty cycles (e.g. 0), the PWM output is simply disabled to |
| 71 | 88 | * allow an external pull-down resistor to hold the GPIO3/LTX pin low. |
| 72 | 89 | */ |
| 73 | − duty_scale = div_u64(state->duty_cycle * 256, IQS620_PWM_PERIOD_NS); | |
| 74 | − | |
| 75 | − mutex_lock(&iqs620_pwm->lock); | |
| 76 | − | |
| 77 | − if (!state->enabled || !duty_scale) { | |
| 78 | − ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, | |
| 79 | − IQS620_PWR_SETTINGS_PWM_OUT, 0); | |
| 80 | − if (ret) | |
| 81 | − goto err_mutex; | |
| 82 | − } | |
| 90 | + duty_cycle = min_t(u64, state->duty_cycle, IQS620_PWM_PERIOD_NS); | |
| 91 | + duty_scale = duty_cycle * 256 / IQS620_PWM_PERIOD_NS; | |
| 83 | 92 | |
| 84 | − if (duty_scale) { | |
| 85 | − u8 duty_val = min_t(u64, duty_scale - 1, 0xff); | |
| 93 | + if (!state->enabled) | |
| 94 | + duty_scale = 0; | |
| 86 | 95 | |
| 87 | − ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, | |
| 88 | − duty_val); | |
| 89 | − if (ret) | |
| 90 | − goto err_mutex; | |
| 91 | − | |
| 92 | − iqs620_pwm->duty_val = duty_val; | |
| 93 | − } | |
| 94 | − | |
| 95 | − if (state->enabled && duty_scale) { | |
| 96 | − ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, | |
| 97 | − IQS620_PWR_SETTINGS_PWM_OUT, 0xff); | |
| 98 | − if (ret) | |
| 99 | − goto err_mutex; | |
| 100 | − } | |
| 96 | + mutex_lock(&iqs620_pwm->lock); | |
| 101 | 97 | |
| 102 | − iqs620_pwm->out_en = state->enabled; | |
| 98 | + ret = iqs620_pwm_init(iqs620_pwm, duty_scale); | |
| 99 | + if (!ret) | |
| 100 | + iqs620_pwm->duty_scale = duty_scale; | |
| 103 | 101 | |
| 104 | −err_mutex: | |
| 105 | 102 | mutex_unlock(&iqs620_pwm->lock); |
| 106 | 103 | |
| 107 | 104 | return ret; |
| @@ -119,12 +116,11 @@ static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, · 11 unmodified lines | ||
| 119 | 116 | /* |
| 120 | 117 | * Since the device cannot generate a 0% duty cycle, requests to do so |
| 121 | 118 | * cause subsequent calls to iqs620_pwm_get_state to report the output |
| 122 | − * as disabled with duty cycle equal to that which was in use prior to | |
| 123 | − * the request. This is not ideal, but is the best compromise based on | |
| 119 | + * as disabled. This is not ideal, but is the best compromise based on | |
| 124 | 120 | * the capabilities of the device. |
| 125 | 121 | */ |
| 126 | − state->enabled = iqs620_pwm->out_en; | |
| 127 | − state->duty_cycle = DIV_ROUND_UP((iqs620_pwm->duty_val + 1) * | |
| 122 | + state->enabled = iqs620_pwm->duty_scale > 0; | |
| 123 | + state->duty_cycle = DIV_ROUND_UP(iqs620_pwm->duty_scale * | |
| 128 | 124 | IQS620_PWM_PERIOD_NS, 256); |
| 129 | 125 | |
| 130 | 126 | mutex_unlock(&iqs620_pwm->lock); |
| @@ -136,7 +132,6 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier, · 5 unmodified lines | ||
| 136 | 132 | unsigned long event_flags, void *context) |
| 137 | 133 | { |
| 138 | 134 | struct iqs620_pwm_private *iqs620_pwm; |
| 139 | − struct iqs62x_core *iqs62x; | |
| 140 | 135 | int ret; |
| 141 | 136 | |
| 142 | 137 | if (!(event_flags & BIT(IQS62X_EVENT_SYS_RESET))) |
| @@ -144,7 +139,6 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier, · 1 unmodified line | ||
| 144 | 139 | |
| 145 | 140 | iqs620_pwm = container_of(notifier, struct iqs620_pwm_private, |
| 146 | 141 | notifier); |
| 147 | − iqs62x = iqs620_pwm->iqs62x; | |
| 148 | 142 | |
| 149 | 143 | mutex_lock(&iqs620_pwm->lock); |
| 150 | 144 | |
| @@ -153,16 +147,8 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier, · 2 unmodified lines | ||
| 153 | 147 | * of a device reset, so nothing else is printed here unless there is |
| 154 | 148 | * an additional failure. |
| 155 | 149 | */ |
| 156 | − ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, | |
| 157 | − iqs620_pwm->duty_val); | |
| 158 | − if (ret) | |
| 159 | − goto err_mutex; | |
| 150 | + ret = iqs620_pwm_init(iqs620_pwm, iqs620_pwm->duty_scale); | |
| 160 | 151 | |
| 161 | − ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS, | |
| 162 | − IQS620_PWR_SETTINGS_PWM_OUT, | |
| 163 | − iqs620_pwm->out_en ? 0xff : 0); | |
| 164 | − | |
| 165 | −err_mutex: | |
| 166 | 152 | mutex_unlock(&iqs620_pwm->lock); |
| 167 | 153 | |
| 168 | 154 | if (ret) { |
| @@ -209,12 +195,14 @@ static int iqs620_pwm_probe(struct platform_device *pdev) · 40 unmodified lines | ||
| 209 | 195 | ret = regmap_read(iqs62x->regmap, IQS620_PWR_SETTINGS, &val); |
| 210 | 196 | if (ret) |
| 211 | 197 | return ret; |
| 212 | − iqs620_pwm->out_en = val & IQS620_PWR_SETTINGS_PWM_OUT; | |
| 213 | 198 | |
| 214 | − ret = regmap_read(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, &val); | |
| 215 | − if (ret) | |
| 216 | − return ret; | |
| 217 | − iqs620_pwm->duty_val = val; | |
| 199 | + if (val & IQS620_PWR_SETTINGS_PWM_OUT) { | |
| 200 | + ret = regmap_read(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, &val); | |
| 201 | + if (ret) | |
| 202 | + return ret; | |
| 203 | + | |
| 204 | + iqs620_pwm->duty_scale = val + 1; | |
| 205 | + } | |
| 218 | 206 | |
| 219 | 207 | iqs620_pwm->chip.dev = &pdev->dev; |
| 220 | 208 | iqs620_pwm->chip.ops = &iqs620_pwm_ops; |
| @@ -289,7 +289,7 @@ static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) · 288 unmodified lines | ||
| 289 | 289 | dev_err(lpc18xx_pwm->dev, |
| 290 | 290 | "maximum number of simultaneous channels reached\n"); |
| 291 | 291 | return -EBUSY; |
| 292 | − }; | |
| 292 | + } | |
| 293 | 293 | |
| 294 | 294 | set_bit(event, &lpc18xx_pwm->event_map); |
| 295 | 295 | lpc18xx_data->duty_event = event; |
| @@ -72,6 +72,10 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, · 71 unmodified lines | ||
| 72 | 72 | if (ret) |
| 73 | 73 | return; |
| 74 | 74 | |
| 75 | + ret = clk_enable(pc->clk); | |
| 76 | + if (ret) | |
| 77 | + return; | |
| 78 | + | |
| 75 | 79 | clk_rate = clk_get_rate(pc->clk); |
| 76 | 80 | |
| 77 | 81 | tmp = readl_relaxed(pc->base + pc->data->regs.period); |
| @@ -90,6 +94,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, · 12 unmodified lines | ||
| 90 | 94 | else |
| 91 | 95 | state->polarity = PWM_POLARITY_NORMAL; |
| 92 | 96 | |
| 97 | + clk_disable(pc->clk); | |
| 93 | 98 | clk_disable(pc->pclk); |
| 94 | 99 | } |
| 95 | 100 | |
| @@ -189,6 +194,10 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 93 unmodified lines | ||
| 189 | 194 | if (ret) |
| 190 | 195 | return ret; |
| 191 | 196 | |
| 197 | + ret = clk_enable(pc->clk); | |
| 198 | + if (ret) | |
| 199 | + return ret; | |
| 200 | + | |
| 192 | 201 | pwm_get_state(pwm, &curstate); |
| 193 | 202 | enabled = curstate.enabled; |
| 194 | 203 | |
| @@ -208,6 +217,7 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 13 unmodified lines | ||
| 208 | 217 | } |
| 209 | 218 | |
| 210 | 219 | out: |
| 220 | + clk_disable(pc->clk); | |
| 211 | 221 | clk_disable(pc->pclk); |
| 212 | 222 | |
| 213 | 223 | return ret; |
| @@ -288,6 +298,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) · 74 unmodified lines | ||
| 288 | 298 | const struct of_device_id *id; |
| 289 | 299 | struct rockchip_pwm_chip *pc; |
| 290 | 300 | u32 enable_conf, ctrl; |
| 301 | + bool enabled; | |
| 291 | 302 | int ret, count; |
| 292 | 303 | |
| 293 | 304 | id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev); |
| @@ -307,7 +318,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) · 13 unmodified lines | ||
| 307 | 318 | pc->clk = devm_clk_get(&pdev->dev, NULL); |
| 308 | 319 | if (IS_ERR(pc->clk)) |
| 309 | 320 | return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), |
| 310 | − "Can't get bus clk\n"); | |
| 321 | + "Can't get PWM clk\n"); | |
| 311 | 322 | } |
| 312 | 323 | |
| 313 | 324 | count = of_count_phandle_with_args(pdev->dev.of_node, |
| @@ -326,13 +337,13 @@ static int rockchip_pwm_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 326 | 337 | |
| 327 | 338 | ret = clk_prepare_enable(pc->clk); |
| 328 | 339 | if (ret) { |
| 329 | − dev_err(&pdev->dev, "Can't prepare enable bus clk: %d\n", ret); | |
| 340 | + dev_err(&pdev->dev, "Can't prepare enable PWM clk: %d\n", ret); | |
| 330 | 341 | return ret; |
| 331 | 342 | } |
| 332 | 343 | |
| 333 | − ret = clk_prepare(pc->pclk); | |
| 344 | + ret = clk_prepare_enable(pc->pclk); | |
| 334 | 345 | if (ret) { |
| 335 | − dev_err(&pdev->dev, "Can't prepare APB clk: %d\n", ret); | |
| 346 | + dev_err(&pdev->dev, "Can't prepare enable APB clk: %d\n", ret); | |
| 336 | 347 | goto err_clk; |
| 337 | 348 | } |
| 338 | 349 | |
| @@ -349,23 +360,26 @@ static int rockchip_pwm_probe(struct platform_device *pdev) · 10 unmodified lines | ||
| 349 | 360 | pc->chip.of_pwm_n_cells = 3; |
| 350 | 361 | } |
| 351 | 362 | |
| 363 | + enable_conf = pc->data->enable_conf; | |
| 364 | + ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); | |
| 365 | + enabled = (ctrl & enable_conf) == enable_conf; | |
| 366 | + | |
| 352 | 367 | ret = pwmchip_add(&pc->chip); |
| 353 | 368 | if (ret < 0) { |
| 354 | − clk_unprepare(pc->clk); | |
| 355 | 369 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); |
| 356 | 370 | goto err_pclk; |
| 357 | 371 | } |
| 358 | 372 | |
| 359 | 373 | /* Keep the PWM clk enabled if the PWM appears to be up and running. */ |
| 360 | − enable_conf = pc->data->enable_conf; | |
| 361 | − ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); | |
| 362 | − if ((ctrl & enable_conf) != enable_conf) | |
| 374 | + if (!enabled) | |
| 363 | 375 | clk_disable(pc->clk); |
| 364 | 376 | |
| 377 | + clk_disable(pc->pclk); | |
| 378 | + | |
| 365 | 379 | return 0; |
| 366 | 380 | |
| 367 | 381 | err_pclk: |
| 368 | − clk_unprepare(pc->pclk); | |
| 382 | + clk_disable_unprepare(pc->pclk); | |
| 369 | 383 | err_clk: |
| 370 | 384 | clk_disable_unprepare(pc->clk); |
| 371 | 385 | |
| @@ -1,278 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Copyright (C) 2017 Sanechips Technology Co., Ltd. | |
| 4 | − * Copyright 2017 Linaro Ltd. | |
| 5 | − */ | |
| 6 | − | |
| 7 | −#include <linux/clk.h> | |
| 8 | −#include <linux/err.h> | |
| 9 | −#include <linux/io.h> | |
| 10 | −#include <linux/kernel.h> | |
| 11 | −#include <linux/module.h> | |
| 12 | −#include <linux/platform_device.h> | |
| 13 | −#include <linux/pwm.h> | |
| 14 | −#include <linux/slab.h> | |
| 15 | − | |
| 16 | −#define ZX_PWM_MODE 0x0 | |
| 17 | −#define ZX_PWM_CLKDIV_SHIFT 2 | |
| 18 | −#define ZX_PWM_CLKDIV_MASK GENMASK(11, 2) | |
| 19 | −#define ZX_PWM_CLKDIV(x) (((x) << ZX_PWM_CLKDIV_SHIFT) & \ | |
| 20 | − ZX_PWM_CLKDIV_MASK) | |
| 21 | −#define ZX_PWM_POLAR BIT(1) | |
| 22 | −#define ZX_PWM_EN BIT(0) | |
| 23 | −#define ZX_PWM_PERIOD 0x4 | |
| 24 | −#define ZX_PWM_DUTY 0x8 | |
| 25 | − | |
| 26 | −#define ZX_PWM_CLKDIV_MAX 1023 | |
| 27 | −#define ZX_PWM_PERIOD_MAX 65535 | |
| 28 | − | |
| 29 | −struct zx_pwm_chip { | |
| 30 | − struct pwm_chip chip; | |
| 31 | − struct clk *pclk; | |
| 32 | − struct clk *wclk; | |
| 33 | − void __iomem *base; | |
| 34 | −}; | |
| 35 | − | |
| 36 | −static inline struct zx_pwm_chip *to_zx_pwm_chip(struct pwm_chip *chip) | |
| 37 | −{ | |
| 38 | − return container_of(chip, struct zx_pwm_chip, chip); | |
| 39 | −} | |
| 40 | − | |
| 41 | −static inline u32 zx_pwm_readl(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
| 42 | − unsigned int offset) | |
| 43 | −{ | |
| 44 | − return readl(zpc->base + (hwpwm + 1) * 0x10 + offset); | |
| 45 | −} | |
| 46 | − | |
| 47 | −static inline void zx_pwm_writel(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
| 48 | − unsigned int offset, u32 value) | |
| 49 | −{ | |
| 50 | − writel(value, zpc->base + (hwpwm + 1) * 0x10 + offset); | |
| 51 | −} | |
| 52 | − | |
| 53 | −static void zx_pwm_set_mask(struct zx_pwm_chip *zpc, unsigned int hwpwm, | |
| 54 | − unsigned int offset, u32 mask, u32 value) | |
| 55 | −{ | |
| 56 | − u32 data; | |
| 57 | − | |
| 58 | − data = zx_pwm_readl(zpc, hwpwm, offset); | |
| 59 | − data &= ~mask; | |
| 60 | − data |= value & mask; | |
| 61 | − zx_pwm_writel(zpc, hwpwm, offset, data); | |
| 62 | −} | |
| 63 | − | |
| 64 | −static void zx_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, | |
| 65 | − struct pwm_state *state) | |
| 66 | −{ | |
| 67 | − struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
| 68 | − unsigned long rate; | |
| 69 | − unsigned int div; | |
| 70 | − u32 value; | |
| 71 | − u64 tmp; | |
| 72 | − | |
| 73 | − value = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_MODE); | |
| 74 | − | |
| 75 | − if (value & ZX_PWM_POLAR) | |
| 76 | − state->polarity = PWM_POLARITY_NORMAL; | |
| 77 | − else | |
| 78 | − state->polarity = PWM_POLARITY_INVERSED; | |
| 79 | − | |
| 80 | − if (value & ZX_PWM_EN) | |
| 81 | − state->enabled = true; | |
| 82 | − else | |
| 83 | − state->enabled = false; | |
| 84 | − | |
| 85 | − div = (value & ZX_PWM_CLKDIV_MASK) >> ZX_PWM_CLKDIV_SHIFT; | |
| 86 | − rate = clk_get_rate(zpc->wclk); | |
| 87 | − | |
| 88 | − tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_PERIOD); | |
| 89 | − tmp *= div * NSEC_PER_SEC; | |
| 90 | − state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
| 91 | − | |
| 92 | − tmp = zx_pwm_readl(zpc, pwm->hwpwm, ZX_PWM_DUTY); | |
| 93 | − tmp *= div * NSEC_PER_SEC; | |
| 94 | − state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); | |
| 95 | −} | |
| 96 | − | |
| 97 | −static int zx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |
| 98 | − unsigned int duty_ns, unsigned int period_ns) | |
| 99 | −{ | |
| 100 | − struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
| 101 | − unsigned int period_cycles, duty_cycles; | |
| 102 | − unsigned long long c; | |
| 103 | − unsigned int div = 1; | |
| 104 | − unsigned long rate; | |
| 105 | − | |
| 106 | − /* Find out the best divider */ | |
| 107 | − rate = clk_get_rate(zpc->wclk); | |
| 108 | − | |
| 109 | − while (1) { | |
| 110 | − c = rate / div; | |
| 111 | − c = c * period_ns; | |
| 112 | − do_div(c, NSEC_PER_SEC); | |
| 113 | − | |
| 114 | − if (c < ZX_PWM_PERIOD_MAX) | |
| 115 | − break; | |
| 116 | − | |
| 117 | − div++; | |
| 118 | − | |
| 119 | − if (div > ZX_PWM_CLKDIV_MAX) | |
| 120 | − return -ERANGE; | |
| 121 | − } | |
| 122 | − | |
| 123 | − /* Calculate duty cycles */ | |
| 124 | − period_cycles = c; | |
| 125 | − c *= duty_ns; | |
| 126 | − do_div(c, period_ns); | |
| 127 | − duty_cycles = c; | |
| 128 | − | |
| 129 | − /* | |
| 130 | − * If the PWM is being enabled, we have to temporarily disable it | |
| 131 | − * before configuring the registers. | |
| 132 | − */ | |
| 133 | − if (pwm_is_enabled(pwm)) | |
| 134 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_EN, 0); | |
| 135 | − | |
| 136 | − /* Set up registers */ | |
| 137 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_CLKDIV_MASK, | |
| 138 | − ZX_PWM_CLKDIV(div)); | |
| 139 | − zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_PERIOD, period_cycles); | |
| 140 | − zx_pwm_writel(zpc, pwm->hwpwm, ZX_PWM_DUTY, duty_cycles); | |
| 141 | − | |
| 142 | − /* Re-enable the PWM if needed */ | |
| 143 | − if (pwm_is_enabled(pwm)) | |
| 144 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
| 145 | − ZX_PWM_EN, ZX_PWM_EN); | |
| 146 | − | |
| 147 | − return 0; | |
| 148 | −} | |
| 149 | − | |
| 150 | −static int zx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, | |
| 151 | − const struct pwm_state *state) | |
| 152 | −{ | |
| 153 | − struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); | |
| 154 | − struct pwm_state cstate; | |
| 155 | − int ret; | |
| 156 | − | |
| 157 | − pwm_get_state(pwm, &cstate); | |
| 158 | − | |
| 159 | − if (state->polarity != cstate.polarity) | |
| 160 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, ZX_PWM_POLAR, | |
| 161 | − (state->polarity == PWM_POLARITY_INVERSED) ? | |
| 162 | − 0 : ZX_PWM_POLAR); | |
| 163 | − | |
| 164 | − if (state->period != cstate.period || | |
| 165 | − state->duty_cycle != cstate.duty_cycle) { | |
| 166 | − ret = zx_pwm_config(chip, pwm, state->duty_cycle, | |
| 167 | − state->period); | |
| 168 | − if (ret) | |
| 169 | − return ret; | |
| 170 | − } | |
| 171 | − | |
| 172 | − if (state->enabled != cstate.enabled) { | |
| 173 | − if (state->enabled) { | |
| 174 | − ret = clk_prepare_enable(zpc->wclk); | |
| 175 | − if (ret) | |
| 176 | − return ret; | |
| 177 | − | |
| 178 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
| 179 | − ZX_PWM_EN, ZX_PWM_EN); | |
| 180 | − } else { | |
| 181 | − zx_pwm_set_mask(zpc, pwm->hwpwm, ZX_PWM_MODE, | |
| 182 | − ZX_PWM_EN, 0); | |
| 183 | − clk_disable_unprepare(zpc->wclk); | |
| 184 | − } | |
| 185 | − } | |
| 186 | − | |
| 187 | − return 0; | |
| 188 | −} | |
| 189 | − | |
| 190 | −static const struct pwm_ops zx_pwm_ops = { | |
| 191 | − .apply = zx_pwm_apply, | |
| 192 | − .get_state = zx_pwm_get_state, | |
| 193 | − .owner = THIS_MODULE, | |
| 194 | −}; | |
| 195 | − | |
| 196 | −static int zx_pwm_probe(struct platform_device *pdev) | |
| 197 | −{ | |
| 198 | − struct zx_pwm_chip *zpc; | |
| 199 | − unsigned int i; | |
| 200 | − int ret; | |
| 201 | − | |
| 202 | − zpc = devm_kzalloc(&pdev->dev, sizeof(*zpc), GFP_KERNEL); | |
| 203 | − if (!zpc) | |
| 204 | − return -ENOMEM; | |
| 205 | − | |
| 206 | − zpc->base = devm_platform_ioremap_resource(pdev, 0); | |
| 207 | − if (IS_ERR(zpc->base)) | |
| 208 | − return PTR_ERR(zpc->base); | |
| 209 | − | |
| 210 | − zpc->pclk = devm_clk_get(&pdev->dev, "pclk"); | |
| 211 | − if (IS_ERR(zpc->pclk)) | |
| 212 | − return PTR_ERR(zpc->pclk); | |
| 213 | − | |
| 214 | − zpc->wclk = devm_clk_get(&pdev->dev, "wclk"); | |
| 215 | − if (IS_ERR(zpc->wclk)) | |
| 216 | − return PTR_ERR(zpc->wclk); | |
| 217 | − | |
| 218 | − ret = clk_prepare_enable(zpc->pclk); | |
| 219 | − if (ret) | |
| 220 | − return ret; | |
| 221 | − | |
| 222 | − zpc->chip.dev = &pdev->dev; | |
| 223 | − zpc->chip.ops = &zx_pwm_ops; | |
| 224 | − zpc->chip.base = -1; | |
| 225 | − zpc->chip.npwm = 4; | |
| 226 | − zpc->chip.of_xlate = of_pwm_xlate_with_flags; | |
| 227 | − zpc->chip.of_pwm_n_cells = 3; | |
| 228 | − | |
| 229 | − /* | |
| 230 | − * PWM devices may be enabled by firmware, and let's disable all of | |
| 231 | − * them initially to save power. | |
| 232 | − */ | |
| 233 | − for (i = 0; i < zpc->chip.npwm; i++) | |
| 234 | − zx_pwm_set_mask(zpc, i, ZX_PWM_MODE, ZX_PWM_EN, 0); | |
| 235 | − | |
| 236 | − ret = pwmchip_add(&zpc->chip); | |
| 237 | − if (ret < 0) { | |
| 238 | − dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); | |
| 239 | − clk_disable_unprepare(zpc->pclk); | |
| 240 | − return ret; | |
| 241 | − } | |
| 242 | − | |
| 243 | − platform_set_drvdata(pdev, zpc); | |
| 244 | − | |
| 245 | − return 0; | |
| 246 | −} | |
| 247 | − | |
| 248 | −static int zx_pwm_remove(struct platform_device *pdev) | |
| 249 | −{ | |
| 250 | − struct zx_pwm_chip *zpc = platform_get_drvdata(pdev); | |
| 251 | − int ret; | |
| 252 | − | |
| 253 | − ret = pwmchip_remove(&zpc->chip); | |
| 254 | − clk_disable_unprepare(zpc->pclk); | |
| 255 | − | |
| 256 | − return ret; | |
| 257 | −} | |
| 258 | − | |
| 259 | −static const struct of_device_id zx_pwm_dt_ids[] = { | |
| 260 | − { .compatible = "zte,zx296718-pwm", }, | |
| 261 | − { /* sentinel */ } | |
| 262 | −}; | |
| 263 | −MODULE_DEVICE_TABLE(of, zx_pwm_dt_ids); | |
| 264 | − | |
| 265 | −static struct platform_driver zx_pwm_driver = { | |
| 266 | − .driver = { | |
| 267 | − .name = "zx-pwm", | |
| 268 | − .of_match_table = zx_pwm_dt_ids, | |
| 269 | − }, | |
| 270 | − .probe = zx_pwm_probe, | |
| 271 | − .remove = zx_pwm_remove, | |
| 272 | −}; | |
| 273 | −module_platform_driver(zx_pwm_driver); | |
| 274 | − | |
| 275 | −MODULE_ALIAS("platform:zx-pwm"); | |
| 276 | −MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | |
| 277 | −MODULE_DESCRIPTION("ZTE ZX PWM Driver"); | |
| 278 | −MODULE_LICENSE("GPL v2"); | |