diff options
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/Kconfig | 29 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 3 | ||||
-rw-r--r-- | drivers/pwm/core.c | 82 | ||||
-rw-r--r-- | drivers/pwm/pwm-ab8500.c | 153 | ||||
-rw-r--r-- | drivers/pwm/pwm-bfin.c | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-imx.c | 278 | ||||
-rw-r--r-- | drivers/pwm/pwm-jz4740.c | 221 | ||||
-rw-r--r-- | drivers/pwm/pwm-puv3.c | 161 | ||||
-rw-r--r-- | drivers/pwm/pwm-pxa.c | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-samsung.c | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-tiecap.c | 24 | ||||
-rw-r--r-- | drivers/pwm/pwm-tiehrpwm.c | 75 |
12 files changed, 904 insertions, 131 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index d7c6b83097c1..ed81720e7b2b 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -1,6 +1,5 @@ | |||
1 | menuconfig PWM | 1 | menuconfig PWM |
2 | bool "Pulse-Width Modulation (PWM) Support" | 2 | bool "Pulse-Width Modulation (PWM) Support" |
3 | depends on !MACH_JZ4740 && !PUV3_PWM | ||
4 | help | 3 | help |
5 | Generic Pulse-Width Modulation (PWM) support. | 4 | Generic Pulse-Width Modulation (PWM) support. |
6 | 5 | ||
@@ -29,6 +28,15 @@ menuconfig PWM | |||
29 | 28 | ||
30 | if PWM | 29 | if PWM |
31 | 30 | ||
31 | config PWM_AB8500 | ||
32 | tristate "AB8500 PWM support" | ||
33 | depends on AB8500_CORE && ARCH_U8500 | ||
34 | help | ||
35 | Generic PWM framework driver for Analog Baseband AB8500. | ||
36 | |||
37 | To compile this driver as a module, choose M here: the module | ||
38 | will be called pwm-ab8500. | ||
39 | |||
32 | config PWM_BFIN | 40 | config PWM_BFIN |
33 | tristate "Blackfin PWM support" | 41 | tristate "Blackfin PWM support" |
34 | depends on BFIN_GPTIMERS | 42 | depends on BFIN_GPTIMERS |
@@ -47,6 +55,16 @@ config PWM_IMX | |||
47 | To compile this driver as a module, choose M here: the module | 55 | To compile this driver as a module, choose M here: the module |
48 | will be called pwm-imx. | 56 | will be called pwm-imx. |
49 | 57 | ||
58 | config PWM_JZ4740 | ||
59 | tristate "Ingenic JZ4740 PWM support" | ||
60 | depends on MACH_JZ4740 | ||
61 | help | ||
62 | Generic PWM framework driver for Ingenic JZ4740 based | ||
63 | machines. | ||
64 | |||
65 | To compile this driver as a module, choose M here: the module | ||
66 | will be called pwm-jz4740. | ||
67 | |||
50 | config PWM_LPC32XX | 68 | config PWM_LPC32XX |
51 | tristate "LPC32XX PWM support" | 69 | tristate "LPC32XX PWM support" |
52 | depends on ARCH_LPC32XX | 70 | depends on ARCH_LPC32XX |
@@ -67,6 +85,15 @@ config PWM_MXS | |||
67 | To compile this driver as a module, choose M here: the module | 85 | To compile this driver as a module, choose M here: the module |
68 | will be called pwm-mxs. | 86 | will be called pwm-mxs. |
69 | 87 | ||
88 | config PWM_PUV3 | ||
89 | tristate "PKUnity NetBook-0916 PWM support" | ||
90 | depends on ARCH_PUV3 | ||
91 | help | ||
92 | Generic PWM framework driver for PKUnity NetBook-0916. | ||
93 | |||
94 | To compile this driver as a module, choose M here: the module | ||
95 | will be called pwm-puv3. | ||
96 | |||
70 | config PWM_PXA | 97 | config PWM_PXA |
71 | tristate "PXA PWM support" | 98 | tristate "PXA PWM support" |
72 | depends on ARCH_PXA | 99 | depends on ARCH_PXA |
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 78f123dca30d..acfe4821c58b 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile | |||
@@ -1,8 +1,11 @@ | |||
1 | obj-$(CONFIG_PWM) += core.o | 1 | obj-$(CONFIG_PWM) += core.o |
2 | obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o | ||
2 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o | 3 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o |
3 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o | 4 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o |
5 | obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o | ||
4 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | 6 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o |
5 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | 7 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
8 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | ||
6 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | 9 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o |
7 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o | 10 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o |
8 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o | 11 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o |
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index c6e05078d3ad..f5acdaa52707 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c | |||
@@ -371,7 +371,7 @@ EXPORT_SYMBOL_GPL(pwm_free); | |||
371 | */ | 371 | */ |
372 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | 372 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) |
373 | { | 373 | { |
374 | if (!pwm || period_ns == 0 || duty_ns > period_ns) | 374 | if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns) |
375 | return -EINVAL; | 375 | return -EINVAL; |
376 | 376 | ||
377 | return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); | 377 | return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); |
@@ -379,6 +379,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
379 | EXPORT_SYMBOL_GPL(pwm_config); | 379 | EXPORT_SYMBOL_GPL(pwm_config); |
380 | 380 | ||
381 | /** | 381 | /** |
382 | * pwm_set_polarity() - configure the polarity of a PWM signal | ||
383 | * @pwm: PWM device | ||
384 | * @polarity: new polarity of the PWM signal | ||
385 | * | ||
386 | * Note that the polarity cannot be configured while the PWM device is enabled | ||
387 | */ | ||
388 | int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) | ||
389 | { | ||
390 | if (!pwm || !pwm->chip->ops) | ||
391 | return -EINVAL; | ||
392 | |||
393 | if (!pwm->chip->ops->set_polarity) | ||
394 | return -ENOSYS; | ||
395 | |||
396 | if (test_bit(PWMF_ENABLED, &pwm->flags)) | ||
397 | return -EBUSY; | ||
398 | |||
399 | return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); | ||
400 | } | ||
401 | EXPORT_SYMBOL_GPL(pwm_set_polarity); | ||
402 | |||
403 | /** | ||
382 | * pwm_enable() - start a PWM output toggling | 404 | * pwm_enable() - start a PWM output toggling |
383 | * @pwm: PWM device | 405 | * @pwm: PWM device |
384 | */ | 406 | */ |
@@ -624,6 +646,64 @@ out: | |||
624 | } | 646 | } |
625 | EXPORT_SYMBOL_GPL(pwm_put); | 647 | EXPORT_SYMBOL_GPL(pwm_put); |
626 | 648 | ||
649 | static void devm_pwm_release(struct device *dev, void *res) | ||
650 | { | ||
651 | pwm_put(*(struct pwm_device **)res); | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * devm_pwm_get() - resource managed pwm_get() | ||
656 | * @dev: device for PWM consumer | ||
657 | * @con_id: consumer name | ||
658 | * | ||
659 | * This function performs like pwm_get() but the acquired PWM device will | ||
660 | * automatically be released on driver detach. | ||
661 | */ | ||
662 | struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) | ||
663 | { | ||
664 | struct pwm_device **ptr, *pwm; | ||
665 | |||
666 | ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); | ||
667 | if (!ptr) | ||
668 | return ERR_PTR(-ENOMEM); | ||
669 | |||
670 | pwm = pwm_get(dev, con_id); | ||
671 | if (!IS_ERR(pwm)) { | ||
672 | *ptr = pwm; | ||
673 | devres_add(dev, ptr); | ||
674 | } else { | ||
675 | devres_free(ptr); | ||
676 | } | ||
677 | |||
678 | return pwm; | ||
679 | } | ||
680 | EXPORT_SYMBOL_GPL(devm_pwm_get); | ||
681 | |||
682 | static int devm_pwm_match(struct device *dev, void *res, void *data) | ||
683 | { | ||
684 | struct pwm_device **p = res; | ||
685 | |||
686 | if (WARN_ON(!p || !*p)) | ||
687 | return 0; | ||
688 | |||
689 | return *p == data; | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * devm_pwm_put() - resource managed pwm_put() | ||
694 | * @dev: device for PWM consumer | ||
695 | * @pwm: PWM device | ||
696 | * | ||
697 | * Release a PWM previously allocated using devm_pwm_get(). Calling this | ||
698 | * function is usually not needed because devm-allocated resources are | ||
699 | * automatically released on driver detach. | ||
700 | */ | ||
701 | void devm_pwm_put(struct device *dev, struct pwm_device *pwm) | ||
702 | { | ||
703 | WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm)); | ||
704 | } | ||
705 | EXPORT_SYMBOL_GPL(devm_pwm_put); | ||
706 | |||
627 | #ifdef CONFIG_DEBUG_FS | 707 | #ifdef CONFIG_DEBUG_FS |
628 | static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) | 708 | static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) |
629 | { | 709 | { |
diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c new file mode 100644 index 000000000000..cfb72ca873d1 --- /dev/null +++ b/drivers/pwm/pwm-ab8500.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | */ | ||
7 | #include <linux/err.h> | ||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/pwm.h> | ||
11 | #include <linux/mfd/abx500.h> | ||
12 | #include <linux/mfd/abx500/ab8500.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | /* | ||
16 | * PWM Out generators | ||
17 | * Bank: 0x10 | ||
18 | */ | ||
19 | #define AB8500_PWM_OUT_CTRL1_REG 0x60 | ||
20 | #define AB8500_PWM_OUT_CTRL2_REG 0x61 | ||
21 | #define AB8500_PWM_OUT_CTRL7_REG 0x66 | ||
22 | |||
23 | /* backlight driver constants */ | ||
24 | #define ENABLE_PWM 1 | ||
25 | #define DISABLE_PWM 0 | ||
26 | |||
27 | struct ab8500_pwm_chip { | ||
28 | struct pwm_chip chip; | ||
29 | }; | ||
30 | |||
31 | static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
32 | int duty_ns, int period_ns) | ||
33 | { | ||
34 | int ret = 0; | ||
35 | unsigned int higher_val, lower_val; | ||
36 | u8 reg; | ||
37 | |||
38 | /* | ||
39 | * get the first 8 bits that are be written to | ||
40 | * AB8500_PWM_OUT_CTRL1_REG[0:7] | ||
41 | */ | ||
42 | lower_val = duty_ns & 0x00FF; | ||
43 | /* | ||
44 | * get bits [9:10] that are to be written to | ||
45 | * AB8500_PWM_OUT_CTRL2_REG[0:1] | ||
46 | */ | ||
47 | higher_val = ((duty_ns & 0x0300) >> 8); | ||
48 | |||
49 | reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2); | ||
50 | |||
51 | ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC, | ||
52 | reg, (u8)lower_val); | ||
53 | if (ret < 0) | ||
54 | return ret; | ||
55 | ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC, | ||
56 | (reg + 1), (u8)higher_val); | ||
57 | |||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
62 | { | ||
63 | int ret; | ||
64 | |||
65 | ret = abx500_mask_and_set_register_interruptible(chip->dev, | ||
66 | AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, | ||
67 | 1 << (chip->base - 1), ENABLE_PWM); | ||
68 | if (ret < 0) | ||
69 | dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", | ||
70 | pwm->label, ret); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
75 | { | ||
76 | int ret; | ||
77 | |||
78 | ret = abx500_mask_and_set_register_interruptible(chip->dev, | ||
79 | AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, | ||
80 | 1 << (chip->base - 1), DISABLE_PWM); | ||
81 | if (ret < 0) | ||
82 | dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", | ||
83 | pwm->label, ret); | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | static const struct pwm_ops ab8500_pwm_ops = { | ||
88 | .config = ab8500_pwm_config, | ||
89 | .enable = ab8500_pwm_enable, | ||
90 | .disable = ab8500_pwm_disable, | ||
91 | }; | ||
92 | |||
93 | static int __devinit ab8500_pwm_probe(struct platform_device *pdev) | ||
94 | { | ||
95 | struct ab8500_pwm_chip *ab8500; | ||
96 | int err; | ||
97 | |||
98 | /* | ||
99 | * Nothing to be done in probe, this is required to get the | ||
100 | * device which is required for ab8500 read and write | ||
101 | */ | ||
102 | ab8500 = kzalloc(sizeof(*ab8500), GFP_KERNEL); | ||
103 | if (ab8500 == NULL) { | ||
104 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
105 | return -ENOMEM; | ||
106 | } | ||
107 | |||
108 | ab8500->chip.dev = &pdev->dev; | ||
109 | ab8500->chip.ops = &ab8500_pwm_ops; | ||
110 | ab8500->chip.base = pdev->id; | ||
111 | ab8500->chip.npwm = 1; | ||
112 | |||
113 | err = pwmchip_add(&ab8500->chip); | ||
114 | if (err < 0) { | ||
115 | kfree(ab8500); | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | dev_dbg(&pdev->dev, "pwm probe successful\n"); | ||
120 | platform_set_drvdata(pdev, ab8500); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int __devexit ab8500_pwm_remove(struct platform_device *pdev) | ||
126 | { | ||
127 | struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev); | ||
128 | int err; | ||
129 | |||
130 | err = pwmchip_remove(&ab8500->chip); | ||
131 | if (err < 0) | ||
132 | return err; | ||
133 | |||
134 | dev_dbg(&pdev->dev, "pwm driver removed\n"); | ||
135 | kfree(ab8500); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static struct platform_driver ab8500_pwm_driver = { | ||
141 | .driver = { | ||
142 | .name = "ab8500-pwm", | ||
143 | .owner = THIS_MODULE, | ||
144 | }, | ||
145 | .probe = ab8500_pwm_probe, | ||
146 | .remove = __devexit_p(ab8500_pwm_remove), | ||
147 | }; | ||
148 | module_platform_driver(ab8500_pwm_driver); | ||
149 | |||
150 | MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>"); | ||
151 | MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver"); | ||
152 | MODULE_ALIAS("platform:ab8500-pwm"); | ||
153 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c index d53c4e7941ef..5da8e185e838 100644 --- a/drivers/pwm/pwm-bfin.c +++ b/drivers/pwm/pwm-bfin.c | |||
@@ -69,9 +69,6 @@ static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
69 | unsigned long period, duty; | 69 | unsigned long period, duty; |
70 | unsigned long long val; | 70 | unsigned long long val; |
71 | 71 | ||
72 | if (duty_ns < 0 || duty_ns > period_ns) | ||
73 | return -EINVAL; | ||
74 | |||
75 | val = (unsigned long long)get_sclk() * period_ns; | 72 | val = (unsigned long long)get_sclk() * period_ns; |
76 | do_div(val, NSEC_PER_SEC); | 73 | do_div(val, NSEC_PER_SEC); |
77 | period = val; | 74 | period = val; |
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 2a0b35333972..8a5d3ae2946a 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -16,8 +16,7 @@ | |||
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/pwm.h> | 18 | #include <linux/pwm.h> |
19 | #include <mach/hardware.h> | 19 | #include <linux/of_device.h> |
20 | |||
21 | 20 | ||
22 | /* i.MX1 and i.MX21 share the same PWM function block: */ | 21 | /* i.MX1 and i.MX21 share the same PWM function block: */ |
23 | 22 | ||
@@ -25,6 +24,7 @@ | |||
25 | #define MX1_PWMS 0x04 /* PWM Sample Register */ | 24 | #define MX1_PWMS 0x04 /* PWM Sample Register */ |
26 | #define MX1_PWMP 0x08 /* PWM Period Register */ | 25 | #define MX1_PWMP 0x08 /* PWM Period Register */ |
27 | 26 | ||
27 | #define MX1_PWMC_EN (1 << 4) | ||
28 | 28 | ||
29 | /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ | 29 | /* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ |
30 | 30 | ||
@@ -40,110 +40,165 @@ | |||
40 | #define MX3_PWMCR_EN (1 << 0) | 40 | #define MX3_PWMCR_EN (1 << 0) |
41 | 41 | ||
42 | struct imx_chip { | 42 | struct imx_chip { |
43 | struct clk *clk; | 43 | struct clk *clk_per; |
44 | struct clk *clk_ipg; | ||
44 | 45 | ||
45 | int clk_enabled; | 46 | int enabled; |
46 | void __iomem *mmio_base; | 47 | void __iomem *mmio_base; |
47 | 48 | ||
48 | struct pwm_chip chip; | 49 | struct pwm_chip chip; |
50 | |||
51 | int (*config)(struct pwm_chip *chip, | ||
52 | struct pwm_device *pwm, int duty_ns, int period_ns); | ||
53 | void (*set_enable)(struct pwm_chip *chip, bool enable); | ||
49 | }; | 54 | }; |
50 | 55 | ||
51 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) | 56 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) |
52 | 57 | ||
53 | static int imx_pwm_config(struct pwm_chip *chip, | 58 | static int imx_pwm_config_v1(struct pwm_chip *chip, |
54 | struct pwm_device *pwm, int duty_ns, int period_ns) | 59 | struct pwm_device *pwm, int duty_ns, int period_ns) |
55 | { | 60 | { |
56 | struct imx_chip *imx = to_imx_chip(chip); | 61 | struct imx_chip *imx = to_imx_chip(chip); |
57 | 62 | ||
58 | if (!(cpu_is_mx1() || cpu_is_mx21())) { | 63 | /* |
59 | unsigned long long c; | 64 | * The PWM subsystem allows for exact frequencies. However, |
60 | unsigned long period_cycles, duty_cycles, prescale; | 65 | * I cannot connect a scope on my device to the PWM line and |
61 | u32 cr; | 66 | * thus cannot provide the program the PWM controller |
62 | 67 | * exactly. Instead, I'm relying on the fact that the | |
63 | c = clk_get_rate(imx->clk); | 68 | * Bootloader (u-boot or WinCE+haret) has programmed the PWM |
64 | c = c * period_ns; | 69 | * function group already. So I'll just modify the PWM sample |
65 | do_div(c, 1000000000); | 70 | * register to follow the ratio of duty_ns vs. period_ns |
66 | period_cycles = c; | 71 | * accordingly. |
67 | 72 | * | |
68 | prescale = period_cycles / 0x10000 + 1; | 73 | * This is good enough for programming the brightness of |
69 | 74 | * the LCD backlight. | |
70 | period_cycles /= prescale; | 75 | * |
71 | c = (unsigned long long)period_cycles * duty_ns; | 76 | * The real implementation would divide PERCLK[0] first by |
72 | do_div(c, period_ns); | 77 | * both the prescaler (/1 .. /128) and then by CLKSEL |
73 | duty_cycles = c; | 78 | * (/2 .. /16). |
74 | 79 | */ | |
75 | /* | 80 | u32 max = readl(imx->mmio_base + MX1_PWMP); |
76 | * according to imx pwm RM, the real period value should be | 81 | u32 p = max * duty_ns / period_ns; |
77 | * PERIOD value in PWMPR plus 2. | 82 | writel(max - p, imx->mmio_base + MX1_PWMS); |
78 | */ | ||
79 | if (period_cycles > 2) | ||
80 | period_cycles -= 2; | ||
81 | else | ||
82 | period_cycles = 0; | ||
83 | |||
84 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); | ||
85 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); | ||
86 | |||
87 | cr = MX3_PWMCR_PRESCALER(prescale) | | ||
88 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | ||
89 | MX3_PWMCR_DBGEN | MX3_PWMCR_EN; | ||
90 | |||
91 | if (cpu_is_mx25()) | ||
92 | cr |= MX3_PWMCR_CLKSRC_IPG; | ||
93 | else | ||
94 | cr |= MX3_PWMCR_CLKSRC_IPG_HIGH; | ||
95 | |||
96 | writel(cr, imx->mmio_base + MX3_PWMCR); | ||
97 | } else if (cpu_is_mx1() || cpu_is_mx21()) { | ||
98 | /* The PWM subsystem allows for exact frequencies. However, | ||
99 | * I cannot connect a scope on my device to the PWM line and | ||
100 | * thus cannot provide the program the PWM controller | ||
101 | * exactly. Instead, I'm relying on the fact that the | ||
102 | * Bootloader (u-boot or WinCE+haret) has programmed the PWM | ||
103 | * function group already. So I'll just modify the PWM sample | ||
104 | * register to follow the ratio of duty_ns vs. period_ns | ||
105 | * accordingly. | ||
106 | * | ||
107 | * This is good enough for programming the brightness of | ||
108 | * the LCD backlight. | ||
109 | * | ||
110 | * The real implementation would divide PERCLK[0] first by | ||
111 | * both the prescaler (/1 .. /128) and then by CLKSEL | ||
112 | * (/2 .. /16). | ||
113 | */ | ||
114 | u32 max = readl(imx->mmio_base + MX1_PWMP); | ||
115 | u32 p = max * duty_ns / period_ns; | ||
116 | writel(max - p, imx->mmio_base + MX1_PWMS); | ||
117 | } else { | ||
118 | BUG(); | ||
119 | } | ||
120 | 83 | ||
121 | return 0; | 84 | return 0; |
122 | } | 85 | } |
123 | 86 | ||
87 | static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) | ||
88 | { | ||
89 | struct imx_chip *imx = to_imx_chip(chip); | ||
90 | u32 val; | ||
91 | |||
92 | val = readl(imx->mmio_base + MX1_PWMC); | ||
93 | |||
94 | if (enable) | ||
95 | val |= MX1_PWMC_EN; | ||
96 | else | ||
97 | val &= ~MX1_PWMC_EN; | ||
98 | |||
99 | writel(val, imx->mmio_base + MX1_PWMC); | ||
100 | } | ||
101 | |||
102 | static int imx_pwm_config_v2(struct pwm_chip *chip, | ||
103 | struct pwm_device *pwm, int duty_ns, int period_ns) | ||
104 | { | ||
105 | struct imx_chip *imx = to_imx_chip(chip); | ||
106 | unsigned long long c; | ||
107 | unsigned long period_cycles, duty_cycles, prescale; | ||
108 | u32 cr; | ||
109 | |||
110 | c = clk_get_rate(imx->clk_per); | ||
111 | c = c * period_ns; | ||
112 | do_div(c, 1000000000); | ||
113 | period_cycles = c; | ||
114 | |||
115 | prescale = period_cycles / 0x10000 + 1; | ||
116 | |||
117 | period_cycles /= prescale; | ||
118 | c = (unsigned long long)period_cycles * duty_ns; | ||
119 | do_div(c, period_ns); | ||
120 | duty_cycles = c; | ||
121 | |||
122 | /* | ||
123 | * according to imx pwm RM, the real period value should be | ||
124 | * PERIOD value in PWMPR plus 2. | ||
125 | */ | ||
126 | if (period_cycles > 2) | ||
127 | period_cycles -= 2; | ||
128 | else | ||
129 | period_cycles = 0; | ||
130 | |||
131 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); | ||
132 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); | ||
133 | |||
134 | cr = MX3_PWMCR_PRESCALER(prescale) | | ||
135 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | ||
136 | MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; | ||
137 | |||
138 | if (imx->enabled) | ||
139 | cr |= MX3_PWMCR_EN; | ||
140 | |||
141 | writel(cr, imx->mmio_base + MX3_PWMCR); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) | ||
147 | { | ||
148 | struct imx_chip *imx = to_imx_chip(chip); | ||
149 | u32 val; | ||
150 | |||
151 | val = readl(imx->mmio_base + MX3_PWMCR); | ||
152 | |||
153 | if (enable) | ||
154 | val |= MX3_PWMCR_EN; | ||
155 | else | ||
156 | val &= ~MX3_PWMCR_EN; | ||
157 | |||
158 | writel(val, imx->mmio_base + MX3_PWMCR); | ||
159 | } | ||
160 | |||
161 | static int imx_pwm_config(struct pwm_chip *chip, | ||
162 | struct pwm_device *pwm, int duty_ns, int period_ns) | ||
163 | { | ||
164 | struct imx_chip *imx = to_imx_chip(chip); | ||
165 | int ret; | ||
166 | |||
167 | ret = clk_prepare_enable(imx->clk_ipg); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | |||
171 | ret = imx->config(chip, pwm, duty_ns, period_ns); | ||
172 | |||
173 | clk_disable_unprepare(imx->clk_ipg); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
124 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 178 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
125 | { | 179 | { |
126 | struct imx_chip *imx = to_imx_chip(chip); | 180 | struct imx_chip *imx = to_imx_chip(chip); |
127 | int rc = 0; | 181 | int ret; |
128 | 182 | ||
129 | if (!imx->clk_enabled) { | 183 | ret = clk_prepare_enable(imx->clk_per); |
130 | rc = clk_prepare_enable(imx->clk); | 184 | if (ret) |
131 | if (!rc) | 185 | return ret; |
132 | imx->clk_enabled = 1; | 186 | |
133 | } | 187 | imx->set_enable(chip, true); |
134 | return rc; | 188 | |
189 | imx->enabled = 1; | ||
190 | |||
191 | return 0; | ||
135 | } | 192 | } |
136 | 193 | ||
137 | static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | 194 | static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
138 | { | 195 | { |
139 | struct imx_chip *imx = to_imx_chip(chip); | 196 | struct imx_chip *imx = to_imx_chip(chip); |
140 | 197 | ||
141 | writel(0, imx->mmio_base + MX3_PWMCR); | 198 | imx->set_enable(chip, false); |
142 | 199 | ||
143 | if (imx->clk_enabled) { | 200 | clk_disable_unprepare(imx->clk_per); |
144 | clk_disable_unprepare(imx->clk); | 201 | imx->enabled = 0; |
145 | imx->clk_enabled = 0; | ||
146 | } | ||
147 | } | 202 | } |
148 | 203 | ||
149 | static struct pwm_ops imx_pwm_ops = { | 204 | static struct pwm_ops imx_pwm_ops = { |
@@ -153,30 +208,66 @@ static struct pwm_ops imx_pwm_ops = { | |||
153 | .owner = THIS_MODULE, | 208 | .owner = THIS_MODULE, |
154 | }; | 209 | }; |
155 | 210 | ||
211 | struct imx_pwm_data { | ||
212 | int (*config)(struct pwm_chip *chip, | ||
213 | struct pwm_device *pwm, int duty_ns, int period_ns); | ||
214 | void (*set_enable)(struct pwm_chip *chip, bool enable); | ||
215 | }; | ||
216 | |||
217 | static struct imx_pwm_data imx_pwm_data_v1 = { | ||
218 | .config = imx_pwm_config_v1, | ||
219 | .set_enable = imx_pwm_set_enable_v1, | ||
220 | }; | ||
221 | |||
222 | static struct imx_pwm_data imx_pwm_data_v2 = { | ||
223 | .config = imx_pwm_config_v2, | ||
224 | .set_enable = imx_pwm_set_enable_v2, | ||
225 | }; | ||
226 | |||
227 | static const struct of_device_id imx_pwm_dt_ids[] = { | ||
228 | { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, }, | ||
229 | { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, | ||
230 | { /* sentinel */ } | ||
231 | }; | ||
232 | MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); | ||
233 | |||
156 | static int __devinit imx_pwm_probe(struct platform_device *pdev) | 234 | static int __devinit imx_pwm_probe(struct platform_device *pdev) |
157 | { | 235 | { |
236 | const struct of_device_id *of_id = | ||
237 | of_match_device(imx_pwm_dt_ids, &pdev->dev); | ||
238 | struct imx_pwm_data *data; | ||
158 | struct imx_chip *imx; | 239 | struct imx_chip *imx; |
159 | struct resource *r; | 240 | struct resource *r; |
160 | int ret = 0; | 241 | int ret = 0; |
161 | 242 | ||
243 | if (!of_id) | ||
244 | return -ENODEV; | ||
245 | |||
162 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); | 246 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); |
163 | if (imx == NULL) { | 247 | if (imx == NULL) { |
164 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 248 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
165 | return -ENOMEM; | 249 | return -ENOMEM; |
166 | } | 250 | } |
167 | 251 | ||
168 | imx->clk = devm_clk_get(&pdev->dev, "pwm"); | 252 | imx->clk_per = devm_clk_get(&pdev->dev, "per"); |
253 | if (IS_ERR(imx->clk_per)) { | ||
254 | dev_err(&pdev->dev, "getting per clock failed with %ld\n", | ||
255 | PTR_ERR(imx->clk_per)); | ||
256 | return PTR_ERR(imx->clk_per); | ||
257 | } | ||
169 | 258 | ||
170 | if (IS_ERR(imx->clk)) | 259 | imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); |
171 | return PTR_ERR(imx->clk); | 260 | if (IS_ERR(imx->clk_ipg)) { |
261 | dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", | ||
262 | PTR_ERR(imx->clk_ipg)); | ||
263 | return PTR_ERR(imx->clk_ipg); | ||
264 | } | ||
172 | 265 | ||
173 | imx->chip.ops = &imx_pwm_ops; | 266 | imx->chip.ops = &imx_pwm_ops; |
174 | imx->chip.dev = &pdev->dev; | 267 | imx->chip.dev = &pdev->dev; |
175 | imx->chip.base = -1; | 268 | imx->chip.base = -1; |
176 | imx->chip.npwm = 1; | 269 | imx->chip.npwm = 1; |
177 | 270 | ||
178 | imx->clk_enabled = 0; | ||
179 | |||
180 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 271 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
181 | if (r == NULL) { | 272 | if (r == NULL) { |
182 | dev_err(&pdev->dev, "no memory resource defined\n"); | 273 | dev_err(&pdev->dev, "no memory resource defined\n"); |
@@ -187,6 +278,10 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) | |||
187 | if (imx->mmio_base == NULL) | 278 | if (imx->mmio_base == NULL) |
188 | return -EADDRNOTAVAIL; | 279 | return -EADDRNOTAVAIL; |
189 | 280 | ||
281 | data = of_id->data; | ||
282 | imx->config = data->config; | ||
283 | imx->set_enable = data->set_enable; | ||
284 | |||
190 | ret = pwmchip_add(&imx->chip); | 285 | ret = pwmchip_add(&imx->chip); |
191 | if (ret < 0) | 286 | if (ret < 0) |
192 | return ret; | 287 | return ret; |
@@ -208,23 +303,14 @@ static int __devexit imx_pwm_remove(struct platform_device *pdev) | |||
208 | 303 | ||
209 | static struct platform_driver imx_pwm_driver = { | 304 | static struct platform_driver imx_pwm_driver = { |
210 | .driver = { | 305 | .driver = { |
211 | .name = "mxc_pwm", | 306 | .name = "imx-pwm", |
307 | .of_match_table = of_match_ptr(imx_pwm_dt_ids), | ||
212 | }, | 308 | }, |
213 | .probe = imx_pwm_probe, | 309 | .probe = imx_pwm_probe, |
214 | .remove = __devexit_p(imx_pwm_remove), | 310 | .remove = __devexit_p(imx_pwm_remove), |
215 | }; | 311 | }; |
216 | 312 | ||
217 | static int __init imx_pwm_init(void) | 313 | module_platform_driver(imx_pwm_driver); |
218 | { | ||
219 | return platform_driver_register(&imx_pwm_driver); | ||
220 | } | ||
221 | arch_initcall(imx_pwm_init); | ||
222 | |||
223 | static void __exit imx_pwm_exit(void) | ||
224 | { | ||
225 | platform_driver_unregister(&imx_pwm_driver); | ||
226 | } | ||
227 | module_exit(imx_pwm_exit); | ||
228 | 314 | ||
229 | MODULE_LICENSE("GPL v2"); | 315 | MODULE_LICENSE("GPL v2"); |
230 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | 316 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); |
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c new file mode 100644 index 000000000000..10250fcefb98 --- /dev/null +++ b/drivers/pwm/pwm-jz4740.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | ||
3 | * JZ4740 platform PWM support | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * You should have received a copy of the GNU General Public License along | ||
11 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pwm.h> | ||
23 | |||
24 | #include <asm/mach-jz4740/gpio.h> | ||
25 | #include <asm/mach-jz4740/timer.h> | ||
26 | |||
27 | #define NUM_PWM 8 | ||
28 | |||
29 | static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = { | ||
30 | JZ_GPIO_PWM0, | ||
31 | JZ_GPIO_PWM1, | ||
32 | JZ_GPIO_PWM2, | ||
33 | JZ_GPIO_PWM3, | ||
34 | JZ_GPIO_PWM4, | ||
35 | JZ_GPIO_PWM5, | ||
36 | JZ_GPIO_PWM6, | ||
37 | JZ_GPIO_PWM7, | ||
38 | }; | ||
39 | |||
40 | struct jz4740_pwm_chip { | ||
41 | struct pwm_chip chip; | ||
42 | struct clk *clk; | ||
43 | }; | ||
44 | |||
45 | static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) | ||
46 | { | ||
47 | return container_of(chip, struct jz4740_pwm_chip, chip); | ||
48 | } | ||
49 | |||
50 | static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | ||
51 | { | ||
52 | unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm]; | ||
53 | int ret; | ||
54 | |||
55 | /* | ||
56 | * Timers 0 and 1 are used for system tasks, so they are unavailable | ||
57 | * for use as PWMs. | ||
58 | */ | ||
59 | if (pwm->hwpwm < 2) | ||
60 | return -EBUSY; | ||
61 | |||
62 | ret = gpio_request(gpio, pwm->label); | ||
63 | if (ret) { | ||
64 | dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n", | ||
65 | gpio, ret); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM); | ||
70 | |||
71 | jz4740_timer_start(pwm->hwpwm); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
77 | { | ||
78 | unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm]; | ||
79 | |||
80 | jz4740_timer_set_ctrl(pwm->hwpwm, 0); | ||
81 | |||
82 | jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); | ||
83 | gpio_free(gpio); | ||
84 | |||
85 | jz4740_timer_stop(pwm->hwpwm); | ||
86 | } | ||
87 | |||
88 | static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
89 | { | ||
90 | uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm); | ||
91 | |||
92 | ctrl |= JZ_TIMER_CTRL_PWM_ENABLE; | ||
93 | jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | ||
94 | jz4740_timer_enable(pwm->hwpwm); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
100 | { | ||
101 | uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm); | ||
102 | |||
103 | ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE; | ||
104 | jz4740_timer_disable(pwm->hwpwm); | ||
105 | jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | ||
106 | } | ||
107 | |||
108 | static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
109 | int duty_ns, int period_ns) | ||
110 | { | ||
111 | struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); | ||
112 | unsigned long long tmp; | ||
113 | unsigned long period, duty; | ||
114 | unsigned int prescaler = 0; | ||
115 | uint16_t ctrl; | ||
116 | bool is_enabled; | ||
117 | |||
118 | tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns; | ||
119 | do_div(tmp, 1000000000); | ||
120 | period = tmp; | ||
121 | |||
122 | while (period > 0xffff && prescaler < 6) { | ||
123 | period >>= 2; | ||
124 | ++prescaler; | ||
125 | } | ||
126 | |||
127 | if (prescaler == 6) | ||
128 | return -EINVAL; | ||
129 | |||
130 | tmp = (unsigned long long)period * duty_ns; | ||
131 | do_div(tmp, period_ns); | ||
132 | duty = period - tmp; | ||
133 | |||
134 | if (duty >= period) | ||
135 | duty = period - 1; | ||
136 | |||
137 | is_enabled = jz4740_timer_is_enabled(pwm->hwpwm); | ||
138 | if (is_enabled) | ||
139 | jz4740_pwm_disable(chip, pwm); | ||
140 | |||
141 | jz4740_timer_set_count(pwm->hwpwm, 0); | ||
142 | jz4740_timer_set_duty(pwm->hwpwm, duty); | ||
143 | jz4740_timer_set_period(pwm->hwpwm, period); | ||
144 | |||
145 | ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT | | ||
146 | JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN; | ||
147 | |||
148 | jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | ||
149 | |||
150 | if (is_enabled) | ||
151 | jz4740_pwm_enable(chip, pwm); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static const struct pwm_ops jz4740_pwm_ops = { | ||
157 | .request = jz4740_pwm_request, | ||
158 | .free = jz4740_pwm_free, | ||
159 | .config = jz4740_pwm_config, | ||
160 | .enable = jz4740_pwm_enable, | ||
161 | .disable = jz4740_pwm_disable, | ||
162 | .owner = THIS_MODULE, | ||
163 | }; | ||
164 | |||
165 | static int __devinit jz4740_pwm_probe(struct platform_device *pdev) | ||
166 | { | ||
167 | struct jz4740_pwm_chip *jz4740; | ||
168 | int ret; | ||
169 | |||
170 | jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL); | ||
171 | if (!jz4740) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | jz4740->clk = clk_get(NULL, "ext"); | ||
175 | if (IS_ERR(jz4740->clk)) | ||
176 | return PTR_ERR(jz4740->clk); | ||
177 | |||
178 | jz4740->chip.dev = &pdev->dev; | ||
179 | jz4740->chip.ops = &jz4740_pwm_ops; | ||
180 | jz4740->chip.npwm = NUM_PWM; | ||
181 | jz4740->chip.base = -1; | ||
182 | |||
183 | ret = pwmchip_add(&jz4740->chip); | ||
184 | if (ret < 0) { | ||
185 | clk_put(jz4740->clk); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | platform_set_drvdata(pdev, jz4740); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int __devexit jz4740_pwm_remove(struct platform_device *pdev) | ||
195 | { | ||
196 | struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev); | ||
197 | int ret; | ||
198 | |||
199 | ret = pwmchip_remove(&jz4740->chip); | ||
200 | if (ret < 0) | ||
201 | return ret; | ||
202 | |||
203 | clk_put(jz4740->clk); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static struct platform_driver jz4740_pwm_driver = { | ||
209 | .driver = { | ||
210 | .name = "jz4740-pwm", | ||
211 | .owner = THIS_MODULE, | ||
212 | }, | ||
213 | .probe = jz4740_pwm_probe, | ||
214 | .remove = __devexit_p(jz4740_pwm_remove), | ||
215 | }; | ||
216 | module_platform_driver(jz4740_pwm_driver); | ||
217 | |||
218 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
219 | MODULE_DESCRIPTION("Ingenic JZ4740 PWM driver"); | ||
220 | MODULE_ALIAS("platform:jz4740-pwm"); | ||
221 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c new file mode 100644 index 000000000000..2a93f37c46ad --- /dev/null +++ b/drivers/pwm/pwm-puv3.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/kernel/pwm.c | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> | ||
7 | * Copyright (C) 2001-2010 Guan Xuetao | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/pwm.h> | ||
22 | |||
23 | #include <asm/div64.h> | ||
24 | #include <mach/hardware.h> | ||
25 | |||
26 | struct puv3_pwm_chip { | ||
27 | struct pwm_chip chip; | ||
28 | void __iomem *base; | ||
29 | struct clk *clk; | ||
30 | bool enabled; | ||
31 | }; | ||
32 | |||
33 | static inline struct puv3_pwm_chip *to_puv3(struct pwm_chip *chip) | ||
34 | { | ||
35 | return container_of(chip, struct puv3_pwm_chip, chip); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE | ||
40 | * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE | ||
41 | */ | ||
42 | static int puv3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
43 | int duty_ns, int period_ns) | ||
44 | { | ||
45 | unsigned long period_cycles, prescale, pv, dc; | ||
46 | struct puv3_pwm_chip *puv3 = to_puv3(chip); | ||
47 | unsigned long long c; | ||
48 | |||
49 | c = clk_get_rate(puv3->clk); | ||
50 | c = c * period_ns; | ||
51 | do_div(c, 1000000000); | ||
52 | period_cycles = c; | ||
53 | |||
54 | if (period_cycles < 1) | ||
55 | period_cycles = 1; | ||
56 | |||
57 | prescale = (period_cycles - 1) / 1024; | ||
58 | pv = period_cycles / (prescale + 1) - 1; | ||
59 | |||
60 | if (prescale > 63) | ||
61 | return -EINVAL; | ||
62 | |||
63 | if (duty_ns == period_ns) | ||
64 | dc = OST_PWMDCCR_FDCYCLE; | ||
65 | else | ||
66 | dc = (pv + 1) * duty_ns / period_ns; | ||
67 | |||
68 | /* | ||
69 | * NOTE: the clock to PWM has to be enabled first | ||
70 | * before writing to the registers | ||
71 | */ | ||
72 | clk_prepare_enable(puv3->clk); | ||
73 | |||
74 | writel(prescale, puv3->base + OST_PWM_PWCR); | ||
75 | writel(pv - dc, puv3->base + OST_PWM_DCCR); | ||
76 | writel(pv, puv3->base + OST_PWM_PCR); | ||
77 | |||
78 | clk_disable_unprepare(puv3->clk); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int puv3_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
84 | { | ||
85 | struct puv3_pwm_chip *puv3 = to_puv3(chip); | ||
86 | |||
87 | return clk_prepare_enable(puv3->clk); | ||
88 | } | ||
89 | |||
90 | static void puv3_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
91 | { | ||
92 | struct puv3_pwm_chip *puv3 = to_puv3(chip); | ||
93 | |||
94 | clk_disable_unprepare(puv3->clk); | ||
95 | } | ||
96 | |||
97 | static const struct pwm_ops puv3_pwm_ops = { | ||
98 | .config = puv3_pwm_config, | ||
99 | .enable = puv3_pwm_enable, | ||
100 | .disable = puv3_pwm_disable, | ||
101 | .owner = THIS_MODULE, | ||
102 | }; | ||
103 | |||
104 | static int __devinit pwm_probe(struct platform_device *pdev) | ||
105 | { | ||
106 | struct puv3_pwm_chip *puv3; | ||
107 | struct resource *r; | ||
108 | int ret; | ||
109 | |||
110 | puv3 = devm_kzalloc(&pdev->dev, sizeof(*puv3), GFP_KERNEL); | ||
111 | if (puv3 == NULL) { | ||
112 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
113 | return -ENOMEM; | ||
114 | } | ||
115 | |||
116 | puv3->clk = devm_clk_get(&pdev->dev, "OST_CLK"); | ||
117 | if (IS_ERR(puv3->clk)) | ||
118 | return PTR_ERR(puv3->clk); | ||
119 | |||
120 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
121 | if (r == NULL) { | ||
122 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
123 | return -ENODEV; | ||
124 | } | ||
125 | |||
126 | puv3->base = devm_request_and_ioremap(&pdev->dev, r); | ||
127 | if (puv3->base == NULL) | ||
128 | return -EADDRNOTAVAIL; | ||
129 | |||
130 | puv3->chip.dev = &pdev->dev; | ||
131 | puv3->chip.ops = &puv3_pwm_ops; | ||
132 | puv3->chip.base = -1; | ||
133 | puv3->chip.npwm = 1; | ||
134 | |||
135 | ret = pwmchip_add(&puv3->chip); | ||
136 | if (ret < 0) { | ||
137 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | platform_set_drvdata(pdev, puv3); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int __devexit pwm_remove(struct platform_device *pdev) | ||
146 | { | ||
147 | struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev); | ||
148 | |||
149 | return pwmchip_remove(&puv3->chip); | ||
150 | } | ||
151 | |||
152 | static struct platform_driver puv3_pwm_driver = { | ||
153 | .driver = { | ||
154 | .name = "PKUnity-v3-PWM", | ||
155 | }, | ||
156 | .probe = pwm_probe, | ||
157 | .remove = __devexit_p(pwm_remove), | ||
158 | }; | ||
159 | module_platform_driver(puv3_pwm_driver); | ||
160 | |||
161 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index bd5867a1c700..260c3a88564d 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c | |||
@@ -70,9 +70,6 @@ static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
70 | unsigned long offset; | 70 | unsigned long offset; |
71 | int rc; | 71 | int rc; |
72 | 72 | ||
73 | if (period_ns == 0 || duty_ns > period_ns) | ||
74 | return -EINVAL; | ||
75 | |||
76 | offset = pwm->hwpwm ? 0x10 : 0; | 73 | offset = pwm->hwpwm ? 0x10 : 0; |
77 | 74 | ||
78 | c = clk_get_rate(pc->clk); | 75 | c = clk_get_rate(pc->clk); |
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index e5187c0ade9f..023a3bee76e7 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c | |||
@@ -126,9 +126,6 @@ static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
126 | if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) | 126 | if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) |
127 | return -ERANGE; | 127 | return -ERANGE; |
128 | 128 | ||
129 | if (duty_ns > period_ns) | ||
130 | return -EINVAL; | ||
131 | |||
132 | if (period_ns == s3c->period_ns && | 129 | if (period_ns == s3c->period_ns && |
133 | duty_ns == s3c->duty_ns) | 130 | duty_ns == s3c->duty_ns) |
134 | return 0; | 131 | return 0; |
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 4b6688909fee..d6d4cf05565e 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #define CAP3 0x10 | 32 | #define CAP3 0x10 |
33 | #define CAP4 0x14 | 33 | #define CAP4 0x14 |
34 | #define ECCTL2 0x2A | 34 | #define ECCTL2 0x2A |
35 | #define ECCTL2_APWM_POL_LOW BIT(10) | ||
35 | #define ECCTL2_APWM_MODE BIT(9) | 36 | #define ECCTL2_APWM_MODE BIT(9) |
36 | #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) | 37 | #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) |
37 | #define ECCTL2_TSCTR_FREERUN BIT(4) | 38 | #define ECCTL2_TSCTR_FREERUN BIT(4) |
@@ -59,7 +60,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
59 | unsigned long period_cycles, duty_cycles; | 60 | unsigned long period_cycles, duty_cycles; |
60 | unsigned int reg_val; | 61 | unsigned int reg_val; |
61 | 62 | ||
62 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) | 63 | if (period_ns > NSEC_PER_SEC) |
63 | return -ERANGE; | 64 | return -ERANGE; |
64 | 65 | ||
65 | c = pc->clk_rate; | 66 | c = pc->clk_rate; |
@@ -111,6 +112,26 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
111 | return 0; | 112 | return 0; |
112 | } | 113 | } |
113 | 114 | ||
115 | static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, | ||
116 | enum pwm_polarity polarity) | ||
117 | { | ||
118 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); | ||
119 | unsigned short reg_val; | ||
120 | |||
121 | pm_runtime_get_sync(pc->chip.dev); | ||
122 | reg_val = readw(pc->mmio_base + ECCTL2); | ||
123 | if (polarity == PWM_POLARITY_INVERSED) | ||
124 | /* Duty cycle defines LOW period of PWM */ | ||
125 | reg_val |= ECCTL2_APWM_POL_LOW; | ||
126 | else | ||
127 | /* Duty cycle defines HIGH period of PWM */ | ||
128 | reg_val &= ~ECCTL2_APWM_POL_LOW; | ||
129 | |||
130 | writew(reg_val, pc->mmio_base + ECCTL2); | ||
131 | pm_runtime_put_sync(pc->chip.dev); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
114 | static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 135 | static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
115 | { | 136 | { |
116 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); | 137 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); |
@@ -157,6 +178,7 @@ static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |||
157 | static const struct pwm_ops ecap_pwm_ops = { | 178 | static const struct pwm_ops ecap_pwm_ops = { |
158 | .free = ecap_pwm_free, | 179 | .free = ecap_pwm_free, |
159 | .config = ecap_pwm_config, | 180 | .config = ecap_pwm_config, |
181 | .set_polarity = ecap_pwm_set_polarity, | ||
160 | .enable = ecap_pwm_enable, | 182 | .enable = ecap_pwm_enable, |
161 | .disable = ecap_pwm_disable, | 183 | .disable = ecap_pwm_disable, |
162 | .owner = THIS_MODULE, | 184 | .owner = THIS_MODULE, |
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index b1996bcd5b78..d3c1dff0a0dc 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c | |||
@@ -81,6 +81,15 @@ | |||
81 | #define AQCTL_ZRO_FRCHIGH BIT(1) | 81 | #define AQCTL_ZRO_FRCHIGH BIT(1) |
82 | #define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0)) | 82 | #define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0)) |
83 | 83 | ||
84 | #define AQCTL_CHANA_POLNORMAL (AQCTL_CAU_FRCLOW | AQCTL_PRD_FRCHIGH | \ | ||
85 | AQCTL_ZRO_FRCHIGH) | ||
86 | #define AQCTL_CHANA_POLINVERSED (AQCTL_CAU_FRCHIGH | AQCTL_PRD_FRCLOW | \ | ||
87 | AQCTL_ZRO_FRCLOW) | ||
88 | #define AQCTL_CHANB_POLNORMAL (AQCTL_CBU_FRCLOW | AQCTL_PRD_FRCHIGH | \ | ||
89 | AQCTL_ZRO_FRCHIGH) | ||
90 | #define AQCTL_CHANB_POLINVERSED (AQCTL_CBU_FRCHIGH | AQCTL_PRD_FRCLOW | \ | ||
91 | AQCTL_ZRO_FRCLOW) | ||
92 | |||
84 | #define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6)) | 93 | #define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6)) |
85 | #define AQSFRC_RLDCSF_ZRO 0 | 94 | #define AQSFRC_RLDCSF_ZRO 0 |
86 | #define AQSFRC_RLDCSF_PRD BIT(6) | 95 | #define AQSFRC_RLDCSF_PRD BIT(6) |
@@ -105,6 +114,7 @@ struct ehrpwm_pwm_chip { | |||
105 | unsigned int clk_rate; | 114 | unsigned int clk_rate; |
106 | void __iomem *mmio_base; | 115 | void __iomem *mmio_base; |
107 | unsigned long period_cycles[NUM_PWM_CHANNEL]; | 116 | unsigned long period_cycles[NUM_PWM_CHANNEL]; |
117 | enum pwm_polarity polarity[NUM_PWM_CHANNEL]; | ||
108 | }; | 118 | }; |
109 | 119 | ||
110 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | 120 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) |
@@ -165,39 +175,37 @@ static int set_prescale_div(unsigned long rqst_prescaler, | |||
165 | return 1; | 175 | return 1; |
166 | } | 176 | } |
167 | 177 | ||
168 | static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan, | 178 | static void configure_polarity(struct ehrpwm_pwm_chip *pc, int chan) |
169 | unsigned long duty_cycles) | ||
170 | { | 179 | { |
171 | int cmp_reg, aqctl_reg; | 180 | int aqctl_reg; |
172 | unsigned short aqctl_val, aqctl_mask; | 181 | unsigned short aqctl_val, aqctl_mask; |
173 | 182 | ||
174 | /* | 183 | /* |
175 | * Channels can be configured from action qualifier module. | 184 | * Configure PWM output to HIGH/LOW level on counter |
176 | * Channel 0 configured with compare A register and for | 185 | * reaches compare register value and LOW/HIGH level |
177 | * up-counter mode. | 186 | * on counter value reaches period register value and |
178 | * Channel 1 configured with compare B register and for | 187 | * zero value on counter |
179 | * up-counter mode. | ||
180 | */ | 188 | */ |
181 | if (chan == 1) { | 189 | if (chan == 1) { |
182 | aqctl_reg = AQCTLB; | 190 | aqctl_reg = AQCTLB; |
183 | cmp_reg = CMPB; | ||
184 | /* Configure PWM Low from compare B value */ | ||
185 | aqctl_val = AQCTL_CBU_FRCLOW; | ||
186 | aqctl_mask = AQCTL_CBU_MASK; | 191 | aqctl_mask = AQCTL_CBU_MASK; |
192 | |||
193 | if (pc->polarity[chan] == PWM_POLARITY_INVERSED) | ||
194 | aqctl_val = AQCTL_CHANB_POLINVERSED; | ||
195 | else | ||
196 | aqctl_val = AQCTL_CHANB_POLNORMAL; | ||
187 | } else { | 197 | } else { |
188 | cmp_reg = CMPA; | ||
189 | aqctl_reg = AQCTLA; | 198 | aqctl_reg = AQCTLA; |
190 | /* Configure PWM Low from compare A value*/ | ||
191 | aqctl_val = AQCTL_CAU_FRCLOW; | ||
192 | aqctl_mask = AQCTL_CAU_MASK; | 199 | aqctl_mask = AQCTL_CAU_MASK; |
200 | |||
201 | if (pc->polarity[chan] == PWM_POLARITY_INVERSED) | ||
202 | aqctl_val = AQCTL_CHANA_POLINVERSED; | ||
203 | else | ||
204 | aqctl_val = AQCTL_CHANA_POLNORMAL; | ||
193 | } | 205 | } |
194 | 206 | ||
195 | /* Configure PWM High from period value and zero value */ | ||
196 | aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH; | ||
197 | aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK; | 207 | aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK; |
198 | ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val); | 208 | ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val); |
199 | |||
200 | ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); | ||
201 | } | 209 | } |
202 | 210 | ||
203 | /* | 211 | /* |
@@ -211,9 +219,9 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
211 | unsigned long long c; | 219 | unsigned long long c; |
212 | unsigned long period_cycles, duty_cycles; | 220 | unsigned long period_cycles, duty_cycles; |
213 | unsigned short ps_divval, tb_divval; | 221 | unsigned short ps_divval, tb_divval; |
214 | int i; | 222 | int i, cmp_reg; |
215 | 223 | ||
216 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) | 224 | if (period_ns > NSEC_PER_SEC) |
217 | return -ERANGE; | 225 | return -ERANGE; |
218 | 226 | ||
219 | c = pc->clk_rate; | 227 | c = pc->clk_rate; |
@@ -278,12 +286,29 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
278 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK, | 286 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK, |
279 | TBCTL_CTRMODE_UP); | 287 | TBCTL_CTRMODE_UP); |
280 | 288 | ||
281 | /* Configure the channel for duty cycle */ | 289 | if (pwm->hwpwm == 1) |
282 | configure_chans(pc, pwm->hwpwm, duty_cycles); | 290 | /* Channel 1 configured with compare B register */ |
291 | cmp_reg = CMPB; | ||
292 | else | ||
293 | /* Channel 0 configured with compare A register */ | ||
294 | cmp_reg = CMPA; | ||
295 | |||
296 | ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); | ||
297 | |||
283 | pm_runtime_put_sync(chip->dev); | 298 | pm_runtime_put_sync(chip->dev); |
284 | return 0; | 299 | return 0; |
285 | } | 300 | } |
286 | 301 | ||
302 | static int ehrpwm_pwm_set_polarity(struct pwm_chip *chip, | ||
303 | struct pwm_device *pwm, enum pwm_polarity polarity) | ||
304 | { | ||
305 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | ||
306 | |||
307 | /* Configuration of polarity in hardware delayed, do at enable */ | ||
308 | pc->polarity[pwm->hwpwm] = polarity; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
287 | static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 312 | static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
288 | { | 313 | { |
289 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | 314 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); |
@@ -307,6 +332,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
307 | 332 | ||
308 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); | 333 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); |
309 | 334 | ||
335 | /* Channels polarity can be configured from action qualifier module */ | ||
336 | configure_polarity(pc, pwm->hwpwm); | ||
337 | |||
310 | /* Enable time counter for free_run */ | 338 | /* Enable time counter for free_run */ |
311 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); | 339 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); |
312 | return 0; | 340 | return 0; |
@@ -358,6 +386,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | |||
358 | static const struct pwm_ops ehrpwm_pwm_ops = { | 386 | static const struct pwm_ops ehrpwm_pwm_ops = { |
359 | .free = ehrpwm_pwm_free, | 387 | .free = ehrpwm_pwm_free, |
360 | .config = ehrpwm_pwm_config, | 388 | .config = ehrpwm_pwm_config, |
389 | .set_polarity = ehrpwm_pwm_set_polarity, | ||
361 | .enable = ehrpwm_pwm_enable, | 390 | .enable = ehrpwm_pwm_enable, |
362 | .disable = ehrpwm_pwm_disable, | 391 | .disable = ehrpwm_pwm_disable, |
363 | .owner = THIS_MODULE, | 392 | .owner = THIS_MODULE, |