diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-21 11:17:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-21 11:17:43 -0400 |
commit | 5b9c8972527fdb52d5cd7dadc9853c57430e0ff5 (patch) | |
tree | a829bb857ae7f19369fd7479597c640d30e0f47e | |
parent | 3d430bdb74140224d90dd6253d67ff71d181cf64 (diff) | |
parent | dec02f98ae2e341a2e0bb25f27e84867e5f9f64a (diff) |
Merge tag 'pwm/for-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm changes from Thierry Reding:
"There are no new drivers here, only a couple of fixes all over the
place"
* tag 'pwm/for-3.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
pwm: Let PWM_CLPS711X depend on HAS_IOMEM
pwm: atmel: Fix calculation of prescale value
pwm: Fix uninitialized warnings in pwm_get()
pwm: rockchip: Allow polarity invert on rk3288
pwm: imx: Avoid sample FIFO overflow for i.MX PWM version2
pwm: imx: Cleanup indentation for register definitions
pwm: imx: Fix the macro MX3_PWMCR_PRESCALER(x) definition
pwm: Fix possible ZERO_SIZE_PTR pointer dereferencing error.
pwm: lpss: make it buildable only on X86
pwm: lpss: use c99 initializers in structures
pwm: lpss: Fix build failure on PowerPC
pwm: lpss: pci: Move to use pcim_enable_device()
pwm: lpss: Properly split driver to parts
pwm: lpss: Add ACPI and PCI IDs for Intel Braswell
pwm: fsl-ftm: Select REGMAP_MMIO
pwm: fsl-ftm: Document 'big-endian' property
pwm: fsl-ftm: Convert to direct regmap API usage
pwm: fsl-ftm: Clean up the code
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt | 19 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-rockchip.txt | 4 | ||||
-rw-r--r-- | drivers/pwm/Kconfig | 22 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 2 | ||||
-rw-r--r-- | drivers/pwm/core.c | 31 | ||||
-rw-r--r-- | drivers/pwm/pwm-atmel.c | 24 | ||||
-rw-r--r-- | drivers/pwm/pwm-fsl-ftm.c | 90 | ||||
-rw-r--r-- | drivers/pwm/pwm-imx.c | 71 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss-pci.c | 64 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss-platform.c | 68 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss.c | 137 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss.h | 32 | ||||
-rw-r--r-- | drivers/pwm/pwm-rockchip.c | 57 |
13 files changed, 399 insertions, 222 deletions
diff --git a/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt index 0bda229a6171..3899d6a557c1 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-fsl-ftm.txt | |||
@@ -1,5 +1,20 @@ | |||
1 | Freescale FlexTimer Module (FTM) PWM controller | 1 | Freescale FlexTimer Module (FTM) PWM controller |
2 | 2 | ||
3 | The same FTM PWM device can have a different endianness on different SoCs. The | ||
4 | device tree provides a property to describing this so that an operating system | ||
5 | device driver can handle all variants of the device. Refer to the table below | ||
6 | for the endianness of the FTM PWM block as integrated into the existing SoCs: | ||
7 | |||
8 | SoC | FTM-PWM endianness | ||
9 | --------+------------------- | ||
10 | Vybrid | LE | ||
11 | LS1 | BE | ||
12 | LS2 | LE | ||
13 | |||
14 | Please see ../regmap/regmap.txt for more detail about how to specify endian | ||
15 | modes in device tree. | ||
16 | |||
17 | |||
3 | Required properties: | 18 | Required properties: |
4 | - compatible: Should be "fsl,vf610-ftm-pwm". | 19 | - compatible: Should be "fsl,vf610-ftm-pwm". |
5 | - reg: Physical base address and length of the controller's registers | 20 | - reg: Physical base address and length of the controller's registers |
@@ -16,7 +31,8 @@ Required properties: | |||
16 | - pinctrl-names: Must contain a "default" entry. | 31 | - pinctrl-names: Must contain a "default" entry. |
17 | - pinctrl-NNN: One property must exist for each entry in pinctrl-names. | 32 | - pinctrl-NNN: One property must exist for each entry in pinctrl-names. |
18 | See pinctrl/pinctrl-bindings.txt for details of the property values. | 33 | See pinctrl/pinctrl-bindings.txt for details of the property values. |
19 | 34 | - big-endian: Boolean property, required if the FTM PWM registers use a big- | |
35 | endian rather than little-endian layout. | ||
20 | 36 | ||
21 | Example: | 37 | Example: |
22 | 38 | ||
@@ -32,4 +48,5 @@ pwm0: pwm@40038000 { | |||
32 | <&clks VF610_CLK_FTM0_EXT_FIX_EN>; | 48 | <&clks VF610_CLK_FTM0_EXT_FIX_EN>; |
33 | pinctrl-names = "default"; | 49 | pinctrl-names = "default"; |
34 | pinctrl-0 = <&pinctrl_pwm0_1>; | 50 | pinctrl-0 = <&pinctrl_pwm0_1>; |
51 | big-endian; | ||
35 | }; | 52 | }; |
diff --git a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt index d47d15a6a298..b8be3d09ee26 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt | |||
@@ -7,8 +7,8 @@ Required properties: | |||
7 | "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC | 7 | "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC |
8 | - reg: physical base address and length of the controller's registers | 8 | - reg: physical base address and length of the controller's registers |
9 | - clocks: phandle and clock specifier of the PWM reference clock | 9 | - clocks: phandle and clock specifier of the PWM reference clock |
10 | - #pwm-cells: should be 2. See pwm.txt in this directory for a | 10 | - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory |
11 | description of the cell format. | 11 | for a description of the cell format. |
12 | 12 | ||
13 | Example: | 13 | Example: |
14 | 14 | ||
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b800783800a3..ef2dd2e4754b 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -83,6 +83,7 @@ config PWM_BFIN | |||
83 | config PWM_CLPS711X | 83 | config PWM_CLPS711X |
84 | tristate "CLPS711X PWM support" | 84 | tristate "CLPS711X PWM support" |
85 | depends on ARCH_CLPS711X || COMPILE_TEST | 85 | depends on ARCH_CLPS711X || COMPILE_TEST |
86 | depends on HAS_IOMEM | ||
86 | help | 87 | help |
87 | Generic PWM framework driver for Cirrus Logic CLPS711X. | 88 | Generic PWM framework driver for Cirrus Logic CLPS711X. |
88 | 89 | ||
@@ -101,6 +102,7 @@ config PWM_EP93XX | |||
101 | config PWM_FSL_FTM | 102 | config PWM_FSL_FTM |
102 | tristate "Freescale FlexTimer Module (FTM) PWM support" | 103 | tristate "Freescale FlexTimer Module (FTM) PWM support" |
103 | depends on OF | 104 | depends on OF |
105 | select REGMAP_MMIO | ||
104 | help | 106 | help |
105 | Generic FTM PWM framework driver for Freescale VF610 and | 107 | Generic FTM PWM framework driver for Freescale VF610 and |
106 | Layerscape LS-1 SoCs. | 108 | Layerscape LS-1 SoCs. |
@@ -149,7 +151,7 @@ config PWM_LPC32XX | |||
149 | 151 | ||
150 | config PWM_LPSS | 152 | config PWM_LPSS |
151 | tristate "Intel LPSS PWM support" | 153 | tristate "Intel LPSS PWM support" |
152 | depends on ACPI | 154 | depends on X86 |
153 | help | 155 | help |
154 | Generic PWM framework driver for Intel Low Power Subsystem PWM | 156 | Generic PWM framework driver for Intel Low Power Subsystem PWM |
155 | controller. | 157 | controller. |
@@ -157,6 +159,24 @@ config PWM_LPSS | |||
157 | To compile this driver as a module, choose M here: the module | 159 | To compile this driver as a module, choose M here: the module |
158 | will be called pwm-lpss. | 160 | will be called pwm-lpss. |
159 | 161 | ||
162 | config PWM_LPSS_PCI | ||
163 | tristate "Intel LPSS PWM PCI driver" | ||
164 | depends on PWM_LPSS && PCI | ||
165 | help | ||
166 | The PCI driver for Intel Low Power Subsystem PWM controller. | ||
167 | |||
168 | To compile this driver as a module, choose M here: the module | ||
169 | will be called pwm-lpss-pci. | ||
170 | |||
171 | config PWM_LPSS_PLATFORM | ||
172 | tristate "Intel LPSS PWM platform driver" | ||
173 | depends on PWM_LPSS && ACPI | ||
174 | help | ||
175 | The platform driver for Intel Low Power Subsystem PWM controller. | ||
176 | |||
177 | To compile this driver as a module, choose M here: the module | ||
178 | will be called pwm-lpss-platform. | ||
179 | |||
160 | config PWM_MXS | 180 | config PWM_MXS |
161 | tristate "Freescale MXS PWM support" | 181 | tristate "Freescale MXS PWM support" |
162 | depends on ARCH_MXS && OF | 182 | depends on ARCH_MXS && OF |
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index f8c577d41091..c458606c3755 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile | |||
@@ -13,6 +13,8 @@ obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o | |||
13 | obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o | 13 | obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o |
14 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | 14 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o |
15 | obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o | 15 | obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o |
16 | obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o | ||
17 | obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o | ||
16 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | 18 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
17 | obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o | 19 | obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o |
18 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | 20 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o |
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index d2c35920ff08..966497d10c6e 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c | |||
@@ -236,7 +236,7 @@ int pwmchip_add(struct pwm_chip *chip) | |||
236 | int ret; | 236 | int ret; |
237 | 237 | ||
238 | if (!chip || !chip->dev || !chip->ops || !chip->ops->config || | 238 | if (!chip || !chip->dev || !chip->ops || !chip->ops->config || |
239 | !chip->ops->enable || !chip->ops->disable) | 239 | !chip->ops->enable || !chip->ops->disable || !chip->npwm) |
240 | return -EINVAL; | 240 | return -EINVAL; |
241 | 241 | ||
242 | mutex_lock(&pwm_lock); | 242 | mutex_lock(&pwm_lock); |
@@ -602,12 +602,9 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) | |||
602 | struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER); | 602 | struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER); |
603 | const char *dev_id = dev ? dev_name(dev) : NULL; | 603 | const char *dev_id = dev ? dev_name(dev) : NULL; |
604 | struct pwm_chip *chip = NULL; | 604 | struct pwm_chip *chip = NULL; |
605 | unsigned int index = 0; | ||
606 | unsigned int best = 0; | 605 | unsigned int best = 0; |
607 | struct pwm_lookup *p; | 606 | struct pwm_lookup *p, *chosen = NULL; |
608 | unsigned int match; | 607 | unsigned int match; |
609 | unsigned int period; | ||
610 | enum pwm_polarity polarity; | ||
611 | 608 | ||
612 | /* look up via DT first */ | 609 | /* look up via DT first */ |
613 | if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) | 610 | if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) |
@@ -653,10 +650,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) | |||
653 | } | 650 | } |
654 | 651 | ||
655 | if (match > best) { | 652 | if (match > best) { |
656 | chip = pwmchip_find_by_name(p->provider); | 653 | chosen = p; |
657 | index = p->index; | ||
658 | period = p->period; | ||
659 | polarity = p->polarity; | ||
660 | 654 | ||
661 | if (match != 3) | 655 | if (match != 3) |
662 | best = match; | 656 | best = match; |
@@ -665,17 +659,22 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) | |||
665 | } | 659 | } |
666 | } | 660 | } |
667 | 661 | ||
668 | mutex_unlock(&pwm_lookup_lock); | 662 | if (!chosen) |
663 | goto out; | ||
669 | 664 | ||
670 | if (chip) | 665 | chip = pwmchip_find_by_name(chosen->provider); |
671 | pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id); | 666 | if (!chip) |
672 | if (IS_ERR(pwm)) | 667 | goto out; |
673 | return pwm; | ||
674 | 668 | ||
675 | pwm_set_period(pwm, period); | 669 | pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id); |
676 | pwm_set_polarity(pwm, polarity); | 670 | if (IS_ERR(pwm)) |
671 | goto out; | ||
677 | 672 | ||
673 | pwm_set_period(pwm, chosen->period); | ||
674 | pwm_set_polarity(pwm, chosen->polarity); | ||
678 | 675 | ||
676 | out: | ||
677 | mutex_unlock(&pwm_lookup_lock); | ||
679 | return pwm; | 678 | return pwm; |
680 | } | 679 | } |
681 | EXPORT_SYMBOL_GPL(pwm_get); | 680 | EXPORT_SYMBOL_GPL(pwm_get); |
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 6e700a541ca3..d3c22de9ee47 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c | |||
@@ -102,7 +102,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
102 | int duty_ns, int period_ns) | 102 | int duty_ns, int period_ns) |
103 | { | 103 | { |
104 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); | 104 | struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); |
105 | unsigned long clk_rate, prd, dty; | 105 | unsigned long prd, dty; |
106 | unsigned long long div; | 106 | unsigned long long div; |
107 | unsigned int pres = 0; | 107 | unsigned int pres = 0; |
108 | u32 val; | 108 | u32 val; |
@@ -113,20 +113,18 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
113 | return -EBUSY; | 113 | return -EBUSY; |
114 | } | 114 | } |
115 | 115 | ||
116 | clk_rate = clk_get_rate(atmel_pwm->clk); | 116 | /* Calculate the period cycles and prescale value */ |
117 | div = clk_rate; | 117 | div = (unsigned long long)clk_get_rate(atmel_pwm->clk) * period_ns; |
118 | do_div(div, NSEC_PER_SEC); | ||
118 | 119 | ||
119 | /* Calculate the period cycles */ | ||
120 | while (div > PWM_MAX_PRD) { | 120 | while (div > PWM_MAX_PRD) { |
121 | div = clk_rate / (1 << pres); | 121 | div >>= 1; |
122 | div = div * period_ns; | 122 | pres++; |
123 | /* 1/Hz = 100000000 ns */ | 123 | } |
124 | do_div(div, 1000000000); | 124 | |
125 | 125 | if (pres > PRD_MAX_PRES) { | |
126 | if (pres++ > PRD_MAX_PRES) { | 126 | dev_err(chip->dev, "pres exceeds the maximum value\n"); |
127 | dev_err(chip->dev, "pres exceeds the maximum value\n"); | 127 | return -EINVAL; |
128 | return -EINVAL; | ||
129 | } | ||
130 | } | 128 | } |
131 | 129 | ||
132 | /* Calculate the duty cycles */ | 130 | /* Calculate the duty cycles */ |
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index a18bc8fea385..0f2cc7ef7784 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c | |||
@@ -18,14 +18,14 @@ | |||
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pwm.h> | 20 | #include <linux/pwm.h> |
21 | #include <linux/regmap.h> | ||
21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
22 | 23 | ||
23 | #define FTM_SC 0x00 | 24 | #define FTM_SC 0x00 |
24 | #define FTM_SC_CLK_MASK 0x3 | 25 | #define FTM_SC_CLK_MASK_SHIFT 3 |
25 | #define FTM_SC_CLK_SHIFT 3 | 26 | #define FTM_SC_CLK_MASK (3 << FTM_SC_CLK_MASK_SHIFT) |
26 | #define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_SHIFT) | 27 | #define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_MASK_SHIFT) |
27 | #define FTM_SC_PS_MASK 0x7 | 28 | #define FTM_SC_PS_MASK 0x7 |
28 | #define FTM_SC_PS_SHIFT 0 | ||
29 | 29 | ||
30 | #define FTM_CNT 0x04 | 30 | #define FTM_CNT 0x04 |
31 | #define FTM_MOD 0x08 | 31 | #define FTM_MOD 0x08 |
@@ -83,7 +83,7 @@ struct fsl_pwm_chip { | |||
83 | unsigned int cnt_select; | 83 | unsigned int cnt_select; |
84 | unsigned int clk_ps; | 84 | unsigned int clk_ps; |
85 | 85 | ||
86 | void __iomem *base; | 86 | struct regmap *regmap; |
87 | 87 | ||
88 | int period_ns; | 88 | int period_ns; |
89 | 89 | ||
@@ -219,10 +219,11 @@ static unsigned long fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc, | |||
219 | unsigned long period_ns, | 219 | unsigned long period_ns, |
220 | unsigned long duty_ns) | 220 | unsigned long duty_ns) |
221 | { | 221 | { |
222 | unsigned long long val, duty; | 222 | unsigned long long duty; |
223 | u32 val; | ||
223 | 224 | ||
224 | val = readl(fpc->base + FTM_MOD); | 225 | regmap_read(fpc->regmap, FTM_MOD, &val); |
225 | duty = duty_ns * (val + 1); | 226 | duty = (unsigned long long)duty_ns * (val + 1); |
226 | do_div(duty, period_ns); | 227 | do_div(duty, period_ns); |
227 | 228 | ||
228 | return (unsigned long)duty; | 229 | return (unsigned long)duty; |
@@ -232,7 +233,7 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
232 | int duty_ns, int period_ns) | 233 | int duty_ns, int period_ns) |
233 | { | 234 | { |
234 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 235 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
235 | u32 val, period, duty; | 236 | u32 period, duty; |
236 | 237 | ||
237 | mutex_lock(&fpc->lock); | 238 | mutex_lock(&fpc->lock); |
238 | 239 | ||
@@ -257,11 +258,9 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
257 | return -EINVAL; | 258 | return -EINVAL; |
258 | } | 259 | } |
259 | 260 | ||
260 | val = readl(fpc->base + FTM_SC); | 261 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK, |
261 | val &= ~(FTM_SC_PS_MASK << FTM_SC_PS_SHIFT); | 262 | fpc->clk_ps); |
262 | val |= fpc->clk_ps; | 263 | regmap_write(fpc->regmap, FTM_MOD, period - 1); |
263 | writel(val, fpc->base + FTM_SC); | ||
264 | writel(period - 1, fpc->base + FTM_MOD); | ||
265 | 264 | ||
266 | fpc->period_ns = period_ns; | 265 | fpc->period_ns = period_ns; |
267 | } | 266 | } |
@@ -270,8 +269,9 @@ static int fsl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
270 | 269 | ||
271 | duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); | 270 | duty = fsl_pwm_calculate_duty(fpc, period_ns, duty_ns); |
272 | 271 | ||
273 | writel(FTM_CSC_MSB | FTM_CSC_ELSB, fpc->base + FTM_CSC(pwm->hwpwm)); | 272 | regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm), |
274 | writel(duty, fpc->base + FTM_CV(pwm->hwpwm)); | 273 | FTM_CSC_MSB | FTM_CSC_ELSB); |
274 | regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty); | ||
275 | 275 | ||
276 | return 0; | 276 | return 0; |
277 | } | 277 | } |
@@ -283,31 +283,28 @@ static int fsl_pwm_set_polarity(struct pwm_chip *chip, | |||
283 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 283 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
284 | u32 val; | 284 | u32 val; |
285 | 285 | ||
286 | val = readl(fpc->base + FTM_POL); | 286 | regmap_read(fpc->regmap, FTM_POL, &val); |
287 | 287 | ||
288 | if (polarity == PWM_POLARITY_INVERSED) | 288 | if (polarity == PWM_POLARITY_INVERSED) |
289 | val |= BIT(pwm->hwpwm); | 289 | val |= BIT(pwm->hwpwm); |
290 | else | 290 | else |
291 | val &= ~BIT(pwm->hwpwm); | 291 | val &= ~BIT(pwm->hwpwm); |
292 | 292 | ||
293 | writel(val, fpc->base + FTM_POL); | 293 | regmap_write(fpc->regmap, FTM_POL, val); |
294 | 294 | ||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) | 298 | static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) |
299 | { | 299 | { |
300 | u32 val; | ||
301 | int ret; | 300 | int ret; |
302 | 301 | ||
303 | if (fpc->use_count != 0) | 302 | if (fpc->use_count != 0) |
304 | return 0; | 303 | return 0; |
305 | 304 | ||
306 | /* select counter clock source */ | 305 | /* select counter clock source */ |
307 | val = readl(fpc->base + FTM_SC); | 306 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, |
308 | val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT); | 307 | FTM_SC_CLK(fpc->cnt_select)); |
309 | val |= FTM_SC_CLK(fpc->cnt_select); | ||
310 | writel(val, fpc->base + FTM_SC); | ||
311 | 308 | ||
312 | ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); | 309 | ret = clk_prepare_enable(fpc->clk[fpc->cnt_select]); |
313 | if (ret) | 310 | if (ret) |
@@ -327,13 +324,10 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) | |||
327 | static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 324 | static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
328 | { | 325 | { |
329 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); | 326 | struct fsl_pwm_chip *fpc = to_fsl_chip(chip); |
330 | u32 val; | ||
331 | int ret; | 327 | int ret; |
332 | 328 | ||
333 | mutex_lock(&fpc->lock); | 329 | mutex_lock(&fpc->lock); |
334 | val = readl(fpc->base + FTM_OUTMASK); | 330 | regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 0); |
335 | val &= ~BIT(pwm->hwpwm); | ||
336 | writel(val, fpc->base + FTM_OUTMASK); | ||
337 | 331 | ||
338 | ret = fsl_counter_clock_enable(fpc); | 332 | ret = fsl_counter_clock_enable(fpc); |
339 | mutex_unlock(&fpc->lock); | 333 | mutex_unlock(&fpc->lock); |
@@ -343,8 +337,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
343 | 337 | ||
344 | static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) | 338 | static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) |
345 | { | 339 | { |
346 | u32 val; | ||
347 | |||
348 | /* | 340 | /* |
349 | * already disabled, do nothing | 341 | * already disabled, do nothing |
350 | */ | 342 | */ |
@@ -356,9 +348,7 @@ static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) | |||
356 | return; | 348 | return; |
357 | 349 | ||
358 | /* no users left, disable PWM counter clock */ | 350 | /* no users left, disable PWM counter clock */ |
359 | val = readl(fpc->base + FTM_SC); | 351 | regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0); |
360 | val &= ~(FTM_SC_CLK_MASK << FTM_SC_CLK_SHIFT); | ||
361 | writel(val, fpc->base + FTM_SC); | ||
362 | 352 | ||
363 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); | 353 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); |
364 | clk_disable_unprepare(fpc->clk[fpc->cnt_select]); | 354 | clk_disable_unprepare(fpc->clk[fpc->cnt_select]); |
@@ -370,14 +360,12 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
370 | u32 val; | 360 | u32 val; |
371 | 361 | ||
372 | mutex_lock(&fpc->lock); | 362 | mutex_lock(&fpc->lock); |
373 | val = readl(fpc->base + FTM_OUTMASK); | 363 | regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), |
374 | val |= BIT(pwm->hwpwm); | 364 | BIT(pwm->hwpwm)); |
375 | writel(val, fpc->base + FTM_OUTMASK); | ||
376 | 365 | ||
377 | fsl_counter_clock_disable(fpc); | 366 | fsl_counter_clock_disable(fpc); |
378 | 367 | ||
379 | val = readl(fpc->base + FTM_OUTMASK); | 368 | regmap_read(fpc->regmap, FTM_OUTMASK, &val); |
380 | |||
381 | if ((val & 0xFF) == 0xFF) | 369 | if ((val & 0xFF) == 0xFF) |
382 | fpc->period_ns = 0; | 370 | fpc->period_ns = 0; |
383 | 371 | ||
@@ -402,19 +390,28 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) | |||
402 | if (ret) | 390 | if (ret) |
403 | return ret; | 391 | return ret; |
404 | 392 | ||
405 | writel(0x00, fpc->base + FTM_CNTIN); | 393 | regmap_write(fpc->regmap, FTM_CNTIN, 0x00); |
406 | writel(0x00, fpc->base + FTM_OUTINIT); | 394 | regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); |
407 | writel(0xFF, fpc->base + FTM_OUTMASK); | 395 | regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); |
408 | 396 | ||
409 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); | 397 | clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); |
410 | 398 | ||
411 | return 0; | 399 | return 0; |
412 | } | 400 | } |
413 | 401 | ||
402 | static const struct regmap_config fsl_pwm_regmap_config = { | ||
403 | .reg_bits = 32, | ||
404 | .reg_stride = 4, | ||
405 | .val_bits = 32, | ||
406 | |||
407 | .max_register = FTM_PWMLOAD, | ||
408 | }; | ||
409 | |||
414 | static int fsl_pwm_probe(struct platform_device *pdev) | 410 | static int fsl_pwm_probe(struct platform_device *pdev) |
415 | { | 411 | { |
416 | struct fsl_pwm_chip *fpc; | 412 | struct fsl_pwm_chip *fpc; |
417 | struct resource *res; | 413 | struct resource *res; |
414 | void __iomem *base; | ||
418 | int ret; | 415 | int ret; |
419 | 416 | ||
420 | fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); | 417 | fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); |
@@ -426,9 +423,16 @@ static int fsl_pwm_probe(struct platform_device *pdev) | |||
426 | fpc->chip.dev = &pdev->dev; | 423 | fpc->chip.dev = &pdev->dev; |
427 | 424 | ||
428 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 425 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
429 | fpc->base = devm_ioremap_resource(&pdev->dev, res); | 426 | base = devm_ioremap_resource(&pdev->dev, res); |
430 | if (IS_ERR(fpc->base)) | 427 | if (IS_ERR(base)) |
431 | return PTR_ERR(fpc->base); | 428 | return PTR_ERR(base); |
429 | |||
430 | fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, | ||
431 | &fsl_pwm_regmap_config); | ||
432 | if (IS_ERR(fpc->regmap)) { | ||
433 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
434 | return PTR_ERR(fpc->regmap); | ||
435 | } | ||
432 | 436 | ||
433 | fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); | 437 | fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); |
434 | if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { | 438 | if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { |
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 5449d9150d40..f8b5f109c1ab 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/delay.h> | ||
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
18 | #include <linux/pwm.h> | 19 | #include <linux/pwm.h> |
19 | #include <linux/of.h> | 20 | #include <linux/of.h> |
@@ -21,24 +22,30 @@ | |||
21 | 22 | ||
22 | /* i.MX1 and i.MX21 share the same PWM function block: */ | 23 | /* i.MX1 and i.MX21 share the same PWM function block: */ |
23 | 24 | ||
24 | #define MX1_PWMC 0x00 /* PWM Control Register */ | 25 | #define MX1_PWMC 0x00 /* PWM Control Register */ |
25 | #define MX1_PWMS 0x04 /* PWM Sample Register */ | 26 | #define MX1_PWMS 0x04 /* PWM Sample Register */ |
26 | #define MX1_PWMP 0x08 /* PWM Period Register */ | 27 | #define MX1_PWMP 0x08 /* PWM Period Register */ |
27 | 28 | ||
28 | #define MX1_PWMC_EN (1 << 4) | 29 | #define MX1_PWMC_EN (1 << 4) |
29 | 30 | ||
30 | /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ | 31 | /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ |
31 | 32 | ||
32 | #define MX3_PWMCR 0x00 /* PWM Control Register */ | 33 | #define MX3_PWMCR 0x00 /* PWM Control Register */ |
33 | #define MX3_PWMSAR 0x0C /* PWM Sample Register */ | 34 | #define MX3_PWMSR 0x04 /* PWM Status Register */ |
34 | #define MX3_PWMPR 0x10 /* PWM Period Register */ | 35 | #define MX3_PWMSAR 0x0C /* PWM Sample Register */ |
35 | #define MX3_PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4) | 36 | #define MX3_PWMPR 0x10 /* PWM Period Register */ |
36 | #define MX3_PWMCR_DOZEEN (1 << 24) | 37 | #define MX3_PWMCR_PRESCALER(x) ((((x) - 1) & 0xFFF) << 4) |
37 | #define MX3_PWMCR_WAITEN (1 << 23) | 38 | #define MX3_PWMCR_DOZEEN (1 << 24) |
39 | #define MX3_PWMCR_WAITEN (1 << 23) | ||
38 | #define MX3_PWMCR_DBGEN (1 << 22) | 40 | #define MX3_PWMCR_DBGEN (1 << 22) |
39 | #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) | 41 | #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) |
40 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) | 42 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) |
41 | #define MX3_PWMCR_EN (1 << 0) | 43 | #define MX3_PWMCR_SWR (1 << 3) |
44 | #define MX3_PWMCR_EN (1 << 0) | ||
45 | #define MX3_PWMSR_FIFOAV_4WORDS 0x4 | ||
46 | #define MX3_PWMSR_FIFOAV_MASK 0x7 | ||
47 | |||
48 | #define MX3_PWM_SWR_LOOP 5 | ||
42 | 49 | ||
43 | struct imx_chip { | 50 | struct imx_chip { |
44 | struct clk *clk_per; | 51 | struct clk *clk_per; |
@@ -103,9 +110,43 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, | |||
103 | struct pwm_device *pwm, int duty_ns, int period_ns) | 110 | struct pwm_device *pwm, int duty_ns, int period_ns) |
104 | { | 111 | { |
105 | struct imx_chip *imx = to_imx_chip(chip); | 112 | struct imx_chip *imx = to_imx_chip(chip); |
113 | struct device *dev = chip->dev; | ||
106 | unsigned long long c; | 114 | unsigned long long c; |
107 | unsigned long period_cycles, duty_cycles, prescale; | 115 | unsigned long period_cycles, duty_cycles, prescale; |
108 | u32 cr; | 116 | unsigned int period_ms; |
117 | bool enable = test_bit(PWMF_ENABLED, &pwm->flags); | ||
118 | int wait_count = 0, fifoav; | ||
119 | u32 cr, sr; | ||
120 | |||
121 | /* | ||
122 | * i.MX PWMv2 has a 4-word sample FIFO. | ||
123 | * In order to avoid FIFO overflow issue, we do software reset | ||
124 | * to clear all sample FIFO if the controller is disabled or | ||
125 | * wait for a full PWM cycle to get a relinquished FIFO slot | ||
126 | * when the controller is enabled and the FIFO is fully loaded. | ||
127 | */ | ||
128 | if (enable) { | ||
129 | sr = readl(imx->mmio_base + MX3_PWMSR); | ||
130 | fifoav = sr & MX3_PWMSR_FIFOAV_MASK; | ||
131 | if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { | ||
132 | period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC); | ||
133 | msleep(period_ms); | ||
134 | |||
135 | sr = readl(imx->mmio_base + MX3_PWMSR); | ||
136 | if (fifoav == (sr & MX3_PWMSR_FIFOAV_MASK)) | ||
137 | dev_warn(dev, "there is no free FIFO slot\n"); | ||
138 | } | ||
139 | } else { | ||
140 | writel(MX3_PWMCR_SWR, imx->mmio_base + MX3_PWMCR); | ||
141 | do { | ||
142 | usleep_range(200, 1000); | ||
143 | cr = readl(imx->mmio_base + MX3_PWMCR); | ||
144 | } while ((cr & MX3_PWMCR_SWR) && | ||
145 | (wait_count++ < MX3_PWM_SWR_LOOP)); | ||
146 | |||
147 | if (cr & MX3_PWMCR_SWR) | ||
148 | dev_warn(dev, "software reset timeout\n"); | ||
149 | } | ||
109 | 150 | ||
110 | c = clk_get_rate(imx->clk_per); | 151 | c = clk_get_rate(imx->clk_per); |
111 | c = c * period_ns; | 152 | c = c * period_ns; |
@@ -135,7 +176,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, | |||
135 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | 176 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | |
136 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; | 177 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; |
137 | 178 | ||
138 | if (test_bit(PWMF_ENABLED, &pwm->flags)) | 179 | if (enable) |
139 | cr |= MX3_PWMCR_EN; | 180 | cr |= MX3_PWMCR_EN; |
140 | 181 | ||
141 | writel(cr, imx->mmio_base + MX3_PWMCR); | 182 | writel(cr, imx->mmio_base + MX3_PWMCR); |
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c new file mode 100644 index 000000000000..cf20d2beacdd --- /dev/null +++ b/drivers/pwm/pwm-lpss-pci.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Intel Low Power Subsystem PWM controller PCI driver | ||
3 | * | ||
4 | * Copyright (C) 2014, Intel Corporation | ||
5 | * | ||
6 | * Derived from the original pwm-lpss.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/pci.h> | ||
16 | |||
17 | #include "pwm-lpss.h" | ||
18 | |||
19 | static int pwm_lpss_probe_pci(struct pci_dev *pdev, | ||
20 | const struct pci_device_id *id) | ||
21 | { | ||
22 | const struct pwm_lpss_boardinfo *info; | ||
23 | struct pwm_lpss_chip *lpwm; | ||
24 | int err; | ||
25 | |||
26 | err = pcim_enable_device(pdev); | ||
27 | if (err < 0) | ||
28 | return err; | ||
29 | |||
30 | info = (struct pwm_lpss_boardinfo *)id->driver_data; | ||
31 | lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); | ||
32 | if (IS_ERR(lpwm)) | ||
33 | return PTR_ERR(lpwm); | ||
34 | |||
35 | pci_set_drvdata(pdev, lpwm); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static void pwm_lpss_remove_pci(struct pci_dev *pdev) | ||
40 | { | ||
41 | struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); | ||
42 | |||
43 | pwm_lpss_remove(lpwm); | ||
44 | } | ||
45 | |||
46 | static const struct pci_device_id pwm_lpss_pci_ids[] = { | ||
47 | { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info}, | ||
48 | { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info}, | ||
49 | { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info}, | ||
50 | { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info}, | ||
51 | { }, | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); | ||
54 | |||
55 | static struct pci_driver pwm_lpss_driver_pci = { | ||
56 | .name = "pwm-lpss", | ||
57 | .id_table = pwm_lpss_pci_ids, | ||
58 | .probe = pwm_lpss_probe_pci, | ||
59 | .remove = pwm_lpss_remove_pci, | ||
60 | }; | ||
61 | module_pci_driver(pwm_lpss_driver_pci); | ||
62 | |||
63 | MODULE_DESCRIPTION("PWM PCI driver for Intel LPSS"); | ||
64 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c new file mode 100644 index 000000000000..18a9c880a76d --- /dev/null +++ b/drivers/pwm/pwm-lpss-platform.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Intel Low Power Subsystem PWM controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014, Intel Corporation | ||
5 | * | ||
6 | * Derived from the original pwm-lpss.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/acpi.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include "pwm-lpss.h" | ||
19 | |||
20 | static int pwm_lpss_probe_platform(struct platform_device *pdev) | ||
21 | { | ||
22 | const struct pwm_lpss_boardinfo *info; | ||
23 | const struct acpi_device_id *id; | ||
24 | struct pwm_lpss_chip *lpwm; | ||
25 | struct resource *r; | ||
26 | |||
27 | id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); | ||
28 | if (!id) | ||
29 | return -ENODEV; | ||
30 | |||
31 | info = (const struct pwm_lpss_boardinfo *)id->driver_data; | ||
32 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
33 | |||
34 | lpwm = pwm_lpss_probe(&pdev->dev, r, info); | ||
35 | if (IS_ERR(lpwm)) | ||
36 | return PTR_ERR(lpwm); | ||
37 | |||
38 | platform_set_drvdata(pdev, lpwm); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int pwm_lpss_remove_platform(struct platform_device *pdev) | ||
43 | { | ||
44 | struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); | ||
45 | |||
46 | return pwm_lpss_remove(lpwm); | ||
47 | } | ||
48 | |||
49 | static const struct acpi_device_id pwm_lpss_acpi_match[] = { | ||
50 | { "80860F09", (unsigned long)&pwm_lpss_byt_info }, | ||
51 | { "80862288", (unsigned long)&pwm_lpss_bsw_info }, | ||
52 | { }, | ||
53 | }; | ||
54 | MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); | ||
55 | |||
56 | static struct platform_driver pwm_lpss_driver_platform = { | ||
57 | .driver = { | ||
58 | .name = "pwm-lpss", | ||
59 | .acpi_match_table = pwm_lpss_acpi_match, | ||
60 | }, | ||
61 | .probe = pwm_lpss_probe_platform, | ||
62 | .remove = pwm_lpss_remove_platform, | ||
63 | }; | ||
64 | module_platform_driver(pwm_lpss_driver_platform); | ||
65 | |||
66 | MODULE_DESCRIPTION("PWM platform driver for Intel LPSS"); | ||
67 | MODULE_LICENSE("GPL v2"); | ||
68 | MODULE_ALIAS("platform:pwm-lpss"); | ||
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 4df994f72d96..e9798253a16f 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c | |||
@@ -13,15 +13,11 @@ | |||
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/acpi.h> | 16 | #include <linux/io.h> |
17 | #include <linux/device.h> | ||
18 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
20 | #include <linux/pwm.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pci.h> | ||
23 | 19 | ||
24 | static int pci_drv, plat_drv; /* So we know which drivers registered */ | 20 | #include "pwm-lpss.h" |
25 | 21 | ||
26 | #define PWM 0x00000000 | 22 | #define PWM 0x00000000 |
27 | #define PWM_ENABLE BIT(31) | 23 | #define PWM_ENABLE BIT(31) |
@@ -39,14 +35,17 @@ struct pwm_lpss_chip { | |||
39 | unsigned long clk_rate; | 35 | unsigned long clk_rate; |
40 | }; | 36 | }; |
41 | 37 | ||
42 | struct pwm_lpss_boardinfo { | 38 | /* BayTrail */ |
43 | unsigned long clk_rate; | 39 | const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { |
40 | .clk_rate = 25000000 | ||
44 | }; | 41 | }; |
42 | EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); | ||
45 | 43 | ||
46 | /* BayTrail */ | 44 | /* Braswell */ |
47 | static const struct pwm_lpss_boardinfo byt_info = { | 45 | const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { |
48 | 25000000 | 46 | .clk_rate = 19200000 |
49 | }; | 47 | }; |
48 | EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); | ||
50 | 49 | ||
51 | static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) | 50 | static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) |
52 | { | 51 | { |
@@ -118,9 +117,8 @@ static const struct pwm_ops pwm_lpss_ops = { | |||
118 | .owner = THIS_MODULE, | 117 | .owner = THIS_MODULE, |
119 | }; | 118 | }; |
120 | 119 | ||
121 | static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, | 120 | struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, |
122 | struct resource *r, | 121 | const struct pwm_lpss_boardinfo *info) |
123 | const struct pwm_lpss_boardinfo *info) | ||
124 | { | 122 | { |
125 | struct pwm_lpss_chip *lpwm; | 123 | struct pwm_lpss_chip *lpwm; |
126 | int ret; | 124 | int ret; |
@@ -147,8 +145,9 @@ static struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, | |||
147 | 145 | ||
148 | return lpwm; | 146 | return lpwm; |
149 | } | 147 | } |
148 | EXPORT_SYMBOL_GPL(pwm_lpss_probe); | ||
150 | 149 | ||
151 | static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) | 150 | int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) |
152 | { | 151 | { |
153 | u32 ctrl; | 152 | u32 ctrl; |
154 | 153 | ||
@@ -157,114 +156,8 @@ static int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) | |||
157 | 156 | ||
158 | return pwmchip_remove(&lpwm->chip); | 157 | return pwmchip_remove(&lpwm->chip); |
159 | } | 158 | } |
160 | 159 | EXPORT_SYMBOL_GPL(pwm_lpss_remove); | |
161 | static int pwm_lpss_probe_pci(struct pci_dev *pdev, | ||
162 | const struct pci_device_id *id) | ||
163 | { | ||
164 | const struct pwm_lpss_boardinfo *info; | ||
165 | struct pwm_lpss_chip *lpwm; | ||
166 | int err; | ||
167 | |||
168 | err = pci_enable_device(pdev); | ||
169 | if (err < 0) | ||
170 | return err; | ||
171 | |||
172 | info = (struct pwm_lpss_boardinfo *)id->driver_data; | ||
173 | lpwm = pwm_lpss_probe(&pdev->dev, &pdev->resource[0], info); | ||
174 | if (IS_ERR(lpwm)) | ||
175 | return PTR_ERR(lpwm); | ||
176 | |||
177 | pci_set_drvdata(pdev, lpwm); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static void pwm_lpss_remove_pci(struct pci_dev *pdev) | ||
182 | { | ||
183 | struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev); | ||
184 | |||
185 | pwm_lpss_remove(lpwm); | ||
186 | pci_disable_device(pdev); | ||
187 | } | ||
188 | |||
189 | static struct pci_device_id pwm_lpss_pci_ids[] = { | ||
190 | { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&byt_info}, | ||
191 | { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&byt_info}, | ||
192 | { }, | ||
193 | }; | ||
194 | MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids); | ||
195 | |||
196 | static struct pci_driver pwm_lpss_driver_pci = { | ||
197 | .name = "pwm-lpss", | ||
198 | .id_table = pwm_lpss_pci_ids, | ||
199 | .probe = pwm_lpss_probe_pci, | ||
200 | .remove = pwm_lpss_remove_pci, | ||
201 | }; | ||
202 | |||
203 | static int pwm_lpss_probe_platform(struct platform_device *pdev) | ||
204 | { | ||
205 | const struct pwm_lpss_boardinfo *info; | ||
206 | const struct acpi_device_id *id; | ||
207 | struct pwm_lpss_chip *lpwm; | ||
208 | struct resource *r; | ||
209 | |||
210 | id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); | ||
211 | if (!id) | ||
212 | return -ENODEV; | ||
213 | |||
214 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
215 | |||
216 | info = (struct pwm_lpss_boardinfo *)id->driver_data; | ||
217 | lpwm = pwm_lpss_probe(&pdev->dev, r, info); | ||
218 | if (IS_ERR(lpwm)) | ||
219 | return PTR_ERR(lpwm); | ||
220 | |||
221 | platform_set_drvdata(pdev, lpwm); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int pwm_lpss_remove_platform(struct platform_device *pdev) | ||
226 | { | ||
227 | struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev); | ||
228 | |||
229 | return pwm_lpss_remove(lpwm); | ||
230 | } | ||
231 | |||
232 | static const struct acpi_device_id pwm_lpss_acpi_match[] = { | ||
233 | { "80860F09", (unsigned long)&byt_info }, | ||
234 | { }, | ||
235 | }; | ||
236 | MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match); | ||
237 | |||
238 | static struct platform_driver pwm_lpss_driver_platform = { | ||
239 | .driver = { | ||
240 | .name = "pwm-lpss", | ||
241 | .acpi_match_table = pwm_lpss_acpi_match, | ||
242 | }, | ||
243 | .probe = pwm_lpss_probe_platform, | ||
244 | .remove = pwm_lpss_remove_platform, | ||
245 | }; | ||
246 | |||
247 | static int __init pwm_init(void) | ||
248 | { | ||
249 | pci_drv = pci_register_driver(&pwm_lpss_driver_pci); | ||
250 | plat_drv = platform_driver_register(&pwm_lpss_driver_platform); | ||
251 | if (pci_drv && plat_drv) | ||
252 | return pci_drv; | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | module_init(pwm_init); | ||
257 | |||
258 | static void __exit pwm_exit(void) | ||
259 | { | ||
260 | if (!pci_drv) | ||
261 | pci_unregister_driver(&pwm_lpss_driver_pci); | ||
262 | if (!plat_drv) | ||
263 | platform_driver_unregister(&pwm_lpss_driver_platform); | ||
264 | } | ||
265 | module_exit(pwm_exit); | ||
266 | 160 | ||
267 | MODULE_DESCRIPTION("PWM driver for Intel LPSS"); | 161 | MODULE_DESCRIPTION("PWM driver for Intel LPSS"); |
268 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); | 162 | MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); |
269 | MODULE_LICENSE("GPL v2"); | 163 | MODULE_LICENSE("GPL v2"); |
270 | MODULE_ALIAS("platform:pwm-lpss"); | ||
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h new file mode 100644 index 000000000000..aa041bb1b67d --- /dev/null +++ b/drivers/pwm/pwm-lpss.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Intel Low Power Subsystem PWM controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014, Intel Corporation | ||
5 | * | ||
6 | * Derived from the original pwm-lpss.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __PWM_LPSS_H | ||
14 | #define __PWM_LPSS_H | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/pwm.h> | ||
18 | |||
19 | struct pwm_lpss_chip; | ||
20 | |||
21 | struct pwm_lpss_boardinfo { | ||
22 | unsigned long clk_rate; | ||
23 | }; | ||
24 | |||
25 | extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info; | ||
26 | extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info; | ||
27 | |||
28 | struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, | ||
29 | const struct pwm_lpss_boardinfo *info); | ||
30 | int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); | ||
31 | |||
32 | #endif /* __PWM_LPSS_H */ | ||
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index bdd8644c01cf..9442df244101 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c | |||
@@ -24,7 +24,9 @@ | |||
24 | #define PWM_ENABLE (1 << 0) | 24 | #define PWM_ENABLE (1 << 0) |
25 | #define PWM_CONTINUOUS (1 << 1) | 25 | #define PWM_CONTINUOUS (1 << 1) |
26 | #define PWM_DUTY_POSITIVE (1 << 3) | 26 | #define PWM_DUTY_POSITIVE (1 << 3) |
27 | #define PWM_DUTY_NEGATIVE (0 << 3) | ||
27 | #define PWM_INACTIVE_NEGATIVE (0 << 4) | 28 | #define PWM_INACTIVE_NEGATIVE (0 << 4) |
29 | #define PWM_INACTIVE_POSITIVE (1 << 4) | ||
28 | #define PWM_OUTPUT_LEFT (0 << 5) | 30 | #define PWM_OUTPUT_LEFT (0 << 5) |
29 | #define PWM_LP_DISABLE (0 << 8) | 31 | #define PWM_LP_DISABLE (0 << 8) |
30 | 32 | ||
@@ -45,8 +47,10 @@ struct rockchip_pwm_regs { | |||
45 | struct rockchip_pwm_data { | 47 | struct rockchip_pwm_data { |
46 | struct rockchip_pwm_regs regs; | 48 | struct rockchip_pwm_regs regs; |
47 | unsigned int prescaler; | 49 | unsigned int prescaler; |
50 | const struct pwm_ops *ops; | ||
48 | 51 | ||
49 | void (*set_enable)(struct pwm_chip *chip, bool enable); | 52 | void (*set_enable)(struct pwm_chip *chip, |
53 | struct pwm_device *pwm, bool enable); | ||
50 | }; | 54 | }; |
51 | 55 | ||
52 | static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) | 56 | static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) |
@@ -54,7 +58,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) | |||
54 | return container_of(c, struct rockchip_pwm_chip, chip); | 58 | return container_of(c, struct rockchip_pwm_chip, chip); |
55 | } | 59 | } |
56 | 60 | ||
57 | static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) | 61 | static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, |
62 | struct pwm_device *pwm, bool enable) | ||
58 | { | 63 | { |
59 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | 64 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); |
60 | u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN; | 65 | u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN; |
@@ -70,14 +75,19 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) | |||
70 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); | 75 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); |
71 | } | 76 | } |
72 | 77 | ||
73 | static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) | 78 | static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, |
79 | struct pwm_device *pwm, bool enable) | ||
74 | { | 80 | { |
75 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | 81 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); |
76 | u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | | 82 | u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | |
77 | PWM_CONTINUOUS | PWM_DUTY_POSITIVE | | 83 | PWM_CONTINUOUS; |
78 | PWM_INACTIVE_NEGATIVE; | ||
79 | u32 val; | 84 | u32 val; |
80 | 85 | ||
86 | if (pwm->polarity == PWM_POLARITY_INVERSED) | ||
87 | enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; | ||
88 | else | ||
89 | enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; | ||
90 | |||
81 | val = readl_relaxed(pc->base + pc->data->regs.ctrl); | 91 | val = readl_relaxed(pc->base + pc->data->regs.ctrl); |
82 | 92 | ||
83 | if (enable) | 93 | if (enable) |
@@ -124,6 +134,19 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
124 | return 0; | 134 | return 0; |
125 | } | 135 | } |
126 | 136 | ||
137 | static int rockchip_pwm_set_polarity(struct pwm_chip *chip, | ||
138 | struct pwm_device *pwm, | ||
139 | enum pwm_polarity polarity) | ||
140 | { | ||
141 | /* | ||
142 | * No action needed here because pwm->polarity will be set by the core | ||
143 | * and the core will only change polarity when the PWM is not enabled. | ||
144 | * We'll handle things in set_enable(). | ||
145 | */ | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
127 | static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 150 | static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
128 | { | 151 | { |
129 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | 152 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); |
@@ -133,7 +156,7 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
133 | if (ret) | 156 | if (ret) |
134 | return ret; | 157 | return ret; |
135 | 158 | ||
136 | pc->data->set_enable(chip, true); | 159 | pc->data->set_enable(chip, pwm, true); |
137 | 160 | ||
138 | return 0; | 161 | return 0; |
139 | } | 162 | } |
@@ -142,18 +165,26 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
142 | { | 165 | { |
143 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | 166 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); |
144 | 167 | ||
145 | pc->data->set_enable(chip, false); | 168 | pc->data->set_enable(chip, pwm, false); |
146 | 169 | ||
147 | clk_disable(pc->clk); | 170 | clk_disable(pc->clk); |
148 | } | 171 | } |
149 | 172 | ||
150 | static const struct pwm_ops rockchip_pwm_ops = { | 173 | static const struct pwm_ops rockchip_pwm_ops_v1 = { |
151 | .config = rockchip_pwm_config, | 174 | .config = rockchip_pwm_config, |
152 | .enable = rockchip_pwm_enable, | 175 | .enable = rockchip_pwm_enable, |
153 | .disable = rockchip_pwm_disable, | 176 | .disable = rockchip_pwm_disable, |
154 | .owner = THIS_MODULE, | 177 | .owner = THIS_MODULE, |
155 | }; | 178 | }; |
156 | 179 | ||
180 | static const struct pwm_ops rockchip_pwm_ops_v2 = { | ||
181 | .config = rockchip_pwm_config, | ||
182 | .set_polarity = rockchip_pwm_set_polarity, | ||
183 | .enable = rockchip_pwm_enable, | ||
184 | .disable = rockchip_pwm_disable, | ||
185 | .owner = THIS_MODULE, | ||
186 | }; | ||
187 | |||
157 | static const struct rockchip_pwm_data pwm_data_v1 = { | 188 | static const struct rockchip_pwm_data pwm_data_v1 = { |
158 | .regs = { | 189 | .regs = { |
159 | .duty = 0x04, | 190 | .duty = 0x04, |
@@ -162,6 +193,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = { | |||
162 | .ctrl = 0x0c, | 193 | .ctrl = 0x0c, |
163 | }, | 194 | }, |
164 | .prescaler = 2, | 195 | .prescaler = 2, |
196 | .ops = &rockchip_pwm_ops_v1, | ||
165 | .set_enable = rockchip_pwm_set_enable_v1, | 197 | .set_enable = rockchip_pwm_set_enable_v1, |
166 | }; | 198 | }; |
167 | 199 | ||
@@ -173,6 +205,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = { | |||
173 | .ctrl = 0x0c, | 205 | .ctrl = 0x0c, |
174 | }, | 206 | }, |
175 | .prescaler = 1, | 207 | .prescaler = 1, |
208 | .ops = &rockchip_pwm_ops_v2, | ||
176 | .set_enable = rockchip_pwm_set_enable_v2, | 209 | .set_enable = rockchip_pwm_set_enable_v2, |
177 | }; | 210 | }; |
178 | 211 | ||
@@ -184,6 +217,7 @@ static const struct rockchip_pwm_data pwm_data_vop = { | |||
184 | .ctrl = 0x00, | 217 | .ctrl = 0x00, |
185 | }, | 218 | }, |
186 | .prescaler = 1, | 219 | .prescaler = 1, |
220 | .ops = &rockchip_pwm_ops_v2, | ||
187 | .set_enable = rockchip_pwm_set_enable_v2, | 221 | .set_enable = rockchip_pwm_set_enable_v2, |
188 | }; | 222 | }; |
189 | 223 | ||
@@ -227,10 +261,15 @@ static int rockchip_pwm_probe(struct platform_device *pdev) | |||
227 | 261 | ||
228 | pc->data = id->data; | 262 | pc->data = id->data; |
229 | pc->chip.dev = &pdev->dev; | 263 | pc->chip.dev = &pdev->dev; |
230 | pc->chip.ops = &rockchip_pwm_ops; | 264 | pc->chip.ops = pc->data->ops; |
231 | pc->chip.base = -1; | 265 | pc->chip.base = -1; |
232 | pc->chip.npwm = 1; | 266 | pc->chip.npwm = 1; |
233 | 267 | ||
268 | if (pc->data->ops->set_polarity) { | ||
269 | pc->chip.of_xlate = of_pwm_xlate_with_flags; | ||
270 | pc->chip.of_pwm_n_cells = 3; | ||
271 | } | ||
272 | |||
234 | ret = pwmchip_add(&pc->chip); | 273 | ret = pwmchip_add(&pc->chip); |
235 | if (ret < 0) { | 274 | if (ret < 0) { |
236 | clk_unprepare(pc->clk); | 275 | clk_unprepare(pc->clk); |