diff options
44 files changed, 3308 insertions, 1007 deletions
diff --git a/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt b/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt new file mode 100644 index 000000000000..cfe1db3bb6e9 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | LPC32XX PWM controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "nxp,lpc3220-pwm" | ||
5 | - reg: physical base address and length of the controller's registers | ||
6 | |||
7 | Examples: | ||
8 | |||
9 | pwm@0x4005C000 { | ||
10 | compatible = "nxp,lpc3220-pwm"; | ||
11 | reg = <0x4005C000 0x8>; | ||
12 | }; | ||
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt new file mode 100644 index 000000000000..b16f4a57d111 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | Freescale MXS PWM controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "fsl,imx23-pwm" | ||
5 | - reg: physical base address and length of the controller's registers | ||
6 | - #pwm-cells: should be 2. The first cell specifies the per-chip index | ||
7 | of the PWM to use and the second cell is the duty cycle in nanoseconds. | ||
8 | - fsl,pwm-number: the number of PWM devices | ||
9 | |||
10 | Example: | ||
11 | |||
12 | pwm: pwm@80064000 { | ||
13 | compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; | ||
14 | reg = <0x80064000 2000>; | ||
15 | #pwm-cells = <2>; | ||
16 | fsl,pwm-number = <8>; | ||
17 | }; | ||
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt new file mode 100644 index 000000000000..bbbeedb4ec05 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | |||
@@ -0,0 +1,18 @@ | |||
1 | Tegra SoC PWFM controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be one of: | ||
5 | - "nvidia,tegra20-pwm" | ||
6 | - "nvidia,tegra30-pwm" | ||
7 | - reg: physical base address and length of the controller's registers | ||
8 | - #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The | ||
9 | first cell specifies the per-chip index of the PWM to use and the second | ||
10 | cell is the duty cycle in nanoseconds. | ||
11 | |||
12 | Example: | ||
13 | |||
14 | pwm: pwm@7000a000 { | ||
15 | compatible = "nvidia,tegra20-pwm"; | ||
16 | reg = <0x7000a000 0x100>; | ||
17 | #pwm-cells = <2>; | ||
18 | }; | ||
diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt new file mode 100644 index 000000000000..73ec962bfe8c --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm.txt | |||
@@ -0,0 +1,57 @@ | |||
1 | Specifying PWM information for devices | ||
2 | ====================================== | ||
3 | |||
4 | 1) PWM user nodes | ||
5 | ----------------- | ||
6 | |||
7 | PWM users should specify a list of PWM devices that they want to use | ||
8 | with a property containing a 'pwm-list': | ||
9 | |||
10 | pwm-list ::= <single-pwm> [pwm-list] | ||
11 | single-pwm ::= <pwm-phandle> <pwm-specifier> | ||
12 | pwm-phandle : phandle to PWM controller node | ||
13 | pwm-specifier : array of #pwm-cells specifying the given PWM | ||
14 | (controller specific) | ||
15 | |||
16 | PWM properties should be named "pwms". The exact meaning of each pwms | ||
17 | property must be documented in the device tree binding for each device. | ||
18 | An optional property "pwm-names" may contain a list of strings to label | ||
19 | each of the PWM devices listed in the "pwms" property. If no "pwm-names" | ||
20 | property is given, the name of the user node will be used as fallback. | ||
21 | |||
22 | Drivers for devices that use more than a single PWM device can use the | ||
23 | "pwm-names" property to map the name of the PWM device requested by the | ||
24 | pwm_get() call to an index into the list given by the "pwms" property. | ||
25 | |||
26 | The following example could be used to describe a PWM-based backlight | ||
27 | device: | ||
28 | |||
29 | pwm: pwm { | ||
30 | #pwm-cells = <2>; | ||
31 | }; | ||
32 | |||
33 | [...] | ||
34 | |||
35 | bl: backlight { | ||
36 | pwms = <&pwm 0 5000000>; | ||
37 | pwm-names = "backlight"; | ||
38 | }; | ||
39 | |||
40 | pwm-specifier typically encodes the chip-relative PWM number and the PWM | ||
41 | period in nanoseconds. Note that in the example above, specifying the | ||
42 | "pwm-names" is redundant because the name "backlight" would be used as | ||
43 | fallback anyway. | ||
44 | |||
45 | 2) PWM controller nodes | ||
46 | ----------------------- | ||
47 | |||
48 | PWM controller nodes must specify the number of cells used for the | ||
49 | specifier using the '#pwm-cells' property. | ||
50 | |||
51 | An example PWM controller might look like this: | ||
52 | |||
53 | pwm: pwm@7000a000 { | ||
54 | compatible = "nvidia,tegra20-pwm"; | ||
55 | reg = <0x7000a000 0x100>; | ||
56 | #pwm-cells = <2>; | ||
57 | }; | ||
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt new file mode 100644 index 000000000000..1e4fc727f3b1 --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | pwm-backlight bindings | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: "pwm-backlight" | ||
5 | - pwms: OF device-tree PWM specification (see PWM binding[0]) | ||
6 | - brightness-levels: Array of distinct brightness levels. Typically these | ||
7 | are in the range from 0 to 255, but any range starting at 0 will do. | ||
8 | The actual brightness level (PWM duty cycle) will be interpolated | ||
9 | from these values. 0 means a 0% duty cycle (darkest/off), while the | ||
10 | last value in the array represents a 100% duty cycle (brightest). | ||
11 | - default-brightness-level: the default brightness level (index into the | ||
12 | array defined by the "brightness-levels" property) | ||
13 | |||
14 | Optional properties: | ||
15 | - pwm-names: a list of names for the PWM devices specified in the | ||
16 | "pwms" property (see PWM binding[0]) | ||
17 | |||
18 | [0]: Documentation/devicetree/bindings/pwm/pwm.txt | ||
19 | |||
20 | Example: | ||
21 | |||
22 | backlight { | ||
23 | compatible = "pwm-backlight"; | ||
24 | pwms = <&pwm 0 5000000>; | ||
25 | |||
26 | brightness-levels = <0 4 8 16 32 64 128 255>; | ||
27 | default-brightness-level = <6>; | ||
28 | }; | ||
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt new file mode 100644 index 000000000000..554290ebab94 --- /dev/null +++ b/Documentation/pwm.txt | |||
@@ -0,0 +1,76 @@ | |||
1 | Pulse Width Modulation (PWM) interface | ||
2 | |||
3 | This provides an overview about the Linux PWM interface | ||
4 | |||
5 | PWMs are commonly used for controlling LEDs, fans or vibrators in | ||
6 | cell phones. PWMs with a fixed purpose have no need implementing | ||
7 | the Linux PWM API (although they could). However, PWMs are often | ||
8 | found as discrete devices on SoCs which have no fixed purpose. It's | ||
9 | up to the board designer to connect them to LEDs or fans. To provide | ||
10 | this kind of flexibility the generic PWM API exists. | ||
11 | |||
12 | Identifying PWMs | ||
13 | ---------------- | ||
14 | |||
15 | Users of the legacy PWM API use unique IDs to refer to PWM devices. | ||
16 | |||
17 | Instead of referring to a PWM device via its unique ID, board setup code | ||
18 | should instead register a static mapping that can be used to match PWM | ||
19 | consumers to providers, as given in the following example: | ||
20 | |||
21 | static struct pwm_lookup board_pwm_lookup[] = { | ||
22 | PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL), | ||
23 | }; | ||
24 | |||
25 | static void __init board_init(void) | ||
26 | { | ||
27 | ... | ||
28 | pwm_add_table(board_pwm_lookup, ARRAY_SIZE(board_pwm_lookup)); | ||
29 | ... | ||
30 | } | ||
31 | |||
32 | Using PWMs | ||
33 | ---------- | ||
34 | |||
35 | Legacy users can request a PWM device using pwm_request() and free it | ||
36 | after usage with pwm_free(). | ||
37 | |||
38 | New users should use the pwm_get() function and pass to it the consumer | ||
39 | device or a consumer name. pwm_put() is used to free the PWM device. | ||
40 | |||
41 | After being requested a PWM has to be configured using: | ||
42 | |||
43 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns); | ||
44 | |||
45 | To start/stop toggling the PWM output use pwm_enable()/pwm_disable(). | ||
46 | |||
47 | Implementing a PWM driver | ||
48 | ------------------------- | ||
49 | |||
50 | Currently there are two ways to implement pwm drivers. Traditionally | ||
51 | there only has been the barebone API meaning that each driver has | ||
52 | to implement the pwm_*() functions itself. This means that it's impossible | ||
53 | to have multiple PWM drivers in the system. For this reason it's mandatory | ||
54 | for new drivers to use the generic PWM framework. | ||
55 | |||
56 | A new PWM controller/chip can be added using pwmchip_add() and removed | ||
57 | again with pwmchip_remove(). pwmchip_add() takes a filled in struct | ||
58 | pwm_chip as argument which provides a description of the PWM chip, the | ||
59 | number of PWM devices provider by the chip and the chip-specific | ||
60 | implementation of the supported PWM operations to the framework. | ||
61 | |||
62 | Locking | ||
63 | ------- | ||
64 | |||
65 | The PWM core list manipulations are protected by a mutex, so pwm_request() | ||
66 | and pwm_free() may not be called from an atomic context. Currently the | ||
67 | PWM core does not enforce any locking to pwm_enable(), pwm_disable() and | ||
68 | pwm_config(), so the calling context is currently driver specific. This | ||
69 | is an issue derived from the former barebone API and should be fixed soon. | ||
70 | |||
71 | Helpers | ||
72 | ------- | ||
73 | |||
74 | Currently a PWM can only be configured with period_ns and duty_ns. For several | ||
75 | use cases freq_hz and duty_percent might be better. Instead of calculating | ||
76 | this in your driver please consider adding appropriate helpers to the framework. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index bd451649f13a..b141083b2621 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5526,6 +5526,18 @@ S: Maintained | |||
5526 | F: Documentation/video4linux/README.pvrusb2 | 5526 | F: Documentation/video4linux/README.pvrusb2 |
5527 | F: drivers/media/video/pvrusb2/ | 5527 | F: drivers/media/video/pvrusb2/ |
5528 | 5528 | ||
5529 | PWM SUBSYSTEM | ||
5530 | M: Thierry Reding <thierry.reding@avionic-design.de> | ||
5531 | L: linux-kernel@vger.kernel.org | ||
5532 | S: Maintained | ||
5533 | W: http://gitorious.org/linux-pwm | ||
5534 | T: git git://gitorious.org/linux-pwm/linux-pwm.git | ||
5535 | F: Documentation/pwm.txt | ||
5536 | F: Documentation/devicetree/bindings/pwm/ | ||
5537 | F: include/linux/pwm.h | ||
5538 | F: include/linux/of_pwm.h | ||
5539 | F: drivers/pwm/ | ||
5540 | |||
5529 | PXA2xx/PXA3xx SUPPORT | 5541 | PXA2xx/PXA3xx SUPPORT |
5530 | M: Eric Miao <eric.y.miao@gmail.com> | 5542 | M: Eric Miao <eric.y.miao@gmail.com> |
5531 | M: Russell King <linux@arm.linux.org.uk> | 5543 | M: Russell King <linux@arm.linux.org.uk> |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fbdd8533c05d..6b86bb963a28 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1009,7 +1009,6 @@ config ARCH_VT8500 | |||
1009 | select ARCH_HAS_CPUFREQ | 1009 | select ARCH_HAS_CPUFREQ |
1010 | select GENERIC_CLOCKEVENTS | 1010 | select GENERIC_CLOCKEVENTS |
1011 | select ARCH_REQUIRE_GPIOLIB | 1011 | select ARCH_REQUIRE_GPIOLIB |
1012 | select HAVE_PWM | ||
1013 | help | 1012 | help |
1014 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. | 1013 | Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. |
1015 | 1014 | ||
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 9f1921634eb7..405d1673904e 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi | |||
@@ -123,6 +123,12 @@ | |||
123 | status = "disabled"; | 123 | status = "disabled"; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | pwm { | ||
127 | compatible = "nvidia,tegra20-pwm"; | ||
128 | reg = <0x7000a000 0x100>; | ||
129 | #pwm-cells = <2>; | ||
130 | }; | ||
131 | |||
126 | i2c@7000c000 { | 132 | i2c@7000c000 { |
127 | compatible = "nvidia,tegra20-i2c"; | 133 | compatible = "nvidia,tegra20-i2c"; |
128 | reg = <0x7000c000 0x100>; | 134 | reg = <0x7000c000 0x100>; |
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index da740191771f..3e4334d14efb 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi | |||
@@ -117,6 +117,12 @@ | |||
117 | status = "disabled"; | 117 | status = "disabled"; |
118 | }; | 118 | }; |
119 | 119 | ||
120 | pwm { | ||
121 | compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; | ||
122 | reg = <0x7000a000 0x100>; | ||
123 | #pwm-cells = <2>; | ||
124 | }; | ||
125 | |||
120 | i2c@7000c000 { | 126 | i2c@7000c000 { |
121 | compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; | 127 | compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; |
122 | reg = <0x7000c000 0x100>; | 128 | reg = <0x7000c000 0x100>; |
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index d0de9c1192f7..c0999633a9ab 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c | |||
@@ -64,7 +64,8 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { | |||
64 | &tegra_ehci2_pdata), | 64 | &tegra_ehci2_pdata), |
65 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", | 65 | OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2", |
66 | &tegra_ehci3_pdata), | 66 | &tegra_ehci3_pdata), |
67 | OF_DEV_AUXDATA("nvidia,tegra20-apbdma", 0x6000a000, "tegra-apbdma", NULL), | 67 | OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL), |
68 | OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), | ||
68 | {} | 69 | {} |
69 | }; | 70 | }; |
70 | 71 | ||
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index ee48214bfd89..53bf60f11580 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
34 | #include <asm/hardware/gic.h> | 34 | #include <asm/hardware/gic.h> |
35 | 35 | ||
36 | #include <mach/iomap.h> | ||
37 | |||
36 | #include "board.h" | 38 | #include "board.h" |
37 | #include "clock.h" | 39 | #include "clock.h" |
38 | 40 | ||
@@ -48,6 +50,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { | |||
48 | OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), | 50 | OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), |
49 | OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), | 51 | OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), |
50 | OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), | 52 | OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL), |
53 | OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), | ||
51 | {} | 54 | {} |
52 | }; | 55 | }; |
53 | 56 | ||
diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile index 54e69973f39b..7ce51767c99c 100644 --- a/arch/arm/mach-vt8500/Makefile +++ b/arch/arm/mach-vt8500/Makefile | |||
@@ -5,5 +5,3 @@ obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o | |||
5 | 5 | ||
6 | obj-$(CONFIG_MACH_BV07) += bv07.o | 6 | obj-$(CONFIG_MACH_BV07) += bv07.o |
7 | obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o | 7 | obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o |
8 | |||
9 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c deleted file mode 100644 index 8ad825e93592..000000000000 --- a/arch/arm/mach-vt8500/pwm.c +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-vt8500/pwm.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/pwm.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <asm/div64.h> | ||
26 | |||
27 | #define VT8500_NR_PWMS 4 | ||
28 | |||
29 | static DEFINE_MUTEX(pwm_lock); | ||
30 | static LIST_HEAD(pwm_list); | ||
31 | |||
32 | struct pwm_device { | ||
33 | struct list_head node; | ||
34 | struct platform_device *pdev; | ||
35 | |||
36 | const char *label; | ||
37 | |||
38 | void __iomem *regbase; | ||
39 | |||
40 | unsigned int use_count; | ||
41 | unsigned int pwm_id; | ||
42 | }; | ||
43 | |||
44 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | ||
45 | static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) | ||
46 | { | ||
47 | int loops = msecs_to_loops(10); | ||
48 | while ((readb(reg) & bitmask) && --loops) | ||
49 | cpu_relax(); | ||
50 | |||
51 | if (unlikely(!loops)) | ||
52 | pr_warning("Waiting for status bits 0x%x to clear timed out\n", | ||
53 | bitmask); | ||
54 | } | ||
55 | |||
56 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
57 | { | ||
58 | unsigned long long c; | ||
59 | unsigned long period_cycles, prescale, pv, dc; | ||
60 | |||
61 | if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | ||
62 | return -EINVAL; | ||
63 | |||
64 | c = 25000000/2; /* wild guess --- need to implement clocks */ | ||
65 | c = c * period_ns; | ||
66 | do_div(c, 1000000000); | ||
67 | period_cycles = c; | ||
68 | |||
69 | if (period_cycles < 1) | ||
70 | period_cycles = 1; | ||
71 | prescale = (period_cycles - 1) / 4096; | ||
72 | pv = period_cycles / (prescale + 1) - 1; | ||
73 | if (pv > 4095) | ||
74 | pv = 4095; | ||
75 | |||
76 | if (prescale > 1023) | ||
77 | return -EINVAL; | ||
78 | |||
79 | c = (unsigned long long)pv * duty_ns; | ||
80 | do_div(c, period_ns); | ||
81 | dc = c; | ||
82 | |||
83 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1)); | ||
84 | writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4)); | ||
85 | |||
86 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2)); | ||
87 | writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4)); | ||
88 | |||
89 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3)); | ||
90 | writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4)); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | EXPORT_SYMBOL(pwm_config); | ||
95 | |||
96 | int pwm_enable(struct pwm_device *pwm) | ||
97 | { | ||
98 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); | ||
99 | writel(5, pwm->regbase + (pwm->pwm_id << 4)); | ||
100 | return 0; | ||
101 | } | ||
102 | EXPORT_SYMBOL(pwm_enable); | ||
103 | |||
104 | void pwm_disable(struct pwm_device *pwm) | ||
105 | { | ||
106 | pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); | ||
107 | writel(0, pwm->regbase + (pwm->pwm_id << 4)); | ||
108 | } | ||
109 | EXPORT_SYMBOL(pwm_disable); | ||
110 | |||
111 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
112 | { | ||
113 | struct pwm_device *pwm; | ||
114 | int found = 0; | ||
115 | |||
116 | mutex_lock(&pwm_lock); | ||
117 | |||
118 | list_for_each_entry(pwm, &pwm_list, node) { | ||
119 | if (pwm->pwm_id == pwm_id) { | ||
120 | found = 1; | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | if (found) { | ||
126 | if (pwm->use_count == 0) { | ||
127 | pwm->use_count++; | ||
128 | pwm->label = label; | ||
129 | } else { | ||
130 | pwm = ERR_PTR(-EBUSY); | ||
131 | } | ||
132 | } else { | ||
133 | pwm = ERR_PTR(-ENOENT); | ||
134 | } | ||
135 | |||
136 | mutex_unlock(&pwm_lock); | ||
137 | return pwm; | ||
138 | } | ||
139 | EXPORT_SYMBOL(pwm_request); | ||
140 | |||
141 | void pwm_free(struct pwm_device *pwm) | ||
142 | { | ||
143 | mutex_lock(&pwm_lock); | ||
144 | |||
145 | if (pwm->use_count) { | ||
146 | pwm->use_count--; | ||
147 | pwm->label = NULL; | ||
148 | } else { | ||
149 | pr_warning("PWM device already freed\n"); | ||
150 | } | ||
151 | |||
152 | mutex_unlock(&pwm_lock); | ||
153 | } | ||
154 | EXPORT_SYMBOL(pwm_free); | ||
155 | |||
156 | static inline void __add_pwm(struct pwm_device *pwm) | ||
157 | { | ||
158 | mutex_lock(&pwm_lock); | ||
159 | list_add_tail(&pwm->node, &pwm_list); | ||
160 | mutex_unlock(&pwm_lock); | ||
161 | } | ||
162 | |||
163 | static int __devinit pwm_probe(struct platform_device *pdev) | ||
164 | { | ||
165 | struct pwm_device *pwms; | ||
166 | struct resource *r; | ||
167 | int ret = 0; | ||
168 | int i; | ||
169 | |||
170 | pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL); | ||
171 | if (pwms == NULL) { | ||
172 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | |||
176 | for (i = 0; i < VT8500_NR_PWMS; i++) { | ||
177 | pwms[i].use_count = 0; | ||
178 | pwms[i].pwm_id = i; | ||
179 | pwms[i].pdev = pdev; | ||
180 | } | ||
181 | |||
182 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
183 | if (r == NULL) { | ||
184 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
185 | ret = -ENODEV; | ||
186 | goto err_free; | ||
187 | } | ||
188 | |||
189 | r = request_mem_region(r->start, resource_size(r), pdev->name); | ||
190 | if (r == NULL) { | ||
191 | dev_err(&pdev->dev, "failed to request memory resource\n"); | ||
192 | ret = -EBUSY; | ||
193 | goto err_free; | ||
194 | } | ||
195 | |||
196 | pwms[0].regbase = ioremap(r->start, resource_size(r)); | ||
197 | if (pwms[0].regbase == NULL) { | ||
198 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | ||
199 | ret = -ENODEV; | ||
200 | goto err_free_mem; | ||
201 | } | ||
202 | |||
203 | for (i = 1; i < VT8500_NR_PWMS; i++) | ||
204 | pwms[i].regbase = pwms[0].regbase; | ||
205 | |||
206 | for (i = 0; i < VT8500_NR_PWMS; i++) | ||
207 | __add_pwm(&pwms[i]); | ||
208 | |||
209 | platform_set_drvdata(pdev, pwms); | ||
210 | return 0; | ||
211 | |||
212 | err_free_mem: | ||
213 | release_mem_region(r->start, resource_size(r)); | ||
214 | err_free: | ||
215 | kfree(pwms); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int __devexit pwm_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | struct pwm_device *pwms; | ||
222 | struct resource *r; | ||
223 | int i; | ||
224 | |||
225 | pwms = platform_get_drvdata(pdev); | ||
226 | if (pwms == NULL) | ||
227 | return -ENODEV; | ||
228 | |||
229 | mutex_lock(&pwm_lock); | ||
230 | |||
231 | for (i = 0; i < VT8500_NR_PWMS; i++) | ||
232 | list_del(&pwms[i].node); | ||
233 | mutex_unlock(&pwm_lock); | ||
234 | |||
235 | iounmap(pwms[0].regbase); | ||
236 | |||
237 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
238 | release_mem_region(r->start, resource_size(r)); | ||
239 | |||
240 | kfree(pwms); | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static struct platform_driver pwm_driver = { | ||
245 | .driver = { | ||
246 | .name = "vt8500-pwm", | ||
247 | .owner = THIS_MODULE, | ||
248 | }, | ||
249 | .probe = pwm_probe, | ||
250 | .remove = __devexit_p(pwm_remove), | ||
251 | }; | ||
252 | |||
253 | static int __init pwm_init(void) | ||
254 | { | ||
255 | return platform_driver_register(&pwm_driver); | ||
256 | } | ||
257 | arch_initcall(pwm_init); | ||
258 | |||
259 | static void __exit pwm_exit(void) | ||
260 | { | ||
261 | platform_driver_unregister(&pwm_driver); | ||
262 | } | ||
263 | module_exit(pwm_exit); | ||
264 | |||
265 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index c722f9ce6918..baf9064c0844 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig | |||
@@ -47,12 +47,6 @@ config MXC_TZIC | |||
47 | config MXC_AVIC | 47 | config MXC_AVIC |
48 | bool | 48 | bool |
49 | 49 | ||
50 | config MXC_PWM | ||
51 | tristate "Enable PWM driver" | ||
52 | select HAVE_PWM | ||
53 | help | ||
54 | Enable support for the i.MX PWM controller(s). | ||
55 | |||
56 | config MXC_DEBUG_BOARD | 50 | config MXC_DEBUG_BOARD |
57 | bool "Enable MXC debug board(for 3-stack)" | 51 | bool "Enable MXC debug board(for 3-stack)" |
58 | help | 52 | help |
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 63b064b5c1d5..6ac720031150 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile | |||
@@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o | |||
11 | obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o | 11 | obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o |
12 | obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o | 12 | obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o |
13 | obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o | 13 | obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o |
14 | obj-$(CONFIG_MXC_PWM) += pwm.o | ||
15 | obj-$(CONFIG_MXC_ULPI) += ulpi.o | 14 | obj-$(CONFIG_MXC_ULPI) += ulpi.o |
16 | obj-$(CONFIG_MXC_USE_EPIT) += epit.o | 15 | obj-$(CONFIG_MXC_USE_EPIT) += epit.o |
17 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | 16 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o |
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile index f302d048392d..af8e484001e5 100644 --- a/arch/arm/plat-pxa/Makefile +++ b/arch/arm/plat-pxa/Makefile | |||
@@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx) += mfp.o | |||
8 | obj-$(CONFIG_PXA95x) += mfp.o | 8 | obj-$(CONFIG_PXA95x) += mfp.o |
9 | obj-$(CONFIG_ARCH_MMP) += mfp.o | 9 | obj-$(CONFIG_ARCH_MMP) += mfp.o |
10 | 10 | ||
11 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
12 | obj-$(CONFIG_PXA_SSP) += ssp.o | 11 | obj-$(CONFIG_PXA_SSP) += ssp.o |
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c deleted file mode 100644 index ef32686feef9..000000000000 --- a/arch/arm/plat-pxa/pwm.c +++ /dev/null | |||
@@ -1,304 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/pwm.c | ||
3 | * | ||
4 | * simple driver for PWM (Pulse Width Modulator) controller | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * 2008-02-13 initial version | ||
11 | * eric miao <eric.miao@marvell.com> | ||
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 | |||
25 | #define HAS_SECONDARY_PWM 0x10 | ||
26 | #define PWM_ID_BASE(d) ((d) & 0xf) | ||
27 | |||
28 | static const struct platform_device_id pwm_id_table[] = { | ||
29 | /* PWM has_secondary_pwm? */ | ||
30 | { "pxa25x-pwm", 0 }, | ||
31 | { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM }, | ||
32 | { "pxa168-pwm", 1 }, | ||
33 | { "pxa910-pwm", 1 }, | ||
34 | { }, | ||
35 | }; | ||
36 | MODULE_DEVICE_TABLE(platform, pwm_id_table); | ||
37 | |||
38 | /* PWM registers and bits definitions */ | ||
39 | #define PWMCR (0x00) | ||
40 | #define PWMDCR (0x04) | ||
41 | #define PWMPCR (0x08) | ||
42 | |||
43 | #define PWMCR_SD (1 << 6) | ||
44 | #define PWMDCR_FD (1 << 10) | ||
45 | |||
46 | struct pwm_device { | ||
47 | struct list_head node; | ||
48 | struct pwm_device *secondary; | ||
49 | struct platform_device *pdev; | ||
50 | |||
51 | const char *label; | ||
52 | struct clk *clk; | ||
53 | int clk_enabled; | ||
54 | void __iomem *mmio_base; | ||
55 | |||
56 | unsigned int use_count; | ||
57 | unsigned int pwm_id; | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE | ||
62 | * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE | ||
63 | */ | ||
64 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
65 | { | ||
66 | unsigned long long c; | ||
67 | unsigned long period_cycles, prescale, pv, dc; | ||
68 | |||
69 | if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | ||
70 | return -EINVAL; | ||
71 | |||
72 | c = clk_get_rate(pwm->clk); | ||
73 | c = c * period_ns; | ||
74 | do_div(c, 1000000000); | ||
75 | period_cycles = c; | ||
76 | |||
77 | if (period_cycles < 1) | ||
78 | period_cycles = 1; | ||
79 | prescale = (period_cycles - 1) / 1024; | ||
80 | pv = period_cycles / (prescale + 1) - 1; | ||
81 | |||
82 | if (prescale > 63) | ||
83 | return -EINVAL; | ||
84 | |||
85 | if (duty_ns == period_ns) | ||
86 | dc = PWMDCR_FD; | ||
87 | else | ||
88 | dc = (pv + 1) * duty_ns / period_ns; | ||
89 | |||
90 | /* NOTE: the clock to PWM has to be enabled first | ||
91 | * before writing to the registers | ||
92 | */ | ||
93 | clk_enable(pwm->clk); | ||
94 | __raw_writel(prescale, pwm->mmio_base + PWMCR); | ||
95 | __raw_writel(dc, pwm->mmio_base + PWMDCR); | ||
96 | __raw_writel(pv, pwm->mmio_base + PWMPCR); | ||
97 | clk_disable(pwm->clk); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | EXPORT_SYMBOL(pwm_config); | ||
102 | |||
103 | int pwm_enable(struct pwm_device *pwm) | ||
104 | { | ||
105 | int rc = 0; | ||
106 | |||
107 | if (!pwm->clk_enabled) { | ||
108 | rc = clk_enable(pwm->clk); | ||
109 | if (!rc) | ||
110 | pwm->clk_enabled = 1; | ||
111 | } | ||
112 | return rc; | ||
113 | } | ||
114 | EXPORT_SYMBOL(pwm_enable); | ||
115 | |||
116 | void pwm_disable(struct pwm_device *pwm) | ||
117 | { | ||
118 | if (pwm->clk_enabled) { | ||
119 | clk_disable(pwm->clk); | ||
120 | pwm->clk_enabled = 0; | ||
121 | } | ||
122 | } | ||
123 | EXPORT_SYMBOL(pwm_disable); | ||
124 | |||
125 | static DEFINE_MUTEX(pwm_lock); | ||
126 | static LIST_HEAD(pwm_list); | ||
127 | |||
128 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
129 | { | ||
130 | struct pwm_device *pwm; | ||
131 | int found = 0; | ||
132 | |||
133 | mutex_lock(&pwm_lock); | ||
134 | |||
135 | list_for_each_entry(pwm, &pwm_list, node) { | ||
136 | if (pwm->pwm_id == pwm_id) { | ||
137 | found = 1; | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | if (found) { | ||
143 | if (pwm->use_count == 0) { | ||
144 | pwm->use_count++; | ||
145 | pwm->label = label; | ||
146 | } else | ||
147 | pwm = ERR_PTR(-EBUSY); | ||
148 | } else | ||
149 | pwm = ERR_PTR(-ENOENT); | ||
150 | |||
151 | mutex_unlock(&pwm_lock); | ||
152 | return pwm; | ||
153 | } | ||
154 | EXPORT_SYMBOL(pwm_request); | ||
155 | |||
156 | void pwm_free(struct pwm_device *pwm) | ||
157 | { | ||
158 | mutex_lock(&pwm_lock); | ||
159 | |||
160 | if (pwm->use_count) { | ||
161 | pwm->use_count--; | ||
162 | pwm->label = NULL; | ||
163 | } else | ||
164 | pr_warning("PWM device already freed\n"); | ||
165 | |||
166 | mutex_unlock(&pwm_lock); | ||
167 | } | ||
168 | EXPORT_SYMBOL(pwm_free); | ||
169 | |||
170 | static inline void __add_pwm(struct pwm_device *pwm) | ||
171 | { | ||
172 | mutex_lock(&pwm_lock); | ||
173 | list_add_tail(&pwm->node, &pwm_list); | ||
174 | mutex_unlock(&pwm_lock); | ||
175 | } | ||
176 | |||
177 | static int __devinit pwm_probe(struct platform_device *pdev) | ||
178 | { | ||
179 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
180 | struct pwm_device *pwm, *secondary = NULL; | ||
181 | struct resource *r; | ||
182 | int ret = 0; | ||
183 | |||
184 | pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | ||
185 | if (pwm == NULL) { | ||
186 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
187 | return -ENOMEM; | ||
188 | } | ||
189 | |||
190 | pwm->clk = clk_get(&pdev->dev, NULL); | ||
191 | if (IS_ERR(pwm->clk)) { | ||
192 | ret = PTR_ERR(pwm->clk); | ||
193 | goto err_free; | ||
194 | } | ||
195 | pwm->clk_enabled = 0; | ||
196 | |||
197 | pwm->use_count = 0; | ||
198 | pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id; | ||
199 | pwm->pdev = pdev; | ||
200 | |||
201 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
202 | if (r == NULL) { | ||
203 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
204 | ret = -ENODEV; | ||
205 | goto err_free_clk; | ||
206 | } | ||
207 | |||
208 | r = request_mem_region(r->start, resource_size(r), pdev->name); | ||
209 | if (r == NULL) { | ||
210 | dev_err(&pdev->dev, "failed to request memory resource\n"); | ||
211 | ret = -EBUSY; | ||
212 | goto err_free_clk; | ||
213 | } | ||
214 | |||
215 | pwm->mmio_base = ioremap(r->start, resource_size(r)); | ||
216 | if (pwm->mmio_base == NULL) { | ||
217 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | ||
218 | ret = -ENODEV; | ||
219 | goto err_free_mem; | ||
220 | } | ||
221 | |||
222 | if (id->driver_data & HAS_SECONDARY_PWM) { | ||
223 | secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | ||
224 | if (secondary == NULL) { | ||
225 | ret = -ENOMEM; | ||
226 | goto err_free_mem; | ||
227 | } | ||
228 | |||
229 | *secondary = *pwm; | ||
230 | pwm->secondary = secondary; | ||
231 | |||
232 | /* registers for the second PWM has offset of 0x10 */ | ||
233 | secondary->mmio_base = pwm->mmio_base + 0x10; | ||
234 | secondary->pwm_id = pdev->id + 2; | ||
235 | } | ||
236 | |||
237 | __add_pwm(pwm); | ||
238 | if (secondary) | ||
239 | __add_pwm(secondary); | ||
240 | |||
241 | platform_set_drvdata(pdev, pwm); | ||
242 | return 0; | ||
243 | |||
244 | err_free_mem: | ||
245 | release_mem_region(r->start, resource_size(r)); | ||
246 | err_free_clk: | ||
247 | clk_put(pwm->clk); | ||
248 | err_free: | ||
249 | kfree(pwm); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | static int __devexit pwm_remove(struct platform_device *pdev) | ||
254 | { | ||
255 | struct pwm_device *pwm; | ||
256 | struct resource *r; | ||
257 | |||
258 | pwm = platform_get_drvdata(pdev); | ||
259 | if (pwm == NULL) | ||
260 | return -ENODEV; | ||
261 | |||
262 | mutex_lock(&pwm_lock); | ||
263 | |||
264 | if (pwm->secondary) { | ||
265 | list_del(&pwm->secondary->node); | ||
266 | kfree(pwm->secondary); | ||
267 | } | ||
268 | |||
269 | list_del(&pwm->node); | ||
270 | mutex_unlock(&pwm_lock); | ||
271 | |||
272 | iounmap(pwm->mmio_base); | ||
273 | |||
274 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
275 | release_mem_region(r->start, resource_size(r)); | ||
276 | |||
277 | clk_put(pwm->clk); | ||
278 | kfree(pwm); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static struct platform_driver pwm_driver = { | ||
283 | .driver = { | ||
284 | .name = "pxa25x-pwm", | ||
285 | .owner = THIS_MODULE, | ||
286 | }, | ||
287 | .probe = pwm_probe, | ||
288 | .remove = __devexit_p(pwm_remove), | ||
289 | .id_table = pwm_id_table, | ||
290 | }; | ||
291 | |||
292 | static int __init pwm_init(void) | ||
293 | { | ||
294 | return platform_driver_register(&pwm_driver); | ||
295 | } | ||
296 | arch_initcall(pwm_init); | ||
297 | |||
298 | static void __exit pwm_exit(void) | ||
299 | { | ||
300 | platform_driver_unregister(&pwm_driver); | ||
301 | } | ||
302 | module_exit(pwm_exit); | ||
303 | |||
304 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index b78717496677..9e40e8d00740 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile | |||
@@ -59,7 +59,3 @@ obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o | |||
59 | 59 | ||
60 | obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o | 60 | obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o |
61 | obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o | 61 | obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o |
62 | |||
63 | # PWM support | ||
64 | |||
65 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 9b765107e15c..ec44fc6c34ca 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig | |||
@@ -1002,16 +1002,6 @@ config BFIN_GPTIMERS | |||
1002 | To compile this driver as a module, choose M here: the module | 1002 | To compile this driver as a module, choose M here: the module |
1003 | will be called gptimers. | 1003 | will be called gptimers. |
1004 | 1004 | ||
1005 | config HAVE_PWM | ||
1006 | tristate "Enable PWM API support" | ||
1007 | depends on BFIN_GPTIMERS | ||
1008 | help | ||
1009 | Enable support for the Pulse Width Modulation framework (as | ||
1010 | found in linux/pwm.h). | ||
1011 | |||
1012 | To compile this driver as a module, choose M here: the module | ||
1013 | will be called pwm. | ||
1014 | |||
1015 | choice | 1005 | choice |
1016 | prompt "Uncached DMA region" | 1006 | prompt "Uncached DMA region" |
1017 | default DMA_UNCACHED_1M | 1007 | default DMA_UNCACHED_1M |
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 08e6625106be..735f24e07425 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile | |||
@@ -21,7 +21,6 @@ obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o | |||
21 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 21 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
22 | CFLAGS_REMOVE_ftrace.o = -pg | 22 | CFLAGS_REMOVE_ftrace.o = -pg |
23 | 23 | ||
24 | obj-$(CONFIG_HAVE_PWM) += pwm.o | ||
25 | obj-$(CONFIG_IPIPE) += ipipe.o | 24 | obj-$(CONFIG_IPIPE) += ipipe.o |
26 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o | 25 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o |
27 | obj-$(CONFIG_CPLB_INFO) += cplbinfo.o | 26 | obj-$(CONFIG_CPLB_INFO) += cplbinfo.o |
diff --git a/arch/blackfin/kernel/pwm.c b/arch/blackfin/kernel/pwm.c deleted file mode 100644 index 33f5942733bd..000000000000 --- a/arch/blackfin/kernel/pwm.c +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
1 | /* | ||
2 | * Blackfin Pulse Width Modulation (PWM) core | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/pwm.h> | ||
11 | #include <linux/slab.h> | ||
12 | |||
13 | #include <asm/gptimers.h> | ||
14 | #include <asm/portmux.h> | ||
15 | |||
16 | struct pwm_device { | ||
17 | unsigned id; | ||
18 | unsigned short pin; | ||
19 | }; | ||
20 | |||
21 | static const unsigned short pwm_to_gptimer_per[] = { | ||
22 | P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5, | ||
23 | P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11, | ||
24 | }; | ||
25 | |||
26 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
27 | { | ||
28 | struct pwm_device *pwm; | ||
29 | int ret; | ||
30 | |||
31 | /* XXX: pwm_id really should be unsigned */ | ||
32 | if (pwm_id < 0) | ||
33 | return NULL; | ||
34 | |||
35 | pwm = kzalloc(sizeof(*pwm), GFP_KERNEL); | ||
36 | if (!pwm) | ||
37 | return pwm; | ||
38 | |||
39 | pwm->id = pwm_id; | ||
40 | if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per)) | ||
41 | goto err; | ||
42 | |||
43 | pwm->pin = pwm_to_gptimer_per[pwm->id]; | ||
44 | ret = peripheral_request(pwm->pin, label); | ||
45 | if (ret) | ||
46 | goto err; | ||
47 | |||
48 | return pwm; | ||
49 | err: | ||
50 | kfree(pwm); | ||
51 | return NULL; | ||
52 | } | ||
53 | EXPORT_SYMBOL(pwm_request); | ||
54 | |||
55 | void pwm_free(struct pwm_device *pwm) | ||
56 | { | ||
57 | peripheral_free(pwm->pin); | ||
58 | kfree(pwm); | ||
59 | } | ||
60 | EXPORT_SYMBOL(pwm_free); | ||
61 | |||
62 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
63 | { | ||
64 | unsigned long period, duty; | ||
65 | unsigned long long val; | ||
66 | |||
67 | if (duty_ns < 0 || duty_ns > period_ns) | ||
68 | return -EINVAL; | ||
69 | |||
70 | val = (unsigned long long)get_sclk() * period_ns; | ||
71 | do_div(val, NSEC_PER_SEC); | ||
72 | period = val; | ||
73 | |||
74 | val = (unsigned long long)period * duty_ns; | ||
75 | do_div(val, period_ns); | ||
76 | duty = period - val; | ||
77 | |||
78 | if (duty >= period) | ||
79 | duty = period - 1; | ||
80 | |||
81 | set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT); | ||
82 | set_gptimer_pwidth(pwm->id, duty); | ||
83 | set_gptimer_period(pwm->id, period); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL(pwm_config); | ||
88 | |||
89 | int pwm_enable(struct pwm_device *pwm) | ||
90 | { | ||
91 | enable_gptimer(pwm->id); | ||
92 | return 0; | ||
93 | } | ||
94 | EXPORT_SYMBOL(pwm_enable); | ||
95 | |||
96 | void pwm_disable(struct pwm_device *pwm) | ||
97 | { | ||
98 | disable_gptimer(pwm->id); | ||
99 | } | ||
100 | EXPORT_SYMBOL(pwm_disable); | ||
diff --git a/drivers/Kconfig b/drivers/Kconfig index bfc918633fd9..805c432c9439 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -148,4 +148,6 @@ source "drivers/iio/Kconfig" | |||
148 | 148 | ||
149 | source "drivers/vme/Kconfig" | 149 | source "drivers/vme/Kconfig" |
150 | 150 | ||
151 | source "drivers/pwm/Kconfig" | ||
152 | |||
151 | endmenu | 153 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index 2ba29ffef2cb..bd36f09f2246 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -8,6 +8,7 @@ | |||
8 | # GPIO must come after pinctrl as gpios may need to mux pins etc | 8 | # GPIO must come after pinctrl as gpios may need to mux pins etc |
9 | obj-y += pinctrl/ | 9 | obj-y += pinctrl/ |
10 | obj-y += gpio/ | 10 | obj-y += gpio/ |
11 | obj-y += pwm/ | ||
11 | obj-$(CONFIG_PCI) += pci/ | 12 | obj-$(CONFIG_PCI) += pci/ |
12 | obj-$(CONFIG_PARISC) += parisc/ | 13 | obj-$(CONFIG_PARISC) += parisc/ |
13 | obj-$(CONFIG_RAPIDIO) += rapidio/ | 14 | obj-$(CONFIG_RAPIDIO) += rapidio/ |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 92144ed1ad46..4fdc04ef37c2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -276,6 +276,7 @@ config TWL6030_PWM | |||
276 | tristate "TWL6030 PWM (Pulse Width Modulator) Support" | 276 | tristate "TWL6030 PWM (Pulse Width Modulator) Support" |
277 | depends on TWL4030_CORE | 277 | depends on TWL4030_CORE |
278 | select HAVE_PWM | 278 | select HAVE_PWM |
279 | depends on !PWM | ||
279 | default n | 280 | default n |
280 | help | 281 | help |
281 | Say yes here if you want support for TWL6030 PWM. | 282 | Say yes here if you want support for TWL6030 PWM. |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 154f3ef07631..98a442da892a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -64,6 +64,7 @@ config AB8500_PWM | |||
64 | bool "AB8500 PWM support" | 64 | bool "AB8500 PWM support" |
65 | depends on AB8500_CORE && ARCH_U8500 | 65 | depends on AB8500_CORE && ARCH_U8500 |
66 | select HAVE_PWM | 66 | select HAVE_PWM |
67 | depends on !PWM | ||
67 | help | 68 | help |
68 | This driver exports functions to enable/disble/config/free Pulse | 69 | This driver exports functions to enable/disble/config/free Pulse |
69 | Width Modulation in the Analog Baseband Chip AB8500. | 70 | Width Modulation in the Analog Baseband Chip AB8500. |
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig new file mode 100644 index 000000000000..8fc3808d7a3e --- /dev/null +++ b/drivers/pwm/Kconfig | |||
@@ -0,0 +1,108 @@ | |||
1 | menuconfig PWM | ||
2 | bool "PWM Support" | ||
3 | depends on !MACH_JZ4740 && !PUV3_PWM | ||
4 | help | ||
5 | This enables PWM support through the generic PWM framework. | ||
6 | You only need to enable this, if you also want to enable | ||
7 | one or more of the PWM drivers below. | ||
8 | |||
9 | If unsure, say N. | ||
10 | |||
11 | if PWM | ||
12 | |||
13 | config PWM_BFIN | ||
14 | tristate "Blackfin PWM support" | ||
15 | depends on BFIN_GPTIMERS | ||
16 | help | ||
17 | Generic PWM framework driver for Blackfin. | ||
18 | |||
19 | To compile this driver as a module, choose M here: the module | ||
20 | will be called pwm-bfin. | ||
21 | |||
22 | config PWM_IMX | ||
23 | tristate "i.MX pwm support" | ||
24 | depends on ARCH_MXC | ||
25 | help | ||
26 | Generic PWM framework driver for i.MX. | ||
27 | |||
28 | To compile this driver as a module, choose M here: the module | ||
29 | will be called pwm-imx. | ||
30 | |||
31 | config PWM_LPC32XX | ||
32 | tristate "LPC32XX PWM support" | ||
33 | depends on ARCH_LPC32XX | ||
34 | help | ||
35 | Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two | ||
36 | PWM controllers. | ||
37 | |||
38 | To compile this driver as a module, choose M here: the module | ||
39 | will be called pwm-lpc32xx. | ||
40 | |||
41 | config PWM_MXS | ||
42 | tristate "Freescale MXS PWM support" | ||
43 | depends on ARCH_MXS && OF | ||
44 | select STMP_DEVICE | ||
45 | help | ||
46 | Generic PWM framework driver for Freescale MXS. | ||
47 | |||
48 | To compile this driver as a module, choose M here: the module | ||
49 | will be called pwm-mxs. | ||
50 | |||
51 | config PWM_PXA | ||
52 | tristate "PXA PWM support" | ||
53 | depends on ARCH_PXA | ||
54 | help | ||
55 | Generic PWM framework driver for PXA. | ||
56 | |||
57 | To compile this driver as a module, choose M here: the module | ||
58 | will be called pwm-pxa. | ||
59 | |||
60 | config PWM_SAMSUNG | ||
61 | tristate "Samsung pwm support" | ||
62 | depends on PLAT_SAMSUNG | ||
63 | help | ||
64 | Generic PWM framework driver for Samsung. | ||
65 | |||
66 | To compile this driver as a module, choose M here: the module | ||
67 | will be called pwm-samsung. | ||
68 | |||
69 | config PWM_TEGRA | ||
70 | tristate "NVIDIA Tegra PWM support" | ||
71 | depends on ARCH_TEGRA | ||
72 | help | ||
73 | Generic PWM framework driver for the PWFM controller found on NVIDIA | ||
74 | Tegra SoCs. | ||
75 | |||
76 | To compile this driver as a module, choose M here: the module | ||
77 | will be called pwm-tegra. | ||
78 | |||
79 | config PWM_TIECAP | ||
80 | tristate "ECAP PWM support" | ||
81 | depends on SOC_AM33XX | ||
82 | help | ||
83 | PWM driver support for the ECAP APWM controller found on AM33XX | ||
84 | TI SOC | ||
85 | |||
86 | To compile this driver as a module, choose M here: the module | ||
87 | will be called pwm-tiecap. | ||
88 | |||
89 | config PWM_TIEHRPWM | ||
90 | tristate "EHRPWM PWM support" | ||
91 | depends on SOC_AM33XX | ||
92 | help | ||
93 | PWM driver support for the EHRPWM controller found on AM33XX | ||
94 | TI SOC | ||
95 | |||
96 | To compile this driver as a module, choose M here: the module | ||
97 | will be called pwm-tiehrpwm. | ||
98 | |||
99 | config PWM_VT8500 | ||
100 | tristate "vt8500 pwm support" | ||
101 | depends on ARCH_VT8500 | ||
102 | help | ||
103 | Generic PWM framework driver for vt8500. | ||
104 | |||
105 | To compile this driver as a module, choose M here: the module | ||
106 | will be called pwm-vt8500. | ||
107 | |||
108 | endif | ||
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile new file mode 100644 index 000000000000..e4b2c898964d --- /dev/null +++ b/drivers/pwm/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | obj-$(CONFIG_PWM) += core.o | ||
2 | obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o | ||
3 | obj-$(CONFIG_PWM_IMX) += pwm-imx.o | ||
4 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | ||
5 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | ||
6 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | ||
7 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o | ||
8 | obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o | ||
9 | obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o | ||
10 | obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o | ||
11 | obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o | ||
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c new file mode 100644 index 000000000000..ecb76909e946 --- /dev/null +++ b/drivers/pwm/core.c | |||
@@ -0,0 +1,713 @@ | |||
1 | /* | ||
2 | * Generic pwmlib implementation | ||
3 | * | ||
4 | * Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de> | ||
5 | * Copyright (C) 2011-2012 Avionic Design GmbH | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; see the file COPYING. If not, write to | ||
19 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/pwm.h> | ||
24 | #include <linux/radix-tree.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | |||
33 | #define MAX_PWMS 1024 | ||
34 | |||
35 | static DEFINE_MUTEX(pwm_lookup_lock); | ||
36 | static LIST_HEAD(pwm_lookup_list); | ||
37 | static DEFINE_MUTEX(pwm_lock); | ||
38 | static LIST_HEAD(pwm_chips); | ||
39 | static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); | ||
40 | static RADIX_TREE(pwm_tree, GFP_KERNEL); | ||
41 | |||
42 | static struct pwm_device *pwm_to_device(unsigned int pwm) | ||
43 | { | ||
44 | return radix_tree_lookup(&pwm_tree, pwm); | ||
45 | } | ||
46 | |||
47 | static int alloc_pwms(int pwm, unsigned int count) | ||
48 | { | ||
49 | unsigned int from = 0; | ||
50 | unsigned int start; | ||
51 | |||
52 | if (pwm >= MAX_PWMS) | ||
53 | return -EINVAL; | ||
54 | |||
55 | if (pwm >= 0) | ||
56 | from = pwm; | ||
57 | |||
58 | start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from, | ||
59 | count, 0); | ||
60 | |||
61 | if (pwm >= 0 && start != pwm) | ||
62 | return -EEXIST; | ||
63 | |||
64 | if (start + count > MAX_PWMS) | ||
65 | return -ENOSPC; | ||
66 | |||
67 | return start; | ||
68 | } | ||
69 | |||
70 | static void free_pwms(struct pwm_chip *chip) | ||
71 | { | ||
72 | unsigned int i; | ||
73 | |||
74 | for (i = 0; i < chip->npwm; i++) { | ||
75 | struct pwm_device *pwm = &chip->pwms[i]; | ||
76 | radix_tree_delete(&pwm_tree, pwm->pwm); | ||
77 | } | ||
78 | |||
79 | bitmap_clear(allocated_pwms, chip->base, chip->npwm); | ||
80 | |||
81 | kfree(chip->pwms); | ||
82 | chip->pwms = NULL; | ||
83 | } | ||
84 | |||
85 | static struct pwm_chip *pwmchip_find_by_name(const char *name) | ||
86 | { | ||
87 | struct pwm_chip *chip; | ||
88 | |||
89 | if (!name) | ||
90 | return NULL; | ||
91 | |||
92 | mutex_lock(&pwm_lock); | ||
93 | |||
94 | list_for_each_entry(chip, &pwm_chips, list) { | ||
95 | const char *chip_name = dev_name(chip->dev); | ||
96 | |||
97 | if (chip_name && strcmp(chip_name, name) == 0) { | ||
98 | mutex_unlock(&pwm_lock); | ||
99 | return chip; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | mutex_unlock(&pwm_lock); | ||
104 | |||
105 | return NULL; | ||
106 | } | ||
107 | |||
108 | static int pwm_device_request(struct pwm_device *pwm, const char *label) | ||
109 | { | ||
110 | int err; | ||
111 | |||
112 | if (test_bit(PWMF_REQUESTED, &pwm->flags)) | ||
113 | return -EBUSY; | ||
114 | |||
115 | if (!try_module_get(pwm->chip->ops->owner)) | ||
116 | return -ENODEV; | ||
117 | |||
118 | if (pwm->chip->ops->request) { | ||
119 | err = pwm->chip->ops->request(pwm->chip, pwm); | ||
120 | if (err) { | ||
121 | module_put(pwm->chip->ops->owner); | ||
122 | return err; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | set_bit(PWMF_REQUESTED, &pwm->flags); | ||
127 | pwm->label = label; | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc, | ||
133 | const struct of_phandle_args *args) | ||
134 | { | ||
135 | struct pwm_device *pwm; | ||
136 | |||
137 | if (pc->of_pwm_n_cells < 2) | ||
138 | return ERR_PTR(-EINVAL); | ||
139 | |||
140 | if (args->args[0] >= pc->npwm) | ||
141 | return ERR_PTR(-EINVAL); | ||
142 | |||
143 | pwm = pwm_request_from_chip(pc, args->args[0], NULL); | ||
144 | if (IS_ERR(pwm)) | ||
145 | return pwm; | ||
146 | |||
147 | pwm_set_period(pwm, args->args[1]); | ||
148 | |||
149 | return pwm; | ||
150 | } | ||
151 | |||
152 | void of_pwmchip_add(struct pwm_chip *chip) | ||
153 | { | ||
154 | if (!chip->dev || !chip->dev->of_node) | ||
155 | return; | ||
156 | |||
157 | if (!chip->of_xlate) { | ||
158 | chip->of_xlate = of_pwm_simple_xlate; | ||
159 | chip->of_pwm_n_cells = 2; | ||
160 | } | ||
161 | |||
162 | of_node_get(chip->dev->of_node); | ||
163 | } | ||
164 | |||
165 | void of_pwmchip_remove(struct pwm_chip *chip) | ||
166 | { | ||
167 | if (chip->dev && chip->dev->of_node) | ||
168 | of_node_put(chip->dev->of_node); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * pwm_set_chip_data() - set private chip data for a PWM | ||
173 | * @pwm: PWM device | ||
174 | * @data: pointer to chip-specific data | ||
175 | */ | ||
176 | int pwm_set_chip_data(struct pwm_device *pwm, void *data) | ||
177 | { | ||
178 | if (!pwm) | ||
179 | return -EINVAL; | ||
180 | |||
181 | pwm->chip_data = data; | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * pwm_get_chip_data() - get private chip data for a PWM | ||
188 | * @pwm: PWM device | ||
189 | */ | ||
190 | void *pwm_get_chip_data(struct pwm_device *pwm) | ||
191 | { | ||
192 | return pwm ? pwm->chip_data : NULL; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * pwmchip_add() - register a new PWM chip | ||
197 | * @chip: the PWM chip to add | ||
198 | * | ||
199 | * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base | ||
200 | * will be used. | ||
201 | */ | ||
202 | int pwmchip_add(struct pwm_chip *chip) | ||
203 | { | ||
204 | struct pwm_device *pwm; | ||
205 | unsigned int i; | ||
206 | int ret; | ||
207 | |||
208 | if (!chip || !chip->dev || !chip->ops || !chip->ops->config || | ||
209 | !chip->ops->enable || !chip->ops->disable) | ||
210 | return -EINVAL; | ||
211 | |||
212 | mutex_lock(&pwm_lock); | ||
213 | |||
214 | ret = alloc_pwms(chip->base, chip->npwm); | ||
215 | if (ret < 0) | ||
216 | goto out; | ||
217 | |||
218 | chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL); | ||
219 | if (!chip->pwms) { | ||
220 | ret = -ENOMEM; | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | chip->base = ret; | ||
225 | |||
226 | for (i = 0; i < chip->npwm; i++) { | ||
227 | pwm = &chip->pwms[i]; | ||
228 | |||
229 | pwm->chip = chip; | ||
230 | pwm->pwm = chip->base + i; | ||
231 | pwm->hwpwm = i; | ||
232 | |||
233 | radix_tree_insert(&pwm_tree, pwm->pwm, pwm); | ||
234 | } | ||
235 | |||
236 | bitmap_set(allocated_pwms, chip->base, chip->npwm); | ||
237 | |||
238 | INIT_LIST_HEAD(&chip->list); | ||
239 | list_add(&chip->list, &pwm_chips); | ||
240 | |||
241 | ret = 0; | ||
242 | |||
243 | if (IS_ENABLED(CONFIG_OF)) | ||
244 | of_pwmchip_add(chip); | ||
245 | |||
246 | out: | ||
247 | mutex_unlock(&pwm_lock); | ||
248 | return ret; | ||
249 | } | ||
250 | EXPORT_SYMBOL_GPL(pwmchip_add); | ||
251 | |||
252 | /** | ||
253 | * pwmchip_remove() - remove a PWM chip | ||
254 | * @chip: the PWM chip to remove | ||
255 | * | ||
256 | * Removes a PWM chip. This function may return busy if the PWM chip provides | ||
257 | * a PWM device that is still requested. | ||
258 | */ | ||
259 | int pwmchip_remove(struct pwm_chip *chip) | ||
260 | { | ||
261 | unsigned int i; | ||
262 | int ret = 0; | ||
263 | |||
264 | mutex_lock(&pwm_lock); | ||
265 | |||
266 | for (i = 0; i < chip->npwm; i++) { | ||
267 | struct pwm_device *pwm = &chip->pwms[i]; | ||
268 | |||
269 | if (test_bit(PWMF_REQUESTED, &pwm->flags)) { | ||
270 | ret = -EBUSY; | ||
271 | goto out; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | list_del_init(&chip->list); | ||
276 | |||
277 | if (IS_ENABLED(CONFIG_OF)) | ||
278 | of_pwmchip_remove(chip); | ||
279 | |||
280 | free_pwms(chip); | ||
281 | |||
282 | out: | ||
283 | mutex_unlock(&pwm_lock); | ||
284 | return ret; | ||
285 | } | ||
286 | EXPORT_SYMBOL_GPL(pwmchip_remove); | ||
287 | |||
288 | /** | ||
289 | * pwm_request() - request a PWM device | ||
290 | * @pwm_id: global PWM device index | ||
291 | * @label: PWM device label | ||
292 | * | ||
293 | * This function is deprecated, use pwm_get() instead. | ||
294 | */ | ||
295 | struct pwm_device *pwm_request(int pwm, const char *label) | ||
296 | { | ||
297 | struct pwm_device *dev; | ||
298 | int err; | ||
299 | |||
300 | if (pwm < 0 || pwm >= MAX_PWMS) | ||
301 | return ERR_PTR(-EINVAL); | ||
302 | |||
303 | mutex_lock(&pwm_lock); | ||
304 | |||
305 | dev = pwm_to_device(pwm); | ||
306 | if (!dev) { | ||
307 | dev = ERR_PTR(-EPROBE_DEFER); | ||
308 | goto out; | ||
309 | } | ||
310 | |||
311 | err = pwm_device_request(dev, label); | ||
312 | if (err < 0) | ||
313 | dev = ERR_PTR(err); | ||
314 | |||
315 | out: | ||
316 | mutex_unlock(&pwm_lock); | ||
317 | |||
318 | return dev; | ||
319 | } | ||
320 | EXPORT_SYMBOL_GPL(pwm_request); | ||
321 | |||
322 | /** | ||
323 | * pwm_request_from_chip() - request a PWM device relative to a PWM chip | ||
324 | * @chip: PWM chip | ||
325 | * @index: per-chip index of the PWM to request | ||
326 | * @label: a literal description string of this PWM | ||
327 | * | ||
328 | * Returns the PWM at the given index of the given PWM chip. A negative error | ||
329 | * code is returned if the index is not valid for the specified PWM chip or | ||
330 | * if the PWM device cannot be requested. | ||
331 | */ | ||
332 | struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, | ||
333 | unsigned int index, | ||
334 | const char *label) | ||
335 | { | ||
336 | struct pwm_device *pwm; | ||
337 | int err; | ||
338 | |||
339 | if (!chip || index >= chip->npwm) | ||
340 | return ERR_PTR(-EINVAL); | ||
341 | |||
342 | mutex_lock(&pwm_lock); | ||
343 | pwm = &chip->pwms[index]; | ||
344 | |||
345 | err = pwm_device_request(pwm, label); | ||
346 | if (err < 0) | ||
347 | pwm = ERR_PTR(err); | ||
348 | |||
349 | mutex_unlock(&pwm_lock); | ||
350 | return pwm; | ||
351 | } | ||
352 | EXPORT_SYMBOL_GPL(pwm_request_from_chip); | ||
353 | |||
354 | /** | ||
355 | * pwm_free() - free a PWM device | ||
356 | * @pwm: PWM device | ||
357 | * | ||
358 | * This function is deprecated, use pwm_put() instead. | ||
359 | */ | ||
360 | void pwm_free(struct pwm_device *pwm) | ||
361 | { | ||
362 | pwm_put(pwm); | ||
363 | } | ||
364 | EXPORT_SYMBOL_GPL(pwm_free); | ||
365 | |||
366 | /** | ||
367 | * pwm_config() - change a PWM device configuration | ||
368 | * @pwm: PWM device | ||
369 | * @duty_ns: "on" time (in nanoseconds) | ||
370 | * @period_ns: duration (in nanoseconds) of one cycle | ||
371 | */ | ||
372 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
373 | { | ||
374 | if (!pwm || period_ns == 0 || duty_ns > period_ns) | ||
375 | return -EINVAL; | ||
376 | |||
377 | return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); | ||
378 | } | ||
379 | EXPORT_SYMBOL_GPL(pwm_config); | ||
380 | |||
381 | /** | ||
382 | * pwm_enable() - start a PWM output toggling | ||
383 | * @pwm: PWM device | ||
384 | */ | ||
385 | int pwm_enable(struct pwm_device *pwm) | ||
386 | { | ||
387 | if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) | ||
388 | return pwm->chip->ops->enable(pwm->chip, pwm); | ||
389 | |||
390 | return pwm ? 0 : -EINVAL; | ||
391 | } | ||
392 | EXPORT_SYMBOL_GPL(pwm_enable); | ||
393 | |||
394 | /** | ||
395 | * pwm_disable() - stop a PWM output toggling | ||
396 | * @pwm: PWM device | ||
397 | */ | ||
398 | void pwm_disable(struct pwm_device *pwm) | ||
399 | { | ||
400 | if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags)) | ||
401 | pwm->chip->ops->disable(pwm->chip, pwm); | ||
402 | } | ||
403 | EXPORT_SYMBOL_GPL(pwm_disable); | ||
404 | |||
405 | static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) | ||
406 | { | ||
407 | struct pwm_chip *chip; | ||
408 | |||
409 | mutex_lock(&pwm_lock); | ||
410 | |||
411 | list_for_each_entry(chip, &pwm_chips, list) | ||
412 | if (chip->dev && chip->dev->of_node == np) { | ||
413 | mutex_unlock(&pwm_lock); | ||
414 | return chip; | ||
415 | } | ||
416 | |||
417 | mutex_unlock(&pwm_lock); | ||
418 | |||
419 | return ERR_PTR(-EPROBE_DEFER); | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * of_pwm_request() - request a PWM via the PWM framework | ||
424 | * @np: device node to get the PWM from | ||
425 | * @con_id: consumer name | ||
426 | * | ||
427 | * Returns the PWM device parsed from the phandle and index specified in the | ||
428 | * "pwms" property of a device tree node or a negative error-code on failure. | ||
429 | * Values parsed from the device tree are stored in the returned PWM device | ||
430 | * object. | ||
431 | * | ||
432 | * If con_id is NULL, the first PWM device listed in the "pwms" property will | ||
433 | * be requested. Otherwise the "pwm-names" property is used to do a reverse | ||
434 | * lookup of the PWM index. This also means that the "pwm-names" property | ||
435 | * becomes mandatory for devices that look up the PWM device via the con_id | ||
436 | * parameter. | ||
437 | */ | ||
438 | static struct pwm_device *of_pwm_request(struct device_node *np, | ||
439 | const char *con_id) | ||
440 | { | ||
441 | struct pwm_device *pwm = NULL; | ||
442 | struct of_phandle_args args; | ||
443 | struct pwm_chip *pc; | ||
444 | int index = 0; | ||
445 | int err; | ||
446 | |||
447 | if (con_id) { | ||
448 | index = of_property_match_string(np, "pwm-names", con_id); | ||
449 | if (index < 0) | ||
450 | return ERR_PTR(index); | ||
451 | } | ||
452 | |||
453 | err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index, | ||
454 | &args); | ||
455 | if (err) { | ||
456 | pr_debug("%s(): can't parse \"pwms\" property\n", __func__); | ||
457 | return ERR_PTR(err); | ||
458 | } | ||
459 | |||
460 | pc = of_node_to_pwmchip(args.np); | ||
461 | if (IS_ERR(pc)) { | ||
462 | pr_debug("%s(): PWM chip not found\n", __func__); | ||
463 | pwm = ERR_CAST(pc); | ||
464 | goto put; | ||
465 | } | ||
466 | |||
467 | if (args.args_count != pc->of_pwm_n_cells) { | ||
468 | pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name, | ||
469 | args.np->full_name); | ||
470 | pwm = ERR_PTR(-EINVAL); | ||
471 | goto put; | ||
472 | } | ||
473 | |||
474 | pwm = pc->of_xlate(pc, &args); | ||
475 | if (IS_ERR(pwm)) | ||
476 | goto put; | ||
477 | |||
478 | /* | ||
479 | * If a consumer name was not given, try to look it up from the | ||
480 | * "pwm-names" property if it exists. Otherwise use the name of | ||
481 | * the user device node. | ||
482 | */ | ||
483 | if (!con_id) { | ||
484 | err = of_property_read_string_index(np, "pwm-names", index, | ||
485 | &con_id); | ||
486 | if (err < 0) | ||
487 | con_id = np->name; | ||
488 | } | ||
489 | |||
490 | pwm->label = con_id; | ||
491 | |||
492 | put: | ||
493 | of_node_put(args.np); | ||
494 | |||
495 | return pwm; | ||
496 | } | ||
497 | |||
498 | /** | ||
499 | * pwm_add_table() - register PWM device consumers | ||
500 | * @table: array of consumers to register | ||
501 | * @num: number of consumers in table | ||
502 | */ | ||
503 | void __init pwm_add_table(struct pwm_lookup *table, size_t num) | ||
504 | { | ||
505 | mutex_lock(&pwm_lookup_lock); | ||
506 | |||
507 | while (num--) { | ||
508 | list_add_tail(&table->list, &pwm_lookup_list); | ||
509 | table++; | ||
510 | } | ||
511 | |||
512 | mutex_unlock(&pwm_lookup_lock); | ||
513 | } | ||
514 | |||
515 | /** | ||
516 | * pwm_get() - look up and request a PWM device | ||
517 | * @dev: device for PWM consumer | ||
518 | * @con_id: consumer name | ||
519 | * | ||
520 | * Lookup is first attempted using DT. If the device was not instantiated from | ||
521 | * a device tree, a PWM chip and a relative index is looked up via a table | ||
522 | * supplied by board setup code (see pwm_add_table()). | ||
523 | * | ||
524 | * Once a PWM chip has been found the specified PWM device will be requested | ||
525 | * and is ready to be used. | ||
526 | */ | ||
527 | struct pwm_device *pwm_get(struct device *dev, const char *con_id) | ||
528 | { | ||
529 | struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER); | ||
530 | const char *dev_id = dev ? dev_name(dev): NULL; | ||
531 | struct pwm_chip *chip = NULL; | ||
532 | unsigned int index = 0; | ||
533 | unsigned int best = 0; | ||
534 | struct pwm_lookup *p; | ||
535 | unsigned int match; | ||
536 | |||
537 | /* look up via DT first */ | ||
538 | if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) | ||
539 | return of_pwm_request(dev->of_node, con_id); | ||
540 | |||
541 | /* | ||
542 | * We look up the provider in the static table typically provided by | ||
543 | * board setup code. We first try to lookup the consumer device by | ||
544 | * name. If the consumer device was passed in as NULL or if no match | ||
545 | * was found, we try to find the consumer by directly looking it up | ||
546 | * by name. | ||
547 | * | ||
548 | * If a match is found, the provider PWM chip is looked up by name | ||
549 | * and a PWM device is requested using the PWM device per-chip index. | ||
550 | * | ||
551 | * The lookup algorithm was shamelessly taken from the clock | ||
552 | * framework: | ||
553 | * | ||
554 | * We do slightly fuzzy matching here: | ||
555 | * An entry with a NULL ID is assumed to be a wildcard. | ||
556 | * If an entry has a device ID, it must match | ||
557 | * If an entry has a connection ID, it must match | ||
558 | * Then we take the most specific entry - with the following order | ||
559 | * of precedence: dev+con > dev only > con only. | ||
560 | */ | ||
561 | mutex_lock(&pwm_lookup_lock); | ||
562 | |||
563 | list_for_each_entry(p, &pwm_lookup_list, list) { | ||
564 | match = 0; | ||
565 | |||
566 | if (p->dev_id) { | ||
567 | if (!dev_id || strcmp(p->dev_id, dev_id)) | ||
568 | continue; | ||
569 | |||
570 | match += 2; | ||
571 | } | ||
572 | |||
573 | if (p->con_id) { | ||
574 | if (!con_id || strcmp(p->con_id, con_id)) | ||
575 | continue; | ||
576 | |||
577 | match += 1; | ||
578 | } | ||
579 | |||
580 | if (match > best) { | ||
581 | chip = pwmchip_find_by_name(p->provider); | ||
582 | index = p->index; | ||
583 | |||
584 | if (match != 3) | ||
585 | best = match; | ||
586 | else | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | if (chip) | ||
592 | pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id); | ||
593 | |||
594 | mutex_unlock(&pwm_lookup_lock); | ||
595 | |||
596 | return pwm; | ||
597 | } | ||
598 | EXPORT_SYMBOL_GPL(pwm_get); | ||
599 | |||
600 | /** | ||
601 | * pwm_put() - release a PWM device | ||
602 | * @pwm: PWM device | ||
603 | */ | ||
604 | void pwm_put(struct pwm_device *pwm) | ||
605 | { | ||
606 | if (!pwm) | ||
607 | return; | ||
608 | |||
609 | mutex_lock(&pwm_lock); | ||
610 | |||
611 | if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) { | ||
612 | pr_warning("PWM device already freed\n"); | ||
613 | goto out; | ||
614 | } | ||
615 | |||
616 | if (pwm->chip->ops->free) | ||
617 | pwm->chip->ops->free(pwm->chip, pwm); | ||
618 | |||
619 | pwm->label = NULL; | ||
620 | |||
621 | module_put(pwm->chip->ops->owner); | ||
622 | out: | ||
623 | mutex_unlock(&pwm_lock); | ||
624 | } | ||
625 | EXPORT_SYMBOL_GPL(pwm_put); | ||
626 | |||
627 | #ifdef CONFIG_DEBUG_FS | ||
628 | static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) | ||
629 | { | ||
630 | unsigned int i; | ||
631 | |||
632 | for (i = 0; i < chip->npwm; i++) { | ||
633 | struct pwm_device *pwm = &chip->pwms[i]; | ||
634 | |||
635 | seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label); | ||
636 | |||
637 | if (test_bit(PWMF_REQUESTED, &pwm->flags)) | ||
638 | seq_printf(s, " requested"); | ||
639 | |||
640 | if (test_bit(PWMF_ENABLED, &pwm->flags)) | ||
641 | seq_printf(s, " enabled"); | ||
642 | |||
643 | seq_printf(s, "\n"); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | static void *pwm_seq_start(struct seq_file *s, loff_t *pos) | ||
648 | { | ||
649 | mutex_lock(&pwm_lock); | ||
650 | s->private = ""; | ||
651 | |||
652 | return seq_list_start(&pwm_chips, *pos); | ||
653 | } | ||
654 | |||
655 | static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
656 | { | ||
657 | s->private = "\n"; | ||
658 | |||
659 | return seq_list_next(v, &pwm_chips, pos); | ||
660 | } | ||
661 | |||
662 | static void pwm_seq_stop(struct seq_file *s, void *v) | ||
663 | { | ||
664 | mutex_unlock(&pwm_lock); | ||
665 | } | ||
666 | |||
667 | static int pwm_seq_show(struct seq_file *s, void *v) | ||
668 | { | ||
669 | struct pwm_chip *chip = list_entry(v, struct pwm_chip, list); | ||
670 | |||
671 | seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private, | ||
672 | chip->dev->bus ? chip->dev->bus->name : "no-bus", | ||
673 | dev_name(chip->dev), chip->npwm, | ||
674 | (chip->npwm != 1) ? "s" : ""); | ||
675 | |||
676 | if (chip->ops->dbg_show) | ||
677 | chip->ops->dbg_show(chip, s); | ||
678 | else | ||
679 | pwm_dbg_show(chip, s); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static const struct seq_operations pwm_seq_ops = { | ||
685 | .start = pwm_seq_start, | ||
686 | .next = pwm_seq_next, | ||
687 | .stop = pwm_seq_stop, | ||
688 | .show = pwm_seq_show, | ||
689 | }; | ||
690 | |||
691 | static int pwm_seq_open(struct inode *inode, struct file *file) | ||
692 | { | ||
693 | return seq_open(file, &pwm_seq_ops); | ||
694 | } | ||
695 | |||
696 | static const struct file_operations pwm_debugfs_ops = { | ||
697 | .owner = THIS_MODULE, | ||
698 | .open = pwm_seq_open, | ||
699 | .read = seq_read, | ||
700 | .llseek = seq_lseek, | ||
701 | .release = seq_release, | ||
702 | }; | ||
703 | |||
704 | static int __init pwm_debugfs_init(void) | ||
705 | { | ||
706 | debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, | ||
707 | &pwm_debugfs_ops); | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | subsys_initcall(pwm_debugfs_init); | ||
713 | #endif /* CONFIG_DEBUG_FS */ | ||
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c new file mode 100644 index 000000000000..d53c4e7941ef --- /dev/null +++ b/drivers/pwm/pwm-bfin.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Blackfin Pulse Width Modulation (PWM) core | ||
3 | * | ||
4 | * Copyright (c) 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | #include <linux/pwm.h> | ||
12 | #include <linux/slab.h> | ||
13 | |||
14 | #include <asm/gptimers.h> | ||
15 | #include <asm/portmux.h> | ||
16 | |||
17 | struct bfin_pwm_chip { | ||
18 | struct pwm_chip chip; | ||
19 | }; | ||
20 | |||
21 | struct bfin_pwm { | ||
22 | unsigned short pin; | ||
23 | }; | ||
24 | |||
25 | static const unsigned short pwm_to_gptimer_per[] = { | ||
26 | P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5, | ||
27 | P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11, | ||
28 | }; | ||
29 | |||
30 | static int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | ||
31 | { | ||
32 | struct bfin_pwm *priv; | ||
33 | int ret; | ||
34 | |||
35 | if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per)) | ||
36 | return -EINVAL; | ||
37 | |||
38 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
39 | if (!priv) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | priv->pin = pwm_to_gptimer_per[pwm->hwpwm]; | ||
43 | |||
44 | ret = peripheral_request(priv->pin, NULL); | ||
45 | if (ret) { | ||
46 | kfree(priv); | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | pwm_set_chip_data(pwm, priv); | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
56 | { | ||
57 | struct bfin_pwm *priv = pwm_get_chip_data(pwm); | ||
58 | |||
59 | if (priv) { | ||
60 | peripheral_free(priv->pin); | ||
61 | kfree(priv); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
66 | int duty_ns, int period_ns) | ||
67 | { | ||
68 | struct bfin_pwm *priv = pwm_get_chip_data(pwm); | ||
69 | unsigned long period, duty; | ||
70 | unsigned long long val; | ||
71 | |||
72 | if (duty_ns < 0 || duty_ns > period_ns) | ||
73 | return -EINVAL; | ||
74 | |||
75 | val = (unsigned long long)get_sclk() * period_ns; | ||
76 | do_div(val, NSEC_PER_SEC); | ||
77 | period = val; | ||
78 | |||
79 | val = (unsigned long long)period * duty_ns; | ||
80 | do_div(val, period_ns); | ||
81 | duty = period - val; | ||
82 | |||
83 | if (duty >= period) | ||
84 | duty = period - 1; | ||
85 | |||
86 | set_gptimer_config(priv->pin, TIMER_MODE_PWM | TIMER_PERIOD_CNT); | ||
87 | set_gptimer_pwidth(priv->pin, duty); | ||
88 | set_gptimer_period(priv->pin, period); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
94 | { | ||
95 | struct bfin_pwm *priv = pwm_get_chip_data(pwm); | ||
96 | |||
97 | enable_gptimer(priv->pin); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
103 | { | ||
104 | struct bfin_pwm *priv = pwm_get_chip_data(pwm); | ||
105 | |||
106 | disable_gptimer(priv->pin); | ||
107 | } | ||
108 | |||
109 | static struct pwm_ops bfin_pwm_ops = { | ||
110 | .request = bfin_pwm_request, | ||
111 | .free = bfin_pwm_free, | ||
112 | .config = bfin_pwm_config, | ||
113 | .enable = bfin_pwm_enable, | ||
114 | .disable = bfin_pwm_disable, | ||
115 | .owner = THIS_MODULE, | ||
116 | }; | ||
117 | |||
118 | static int bfin_pwm_probe(struct platform_device *pdev) | ||
119 | { | ||
120 | struct bfin_pwm_chip *pwm; | ||
121 | int ret; | ||
122 | |||
123 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); | ||
124 | if (!pwm) { | ||
125 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | |||
129 | platform_set_drvdata(pdev, pwm); | ||
130 | |||
131 | pwm->chip.dev = &pdev->dev; | ||
132 | pwm->chip.ops = &bfin_pwm_ops; | ||
133 | pwm->chip.base = -1; | ||
134 | pwm->chip.npwm = 12; | ||
135 | |||
136 | ret = pwmchip_add(&pwm->chip); | ||
137 | if (ret < 0) { | ||
138 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int __devexit bfin_pwm_remove(struct platform_device *pdev) | ||
146 | { | ||
147 | struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev); | ||
148 | |||
149 | return pwmchip_remove(&pwm->chip); | ||
150 | } | ||
151 | |||
152 | static struct platform_driver bfin_pwm_driver = { | ||
153 | .driver = { | ||
154 | .name = "bfin-pwm", | ||
155 | }, | ||
156 | .probe = bfin_pwm_probe, | ||
157 | .remove = __devexit_p(bfin_pwm_remove), | ||
158 | }; | ||
159 | |||
160 | module_platform_driver(bfin_pwm_driver); | ||
161 | |||
162 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/plat-mxc/pwm.c b/drivers/pwm/pwm-imx.c index c0cab2270dd1..2a0b35333972 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/drivers/pwm/pwm-imx.c | |||
@@ -39,33 +39,28 @@ | |||
39 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) | 39 | #define MX3_PWMCR_CLKSRC_IPG (1 << 16) |
40 | #define MX3_PWMCR_EN (1 << 0) | 40 | #define MX3_PWMCR_EN (1 << 0) |
41 | 41 | ||
42 | 42 | struct imx_chip { | |
43 | |||
44 | struct pwm_device { | ||
45 | struct list_head node; | ||
46 | struct platform_device *pdev; | ||
47 | |||
48 | const char *label; | ||
49 | struct clk *clk; | 43 | struct clk *clk; |
50 | 44 | ||
51 | int clk_enabled; | 45 | int clk_enabled; |
52 | void __iomem *mmio_base; | 46 | void __iomem *mmio_base; |
53 | 47 | ||
54 | unsigned int use_count; | 48 | struct pwm_chip chip; |
55 | unsigned int pwm_id; | ||
56 | }; | 49 | }; |
57 | 50 | ||
58 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | 51 | #define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) |
52 | |||
53 | static int imx_pwm_config(struct pwm_chip *chip, | ||
54 | struct pwm_device *pwm, int duty_ns, int period_ns) | ||
59 | { | 55 | { |
60 | if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) | 56 | struct imx_chip *imx = to_imx_chip(chip); |
61 | return -EINVAL; | ||
62 | 57 | ||
63 | if (!(cpu_is_mx1() || cpu_is_mx21())) { | 58 | if (!(cpu_is_mx1() || cpu_is_mx21())) { |
64 | unsigned long long c; | 59 | unsigned long long c; |
65 | unsigned long period_cycles, duty_cycles, prescale; | 60 | unsigned long period_cycles, duty_cycles, prescale; |
66 | u32 cr; | 61 | u32 cr; |
67 | 62 | ||
68 | c = clk_get_rate(pwm->clk); | 63 | c = clk_get_rate(imx->clk); |
69 | c = c * period_ns; | 64 | c = c * period_ns; |
70 | do_div(c, 1000000000); | 65 | do_div(c, 1000000000); |
71 | period_cycles = c; | 66 | period_cycles = c; |
@@ -86,8 +81,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
86 | else | 81 | else |
87 | period_cycles = 0; | 82 | period_cycles = 0; |
88 | 83 | ||
89 | writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); | 84 | writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); |
90 | writel(period_cycles, pwm->mmio_base + MX3_PWMPR); | 85 | writel(period_cycles, imx->mmio_base + MX3_PWMPR); |
91 | 86 | ||
92 | cr = MX3_PWMCR_PRESCALER(prescale) | | 87 | cr = MX3_PWMCR_PRESCALER(prescale) | |
93 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | | 88 | MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | |
@@ -98,7 +93,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
98 | else | 93 | else |
99 | cr |= MX3_PWMCR_CLKSRC_IPG_HIGH; | 94 | cr |= MX3_PWMCR_CLKSRC_IPG_HIGH; |
100 | 95 | ||
101 | writel(cr, pwm->mmio_base + MX3_PWMCR); | 96 | writel(cr, imx->mmio_base + MX3_PWMCR); |
102 | } else if (cpu_is_mx1() || cpu_is_mx21()) { | 97 | } else if (cpu_is_mx1() || cpu_is_mx21()) { |
103 | /* The PWM subsystem allows for exact frequencies. However, | 98 | /* The PWM subsystem allows for exact frequencies. However, |
104 | * I cannot connect a scope on my device to the PWM line and | 99 | * I cannot connect a scope on my device to the PWM line and |
@@ -116,191 +111,120 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
116 | * both the prescaler (/1 .. /128) and then by CLKSEL | 111 | * both the prescaler (/1 .. /128) and then by CLKSEL |
117 | * (/2 .. /16). | 112 | * (/2 .. /16). |
118 | */ | 113 | */ |
119 | u32 max = readl(pwm->mmio_base + MX1_PWMP); | 114 | u32 max = readl(imx->mmio_base + MX1_PWMP); |
120 | u32 p = max * duty_ns / period_ns; | 115 | u32 p = max * duty_ns / period_ns; |
121 | writel(max - p, pwm->mmio_base + MX1_PWMS); | 116 | writel(max - p, imx->mmio_base + MX1_PWMS); |
122 | } else { | 117 | } else { |
123 | BUG(); | 118 | BUG(); |
124 | } | 119 | } |
125 | 120 | ||
126 | return 0; | 121 | return 0; |
127 | } | 122 | } |
128 | EXPORT_SYMBOL(pwm_config); | ||
129 | 123 | ||
130 | int pwm_enable(struct pwm_device *pwm) | 124 | static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
131 | { | 125 | { |
126 | struct imx_chip *imx = to_imx_chip(chip); | ||
132 | int rc = 0; | 127 | int rc = 0; |
133 | 128 | ||
134 | if (!pwm->clk_enabled) { | 129 | if (!imx->clk_enabled) { |
135 | rc = clk_prepare_enable(pwm->clk); | 130 | rc = clk_prepare_enable(imx->clk); |
136 | if (!rc) | 131 | if (!rc) |
137 | pwm->clk_enabled = 1; | 132 | imx->clk_enabled = 1; |
138 | } | 133 | } |
139 | return rc; | 134 | return rc; |
140 | } | 135 | } |
141 | EXPORT_SYMBOL(pwm_enable); | ||
142 | 136 | ||
143 | void pwm_disable(struct pwm_device *pwm) | 137 | static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
144 | { | 138 | { |
145 | writel(0, pwm->mmio_base + MX3_PWMCR); | 139 | struct imx_chip *imx = to_imx_chip(chip); |
146 | 140 | ||
147 | if (pwm->clk_enabled) { | 141 | writel(0, imx->mmio_base + MX3_PWMCR); |
148 | clk_disable_unprepare(pwm->clk); | ||
149 | pwm->clk_enabled = 0; | ||
150 | } | ||
151 | } | ||
152 | EXPORT_SYMBOL(pwm_disable); | ||
153 | 142 | ||
154 | static DEFINE_MUTEX(pwm_lock); | 143 | if (imx->clk_enabled) { |
155 | static LIST_HEAD(pwm_list); | 144 | clk_disable_unprepare(imx->clk); |
156 | 145 | imx->clk_enabled = 0; | |
157 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
158 | { | ||
159 | struct pwm_device *pwm; | ||
160 | int found = 0; | ||
161 | |||
162 | mutex_lock(&pwm_lock); | ||
163 | |||
164 | list_for_each_entry(pwm, &pwm_list, node) { | ||
165 | if (pwm->pwm_id == pwm_id) { | ||
166 | found = 1; | ||
167 | break; | ||
168 | } | ||
169 | } | 146 | } |
170 | |||
171 | if (found) { | ||
172 | if (pwm->use_count == 0) { | ||
173 | pwm->use_count++; | ||
174 | pwm->label = label; | ||
175 | } else | ||
176 | pwm = ERR_PTR(-EBUSY); | ||
177 | } else | ||
178 | pwm = ERR_PTR(-ENOENT); | ||
179 | |||
180 | mutex_unlock(&pwm_lock); | ||
181 | return pwm; | ||
182 | } | 147 | } |
183 | EXPORT_SYMBOL(pwm_request); | ||
184 | 148 | ||
185 | void pwm_free(struct pwm_device *pwm) | 149 | static struct pwm_ops imx_pwm_ops = { |
186 | { | 150 | .enable = imx_pwm_enable, |
187 | mutex_lock(&pwm_lock); | 151 | .disable = imx_pwm_disable, |
188 | 152 | .config = imx_pwm_config, | |
189 | if (pwm->use_count) { | 153 | .owner = THIS_MODULE, |
190 | pwm->use_count--; | 154 | }; |
191 | pwm->label = NULL; | ||
192 | } else | ||
193 | pr_warning("PWM device already freed\n"); | ||
194 | |||
195 | mutex_unlock(&pwm_lock); | ||
196 | } | ||
197 | EXPORT_SYMBOL(pwm_free); | ||
198 | 155 | ||
199 | static int __devinit mxc_pwm_probe(struct platform_device *pdev) | 156 | static int __devinit imx_pwm_probe(struct platform_device *pdev) |
200 | { | 157 | { |
201 | struct pwm_device *pwm; | 158 | struct imx_chip *imx; |
202 | struct resource *r; | 159 | struct resource *r; |
203 | int ret = 0; | 160 | int ret = 0; |
204 | 161 | ||
205 | pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | 162 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); |
206 | if (pwm == NULL) { | 163 | if (imx == NULL) { |
207 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 164 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
208 | return -ENOMEM; | 165 | return -ENOMEM; |
209 | } | 166 | } |
210 | 167 | ||
211 | pwm->clk = clk_get(&pdev->dev, "pwm"); | 168 | imx->clk = devm_clk_get(&pdev->dev, "pwm"); |
212 | 169 | ||
213 | if (IS_ERR(pwm->clk)) { | 170 | if (IS_ERR(imx->clk)) |
214 | ret = PTR_ERR(pwm->clk); | 171 | return PTR_ERR(imx->clk); |
215 | goto err_free; | ||
216 | } | ||
217 | 172 | ||
218 | pwm->clk_enabled = 0; | 173 | imx->chip.ops = &imx_pwm_ops; |
174 | imx->chip.dev = &pdev->dev; | ||
175 | imx->chip.base = -1; | ||
176 | imx->chip.npwm = 1; | ||
219 | 177 | ||
220 | pwm->use_count = 0; | 178 | imx->clk_enabled = 0; |
221 | pwm->pwm_id = pdev->id; | ||
222 | pwm->pdev = pdev; | ||
223 | 179 | ||
224 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 180 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
225 | if (r == NULL) { | 181 | if (r == NULL) { |
226 | dev_err(&pdev->dev, "no memory resource defined\n"); | 182 | dev_err(&pdev->dev, "no memory resource defined\n"); |
227 | ret = -ENODEV; | 183 | return -ENODEV; |
228 | goto err_free_clk; | ||
229 | } | ||
230 | |||
231 | r = request_mem_region(r->start, resource_size(r), pdev->name); | ||
232 | if (r == NULL) { | ||
233 | dev_err(&pdev->dev, "failed to request memory resource\n"); | ||
234 | ret = -EBUSY; | ||
235 | goto err_free_clk; | ||
236 | } | 184 | } |
237 | 185 | ||
238 | pwm->mmio_base = ioremap(r->start, resource_size(r)); | 186 | imx->mmio_base = devm_request_and_ioremap(&pdev->dev, r); |
239 | if (pwm->mmio_base == NULL) { | 187 | if (imx->mmio_base == NULL) |
240 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | 188 | return -EADDRNOTAVAIL; |
241 | ret = -ENODEV; | ||
242 | goto err_free_mem; | ||
243 | } | ||
244 | 189 | ||
245 | mutex_lock(&pwm_lock); | 190 | ret = pwmchip_add(&imx->chip); |
246 | list_add_tail(&pwm->node, &pwm_list); | 191 | if (ret < 0) |
247 | mutex_unlock(&pwm_lock); | 192 | return ret; |
248 | 193 | ||
249 | platform_set_drvdata(pdev, pwm); | 194 | platform_set_drvdata(pdev, imx); |
250 | return 0; | 195 | return 0; |
251 | |||
252 | err_free_mem: | ||
253 | release_mem_region(r->start, resource_size(r)); | ||
254 | err_free_clk: | ||
255 | clk_put(pwm->clk); | ||
256 | err_free: | ||
257 | kfree(pwm); | ||
258 | return ret; | ||
259 | } | 196 | } |
260 | 197 | ||
261 | static int __devexit mxc_pwm_remove(struct platform_device *pdev) | 198 | static int __devexit imx_pwm_remove(struct platform_device *pdev) |
262 | { | 199 | { |
263 | struct pwm_device *pwm; | 200 | struct imx_chip *imx; |
264 | struct resource *r; | ||
265 | 201 | ||
266 | pwm = platform_get_drvdata(pdev); | 202 | imx = platform_get_drvdata(pdev); |
267 | if (pwm == NULL) | 203 | if (imx == NULL) |
268 | return -ENODEV; | 204 | return -ENODEV; |
269 | 205 | ||
270 | mutex_lock(&pwm_lock); | 206 | return pwmchip_remove(&imx->chip); |
271 | list_del(&pwm->node); | ||
272 | mutex_unlock(&pwm_lock); | ||
273 | |||
274 | iounmap(pwm->mmio_base); | ||
275 | |||
276 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
277 | release_mem_region(r->start, resource_size(r)); | ||
278 | |||
279 | clk_put(pwm->clk); | ||
280 | |||
281 | kfree(pwm); | ||
282 | return 0; | ||
283 | } | 207 | } |
284 | 208 | ||
285 | static struct platform_driver mxc_pwm_driver = { | 209 | static struct platform_driver imx_pwm_driver = { |
286 | .driver = { | 210 | .driver = { |
287 | .name = "mxc_pwm", | 211 | .name = "mxc_pwm", |
288 | }, | 212 | }, |
289 | .probe = mxc_pwm_probe, | 213 | .probe = imx_pwm_probe, |
290 | .remove = __devexit_p(mxc_pwm_remove), | 214 | .remove = __devexit_p(imx_pwm_remove), |
291 | }; | 215 | }; |
292 | 216 | ||
293 | static int __init mxc_pwm_init(void) | 217 | static int __init imx_pwm_init(void) |
294 | { | 218 | { |
295 | return platform_driver_register(&mxc_pwm_driver); | 219 | return platform_driver_register(&imx_pwm_driver); |
296 | } | 220 | } |
297 | arch_initcall(mxc_pwm_init); | 221 | arch_initcall(imx_pwm_init); |
298 | 222 | ||
299 | static void __exit mxc_pwm_exit(void) | 223 | static void __exit imx_pwm_exit(void) |
300 | { | 224 | { |
301 | platform_driver_unregister(&mxc_pwm_driver); | 225 | platform_driver_unregister(&imx_pwm_driver); |
302 | } | 226 | } |
303 | module_exit(mxc_pwm_exit); | 227 | module_exit(imx_pwm_exit); |
304 | 228 | ||
305 | MODULE_LICENSE("GPL v2"); | 229 | MODULE_LICENSE("GPL v2"); |
306 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | 230 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); |
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c new file mode 100644 index 000000000000..adb87f0c1633 --- /dev/null +++ b/drivers/pwm/pwm-lpc32xx.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Alexandre Pereira da Silva <aletes.xgr@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/pwm.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | struct lpc32xx_pwm_chip { | ||
22 | struct pwm_chip chip; | ||
23 | struct clk *clk; | ||
24 | void __iomem *base; | ||
25 | }; | ||
26 | |||
27 | #define PWM_ENABLE (1 << 31) | ||
28 | #define PWM_RELOADV(x) (((x) & 0xFF) << 8) | ||
29 | #define PWM_DUTY(x) ((x) & 0xFF) | ||
30 | |||
31 | #define to_lpc32xx_pwm_chip(_chip) \ | ||
32 | container_of(_chip, struct lpc32xx_pwm_chip, chip) | ||
33 | |||
34 | static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
35 | int duty_ns, int period_ns) | ||
36 | { | ||
37 | struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); | ||
38 | unsigned long long c; | ||
39 | int period_cycles, duty_cycles; | ||
40 | |||
41 | c = clk_get_rate(lpc32xx->clk) / 256; | ||
42 | c = c * period_ns; | ||
43 | do_div(c, NSEC_PER_SEC); | ||
44 | |||
45 | /* Handle high and low extremes */ | ||
46 | if (c == 0) | ||
47 | c = 1; | ||
48 | if (c > 255) | ||
49 | c = 0; /* 0 set division by 256 */ | ||
50 | period_cycles = c; | ||
51 | |||
52 | c = 256 * duty_ns; | ||
53 | do_div(c, period_ns); | ||
54 | duty_cycles = c; | ||
55 | |||
56 | writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles), | ||
57 | lpc32xx->base + (pwm->hwpwm << 2)); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
63 | { | ||
64 | struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); | ||
65 | |||
66 | return clk_enable(lpc32xx->clk); | ||
67 | } | ||
68 | |||
69 | static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
70 | { | ||
71 | struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip); | ||
72 | |||
73 | writel(0, lpc32xx->base + (pwm->hwpwm << 2)); | ||
74 | clk_disable(lpc32xx->clk); | ||
75 | } | ||
76 | |||
77 | static const struct pwm_ops lpc32xx_pwm_ops = { | ||
78 | .config = lpc32xx_pwm_config, | ||
79 | .enable = lpc32xx_pwm_enable, | ||
80 | .disable = lpc32xx_pwm_disable, | ||
81 | .owner = THIS_MODULE, | ||
82 | }; | ||
83 | |||
84 | static int lpc32xx_pwm_probe(struct platform_device *pdev) | ||
85 | { | ||
86 | struct lpc32xx_pwm_chip *lpc32xx; | ||
87 | struct resource *res; | ||
88 | int ret; | ||
89 | |||
90 | lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL); | ||
91 | if (!lpc32xx) | ||
92 | return -ENOMEM; | ||
93 | |||
94 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
95 | if (!res) | ||
96 | return -EINVAL; | ||
97 | |||
98 | lpc32xx->base = devm_request_and_ioremap(&pdev->dev, res); | ||
99 | if (!lpc32xx->base) | ||
100 | return -EADDRNOTAVAIL; | ||
101 | |||
102 | lpc32xx->clk = devm_clk_get(&pdev->dev, NULL); | ||
103 | if (IS_ERR(lpc32xx->clk)) | ||
104 | return PTR_ERR(lpc32xx->clk); | ||
105 | |||
106 | lpc32xx->chip.dev = &pdev->dev; | ||
107 | lpc32xx->chip.ops = &lpc32xx_pwm_ops; | ||
108 | lpc32xx->chip.npwm = 2; | ||
109 | |||
110 | ret = pwmchip_add(&lpc32xx->chip); | ||
111 | if (ret < 0) { | ||
112 | dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | platform_set_drvdata(pdev, lpc32xx); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int __devexit lpc32xx_pwm_remove(struct platform_device *pdev) | ||
122 | { | ||
123 | struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev); | ||
124 | |||
125 | clk_disable(lpc32xx->clk); | ||
126 | return pwmchip_remove(&lpc32xx->chip); | ||
127 | } | ||
128 | |||
129 | static struct of_device_id lpc32xx_pwm_dt_ids[] = { | ||
130 | { .compatible = "nxp,lpc3220-pwm", }, | ||
131 | { /* sentinel */ } | ||
132 | }; | ||
133 | MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids); | ||
134 | |||
135 | static struct platform_driver lpc32xx_pwm_driver = { | ||
136 | .driver = { | ||
137 | .name = "lpc32xx-pwm", | ||
138 | .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids), | ||
139 | }, | ||
140 | .probe = lpc32xx_pwm_probe, | ||
141 | .remove = __devexit_p(lpc32xx_pwm_remove), | ||
142 | }; | ||
143 | module_platform_driver(lpc32xx_pwm_driver); | ||
144 | |||
145 | MODULE_ALIAS("platform:lpc32xx-pwm"); | ||
146 | MODULE_AUTHOR("Alexandre Pereira da Silva <aletes.xgr@gmail.com>"); | ||
147 | MODULE_DESCRIPTION("LPC32XX PWM Driver"); | ||
148 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c new file mode 100644 index 000000000000..e5852646f082 --- /dev/null +++ b/drivers/pwm/pwm-mxs.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The code contained herein is licensed under the GNU General Public | ||
5 | * License. You may obtain a copy of the GNU General Public License | ||
6 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/pinctrl/consumer.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/pwm.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/stmp_device.h> | ||
24 | |||
25 | #define SET 0x4 | ||
26 | #define CLR 0x8 | ||
27 | #define TOG 0xc | ||
28 | |||
29 | #define PWM_CTRL 0x0 | ||
30 | #define PWM_ACTIVE0 0x10 | ||
31 | #define PWM_PERIOD0 0x20 | ||
32 | #define PERIOD_PERIOD(p) ((p) & 0xffff) | ||
33 | #define PERIOD_PERIOD_MAX 0x10000 | ||
34 | #define PERIOD_ACTIVE_HIGH (3 << 16) | ||
35 | #define PERIOD_INACTIVE_LOW (2 << 18) | ||
36 | #define PERIOD_CDIV(div) (((div) & 0x7) << 20) | ||
37 | #define PERIOD_CDIV_MAX 8 | ||
38 | |||
39 | struct mxs_pwm_chip { | ||
40 | struct pwm_chip chip; | ||
41 | struct device *dev; | ||
42 | struct clk *clk; | ||
43 | void __iomem *base; | ||
44 | }; | ||
45 | |||
46 | #define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip) | ||
47 | |||
48 | static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
49 | int duty_ns, int period_ns) | ||
50 | { | ||
51 | struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); | ||
52 | int ret, div = 0; | ||
53 | unsigned int period_cycles, duty_cycles; | ||
54 | unsigned long rate; | ||
55 | unsigned long long c; | ||
56 | |||
57 | rate = clk_get_rate(mxs->clk); | ||
58 | while (1) { | ||
59 | c = rate / (1 << div); | ||
60 | c = c * period_ns; | ||
61 | do_div(c, 1000000000); | ||
62 | if (c < PERIOD_PERIOD_MAX) | ||
63 | break; | ||
64 | div++; | ||
65 | if (div > PERIOD_CDIV_MAX) | ||
66 | return -EINVAL; | ||
67 | } | ||
68 | |||
69 | period_cycles = c; | ||
70 | c *= duty_ns; | ||
71 | do_div(c, period_ns); | ||
72 | duty_cycles = c; | ||
73 | |||
74 | /* | ||
75 | * If the PWM channel is disabled, make sure to turn on the clock | ||
76 | * before writing the register. Otherwise, keep it enabled. | ||
77 | */ | ||
78 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
79 | ret = clk_prepare_enable(mxs->clk); | ||
80 | if (ret) | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | writel(duty_cycles << 16, | ||
85 | mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20); | ||
86 | writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH | | ||
87 | PERIOD_INACTIVE_LOW | PERIOD_CDIV(div), | ||
88 | mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20); | ||
89 | |||
90 | /* | ||
91 | * If the PWM is not enabled, turn the clock off again to save power. | ||
92 | */ | ||
93 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) | ||
94 | clk_disable_unprepare(mxs->clk); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int mxs_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
100 | { | ||
101 | struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); | ||
102 | int ret; | ||
103 | |||
104 | ret = clk_prepare_enable(mxs->clk); | ||
105 | if (ret) | ||
106 | return ret; | ||
107 | |||
108 | writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static void mxs_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
114 | { | ||
115 | struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); | ||
116 | |||
117 | writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + CLR); | ||
118 | |||
119 | clk_disable_unprepare(mxs->clk); | ||
120 | } | ||
121 | |||
122 | static const struct pwm_ops mxs_pwm_ops = { | ||
123 | .config = mxs_pwm_config, | ||
124 | .enable = mxs_pwm_enable, | ||
125 | .disable = mxs_pwm_disable, | ||
126 | .owner = THIS_MODULE, | ||
127 | }; | ||
128 | |||
129 | static int mxs_pwm_probe(struct platform_device *pdev) | ||
130 | { | ||
131 | struct device_node *np = pdev->dev.of_node; | ||
132 | struct mxs_pwm_chip *mxs; | ||
133 | struct resource *res; | ||
134 | struct pinctrl *pinctrl; | ||
135 | int ret; | ||
136 | |||
137 | mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL); | ||
138 | if (!mxs) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
142 | mxs->base = devm_request_and_ioremap(&pdev->dev, res); | ||
143 | if (!mxs->base) | ||
144 | return -EADDRNOTAVAIL; | ||
145 | |||
146 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
147 | if (IS_ERR(pinctrl)) | ||
148 | return PTR_ERR(pinctrl); | ||
149 | |||
150 | mxs->clk = devm_clk_get(&pdev->dev, NULL); | ||
151 | if (IS_ERR(mxs->clk)) | ||
152 | return PTR_ERR(mxs->clk); | ||
153 | |||
154 | mxs->chip.dev = &pdev->dev; | ||
155 | mxs->chip.ops = &mxs_pwm_ops; | ||
156 | mxs->chip.base = -1; | ||
157 | ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm); | ||
158 | if (ret < 0) { | ||
159 | dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | ret = pwmchip_add(&mxs->chip); | ||
164 | if (ret < 0) { | ||
165 | dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | mxs->dev = &pdev->dev; | ||
170 | platform_set_drvdata(pdev, mxs); | ||
171 | |||
172 | stmp_reset_block(mxs->base); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int __devexit mxs_pwm_remove(struct platform_device *pdev) | ||
178 | { | ||
179 | struct mxs_pwm_chip *mxs = platform_get_drvdata(pdev); | ||
180 | |||
181 | return pwmchip_remove(&mxs->chip); | ||
182 | } | ||
183 | |||
184 | static struct of_device_id mxs_pwm_dt_ids[] = { | ||
185 | { .compatible = "fsl,imx23-pwm", }, | ||
186 | { /* sentinel */ } | ||
187 | }; | ||
188 | MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids); | ||
189 | |||
190 | static struct platform_driver mxs_pwm_driver = { | ||
191 | .driver = { | ||
192 | .name = "mxs-pwm", | ||
193 | .of_match_table = of_match_ptr(mxs_pwm_dt_ids), | ||
194 | }, | ||
195 | .probe = mxs_pwm_probe, | ||
196 | .remove = __devexit_p(mxs_pwm_remove), | ||
197 | }; | ||
198 | module_platform_driver(mxs_pwm_driver); | ||
199 | |||
200 | MODULE_ALIAS("platform:mxs-pwm"); | ||
201 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | ||
202 | MODULE_DESCRIPTION("Freescale MXS PWM Driver"); | ||
203 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c new file mode 100644 index 000000000000..bd5867a1c700 --- /dev/null +++ b/drivers/pwm/pwm-pxa.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * drivers/pwm/pwm-pxa.c | ||
3 | * | ||
4 | * simple driver for PWM (Pulse Width Modulator) controller | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * 2008-02-13 initial version | ||
11 | * eric miao <eric.miao@marvell.com> | ||
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 | |||
25 | #define HAS_SECONDARY_PWM 0x10 | ||
26 | #define PWM_ID_BASE(d) ((d) & 0xf) | ||
27 | |||
28 | static const struct platform_device_id pwm_id_table[] = { | ||
29 | /* PWM has_secondary_pwm? */ | ||
30 | { "pxa25x-pwm", 0 }, | ||
31 | { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM }, | ||
32 | { "pxa168-pwm", 1 }, | ||
33 | { "pxa910-pwm", 1 }, | ||
34 | { }, | ||
35 | }; | ||
36 | MODULE_DEVICE_TABLE(platform, pwm_id_table); | ||
37 | |||
38 | /* PWM registers and bits definitions */ | ||
39 | #define PWMCR (0x00) | ||
40 | #define PWMDCR (0x04) | ||
41 | #define PWMPCR (0x08) | ||
42 | |||
43 | #define PWMCR_SD (1 << 6) | ||
44 | #define PWMDCR_FD (1 << 10) | ||
45 | |||
46 | struct pxa_pwm_chip { | ||
47 | struct pwm_chip chip; | ||
48 | struct device *dev; | ||
49 | |||
50 | struct clk *clk; | ||
51 | int clk_enabled; | ||
52 | void __iomem *mmio_base; | ||
53 | }; | ||
54 | |||
55 | static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip) | ||
56 | { | ||
57 | return container_of(chip, struct pxa_pwm_chip, chip); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE | ||
62 | * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE | ||
63 | */ | ||
64 | static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
65 | int duty_ns, int period_ns) | ||
66 | { | ||
67 | struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); | ||
68 | unsigned long long c; | ||
69 | unsigned long period_cycles, prescale, pv, dc; | ||
70 | unsigned long offset; | ||
71 | int rc; | ||
72 | |||
73 | if (period_ns == 0 || duty_ns > period_ns) | ||
74 | return -EINVAL; | ||
75 | |||
76 | offset = pwm->hwpwm ? 0x10 : 0; | ||
77 | |||
78 | c = clk_get_rate(pc->clk); | ||
79 | c = c * period_ns; | ||
80 | do_div(c, 1000000000); | ||
81 | period_cycles = c; | ||
82 | |||
83 | if (period_cycles < 1) | ||
84 | period_cycles = 1; | ||
85 | prescale = (period_cycles - 1) / 1024; | ||
86 | pv = period_cycles / (prescale + 1) - 1; | ||
87 | |||
88 | if (prescale > 63) | ||
89 | return -EINVAL; | ||
90 | |||
91 | if (duty_ns == period_ns) | ||
92 | dc = PWMDCR_FD; | ||
93 | else | ||
94 | dc = (pv + 1) * duty_ns / period_ns; | ||
95 | |||
96 | /* NOTE: the clock to PWM has to be enabled first | ||
97 | * before writing to the registers | ||
98 | */ | ||
99 | rc = clk_prepare_enable(pc->clk); | ||
100 | if (rc < 0) | ||
101 | return rc; | ||
102 | |||
103 | writel(prescale, pc->mmio_base + offset + PWMCR); | ||
104 | writel(dc, pc->mmio_base + offset + PWMDCR); | ||
105 | writel(pv, pc->mmio_base + offset + PWMPCR); | ||
106 | |||
107 | clk_disable_unprepare(pc->clk); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
112 | { | ||
113 | struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); | ||
114 | int rc = 0; | ||
115 | |||
116 | if (!pc->clk_enabled) { | ||
117 | rc = clk_prepare_enable(pc->clk); | ||
118 | if (!rc) | ||
119 | pc->clk_enabled++; | ||
120 | } | ||
121 | return rc; | ||
122 | } | ||
123 | |||
124 | static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
125 | { | ||
126 | struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip); | ||
127 | |||
128 | if (pc->clk_enabled) { | ||
129 | clk_disable_unprepare(pc->clk); | ||
130 | pc->clk_enabled--; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static struct pwm_ops pxa_pwm_ops = { | ||
135 | .config = pxa_pwm_config, | ||
136 | .enable = pxa_pwm_enable, | ||
137 | .disable = pxa_pwm_disable, | ||
138 | .owner = THIS_MODULE, | ||
139 | }; | ||
140 | |||
141 | static int __devinit pwm_probe(struct platform_device *pdev) | ||
142 | { | ||
143 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
144 | struct pxa_pwm_chip *pwm; | ||
145 | struct resource *r; | ||
146 | int ret = 0; | ||
147 | |||
148 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); | ||
149 | if (pwm == NULL) { | ||
150 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
151 | return -ENOMEM; | ||
152 | } | ||
153 | |||
154 | pwm->clk = devm_clk_get(&pdev->dev, NULL); | ||
155 | if (IS_ERR(pwm->clk)) | ||
156 | return PTR_ERR(pwm->clk); | ||
157 | |||
158 | pwm->clk_enabled = 0; | ||
159 | |||
160 | pwm->chip.dev = &pdev->dev; | ||
161 | pwm->chip.ops = &pxa_pwm_ops; | ||
162 | pwm->chip.base = -1; | ||
163 | pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; | ||
164 | |||
165 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
166 | if (r == NULL) { | ||
167 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
168 | return -ENODEV; | ||
169 | } | ||
170 | |||
171 | pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r); | ||
172 | if (pwm->mmio_base == NULL) | ||
173 | return -EADDRNOTAVAIL; | ||
174 | |||
175 | ret = pwmchip_add(&pwm->chip); | ||
176 | if (ret < 0) { | ||
177 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | platform_set_drvdata(pdev, pwm); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int __devexit pwm_remove(struct platform_device *pdev) | ||
186 | { | ||
187 | struct pxa_pwm_chip *chip; | ||
188 | |||
189 | chip = platform_get_drvdata(pdev); | ||
190 | if (chip == NULL) | ||
191 | return -ENODEV; | ||
192 | |||
193 | return pwmchip_remove(&chip->chip); | ||
194 | } | ||
195 | |||
196 | static struct platform_driver pwm_driver = { | ||
197 | .driver = { | ||
198 | .name = "pxa25x-pwm", | ||
199 | .owner = THIS_MODULE, | ||
200 | }, | ||
201 | .probe = pwm_probe, | ||
202 | .remove = __devexit_p(pwm_remove), | ||
203 | .id_table = pwm_id_table, | ||
204 | }; | ||
205 | |||
206 | static int __init pwm_init(void) | ||
207 | { | ||
208 | return platform_driver_register(&pwm_driver); | ||
209 | } | ||
210 | arch_initcall(pwm_init); | ||
211 | |||
212 | static void __exit pwm_exit(void) | ||
213 | { | ||
214 | platform_driver_unregister(&pwm_driver); | ||
215 | } | ||
216 | module_exit(pwm_exit); | ||
217 | |||
218 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/arm/plat-samsung/pwm.c b/drivers/pwm/pwm-samsung.c index d3583050fb05..d10386528c9c 100644 --- a/arch/arm/plat-samsung/pwm.c +++ b/drivers/pwm/pwm-samsung.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/plat-s3c/pwm.c | 1 | /* drivers/pwm/pwm-samsung.c |
2 | * | 2 | * |
3 | * Copyright (c) 2007 Ben Dooks | 3 | * Copyright (c) 2007 Ben Dooks |
4 | * Copyright (c) 2008 Simtec Electronics | 4 | * Copyright (c) 2008 Simtec Electronics |
@@ -11,6 +11,8 @@ | |||
11 | * the Free Software Foundation; either version 2 of the License. | 11 | * the Free Software Foundation; either version 2 of the License. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #define pr_fmt(fmt) "pwm-samsung: " fmt | ||
15 | |||
14 | #include <linux/export.h> | 16 | #include <linux/export.h> |
15 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
16 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
@@ -24,8 +26,7 @@ | |||
24 | 26 | ||
25 | #include <plat/regs-timer.h> | 27 | #include <plat/regs-timer.h> |
26 | 28 | ||
27 | struct pwm_device { | 29 | struct s3c_chip { |
28 | struct list_head list; | ||
29 | struct platform_device *pdev; | 30 | struct platform_device *pdev; |
30 | 31 | ||
31 | struct clk *clk_div; | 32 | struct clk *clk_div; |
@@ -36,81 +37,36 @@ struct pwm_device { | |||
36 | unsigned int duty_ns; | 37 | unsigned int duty_ns; |
37 | 38 | ||
38 | unsigned char tcon_base; | 39 | unsigned char tcon_base; |
39 | unsigned char use_count; | ||
40 | unsigned char pwm_id; | 40 | unsigned char pwm_id; |
41 | struct pwm_chip chip; | ||
41 | }; | 42 | }; |
42 | 43 | ||
44 | #define to_s3c_chip(chip) container_of(chip, struct s3c_chip, chip) | ||
45 | |||
43 | #define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg) | 46 | #define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg) |
44 | 47 | ||
45 | static struct clk *clk_scaler[2]; | 48 | static struct clk *clk_scaler[2]; |
46 | 49 | ||
47 | static inline int pwm_is_tdiv(struct pwm_device *pwm) | 50 | static inline int pwm_is_tdiv(struct s3c_chip *chip) |
48 | { | ||
49 | return clk_get_parent(pwm->clk) == pwm->clk_div; | ||
50 | } | ||
51 | |||
52 | static DEFINE_MUTEX(pwm_lock); | ||
53 | static LIST_HEAD(pwm_list); | ||
54 | |||
55 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
56 | { | ||
57 | struct pwm_device *pwm; | ||
58 | int found = 0; | ||
59 | |||
60 | mutex_lock(&pwm_lock); | ||
61 | |||
62 | list_for_each_entry(pwm, &pwm_list, list) { | ||
63 | if (pwm->pwm_id == pwm_id) { | ||
64 | found = 1; | ||
65 | break; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | if (found) { | ||
70 | if (pwm->use_count == 0) { | ||
71 | pwm->use_count = 1; | ||
72 | pwm->label = label; | ||
73 | } else | ||
74 | pwm = ERR_PTR(-EBUSY); | ||
75 | } else | ||
76 | pwm = ERR_PTR(-ENOENT); | ||
77 | |||
78 | mutex_unlock(&pwm_lock); | ||
79 | return pwm; | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL(pwm_request); | ||
83 | |||
84 | |||
85 | void pwm_free(struct pwm_device *pwm) | ||
86 | { | 51 | { |
87 | mutex_lock(&pwm_lock); | 52 | return clk_get_parent(chip->clk) == chip->clk_div; |
88 | |||
89 | if (pwm->use_count) { | ||
90 | pwm->use_count--; | ||
91 | pwm->label = NULL; | ||
92 | } else | ||
93 | printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id); | ||
94 | |||
95 | mutex_unlock(&pwm_lock); | ||
96 | } | 53 | } |
97 | 54 | ||
98 | EXPORT_SYMBOL(pwm_free); | ||
99 | |||
100 | #define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0)) | 55 | #define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0)) |
101 | #define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2)) | 56 | #define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2)) |
102 | #define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3)) | 57 | #define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3)) |
103 | #define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1)) | 58 | #define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1)) |
104 | 59 | ||
105 | int pwm_enable(struct pwm_device *pwm) | 60 | static int s3c_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
106 | { | 61 | { |
62 | struct s3c_chip *s3c = to_s3c_chip(chip); | ||
107 | unsigned long flags; | 63 | unsigned long flags; |
108 | unsigned long tcon; | 64 | unsigned long tcon; |
109 | 65 | ||
110 | local_irq_save(flags); | 66 | local_irq_save(flags); |
111 | 67 | ||
112 | tcon = __raw_readl(S3C2410_TCON); | 68 | tcon = __raw_readl(S3C2410_TCON); |
113 | tcon |= pwm_tcon_start(pwm); | 69 | tcon |= pwm_tcon_start(s3c); |
114 | __raw_writel(tcon, S3C2410_TCON); | 70 | __raw_writel(tcon, S3C2410_TCON); |
115 | 71 | ||
116 | local_irq_restore(flags); | 72 | local_irq_restore(flags); |
@@ -118,31 +74,28 @@ int pwm_enable(struct pwm_device *pwm) | |||
118 | return 0; | 74 | return 0; |
119 | } | 75 | } |
120 | 76 | ||
121 | EXPORT_SYMBOL(pwm_enable); | 77 | static void s3c_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
122 | |||
123 | void pwm_disable(struct pwm_device *pwm) | ||
124 | { | 78 | { |
79 | struct s3c_chip *s3c = to_s3c_chip(chip); | ||
125 | unsigned long flags; | 80 | unsigned long flags; |
126 | unsigned long tcon; | 81 | unsigned long tcon; |
127 | 82 | ||
128 | local_irq_save(flags); | 83 | local_irq_save(flags); |
129 | 84 | ||
130 | tcon = __raw_readl(S3C2410_TCON); | 85 | tcon = __raw_readl(S3C2410_TCON); |
131 | tcon &= ~pwm_tcon_start(pwm); | 86 | tcon &= ~pwm_tcon_start(s3c); |
132 | __raw_writel(tcon, S3C2410_TCON); | 87 | __raw_writel(tcon, S3C2410_TCON); |
133 | 88 | ||
134 | local_irq_restore(flags); | 89 | local_irq_restore(flags); |
135 | } | 90 | } |
136 | 91 | ||
137 | EXPORT_SYMBOL(pwm_disable); | 92 | static unsigned long pwm_calc_tin(struct s3c_chip *s3c, unsigned long freq) |
138 | |||
139 | static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq) | ||
140 | { | 93 | { |
141 | unsigned long tin_parent_rate; | 94 | unsigned long tin_parent_rate; |
142 | unsigned int div; | 95 | unsigned int div; |
143 | 96 | ||
144 | tin_parent_rate = clk_get_rate(clk_get_parent(pwm->clk_div)); | 97 | tin_parent_rate = clk_get_rate(clk_get_parent(s3c->clk_div)); |
145 | pwm_dbg(pwm, "tin parent at %lu\n", tin_parent_rate); | 98 | pwm_dbg(s3c, "tin parent at %lu\n", tin_parent_rate); |
146 | 99 | ||
147 | for (div = 2; div <= 16; div *= 2) { | 100 | for (div = 2; div <= 16; div *= 2) { |
148 | if ((tin_parent_rate / (div << 16)) < freq) | 101 | if ((tin_parent_rate / (div << 16)) < freq) |
@@ -154,8 +107,10 @@ static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq) | |||
154 | 107 | ||
155 | #define NS_IN_HZ (1000000000UL) | 108 | #define NS_IN_HZ (1000000000UL) |
156 | 109 | ||
157 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | 110 | static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
111 | int duty_ns, int period_ns) | ||
158 | { | 112 | { |
113 | struct s3c_chip *s3c = to_s3c_chip(chip); | ||
159 | unsigned long tin_rate; | 114 | unsigned long tin_rate; |
160 | unsigned long tin_ns; | 115 | unsigned long tin_ns; |
161 | unsigned long period; | 116 | unsigned long period; |
@@ -174,38 +129,38 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
174 | if (duty_ns > period_ns) | 129 | if (duty_ns > period_ns) |
175 | return -EINVAL; | 130 | return -EINVAL; |
176 | 131 | ||
177 | if (period_ns == pwm->period_ns && | 132 | if (period_ns == s3c->period_ns && |
178 | duty_ns == pwm->duty_ns) | 133 | duty_ns == s3c->duty_ns) |
179 | return 0; | 134 | return 0; |
180 | 135 | ||
181 | /* The TCMP and TCNT can be read without a lock, they're not | 136 | /* The TCMP and TCNT can be read without a lock, they're not |
182 | * shared between the timers. */ | 137 | * shared between the timers. */ |
183 | 138 | ||
184 | tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id)); | 139 | tcmp = __raw_readl(S3C2410_TCMPB(s3c->pwm_id)); |
185 | tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id)); | 140 | tcnt = __raw_readl(S3C2410_TCNTB(s3c->pwm_id)); |
186 | 141 | ||
187 | period = NS_IN_HZ / period_ns; | 142 | period = NS_IN_HZ / period_ns; |
188 | 143 | ||
189 | pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n", | 144 | pwm_dbg(s3c, "duty_ns=%d, period_ns=%d (%lu)\n", |
190 | duty_ns, period_ns, period); | 145 | duty_ns, period_ns, period); |
191 | 146 | ||
192 | /* Check to see if we are changing the clock rate of the PWM */ | 147 | /* Check to see if we are changing the clock rate of the PWM */ |
193 | 148 | ||
194 | if (pwm->period_ns != period_ns) { | 149 | if (s3c->period_ns != period_ns) { |
195 | if (pwm_is_tdiv(pwm)) { | 150 | if (pwm_is_tdiv(s3c)) { |
196 | tin_rate = pwm_calc_tin(pwm, period); | 151 | tin_rate = pwm_calc_tin(s3c, period); |
197 | clk_set_rate(pwm->clk_div, tin_rate); | 152 | clk_set_rate(s3c->clk_div, tin_rate); |
198 | } else | 153 | } else |
199 | tin_rate = clk_get_rate(pwm->clk); | 154 | tin_rate = clk_get_rate(s3c->clk); |
200 | 155 | ||
201 | pwm->period_ns = period_ns; | 156 | s3c->period_ns = period_ns; |
202 | 157 | ||
203 | pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate); | 158 | pwm_dbg(s3c, "tin_rate=%lu\n", tin_rate); |
204 | 159 | ||
205 | tin_ns = NS_IN_HZ / tin_rate; | 160 | tin_ns = NS_IN_HZ / tin_rate; |
206 | tcnt = period_ns / tin_ns; | 161 | tcnt = period_ns / tin_ns; |
207 | } else | 162 | } else |
208 | tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk); | 163 | tin_ns = NS_IN_HZ / clk_get_rate(s3c->clk); |
209 | 164 | ||
210 | /* Note, counters count down */ | 165 | /* Note, counters count down */ |
211 | 166 | ||
@@ -216,7 +171,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
216 | if (tcmp == tcnt) | 171 | if (tcmp == tcnt) |
217 | tcmp--; | 172 | tcmp--; |
218 | 173 | ||
219 | pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); | 174 | pwm_dbg(s3c, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); |
220 | 175 | ||
221 | if (tcmp < 0) | 176 | if (tcmp < 0) |
222 | tcmp = 0; | 177 | tcmp = 0; |
@@ -225,15 +180,15 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
225 | 180 | ||
226 | local_irq_save(flags); | 181 | local_irq_save(flags); |
227 | 182 | ||
228 | __raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id)); | 183 | __raw_writel(tcmp, S3C2410_TCMPB(s3c->pwm_id)); |
229 | __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id)); | 184 | __raw_writel(tcnt, S3C2410_TCNTB(s3c->pwm_id)); |
230 | 185 | ||
231 | tcon = __raw_readl(S3C2410_TCON); | 186 | tcon = __raw_readl(S3C2410_TCON); |
232 | tcon |= pwm_tcon_manulupdate(pwm); | 187 | tcon |= pwm_tcon_manulupdate(s3c); |
233 | tcon |= pwm_tcon_autoreload(pwm); | 188 | tcon |= pwm_tcon_autoreload(s3c); |
234 | __raw_writel(tcon, S3C2410_TCON); | 189 | __raw_writel(tcon, S3C2410_TCON); |
235 | 190 | ||
236 | tcon &= ~pwm_tcon_manulupdate(pwm); | 191 | tcon &= ~pwm_tcon_manulupdate(s3c); |
237 | __raw_writel(tcon, S3C2410_TCON); | 192 | __raw_writel(tcon, S3C2410_TCON); |
238 | 193 | ||
239 | local_irq_restore(flags); | 194 | local_irq_restore(flags); |
@@ -241,24 +196,17 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | |||
241 | return 0; | 196 | return 0; |
242 | } | 197 | } |
243 | 198 | ||
244 | EXPORT_SYMBOL(pwm_config); | 199 | static struct pwm_ops s3c_pwm_ops = { |
245 | 200 | .enable = s3c_pwm_enable, | |
246 | static int pwm_register(struct pwm_device *pwm) | 201 | .disable = s3c_pwm_disable, |
247 | { | 202 | .config = s3c_pwm_config, |
248 | pwm->duty_ns = -1; | 203 | .owner = THIS_MODULE, |
249 | pwm->period_ns = -1; | 204 | }; |
250 | |||
251 | mutex_lock(&pwm_lock); | ||
252 | list_add_tail(&pwm->list, &pwm_list); | ||
253 | mutex_unlock(&pwm_lock); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | 205 | ||
258 | static int s3c_pwm_probe(struct platform_device *pdev) | 206 | static int s3c_pwm_probe(struct platform_device *pdev) |
259 | { | 207 | { |
260 | struct device *dev = &pdev->dev; | 208 | struct device *dev = &pdev->dev; |
261 | struct pwm_device *pwm; | 209 | struct s3c_chip *s3c; |
262 | unsigned long flags; | 210 | unsigned long flags; |
263 | unsigned long tcon; | 211 | unsigned long tcon; |
264 | unsigned int id = pdev->id; | 212 | unsigned int id = pdev->id; |
@@ -269,83 +217,75 @@ static int s3c_pwm_probe(struct platform_device *pdev) | |||
269 | return -ENXIO; | 217 | return -ENXIO; |
270 | } | 218 | } |
271 | 219 | ||
272 | pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | 220 | s3c = devm_kzalloc(&pdev->dev, sizeof(*s3c), GFP_KERNEL); |
273 | if (pwm == NULL) { | 221 | if (s3c == NULL) { |
274 | dev_err(dev, "failed to allocate pwm_device\n"); | 222 | dev_err(dev, "failed to allocate pwm_device\n"); |
275 | return -ENOMEM; | 223 | return -ENOMEM; |
276 | } | 224 | } |
277 | 225 | ||
278 | pwm->pdev = pdev; | ||
279 | pwm->pwm_id = id; | ||
280 | |||
281 | /* calculate base of control bits in TCON */ | 226 | /* calculate base of control bits in TCON */ |
282 | pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4; | 227 | s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4; |
228 | s3c->chip.ops = &s3c_pwm_ops; | ||
229 | s3c->chip.base = -1; | ||
230 | s3c->chip.npwm = 1; | ||
283 | 231 | ||
284 | pwm->clk = clk_get(dev, "pwm-tin"); | 232 | s3c->clk = devm_clk_get(dev, "pwm-tin"); |
285 | if (IS_ERR(pwm->clk)) { | 233 | if (IS_ERR(s3c->clk)) { |
286 | dev_err(dev, "failed to get pwm tin clk\n"); | 234 | dev_err(dev, "failed to get pwm tin clk\n"); |
287 | ret = PTR_ERR(pwm->clk); | 235 | return PTR_ERR(s3c->clk); |
288 | goto err_alloc; | ||
289 | } | 236 | } |
290 | 237 | ||
291 | pwm->clk_div = clk_get(dev, "pwm-tdiv"); | 238 | s3c->clk_div = devm_clk_get(dev, "pwm-tdiv"); |
292 | if (IS_ERR(pwm->clk_div)) { | 239 | if (IS_ERR(s3c->clk_div)) { |
293 | dev_err(dev, "failed to get pwm tdiv clk\n"); | 240 | dev_err(dev, "failed to get pwm tdiv clk\n"); |
294 | ret = PTR_ERR(pwm->clk_div); | 241 | return PTR_ERR(s3c->clk_div); |
295 | goto err_clk_tin; | ||
296 | } | 242 | } |
297 | 243 | ||
298 | clk_enable(pwm->clk); | 244 | clk_enable(s3c->clk); |
299 | clk_enable(pwm->clk_div); | 245 | clk_enable(s3c->clk_div); |
300 | 246 | ||
301 | local_irq_save(flags); | 247 | local_irq_save(flags); |
302 | 248 | ||
303 | tcon = __raw_readl(S3C2410_TCON); | 249 | tcon = __raw_readl(S3C2410_TCON); |
304 | tcon |= pwm_tcon_invert(pwm); | 250 | tcon |= pwm_tcon_invert(s3c); |
305 | __raw_writel(tcon, S3C2410_TCON); | 251 | __raw_writel(tcon, S3C2410_TCON); |
306 | 252 | ||
307 | local_irq_restore(flags); | 253 | local_irq_restore(flags); |
308 | 254 | ||
309 | 255 | ret = pwmchip_add(&s3c->chip); | |
310 | ret = pwm_register(pwm); | 256 | if (ret < 0) { |
311 | if (ret) { | ||
312 | dev_err(dev, "failed to register pwm\n"); | 257 | dev_err(dev, "failed to register pwm\n"); |
313 | goto err_clk_tdiv; | 258 | goto err_clk_tdiv; |
314 | } | 259 | } |
315 | 260 | ||
316 | pwm_dbg(pwm, "config bits %02x\n", | 261 | pwm_dbg(s3c, "config bits %02x\n", |
317 | (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f); | 262 | (__raw_readl(S3C2410_TCON) >> s3c->tcon_base) & 0x0f); |
318 | 263 | ||
319 | dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", | 264 | dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", |
320 | clk_get_rate(pwm->clk), | 265 | clk_get_rate(s3c->clk), |
321 | clk_get_rate(pwm->clk_div), | 266 | clk_get_rate(s3c->clk_div), |
322 | pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base); | 267 | pwm_is_tdiv(s3c) ? "div" : "ext", s3c->tcon_base); |
323 | 268 | ||
324 | platform_set_drvdata(pdev, pwm); | 269 | platform_set_drvdata(pdev, s3c); |
325 | return 0; | 270 | return 0; |
326 | 271 | ||
327 | err_clk_tdiv: | 272 | err_clk_tdiv: |
328 | clk_disable(pwm->clk_div); | 273 | clk_disable(s3c->clk_div); |
329 | clk_disable(pwm->clk); | 274 | clk_disable(s3c->clk); |
330 | clk_put(pwm->clk_div); | ||
331 | |||
332 | err_clk_tin: | ||
333 | clk_put(pwm->clk); | ||
334 | |||
335 | err_alloc: | ||
336 | kfree(pwm); | ||
337 | return ret; | 275 | return ret; |
338 | } | 276 | } |
339 | 277 | ||
340 | static int __devexit s3c_pwm_remove(struct platform_device *pdev) | 278 | static int __devexit s3c_pwm_remove(struct platform_device *pdev) |
341 | { | 279 | { |
342 | struct pwm_device *pwm = platform_get_drvdata(pdev); | 280 | struct s3c_chip *s3c = platform_get_drvdata(pdev); |
281 | int err; | ||
282 | |||
283 | err = pwmchip_remove(&s3c->chip); | ||
284 | if (err < 0) | ||
285 | return err; | ||
343 | 286 | ||
344 | clk_disable(pwm->clk_div); | 287 | clk_disable(s3c->clk_div); |
345 | clk_disable(pwm->clk); | 288 | clk_disable(s3c->clk); |
346 | clk_put(pwm->clk_div); | ||
347 | clk_put(pwm->clk); | ||
348 | kfree(pwm); | ||
349 | 289 | ||
350 | return 0; | 290 | return 0; |
351 | } | 291 | } |
@@ -353,26 +293,26 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev) | |||
353 | #ifdef CONFIG_PM | 293 | #ifdef CONFIG_PM |
354 | static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state) | 294 | static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state) |
355 | { | 295 | { |
356 | struct pwm_device *pwm = platform_get_drvdata(pdev); | 296 | struct s3c_chip *s3c = platform_get_drvdata(pdev); |
357 | 297 | ||
358 | /* No one preserve these values during suspend so reset them | 298 | /* No one preserve these values during suspend so reset them |
359 | * Otherwise driver leaves PWM unconfigured if same values | 299 | * Otherwise driver leaves PWM unconfigured if same values |
360 | * passed to pwm_config | 300 | * passed to pwm_config |
361 | */ | 301 | */ |
362 | pwm->period_ns = 0; | 302 | s3c->period_ns = 0; |
363 | pwm->duty_ns = 0; | 303 | s3c->duty_ns = 0; |
364 | 304 | ||
365 | return 0; | 305 | return 0; |
366 | } | 306 | } |
367 | 307 | ||
368 | static int s3c_pwm_resume(struct platform_device *pdev) | 308 | static int s3c_pwm_resume(struct platform_device *pdev) |
369 | { | 309 | { |
370 | struct pwm_device *pwm = platform_get_drvdata(pdev); | 310 | struct s3c_chip *s3c = platform_get_drvdata(pdev); |
371 | unsigned long tcon; | 311 | unsigned long tcon; |
372 | 312 | ||
373 | /* Restore invertion */ | 313 | /* Restore invertion */ |
374 | tcon = __raw_readl(S3C2410_TCON); | 314 | tcon = __raw_readl(S3C2410_TCON); |
375 | tcon |= pwm_tcon_invert(pwm); | 315 | tcon |= pwm_tcon_invert(s3c); |
376 | __raw_writel(tcon, S3C2410_TCON); | 316 | __raw_writel(tcon, S3C2410_TCON); |
377 | 317 | ||
378 | return 0; | 318 | return 0; |
@@ -402,13 +342,13 @@ static int __init pwm_init(void) | |||
402 | clk_scaler[1] = clk_get(NULL, "pwm-scaler1"); | 342 | clk_scaler[1] = clk_get(NULL, "pwm-scaler1"); |
403 | 343 | ||
404 | if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) { | 344 | if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) { |
405 | printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__); | 345 | pr_err("failed to get scaler clocks\n"); |
406 | return -EINVAL; | 346 | return -EINVAL; |
407 | } | 347 | } |
408 | 348 | ||
409 | ret = platform_driver_register(&s3c_pwm_driver); | 349 | ret = platform_driver_register(&s3c_pwm_driver); |
410 | if (ret) | 350 | if (ret) |
411 | printk(KERN_ERR "%s: failed to add pwm driver\n", __func__); | 351 | pr_err("failed to add pwm driver\n"); |
412 | 352 | ||
413 | return ret; | 353 | return ret; |
414 | } | 354 | } |
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c new file mode 100644 index 000000000000..02ce18d5e49a --- /dev/null +++ b/drivers/pwm/pwm-tegra.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * drivers/pwm/pwm-tegra.c | ||
3 | * | ||
4 | * Tegra pulse-width-modulation controller driver | ||
5 | * | ||
6 | * Copyright (c) 2010, NVIDIA Corporation. | ||
7 | * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de> | ||
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 as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/clk.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/of.h> | ||
29 | #include <linux/pwm.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #define PWM_ENABLE (1 << 31) | ||
34 | #define PWM_DUTY_WIDTH 8 | ||
35 | #define PWM_DUTY_SHIFT 16 | ||
36 | #define PWM_SCALE_WIDTH 13 | ||
37 | #define PWM_SCALE_SHIFT 0 | ||
38 | |||
39 | #define NUM_PWM 4 | ||
40 | |||
41 | struct tegra_pwm_chip { | ||
42 | struct pwm_chip chip; | ||
43 | struct device *dev; | ||
44 | |||
45 | struct clk *clk; | ||
46 | |||
47 | void __iomem *mmio_base; | ||
48 | }; | ||
49 | |||
50 | static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip) | ||
51 | { | ||
52 | return container_of(chip, struct tegra_pwm_chip, chip); | ||
53 | } | ||
54 | |||
55 | static inline u32 pwm_readl(struct tegra_pwm_chip *chip, unsigned int num) | ||
56 | { | ||
57 | return readl(chip->mmio_base + (num << 4)); | ||
58 | } | ||
59 | |||
60 | static inline void pwm_writel(struct tegra_pwm_chip *chip, unsigned int num, | ||
61 | unsigned long val) | ||
62 | { | ||
63 | writel(val, chip->mmio_base + (num << 4)); | ||
64 | } | ||
65 | |||
66 | static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
67 | int duty_ns, int period_ns) | ||
68 | { | ||
69 | struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); | ||
70 | unsigned long long c; | ||
71 | unsigned long rate, hz; | ||
72 | u32 val = 0; | ||
73 | int err; | ||
74 | |||
75 | /* | ||
76 | * Convert from duty_ns / period_ns to a fixed number of duty ticks | ||
77 | * per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the | ||
78 | * nearest integer during division. | ||
79 | */ | ||
80 | c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1) + period_ns / 2; | ||
81 | do_div(c, period_ns); | ||
82 | |||
83 | val = (u32)c << PWM_DUTY_SHIFT; | ||
84 | |||
85 | /* | ||
86 | * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH) | ||
87 | * cycles at the PWM clock rate will take period_ns nanoseconds. | ||
88 | */ | ||
89 | rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH; | ||
90 | hz = 1000000000ul / period_ns; | ||
91 | |||
92 | rate = (rate + (hz / 2)) / hz; | ||
93 | |||
94 | /* | ||
95 | * Since the actual PWM divider is the register's frequency divider | ||
96 | * field minus 1, we need to decrement to get the correct value to | ||
97 | * write to the register. | ||
98 | */ | ||
99 | if (rate > 0) | ||
100 | rate--; | ||
101 | |||
102 | /* | ||
103 | * Make sure that the rate will fit in the register's frequency | ||
104 | * divider field. | ||
105 | */ | ||
106 | if (rate >> PWM_SCALE_WIDTH) | ||
107 | return -EINVAL; | ||
108 | |||
109 | val |= rate << PWM_SCALE_SHIFT; | ||
110 | |||
111 | /* | ||
112 | * If the PWM channel is disabled, make sure to turn on the clock | ||
113 | * before writing the register. Otherwise, keep it enabled. | ||
114 | */ | ||
115 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
116 | err = clk_prepare_enable(pc->clk); | ||
117 | if (err < 0) | ||
118 | return err; | ||
119 | } else | ||
120 | val |= PWM_ENABLE; | ||
121 | |||
122 | pwm_writel(pc, pwm->hwpwm, val); | ||
123 | |||
124 | /* | ||
125 | * If the PWM is not enabled, turn the clock off again to save power. | ||
126 | */ | ||
127 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) | ||
128 | clk_disable_unprepare(pc->clk); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
134 | { | ||
135 | struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); | ||
136 | int rc = 0; | ||
137 | u32 val; | ||
138 | |||
139 | rc = clk_prepare_enable(pc->clk); | ||
140 | if (rc < 0) | ||
141 | return rc; | ||
142 | |||
143 | val = pwm_readl(pc, pwm->hwpwm); | ||
144 | val |= PWM_ENABLE; | ||
145 | pwm_writel(pc, pwm->hwpwm, val); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
151 | { | ||
152 | struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); | ||
153 | u32 val; | ||
154 | |||
155 | val = pwm_readl(pc, pwm->hwpwm); | ||
156 | val &= ~PWM_ENABLE; | ||
157 | pwm_writel(pc, pwm->hwpwm, val); | ||
158 | |||
159 | clk_disable_unprepare(pc->clk); | ||
160 | } | ||
161 | |||
162 | static const struct pwm_ops tegra_pwm_ops = { | ||
163 | .config = tegra_pwm_config, | ||
164 | .enable = tegra_pwm_enable, | ||
165 | .disable = tegra_pwm_disable, | ||
166 | .owner = THIS_MODULE, | ||
167 | }; | ||
168 | |||
169 | static int tegra_pwm_probe(struct platform_device *pdev) | ||
170 | { | ||
171 | struct tegra_pwm_chip *pwm; | ||
172 | struct resource *r; | ||
173 | int ret; | ||
174 | |||
175 | pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); | ||
176 | if (!pwm) { | ||
177 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
178 | return -ENOMEM; | ||
179 | } | ||
180 | |||
181 | pwm->dev = &pdev->dev; | ||
182 | |||
183 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
184 | if (!r) { | ||
185 | dev_err(&pdev->dev, "no memory resources defined\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r); | ||
190 | if (!pwm->mmio_base) { | ||
191 | dev_err(&pdev->dev, "failed to ioremap() region\n"); | ||
192 | return -EADDRNOTAVAIL; | ||
193 | } | ||
194 | |||
195 | platform_set_drvdata(pdev, pwm); | ||
196 | |||
197 | pwm->clk = devm_clk_get(&pdev->dev, NULL); | ||
198 | if (IS_ERR(pwm->clk)) | ||
199 | return PTR_ERR(pwm->clk); | ||
200 | |||
201 | pwm->chip.dev = &pdev->dev; | ||
202 | pwm->chip.ops = &tegra_pwm_ops; | ||
203 | pwm->chip.base = -1; | ||
204 | pwm->chip.npwm = NUM_PWM; | ||
205 | |||
206 | ret = pwmchip_add(&pwm->chip); | ||
207 | if (ret < 0) { | ||
208 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int __devexit tegra_pwm_remove(struct platform_device *pdev) | ||
216 | { | ||
217 | struct tegra_pwm_chip *pc = platform_get_drvdata(pdev); | ||
218 | int i; | ||
219 | |||
220 | if (WARN_ON(!pc)) | ||
221 | return -ENODEV; | ||
222 | |||
223 | for (i = 0; i < NUM_PWM; i++) { | ||
224 | struct pwm_device *pwm = &pc->chip.pwms[i]; | ||
225 | |||
226 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) | ||
227 | if (clk_prepare_enable(pc->clk) < 0) | ||
228 | continue; | ||
229 | |||
230 | pwm_writel(pc, i, 0); | ||
231 | |||
232 | clk_disable_unprepare(pc->clk); | ||
233 | } | ||
234 | |||
235 | return pwmchip_remove(&pc->chip); | ||
236 | } | ||
237 | |||
238 | #ifdef CONFIG_OF | ||
239 | static struct of_device_id tegra_pwm_of_match[] = { | ||
240 | { .compatible = "nvidia,tegra20-pwm" }, | ||
241 | { .compatible = "nvidia,tegra30-pwm" }, | ||
242 | { } | ||
243 | }; | ||
244 | |||
245 | MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); | ||
246 | #endif | ||
247 | |||
248 | static struct platform_driver tegra_pwm_driver = { | ||
249 | .driver = { | ||
250 | .name = "tegra-pwm", | ||
251 | .of_match_table = of_match_ptr(tegra_pwm_of_match), | ||
252 | }, | ||
253 | .probe = tegra_pwm_probe, | ||
254 | .remove = __devexit_p(tegra_pwm_remove), | ||
255 | }; | ||
256 | |||
257 | module_platform_driver(tegra_pwm_driver); | ||
258 | |||
259 | MODULE_LICENSE("GPL"); | ||
260 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
261 | MODULE_ALIAS("platform:tegra-pwm"); | ||
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c new file mode 100644 index 000000000000..3c2ad284ee3e --- /dev/null +++ b/drivers/pwm/pwm-tiecap.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * ECAP PWM driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/pwm.h> | ||
28 | |||
29 | /* ECAP registers and bits definitions */ | ||
30 | #define CAP1 0x08 | ||
31 | #define CAP2 0x0C | ||
32 | #define CAP3 0x10 | ||
33 | #define CAP4 0x14 | ||
34 | #define ECCTL2 0x2A | ||
35 | #define ECCTL2_APWM_MODE BIT(9) | ||
36 | #define ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) | ||
37 | #define ECCTL2_TSCTR_FREERUN BIT(4) | ||
38 | |||
39 | struct ecap_pwm_chip { | ||
40 | struct pwm_chip chip; | ||
41 | unsigned int clk_rate; | ||
42 | void __iomem *mmio_base; | ||
43 | }; | ||
44 | |||
45 | static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip) | ||
46 | { | ||
47 | return container_of(chip, struct ecap_pwm_chip, chip); | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * period_ns = 10^9 * period_cycles / PWM_CLK_RATE | ||
52 | * duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE | ||
53 | */ | ||
54 | static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
55 | int duty_ns, int period_ns) | ||
56 | { | ||
57 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); | ||
58 | unsigned long long c; | ||
59 | unsigned long period_cycles, duty_cycles; | ||
60 | unsigned int reg_val; | ||
61 | |||
62 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) | ||
63 | return -ERANGE; | ||
64 | |||
65 | c = pc->clk_rate; | ||
66 | c = c * period_ns; | ||
67 | do_div(c, NSEC_PER_SEC); | ||
68 | period_cycles = (unsigned long)c; | ||
69 | |||
70 | if (period_cycles < 1) { | ||
71 | period_cycles = 1; | ||
72 | duty_cycles = 1; | ||
73 | } else { | ||
74 | c = pc->clk_rate; | ||
75 | c = c * duty_ns; | ||
76 | do_div(c, NSEC_PER_SEC); | ||
77 | duty_cycles = (unsigned long)c; | ||
78 | } | ||
79 | |||
80 | pm_runtime_get_sync(pc->chip.dev); | ||
81 | |||
82 | reg_val = readw(pc->mmio_base + ECCTL2); | ||
83 | |||
84 | /* Configure APWM mode & disable sync option */ | ||
85 | reg_val |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA; | ||
86 | |||
87 | writew(reg_val, pc->mmio_base + ECCTL2); | ||
88 | |||
89 | if (!test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
90 | /* Update active registers if not running */ | ||
91 | writel(duty_cycles, pc->mmio_base + CAP2); | ||
92 | writel(period_cycles, pc->mmio_base + CAP1); | ||
93 | } else { | ||
94 | /* | ||
95 | * Update shadow registers to configure period and | ||
96 | * compare values. This helps current PWM period to | ||
97 | * complete on reconfiguring | ||
98 | */ | ||
99 | writel(duty_cycles, pc->mmio_base + CAP4); | ||
100 | writel(period_cycles, pc->mmio_base + CAP3); | ||
101 | } | ||
102 | |||
103 | pm_runtime_put_sync(pc->chip.dev); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
108 | { | ||
109 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); | ||
110 | unsigned int reg_val; | ||
111 | |||
112 | /* Leave clock enabled on enabling PWM */ | ||
113 | pm_runtime_get_sync(pc->chip.dev); | ||
114 | |||
115 | /* | ||
116 | * Enable 'Free run Time stamp counter mode' to start counter | ||
117 | * and 'APWM mode' to enable APWM output | ||
118 | */ | ||
119 | reg_val = readw(pc->mmio_base + ECCTL2); | ||
120 | reg_val |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE; | ||
121 | writew(reg_val, pc->mmio_base + ECCTL2); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
126 | { | ||
127 | struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip); | ||
128 | unsigned int reg_val; | ||
129 | |||
130 | /* | ||
131 | * Disable 'Free run Time stamp counter mode' to stop counter | ||
132 | * and 'APWM mode' to put APWM output to low | ||
133 | */ | ||
134 | reg_val = readw(pc->mmio_base + ECCTL2); | ||
135 | reg_val &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE); | ||
136 | writew(reg_val, pc->mmio_base + ECCTL2); | ||
137 | |||
138 | /* Disable clock on PWM disable */ | ||
139 | pm_runtime_put_sync(pc->chip.dev); | ||
140 | } | ||
141 | |||
142 | static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
143 | { | ||
144 | if (test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
145 | dev_warn(chip->dev, "Removing PWM device without disabling\n"); | ||
146 | pm_runtime_put_sync(chip->dev); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static const struct pwm_ops ecap_pwm_ops = { | ||
151 | .free = ecap_pwm_free, | ||
152 | .config = ecap_pwm_config, | ||
153 | .enable = ecap_pwm_enable, | ||
154 | .disable = ecap_pwm_disable, | ||
155 | .owner = THIS_MODULE, | ||
156 | }; | ||
157 | |||
158 | static int __devinit ecap_pwm_probe(struct platform_device *pdev) | ||
159 | { | ||
160 | int ret; | ||
161 | struct resource *r; | ||
162 | struct clk *clk; | ||
163 | struct ecap_pwm_chip *pc; | ||
164 | |||
165 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); | ||
166 | if (!pc) { | ||
167 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
168 | return -ENOMEM; | ||
169 | } | ||
170 | |||
171 | clk = devm_clk_get(&pdev->dev, "fck"); | ||
172 | if (IS_ERR(clk)) { | ||
173 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
174 | return PTR_ERR(clk); | ||
175 | } | ||
176 | |||
177 | pc->clk_rate = clk_get_rate(clk); | ||
178 | if (!pc->clk_rate) { | ||
179 | dev_err(&pdev->dev, "failed to get clock rate\n"); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | pc->chip.dev = &pdev->dev; | ||
184 | pc->chip.ops = &ecap_pwm_ops; | ||
185 | pc->chip.base = -1; | ||
186 | pc->chip.npwm = 1; | ||
187 | |||
188 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
189 | if (!r) { | ||
190 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
191 | return -ENODEV; | ||
192 | } | ||
193 | |||
194 | pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r); | ||
195 | if (!pc->mmio_base) { | ||
196 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | ||
197 | return -EADDRNOTAVAIL; | ||
198 | } | ||
199 | |||
200 | ret = pwmchip_add(&pc->chip); | ||
201 | if (ret < 0) { | ||
202 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | pm_runtime_enable(&pdev->dev); | ||
207 | platform_set_drvdata(pdev, pc); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int __devexit ecap_pwm_remove(struct platform_device *pdev) | ||
212 | { | ||
213 | struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); | ||
214 | |||
215 | pm_runtime_put_sync(&pdev->dev); | ||
216 | pm_runtime_disable(&pdev->dev); | ||
217 | return pwmchip_remove(&pc->chip); | ||
218 | } | ||
219 | |||
220 | static struct platform_driver ecap_pwm_driver = { | ||
221 | .driver = { | ||
222 | .name = "ecap", | ||
223 | }, | ||
224 | .probe = ecap_pwm_probe, | ||
225 | .remove = __devexit_p(ecap_pwm_remove), | ||
226 | }; | ||
227 | |||
228 | module_platform_driver(ecap_pwm_driver); | ||
229 | |||
230 | MODULE_DESCRIPTION("ECAP PWM driver"); | ||
231 | MODULE_AUTHOR("Texas Instruments"); | ||
232 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c new file mode 100644 index 000000000000..010d232cb0c8 --- /dev/null +++ b/drivers/pwm/pwm-tiehrpwm.c | |||
@@ -0,0 +1,411 @@ | |||
1 | /* | ||
2 | * EHRPWM PWM driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pwm.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/pm_runtime.h> | ||
28 | |||
29 | /* EHRPWM registers and bits definitions */ | ||
30 | |||
31 | /* Time base module registers */ | ||
32 | #define TBCTL 0x00 | ||
33 | #define TBPRD 0x0A | ||
34 | |||
35 | #define TBCTL_RUN_MASK (BIT(15) | BIT(14)) | ||
36 | #define TBCTL_STOP_NEXT 0 | ||
37 | #define TBCTL_STOP_ON_CYCLE BIT(14) | ||
38 | #define TBCTL_FREE_RUN (BIT(15) | BIT(14)) | ||
39 | #define TBCTL_PRDLD_MASK BIT(3) | ||
40 | #define TBCTL_PRDLD_SHDW 0 | ||
41 | #define TBCTL_PRDLD_IMDT BIT(3) | ||
42 | #define TBCTL_CLKDIV_MASK (BIT(12) | BIT(11) | BIT(10) | BIT(9) | \ | ||
43 | BIT(8) | BIT(7)) | ||
44 | #define TBCTL_CTRMODE_MASK (BIT(1) | BIT(0)) | ||
45 | #define TBCTL_CTRMODE_UP 0 | ||
46 | #define TBCTL_CTRMODE_DOWN BIT(0) | ||
47 | #define TBCTL_CTRMODE_UPDOWN BIT(1) | ||
48 | #define TBCTL_CTRMODE_FREEZE (BIT(1) | BIT(0)) | ||
49 | |||
50 | #define TBCTL_HSPCLKDIV_SHIFT 7 | ||
51 | #define TBCTL_CLKDIV_SHIFT 10 | ||
52 | |||
53 | #define CLKDIV_MAX 7 | ||
54 | #define HSPCLKDIV_MAX 7 | ||
55 | #define PERIOD_MAX 0xFFFF | ||
56 | |||
57 | /* compare module registers */ | ||
58 | #define CMPA 0x12 | ||
59 | #define CMPB 0x14 | ||
60 | |||
61 | /* Action qualifier module registers */ | ||
62 | #define AQCTLA 0x16 | ||
63 | #define AQCTLB 0x18 | ||
64 | #define AQSFRC 0x1A | ||
65 | #define AQCSFRC 0x1C | ||
66 | |||
67 | #define AQCTL_CBU_MASK (BIT(9) | BIT(8)) | ||
68 | #define AQCTL_CBU_FRCLOW BIT(8) | ||
69 | #define AQCTL_CBU_FRCHIGH BIT(9) | ||
70 | #define AQCTL_CBU_FRCTOGGLE (BIT(9) | BIT(8)) | ||
71 | #define AQCTL_CAU_MASK (BIT(5) | BIT(4)) | ||
72 | #define AQCTL_CAU_FRCLOW BIT(4) | ||
73 | #define AQCTL_CAU_FRCHIGH BIT(5) | ||
74 | #define AQCTL_CAU_FRCTOGGLE (BIT(5) | BIT(4)) | ||
75 | #define AQCTL_PRD_MASK (BIT(3) | BIT(2)) | ||
76 | #define AQCTL_PRD_FRCLOW BIT(2) | ||
77 | #define AQCTL_PRD_FRCHIGH BIT(3) | ||
78 | #define AQCTL_PRD_FRCTOGGLE (BIT(3) | BIT(2)) | ||
79 | #define AQCTL_ZRO_MASK (BIT(1) | BIT(0)) | ||
80 | #define AQCTL_ZRO_FRCLOW BIT(0) | ||
81 | #define AQCTL_ZRO_FRCHIGH BIT(1) | ||
82 | #define AQCTL_ZRO_FRCTOGGLE (BIT(1) | BIT(0)) | ||
83 | |||
84 | #define AQSFRC_RLDCSF_MASK (BIT(7) | BIT(6)) | ||
85 | #define AQSFRC_RLDCSF_ZRO 0 | ||
86 | #define AQSFRC_RLDCSF_PRD BIT(6) | ||
87 | #define AQSFRC_RLDCSF_ZROPRD BIT(7) | ||
88 | #define AQSFRC_RLDCSF_IMDT (BIT(7) | BIT(6)) | ||
89 | |||
90 | #define AQCSFRC_CSFB_MASK (BIT(3) | BIT(2)) | ||
91 | #define AQCSFRC_CSFB_FRCDIS 0 | ||
92 | #define AQCSFRC_CSFB_FRCLOW BIT(2) | ||
93 | #define AQCSFRC_CSFB_FRCHIGH BIT(3) | ||
94 | #define AQCSFRC_CSFB_DISSWFRC (BIT(3) | BIT(2)) | ||
95 | #define AQCSFRC_CSFA_MASK (BIT(1) | BIT(0)) | ||
96 | #define AQCSFRC_CSFA_FRCDIS 0 | ||
97 | #define AQCSFRC_CSFA_FRCLOW BIT(0) | ||
98 | #define AQCSFRC_CSFA_FRCHIGH BIT(1) | ||
99 | #define AQCSFRC_CSFA_DISSWFRC (BIT(1) | BIT(0)) | ||
100 | |||
101 | #define NUM_PWM_CHANNEL 2 /* EHRPWM channels */ | ||
102 | |||
103 | struct ehrpwm_pwm_chip { | ||
104 | struct pwm_chip chip; | ||
105 | unsigned int clk_rate; | ||
106 | void __iomem *mmio_base; | ||
107 | }; | ||
108 | |||
109 | static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) | ||
110 | { | ||
111 | return container_of(chip, struct ehrpwm_pwm_chip, chip); | ||
112 | } | ||
113 | |||
114 | static void ehrpwm_write(void *base, int offset, unsigned int val) | ||
115 | { | ||
116 | writew(val & 0xFFFF, base + offset); | ||
117 | } | ||
118 | |||
119 | static void ehrpwm_modify(void *base, int offset, | ||
120 | unsigned short mask, unsigned short val) | ||
121 | { | ||
122 | unsigned short regval; | ||
123 | |||
124 | regval = readw(base + offset); | ||
125 | regval &= ~mask; | ||
126 | regval |= val & mask; | ||
127 | writew(regval, base + offset); | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * set_prescale_div - Set up the prescaler divider function | ||
132 | * @rqst_prescaler: prescaler value min | ||
133 | * @prescale_div: prescaler value set | ||
134 | * @tb_clk_div: Time Base Control prescaler bits | ||
135 | */ | ||
136 | static int set_prescale_div(unsigned long rqst_prescaler, | ||
137 | unsigned short *prescale_div, unsigned short *tb_clk_div) | ||
138 | { | ||
139 | unsigned int clkdiv, hspclkdiv; | ||
140 | |||
141 | for (clkdiv = 0; clkdiv <= CLKDIV_MAX; clkdiv++) { | ||
142 | for (hspclkdiv = 0; hspclkdiv <= HSPCLKDIV_MAX; hspclkdiv++) { | ||
143 | |||
144 | /* | ||
145 | * calculations for prescaler value : | ||
146 | * prescale_div = HSPCLKDIVIDER * CLKDIVIDER. | ||
147 | * HSPCLKDIVIDER = 2 ** hspclkdiv | ||
148 | * CLKDIVIDER = (1), if clkdiv == 0 *OR* | ||
149 | * (2 * clkdiv), if clkdiv != 0 | ||
150 | * | ||
151 | * Configure prescale_div value such that period | ||
152 | * register value is less than 65535. | ||
153 | */ | ||
154 | |||
155 | *prescale_div = (1 << clkdiv) * | ||
156 | (hspclkdiv ? (hspclkdiv * 2) : 1); | ||
157 | if (*prescale_div > rqst_prescaler) { | ||
158 | *tb_clk_div = (clkdiv << TBCTL_CLKDIV_SHIFT) | | ||
159 | (hspclkdiv << TBCTL_HSPCLKDIV_SHIFT); | ||
160 | return 0; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan, | ||
168 | unsigned long duty_cycles) | ||
169 | { | ||
170 | int cmp_reg, aqctl_reg; | ||
171 | unsigned short aqctl_val, aqctl_mask; | ||
172 | |||
173 | /* | ||
174 | * Channels can be configured from action qualifier module. | ||
175 | * Channel 0 configured with compare A register and for | ||
176 | * up-counter mode. | ||
177 | * Channel 1 configured with compare B register and for | ||
178 | * up-counter mode. | ||
179 | */ | ||
180 | if (chan == 1) { | ||
181 | aqctl_reg = AQCTLB; | ||
182 | cmp_reg = CMPB; | ||
183 | /* Configure PWM Low from compare B value */ | ||
184 | aqctl_val = AQCTL_CBU_FRCLOW; | ||
185 | aqctl_mask = AQCTL_CBU_MASK; | ||
186 | } else { | ||
187 | cmp_reg = CMPA; | ||
188 | aqctl_reg = AQCTLA; | ||
189 | /* Configure PWM Low from compare A value*/ | ||
190 | aqctl_val = AQCTL_CAU_FRCLOW; | ||
191 | aqctl_mask = AQCTL_CAU_MASK; | ||
192 | } | ||
193 | |||
194 | /* Configure PWM High from period value and zero value */ | ||
195 | aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH; | ||
196 | aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK; | ||
197 | ehrpwm_modify(pc->mmio_base, aqctl_reg, aqctl_mask, aqctl_val); | ||
198 | |||
199 | ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE | ||
204 | * duty_ns = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE | ||
205 | */ | ||
206 | static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
207 | int duty_ns, int period_ns) | ||
208 | { | ||
209 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | ||
210 | unsigned long long c; | ||
211 | unsigned long period_cycles, duty_cycles; | ||
212 | unsigned short ps_divval, tb_divval; | ||
213 | |||
214 | if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC) | ||
215 | return -ERANGE; | ||
216 | |||
217 | c = pc->clk_rate; | ||
218 | c = c * period_ns; | ||
219 | do_div(c, NSEC_PER_SEC); | ||
220 | period_cycles = (unsigned long)c; | ||
221 | |||
222 | if (period_cycles < 1) { | ||
223 | period_cycles = 1; | ||
224 | duty_cycles = 1; | ||
225 | } else { | ||
226 | c = pc->clk_rate; | ||
227 | c = c * duty_ns; | ||
228 | do_div(c, NSEC_PER_SEC); | ||
229 | duty_cycles = (unsigned long)c; | ||
230 | } | ||
231 | |||
232 | /* Configure clock prescaler to support Low frequency PWM wave */ | ||
233 | if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval, | ||
234 | &tb_divval)) { | ||
235 | dev_err(chip->dev, "Unsupported values\n"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | pm_runtime_get_sync(chip->dev); | ||
240 | |||
241 | /* Update clock prescaler values */ | ||
242 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval); | ||
243 | |||
244 | /* Update period & duty cycle with presacler division */ | ||
245 | period_cycles = period_cycles / ps_divval; | ||
246 | duty_cycles = duty_cycles / ps_divval; | ||
247 | |||
248 | /* Configure shadow loading on Period register */ | ||
249 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_PRDLD_MASK, TBCTL_PRDLD_SHDW); | ||
250 | |||
251 | ehrpwm_write(pc->mmio_base, TBPRD, period_cycles); | ||
252 | |||
253 | /* Configure ehrpwm counter for up-count mode */ | ||
254 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK, | ||
255 | TBCTL_CTRMODE_UP); | ||
256 | |||
257 | /* Configure the channel for duty cycle */ | ||
258 | configure_chans(pc, pwm->hwpwm, duty_cycles); | ||
259 | pm_runtime_put_sync(chip->dev); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
264 | { | ||
265 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | ||
266 | unsigned short aqcsfrc_val, aqcsfrc_mask; | ||
267 | |||
268 | /* Leave clock enabled on enabling PWM */ | ||
269 | pm_runtime_get_sync(chip->dev); | ||
270 | |||
271 | /* Disabling Action Qualifier on PWM output */ | ||
272 | if (pwm->hwpwm) { | ||
273 | aqcsfrc_val = AQCSFRC_CSFB_FRCDIS; | ||
274 | aqcsfrc_mask = AQCSFRC_CSFB_MASK; | ||
275 | } else { | ||
276 | aqcsfrc_val = AQCSFRC_CSFA_FRCDIS; | ||
277 | aqcsfrc_mask = AQCSFRC_CSFA_MASK; | ||
278 | } | ||
279 | |||
280 | /* Changes to shadow mode */ | ||
281 | ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK, | ||
282 | AQSFRC_RLDCSF_ZRO); | ||
283 | |||
284 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); | ||
285 | |||
286 | /* Enable time counter for free_run */ | ||
287 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
292 | { | ||
293 | struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); | ||
294 | unsigned short aqcsfrc_val, aqcsfrc_mask; | ||
295 | |||
296 | /* Action Qualifier puts PWM output low forcefully */ | ||
297 | if (pwm->hwpwm) { | ||
298 | aqcsfrc_val = AQCSFRC_CSFB_FRCLOW; | ||
299 | aqcsfrc_mask = AQCSFRC_CSFB_MASK; | ||
300 | } else { | ||
301 | aqcsfrc_val = AQCSFRC_CSFA_FRCLOW; | ||
302 | aqcsfrc_mask = AQCSFRC_CSFA_MASK; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Changes to immediate action on Action Qualifier. This puts | ||
307 | * Action Qualifier control on PWM output from next TBCLK | ||
308 | */ | ||
309 | ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK, | ||
310 | AQSFRC_RLDCSF_IMDT); | ||
311 | |||
312 | ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); | ||
313 | |||
314 | /* Stop Time base counter */ | ||
315 | ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); | ||
316 | |||
317 | /* Disable clock on PWM disable */ | ||
318 | pm_runtime_put_sync(chip->dev); | ||
319 | } | ||
320 | |||
321 | static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
322 | { | ||
323 | if (test_bit(PWMF_ENABLED, &pwm->flags)) { | ||
324 | dev_warn(chip->dev, "Removing PWM device without disabling\n"); | ||
325 | pm_runtime_put_sync(chip->dev); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | static const struct pwm_ops ehrpwm_pwm_ops = { | ||
330 | .free = ehrpwm_pwm_free, | ||
331 | .config = ehrpwm_pwm_config, | ||
332 | .enable = ehrpwm_pwm_enable, | ||
333 | .disable = ehrpwm_pwm_disable, | ||
334 | .owner = THIS_MODULE, | ||
335 | }; | ||
336 | |||
337 | static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) | ||
338 | { | ||
339 | int ret; | ||
340 | struct resource *r; | ||
341 | struct clk *clk; | ||
342 | struct ehrpwm_pwm_chip *pc; | ||
343 | |||
344 | pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); | ||
345 | if (!pc) { | ||
346 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
347 | return -ENOMEM; | ||
348 | } | ||
349 | |||
350 | clk = devm_clk_get(&pdev->dev, "fck"); | ||
351 | if (IS_ERR(clk)) { | ||
352 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
353 | return PTR_ERR(clk); | ||
354 | } | ||
355 | |||
356 | pc->clk_rate = clk_get_rate(clk); | ||
357 | if (!pc->clk_rate) { | ||
358 | dev_err(&pdev->dev, "failed to get clock rate\n"); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | |||
362 | pc->chip.dev = &pdev->dev; | ||
363 | pc->chip.ops = &ehrpwm_pwm_ops; | ||
364 | pc->chip.base = -1; | ||
365 | pc->chip.npwm = NUM_PWM_CHANNEL; | ||
366 | |||
367 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
368 | if (!r) { | ||
369 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
370 | return -ENODEV; | ||
371 | } | ||
372 | |||
373 | pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r); | ||
374 | if (!pc->mmio_base) { | ||
375 | dev_err(&pdev->dev, "failed to ioremap() registers\n"); | ||
376 | return -EADDRNOTAVAIL; | ||
377 | } | ||
378 | |||
379 | ret = pwmchip_add(&pc->chip); | ||
380 | if (ret < 0) { | ||
381 | dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | pm_runtime_enable(&pdev->dev); | ||
386 | platform_set_drvdata(pdev, pc); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev) | ||
391 | { | ||
392 | struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); | ||
393 | |||
394 | pm_runtime_put_sync(&pdev->dev); | ||
395 | pm_runtime_disable(&pdev->dev); | ||
396 | return pwmchip_remove(&pc->chip); | ||
397 | } | ||
398 | |||
399 | static struct platform_driver ehrpwm_pwm_driver = { | ||
400 | .driver = { | ||
401 | .name = "ehrpwm", | ||
402 | }, | ||
403 | .probe = ehrpwm_pwm_probe, | ||
404 | .remove = __devexit_p(ehrpwm_pwm_remove), | ||
405 | }; | ||
406 | |||
407 | module_platform_driver(ehrpwm_pwm_driver); | ||
408 | |||
409 | MODULE_DESCRIPTION("EHRPWM PWM driver"); | ||
410 | MODULE_AUTHOR("Texas Instruments"); | ||
411 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c new file mode 100644 index 000000000000..548021439f0c --- /dev/null +++ b/drivers/pwm/pwm-vt8500.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * drivers/pwm/pwm-vt8500.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/pwm.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <asm/div64.h> | ||
26 | |||
27 | #define VT8500_NR_PWMS 4 | ||
28 | |||
29 | struct vt8500_chip { | ||
30 | struct pwm_chip chip; | ||
31 | void __iomem *base; | ||
32 | }; | ||
33 | |||
34 | #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) | ||
35 | |||
36 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | ||
37 | static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) | ||
38 | { | ||
39 | int loops = msecs_to_loops(10); | ||
40 | while ((readb(reg) & bitmask) && --loops) | ||
41 | cpu_relax(); | ||
42 | |||
43 | if (unlikely(!loops)) | ||
44 | pr_warning("Waiting for status bits 0x%x to clear timed out\n", | ||
45 | bitmask); | ||
46 | } | ||
47 | |||
48 | static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
49 | int duty_ns, int period_ns) | ||
50 | { | ||
51 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | ||
52 | unsigned long long c; | ||
53 | unsigned long period_cycles, prescale, pv, dc; | ||
54 | |||
55 | c = 25000000/2; /* wild guess --- need to implement clocks */ | ||
56 | c = c * period_ns; | ||
57 | do_div(c, 1000000000); | ||
58 | period_cycles = c; | ||
59 | |||
60 | if (period_cycles < 1) | ||
61 | period_cycles = 1; | ||
62 | prescale = (period_cycles - 1) / 4096; | ||
63 | pv = period_cycles / (prescale + 1) - 1; | ||
64 | if (pv > 4095) | ||
65 | pv = 4095; | ||
66 | |||
67 | if (prescale > 1023) | ||
68 | return -EINVAL; | ||
69 | |||
70 | c = (unsigned long long)pv * duty_ns; | ||
71 | do_div(c, period_ns); | ||
72 | dc = c; | ||
73 | |||
74 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 1)); | ||
75 | writel(prescale, vt8500->base + 0x4 + (pwm->hwpwm << 4)); | ||
76 | |||
77 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2)); | ||
78 | writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4)); | ||
79 | |||
80 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); | ||
81 | writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
87 | { | ||
88 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | ||
89 | |||
90 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); | ||
91 | writel(5, vt8500->base + (pwm->hwpwm << 4)); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
96 | { | ||
97 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | ||
98 | |||
99 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); | ||
100 | writel(0, vt8500->base + (pwm->hwpwm << 4)); | ||
101 | } | ||
102 | |||
103 | static struct pwm_ops vt8500_pwm_ops = { | ||
104 | .enable = vt8500_pwm_enable, | ||
105 | .disable = vt8500_pwm_disable, | ||
106 | .config = vt8500_pwm_config, | ||
107 | .owner = THIS_MODULE, | ||
108 | }; | ||
109 | |||
110 | static int __devinit pwm_probe(struct platform_device *pdev) | ||
111 | { | ||
112 | struct vt8500_chip *chip; | ||
113 | struct resource *r; | ||
114 | int ret; | ||
115 | |||
116 | chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); | ||
117 | if (chip == NULL) { | ||
118 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
119 | return -ENOMEM; | ||
120 | } | ||
121 | |||
122 | chip->chip.dev = &pdev->dev; | ||
123 | chip->chip.ops = &vt8500_pwm_ops; | ||
124 | chip->chip.base = -1; | ||
125 | chip->chip.npwm = VT8500_NR_PWMS; | ||
126 | |||
127 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
128 | if (r == NULL) { | ||
129 | dev_err(&pdev->dev, "no memory resource defined\n"); | ||
130 | return -ENODEV; | ||
131 | } | ||
132 | |||
133 | chip->base = devm_request_and_ioremap(&pdev->dev, r); | ||
134 | if (chip->base == NULL) | ||
135 | return -EADDRNOTAVAIL; | ||
136 | |||
137 | ret = pwmchip_add(&chip->chip); | ||
138 | if (ret < 0) | ||
139 | return ret; | ||
140 | |||
141 | platform_set_drvdata(pdev, chip); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static int __devexit pwm_remove(struct platform_device *pdev) | ||
146 | { | ||
147 | struct vt8500_chip *chip; | ||
148 | |||
149 | chip = platform_get_drvdata(pdev); | ||
150 | if (chip == NULL) | ||
151 | return -ENODEV; | ||
152 | |||
153 | return pwmchip_remove(&chip->chip); | ||
154 | } | ||
155 | |||
156 | static struct platform_driver pwm_driver = { | ||
157 | .driver = { | ||
158 | .name = "vt8500-pwm", | ||
159 | .owner = THIS_MODULE, | ||
160 | }, | ||
161 | .probe = pwm_probe, | ||
162 | .remove = __devexit_p(pwm_remove), | ||
163 | }; | ||
164 | |||
165 | static int __init pwm_init(void) | ||
166 | { | ||
167 | return platform_driver_register(&pwm_driver); | ||
168 | } | ||
169 | arch_initcall(pwm_init); | ||
170 | |||
171 | static void __exit pwm_exit(void) | ||
172 | { | ||
173 | platform_driver_unregister(&pwm_driver); | ||
174 | } | ||
175 | module_exit(pwm_exit); | ||
176 | |||
177 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 2979292650d6..cf282763a8dc 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -245,7 +245,7 @@ config BACKLIGHT_CARILLO_RANCH | |||
245 | 245 | ||
246 | config BACKLIGHT_PWM | 246 | config BACKLIGHT_PWM |
247 | tristate "Generic PWM based Backlight Driver" | 247 | tristate "Generic PWM based Backlight Driver" |
248 | depends on HAVE_PWM | 248 | depends on PWM |
249 | help | 249 | help |
250 | If you have a LCD backlight adjustable by PWM, say Y to enable | 250 | If you have a LCD backlight adjustable by PWM, say Y to enable |
251 | this driver. | 251 | this driver. |
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 342b7d7cbb63..995f0164c9b0 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c | |||
@@ -26,11 +26,13 @@ struct pwm_bl_data { | |||
26 | struct device *dev; | 26 | struct device *dev; |
27 | unsigned int period; | 27 | unsigned int period; |
28 | unsigned int lth_brightness; | 28 | unsigned int lth_brightness; |
29 | unsigned int *levels; | ||
29 | int (*notify)(struct device *, | 30 | int (*notify)(struct device *, |
30 | int brightness); | 31 | int brightness); |
31 | void (*notify_after)(struct device *, | 32 | void (*notify_after)(struct device *, |
32 | int brightness); | 33 | int brightness); |
33 | int (*check_fb)(struct device *, struct fb_info *); | 34 | int (*check_fb)(struct device *, struct fb_info *); |
35 | void (*exit)(struct device *); | ||
34 | }; | 36 | }; |
35 | 37 | ||
36 | static int pwm_backlight_update_status(struct backlight_device *bl) | 38 | static int pwm_backlight_update_status(struct backlight_device *bl) |
@@ -52,9 +54,18 @@ static int pwm_backlight_update_status(struct backlight_device *bl) | |||
52 | pwm_config(pb->pwm, 0, pb->period); | 54 | pwm_config(pb->pwm, 0, pb->period); |
53 | pwm_disable(pb->pwm); | 55 | pwm_disable(pb->pwm); |
54 | } else { | 56 | } else { |
55 | brightness = pb->lth_brightness + | 57 | int duty_cycle; |
56 | (brightness * (pb->period - pb->lth_brightness) / max); | 58 | |
57 | pwm_config(pb->pwm, brightness, pb->period); | 59 | if (pb->levels) { |
60 | duty_cycle = pb->levels[brightness]; | ||
61 | max = pb->levels[max]; | ||
62 | } else { | ||
63 | duty_cycle = brightness; | ||
64 | } | ||
65 | |||
66 | duty_cycle = pb->lth_brightness + | ||
67 | (duty_cycle * (pb->period - pb->lth_brightness) / max); | ||
68 | pwm_config(pb->pwm, duty_cycle, pb->period); | ||
58 | pwm_enable(pb->pwm); | 69 | pwm_enable(pb->pwm); |
59 | } | 70 | } |
60 | 71 | ||
@@ -83,17 +94,98 @@ static const struct backlight_ops pwm_backlight_ops = { | |||
83 | .check_fb = pwm_backlight_check_fb, | 94 | .check_fb = pwm_backlight_check_fb, |
84 | }; | 95 | }; |
85 | 96 | ||
97 | #ifdef CONFIG_OF | ||
98 | static int pwm_backlight_parse_dt(struct device *dev, | ||
99 | struct platform_pwm_backlight_data *data) | ||
100 | { | ||
101 | struct device_node *node = dev->of_node; | ||
102 | struct property *prop; | ||
103 | int length; | ||
104 | u32 value; | ||
105 | int ret; | ||
106 | |||
107 | if (!node) | ||
108 | return -ENODEV; | ||
109 | |||
110 | memset(data, 0, sizeof(*data)); | ||
111 | |||
112 | /* determine the number of brightness levels */ | ||
113 | prop = of_find_property(node, "brightness-levels", &length); | ||
114 | if (!prop) | ||
115 | return -EINVAL; | ||
116 | |||
117 | data->max_brightness = length / sizeof(u32); | ||
118 | |||
119 | /* read brightness levels from DT property */ | ||
120 | if (data->max_brightness > 0) { | ||
121 | size_t size = sizeof(*data->levels) * data->max_brightness; | ||
122 | |||
123 | data->levels = devm_kzalloc(dev, size, GFP_KERNEL); | ||
124 | if (!data->levels) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | ret = of_property_read_u32_array(node, "brightness-levels", | ||
128 | data->levels, | ||
129 | data->max_brightness); | ||
130 | if (ret < 0) | ||
131 | return ret; | ||
132 | |||
133 | ret = of_property_read_u32(node, "default-brightness-level", | ||
134 | &value); | ||
135 | if (ret < 0) | ||
136 | return ret; | ||
137 | |||
138 | if (value >= data->max_brightness) { | ||
139 | dev_warn(dev, "invalid default brightness level: %u, using %u\n", | ||
140 | value, data->max_brightness - 1); | ||
141 | value = data->max_brightness - 1; | ||
142 | } | ||
143 | |||
144 | data->dft_brightness = value; | ||
145 | data->max_brightness--; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * TODO: Most users of this driver use a number of GPIOs to control | ||
150 | * backlight power. Support for specifying these needs to be | ||
151 | * added. | ||
152 | */ | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct of_device_id pwm_backlight_of_match[] = { | ||
158 | { .compatible = "pwm-backlight" }, | ||
159 | { } | ||
160 | }; | ||
161 | |||
162 | MODULE_DEVICE_TABLE(of, pwm_backlight_of_match); | ||
163 | #else | ||
164 | static int pwm_backlight_parse_dt(struct device *dev, | ||
165 | struct platform_pwm_backlight_data *data) | ||
166 | { | ||
167 | return -ENODEV; | ||
168 | } | ||
169 | #endif | ||
170 | |||
86 | static int pwm_backlight_probe(struct platform_device *pdev) | 171 | static int pwm_backlight_probe(struct platform_device *pdev) |
87 | { | 172 | { |
88 | struct backlight_properties props; | ||
89 | struct platform_pwm_backlight_data *data = pdev->dev.platform_data; | 173 | struct platform_pwm_backlight_data *data = pdev->dev.platform_data; |
174 | struct platform_pwm_backlight_data defdata; | ||
175 | struct backlight_properties props; | ||
90 | struct backlight_device *bl; | 176 | struct backlight_device *bl; |
91 | struct pwm_bl_data *pb; | 177 | struct pwm_bl_data *pb; |
178 | unsigned int max; | ||
92 | int ret; | 179 | int ret; |
93 | 180 | ||
94 | if (!data) { | 181 | if (!data) { |
95 | dev_err(&pdev->dev, "failed to find platform data\n"); | 182 | ret = pwm_backlight_parse_dt(&pdev->dev, &defdata); |
96 | return -EINVAL; | 183 | if (ret < 0) { |
184 | dev_err(&pdev->dev, "failed to find platform data\n"); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | data = &defdata; | ||
97 | } | 189 | } |
98 | 190 | ||
99 | if (data->init) { | 191 | if (data->init) { |
@@ -109,21 +201,42 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
109 | goto err_alloc; | 201 | goto err_alloc; |
110 | } | 202 | } |
111 | 203 | ||
112 | pb->period = data->pwm_period_ns; | 204 | if (data->levels) { |
205 | max = data->levels[data->max_brightness]; | ||
206 | pb->levels = data->levels; | ||
207 | } else | ||
208 | max = data->max_brightness; | ||
209 | |||
113 | pb->notify = data->notify; | 210 | pb->notify = data->notify; |
114 | pb->notify_after = data->notify_after; | 211 | pb->notify_after = data->notify_after; |
115 | pb->check_fb = data->check_fb; | 212 | pb->check_fb = data->check_fb; |
116 | pb->lth_brightness = data->lth_brightness * | 213 | pb->exit = data->exit; |
117 | (data->pwm_period_ns / data->max_brightness); | ||
118 | pb->dev = &pdev->dev; | 214 | pb->dev = &pdev->dev; |
119 | 215 | ||
120 | pb->pwm = pwm_request(data->pwm_id, "backlight"); | 216 | pb->pwm = pwm_get(&pdev->dev, NULL); |
121 | if (IS_ERR(pb->pwm)) { | 217 | if (IS_ERR(pb->pwm)) { |
122 | dev_err(&pdev->dev, "unable to request PWM for backlight\n"); | 218 | dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); |
123 | ret = PTR_ERR(pb->pwm); | 219 | |
124 | goto err_alloc; | 220 | pb->pwm = pwm_request(data->pwm_id, "pwm-backlight"); |
125 | } else | 221 | if (IS_ERR(pb->pwm)) { |
126 | dev_dbg(&pdev->dev, "got pwm for backlight\n"); | 222 | dev_err(&pdev->dev, "unable to request legacy PWM\n"); |
223 | ret = PTR_ERR(pb->pwm); | ||
224 | goto err_alloc; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | dev_dbg(&pdev->dev, "got pwm for backlight\n"); | ||
229 | |||
230 | /* | ||
231 | * The DT case will set the pwm_period_ns field to 0 and store the | ||
232 | * period, parsed from the DT, in the PWM device. For the non-DT case, | ||
233 | * set the period from platform data. | ||
234 | */ | ||
235 | if (data->pwm_period_ns > 0) | ||
236 | pwm_set_period(pb->pwm, data->pwm_period_ns); | ||
237 | |||
238 | pb->period = pwm_get_period(pb->pwm); | ||
239 | pb->lth_brightness = data->lth_brightness * (pb->period / max); | ||
127 | 240 | ||
128 | memset(&props, 0, sizeof(struct backlight_properties)); | 241 | memset(&props, 0, sizeof(struct backlight_properties)); |
129 | props.type = BACKLIGHT_RAW; | 242 | props.type = BACKLIGHT_RAW; |
@@ -143,7 +256,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
143 | return 0; | 256 | return 0; |
144 | 257 | ||
145 | err_bl: | 258 | err_bl: |
146 | pwm_free(pb->pwm); | 259 | pwm_put(pb->pwm); |
147 | err_alloc: | 260 | err_alloc: |
148 | if (data->exit) | 261 | if (data->exit) |
149 | data->exit(&pdev->dev); | 262 | data->exit(&pdev->dev); |
@@ -152,16 +265,15 @@ err_alloc: | |||
152 | 265 | ||
153 | static int pwm_backlight_remove(struct platform_device *pdev) | 266 | static int pwm_backlight_remove(struct platform_device *pdev) |
154 | { | 267 | { |
155 | struct platform_pwm_backlight_data *data = pdev->dev.platform_data; | ||
156 | struct backlight_device *bl = platform_get_drvdata(pdev); | 268 | struct backlight_device *bl = platform_get_drvdata(pdev); |
157 | struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); | 269 | struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); |
158 | 270 | ||
159 | backlight_device_unregister(bl); | 271 | backlight_device_unregister(bl); |
160 | pwm_config(pb->pwm, 0, pb->period); | 272 | pwm_config(pb->pwm, 0, pb->period); |
161 | pwm_disable(pb->pwm); | 273 | pwm_disable(pb->pwm); |
162 | pwm_free(pb->pwm); | 274 | pwm_put(pb->pwm); |
163 | if (data->exit) | 275 | if (pb->exit) |
164 | data->exit(&pdev->dev); | 276 | pb->exit(&pdev->dev); |
165 | return 0; | 277 | return 0; |
166 | } | 278 | } |
167 | 279 | ||
@@ -195,11 +307,12 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend, | |||
195 | 307 | ||
196 | static struct platform_driver pwm_backlight_driver = { | 308 | static struct platform_driver pwm_backlight_driver = { |
197 | .driver = { | 309 | .driver = { |
198 | .name = "pwm-backlight", | 310 | .name = "pwm-backlight", |
199 | .owner = THIS_MODULE, | 311 | .owner = THIS_MODULE, |
200 | #ifdef CONFIG_PM | 312 | #ifdef CONFIG_PM |
201 | .pm = &pwm_backlight_pm_ops, | 313 | .pm = &pwm_backlight_pm_ops, |
202 | #endif | 314 | #endif |
315 | .of_match_table = of_match_ptr(pwm_backlight_of_match), | ||
203 | }, | 316 | }, |
204 | .probe = pwm_backlight_probe, | 317 | .probe = pwm_backlight_probe, |
205 | .remove = pwm_backlight_remove, | 318 | .remove = pwm_backlight_remove, |
diff --git a/include/linux/of.h b/include/linux/of.h index 0e9cf9eec085..42c2a58328c1 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -386,6 +386,13 @@ static inline int of_property_read_u64(const struct device_node *np, | |||
386 | return -ENOSYS; | 386 | return -ENOSYS; |
387 | } | 387 | } |
388 | 388 | ||
389 | static inline int of_property_match_string(struct device_node *np, | ||
390 | const char *propname, | ||
391 | const char *string) | ||
392 | { | ||
393 | return -ENOSYS; | ||
394 | } | ||
395 | |||
389 | static inline struct device_node *of_parse_phandle(struct device_node *np, | 396 | static inline struct device_node *of_parse_phandle(struct device_node *np, |
390 | const char *phandle_name, | 397 | const char *phandle_name, |
391 | int index) | 398 | int index) |
@@ -393,6 +400,15 @@ static inline struct device_node *of_parse_phandle(struct device_node *np, | |||
393 | return NULL; | 400 | return NULL; |
394 | } | 401 | } |
395 | 402 | ||
403 | static inline int of_parse_phandle_with_args(struct device_node *np, | ||
404 | const char *list_name, | ||
405 | const char *cells_name, | ||
406 | int index, | ||
407 | struct of_phandle_args *out_args) | ||
408 | { | ||
409 | return -ENOSYS; | ||
410 | } | ||
411 | |||
396 | static inline int of_alias_get_id(struct device_node *np, const char *stem) | 412 | static inline int of_alias_get_id(struct device_node *np, const char *stem) |
397 | { | 413 | { |
398 | return -ENOSYS; | 414 | return -ENOSYS; |
diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 7c775751392c..21d076c5089e 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h | |||
@@ -1,7 +1,10 @@ | |||
1 | #ifndef __LINUX_PWM_H | 1 | #ifndef __LINUX_PWM_H |
2 | #define __LINUX_PWM_H | 2 | #define __LINUX_PWM_H |
3 | 3 | ||
4 | #include <linux/of.h> | ||
5 | |||
4 | struct pwm_device; | 6 | struct pwm_device; |
7 | struct seq_file; | ||
5 | 8 | ||
6 | /* | 9 | /* |
7 | * pwm_request - request a PWM device | 10 | * pwm_request - request a PWM device |
@@ -28,4 +31,118 @@ int pwm_enable(struct pwm_device *pwm); | |||
28 | */ | 31 | */ |
29 | void pwm_disable(struct pwm_device *pwm); | 32 | void pwm_disable(struct pwm_device *pwm); |
30 | 33 | ||
34 | #ifdef CONFIG_PWM | ||
35 | struct pwm_chip; | ||
36 | |||
37 | enum { | ||
38 | PWMF_REQUESTED = 1 << 0, | ||
39 | PWMF_ENABLED = 1 << 1, | ||
40 | }; | ||
41 | |||
42 | struct pwm_device { | ||
43 | const char *label; | ||
44 | unsigned long flags; | ||
45 | unsigned int hwpwm; | ||
46 | unsigned int pwm; | ||
47 | struct pwm_chip *chip; | ||
48 | void *chip_data; | ||
49 | |||
50 | unsigned int period; /* in nanoseconds */ | ||
51 | }; | ||
52 | |||
53 | static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period) | ||
54 | { | ||
55 | if (pwm) | ||
56 | pwm->period = period; | ||
57 | } | ||
58 | |||
59 | static inline unsigned int pwm_get_period(struct pwm_device *pwm) | ||
60 | { | ||
61 | return pwm ? pwm->period : 0; | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * struct pwm_ops - PWM controller operations | ||
66 | * @request: optional hook for requesting a PWM | ||
67 | * @free: optional hook for freeing a PWM | ||
68 | * @config: configure duty cycles and period length for this PWM | ||
69 | * @enable: enable PWM output toggling | ||
70 | * @disable: disable PWM output toggling | ||
71 | * @dbg_show: optional routine to show contents in debugfs | ||
72 | * @owner: helps prevent removal of modules exporting active PWMs | ||
73 | */ | ||
74 | struct pwm_ops { | ||
75 | int (*request)(struct pwm_chip *chip, | ||
76 | struct pwm_device *pwm); | ||
77 | void (*free)(struct pwm_chip *chip, | ||
78 | struct pwm_device *pwm); | ||
79 | int (*config)(struct pwm_chip *chip, | ||
80 | struct pwm_device *pwm, | ||
81 | int duty_ns, int period_ns); | ||
82 | int (*enable)(struct pwm_chip *chip, | ||
83 | struct pwm_device *pwm); | ||
84 | void (*disable)(struct pwm_chip *chip, | ||
85 | struct pwm_device *pwm); | ||
86 | #ifdef CONFIG_DEBUG_FS | ||
87 | void (*dbg_show)(struct pwm_chip *chip, | ||
88 | struct seq_file *s); | ||
89 | #endif | ||
90 | struct module *owner; | ||
91 | }; | ||
92 | |||
93 | /** | ||
94 | * struct pwm_chip - abstract a PWM controller | ||
95 | * @dev: device providing the PWMs | ||
96 | * @list: list node for internal use | ||
97 | * @ops: callbacks for this PWM controller | ||
98 | * @base: number of first PWM controlled by this chip | ||
99 | * @npwm: number of PWMs controlled by this chip | ||
100 | * @pwms: array of PWM devices allocated by the framework | ||
101 | */ | ||
102 | struct pwm_chip { | ||
103 | struct device *dev; | ||
104 | struct list_head list; | ||
105 | const struct pwm_ops *ops; | ||
106 | int base; | ||
107 | unsigned int npwm; | ||
108 | |||
109 | struct pwm_device *pwms; | ||
110 | |||
111 | struct pwm_device * (*of_xlate)(struct pwm_chip *pc, | ||
112 | const struct of_phandle_args *args); | ||
113 | unsigned int of_pwm_n_cells; | ||
114 | }; | ||
115 | |||
116 | int pwm_set_chip_data(struct pwm_device *pwm, void *data); | ||
117 | void *pwm_get_chip_data(struct pwm_device *pwm); | ||
118 | |||
119 | int pwmchip_add(struct pwm_chip *chip); | ||
120 | int pwmchip_remove(struct pwm_chip *chip); | ||
121 | struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, | ||
122 | unsigned int index, | ||
123 | const char *label); | ||
124 | |||
125 | struct pwm_device *pwm_get(struct device *dev, const char *consumer); | ||
126 | void pwm_put(struct pwm_device *pwm); | ||
127 | |||
128 | struct pwm_lookup { | ||
129 | struct list_head list; | ||
130 | const char *provider; | ||
131 | unsigned int index; | ||
132 | const char *dev_id; | ||
133 | const char *con_id; | ||
134 | }; | ||
135 | |||
136 | #define PWM_LOOKUP(_provider, _index, _dev_id, _con_id) \ | ||
137 | { \ | ||
138 | .provider = _provider, \ | ||
139 | .index = _index, \ | ||
140 | .dev_id = _dev_id, \ | ||
141 | .con_id = _con_id, \ | ||
142 | } | ||
143 | |||
144 | void pwm_add_table(struct pwm_lookup *table, size_t num); | ||
145 | |||
146 | #endif | ||
147 | |||
31 | #endif /* __LINUX_PWM_H */ | 148 | #endif /* __LINUX_PWM_H */ |
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index 63d2df43e61a..56f4a866539a 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h | |||
@@ -12,6 +12,7 @@ struct platform_pwm_backlight_data { | |||
12 | unsigned int dft_brightness; | 12 | unsigned int dft_brightness; |
13 | unsigned int lth_brightness; | 13 | unsigned int lth_brightness; |
14 | unsigned int pwm_period_ns; | 14 | unsigned int pwm_period_ns; |
15 | unsigned int *levels; | ||
15 | int (*init)(struct device *dev); | 16 | int (*init)(struct device *dev); |
16 | int (*notify)(struct device *dev, int brightness); | 17 | int (*notify)(struct device *dev, int brightness); |
17 | void (*notify_after)(struct device *dev, int brightness); | 18 | void (*notify_after)(struct device *dev, int brightness); |