aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 12:22:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 12:22:37 -0400
commit9ec97169e7d6afe2f8206d694d1411fb3bb49853 (patch)
tree9d24c8cd440a312f96b70db5cdaaef1136787003
parenta410963ba4c0c768302f0298e258b1ee940e8316 (diff)
parent19891b20e7c275feb92d669f4b1879861f7e8c25 (diff)
Merge branch 'for-3.6' of git://gitorious.org/linux-pwm/linux-pwm
Pull PWM subsystem from Thierry Reding: "The new PWM subsystem aims at collecting all implementations of the legacy PWM API and to eventually replace it completely. The subsystem has been in development for over half a year now and many drivers have already been converted. It has been in linux-next for a couple of weeks and there have been no major issues so I think it is ready for inclusion in your tree." Arnd Bergmann <arnd@arndb.de>: "Very much Ack on the new subsystem. It uses the interface declarations as the previously separate pwm drivers, so nothing changes for now in the drivers using it, although it enables us to change those more easily in the future if we want to. This work is also one of the missing pieces that are required to eventually build ARM kernels for multiple platforms, which is currently prohibited (amongs other things) by the fact that you cannot have more than one driver exporting the pwm functions." Tested-and-acked-by: Alexandre Courbot <acourbot@nvidia.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Philip, Avinash <avinashphilip@ti.com> # TI's AM33xx platforms Acked-By: Alexandre Pereira da Silva <aletes.xgr@gmail.com> # LPC32XX Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Sachin Kamat <sachin.kamat@linaro.org> Fix up trivial conflicts with other cleanups and DT updates. * 'for-3.6' of git://gitorious.org/linux-pwm/linux-pwm: (36 commits) pwm: pwm-tiehrpwm: PWM driver support for EHRPWM pwm: pwm-tiecap: PWM driver support for ECAP APWM pwm: fix used-uninitialized warning in pwm_get() pwm: add lpc32xx PWM support pwm_backlight: pass correct brightness to callback pwm: Use pr_* functions in pwm-samsung.c file pwm: Convert pwm-samsung to use devm_* APIs pwm: Convert pwm-tegra to use devm_clk_get() pwm: pwm-mxs: Return proper error if pwmchip_remove() fails pwm: pwm-bfin: Return proper error if pwmchip_remove() fails pwm: pxa: Propagate pwmchip_remove() error pwm: Convert pwm-pxa to use devm_* APIs pwm: Convert pwm-vt8500 to use devm_* APIs pwm: Convert pwm-imx to use devm_* APIs pwm: Conflict with legacy PWM API pwm: pwm-mxs: add pinctrl support pwm: pwm-mxs: use devm_* managed functions pwm: pwm-mxs: use global reset function stmp_reset_block pwm: pwm-mxs: encode soc name in compatible string pwm: Take over maintainership of the PWM subsystem ...
-rw-r--r--Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt12
-rw-r--r--Documentation/devicetree/bindings/pwm/mxs-pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt18
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm.txt57
-rw-r--r--Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt28
-rw-r--r--Documentation/pwm.txt76
-rw-r--r--MAINTAINERS12
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi6
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi6
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra20.c3
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c3
-rw-r--r--arch/arm/mach-vt8500/Makefile2
-rw-r--r--arch/arm/mach-vt8500/pwm.c265
-rw-r--r--arch/arm/plat-mxc/Kconfig6
-rw-r--r--arch/arm/plat-mxc/Makefile1
-rw-r--r--arch/arm/plat-pxa/Makefile1
-rw-r--r--arch/arm/plat-pxa/pwm.c304
-rw-r--r--arch/arm/plat-samsung/Makefile4
-rw-r--r--arch/blackfin/Kconfig10
-rw-r--r--arch/blackfin/kernel/Makefile1
-rw-r--r--arch/blackfin/kernel/pwm.c100
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/pwm/Kconfig108
-rw-r--r--drivers/pwm/Makefile11
-rw-r--r--drivers/pwm/core.c713
-rw-r--r--drivers/pwm/pwm-bfin.c162
-rw-r--r--drivers/pwm/pwm-imx.c (renamed from arch/arm/plat-mxc/pwm.c)204
-rw-r--r--drivers/pwm/pwm-lpc32xx.c148
-rw-r--r--drivers/pwm/pwm-mxs.c203
-rw-r--r--drivers/pwm/pwm-pxa.c218
-rw-r--r--drivers/pwm/pwm-samsung.c (renamed from arch/arm/plat-samsung/pwm.c)234
-rw-r--r--drivers/pwm/pwm-tegra.c261
-rw-r--r--drivers/pwm/pwm-tiecap.c232
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c411
-rw-r--r--drivers/pwm/pwm-vt8500.c177
-rw-r--r--drivers/video/backlight/Kconfig2
-rw-r--r--drivers/video/backlight/pwm_bl.c159
-rw-r--r--include/linux/of.h16
-rw-r--r--include/linux/pwm.h117
-rw-r--r--include/linux/pwm_backlight.h1
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 @@
1LPC32XX PWM controller
2
3Required properties:
4- compatible: should be "nxp,lpc3220-pwm"
5- reg: physical base address and length of the controller's registers
6
7Examples:
8
9pwm@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 @@
1Freescale MXS PWM controller
2
3Required 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
10Example:
11
12pwm: 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 @@
1Tegra SoC PWFM controller
2
3Required 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
12Example:
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 @@
1Specifying PWM information for devices
2======================================
3
41) PWM user nodes
5-----------------
6
7PWM users should specify a list of PWM devices that they want to use
8with 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
16PWM properties should be named "pwms". The exact meaning of each pwms
17property must be documented in the device tree binding for each device.
18An optional property "pwm-names" may contain a list of strings to label
19each of the PWM devices listed in the "pwms" property. If no "pwm-names"
20property is given, the name of the user node will be used as fallback.
21
22Drivers 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
24pwm_get() call to an index into the list given by the "pwms" property.
25
26The following example could be used to describe a PWM-based backlight
27device:
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
40pwm-specifier typically encodes the chip-relative PWM number and the PWM
41period in nanoseconds. Note that in the example above, specifying the
42"pwm-names" is redundant because the name "backlight" would be used as
43fallback anyway.
44
452) PWM controller nodes
46-----------------------
47
48PWM controller nodes must specify the number of cells used for the
49specifier using the '#pwm-cells' property.
50
51An 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 @@
1pwm-backlight bindings
2
3Required 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
14Optional 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
20Example:
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 @@
1Pulse Width Modulation (PWM) interface
2
3This provides an overview about the Linux PWM interface
4
5PWMs are commonly used for controlling LEDs, fans or vibrators in
6cell phones. PWMs with a fixed purpose have no need implementing
7the Linux PWM API (although they could). However, PWMs are often
8found as discrete devices on SoCs which have no fixed purpose. It's
9up to the board designer to connect them to LEDs or fans. To provide
10this kind of flexibility the generic PWM API exists.
11
12Identifying PWMs
13----------------
14
15Users of the legacy PWM API use unique IDs to refer to PWM devices.
16
17Instead of referring to a PWM device via its unique ID, board setup code
18should instead register a static mapping that can be used to match PWM
19consumers 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
32Using PWMs
33----------
34
35Legacy users can request a PWM device using pwm_request() and free it
36after usage with pwm_free().
37
38New users should use the pwm_get() function and pass to it the consumer
39device or a consumer name. pwm_put() is used to free the PWM device.
40
41After being requested a PWM has to be configured using:
42
43int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
44
45To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
46
47Implementing a PWM driver
48-------------------------
49
50Currently there are two ways to implement pwm drivers. Traditionally
51there only has been the barebone API meaning that each driver has
52to implement the pwm_*() functions itself. This means that it's impossible
53to have multiple PWM drivers in the system. For this reason it's mandatory
54for new drivers to use the generic PWM framework.
55
56A new PWM controller/chip can be added using pwmchip_add() and removed
57again with pwmchip_remove(). pwmchip_add() takes a filled in struct
58pwm_chip as argument which provides a description of the PWM chip, the
59number of PWM devices provider by the chip and the chip-specific
60implementation of the supported PWM operations to the framework.
61
62Locking
63-------
64
65The PWM core list manipulations are protected by a mutex, so pwm_request()
66and pwm_free() may not be called from an atomic context. Currently the
67PWM core does not enforce any locking to pwm_enable(), pwm_disable() and
68pwm_config(), so the calling context is currently driver specific. This
69is an issue derived from the former barebone API and should be fixed soon.
70
71Helpers
72-------
73
74Currently a PWM can only be configured with period_ns and duty_ns. For several
75use cases freq_hz and duty_percent might be better. Instead of calculating
76this 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
5526F: Documentation/video4linux/README.pvrusb2 5526F: Documentation/video4linux/README.pvrusb2
5527F: drivers/media/video/pvrusb2/ 5527F: drivers/media/video/pvrusb2/
5528 5528
5529PWM SUBSYSTEM
5530M: Thierry Reding <thierry.reding@avionic-design.de>
5531L: linux-kernel@vger.kernel.org
5532S: Maintained
5533W: http://gitorious.org/linux-pwm
5534T: git git://gitorious.org/linux-pwm/linux-pwm.git
5535F: Documentation/pwm.txt
5536F: Documentation/devicetree/bindings/pwm/
5537F: include/linux/pwm.h
5538F: include/linux/of_pwm.h
5539F: drivers/pwm/
5540
5529PXA2xx/PXA3xx SUPPORT 5541PXA2xx/PXA3xx SUPPORT
5530M: Eric Miao <eric.y.miao@gmail.com> 5542M: Eric Miao <eric.y.miao@gmail.com>
5531M: Russell King <linux@arm.linux.org.uk> 5543M: 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
6obj-$(CONFIG_MACH_BV07) += bv07.o 6obj-$(CONFIG_MACH_BV07) += bv07.o
7obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o 7obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o
8
9obj-$(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
29static DEFINE_MUTEX(pwm_lock);
30static LIST_HEAD(pwm_list);
31
32struct 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)
45static 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
56int 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}
94EXPORT_SYMBOL(pwm_config);
95
96int 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}
102EXPORT_SYMBOL(pwm_enable);
103
104void 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}
109EXPORT_SYMBOL(pwm_disable);
110
111struct 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}
139EXPORT_SYMBOL(pwm_request);
140
141void 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}
154EXPORT_SYMBOL(pwm_free);
155
156static 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
163static 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
212err_free_mem:
213 release_mem_region(r->start, resource_size(r));
214err_free:
215 kfree(pwms);
216 return ret;
217}
218
219static 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
244static 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
253static int __init pwm_init(void)
254{
255 return platform_driver_register(&pwm_driver);
256}
257arch_initcall(pwm_init);
258
259static void __exit pwm_exit(void)
260{
261 platform_driver_unregister(&pwm_driver);
262}
263module_exit(pwm_exit);
264
265MODULE_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
47config MXC_AVIC 47config MXC_AVIC
48 bool 48 bool
49 49
50config MXC_PWM
51 tristate "Enable PWM driver"
52 select HAVE_PWM
53 help
54 Enable support for the i.MX PWM controller(s).
55
56config MXC_DEBUG_BOARD 50config 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
11obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o 11obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
12obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o 12obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
13obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o 13obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
14obj-$(CONFIG_MXC_PWM) += pwm.o
15obj-$(CONFIG_MXC_ULPI) += ulpi.o 14obj-$(CONFIG_MXC_ULPI) += ulpi.o
16obj-$(CONFIG_MXC_USE_EPIT) += epit.o 15obj-$(CONFIG_MXC_USE_EPIT) += epit.o
17obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o 16obj-$(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
8obj-$(CONFIG_PXA95x) += mfp.o 8obj-$(CONFIG_PXA95x) += mfp.o
9obj-$(CONFIG_ARCH_MMP) += mfp.o 9obj-$(CONFIG_ARCH_MMP) += mfp.o
10 10
11obj-$(CONFIG_HAVE_PWM) += pwm.o
12obj-$(CONFIG_PXA_SSP) += ssp.o 11obj-$(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
28static 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};
36MODULE_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
46struct 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 */
64int 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}
101EXPORT_SYMBOL(pwm_config);
102
103int 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}
114EXPORT_SYMBOL(pwm_enable);
115
116void pwm_disable(struct pwm_device *pwm)
117{
118 if (pwm->clk_enabled) {
119 clk_disable(pwm->clk);
120 pwm->clk_enabled = 0;
121 }
122}
123EXPORT_SYMBOL(pwm_disable);
124
125static DEFINE_MUTEX(pwm_lock);
126static LIST_HEAD(pwm_list);
127
128struct 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}
154EXPORT_SYMBOL(pwm_request);
155
156void 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}
168EXPORT_SYMBOL(pwm_free);
169
170static 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
177static 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
244err_free_mem:
245 release_mem_region(r->start, resource_size(r));
246err_free_clk:
247 clk_put(pwm->clk);
248err_free:
249 kfree(pwm);
250 return ret;
251}
252
253static 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
282static 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
292static int __init pwm_init(void)
293{
294 return platform_driver_register(&pwm_driver);
295}
296arch_initcall(pwm_init);
297
298static void __exit pwm_exit(void)
299{
300 platform_driver_unregister(&pwm_driver);
301}
302module_exit(pwm_exit);
303
304MODULE_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
60obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o 60obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o
61obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o 61obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o
62
63# PWM support
64
65obj-$(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
1005config 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
1015choice 1005choice
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
21obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o 21obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
22CFLAGS_REMOVE_ftrace.o = -pg 22CFLAGS_REMOVE_ftrace.o = -pg
23 23
24obj-$(CONFIG_HAVE_PWM) += pwm.o
25obj-$(CONFIG_IPIPE) += ipipe.o 24obj-$(CONFIG_IPIPE) += ipipe.o
26obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o 25obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o
27obj-$(CONFIG_CPLB_INFO) += cplbinfo.o 26obj-$(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
16struct pwm_device {
17 unsigned id;
18 unsigned short pin;
19};
20
21static 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
26struct 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}
53EXPORT_SYMBOL(pwm_request);
54
55void pwm_free(struct pwm_device *pwm)
56{
57 peripheral_free(pwm->pin);
58 kfree(pwm);
59}
60EXPORT_SYMBOL(pwm_free);
61
62int 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}
87EXPORT_SYMBOL(pwm_config);
88
89int pwm_enable(struct pwm_device *pwm)
90{
91 enable_gptimer(pwm->id);
92 return 0;
93}
94EXPORT_SYMBOL(pwm_enable);
95
96void pwm_disable(struct pwm_device *pwm)
97{
98 disable_gptimer(pwm->id);
99}
100EXPORT_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
149source "drivers/vme/Kconfig" 149source "drivers/vme/Kconfig"
150 150
151source "drivers/pwm/Kconfig"
152
151endmenu 153endmenu
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
9obj-y += pinctrl/ 9obj-y += pinctrl/
10obj-y += gpio/ 10obj-y += gpio/
11obj-y += pwm/
11obj-$(CONFIG_PCI) += pci/ 12obj-$(CONFIG_PCI) += pci/
12obj-$(CONFIG_PARISC) += parisc/ 13obj-$(CONFIG_PARISC) += parisc/
13obj-$(CONFIG_RAPIDIO) += rapidio/ 14obj-$(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 @@
1menuconfig 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
11if PWM
12
13config 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
22config 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
31config 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
41config 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
51config 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
60config 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
69config 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
79config 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
89config 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
99config 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
108endif
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 @@
1obj-$(CONFIG_PWM) += core.o
2obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
3obj-$(CONFIG_PWM_IMX) += pwm-imx.o
4obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
5obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
6obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
7obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
8obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
9obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
10obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
11obj-$(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
35static DEFINE_MUTEX(pwm_lookup_lock);
36static LIST_HEAD(pwm_lookup_list);
37static DEFINE_MUTEX(pwm_lock);
38static LIST_HEAD(pwm_chips);
39static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
40static RADIX_TREE(pwm_tree, GFP_KERNEL);
41
42static struct pwm_device *pwm_to_device(unsigned int pwm)
43{
44 return radix_tree_lookup(&pwm_tree, pwm);
45}
46
47static 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
70static 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
85static 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
108static 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
132static 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
152void 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
165void 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 */
176int 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 */
190void *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 */
202int 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
246out:
247 mutex_unlock(&pwm_lock);
248 return ret;
249}
250EXPORT_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 */
259int 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
282out:
283 mutex_unlock(&pwm_lock);
284 return ret;
285}
286EXPORT_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 */
295struct 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
315out:
316 mutex_unlock(&pwm_lock);
317
318 return dev;
319}
320EXPORT_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 */
332struct 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}
352EXPORT_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 */
360void pwm_free(struct pwm_device *pwm)
361{
362 pwm_put(pwm);
363}
364EXPORT_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 */
372int 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}
379EXPORT_SYMBOL_GPL(pwm_config);
380
381/**
382 * pwm_enable() - start a PWM output toggling
383 * @pwm: PWM device
384 */
385int 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}
392EXPORT_SYMBOL_GPL(pwm_enable);
393
394/**
395 * pwm_disable() - stop a PWM output toggling
396 * @pwm: PWM device
397 */
398void 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}
403EXPORT_SYMBOL_GPL(pwm_disable);
404
405static 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 */
438static 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
492put:
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 */
503void __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 */
527struct 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}
598EXPORT_SYMBOL_GPL(pwm_get);
599
600/**
601 * pwm_put() - release a PWM device
602 * @pwm: PWM device
603 */
604void 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);
622out:
623 mutex_unlock(&pwm_lock);
624}
625EXPORT_SYMBOL_GPL(pwm_put);
626
627#ifdef CONFIG_DEBUG_FS
628static 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
647static 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
655static 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
662static void pwm_seq_stop(struct seq_file *s, void *v)
663{
664 mutex_unlock(&pwm_lock);
665}
666
667static 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
684static 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
691static int pwm_seq_open(struct inode *inode, struct file *file)
692{
693 return seq_open(file, &pwm_seq_ops);
694}
695
696static 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
704static 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
712subsys_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
17struct bfin_pwm_chip {
18 struct pwm_chip chip;
19};
20
21struct bfin_pwm {
22 unsigned short pin;
23};
24
25static 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
30static 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
55static 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
65static 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
93static 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
102static 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
109static 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
118static 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
145static 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
152static 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
160module_platform_driver(bfin_pwm_driver);
161
162MODULE_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 42struct imx_chip {
43
44struct 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
58int 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
53static 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}
128EXPORT_SYMBOL(pwm_config);
129 123
130int pwm_enable(struct pwm_device *pwm) 124static 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}
141EXPORT_SYMBOL(pwm_enable);
142 136
143void pwm_disable(struct pwm_device *pwm) 137static 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}
152EXPORT_SYMBOL(pwm_disable);
153 142
154static DEFINE_MUTEX(pwm_lock); 143 if (imx->clk_enabled) {
155static LIST_HEAD(pwm_list); 144 clk_disable_unprepare(imx->clk);
156 145 imx->clk_enabled = 0;
157struct 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}
183EXPORT_SYMBOL(pwm_request);
184 148
185void pwm_free(struct pwm_device *pwm) 149static 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}
197EXPORT_SYMBOL(pwm_free);
198 155
199static int __devinit mxc_pwm_probe(struct platform_device *pdev) 156static 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
252err_free_mem:
253 release_mem_region(r->start, resource_size(r));
254err_free_clk:
255 clk_put(pwm->clk);
256err_free:
257 kfree(pwm);
258 return ret;
259} 196}
260 197
261static int __devexit mxc_pwm_remove(struct platform_device *pdev) 198static 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
285static struct platform_driver mxc_pwm_driver = { 209static 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
293static int __init mxc_pwm_init(void) 217static 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}
297arch_initcall(mxc_pwm_init); 221arch_initcall(imx_pwm_init);
298 222
299static void __exit mxc_pwm_exit(void) 223static void __exit imx_pwm_exit(void)
300{ 224{
301 platform_driver_unregister(&mxc_pwm_driver); 225 platform_driver_unregister(&imx_pwm_driver);
302} 226}
303module_exit(mxc_pwm_exit); 227module_exit(imx_pwm_exit);
304 228
305MODULE_LICENSE("GPL v2"); 229MODULE_LICENSE("GPL v2");
306MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 230MODULE_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
21struct 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
34static 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
62static 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
69static 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
77static 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
84static 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
121static 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
129static struct of_device_id lpc32xx_pwm_dt_ids[] = {
130 { .compatible = "nxp,lpc3220-pwm", },
131 { /* sentinel */ }
132};
133MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids);
134
135static 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};
143module_platform_driver(lpc32xx_pwm_driver);
144
145MODULE_ALIAS("platform:lpc32xx-pwm");
146MODULE_AUTHOR("Alexandre Pereira da Silva <aletes.xgr@gmail.com>");
147MODULE_DESCRIPTION("LPC32XX PWM Driver");
148MODULE_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
39struct 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
48static 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
99static 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
113static 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
122static 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
129static 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
177static 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
184static struct of_device_id mxs_pwm_dt_ids[] = {
185 { .compatible = "fsl,imx23-pwm", },
186 { /* sentinel */ }
187};
188MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids);
189
190static 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};
198module_platform_driver(mxs_pwm_driver);
199
200MODULE_ALIAS("platform:mxs-pwm");
201MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
202MODULE_DESCRIPTION("Freescale MXS PWM Driver");
203MODULE_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
28static 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};
36MODULE_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
46struct 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
55static 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 */
64static 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
111static 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
124static 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
134static 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
141static 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
185static 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
196static 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
206static int __init pwm_init(void)
207{
208 return platform_driver_register(&pwm_driver);
209}
210arch_initcall(pwm_init);
211
212static void __exit pwm_exit(void)
213{
214 platform_driver_unregister(&pwm_driver);
215}
216module_exit(pwm_exit);
217
218MODULE_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
27struct pwm_device { 29struct 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
45static struct clk *clk_scaler[2]; 48static struct clk *clk_scaler[2];
46 49
47static inline int pwm_is_tdiv(struct pwm_device *pwm) 50static inline int pwm_is_tdiv(struct s3c_chip *chip)
48{
49 return clk_get_parent(pwm->clk) == pwm->clk_div;
50}
51
52static DEFINE_MUTEX(pwm_lock);
53static LIST_HEAD(pwm_list);
54
55struct 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
82EXPORT_SYMBOL(pwm_request);
83
84
85void 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
98EXPORT_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
105int pwm_enable(struct pwm_device *pwm) 60static 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
121EXPORT_SYMBOL(pwm_enable); 77static void s3c_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
122
123void 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
137EXPORT_SYMBOL(pwm_disable); 92static unsigned long pwm_calc_tin(struct s3c_chip *s3c, unsigned long freq)
138
139static 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
157int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 110static 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
244EXPORT_SYMBOL(pwm_config); 199static struct pwm_ops s3c_pwm_ops = {
245 200 .enable = s3c_pwm_enable,
246static 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
258static int s3c_pwm_probe(struct platform_device *pdev) 206static 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
340static int __devexit s3c_pwm_remove(struct platform_device *pdev) 278static 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
354static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state) 294static 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
368static int s3c_pwm_resume(struct platform_device *pdev) 308static 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
41struct 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
50static 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
55static inline u32 pwm_readl(struct tegra_pwm_chip *chip, unsigned int num)
56{
57 return readl(chip->mmio_base + (num << 4));
58}
59
60static 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
66static 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
133static 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
150static 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
162static 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
169static 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
215static 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
239static struct of_device_id tegra_pwm_of_match[] = {
240 { .compatible = "nvidia,tegra20-pwm" },
241 { .compatible = "nvidia,tegra30-pwm" },
242 { }
243};
244
245MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
246#endif
247
248static 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
257module_platform_driver(tegra_pwm_driver);
258
259MODULE_LICENSE("GPL");
260MODULE_AUTHOR("NVIDIA Corporation");
261MODULE_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
39struct ecap_pwm_chip {
40 struct pwm_chip chip;
41 unsigned int clk_rate;
42 void __iomem *mmio_base;
43};
44
45static 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 */
54static 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
107static 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
125static 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
142static 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
150static 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
158static 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
211static 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
220static 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
228module_platform_driver(ecap_pwm_driver);
229
230MODULE_DESCRIPTION("ECAP PWM driver");
231MODULE_AUTHOR("Texas Instruments");
232MODULE_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
103struct ehrpwm_pwm_chip {
104 struct pwm_chip chip;
105 unsigned int clk_rate;
106 void __iomem *mmio_base;
107};
108
109static 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
114static void ehrpwm_write(void *base, int offset, unsigned int val)
115{
116 writew(val & 0xFFFF, base + offset);
117}
118
119static 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 */
136static 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
167static 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 */
206static 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
263static 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
291static 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
321static 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
329static 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
337static 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
390static 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
399static 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
407module_platform_driver(ehrpwm_pwm_driver);
408
409MODULE_DESCRIPTION("EHRPWM PWM driver");
410MODULE_AUTHOR("Texas Instruments");
411MODULE_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
29struct 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)
37static 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
48static 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
86static 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
95static 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
103static 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
110static 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
145static 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
156static 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
165static int __init pwm_init(void)
166{
167 return platform_driver_register(&pwm_driver);
168}
169arch_initcall(pwm_init);
170
171static void __exit pwm_exit(void)
172{
173 platform_driver_unregister(&pwm_driver);
174}
175module_exit(pwm_exit);
176
177MODULE_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
246config BACKLIGHT_PWM 246config 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
36static int pwm_backlight_update_status(struct backlight_device *bl) 38static 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
98static 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
157static struct of_device_id pwm_backlight_of_match[] = {
158 { .compatible = "pwm-backlight" },
159 { }
160};
161
162MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
163#else
164static int pwm_backlight_parse_dt(struct device *dev,
165 struct platform_pwm_backlight_data *data)
166{
167 return -ENODEV;
168}
169#endif
170
86static int pwm_backlight_probe(struct platform_device *pdev) 171static 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
145err_bl: 258err_bl:
146 pwm_free(pb->pwm); 259 pwm_put(pb->pwm);
147err_alloc: 260err_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
153static int pwm_backlight_remove(struct platform_device *pdev) 266static 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
196static struct platform_driver pwm_backlight_driver = { 308static 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
389static inline int of_property_match_string(struct device_node *np,
390 const char *propname,
391 const char *string)
392{
393 return -ENOSYS;
394}
395
389static inline struct device_node *of_parse_phandle(struct device_node *np, 396static 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
403static 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
396static inline int of_alias_get_id(struct device_node *np, const char *stem) 412static 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
4struct pwm_device; 6struct pwm_device;
7struct 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 */
29void pwm_disable(struct pwm_device *pwm); 32void pwm_disable(struct pwm_device *pwm);
30 33
34#ifdef CONFIG_PWM
35struct pwm_chip;
36
37enum {
38 PWMF_REQUESTED = 1 << 0,
39 PWMF_ENABLED = 1 << 1,
40};
41
42struct 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
53static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
54{
55 if (pwm)
56 pwm->period = period;
57}
58
59static 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 */
74struct 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 */
102struct 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
116int pwm_set_chip_data(struct pwm_device *pwm, void *data);
117void *pwm_get_chip_data(struct pwm_device *pwm);
118
119int pwmchip_add(struct pwm_chip *chip);
120int pwmchip_remove(struct pwm_chip *chip);
121struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
122 unsigned int index,
123 const char *label);
124
125struct pwm_device *pwm_get(struct device *dev, const char *consumer);
126void pwm_put(struct pwm_device *pwm);
127
128struct 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
144void 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);