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

Merge tag 'pwm/for-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
"This round contains a couple of new drivers for the Marvell Berlin
family of SoCs, various SoCs from Renesas and Broadcom as well as the
backlight PWM present on MediaTek SoCs.

Further existing drivers are extended to support a wider range of
hardware.

The remaining patches are minor fixes and cleanups across the board.

Note that one of the patches included in this pull request is against
arch/unicore32. I've included it here because I couldn't get a
response from Guan Xuetao and I consider the change low-risk.
Equivalent patches have been merged and tested in Samsung and PXA
trees. The goal is to finally get rid of legacy code paths that have
repeatedly been causing headaches"

* tag 'pwm/for-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (24 commits)
pwm: sunxi: Fix whitespace issue
pwm: sysfs: Make use of the DEVICE_ATTR_[RW][WO] macro's
pwm: sysfs: Remove unnecessary temporary variable
unicore32: nb0916: Use PWM lookup table
pwm: pwm-rcar: Revise the device tree binding document about compatible
pwm: Return -ENODEV if no PWM lookup match is found
pwm: sun4i: Add support for PWM controller on sun5i SoCs
pwm: Set enable state properly on failed call to enable
pwm: lpss: Add support for runtime PM
pwm: lpss: Add more Intel Broxton IDs
pwm: lpss: Support all four PWMs on Intel Broxton
pwm: lpss: Add support for multiple PWMs
pwm-pca9685: enable ACPI device found on Galileo Gen2
pwm: Add MediaTek display PWM driver support
dt-bindings: pwm: Add MediaTek display PWM bindings
pwm: tipwmss: Enable on TI DRA7x and AM437x
pwm: atmel-hlcdc: add sama5d2 SoC support.
pwm: Add Broadcom BCM7038 PWM controller support
Documentation: dt: add Broadcom BCM7038 PWM controller binding
pwm: Add support for R-Car PWM Timer
...

+1441 -82
+20
Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
··· 1 + Broadcom BCM7038 PWM controller (BCM7xxx Set Top Box PWM controller) 2 + 3 + Required properties: 4 + 5 + - compatible: must be "brcm,bcm7038-pwm" 6 + - reg: physical base address and length for this controller 7 + - #pwm-cells: should be 2. See pwm.txt in this directory for a description 8 + of the cells format 9 + - clocks: a phandle to the reference clock for this block which is fed through 10 + its internal variable clock frequency generator 11 + 12 + 13 + Example: 14 + 15 + pwm: pwm@f0408000 { 16 + compatible = "brcm,bcm7038-pwm"; 17 + reg = <0xf0408000 0x28>; 18 + #pwm-cells = <2>; 19 + clocks = <&upg_fixed>; 20 + };
+17
Documentation/devicetree/bindings/pwm/pwm-berlin.txt
··· 1 + Berlin PWM controller 2 + 3 + Required properties: 4 + - compatible: should be "marvell,berlin-pwm" 5 + - reg: physical base address and length of the controller's registers 6 + - clocks: phandle to the input clock 7 + - #pwm-cells: should be 3. See pwm.txt in this directory for a description of 8 + the cells format. 9 + 10 + Example: 11 + 12 + pwm: pwm@f7f20000 { 13 + compatible = "marvell,berlin-pwm"; 14 + reg = <0xf7f20000 0x40>; 15 + clocks = <&chip_clk CLKID_CFG>; 16 + #pwm-cells = <3>; 17 + }
+42
Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
··· 1 + MediaTek display PWM controller 2 + 3 + Required properties: 4 + - compatible: should be "mediatek,<name>-disp-pwm": 5 + - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. 6 + - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. 7 + - reg: physical base address and length of the controller's registers. 8 + - #pwm-cells: must be 2. See pwm.txt in this directory for a description of 9 + the cell format. 10 + - clocks: phandle and clock specifier of the PWM reference clock. 11 + - clock-names: must contain the following: 12 + - "main": clock used to generate PWM signals. 13 + - "mm": sync signals from the modules of mmsys. 14 + - pinctrl-names: Must contain a "default" entry. 15 + - pinctrl-0: One property must exist for each entry in pinctrl-names. 16 + See pinctrl/pinctrl-bindings.txt for details of the property values. 17 + 18 + Example: 19 + pwm0: pwm@1401e000 { 20 + compatible = "mediatek,mt8173-disp-pwm", 21 + "mediatek,mt6595-disp-pwm"; 22 + reg = <0 0x1401e000 0 0x1000>; 23 + #pwm-cells = <2>; 24 + clocks = <&mmsys CLK_MM_DISP_PWM026M>, 25 + <&mmsys CLK_MM_DISP_PWM0MM>; 26 + clock-names = "main", "mm"; 27 + pinctrl-names = "default"; 28 + pinctrl-0 = <&disp_pwm0_pins>; 29 + }; 30 + 31 + backlight_lcd: backlight_lcd { 32 + compatible = "pwm-backlight"; 33 + pwms = <&pwm0 0 1000000>; 34 + brightness-levels = < 35 + 0 16 32 48 64 80 96 112 36 + 128 144 160 176 192 208 224 240 37 + 255 38 + >; 39 + default-brightness-level = <9>; 40 + power-supply = <&mt6397_vio18_reg>; 41 + enable-gpios = <&pio 95 GPIO_ACTIVE_HIGH>; 42 + };
+2
Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
··· 3 3 Required properties: 4 4 - compatible: should be one of: 5 5 - "allwinner,sun4i-a10-pwm" 6 + - "allwinner,sun5i-a10s-pwm" 7 + - "allwinner,sun5i-a13-pwm" 6 8 - "allwinner,sun7i-a20-pwm" 7 9 - reg: physical base address and length of the controller's registers 8 10 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+26
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
··· 1 + * Renesas R-Car PWM Timer Controller 2 + 3 + Required Properties: 4 + - compatible: should be "renesas,pwm-rcar" and one of the following. 5 + - "renesas,pwm-r8a7778": for R-Car M1A 6 + - "renesas,pwm-r8a7779": for R-Car H1 7 + - "renesas,pwm-r8a7790": for R-Car H2 8 + - "renesas,pwm-r8a7791": for R-Car M2-W 9 + - "renesas,pwm-r8a7794": for R-Car E2 10 + - reg: base address and length of the registers block for the PWM. 11 + - #pwm-cells: should be 2. See pwm.txt in this directory for a description of 12 + the cells format. 13 + - clocks: clock phandle and specifier pair. 14 + - pinctrl-0: phandle, referring to a default pin configuration node. 15 + - pinctrl-names: Set to "default". 16 + 17 + Example: R8A7790 (R-Car H2) PWM Timer node 18 + 19 + pwm0: pwm@e6e30000 { 20 + compatible = "renesas,pwm-r8a7790", "renesas,pwm-rcar"; 21 + reg = <0 0xe6e30000 0 0x8>; 22 + #pwm-cells = <2>; 23 + clocks = <&mstp5_clks R8A7790_CLK_PWM>; 24 + pinctrl-0 = <&pwm0_pins>; 25 + pinctrl-names = "default"; 26 + };
+8 -2
arch/unicore32/kernel/puv3-nb0916.c
··· 19 19 #include <linux/reboot.h> 20 20 #include <linux/interrupt.h> 21 21 #include <linux/i2c.h> 22 + #include <linux/pwm.h> 22 23 #include <linux/pwm_backlight.h> 23 24 #include <linux/gpio.h> 24 25 #include <linux/gpio_keys.h> ··· 50 49 } 51 50 }; 52 51 52 + static struct pwm_lookup nb0916_pwm_lookup[] = { 53 + PWM_LOOKUP("PKUnity-v3-PWM", 0, "pwm-backlight", NULL, 70 * 1024, 54 + PWM_POLARITY_NORMAL), 55 + }; 56 + 53 57 static struct platform_pwm_backlight_data nb0916_backlight_data = { 54 - .pwm_id = 0, 55 58 .max_brightness = 100, 56 59 .dft_brightness = 100, 57 - .pwm_period_ns = 70 * 1024, 58 60 .enable_gpio = -1, 59 61 }; 60 62 ··· 115 111 116 112 platform_device_register_simple("PKUnity-v3-I2C", -1, 117 113 puv3_i2c_resources, ARRAY_SIZE(puv3_i2c_resources)); 114 + 115 + pwm_add_table(nb0916_pwm_lookup, ARRAY_SIZE(nb0916_pwm_lookup)); 118 116 119 117 platform_device_register_data(NULL, "pwm-backlight", -1, 120 118 &nb0916_backlight_data, sizeof(nb0916_backlight_data));
+45 -4
drivers/pwm/Kconfig
··· 92 92 To compile this driver as a module, choose M here: the module 93 93 will be called pwm-bcm2835. 94 94 95 + config PWM_BERLIN 96 + tristate "Marvell Berlin PWM support" 97 + depends on ARCH_BERLIN 98 + help 99 + PWM framework driver for Marvell Berlin SoCs. 100 + 101 + To compile this driver as a module, choose M here: the module 102 + will be called pwm-berlin. 103 + 95 104 config PWM_BFIN 96 105 tristate "Blackfin PWM support" 97 106 depends on BFIN_GPTIMERS ··· 109 100 110 101 To compile this driver as a module, choose M here: the module 111 102 will be called pwm-bfin. 103 + 104 + config PWM_BRCMSTB 105 + tristate "Broadcom STB PWM support" 106 + depends on ARCH_BRCMSTB || BMIPS_GENERIC 107 + help 108 + Generic PWM framework driver for the Broadcom Set-top-Box 109 + SoCs (BCM7xxx). 110 + 111 + To compile this driver as a module, choose M Here: the module 112 + will be called pwm-brcmstb.c. 112 113 113 114 config PWM_CLPS711X 114 115 tristate "CLPS711X PWM support" ··· 249 230 To compile this driver as a module, choose M here: the module 250 231 will be called pwm-lpss-platform. 251 232 233 + config PWM_MTK_DISP 234 + tristate "MediaTek display PWM driver" 235 + depends on ARCH_MEDIATEK || COMPILE_TEST 236 + depends on HAS_IOMEM 237 + help 238 + Generic PWM framework driver for MediaTek disp-pwm device. 239 + The PWM is used to control the backlight brightness for display. 240 + 241 + To compile this driver as a module, choose M here: the module 242 + will be called pwm-mtk-disp. 243 + 252 244 config PWM_MXS 253 245 tristate "Freescale MXS PWM support" 254 246 depends on ARCH_MXS && OF ··· 272 242 273 243 config PWM_PCA9685 274 244 tristate "NXP PCA9685 PWM driver" 275 - depends on OF && I2C 245 + depends on I2C 276 246 select REGMAP_I2C 277 247 help 278 248 Generic PWM framework driver for NXP PCA9685 LED controller. ··· 297 267 298 268 To compile this driver as a module, choose M here: the module 299 269 will be called pwm-pxa. 270 + 271 + config PWM_RCAR 272 + tristate "Renesas R-Car PWM support" 273 + depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST 274 + depends on HAS_IOMEM 275 + help 276 + This driver exposes the PWM Timer controller found in Renesas 277 + R-Car chips through the PWM API. 278 + 279 + To compile this driver as a module, choose M here: the module 280 + will be called pwm-rcar. 300 281 301 282 config PWM_RENESAS_TPU 302 283 tristate "Renesas TPU PWM support" ··· 379 338 380 339 config PWM_TIECAP 381 340 tristate "ECAP PWM support" 382 - depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX 341 + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX 383 342 help 384 343 PWM driver support for the ECAP APWM controller found on AM33XX 385 344 TI SOC ··· 389 348 390 349 config PWM_TIEHRPWM 391 350 tristate "EHRPWM PWM support" 392 - depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX 351 + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX 393 352 help 394 353 PWM driver support for the EHRPWM controller found on AM33XX 395 354 TI SOC ··· 399 358 400 359 config PWM_TIPWMSS 401 360 bool 402 - default y if SOC_AM33XX && (PWM_TIECAP || PWM_TIEHRPWM) 361 + default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM) 403 362 help 404 363 PWM Subsystem driver support for AM33xx SOC. 405 364
+4
drivers/pwm/Makefile
··· 6 6 obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o 7 7 obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o 8 8 obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o 9 + obj-$(CONFIG_PWM_BERLIN) += pwm-berlin.o 9 10 obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 11 + obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o 10 12 obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o 11 13 obj-$(CONFIG_PWM_CRC) += pwm-crc.o 12 14 obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o ··· 22 20 obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o 23 21 obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o 24 22 obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o 23 + obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o 25 24 obj-$(CONFIG_PWM_MXS) += pwm-mxs.o 26 25 obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o 27 26 obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o 28 27 obj-$(CONFIG_PWM_PXA) += pwm-pxa.o 28 + obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o 29 29 obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o 30 30 obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o 31 31 obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+29 -8
drivers/pwm/core.c
··· 269 269 pwm->pwm = chip->base + i; 270 270 pwm->hwpwm = i; 271 271 pwm->polarity = polarity; 272 + mutex_init(&pwm->lock); 272 273 273 274 radix_tree_insert(&pwm_tree, pwm->pwm, pwm); 274 275 } ··· 474 473 if (!pwm->chip->ops->set_polarity) 475 474 return -ENOSYS; 476 475 477 - if (pwm_is_enabled(pwm)) 478 - return -EBUSY; 476 + mutex_lock(&pwm->lock); 477 + 478 + if (pwm_is_enabled(pwm)) { 479 + err = -EBUSY; 480 + goto unlock; 481 + } 479 482 480 483 err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); 481 484 if (err) 482 - return err; 485 + goto unlock; 483 486 484 487 pwm->polarity = polarity; 485 488 486 - return 0; 489 + unlock: 490 + mutex_unlock(&pwm->lock); 491 + return err; 487 492 } 488 493 EXPORT_SYMBOL_GPL(pwm_set_polarity); 489 494 ··· 501 494 */ 502 495 int pwm_enable(struct pwm_device *pwm) 503 496 { 504 - if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) 505 - return pwm->chip->ops->enable(pwm->chip, pwm); 497 + int err = 0; 506 498 507 - return pwm ? 0 : -EINVAL; 499 + if (!pwm) 500 + return -EINVAL; 501 + 502 + mutex_lock(&pwm->lock); 503 + 504 + if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) { 505 + err = pwm->chip->ops->enable(pwm->chip, pwm); 506 + if (err) 507 + clear_bit(PWMF_ENABLED, &pwm->flags); 508 + } 509 + 510 + mutex_unlock(&pwm->lock); 511 + 512 + return err; 508 513 } 509 514 EXPORT_SYMBOL_GPL(pwm_enable); 510 515 ··· 738 719 } 739 720 } 740 721 741 - if (!chosen) 722 + if (!chosen) { 723 + pwm = ERR_PTR(-ENODEV); 742 724 goto out; 725 + } 743 726 744 727 chip = pwmchip_find_by_name(chosen->provider); 745 728 if (!chip)
+4
drivers/pwm/pwm-atmel-hlcdc.c
··· 227 227 .data = &atmel_hlcdc_pwm_at91sam9x5_errata, 228 228 }, 229 229 { 230 + .compatible = "atmel,sama5d2-hlcdc", 231 + }, 232 + { 230 233 .compatible = "atmel,sama5d3-hlcdc", 231 234 .data = &atmel_hlcdc_pwm_sama5d3_errata, 232 235 }, ··· 239 236 }, 240 237 { /* sentinel */ }, 241 238 }; 239 + MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids); 242 240 243 241 static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) 244 242 {
+219
drivers/pwm/pwm-berlin.c
··· 1 + /* 2 + * Marvell Berlin PWM driver 3 + * 4 + * Copyright (C) 2015 Marvell Technology Group Ltd. 5 + * 6 + * Author: Antoine Tenart <antoine.tenart@free-electrons.com> 7 + * 8 + * This file is licensed under the terms of the GNU General Public 9 + * License version 2. This program is licensed "as is" without any 10 + * warranty of any kind, whether express or implied. 11 + */ 12 + 13 + #include <linux/clk.h> 14 + #include <linux/io.h> 15 + #include <linux/kernel.h> 16 + #include <linux/module.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/pwm.h> 19 + 20 + #define BERLIN_PWM_EN 0x0 21 + #define BERLIN_PWM_ENABLE BIT(0) 22 + #define BERLIN_PWM_CONTROL 0x4 23 + #define BERLIN_PWM_PRESCALE_MASK 0x7 24 + #define BERLIN_PWM_PRESCALE_MAX 4096 25 + #define BERLIN_PWM_INVERT_POLARITY BIT(3) 26 + #define BERLIN_PWM_DUTY 0x8 27 + #define BERLIN_PWM_TCNT 0xc 28 + #define BERLIN_PWM_MAX_TCNT 65535 29 + 30 + struct berlin_pwm_chip { 31 + struct pwm_chip chip; 32 + struct clk *clk; 33 + void __iomem *base; 34 + }; 35 + 36 + static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) 37 + { 38 + return container_of(chip, struct berlin_pwm_chip, chip); 39 + } 40 + 41 + static const u32 prescaler_table[] = { 42 + 1, 4, 8, 16, 64, 256, 1024, 4096 43 + }; 44 + 45 + static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, 46 + unsigned int channel, unsigned long offset) 47 + { 48 + return readl_relaxed(chip->base + channel * 0x10 + offset); 49 + } 50 + 51 + static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, 52 + unsigned int channel, u32 value, 53 + unsigned long offset) 54 + { 55 + writel_relaxed(value, chip->base + channel * 0x10 + offset); 56 + } 57 + 58 + static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, 59 + int duty_ns, int period_ns) 60 + { 61 + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 62 + unsigned int prescale; 63 + u32 value, duty, period; 64 + u64 cycles, tmp; 65 + 66 + cycles = clk_get_rate(pwm->clk); 67 + cycles *= period_ns; 68 + do_div(cycles, NSEC_PER_SEC); 69 + 70 + for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) { 71 + tmp = cycles; 72 + do_div(tmp, prescaler_table[prescale]); 73 + 74 + if (tmp <= BERLIN_PWM_MAX_TCNT) 75 + break; 76 + } 77 + 78 + if (tmp > BERLIN_PWM_MAX_TCNT) 79 + return -ERANGE; 80 + 81 + period = tmp; 82 + cycles = tmp * duty_ns; 83 + do_div(cycles, period_ns); 84 + duty = cycles; 85 + 86 + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); 87 + value &= ~BERLIN_PWM_PRESCALE_MASK; 88 + value |= prescale; 89 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); 90 + 91 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); 92 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT); 93 + 94 + return 0; 95 + } 96 + 97 + static int berlin_pwm_set_polarity(struct pwm_chip *chip, 98 + struct pwm_device *pwm_dev, 99 + enum pwm_polarity polarity) 100 + { 101 + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 102 + u32 value; 103 + 104 + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); 105 + 106 + if (polarity == PWM_POLARITY_NORMAL) 107 + value &= ~BERLIN_PWM_INVERT_POLARITY; 108 + else 109 + value |= BERLIN_PWM_INVERT_POLARITY; 110 + 111 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); 112 + 113 + return 0; 114 + } 115 + 116 + static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) 117 + { 118 + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 119 + u32 value; 120 + 121 + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); 122 + value |= BERLIN_PWM_ENABLE; 123 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); 124 + 125 + return 0; 126 + } 127 + 128 + static void berlin_pwm_disable(struct pwm_chip *chip, 129 + struct pwm_device *pwm_dev) 130 + { 131 + struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 132 + u32 value; 133 + 134 + value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); 135 + value &= ~BERLIN_PWM_ENABLE; 136 + berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); 137 + } 138 + 139 + static const struct pwm_ops berlin_pwm_ops = { 140 + .config = berlin_pwm_config, 141 + .set_polarity = berlin_pwm_set_polarity, 142 + .enable = berlin_pwm_enable, 143 + .disable = berlin_pwm_disable, 144 + .owner = THIS_MODULE, 145 + }; 146 + 147 + static const struct of_device_id berlin_pwm_match[] = { 148 + { .compatible = "marvell,berlin-pwm" }, 149 + { }, 150 + }; 151 + MODULE_DEVICE_TABLE(of, berlin_pwm_match); 152 + 153 + static int berlin_pwm_probe(struct platform_device *pdev) 154 + { 155 + struct berlin_pwm_chip *pwm; 156 + struct resource *res; 157 + int ret; 158 + 159 + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); 160 + if (!pwm) 161 + return -ENOMEM; 162 + 163 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 164 + pwm->base = devm_ioremap_resource(&pdev->dev, res); 165 + if (IS_ERR(pwm->base)) 166 + return PTR_ERR(pwm->base); 167 + 168 + pwm->clk = devm_clk_get(&pdev->dev, NULL); 169 + if (IS_ERR(pwm->clk)) 170 + return PTR_ERR(pwm->clk); 171 + 172 + ret = clk_prepare_enable(pwm->clk); 173 + if (ret) 174 + return ret; 175 + 176 + pwm->chip.dev = &pdev->dev; 177 + pwm->chip.ops = &berlin_pwm_ops; 178 + pwm->chip.base = -1; 179 + pwm->chip.npwm = 4; 180 + pwm->chip.can_sleep = true; 181 + pwm->chip.of_xlate = of_pwm_xlate_with_flags; 182 + pwm->chip.of_pwm_n_cells = 3; 183 + 184 + ret = pwmchip_add(&pwm->chip); 185 + if (ret < 0) { 186 + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 187 + clk_disable_unprepare(pwm->clk); 188 + return ret; 189 + } 190 + 191 + platform_set_drvdata(pdev, pwm); 192 + 193 + return 0; 194 + } 195 + 196 + static int berlin_pwm_remove(struct platform_device *pdev) 197 + { 198 + struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev); 199 + int ret; 200 + 201 + ret = pwmchip_remove(&pwm->chip); 202 + clk_disable_unprepare(pwm->clk); 203 + 204 + return ret; 205 + } 206 + 207 + static struct platform_driver berlin_pwm_driver = { 208 + .probe = berlin_pwm_probe, 209 + .remove = berlin_pwm_remove, 210 + .driver = { 211 + .name = "berlin-pwm", 212 + .of_match_table = berlin_pwm_match, 213 + }, 214 + }; 215 + module_platform_driver(berlin_pwm_driver); 216 + 217 + MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 218 + MODULE_DESCRIPTION("Marvell Berlin PWM driver"); 219 + MODULE_LICENSE("GPL v2");
+343
drivers/pwm/pwm-brcmstb.c
··· 1 + /* 2 + * Broadcom BCM7038 PWM driver 3 + * Author: Florian Fainelli 4 + * 5 + * Copyright (C) 2015 Broadcom Corporation 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 + 20 + #include <linux/clk.h> 21 + #include <linux/export.h> 22 + #include <linux/init.h> 23 + #include <linux/io.h> 24 + #include <linux/kernel.h> 25 + #include <linux/module.h> 26 + #include <linux/of.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/pwm.h> 29 + #include <linux/spinlock.h> 30 + 31 + #define PWM_CTRL 0x00 32 + #define CTRL_START BIT(0) 33 + #define CTRL_OEB BIT(1) 34 + #define CTRL_FORCE_HIGH BIT(2) 35 + #define CTRL_OPENDRAIN BIT(3) 36 + #define CTRL_CHAN_OFFS 4 37 + 38 + #define PWM_CTRL2 0x04 39 + #define CTRL2_OUT_SELECT BIT(0) 40 + 41 + #define PWM_CH_SIZE 0x8 42 + 43 + #define PWM_CWORD_MSB(ch) (0x08 + ((ch) * PWM_CH_SIZE)) 44 + #define PWM_CWORD_LSB(ch) (0x0c + ((ch) * PWM_CH_SIZE)) 45 + 46 + /* Number of bits for the CWORD value */ 47 + #define CWORD_BIT_SIZE 16 48 + 49 + /* 50 + * Maximum control word value allowed when variable-frequency PWM is used as a 51 + * clock for the constant-frequency PMW. 52 + */ 53 + #define CONST_VAR_F_MAX 32768 54 + #define CONST_VAR_F_MIN 1 55 + 56 + #define PWM_ON(ch) (0x18 + ((ch) * PWM_CH_SIZE)) 57 + #define PWM_ON_MIN 1 58 + #define PWM_PERIOD(ch) (0x1c + ((ch) * PWM_CH_SIZE)) 59 + #define PWM_PERIOD_MIN 0 60 + 61 + #define PWM_ON_PERIOD_MAX 0xff 62 + 63 + struct brcmstb_pwm { 64 + void __iomem *base; 65 + spinlock_t lock; 66 + struct clk *clk; 67 + struct pwm_chip chip; 68 + }; 69 + 70 + static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p, 71 + unsigned int offset) 72 + { 73 + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 74 + return __raw_readl(p->base + offset); 75 + else 76 + return readl_relaxed(p->base + offset); 77 + } 78 + 79 + static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value, 80 + unsigned int offset) 81 + { 82 + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 83 + __raw_writel(value, p->base + offset); 84 + else 85 + writel_relaxed(value, p->base + offset); 86 + } 87 + 88 + static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip) 89 + { 90 + return container_of(chip, struct brcmstb_pwm, chip); 91 + } 92 + 93 + /* 94 + * Fv is derived from the variable frequency output. The variable frequency 95 + * output is configured using this formula: 96 + * 97 + * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword 98 + * 99 + * Fv = W x 2 ^ -16 x 27Mhz (reference clock) 100 + * 101 + * The period is: (period + 1) / Fv and "on" time is on / (period + 1) 102 + * 103 + * The PWM core framework specifies that the "duty_ns" parameter is in fact the 104 + * "on" time, so this translates directly into our HW programming here. 105 + */ 106 + static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 107 + int duty_ns, int period_ns) 108 + { 109 + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); 110 + unsigned long pc, dc, cword = CONST_VAR_F_MAX; 111 + unsigned int channel = pwm->hwpwm; 112 + u32 value; 113 + 114 + /* 115 + * If asking for a duty_ns equal to period_ns, we need to substract 116 + * the period value by 1 to make it shorter than the "on" time and 117 + * produce a flat 100% duty cycle signal, and max out the "on" time 118 + */ 119 + if (duty_ns == period_ns) { 120 + dc = PWM_ON_PERIOD_MAX; 121 + pc = PWM_ON_PERIOD_MAX - 1; 122 + goto done; 123 + } 124 + 125 + while (1) { 126 + u64 rate, tmp; 127 + 128 + /* 129 + * Calculate the base rate from base frequency and current 130 + * cword 131 + */ 132 + rate = (u64)clk_get_rate(p->clk) * (u64)cword; 133 + do_div(rate, 1 << CWORD_BIT_SIZE); 134 + 135 + tmp = period_ns * rate; 136 + do_div(tmp, NSEC_PER_SEC); 137 + pc = tmp; 138 + 139 + tmp = (duty_ns + 1) * rate; 140 + do_div(tmp, NSEC_PER_SEC); 141 + dc = tmp; 142 + 143 + /* 144 + * We can be called with separate duty and period updates, 145 + * so do not reject dc == 0 right away 146 + */ 147 + if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns)) 148 + return -EINVAL; 149 + 150 + /* We converged on a calculation */ 151 + if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX) 152 + break; 153 + 154 + /* 155 + * The cword needs to be a power of 2 for the variable 156 + * frequency generator to output a 50% duty cycle variable 157 + * frequency which is used as input clock to the fixed 158 + * frequency generator. 159 + */ 160 + cword >>= 1; 161 + 162 + /* 163 + * Desired periods are too large, we do not have a divider 164 + * for them 165 + */ 166 + if (cword < CONST_VAR_F_MIN) 167 + return -EINVAL; 168 + } 169 + 170 + done: 171 + /* 172 + * Configure the defined "cword" value to have the variable frequency 173 + * generator output a base frequency for the constant frequency 174 + * generator to derive from. 175 + */ 176 + spin_lock(&p->lock); 177 + brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel)); 178 + brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel)); 179 + 180 + /* Select constant frequency signal output */ 181 + value = brcmstb_pwm_readl(p, PWM_CTRL2); 182 + value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS); 183 + brcmstb_pwm_writel(p, value, PWM_CTRL2); 184 + 185 + /* Configure on and period value */ 186 + brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel)); 187 + brcmstb_pwm_writel(p, dc, PWM_ON(channel)); 188 + spin_unlock(&p->lock); 189 + 190 + return 0; 191 + } 192 + 193 + static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p, 194 + unsigned int channel, bool enable) 195 + { 196 + unsigned int shift = channel * CTRL_CHAN_OFFS; 197 + u32 value; 198 + 199 + spin_lock(&p->lock); 200 + value = brcmstb_pwm_readl(p, PWM_CTRL); 201 + 202 + if (enable) { 203 + value &= ~(CTRL_OEB << shift); 204 + value |= (CTRL_START | CTRL_OPENDRAIN) << shift; 205 + } else { 206 + value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift); 207 + value |= CTRL_OEB << shift; 208 + } 209 + 210 + brcmstb_pwm_writel(p, value, PWM_CTRL); 211 + spin_unlock(&p->lock); 212 + } 213 + 214 + static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 215 + { 216 + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); 217 + 218 + brcmstb_pwm_enable_set(p, pwm->hwpwm, true); 219 + 220 + return 0; 221 + } 222 + 223 + static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 224 + { 225 + struct brcmstb_pwm *p = to_brcmstb_pwm(chip); 226 + 227 + brcmstb_pwm_enable_set(p, pwm->hwpwm, false); 228 + } 229 + 230 + static const struct pwm_ops brcmstb_pwm_ops = { 231 + .config = brcmstb_pwm_config, 232 + .enable = brcmstb_pwm_enable, 233 + .disable = brcmstb_pwm_disable, 234 + .owner = THIS_MODULE, 235 + }; 236 + 237 + static const struct of_device_id brcmstb_pwm_of_match[] = { 238 + { .compatible = "brcm,bcm7038-pwm", }, 239 + { /* sentinel */ } 240 + }; 241 + MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match); 242 + 243 + static int brcmstb_pwm_probe(struct platform_device *pdev) 244 + { 245 + struct brcmstb_pwm *p; 246 + struct resource *res; 247 + int ret; 248 + 249 + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 250 + if (!p) 251 + return -ENOMEM; 252 + 253 + spin_lock_init(&p->lock); 254 + 255 + p->clk = devm_clk_get(&pdev->dev, NULL); 256 + if (IS_ERR(p->clk)) { 257 + dev_err(&pdev->dev, "failed to obtain clock\n"); 258 + return PTR_ERR(p->clk); 259 + } 260 + 261 + ret = clk_prepare_enable(p->clk); 262 + if (ret < 0) { 263 + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); 264 + return ret; 265 + } 266 + 267 + platform_set_drvdata(pdev, p); 268 + 269 + p->chip.dev = &pdev->dev; 270 + p->chip.ops = &brcmstb_pwm_ops; 271 + p->chip.base = -1; 272 + p->chip.npwm = 2; 273 + p->chip.can_sleep = true; 274 + 275 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 276 + p->base = devm_ioremap_resource(&pdev->dev, res); 277 + if (!p->base) { 278 + ret = -ENOMEM; 279 + goto out_clk; 280 + } 281 + 282 + ret = pwmchip_add(&p->chip); 283 + if (ret) { 284 + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 285 + goto out_clk; 286 + } 287 + 288 + return 0; 289 + 290 + out_clk: 291 + clk_disable_unprepare(p->clk); 292 + return ret; 293 + } 294 + 295 + static int brcmstb_pwm_remove(struct platform_device *pdev) 296 + { 297 + struct brcmstb_pwm *p = platform_get_drvdata(pdev); 298 + int ret; 299 + 300 + ret = pwmchip_remove(&p->chip); 301 + clk_disable_unprepare(p->clk); 302 + 303 + return ret; 304 + } 305 + 306 + #ifdef CONFIG_PM_SLEEP 307 + static int brcmstb_pwm_suspend(struct device *dev) 308 + { 309 + struct brcmstb_pwm *p = dev_get_drvdata(dev); 310 + 311 + clk_disable(p->clk); 312 + 313 + return 0; 314 + } 315 + 316 + static int brcmstb_pwm_resume(struct device *dev) 317 + { 318 + struct brcmstb_pwm *p = dev_get_drvdata(dev); 319 + 320 + clk_enable(p->clk); 321 + 322 + return 0; 323 + } 324 + #endif 325 + 326 + static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend, 327 + brcmstb_pwm_resume); 328 + 329 + static struct platform_driver brcmstb_pwm_driver = { 330 + .probe = brcmstb_pwm_probe, 331 + .remove = brcmstb_pwm_remove, 332 + .driver = { 333 + .name = "pwm-brcmstb", 334 + .of_match_table = brcmstb_pwm_of_match, 335 + .pm = &brcmstb_pwm_pm_ops, 336 + }, 337 + }; 338 + module_platform_driver(brcmstb_pwm_driver); 339 + 340 + MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>"); 341 + MODULE_DESCRIPTION("Broadcom STB PWM driver"); 342 + MODULE_ALIAS("platform:pwm-brcmstb"); 343 + MODULE_LICENSE("GPL");
+35 -2
drivers/pwm/pwm-lpss-pci.c
··· 13 13 #include <linux/kernel.h> 14 14 #include <linux/module.h> 15 15 #include <linux/pci.h> 16 + #include <linux/pm_runtime.h> 16 17 17 18 #include "pwm-lpss.h" 18 19 ··· 34 33 return PTR_ERR(lpwm); 35 34 36 35 pci_set_drvdata(pdev, lpwm); 36 + 37 + pm_runtime_put(&pdev->dev); 38 + pm_runtime_allow(&pdev->dev); 39 + 37 40 return 0; 38 41 } 39 42 ··· 45 40 { 46 41 struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); 47 42 43 + pm_runtime_forbid(&pdev->dev); 44 + pm_runtime_get_sync(&pdev->dev); 45 + 48 46 pwm_lpss_remove(lpwm); 49 47 } 50 48 49 + #ifdef CONFIG_PM 50 + static int pwm_lpss_runtime_suspend_pci(struct device *dev) 51 + { 52 + /* 53 + * The PCI core will handle transition to D3 automatically. We only 54 + * need to provide runtime PM hooks for that to happen. 55 + */ 56 + return 0; 57 + } 58 + 59 + static int pwm_lpss_runtime_resume_pci(struct device *dev) 60 + { 61 + return 0; 62 + } 63 + #endif 64 + 65 + static const struct dev_pm_ops pwm_lpss_pci_pm = { 66 + SET_RUNTIME_PM_OPS(pwm_lpss_runtime_suspend_pci, 67 + pwm_lpss_runtime_resume_pci, NULL) 68 + }; 69 + 51 70 static const struct pci_device_id pwm_lpss_pci_ids[] = { 52 - { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bsw_info}, 71 + { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info}, 53 72 { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info}, 54 73 { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info}, 55 - { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bsw_info}, 74 + { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info}, 56 75 { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info}, 57 76 { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info}, 77 + { PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info}, 58 78 { }, 59 79 }; 60 80 MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); ··· 89 59 .id_table = pwm_lpss_pci_ids, 90 60 .probe = pwm_lpss_probe_pci, 91 61 .remove = pwm_lpss_remove_pci, 62 + .driver = { 63 + .pm = &pwm_lpss_pci_pm, 64 + }, 92 65 }; 93 66 module_pci_driver(pwm_lpss_driver_pci); 94 67
+7
drivers/pwm/pwm-lpss-platform.c
··· 14 14 #include <linux/kernel.h> 15 15 #include <linux/module.h> 16 16 #include <linux/platform_device.h> 17 + #include <linux/pm_runtime.h> 17 18 18 19 #include "pwm-lpss.h" 19 20 ··· 37 36 return PTR_ERR(lpwm); 38 37 39 38 platform_set_drvdata(pdev, lpwm); 39 + 40 + pm_runtime_set_active(&pdev->dev); 41 + pm_runtime_enable(&pdev->dev); 42 + 40 43 return 0; 41 44 } 42 45 ··· 48 43 { 49 44 struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); 50 45 46 + pm_runtime_disable(&pdev->dev); 51 47 return pwm_lpss_remove(lpwm); 52 48 } 53 49 54 50 static const struct acpi_device_id pwm_lpss_acpi_match[] = { 55 51 { "80860F09", (unsigned long)&pwm_lpss_byt_info }, 56 52 { "80862288", (unsigned long)&pwm_lpss_bsw_info }, 53 + { "80865AC8", (unsigned long)&pwm_lpss_bxt_info }, 57 54 { }, 58 55 }; 59 56 MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
+41 -21
drivers/pwm/pwm-lpss.c
··· 16 16 #include <linux/io.h> 17 17 #include <linux/kernel.h> 18 18 #include <linux/module.h> 19 + #include <linux/pm_runtime.h> 19 20 20 21 #include "pwm-lpss.h" 21 22 ··· 30 29 #define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) 31 30 #define NSECS_PER_SEC 1000000000UL 32 31 32 + /* Size of each PWM register space if multiple */ 33 + #define PWM_SIZE 0x400 34 + 33 35 struct pwm_lpss_chip { 34 36 struct pwm_chip chip; 35 37 void __iomem *regs; ··· 41 37 42 38 /* BayTrail */ 43 39 const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { 44 - .clk_rate = 25000000 40 + .clk_rate = 25000000, 41 + .npwm = 1, 45 42 }; 46 43 EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); 47 44 48 45 /* Braswell */ 49 46 const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { 50 - .clk_rate = 19200000 47 + .clk_rate = 19200000, 48 + .npwm = 1, 51 49 }; 52 50 EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); 51 + 52 + /* Broxton */ 53 + const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = { 54 + .clk_rate = 19200000, 55 + .npwm = 4, 56 + }; 57 + EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info); 53 58 54 59 static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 55 60 { 56 61 return container_of(chip, struct pwm_lpss_chip, chip); 62 + } 63 + 64 + static inline u32 pwm_lpss_read(const struct pwm_device *pwm) 65 + { 66 + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); 67 + 68 + return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); 69 + } 70 + 71 + static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) 72 + { 73 + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); 74 + 75 + writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); 57 76 } 58 77 59 78 static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, ··· 106 79 duty_ns = 1; 107 80 on_time_div = 255 - (255 * duty_ns / period_ns); 108 81 109 - ctrl = readl(lpwm->regs + PWM); 82 + pm_runtime_get_sync(chip->dev); 83 + 84 + ctrl = pwm_lpss_read(pwm); 110 85 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); 111 86 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; 112 87 ctrl |= on_time_div; 113 88 /* request PWM to update on next cycle */ 114 89 ctrl |= PWM_SW_UPDATE; 115 - writel(ctrl, lpwm->regs + PWM); 90 + pwm_lpss_write(pwm, ctrl); 91 + 92 + pm_runtime_put(chip->dev); 116 93 117 94 return 0; 118 95 } 119 96 120 97 static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) 121 98 { 122 - struct pwm_lpss_chip *lpwm = to_lpwm(chip); 123 - u32 ctrl; 124 - 125 - ctrl = readl(lpwm->regs + PWM); 126 - writel(ctrl | PWM_ENABLE, lpwm->regs + PWM); 127 - 99 + pm_runtime_get_sync(chip->dev); 100 + pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); 128 101 return 0; 129 102 } 130 103 131 104 static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) 132 105 { 133 - struct pwm_lpss_chip *lpwm = to_lpwm(chip); 134 - u32 ctrl; 135 - 136 - ctrl = readl(lpwm->regs + PWM); 137 - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); 106 + pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); 107 + pm_runtime_put(chip->dev); 138 108 } 139 109 140 110 static const struct pwm_ops pwm_lpss_ops = { 111 + .free = pwm_lpss_disable, 141 112 .config = pwm_lpss_config, 142 113 .enable = pwm_lpss_enable, 143 114 .disable = pwm_lpss_disable, ··· 160 135 lpwm->chip.dev = dev; 161 136 lpwm->chip.ops = &pwm_lpss_ops; 162 137 lpwm->chip.base = -1; 163 - lpwm->chip.npwm = 1; 138 + lpwm->chip.npwm = info->npwm; 164 139 165 140 ret = pwmchip_add(&lpwm->chip); 166 141 if (ret) { ··· 174 149 175 150 int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 176 151 { 177 - u32 ctrl; 178 - 179 - ctrl = readl(lpwm->regs + PWM); 180 - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); 181 - 182 152 return pwmchip_remove(&lpwm->chip); 183 153 } 184 154 EXPORT_SYMBOL_GPL(pwm_lpss_remove);
+2
drivers/pwm/pwm-lpss.h
··· 20 20 21 21 struct pwm_lpss_boardinfo { 22 22 unsigned long clk_rate; 23 + unsigned int npwm; 23 24 }; 24 25 25 26 extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info; 26 27 extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info; 28 + extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info; 27 29 28 30 struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, 29 31 const struct pwm_lpss_boardinfo *info);
+243
drivers/pwm/pwm-mtk-disp.c
··· 1 + /* 2 + * MediaTek display pulse-width-modulation controller driver. 3 + * Copyright (c) 2015 MediaTek Inc. 4 + * Author: YH Huang <yh.huang@mediatek.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <linux/clk.h> 17 + #include <linux/err.h> 18 + #include <linux/io.h> 19 + #include <linux/module.h> 20 + #include <linux/of.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/pwm.h> 23 + #include <linux/slab.h> 24 + 25 + #define DISP_PWM_EN 0x00 26 + #define PWM_ENABLE_MASK BIT(0) 27 + 28 + #define DISP_PWM_COMMIT 0x08 29 + #define PWM_COMMIT_MASK BIT(0) 30 + 31 + #define DISP_PWM_CON_0 0x10 32 + #define PWM_CLKDIV_SHIFT 16 33 + #define PWM_CLKDIV_MAX 0x3ff 34 + #define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT) 35 + 36 + #define DISP_PWM_CON_1 0x14 37 + #define PWM_PERIOD_BIT_WIDTH 12 38 + #define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1) 39 + 40 + #define PWM_HIGH_WIDTH_SHIFT 16 41 + #define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT) 42 + 43 + struct mtk_disp_pwm { 44 + struct pwm_chip chip; 45 + struct clk *clk_main; 46 + struct clk *clk_mm; 47 + void __iomem *base; 48 + }; 49 + 50 + static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip) 51 + { 52 + return container_of(chip, struct mtk_disp_pwm, chip); 53 + } 54 + 55 + static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset, 56 + u32 mask, u32 data) 57 + { 58 + void __iomem *address = mdp->base + offset; 59 + u32 value; 60 + 61 + value = readl(address); 62 + value &= ~mask; 63 + value |= data; 64 + writel(value, address); 65 + } 66 + 67 + static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 68 + int duty_ns, int period_ns) 69 + { 70 + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); 71 + u32 clk_div, period, high_width, value; 72 + u64 div, rate; 73 + int err; 74 + 75 + /* 76 + * Find period, high_width and clk_div to suit duty_ns and period_ns. 77 + * Calculate proper div value to keep period value in the bound. 78 + * 79 + * period_ns = 10^9 * (clk_div + 1) * (period + 1) / PWM_CLK_RATE 80 + * duty_ns = 10^9 * (clk_div + 1) * high_width / PWM_CLK_RATE 81 + * 82 + * period = (PWM_CLK_RATE * period_ns) / (10^9 * (clk_div + 1)) - 1 83 + * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1)) 84 + */ 85 + rate = clk_get_rate(mdp->clk_main); 86 + clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >> 87 + PWM_PERIOD_BIT_WIDTH; 88 + if (clk_div > PWM_CLKDIV_MAX) 89 + return -EINVAL; 90 + 91 + div = NSEC_PER_SEC * (clk_div + 1); 92 + period = div64_u64(rate * period_ns, div); 93 + if (period > 0) 94 + period--; 95 + 96 + high_width = div64_u64(rate * duty_ns, div); 97 + value = period | (high_width << PWM_HIGH_WIDTH_SHIFT); 98 + 99 + err = clk_enable(mdp->clk_main); 100 + if (err < 0) 101 + return err; 102 + 103 + err = clk_enable(mdp->clk_mm); 104 + if (err < 0) { 105 + clk_disable(mdp->clk_main); 106 + return err; 107 + } 108 + 109 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK, 110 + clk_div << PWM_CLKDIV_SHIFT); 111 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1, 112 + PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value); 113 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1); 114 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0); 115 + 116 + clk_disable(mdp->clk_mm); 117 + clk_disable(mdp->clk_main); 118 + 119 + return 0; 120 + } 121 + 122 + static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 123 + { 124 + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); 125 + int err; 126 + 127 + err = clk_enable(mdp->clk_main); 128 + if (err < 0) 129 + return err; 130 + 131 + err = clk_enable(mdp->clk_mm); 132 + if (err < 0) { 133 + clk_disable(mdp->clk_main); 134 + return err; 135 + } 136 + 137 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1); 138 + 139 + return 0; 140 + } 141 + 142 + static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 143 + { 144 + struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip); 145 + 146 + mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0); 147 + 148 + clk_disable(mdp->clk_mm); 149 + clk_disable(mdp->clk_main); 150 + } 151 + 152 + static const struct pwm_ops mtk_disp_pwm_ops = { 153 + .config = mtk_disp_pwm_config, 154 + .enable = mtk_disp_pwm_enable, 155 + .disable = mtk_disp_pwm_disable, 156 + .owner = THIS_MODULE, 157 + }; 158 + 159 + static int mtk_disp_pwm_probe(struct platform_device *pdev) 160 + { 161 + struct mtk_disp_pwm *mdp; 162 + struct resource *r; 163 + int ret; 164 + 165 + mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL); 166 + if (!mdp) 167 + return -ENOMEM; 168 + 169 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 170 + mdp->base = devm_ioremap_resource(&pdev->dev, r); 171 + if (IS_ERR(mdp->base)) 172 + return PTR_ERR(mdp->base); 173 + 174 + mdp->clk_main = devm_clk_get(&pdev->dev, "main"); 175 + if (IS_ERR(mdp->clk_main)) 176 + return PTR_ERR(mdp->clk_main); 177 + 178 + mdp->clk_mm = devm_clk_get(&pdev->dev, "mm"); 179 + if (IS_ERR(mdp->clk_mm)) 180 + return PTR_ERR(mdp->clk_mm); 181 + 182 + ret = clk_prepare(mdp->clk_main); 183 + if (ret < 0) 184 + return ret; 185 + 186 + ret = clk_prepare(mdp->clk_mm); 187 + if (ret < 0) 188 + goto disable_clk_main; 189 + 190 + mdp->chip.dev = &pdev->dev; 191 + mdp->chip.ops = &mtk_disp_pwm_ops; 192 + mdp->chip.base = -1; 193 + mdp->chip.npwm = 1; 194 + 195 + ret = pwmchip_add(&mdp->chip); 196 + if (ret < 0) { 197 + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 198 + goto disable_clk_mm; 199 + } 200 + 201 + platform_set_drvdata(pdev, mdp); 202 + 203 + return 0; 204 + 205 + disable_clk_mm: 206 + clk_unprepare(mdp->clk_mm); 207 + disable_clk_main: 208 + clk_unprepare(mdp->clk_main); 209 + return ret; 210 + } 211 + 212 + static int mtk_disp_pwm_remove(struct platform_device *pdev) 213 + { 214 + struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev); 215 + int ret; 216 + 217 + ret = pwmchip_remove(&mdp->chip); 218 + clk_unprepare(mdp->clk_mm); 219 + clk_unprepare(mdp->clk_main); 220 + 221 + return ret; 222 + } 223 + 224 + static const struct of_device_id mtk_disp_pwm_of_match[] = { 225 + { .compatible = "mediatek,mt8173-disp-pwm" }, 226 + { .compatible = "mediatek,mt6595-disp-pwm" }, 227 + { } 228 + }; 229 + MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match); 230 + 231 + static struct platform_driver mtk_disp_pwm_driver = { 232 + .driver = { 233 + .name = "mediatek-disp-pwm", 234 + .of_match_table = mtk_disp_pwm_of_match, 235 + }, 236 + .probe = mtk_disp_pwm_probe, 237 + .remove = mtk_disp_pwm_remove, 238 + }; 239 + module_platform_driver(mtk_disp_pwm_driver); 240 + 241 + MODULE_AUTHOR("YH Huang <yh.huang@mediatek.com>"); 242 + MODULE_DESCRIPTION("MediaTek SoC display PWM driver"); 243 + MODULE_LICENSE("GPL v2");
+16 -4
drivers/pwm/pwm-pca9685.c
··· 19 19 * this program. If not, see <http://www.gnu.org/licenses/>. 20 20 */ 21 21 22 + #include <linux/acpi.h> 22 23 #include <linux/i2c.h> 23 24 #include <linux/module.h> 24 25 #include <linux/platform_device.h> 26 + #include <linux/property.h> 25 27 #include <linux/pwm.h> 26 28 #include <linux/regmap.h> 27 29 #include <linux/slab.h> ··· 299 297 static int pca9685_pwm_probe(struct i2c_client *client, 300 298 const struct i2c_device_id *id) 301 299 { 302 - struct device_node *np = client->dev.of_node; 303 300 struct pca9685 *pca; 304 301 int ret; 305 302 int mode2; ··· 321 320 322 321 regmap_read(pca->regmap, PCA9685_MODE2, &mode2); 323 322 324 - if (of_property_read_bool(np, "invert")) 323 + if (device_property_read_bool(&client->dev, "invert")) 325 324 mode2 |= MODE2_INVRT; 326 325 else 327 326 mode2 &= ~MODE2_INVRT; 328 327 329 - if (of_property_read_bool(np, "open-drain")) 328 + if (device_property_read_bool(&client->dev, "open-drain")) 330 329 mode2 &= ~MODE2_OUTDRV; 331 330 else 332 331 mode2 |= MODE2_OUTDRV; ··· 364 363 }; 365 364 MODULE_DEVICE_TABLE(i2c, pca9685_id); 366 365 366 + #ifdef CONFIG_ACPI 367 + static const struct acpi_device_id pca9685_acpi_ids[] = { 368 + { "INT3492", 0 }, 369 + { /* sentinel */ }, 370 + }; 371 + MODULE_DEVICE_TABLE(acpi, pca9685_acpi_ids); 372 + #endif 373 + 374 + #ifdef CONFIG_OF 367 375 static const struct of_device_id pca9685_dt_ids[] = { 368 376 { .compatible = "nxp,pca9685-pwm", }, 369 377 { /* sentinel */ } 370 378 }; 371 379 MODULE_DEVICE_TABLE(of, pca9685_dt_ids); 380 + #endif 372 381 373 382 static struct i2c_driver pca9685_i2c_driver = { 374 383 .driver = { 375 384 .name = "pca9685-pwm", 376 - .of_match_table = pca9685_dt_ids, 385 + .acpi_match_table = ACPI_PTR(pca9685_acpi_ids), 386 + .of_match_table = of_match_ptr(pca9685_dt_ids), 377 387 }, 378 388 .probe = pca9685_pwm_probe, 379 389 .remove = pca9685_pwm_remove,
+274
drivers/pwm/pwm-rcar.c
··· 1 + /* 2 + * R-Car PWM Timer driver 3 + * 4 + * Copyright (C) 2015 Renesas Electronics Corporation 5 + * 6 + * This is free software; you can redistribute it and/or modify 7 + * it under the terms of version 2 of the GNU General Public License as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/err.h> 13 + #include <linux/io.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/pm_runtime.h> 18 + #include <linux/pwm.h> 19 + #include <linux/slab.h> 20 + 21 + #define RCAR_PWM_MAX_DIVISION 24 22 + #define RCAR_PWM_MAX_CYCLE 1023 23 + 24 + #define RCAR_PWMCR 0x00 25 + #define RCAR_PWMCR_CC0_MASK 0x000f0000 26 + #define RCAR_PWMCR_CC0_SHIFT 16 27 + #define RCAR_PWMCR_CCMD BIT(15) 28 + #define RCAR_PWMCR_SYNC BIT(11) 29 + #define RCAR_PWMCR_SS0 BIT(4) 30 + #define RCAR_PWMCR_EN0 BIT(0) 31 + 32 + #define RCAR_PWMCNT 0x04 33 + #define RCAR_PWMCNT_CYC0_MASK 0x03ff0000 34 + #define RCAR_PWMCNT_CYC0_SHIFT 16 35 + #define RCAR_PWMCNT_PH0_MASK 0x000003ff 36 + #define RCAR_PWMCNT_PH0_SHIFT 0 37 + 38 + struct rcar_pwm_chip { 39 + struct pwm_chip chip; 40 + void __iomem *base; 41 + struct clk *clk; 42 + }; 43 + 44 + static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip) 45 + { 46 + return container_of(chip, struct rcar_pwm_chip, chip); 47 + } 48 + 49 + static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data, 50 + unsigned int offset) 51 + { 52 + writel(data, rp->base + offset); 53 + } 54 + 55 + static u32 rcar_pwm_read(struct rcar_pwm_chip *rp, unsigned int offset) 56 + { 57 + return readl(rp->base + offset); 58 + } 59 + 60 + static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data, 61 + unsigned int offset) 62 + { 63 + u32 value; 64 + 65 + value = rcar_pwm_read(rp, offset); 66 + value &= ~mask; 67 + value |= data & mask; 68 + rcar_pwm_write(rp, value, offset); 69 + } 70 + 71 + static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns) 72 + { 73 + unsigned long clk_rate = clk_get_rate(rp->clk); 74 + unsigned long long max; /* max cycle / nanoseconds */ 75 + unsigned int div; 76 + 77 + if (clk_rate == 0) 78 + return -EINVAL; 79 + 80 + for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) { 81 + max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE * 82 + (1 << div); 83 + do_div(max, clk_rate); 84 + if (period_ns < max) 85 + break; 86 + } 87 + 88 + return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE; 89 + } 90 + 91 + static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp, 92 + unsigned int div) 93 + { 94 + u32 value; 95 + 96 + value = rcar_pwm_read(rp, RCAR_PWMCR); 97 + value &= ~(RCAR_PWMCR_CCMD | RCAR_PWMCR_CC0_MASK); 98 + 99 + if (div & 1) 100 + value |= RCAR_PWMCR_CCMD; 101 + 102 + div >>= 1; 103 + 104 + value |= div << RCAR_PWMCR_CC0_SHIFT; 105 + rcar_pwm_write(rp, value, RCAR_PWMCR); 106 + } 107 + 108 + static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns, 109 + int period_ns) 110 + { 111 + unsigned long long one_cycle, tmp; /* 0.01 nanoseconds */ 112 + unsigned long clk_rate = clk_get_rate(rp->clk); 113 + u32 cyc, ph; 114 + 115 + one_cycle = (unsigned long long)NSEC_PER_SEC * 100ULL * (1 << div); 116 + do_div(one_cycle, clk_rate); 117 + 118 + tmp = period_ns * 100ULL; 119 + do_div(tmp, one_cycle); 120 + cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK; 121 + 122 + tmp = duty_ns * 100ULL; 123 + do_div(tmp, one_cycle); 124 + ph = tmp & RCAR_PWMCNT_PH0_MASK; 125 + 126 + /* Avoid prohibited setting */ 127 + if (cyc == 0 || ph == 0) 128 + return -EINVAL; 129 + 130 + rcar_pwm_write(rp, cyc | ph, RCAR_PWMCNT); 131 + 132 + return 0; 133 + } 134 + 135 + static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 136 + { 137 + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 138 + 139 + return clk_prepare_enable(rp->clk); 140 + } 141 + 142 + static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 143 + { 144 + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 145 + 146 + clk_disable_unprepare(rp->clk); 147 + } 148 + 149 + static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 150 + int duty_ns, int period_ns) 151 + { 152 + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 153 + int div, ret; 154 + 155 + div = rcar_pwm_get_clock_division(rp, period_ns); 156 + if (div < 0) 157 + return div; 158 + 159 + /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ 160 + if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns) 161 + return 0; 162 + 163 + rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); 164 + 165 + ret = rcar_pwm_set_counter(rp, div, duty_ns, period_ns); 166 + if (!ret) 167 + rcar_pwm_set_clock_control(rp, div); 168 + 169 + /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */ 170 + rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR); 171 + 172 + return ret; 173 + } 174 + 175 + static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 176 + { 177 + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 178 + u32 value; 179 + 180 + /* Don't enable the PWM device if CYC0 or PH0 is 0 */ 181 + value = rcar_pwm_read(rp, RCAR_PWMCNT); 182 + if ((value & RCAR_PWMCNT_CYC0_MASK) == 0 || 183 + (value & RCAR_PWMCNT_PH0_MASK) == 0) 184 + return -EINVAL; 185 + 186 + rcar_pwm_update(rp, RCAR_PWMCR_EN0, RCAR_PWMCR_EN0, RCAR_PWMCR); 187 + 188 + return 0; 189 + } 190 + 191 + static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 192 + { 193 + struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); 194 + 195 + rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR); 196 + } 197 + 198 + static const struct pwm_ops rcar_pwm_ops = { 199 + .request = rcar_pwm_request, 200 + .free = rcar_pwm_free, 201 + .config = rcar_pwm_config, 202 + .enable = rcar_pwm_enable, 203 + .disable = rcar_pwm_disable, 204 + .owner = THIS_MODULE, 205 + }; 206 + 207 + static int rcar_pwm_probe(struct platform_device *pdev) 208 + { 209 + struct rcar_pwm_chip *rcar_pwm; 210 + struct resource *res; 211 + int ret; 212 + 213 + rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL); 214 + if (rcar_pwm == NULL) 215 + return -ENOMEM; 216 + 217 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 218 + rcar_pwm->base = devm_ioremap_resource(&pdev->dev, res); 219 + if (IS_ERR(rcar_pwm->base)) 220 + return PTR_ERR(rcar_pwm->base); 221 + 222 + rcar_pwm->clk = devm_clk_get(&pdev->dev, NULL); 223 + if (IS_ERR(rcar_pwm->clk)) { 224 + dev_err(&pdev->dev, "cannot get clock\n"); 225 + return PTR_ERR(rcar_pwm->clk); 226 + } 227 + 228 + platform_set_drvdata(pdev, rcar_pwm); 229 + 230 + rcar_pwm->chip.dev = &pdev->dev; 231 + rcar_pwm->chip.ops = &rcar_pwm_ops; 232 + rcar_pwm->chip.base = -1; 233 + rcar_pwm->chip.npwm = 1; 234 + 235 + ret = pwmchip_add(&rcar_pwm->chip); 236 + if (ret < 0) { 237 + dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret); 238 + return ret; 239 + } 240 + 241 + pm_runtime_enable(&pdev->dev); 242 + 243 + return 0; 244 + } 245 + 246 + static int rcar_pwm_remove(struct platform_device *pdev) 247 + { 248 + struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); 249 + 250 + pm_runtime_disable(&pdev->dev); 251 + 252 + return pwmchip_remove(&rcar_pwm->chip); 253 + } 254 + 255 + static const struct of_device_id rcar_pwm_of_table[] = { 256 + { .compatible = "renesas,pwm-rcar", }, 257 + { }, 258 + }; 259 + MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); 260 + 261 + static struct platform_driver rcar_pwm_driver = { 262 + .probe = rcar_pwm_probe, 263 + .remove = rcar_pwm_remove, 264 + .driver = { 265 + .name = "pwm-rcar", 266 + .of_match_table = of_match_ptr(rcar_pwm_of_table), 267 + } 268 + }; 269 + module_platform_driver(rcar_pwm_driver); 270 + 271 + MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>"); 272 + MODULE_DESCRIPTION("Renesas PWM Timer Driver"); 273 + MODULE_LICENSE("GPL v2"); 274 + MODULE_ALIAS("platform:pwm-rcar");
+24 -3
drivers/pwm/pwm-sun4i.c
··· 68 68 struct sun4i_pwm_data { 69 69 bool has_prescaler_bypass; 70 70 bool has_rdy; 71 + unsigned int npwm; 71 72 }; 72 73 73 74 struct sun4i_pwm_chip { ··· 115 114 * is not an integer so round it half up instead of 116 115 * truncating to get less surprising values. 117 116 */ 118 - div = clk_rate * period_ns + NSEC_PER_SEC/2; 117 + div = clk_rate * period_ns + NSEC_PER_SEC / 2; 119 118 do_div(div, NSEC_PER_SEC); 120 119 if (div - 1 > PWM_PRD_MASK) 121 120 prescaler = 0; ··· 263 262 static const struct sun4i_pwm_data sun4i_pwm_data_a10 = { 264 263 .has_prescaler_bypass = false, 265 264 .has_rdy = false, 265 + .npwm = 2, 266 + }; 267 + 268 + static const struct sun4i_pwm_data sun4i_pwm_data_a10s = { 269 + .has_prescaler_bypass = true, 270 + .has_rdy = true, 271 + .npwm = 2, 272 + }; 273 + 274 + static const struct sun4i_pwm_data sun4i_pwm_data_a13 = { 275 + .has_prescaler_bypass = true, 276 + .has_rdy = true, 277 + .npwm = 1, 266 278 }; 267 279 268 280 static const struct sun4i_pwm_data sun4i_pwm_data_a20 = { 269 281 .has_prescaler_bypass = true, 270 282 .has_rdy = true, 283 + .npwm = 2, 271 284 }; 272 285 273 286 static const struct of_device_id sun4i_pwm_dt_ids[] = { 274 287 { 275 288 .compatible = "allwinner,sun4i-a10-pwm", 276 289 .data = &sun4i_pwm_data_a10, 290 + }, { 291 + .compatible = "allwinner,sun5i-a10s-pwm", 292 + .data = &sun4i_pwm_data_a10s, 293 + }, { 294 + .compatible = "allwinner,sun5i-a13-pwm", 295 + .data = &sun4i_pwm_data_a13, 277 296 }, { 278 297 .compatible = "allwinner,sun7i-a20-pwm", 279 298 .data = &sun4i_pwm_data_a20, ··· 326 305 if (IS_ERR(pwm->clk)) 327 306 return PTR_ERR(pwm->clk); 328 307 308 + pwm->data = match->data; 329 309 pwm->chip.dev = &pdev->dev; 330 310 pwm->chip.ops = &sun4i_pwm_ops; 331 311 pwm->chip.base = -1; 332 - pwm->chip.npwm = 2; 312 + pwm->chip.npwm = pwm->data->npwm; 333 313 pwm->chip.can_sleep = true; 334 314 pwm->chip.of_xlate = of_pwm_xlate_with_flags; 335 315 pwm->chip.of_pwm_n_cells = 3; 336 - pwm->data = match->data; 337 316 338 317 spin_lock_init(&pwm->ctrl_lock); 339 318
+37 -38
drivers/pwm/sysfs.c
··· 40 40 return export->pwm; 41 41 } 42 42 43 - static ssize_t pwm_period_show(struct device *child, 44 - struct device_attribute *attr, 45 - char *buf) 43 + static ssize_t period_show(struct device *child, 44 + struct device_attribute *attr, 45 + char *buf) 46 46 { 47 47 const struct pwm_device *pwm = child_to_pwm_device(child); 48 48 49 49 return sprintf(buf, "%u\n", pwm_get_period(pwm)); 50 50 } 51 51 52 - static ssize_t pwm_period_store(struct device *child, 53 - struct device_attribute *attr, 54 - const char *buf, size_t size) 52 + static ssize_t period_store(struct device *child, 53 + struct device_attribute *attr, 54 + const char *buf, size_t size) 55 55 { 56 56 struct pwm_device *pwm = child_to_pwm_device(child); 57 57 unsigned int val; ··· 66 66 return ret ? : size; 67 67 } 68 68 69 - static ssize_t pwm_duty_cycle_show(struct device *child, 70 - struct device_attribute *attr, 71 - char *buf) 69 + static ssize_t duty_cycle_show(struct device *child, 70 + struct device_attribute *attr, 71 + char *buf) 72 72 { 73 73 const struct pwm_device *pwm = child_to_pwm_device(child); 74 74 75 75 return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); 76 76 } 77 77 78 - static ssize_t pwm_duty_cycle_store(struct device *child, 79 - struct device_attribute *attr, 80 - const char *buf, size_t size) 78 + static ssize_t duty_cycle_store(struct device *child, 79 + struct device_attribute *attr, 80 + const char *buf, size_t size) 81 81 { 82 82 struct pwm_device *pwm = child_to_pwm_device(child); 83 83 unsigned int val; ··· 92 92 return ret ? : size; 93 93 } 94 94 95 - static ssize_t pwm_enable_show(struct device *child, 96 - struct device_attribute *attr, 97 - char *buf) 95 + static ssize_t enable_show(struct device *child, 96 + struct device_attribute *attr, 97 + char *buf) 98 98 { 99 99 const struct pwm_device *pwm = child_to_pwm_device(child); 100 - int enabled = pwm_is_enabled(pwm); 101 100 102 - return sprintf(buf, "%d\n", enabled); 101 + return sprintf(buf, "%d\n", pwm_is_enabled(pwm)); 103 102 } 104 103 105 - static ssize_t pwm_enable_store(struct device *child, 106 - struct device_attribute *attr, 107 - const char *buf, size_t size) 104 + static ssize_t enable_store(struct device *child, 105 + struct device_attribute *attr, 106 + const char *buf, size_t size) 108 107 { 109 108 struct pwm_device *pwm = child_to_pwm_device(child); 110 109 int val, ret; ··· 127 128 return ret ? : size; 128 129 } 129 130 130 - static ssize_t pwm_polarity_show(struct device *child, 131 - struct device_attribute *attr, 132 - char *buf) 131 + static ssize_t polarity_show(struct device *child, 132 + struct device_attribute *attr, 133 + char *buf) 133 134 { 134 135 const struct pwm_device *pwm = child_to_pwm_device(child); 135 136 const char *polarity = "unknown"; ··· 147 148 return sprintf(buf, "%s\n", polarity); 148 149 } 149 150 150 - static ssize_t pwm_polarity_store(struct device *child, 151 - struct device_attribute *attr, 152 - const char *buf, size_t size) 151 + static ssize_t polarity_store(struct device *child, 152 + struct device_attribute *attr, 153 + const char *buf, size_t size) 153 154 { 154 155 struct pwm_device *pwm = child_to_pwm_device(child); 155 156 enum pwm_polarity polarity; ··· 167 168 return ret ? : size; 168 169 } 169 170 170 - static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store); 171 - static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store); 172 - static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store); 173 - static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store); 171 + static DEVICE_ATTR_RW(period); 172 + static DEVICE_ATTR_RW(duty_cycle); 173 + static DEVICE_ATTR_RW(enable); 174 + static DEVICE_ATTR_RW(polarity); 174 175 175 176 static struct attribute *pwm_attrs[] = { 176 177 &dev_attr_period.attr, ··· 244 245 return 0; 245 246 } 246 247 247 - static ssize_t pwm_export_store(struct device *parent, 248 - struct device_attribute *attr, 249 - const char *buf, size_t len) 248 + static ssize_t export_store(struct device *parent, 249 + struct device_attribute *attr, 250 + const char *buf, size_t len) 250 251 { 251 252 struct pwm_chip *chip = dev_get_drvdata(parent); 252 253 struct pwm_device *pwm; ··· 270 271 271 272 return ret ? : len; 272 273 } 273 - static DEVICE_ATTR(export, 0200, NULL, pwm_export_store); 274 + static DEVICE_ATTR_WO(export); 274 275 275 - static ssize_t pwm_unexport_store(struct device *parent, 276 - struct device_attribute *attr, 277 - const char *buf, size_t len) 276 + static ssize_t unexport_store(struct device *parent, 277 + struct device_attribute *attr, 278 + const char *buf, size_t len) 278 279 { 279 280 struct pwm_chip *chip = dev_get_drvdata(parent); 280 281 unsigned int hwpwm; ··· 291 292 292 293 return ret ? : len; 293 294 } 294 - static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store); 295 + static DEVICE_ATTR_WO(unexport); 295 296 296 297 static ssize_t npwm_show(struct device *parent, struct device_attribute *attr, 297 298 char *buf)
+3
include/linux/pwm.h
··· 2 2 #define __LINUX_PWM_H 3 3 4 4 #include <linux/err.h> 5 + #include <linux/mutex.h> 5 6 #include <linux/of.h> 6 7 7 8 struct pwm_device; ··· 88 87 * @pwm: global index of the PWM device 89 88 * @chip: PWM chip providing this PWM device 90 89 * @chip_data: chip-private data associated with the PWM device 90 + * @lock: used to serialize accesses to the PWM device where necessary 91 91 * @period: period of the PWM signal (in nanoseconds) 92 92 * @duty_cycle: duty cycle of the PWM signal (in nanoseconds) 93 93 * @polarity: polarity of the PWM signal ··· 100 98 unsigned int pwm; 101 99 struct pwm_chip *chip; 102 100 void *chip_data; 101 + struct mutex lock; 103 102 104 103 unsigned int period; 105 104 unsigned int duty_cycle;