All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/10] Add PWM framework and device tree support.
@ 2012-02-22 15:17 ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

This patch series adds very rudimentary device-tree support for PWM
devices. With all of these patches applied (plus one board-specific
patch that is not included), I'm able to control the backlight on the
device I'm working on using the sysfs interface provided by the pwm-bl
driver and the backlight class.

This series is based on Sascha Hauer's series of patches[0] to add a
generic PWM framework. The first patch in this series is taken from
Sascha's branch, while the second patch enables each PWM chip to provide
multiple PWM devices (the Blackfin and PXA drivers have been ported to
the framework for reference). When this series is ready I think it would
be best to merge patches 1 and 2. Currently a global namespace is still
provided to keep backwards-compatibility with the legacy PWM API. In
order to achieve this, the number of global PWM devices is limited to
1024. However, patch 2 introduces per-chip indexing of PWM devices in
the core, so it should be easy to add an API to request a PWM device on
a per-chip basis and get rid of the global namespace eventually. The
device tree support code does not use the global namespace.

Patch 3 adds some code to lookup a PWM chip given its device-tree
handle. This code will be used later on by the pwm-bl driver to find the
PWM device that it should be using. Device tree binding documentation is
also provided.

Patch 4 was taken from the Chromium tree and is required to provide
proper clocking of the Tegra2 PWFM controller. All Chromium-specific
tags have been removed from the commit message. Some cleanup of the
clock registration for Tegra is done in patch 5 because a subsequent
patch will instantiate one PWFM controller device instead of four.

Patch 6 adds a generic PWM framework driver for the Tegra2 PWFM
controller. The code is taken from the Chromium tree with some
adjustments to integrate it with the PWM framework. Device tree based
probing of the driver is implemented in patch 7.

Patches 8 and 9 are ports of the Blackfin PWM and the PXA PWM drivers to
the PWM framework. These are only compile-tested as I do not have any
hardware to test them on. They are meant as test-bed for the framework.
Sascha already has patches that port all in-tree drivers to the
framework and will rebase them on top of this series when it is ready.

Patch 10 implements DT-based probing in the pwm-backlight driver. Note
that this code only handles the "pwm" property (by looking up the PWM
device via the new PWM DT binding). Switching power to the backlight via
GPIOs is not supported yet. The DT binding also deviates from the
platform data in that it requires a list of brightness levels to be
specified instead of assuming a linearily spaced range from 0 to a given
maximum brightness.

The whole series is based on the linux-next tree from 20120222. I think I've
addressed all of the concerns raised in the first two versions.

Thierry

[0]: http://git.pengutronix.de/?p=imx/linux-2.6.git;a=shortlog;h=refs/heads/pwmlib

Sascha Hauer (1):
  PWM: add pwm framework support

Simon Que (1):
  arm/tegra: Fix PWM clock programming

Thierry Reding (8):
  pwm: Allow chips to support multiple PWMs.
  of: Add PWM support.
  arm/tegra: Provide clock for only one PWM controller
  pwm: Add NVIDIA Tegra SoC support
  arm/tegra: Add PWFM controller device tree probing
  pwm: Add Blackfin support
  pwm: Add PXA support
  pwm-backlight: Add rudimentary device tree support

 Documentation/devicetree/bindings/pwm/pwm.txt      |   48 +++
 .../bindings/video/backlight/pwm-backlight         |   19 +
 Documentation/pwm.txt                              |   56 +++
 MAINTAINERS                                        |    6 +
 arch/arm/boot/dts/tegra20.dtsi                     |    6 +
 arch/arm/boot/dts/tegra30.dtsi                     |    6 +
 arch/arm/mach-tegra/board-dt-tegra20.c             |    1 +
 arch/arm/mach-tegra/board-dt-tegra30.c             |    3 +
 arch/arm/mach-tegra/clock.h                        |    1 +
 arch/arm/mach-tegra/tegra2_clocks.c                |   33 ++-
 arch/arm/plat-pxa/Makefile                         |    1 -
 arch/arm/plat-pxa/pwm.c                            |  304 ----------------
 arch/blackfin/Kconfig                              |   10 -
 arch/blackfin/kernel/Makefile                      |    1 -
 arch/blackfin/kernel/pwm.c                         |  100 -----
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/of/Kconfig                                 |    6 +
 drivers/of/Makefile                                |    1 +
 drivers/of/pwm.c                                   |  130 +++++++
 drivers/pwm/Kconfig                                |   40 ++
 drivers/pwm/Makefile                               |    4 +
 drivers/pwm/core.c                                 |  381 ++++++++++++++++++++
 drivers/pwm/pwm-bfin.c                             |  164 +++++++++
 drivers/pwm/pwm-pxa.c                              |  244 +++++++++++++
 drivers/pwm/pwm-tegra.c                            |  263 ++++++++++++++
 drivers/video/backlight/Kconfig                    |    2 +-
 drivers/video/backlight/pwm_bl.c                   |  113 ++++++-
 include/linux/of_pwm.h                             |   51 +++
 include/linux/pwm.h                                |   89 +++++
 include/linux/pwm_backlight.h                      |    1 +
 31 files changed, 1652 insertions(+), 435 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt
 create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight
 create mode 100644 Documentation/pwm.txt
 delete mode 100644 arch/arm/plat-pxa/pwm.c
 delete mode 100644 arch/blackfin/kernel/pwm.c
 create mode 100644 drivers/of/pwm.c
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/core.c
 create mode 100644 drivers/pwm/pwm-bfin.c
 create mode 100644 drivers/pwm/pwm-pxa.c
 create mode 100644 drivers/pwm/pwm-tegra.c
 create mode 100644 include/linux/of_pwm.h

-- 
1.7.9.1

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 00/10] Add PWM framework and device tree support.
@ 2012-02-22 15:17 ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series adds very rudimentary device-tree support for PWM
devices. With all of these patches applied (plus one board-specific
patch that is not included), I'm able to control the backlight on the
device I'm working on using the sysfs interface provided by the pwm-bl
driver and the backlight class.

This series is based on Sascha Hauer's series of patches[0] to add a
generic PWM framework. The first patch in this series is taken from
Sascha's branch, while the second patch enables each PWM chip to provide
multiple PWM devices (the Blackfin and PXA drivers have been ported to
the framework for reference). When this series is ready I think it would
be best to merge patches 1 and 2. Currently a global namespace is still
provided to keep backwards-compatibility with the legacy PWM API. In
order to achieve this, the number of global PWM devices is limited to
1024. However, patch 2 introduces per-chip indexing of PWM devices in
the core, so it should be easy to add an API to request a PWM device on
a per-chip basis and get rid of the global namespace eventually. The
device tree support code does not use the global namespace.

Patch 3 adds some code to lookup a PWM chip given its device-tree
handle. This code will be used later on by the pwm-bl driver to find the
PWM device that it should be using. Device tree binding documentation is
also provided.

Patch 4 was taken from the Chromium tree and is required to provide
proper clocking of the Tegra2 PWFM controller. All Chromium-specific
tags have been removed from the commit message. Some cleanup of the
clock registration for Tegra is done in patch 5 because a subsequent
patch will instantiate one PWFM controller device instead of four.

Patch 6 adds a generic PWM framework driver for the Tegra2 PWFM
controller. The code is taken from the Chromium tree with some
adjustments to integrate it with the PWM framework. Device tree based
probing of the driver is implemented in patch 7.

Patches 8 and 9 are ports of the Blackfin PWM and the PXA PWM drivers to
the PWM framework. These are only compile-tested as I do not have any
hardware to test them on. They are meant as test-bed for the framework.
Sascha already has patches that port all in-tree drivers to the
framework and will rebase them on top of this series when it is ready.

Patch 10 implements DT-based probing in the pwm-backlight driver. Note
that this code only handles the "pwm" property (by looking up the PWM
device via the new PWM DT binding). Switching power to the backlight via
GPIOs is not supported yet. The DT binding also deviates from the
platform data in that it requires a list of brightness levels to be
specified instead of assuming a linearily spaced range from 0 to a given
maximum brightness.

The whole series is based on the linux-next tree from 20120222. I think I've
addressed all of the concerns raised in the first two versions.

Thierry

[0]: http://git.pengutronix.de/?p=imx/linux-2.6.git;a=shortlog;h=refs/heads/pwmlib

Sascha Hauer (1):
  PWM: add pwm framework support

Simon Que (1):
  arm/tegra: Fix PWM clock programming

Thierry Reding (8):
  pwm: Allow chips to support multiple PWMs.
  of: Add PWM support.
  arm/tegra: Provide clock for only one PWM controller
  pwm: Add NVIDIA Tegra SoC support
  arm/tegra: Add PWFM controller device tree probing
  pwm: Add Blackfin support
  pwm: Add PXA support
  pwm-backlight: Add rudimentary device tree support

 Documentation/devicetree/bindings/pwm/pwm.txt      |   48 +++
 .../bindings/video/backlight/pwm-backlight         |   19 +
 Documentation/pwm.txt                              |   56 +++
 MAINTAINERS                                        |    6 +
 arch/arm/boot/dts/tegra20.dtsi                     |    6 +
 arch/arm/boot/dts/tegra30.dtsi                     |    6 +
 arch/arm/mach-tegra/board-dt-tegra20.c             |    1 +
 arch/arm/mach-tegra/board-dt-tegra30.c             |    3 +
 arch/arm/mach-tegra/clock.h                        |    1 +
 arch/arm/mach-tegra/tegra2_clocks.c                |   33 ++-
 arch/arm/plat-pxa/Makefile                         |    1 -
 arch/arm/plat-pxa/pwm.c                            |  304 ----------------
 arch/blackfin/Kconfig                              |   10 -
 arch/blackfin/kernel/Makefile                      |    1 -
 arch/blackfin/kernel/pwm.c                         |  100 -----
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/of/Kconfig                                 |    6 +
 drivers/of/Makefile                                |    1 +
 drivers/of/pwm.c                                   |  130 +++++++
 drivers/pwm/Kconfig                                |   40 ++
 drivers/pwm/Makefile                               |    4 +
 drivers/pwm/core.c                                 |  381 ++++++++++++++++++++
 drivers/pwm/pwm-bfin.c                             |  164 +++++++++
 drivers/pwm/pwm-pxa.c                              |  244 +++++++++++++
 drivers/pwm/pwm-tegra.c                            |  263 ++++++++++++++
 drivers/video/backlight/Kconfig                    |    2 +-
 drivers/video/backlight/pwm_bl.c                   |  113 ++++++-
 include/linux/of_pwm.h                             |   51 +++
 include/linux/pwm.h                                |   89 +++++
 include/linux/pwm_backlight.h                      |    1 +
 31 files changed, 1652 insertions(+), 435 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt
 create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight
 create mode 100644 Documentation/pwm.txt
 delete mode 100644 arch/arm/plat-pxa/pwm.c
 delete mode 100644 arch/blackfin/kernel/pwm.c
 create mode 100644 drivers/of/pwm.c
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/core.c
 create mode 100644 drivers/pwm/pwm-bfin.c
 create mode 100644 drivers/pwm/pwm-pxa.c
 create mode 100644 drivers/pwm/pwm-tegra.c
 create mode 100644 include/linux/of_pwm.h

-- 
1.7.9.1

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 01/10] PWM: add pwm framework support
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: Mark Brown, Ryan Mallon, Sascha Hauer, Colin Cross, Rob Herring,
	Lars-Peter Clausen, Richard Purdie, Matthias Kaehlcke,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck

From: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

This patch adds framework support for PWM (pulse width modulation) devices.

The is a barebone PWM API already in the kernel under include/linux/pwm.h,
but it does not allow for multiple drivers as each of them implements the
pwm_*() functions.

There are other PWM framework patches around from Bill Gatliff. Unlike
his framework this one does not change the existing API for PWMs so that
this framework can act as a drop in replacement for the existing API.

Why another framework?

Several people argue that there should not be another framework for PWMs
but they should be integrated into one of the existing frameworks like led
or hwmon. Unlike these frameworks the PWM framework is agnostic to the
purpose of the PWM. In fact, a PWM can drive a LED, but this makes the
LED framework a user of a PWM, like already done in leds-pwm.c. The gpio
framework also is not suitable for PWMs. Every gpio could be turned into
a PWM using timer based toggling, but on the other hand not every PWM hardware
device can be turned into a gpio due to the lack of hardware capabilities.

This patch does not try to improve the PWM API yet, this could be done in
subsequent patches.

Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Acked-by: Kurt Van Dijck <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
Reviewed-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
Reviewed-by: Matthias Kaehlcke <matthias-RprLehDfhQ3k1uMJSBkQmQ@public.gmane.org>
---
 Documentation/pwm.txt |   56 +++++++++++++
 MAINTAINERS           |    6 ++
 drivers/Kconfig       |    2 +
 drivers/Makefile      |    1 +
 drivers/pwm/Kconfig   |   12 +++
 drivers/pwm/Makefile  |    1 +
 drivers/pwm/core.c    |  220 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pwm.h   |   37 ++++++++
 8 files changed, 335 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/pwm.txt
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/core.c

diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
new file mode 100644
index 0000000..c7c5cb1
--- /dev/null
+++ b/Documentation/pwm.txt
@@ -0,0 +1,56 @@
+Pulse Width Modulation (PWM) interface
+
+This provides an overview about the Linux PWM interface
+
+PWMs are commonly used for controlling LEDs, fans or vibrators in
+cell phones. PWMs with a fixed purpose have no need implementing
+the Linux PWM API (although they could). However, PWMs are often
+found as discrete devices on SoCs which have no fixed purpose. It's
+up to the board designer to connect them to LEDs or fans. To provide
+this kind of flexibility the generic PWM API exists.
+
+Identifying PWMs
+----------------
+
+PWMs are identified by unique ids throughout the system. A platform
+should call pwmchip_reserve() during init time to reserve the id range
+for internal PWMs so that users have a fixed id to refer to specific
+PWMs.
+
+Using PWMs
+----------
+
+A PWM can be requested using pwm_request() and freed after usage with
+pwm_free(). After being requested a PWM has to be configured using
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
+
+To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+
+Implementing a PWM driver
+-------------------------
+
+Currently there are two ways to implement pwm drivers. Traditionally
+there only has been the barebone API meaning that each driver has
+to implement the pwm_*() functions itself. This means that it's impossible
+to have multiple PWM drivers in the system. For this reason it's mandatory
+for new drivers to use the generic PWM framework.
+A new PWM device can be added using pwmchip_add() and removed again with
+pwmchip_remove(). pwmchip_add() takes a filled in struct pwm_chip as
+argument which provides the ops and the pwm id to the framework.
+
+Locking
+-------
+
+The PWM core list manipulations are protected by a mutex, so pwm_request()
+and pwm_free() may not be called from an atomic context. Currently the
+PWM core does not enforce any locking to pwm_enable(), pwm_disable() and
+pwm_config(), so the calling context is currently driver specific. This
+is an issue derived from the former barebone API and should be fixed soon.
+
+Helpers
+-------
+
+Currently a PWM can only be configured with period_ns and duty_ns. For several
+use cases freq_hz and duty_percent might be better. Instead of calculating 
+this in your driver please consider adding appropriate helpers to the framework.
diff --git a/MAINTAINERS b/MAINTAINERS
index 467f8c8..5916b85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5357,6 +5357,12 @@ S:	Maintained
 F:	Documentation/video4linux/README.pvrusb2
 F:	drivers/media/video/pvrusb2/
 
+PPWM core
+M:	Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+L:	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+S:	Maintained
+F:	drivers/pwm/
+
 PXA2xx/PXA3xx SUPPORT
 M:	Eric Miao <eric.y.miao-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
 M:	Russell King <linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3ae9e5..ec094b5 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -142,4 +142,6 @@ source "drivers/devfreq/Kconfig"
 
 source "drivers/modem_shm/Kconfig"
 
+source "drivers/pwm/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4855a1a..52fe956 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -8,6 +8,7 @@
 # GPIO must come after pinctrl as gpios may need to mux pins etc
 obj-y				+= pinctrl/
 obj-y				+= gpio/
+obj-y				+= pwm/
 obj-$(CONFIG_PCI)		+= pci/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-$(CONFIG_RAPIDIO)		+= rapidio/
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
new file mode 100644
index 0000000..93c1052
--- /dev/null
+++ b/drivers/pwm/Kconfig
@@ -0,0 +1,12 @@
+menuconfig PWM
+	bool "PWM Support"
+	help
+	  This enables PWM support through the generic PWM framework.
+	  You only need to enable this, if you also want to enable
+	  one or more of the PWM drivers below.
+
+	  If unsure, say N.
+
+if PWM
+
+endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
new file mode 100644
index 0000000..3469c3d
--- /dev/null
+++ b/drivers/pwm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PWM)		+= core.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
new file mode 100644
index 0000000..71de479
--- /dev/null
+++ b/drivers/pwm/core.c
@@ -0,0 +1,220 @@
+/*
+ * Generic pwmlib implementation
+ *
+ * Copyright (C) 2011 Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+struct pwm_device {
+	struct			pwm_chip *chip;
+	const char		*label;
+	unsigned long		flags;
+#define FLAG_REQUESTED	0
+#define FLAG_ENABLED	1
+	struct list_head	node;
+};
+
+static LIST_HEAD(pwm_list);
+
+static DEFINE_MUTEX(pwm_lock);
+
+static struct pwm_device *_find_pwm(int pwm_id)
+{
+	struct pwm_device *pwm;
+
+	list_for_each_entry(pwm, &pwm_list, node) {
+		if (pwm->chip->pwm_id == pwm_id)
+			return pwm;
+	}
+
+	return NULL;
+}
+
+/**
+ * pwmchip_add() - register a new pwm
+ * @chip: the pwm
+ *
+ * register a new pwm. pwm->pwm_id must be initialized. if pwm_id < 0 then
+ * a dynamically assigned id will be used, otherwise the id specified,
+ */
+int pwmchip_add(struct pwm_chip *chip)
+{
+	struct pwm_device *pwm;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->chip = chip;
+
+	mutex_lock(&pwm_lock);
+
+	if (chip->pwm_id >= 0 && _find_pwm(chip->pwm_id)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	list_add_tail(&pwm->node, &pwm_list);
+out:
+	mutex_unlock(&pwm_lock);
+
+	if (ret)
+		kfree(pwm);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_add);
+
+/**
+ * pwmchip_remove() - remove a pwm
+ * @chip: the pwm
+ *
+ * remove a pwm. This function may return busy if the pwm is still requested.
+ */
+int pwmchip_remove(struct pwm_chip *chip)
+{
+	struct pwm_device *pwm;
+	int ret = 0;
+
+	mutex_lock(&pwm_lock);
+
+	pwm = _find_pwm(chip->pwm_id);
+	if (!pwm) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	list_del(&pwm->node);
+
+	kfree(pwm);
+out:
+	mutex_unlock(&pwm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_remove);
+
+/*
+ * pwm_request - request a PWM device
+ */
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	struct pwm_device *pwm;
+	int ret;
+
+	mutex_lock(&pwm_lock);
+
+	pwm = _find_pwm(pwm_id);
+	if (!pwm) {
+		pwm = ERR_PTR(-ENOENT);
+		goto out;
+	}
+
+	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
+		pwm = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	if (!try_module_get(pwm->chip->ops->owner)) {
+		pwm = ERR_PTR(-ENODEV);
+		goto out;
+	}
+
+	if (pwm->chip->ops->request) {
+		ret = pwm->chip->ops->request(pwm->chip);
+		if (ret) {
+			pwm = ERR_PTR(ret);
+			goto out_put;
+		}
+	}
+
+	pwm->label = label;
+	set_bit(FLAG_REQUESTED, &pwm->flags);
+
+	goto out;
+
+out_put:
+	module_put(pwm->chip->ops->owner);
+out:
+	mutex_unlock(&pwm_lock);
+
+	return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_request);
+
+/*
+ * pwm_free - free a PWM device
+ */
+void pwm_free(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+
+	if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) {
+		pr_warning("PWM device already freed\n");
+		goto out;
+	}
+
+	pwm->label = NULL;
+
+	module_put(pwm->chip->ops->owner);
+out:
+	mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL_GPL(pwm_free);
+
+/*
+ * pwm_config - change a PWM device configuration
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/*
+ * pwm_enable - start a PWM output toggling
+ */
+int pwm_enable(struct pwm_device *pwm)
+{
+	if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
+		return pwm->chip->ops->enable(pwm->chip);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pwm_enable);
+
+/*
+ * pwm_disable - stop a PWM output toggling
+ */
+void pwm_disable(struct pwm_device *pwm)
+{
+	if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
+		pwm->chip->ops->disable(pwm->chip);
+}
+EXPORT_SYMBOL_GPL(pwm_disable);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 7c77575..df9681b 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -28,4 +28,41 @@ int pwm_enable(struct pwm_device *pwm);
  */
 void pwm_disable(struct pwm_device *pwm);
 
+#ifdef CONFIG_PWM
+struct pwm_chip;
+
+/**
+ * struct pwm_ops - PWM operations
+ * @request: optional hook for requesting a PWM
+ * @free: optional hook for freeing a PWM
+ * @config: configure duty cycles and period length for this PWM
+ * @enable: enable PWM output toggling
+ * @disable: disable PWM output toggling
+ */
+struct pwm_ops {
+	int			(*request)(struct pwm_chip *chip);
+	void			(*free)(struct pwm_chip *chip);
+	int			(*config)(struct pwm_chip *chip, int duty_ns,
+						int period_ns);
+	int			(*enable)(struct pwm_chip *chip);
+	void			(*disable)(struct pwm_chip *chip);
+	struct module		*owner;
+};
+
+/**
+ * struct pwm_chip - abstract a PWM
+ * @label: for diagnostics
+ * @owner: helps prevent removal of modules exporting active PWMs
+ * @ops: The callbacks for this PWM
+ */
+struct pwm_chip {
+	int			pwm_id;
+	const char		*label;
+	struct pwm_ops		*ops;
+};
+
+int pwmchip_add(struct pwm_chip *chip);
+int pwmchip_remove(struct pwm_chip *chip);
+#endif
+
 #endif /* __LINUX_PWM_H */
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 01/10] PWM: add pwm framework support
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

From: Sascha Hauer <s.hauer@pengutronix.de>

This patch adds framework support for PWM (pulse width modulation) devices.

The is a barebone PWM API already in the kernel under include/linux/pwm.h,
but it does not allow for multiple drivers as each of them implements the
pwm_*() functions.

There are other PWM framework patches around from Bill Gatliff. Unlike
his framework this one does not change the existing API for PWMs so that
this framework can act as a drop in replacement for the existing API.

Why another framework?

Several people argue that there should not be another framework for PWMs
but they should be integrated into one of the existing frameworks like led
or hwmon. Unlike these frameworks the PWM framework is agnostic to the
purpose of the PWM. In fact, a PWM can drive a LED, but this makes the
LED framework a user of a PWM, like already done in leds-pwm.c. The gpio
framework also is not suitable for PWMs. Every gpio could be turned into
a PWM using timer based toggling, but on the other hand not every PWM hardware
device can be turned into a gpio due to the lack of hardware capabilities.

This patch does not try to improve the PWM API yet, this could be done in
subsequent patches.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Kurt Van Dijck <kurt.van.dijck@eia.be>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Matthias Kaehlcke <matthias@kaehlcke.net>
---
 Documentation/pwm.txt |   56 +++++++++++++
 MAINTAINERS           |    6 ++
 drivers/Kconfig       |    2 +
 drivers/Makefile      |    1 +
 drivers/pwm/Kconfig   |   12 +++
 drivers/pwm/Makefile  |    1 +
 drivers/pwm/core.c    |  220 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pwm.h   |   37 ++++++++
 8 files changed, 335 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/pwm.txt
 create mode 100644 drivers/pwm/Kconfig
 create mode 100644 drivers/pwm/Makefile
 create mode 100644 drivers/pwm/core.c

diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
new file mode 100644
index 0000000..c7c5cb1
--- /dev/null
+++ b/Documentation/pwm.txt
@@ -0,0 +1,56 @@
+Pulse Width Modulation (PWM) interface
+
+This provides an overview about the Linux PWM interface
+
+PWMs are commonly used for controlling LEDs, fans or vibrators in
+cell phones. PWMs with a fixed purpose have no need implementing
+the Linux PWM API (although they could). However, PWMs are often
+found as discrete devices on SoCs which have no fixed purpose. It's
+up to the board designer to connect them to LEDs or fans. To provide
+this kind of flexibility the generic PWM API exists.
+
+Identifying PWMs
+----------------
+
+PWMs are identified by unique ids throughout the system. A platform
+should call pwmchip_reserve() during init time to reserve the id range
+for internal PWMs so that users have a fixed id to refer to specific
+PWMs.
+
+Using PWMs
+----------
+
+A PWM can be requested using pwm_request() and freed after usage with
+pwm_free(). After being requested a PWM has to be configured using
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
+
+To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+
+Implementing a PWM driver
+-------------------------
+
+Currently there are two ways to implement pwm drivers. Traditionally
+there only has been the barebone API meaning that each driver has
+to implement the pwm_*() functions itself. This means that it's impossible
+to have multiple PWM drivers in the system. For this reason it's mandatory
+for new drivers to use the generic PWM framework.
+A new PWM device can be added using pwmchip_add() and removed again with
+pwmchip_remove(). pwmchip_add() takes a filled in struct pwm_chip as
+argument which provides the ops and the pwm id to the framework.
+
+Locking
+-------
+
+The PWM core list manipulations are protected by a mutex, so pwm_request()
+and pwm_free() may not be called from an atomic context. Currently the
+PWM core does not enforce any locking to pwm_enable(), pwm_disable() and
+pwm_config(), so the calling context is currently driver specific. This
+is an issue derived from the former barebone API and should be fixed soon.
+
+Helpers
+-------
+
+Currently a PWM can only be configured with period_ns and duty_ns. For several
+use cases freq_hz and duty_percent might be better. Instead of calculating 
+this in your driver please consider adding appropriate helpers to the framework.
diff --git a/MAINTAINERS b/MAINTAINERS
index 467f8c8..5916b85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5357,6 +5357,12 @@ S:	Maintained
 F:	Documentation/video4linux/README.pvrusb2
 F:	drivers/media/video/pvrusb2/
 
+PPWM core
+M:	Sascha Hauer <s.hauer@pengutronix.de>
+L:	linux-kernel at vger.kernel.org
+S:	Maintained
+F:	drivers/pwm/
+
 PXA2xx/PXA3xx SUPPORT
 M:	Eric Miao <eric.y.miao@gmail.com>
 M:	Russell King <linux@arm.linux.org.uk>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3ae9e5..ec094b5 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -142,4 +142,6 @@ source "drivers/devfreq/Kconfig"
 
 source "drivers/modem_shm/Kconfig"
 
+source "drivers/pwm/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4855a1a..52fe956 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -8,6 +8,7 @@
 # GPIO must come after pinctrl as gpios may need to mux pins etc
 obj-y				+= pinctrl/
 obj-y				+= gpio/
+obj-y				+= pwm/
 obj-$(CONFIG_PCI)		+= pci/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-$(CONFIG_RAPIDIO)		+= rapidio/
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
new file mode 100644
index 0000000..93c1052
--- /dev/null
+++ b/drivers/pwm/Kconfig
@@ -0,0 +1,12 @@
+menuconfig PWM
+	bool "PWM Support"
+	help
+	  This enables PWM support through the generic PWM framework.
+	  You only need to enable this, if you also want to enable
+	  one or more of the PWM drivers below.
+
+	  If unsure, say N.
+
+if PWM
+
+endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
new file mode 100644
index 0000000..3469c3d
--- /dev/null
+++ b/drivers/pwm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PWM)		+= core.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
new file mode 100644
index 0000000..71de479
--- /dev/null
+++ b/drivers/pwm/core.c
@@ -0,0 +1,220 @@
+/*
+ * Generic pwmlib implementation
+ *
+ * Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+struct pwm_device {
+	struct			pwm_chip *chip;
+	const char		*label;
+	unsigned long		flags;
+#define FLAG_REQUESTED	0
+#define FLAG_ENABLED	1
+	struct list_head	node;
+};
+
+static LIST_HEAD(pwm_list);
+
+static DEFINE_MUTEX(pwm_lock);
+
+static struct pwm_device *_find_pwm(int pwm_id)
+{
+	struct pwm_device *pwm;
+
+	list_for_each_entry(pwm, &pwm_list, node) {
+		if (pwm->chip->pwm_id == pwm_id)
+			return pwm;
+	}
+
+	return NULL;
+}
+
+/**
+ * pwmchip_add() - register a new pwm
+ * @chip: the pwm
+ *
+ * register a new pwm. pwm->pwm_id must be initialized. if pwm_id < 0 then
+ * a dynamically assigned id will be used, otherwise the id specified,
+ */
+int pwmchip_add(struct pwm_chip *chip)
+{
+	struct pwm_device *pwm;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->chip = chip;
+
+	mutex_lock(&pwm_lock);
+
+	if (chip->pwm_id >= 0 && _find_pwm(chip->pwm_id)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	list_add_tail(&pwm->node, &pwm_list);
+out:
+	mutex_unlock(&pwm_lock);
+
+	if (ret)
+		kfree(pwm);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_add);
+
+/**
+ * pwmchip_remove() - remove a pwm
+ * @chip: the pwm
+ *
+ * remove a pwm. This function may return busy if the pwm is still requested.
+ */
+int pwmchip_remove(struct pwm_chip *chip)
+{
+	struct pwm_device *pwm;
+	int ret = 0;
+
+	mutex_lock(&pwm_lock);
+
+	pwm = _find_pwm(chip->pwm_id);
+	if (!pwm) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	list_del(&pwm->node);
+
+	kfree(pwm);
+out:
+	mutex_unlock(&pwm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_remove);
+
+/*
+ * pwm_request - request a PWM device
+ */
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	struct pwm_device *pwm;
+	int ret;
+
+	mutex_lock(&pwm_lock);
+
+	pwm = _find_pwm(pwm_id);
+	if (!pwm) {
+		pwm = ERR_PTR(-ENOENT);
+		goto out;
+	}
+
+	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
+		pwm = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	if (!try_module_get(pwm->chip->ops->owner)) {
+		pwm = ERR_PTR(-ENODEV);
+		goto out;
+	}
+
+	if (pwm->chip->ops->request) {
+		ret = pwm->chip->ops->request(pwm->chip);
+		if (ret) {
+			pwm = ERR_PTR(ret);
+			goto out_put;
+		}
+	}
+
+	pwm->label = label;
+	set_bit(FLAG_REQUESTED, &pwm->flags);
+
+	goto out;
+
+out_put:
+	module_put(pwm->chip->ops->owner);
+out:
+	mutex_unlock(&pwm_lock);
+
+	return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_request);
+
+/*
+ * pwm_free - free a PWM device
+ */
+void pwm_free(struct pwm_device *pwm)
+{
+	mutex_lock(&pwm_lock);
+
+	if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) {
+		pr_warning("PWM device already freed\n");
+		goto out;
+	}
+
+	pwm->label = NULL;
+
+	module_put(pwm->chip->ops->owner);
+out:
+	mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL_GPL(pwm_free);
+
+/*
+ * pwm_config - change a PWM device configuration
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/*
+ * pwm_enable - start a PWM output toggling
+ */
+int pwm_enable(struct pwm_device *pwm)
+{
+	if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
+		return pwm->chip->ops->enable(pwm->chip);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pwm_enable);
+
+/*
+ * pwm_disable - stop a PWM output toggling
+ */
+void pwm_disable(struct pwm_device *pwm)
+{
+	if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
+		pwm->chip->ops->disable(pwm->chip);
+}
+EXPORT_SYMBOL_GPL(pwm_disable);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 7c77575..df9681b 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -28,4 +28,41 @@ int pwm_enable(struct pwm_device *pwm);
  */
 void pwm_disable(struct pwm_device *pwm);
 
+#ifdef CONFIG_PWM
+struct pwm_chip;
+
+/**
+ * struct pwm_ops - PWM operations
+ * @request: optional hook for requesting a PWM
+ * @free: optional hook for freeing a PWM
+ * @config: configure duty cycles and period length for this PWM
+ * @enable: enable PWM output toggling
+ * @disable: disable PWM output toggling
+ */
+struct pwm_ops {
+	int			(*request)(struct pwm_chip *chip);
+	void			(*free)(struct pwm_chip *chip);
+	int			(*config)(struct pwm_chip *chip, int duty_ns,
+						int period_ns);
+	int			(*enable)(struct pwm_chip *chip);
+	void			(*disable)(struct pwm_chip *chip);
+	struct module		*owner;
+};
+
+/**
+ * struct pwm_chip - abstract a PWM
+ * @label: for diagnostics
+ * @owner: helps prevent removal of modules exporting active PWMs
+ * @ops: The callbacks for this PWM
+ */
+struct pwm_chip {
+	int			pwm_id;
+	const char		*label;
+	struct pwm_ops		*ops;
+};
+
+int pwmchip_add(struct pwm_chip *chip);
+int pwmchip_remove(struct pwm_chip *chip);
+#endif
+
 #endif /* __LINUX_PWM_H */
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Many PWM controllers provide access to more than a single PWM output and
may even share some resource among them. Allowing a PWM chip to provide
multiple PWM devices enables better sharing of those resources. As a
side-effect this change allows easy integration with the device tree
where a given PWM can be looked up based on the PWM chip's phandle and a
corresponding index.

This commit modifies the PWM core to support multiple PWMs per struct
pwm_chip. It achieves this in a similar way to how gpiolib works, by
allowing PWM ranges to be requested dynamically (pwm_chip.base == -1) or
starting at a given offset (pwm_chip.base >= 0). A chip specifies how
many PWMs it controls using the npwm member. Each of the functions in
the pwm_ops structure gets an additional struct pwm_device * argument
that points to the PWM device that is to be operated on. The per-chip
index of a PWM device is available in the hwpwm field.

The total maximum number of PWM devices is currently fixed to 1024 while
the data is actually stored in a radix tree, thus saving resources if
not all of them are used. The core no longer uses the global namespace,
which is only provided for backwards-compatibility until all PWM API
users are converted to use the PWM framework and request devices using
a per-chip index.

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - get rid of pwm_desc structure and keep only struct pwm_device
  - keep a list of pwm_chip structures for fast and easy lookup
  - pass struct pwm_device directly to pwm_ops
  - add debugfs file

Changes in v2:
  - add 'struct device *dev' field to pwm_chip, drop label field
  - use radix tree for PWM descriptors
  - add pwm_set_chip_data() and pwm_get_chip_data() functions to allow
    storing and retrieving chip-specific per-PWM data

TODO:
  - we can probably get rid of the chip parameter in PWM ops because it
    is already tracked in struct pwm_device
  - merge with Sascha's patch

 drivers/pwm/core.c  |  301 +++++++++++++++++++++++++++++++++++++++------------
 include/linux/pwm.h |   61 ++++++++---
 2 files changed, 279 insertions(+), 83 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 71de479..d4d2249 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -17,154 +17,247 @@
  *  along with this program; see the file COPYING.  If not, write to
  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
 #include <linux/module.h>
+#include <linux/of_pwm.h>
 #include <linux/pwm.h>
+#include <linux/radix-tree.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
-struct pwm_device {
-	struct			pwm_chip *chip;
-	const char		*label;
-	unsigned long		flags;
-#define FLAG_REQUESTED	0
-#define FLAG_ENABLED	1
-	struct list_head	node;
-};
-
-static LIST_HEAD(pwm_list);
+#define MAX_PWMS 1024
 
 static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_chips);
+static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
+static RADIX_TREE(pwm_tree, GFP_KERNEL);
 
-static struct pwm_device *_find_pwm(int pwm_id)
+static struct pwm_device *pwm_to_device(unsigned int pwm)
 {
-	struct pwm_device *pwm;
+	return radix_tree_lookup(&pwm_tree, pwm);
+}
+
+static int alloc_pwms(int pwm, unsigned int count)
+{
+	unsigned int from = 0;
+	unsigned int start;
 
-	list_for_each_entry(pwm, &pwm_list, node) {
-		if (pwm->chip->pwm_id == pwm_id)
-			return pwm;
+	if (pwm >= MAX_PWMS)
+		return -EINVAL;
+
+	if (pwm >= 0)
+		from = pwm;
+
+	start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from,
+					   count, 0);
+
+	if (pwm >= 0 && start != pwm)
+		return -EEXIST;
+
+	if (start + count > MAX_PWMS)
+		return -ENOSPC;
+
+	return start;
+}
+
+static void free_pwms(struct pwm_chip *chip)
+{
+	unsigned int i;
+
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+		radix_tree_delete(&pwm_tree, pwm->pwm);
 	}
 
-	return NULL;
+	bitmap_clear(allocated_pwms, chip->base, chip->npwm);
+
+	kfree(chip->pwms);
+	chip->pwms = NULL;
+}
+
+/**
+ * pwm_set_chip_data - set private chip data for a PWM
+ * @pwm: PWM device
+ * @data: pointer to chip-specific data
+ */
+int pwm_set_chip_data(struct pwm_device *pwm, void *data)
+{
+	if (!pwm)
+		return -EINVAL;
+
+	pwm->chip_data = data;
+
+	return 0;
 }
 
 /**
- * pwmchip_add() - register a new pwm
- * @chip: the pwm
+ * pwm_get_chip_data - get private chip data for a PWM
+ * @pwm: PWM device
+ */
+void *pwm_get_chip_data(struct pwm_device *pwm)
+{
+	return pwm ? pwm->chip_data : NULL;
+}
+
+/**
+ * pwmchip_add() - register a new PWM chip
+ * @chip: the PWM chip to add
  *
- * register a new pwm. pwm->pwm_id must be initialized. if pwm_id < 0 then
- * a dynamically assigned id will be used, otherwise the id specified,
+ * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
+ * will be used.
  */
 int pwmchip_add(struct pwm_chip *chip)
 {
 	struct pwm_device *pwm;
-	int ret = 0;
+	unsigned int i;
+	int ret;
 
-	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
-	if (!pwm)
+	mutex_lock(&pwm_lock);
+
+	ret = alloc_pwms(chip->base, chip->npwm);
+	if (ret < 0)
+		goto out;
+
+	chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL);
+	if (!chip->pwms)
 		return -ENOMEM;
 
-	pwm->chip = chip;
+	chip->base = ret;
 
-	mutex_lock(&pwm_lock);
+	for (i = 0; i < chip->npwm; i++) {
+		pwm = &chip->pwms[i];
 
-	if (chip->pwm_id >= 0 && _find_pwm(chip->pwm_id)) {
-		ret = -EBUSY;
-		goto out;
+		pwm->chip = chip;
+		pwm->pwm = chip->base + i;
+		pwm->hwpwm = i;
+
+		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
 	}
 
-	list_add_tail(&pwm->node, &pwm_list);
-out:
-	mutex_unlock(&pwm_lock);
+	bitmap_set(allocated_pwms, chip->base, chip->npwm);
 
-	if (ret)
-		kfree(pwm);
+	INIT_LIST_HEAD(&chip->list);
+	list_add(&chip->list, &pwm_chips);
+	of_pwmchip_add(chip);
 
+out:
+	mutex_unlock(&pwm_lock);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_add);
 
 /**
- * pwmchip_remove() - remove a pwm
- * @chip: the pwm
+ * pwmchip_remove() - remove a PWM chip
+ * @chip: the PWM chip to remove
  *
- * remove a pwm. This function may return busy if the pwm is still requested.
+ * Removes a PWM chip. This function may return busy if the PWM chip provides
+ * a PWM device that is still requested.
  */
 int pwmchip_remove(struct pwm_chip *chip)
 {
-	struct pwm_device *pwm;
+	unsigned int i;
 	int ret = 0;
 
 	mutex_lock(&pwm_lock);
 
-	pwm = _find_pwm(chip->pwm_id);
-	if (!pwm) {
-		ret = -ENOENT;
-		goto out;
-	}
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
-	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
-		ret = -EBUSY;
-		goto out;
+		if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
+			ret = -EBUSY;
+			goto out;
+		}
 	}
 
-	list_del(&pwm->node);
+	list_del_init(&chip->list);
+	of_pwmchip_remove(chip);
+	free_pwms(chip);
 
-	kfree(pwm);
 out:
 	mutex_unlock(&pwm_lock);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_remove);
 
+/**
+ * pwmchip_find() - iterator for locating a specific pwm_chip
+ * @data: data to pass to match function
+ * @match: callback function to check pwm_chip
+ */
+struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
+						       void *data))
+{
+	struct pwm_chip *ret = NULL;
+	struct pwm_chip *chip;
+
+	mutex_lock(&pwm_lock);
+
+	list_for_each_entry(chip, &pwm_chips, list) {
+		if (match(chip, data)) {
+			ret = chip;
+			break;
+		}
+	}
+
+	mutex_unlock(&pwm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_find);
+
 /*
  * pwm_request - request a PWM device
  */
-struct pwm_device *pwm_request(int pwm_id, const char *label)
+struct pwm_device *pwm_request(int pwm, const char *label)
 {
-	struct pwm_device *pwm;
+	struct pwm_device *dev;
 	int ret;
 
+	if (pwm < 0 || pwm >= MAX_PWMS)
+		return ERR_PTR(-EINVAL);
+
 	mutex_lock(&pwm_lock);
 
-	pwm = _find_pwm(pwm_id);
-	if (!pwm) {
-		pwm = ERR_PTR(-ENOENT);
+	dev = pwm_to_device(pwm);
+	if (!dev) {
+		dev = ERR_PTR(-ENODEV);
 		goto out;
 	}
 
-	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
-		pwm = ERR_PTR(-EBUSY);
+	if (test_bit(PWMF_REQUESTED, &dev->flags)) {
+		dev = ERR_PTR(-EBUSY);
 		goto out;
 	}
 
-	if (!try_module_get(pwm->chip->ops->owner)) {
-		pwm = ERR_PTR(-ENODEV);
+	if (!try_module_get(dev->chip->ops->owner)) {
+		dev = ERR_PTR(-ENODEV);
 		goto out;
 	}
 
-	if (pwm->chip->ops->request) {
-		ret = pwm->chip->ops->request(pwm->chip);
+	if (dev->chip->ops->request) {
+		ret = dev->chip->ops->request(dev->chip, dev);
 		if (ret) {
-			pwm = ERR_PTR(ret);
+			dev = ERR_PTR(ret);
 			goto out_put;
 		}
 	}
 
-	pwm->label = label;
-	set_bit(FLAG_REQUESTED, &pwm->flags);
+	set_bit(PWMF_REQUESTED, &dev->flags);
+	dev->label = label;
 
 	goto out;
 
 out_put:
-	module_put(pwm->chip->ops->owner);
+	module_put(dev->chip->ops->owner);
 out:
 	mutex_unlock(&pwm_lock);
 
-	return pwm;
+	return dev;
 }
 EXPORT_SYMBOL_GPL(pwm_request);
 
@@ -175,11 +268,14 @@ void pwm_free(struct pwm_device *pwm)
 {
 	mutex_lock(&pwm_lock);
 
-	if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) {
+	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
 		pr_warning("PWM device already freed\n");
 		goto out;
 	}
 
+	if (pwm->chip->ops->free)
+		pwm->chip->ops->free(pwm->chip, pwm);
+
 	pwm->label = NULL;
 
 	module_put(pwm->chip->ops->owner);
@@ -193,7 +289,7 @@ EXPORT_SYMBOL_GPL(pwm_free);
  */
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-	return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
+	return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
 }
 EXPORT_SYMBOL_GPL(pwm_config);
 
@@ -202,8 +298,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
  */
 int pwm_enable(struct pwm_device *pwm)
 {
-	if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
-		return pwm->chip->ops->enable(pwm->chip);
+	if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags))
+		return pwm->chip->ops->enable(pwm->chip, pwm);
 
 	return 0;
 }
@@ -214,7 +310,72 @@ EXPORT_SYMBOL_GPL(pwm_enable);
  */
 void pwm_disable(struct pwm_device *pwm)
 {
-	if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
-		pwm->chip->ops->disable(pwm->chip);
+	if (test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+		pwm->chip->ops->disable(pwm->chip, pwm);
 }
 EXPORT_SYMBOL_GPL(pwm_disable);
+
+#ifdef CONFIG_DEBUG_FS
+static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
+{
+	unsigned int i;
+
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+
+		seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label);
+
+		if (test_bit(PWMF_REQUESTED, &pwm->flags))
+			seq_printf(s, " requested");
+
+		if (test_bit(PWMF_ENABLED, &pwm->flags))
+			seq_printf(s, " enabled");
+
+		seq_printf(s, "\n");
+	}
+}
+
+static int pwm_show(struct seq_file *s, void *unused)
+{
+	const char *prefix = "";
+	struct pwm_chip *chip;
+
+	list_for_each_entry(chip, &pwm_chips, list) {
+		struct device *dev = chip->dev;
+
+		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
+			   dev->bus ? dev->bus->name : "no-bus",
+			   dev_name(dev), chip->npwm);
+
+		if (chip->ops->dbg_show)
+			chip->ops->dbg_show(chip, s);
+		else
+			pwm_dbg_show(chip, s);
+
+		prefix = "\n";
+	}
+
+	return 0;
+}
+
+static int pwm_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pwm_show, NULL);
+}
+
+static const struct file_operations pwm_ops = {
+	.open = pwm_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init pwm_debugfs_init(void)
+{
+	debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, &pwm_ops);
+
+	return 0;
+}
+
+subsys_initcall(pwm_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index df9681b..b00a91f 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -31,38 +31,73 @@ void pwm_disable(struct pwm_device *pwm);
 #ifdef CONFIG_PWM
 struct pwm_chip;
 
+enum {
+	PWMF_REQUESTED = 1 << 0,
+	PWMF_ENABLED = 1 << 1,
+};
+
+struct pwm_device {
+	const char		*label;
+	unsigned long		flags;
+	unsigned int		hwpwm;
+	unsigned int		pwm;
+	struct pwm_chip		*chip;
+	void			*chip_data;
+};
+
 /**
- * struct pwm_ops - PWM operations
+ * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
  * @config: configure duty cycles and period length for this PWM
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
+ * @dbg_show: optional routine to show contents in debugfs
+ * @owner: helps prevent removal of modules exporting active PWMs
  */
 struct pwm_ops {
-	int			(*request)(struct pwm_chip *chip);
-	void			(*free)(struct pwm_chip *chip);
-	int			(*config)(struct pwm_chip *chip, int duty_ns,
-						int period_ns);
-	int			(*enable)(struct pwm_chip *chip);
-	void			(*disable)(struct pwm_chip *chip);
+	int			(*request)(struct pwm_chip *chip,
+					   struct pwm_device *pwm);
+	void			(*free)(struct pwm_chip *chip,
+					struct pwm_device *pwm);
+	int			(*config)(struct pwm_chip *chip,
+					  struct pwm_device *pwm,
+					  int duty_ns, int period_ns);
+	int			(*enable)(struct pwm_chip *chip,
+					  struct pwm_device *pwm);
+	void			(*disable)(struct pwm_chip *chip,
+					   struct pwm_device *pwm);
+#ifdef CONFIG_DEBUG_FS
+	void			(*dbg_show)(struct pwm_chip *chip,
+					    struct seq_file *s);
+#endif
 	struct module		*owner;
 };
 
 /**
- * struct pwm_chip - abstract a PWM
- * @label: for diagnostics
- * @owner: helps prevent removal of modules exporting active PWMs
- * @ops: The callbacks for this PWM
+ * struct pwm_chip - abstract a PWM controller
+ * @dev: device providing the PWMs
+ * @ops: callbacks for this PWM controller
+ * @base: number of first PWM controlled by this chip
+ * @npwm: number of PWMs controlled by this chip
  */
 struct pwm_chip {
-	int			pwm_id;
-	const char		*label;
+	struct device		*dev;
+	struct list_head	list;
 	struct pwm_ops		*ops;
+	int			base;
+	unsigned int		npwm;
+
+	struct pwm_device	*pwms;
 };
 
+int pwm_set_chip_data(struct pwm_device *pwm, void *data);
+void *pwm_get_chip_data(struct pwm_device *pwm);
+
 int pwmchip_add(struct pwm_chip *chip);
 int pwmchip_remove(struct pwm_chip *chip);
+struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
+						       void *data));
 #endif
 
 #endif /* __LINUX_PWM_H */
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

Many PWM controllers provide access to more than a single PWM output and
may even share some resource among them. Allowing a PWM chip to provide
multiple PWM devices enables better sharing of those resources. As a
side-effect this change allows easy integration with the device tree
where a given PWM can be looked up based on the PWM chip's phandle and a
corresponding index.

This commit modifies the PWM core to support multiple PWMs per struct
pwm_chip. It achieves this in a similar way to how gpiolib works, by
allowing PWM ranges to be requested dynamically (pwm_chip.base == -1) or
starting at a given offset (pwm_chip.base >= 0). A chip specifies how
many PWMs it controls using the npwm member. Each of the functions in
the pwm_ops structure gets an additional struct pwm_device * argument
that points to the PWM device that is to be operated on. The per-chip
index of a PWM device is available in the hwpwm field.

The total maximum number of PWM devices is currently fixed to 1024 while
the data is actually stored in a radix tree, thus saving resources if
not all of them are used. The core no longer uses the global namespace,
which is only provided for backwards-compatibility until all PWM API
users are converted to use the PWM framework and request devices using
a per-chip index.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - get rid of pwm_desc structure and keep only struct pwm_device
  - keep a list of pwm_chip structures for fast and easy lookup
  - pass struct pwm_device directly to pwm_ops
  - add debugfs file

Changes in v2:
  - add 'struct device *dev' field to pwm_chip, drop label field
  - use radix tree for PWM descriptors
  - add pwm_set_chip_data() and pwm_get_chip_data() functions to allow
    storing and retrieving chip-specific per-PWM data

TODO:
  - we can probably get rid of the chip parameter in PWM ops because it
    is already tracked in struct pwm_device
  - merge with Sascha's patch

 drivers/pwm/core.c  |  301 +++++++++++++++++++++++++++++++++++++++------------
 include/linux/pwm.h |   61 ++++++++---
 2 files changed, 279 insertions(+), 83 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 71de479..d4d2249 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -17,154 +17,247 @@
  *  along with this program; see the file COPYING.  If not, write to
  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
 #include <linux/module.h>
+#include <linux/of_pwm.h>
 #include <linux/pwm.h>
+#include <linux/radix-tree.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
-struct pwm_device {
-	struct			pwm_chip *chip;
-	const char		*label;
-	unsigned long		flags;
-#define FLAG_REQUESTED	0
-#define FLAG_ENABLED	1
-	struct list_head	node;
-};
-
-static LIST_HEAD(pwm_list);
+#define MAX_PWMS 1024
 
 static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_chips);
+static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
+static RADIX_TREE(pwm_tree, GFP_KERNEL);
 
-static struct pwm_device *_find_pwm(int pwm_id)
+static struct pwm_device *pwm_to_device(unsigned int pwm)
 {
-	struct pwm_device *pwm;
+	return radix_tree_lookup(&pwm_tree, pwm);
+}
+
+static int alloc_pwms(int pwm, unsigned int count)
+{
+	unsigned int from = 0;
+	unsigned int start;
 
-	list_for_each_entry(pwm, &pwm_list, node) {
-		if (pwm->chip->pwm_id == pwm_id)
-			return pwm;
+	if (pwm >= MAX_PWMS)
+		return -EINVAL;
+
+	if (pwm >= 0)
+		from = pwm;
+
+	start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from,
+					   count, 0);
+
+	if (pwm >= 0 && start != pwm)
+		return -EEXIST;
+
+	if (start + count > MAX_PWMS)
+		return -ENOSPC;
+
+	return start;
+}
+
+static void free_pwms(struct pwm_chip *chip)
+{
+	unsigned int i;
+
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+		radix_tree_delete(&pwm_tree, pwm->pwm);
 	}
 
-	return NULL;
+	bitmap_clear(allocated_pwms, chip->base, chip->npwm);
+
+	kfree(chip->pwms);
+	chip->pwms = NULL;
+}
+
+/**
+ * pwm_set_chip_data - set private chip data for a PWM
+ * @pwm: PWM device
+ * @data: pointer to chip-specific data
+ */
+int pwm_set_chip_data(struct pwm_device *pwm, void *data)
+{
+	if (!pwm)
+		return -EINVAL;
+
+	pwm->chip_data = data;
+
+	return 0;
 }
 
 /**
- * pwmchip_add() - register a new pwm
- * @chip: the pwm
+ * pwm_get_chip_data - get private chip data for a PWM
+ * @pwm: PWM device
+ */
+void *pwm_get_chip_data(struct pwm_device *pwm)
+{
+	return pwm ? pwm->chip_data : NULL;
+}
+
+/**
+ * pwmchip_add() - register a new PWM chip
+ * @chip: the PWM chip to add
  *
- * register a new pwm. pwm->pwm_id must be initialized. if pwm_id < 0 then
- * a dynamically assigned id will be used, otherwise the id specified,
+ * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
+ * will be used.
  */
 int pwmchip_add(struct pwm_chip *chip)
 {
 	struct pwm_device *pwm;
-	int ret = 0;
+	unsigned int i;
+	int ret;
 
-	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
-	if (!pwm)
+	mutex_lock(&pwm_lock);
+
+	ret = alloc_pwms(chip->base, chip->npwm);
+	if (ret < 0)
+		goto out;
+
+	chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL);
+	if (!chip->pwms)
 		return -ENOMEM;
 
-	pwm->chip = chip;
+	chip->base = ret;
 
-	mutex_lock(&pwm_lock);
+	for (i = 0; i < chip->npwm; i++) {
+		pwm = &chip->pwms[i];
 
-	if (chip->pwm_id >= 0 && _find_pwm(chip->pwm_id)) {
-		ret = -EBUSY;
-		goto out;
+		pwm->chip = chip;
+		pwm->pwm = chip->base + i;
+		pwm->hwpwm = i;
+
+		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
 	}
 
-	list_add_tail(&pwm->node, &pwm_list);
-out:
-	mutex_unlock(&pwm_lock);
+	bitmap_set(allocated_pwms, chip->base, chip->npwm);
 
-	if (ret)
-		kfree(pwm);
+	INIT_LIST_HEAD(&chip->list);
+	list_add(&chip->list, &pwm_chips);
+	of_pwmchip_add(chip);
 
+out:
+	mutex_unlock(&pwm_lock);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_add);
 
 /**
- * pwmchip_remove() - remove a pwm
- * @chip: the pwm
+ * pwmchip_remove() - remove a PWM chip
+ * @chip: the PWM chip to remove
  *
- * remove a pwm. This function may return busy if the pwm is still requested.
+ * Removes a PWM chip. This function may return busy if the PWM chip provides
+ * a PWM device that is still requested.
  */
 int pwmchip_remove(struct pwm_chip *chip)
 {
-	struct pwm_device *pwm;
+	unsigned int i;
 	int ret = 0;
 
 	mutex_lock(&pwm_lock);
 
-	pwm = _find_pwm(chip->pwm_id);
-	if (!pwm) {
-		ret = -ENOENT;
-		goto out;
-	}
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
-	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
-		ret = -EBUSY;
-		goto out;
+		if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
+			ret = -EBUSY;
+			goto out;
+		}
 	}
 
-	list_del(&pwm->node);
+	list_del_init(&chip->list);
+	of_pwmchip_remove(chip);
+	free_pwms(chip);
 
-	kfree(pwm);
 out:
 	mutex_unlock(&pwm_lock);
-
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pwmchip_remove);
 
+/**
+ * pwmchip_find() - iterator for locating a specific pwm_chip
+ * @data: data to pass to match function
+ * @match: callback function to check pwm_chip
+ */
+struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
+						       void *data))
+{
+	struct pwm_chip *ret = NULL;
+	struct pwm_chip *chip;
+
+	mutex_lock(&pwm_lock);
+
+	list_for_each_entry(chip, &pwm_chips, list) {
+		if (match(chip, data)) {
+			ret = chip;
+			break;
+		}
+	}
+
+	mutex_unlock(&pwm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_find);
+
 /*
  * pwm_request - request a PWM device
  */
-struct pwm_device *pwm_request(int pwm_id, const char *label)
+struct pwm_device *pwm_request(int pwm, const char *label)
 {
-	struct pwm_device *pwm;
+	struct pwm_device *dev;
 	int ret;
 
+	if (pwm < 0 || pwm >= MAX_PWMS)
+		return ERR_PTR(-EINVAL);
+
 	mutex_lock(&pwm_lock);
 
-	pwm = _find_pwm(pwm_id);
-	if (!pwm) {
-		pwm = ERR_PTR(-ENOENT);
+	dev = pwm_to_device(pwm);
+	if (!dev) {
+		dev = ERR_PTR(-ENODEV);
 		goto out;
 	}
 
-	if (test_bit(FLAG_REQUESTED, &pwm->flags)) {
-		pwm = ERR_PTR(-EBUSY);
+	if (test_bit(PWMF_REQUESTED, &dev->flags)) {
+		dev = ERR_PTR(-EBUSY);
 		goto out;
 	}
 
-	if (!try_module_get(pwm->chip->ops->owner)) {
-		pwm = ERR_PTR(-ENODEV);
+	if (!try_module_get(dev->chip->ops->owner)) {
+		dev = ERR_PTR(-ENODEV);
 		goto out;
 	}
 
-	if (pwm->chip->ops->request) {
-		ret = pwm->chip->ops->request(pwm->chip);
+	if (dev->chip->ops->request) {
+		ret = dev->chip->ops->request(dev->chip, dev);
 		if (ret) {
-			pwm = ERR_PTR(ret);
+			dev = ERR_PTR(ret);
 			goto out_put;
 		}
 	}
 
-	pwm->label = label;
-	set_bit(FLAG_REQUESTED, &pwm->flags);
+	set_bit(PWMF_REQUESTED, &dev->flags);
+	dev->label = label;
 
 	goto out;
 
 out_put:
-	module_put(pwm->chip->ops->owner);
+	module_put(dev->chip->ops->owner);
 out:
 	mutex_unlock(&pwm_lock);
 
-	return pwm;
+	return dev;
 }
 EXPORT_SYMBOL_GPL(pwm_request);
 
@@ -175,11 +268,14 @@ void pwm_free(struct pwm_device *pwm)
 {
 	mutex_lock(&pwm_lock);
 
-	if (!test_and_clear_bit(FLAG_REQUESTED, &pwm->flags)) {
+	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
 		pr_warning("PWM device already freed\n");
 		goto out;
 	}
 
+	if (pwm->chip->ops->free)
+		pwm->chip->ops->free(pwm->chip, pwm);
+
 	pwm->label = NULL;
 
 	module_put(pwm->chip->ops->owner);
@@ -193,7 +289,7 @@ EXPORT_SYMBOL_GPL(pwm_free);
  */
 int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-	return pwm->chip->ops->config(pwm->chip, duty_ns, period_ns);
+	return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
 }
 EXPORT_SYMBOL_GPL(pwm_config);
 
@@ -202,8 +298,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
  */
 int pwm_enable(struct pwm_device *pwm)
 {
-	if (!test_and_set_bit(FLAG_ENABLED, &pwm->flags))
-		return pwm->chip->ops->enable(pwm->chip);
+	if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags))
+		return pwm->chip->ops->enable(pwm->chip, pwm);
 
 	return 0;
 }
@@ -214,7 +310,72 @@ EXPORT_SYMBOL_GPL(pwm_enable);
  */
 void pwm_disable(struct pwm_device *pwm)
 {
-	if (test_and_clear_bit(FLAG_ENABLED, &pwm->flags))
-		pwm->chip->ops->disable(pwm->chip);
+	if (test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+		pwm->chip->ops->disable(pwm->chip, pwm);
 }
 EXPORT_SYMBOL_GPL(pwm_disable);
+
+#ifdef CONFIG_DEBUG_FS
+static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
+{
+	unsigned int i;
+
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+
+		seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label);
+
+		if (test_bit(PWMF_REQUESTED, &pwm->flags))
+			seq_printf(s, " requested");
+
+		if (test_bit(PWMF_ENABLED, &pwm->flags))
+			seq_printf(s, " enabled");
+
+		seq_printf(s, "\n");
+	}
+}
+
+static int pwm_show(struct seq_file *s, void *unused)
+{
+	const char *prefix = "";
+	struct pwm_chip *chip;
+
+	list_for_each_entry(chip, &pwm_chips, list) {
+		struct device *dev = chip->dev;
+
+		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
+			   dev->bus ? dev->bus->name : "no-bus",
+			   dev_name(dev), chip->npwm);
+
+		if (chip->ops->dbg_show)
+			chip->ops->dbg_show(chip, s);
+		else
+			pwm_dbg_show(chip, s);
+
+		prefix = "\n";
+	}
+
+	return 0;
+}
+
+static int pwm_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pwm_show, NULL);
+}
+
+static const struct file_operations pwm_ops = {
+	.open = pwm_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init pwm_debugfs_init(void)
+{
+	debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, &pwm_ops);
+
+	return 0;
+}
+
+subsys_initcall(pwm_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index df9681b..b00a91f 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -31,38 +31,73 @@ void pwm_disable(struct pwm_device *pwm);
 #ifdef CONFIG_PWM
 struct pwm_chip;
 
+enum {
+	PWMF_REQUESTED = 1 << 0,
+	PWMF_ENABLED = 1 << 1,
+};
+
+struct pwm_device {
+	const char		*label;
+	unsigned long		flags;
+	unsigned int		hwpwm;
+	unsigned int		pwm;
+	struct pwm_chip		*chip;
+	void			*chip_data;
+};
+
 /**
- * struct pwm_ops - PWM operations
+ * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
  * @config: configure duty cycles and period length for this PWM
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
+ * @dbg_show: optional routine to show contents in debugfs
+ * @owner: helps prevent removal of modules exporting active PWMs
  */
 struct pwm_ops {
-	int			(*request)(struct pwm_chip *chip);
-	void			(*free)(struct pwm_chip *chip);
-	int			(*config)(struct pwm_chip *chip, int duty_ns,
-						int period_ns);
-	int			(*enable)(struct pwm_chip *chip);
-	void			(*disable)(struct pwm_chip *chip);
+	int			(*request)(struct pwm_chip *chip,
+					   struct pwm_device *pwm);
+	void			(*free)(struct pwm_chip *chip,
+					struct pwm_device *pwm);
+	int			(*config)(struct pwm_chip *chip,
+					  struct pwm_device *pwm,
+					  int duty_ns, int period_ns);
+	int			(*enable)(struct pwm_chip *chip,
+					  struct pwm_device *pwm);
+	void			(*disable)(struct pwm_chip *chip,
+					   struct pwm_device *pwm);
+#ifdef CONFIG_DEBUG_FS
+	void			(*dbg_show)(struct pwm_chip *chip,
+					    struct seq_file *s);
+#endif
 	struct module		*owner;
 };
 
 /**
- * struct pwm_chip - abstract a PWM
- * @label: for diagnostics
- * @owner: helps prevent removal of modules exporting active PWMs
- * @ops: The callbacks for this PWM
+ * struct pwm_chip - abstract a PWM controller
+ * @dev: device providing the PWMs
+ * @ops: callbacks for this PWM controller
+ * @base: number of first PWM controlled by this chip
+ * @npwm: number of PWMs controlled by this chip
  */
 struct pwm_chip {
-	int			pwm_id;
-	const char		*label;
+	struct device		*dev;
+	struct list_head	list;
 	struct pwm_ops		*ops;
+	int			base;
+	unsigned int		npwm;
+
+	struct pwm_device	*pwms;
 };
 
+int pwm_set_chip_data(struct pwm_device *pwm, void *data);
+void *pwm_get_chip_data(struct pwm_device *pwm);
+
 int pwmchip_add(struct pwm_chip *chip);
 int pwmchip_remove(struct pwm_chip *chip);
+struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
+						       void *data));
 #endif
 
 #endif /* __LINUX_PWM_H */
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

This patch adds helpers to support device tree bindings for the generic
PWM API. Device tree binding documentation for PWM controllers is also
provided.

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - none

Changes in v2:
  - add device tree binding documentation
  - add of_xlate to parse controller-specific PWM-specifier

 Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
 drivers/of/Kconfig                            |    6 +
 drivers/of/Makefile                           |    1 +
 drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
 include/linux/of_pwm.h                        |   51 ++++++++++
 include/linux/pwm.h                           |   17 +++
 6 files changed, 253 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt
 create mode 100644 drivers/of/pwm.c
 create mode 100644 include/linux/of_pwm.h

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
new file mode 100644
index 0000000..9421fe7
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -0,0 +1,48 @@
+Specifying PWM information for devices
+======================================
+
+1) PWM user nodes
+-----------------
+
+PWM users should specify a list of PWM devices that they want to use
+with a property containing a 'pwm-list':
+
+	pwm-list ::= <single-pwm> [pwm-list]
+	single-pwm ::= <pwm-phandle> <pwm-specifier>
+	pwm-phandle : phandle to PWM controller node
+	pwm-specifier : array of #pwm-cells specifying the given PWM
+			(controller specific)
+
+PWM properties should be named "[<name>-]pwms". Exact meaning of each
+pwms property must be documented in the device tree binding for each
+device.
+
+The following example could be used to describe a PWM-based backlight
+device:
+
+	pwm: pwm {
+		#pwm-cells = <2>;
+	};
+
+	[...]
+
+	bl: backlight {
+		pwms = <&pwm 0 5000000>;
+	};
+
+pwm-specifier typically encodes the chip-relative PWM number and the PWM
+period in nanoseconds.
+
+2) PWM controller nodes
+-----------------------
+
+PWM controller nodes must specify the number of cells used for the
+specifier using the '#pwm-cells' property.
+
+An example PWM controller might look like this:
+
+	pwm: pwm@7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6ea51dc..d47b8ee 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -57,6 +57,12 @@ config OF_GPIO
 	help
 	  OpenFirmware GPIO accessors
 
+config OF_PWM
+	def_bool y
+	depends on PWM
+	help
+	  OpenFirmware PWM accessors
+
 config OF_I2C
 	def_tristate I2C
 	depends on I2C && !SPARC
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index a73f5a5..3dd13e3 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_OF_ADDRESS)  += address.o
 obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
+obj-$(CONFIG_OF_PWM)	+= pwm.o
 obj-$(CONFIG_OF_I2C)	+= of_i2c.o
 obj-$(CONFIG_OF_NET)	+= of_net.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
diff --git a/drivers/of/pwm.c b/drivers/of/pwm.c
new file mode 100644
index 0000000..d6f7f33
--- /dev/null
+++ b/drivers/of/pwm.c
@@ -0,0 +1,130 @@
+/*
+ * OF helpers for the PWM API
+ *
+ * Copyright (c) 2011 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pwm.h>
+
+static int of_pwmchip_is_match(struct pwm_chip *chip, void *data)
+{
+	return chip->dev ? chip->dev->of_node == data : 0;
+}
+
+/**
+ * of_node_to_pwmchip() - finds the PWM chip associated with a device node
+ * @np: device node of the PWM chip
+ *
+ * Returns a pointer to the PWM chip associated with the specified device
+ * node or NULL if the device node doesn't represent a PWM chip.
+ */
+struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+	return pwmchip_find(np, of_pwmchip_is_match);
+}
+
+int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
+			struct pwm_spec *spec)
+{
+	if (pc->of_pwm_n_cells < 2)
+		return -EINVAL;
+
+	if (args->args_count < pc->of_pwm_n_cells)
+		return -EINVAL;
+
+	if (args->args[0] >= pc->npwm)
+		return -EINVAL;
+
+	if (spec)
+		spec->period = args->args[1];
+
+	return args->args[0];
+}
+
+void of_pwmchip_add(struct pwm_chip *chip)
+{
+	if (!chip->dev || !chip->dev->of_node)
+		return;
+
+	if (!chip->of_xlate) {
+		chip->of_xlate = of_pwm_simple_xlate;
+		chip->of_pwm_n_cells = 2;
+	}
+
+	of_node_get(chip->dev->of_node);
+}
+
+void of_pwmchip_remove(struct pwm_chip *chip)
+{
+	if (chip->dev && chip->dev->of_node)
+		of_node_put(chip->dev->of_node);
+}
+
+/**
+ * of_get_named_pwm() - get a PWM number and period to use with the PWM API
+ * @np: device node to get the PWM from
+ * @propname: property name containing PWM specifier(s)
+ * @index: index of the PWM
+ * @spec: a pointer to a struct pwm_spec to fill in
+ *
+ * Returns PWM number to use with the Linux generic PWM API or a negative
+ * error code on failure. If @spec is not NULL the function fills in the
+ * values parsed from the device tree.
+ */
+int of_get_named_pwm(struct device_node *np, const char *propname,
+		     int index, struct pwm_spec *spec)
+{
+	struct of_phandle_args args;
+	struct pwm_chip *pc;
+	int ret;
+
+	ret = of_parse_phandle_with_args(np, propname, "#pwm-cells", index,
+					  &args);
+	if (ret) {
+		pr_debug("%s(): can't parse pwms property\n", __func__);
+		goto out;
+	}
+
+	pc = of_node_to_pwmchip(args.np);
+	if (!pc) {
+		ret = -ENODEV;
+		goto put;
+	}
+
+	if (args.args_count != pc->of_pwm_n_cells) {
+		pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
+			 args.np->full_name);
+		ret = -EINVAL;
+		goto put;
+	}
+
+	/*
+	 * reset the specifier structure since .of_xlate might decide not to
+	 * fill it in
+	 */
+	if (spec)
+		spec->period = 0;
+
+	ret = pc->of_xlate(pc, &args, spec);
+	if (ret < 0)
+		goto put;
+
+	ret += pc->base;
+
+put:
+	of_node_put(args.np);
+out:
+	pr_debug("%s() exited with status %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(of_get_named_pwm);
diff --git a/include/linux/of_pwm.h b/include/linux/of_pwm.h
new file mode 100644
index 0000000..a6af951
--- /dev/null
+++ b/include/linux/of_pwm.h
@@ -0,0 +1,51 @@
+/*
+ * OF helpers for the PWM API
+ *
+ * Copyright (c) 2011 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_PWM_H
+#define __LINUX_OF_PWM_H
+
+#include <linux/pwm.h>
+
+struct device_node;
+
+#ifdef CONFIG_OF_PWM
+
+struct pwm_chip *of_node_to_pwmchip(struct device_node *np);
+int of_get_named_pwm(struct device_node *np, const char *propname,
+		     int index, struct pwm_spec *spec);
+void of_pwmchip_add(struct pwm_chip *pc);
+void of_pwmchip_remove(struct pwm_chip *pc);
+
+#else
+
+static inline struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+	return NULL;
+}
+
+static inline int of_get_named_pwm(struct device_node *np,
+				   const char *propname, int index,
+				   unsigned int *period_ns)
+{
+	return -ENOSYS;
+}
+
+static inline void of_pwmchip_add(struct pwm_chip *pc)
+{
+}
+
+static inline void of_pwmchip_remove(struct pwm_chip *pc)
+{
+}
+
+#endif /* CONFIG_OF_PWM */
+
+#endif /* __LINUX_OF_PWM_H */
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index b00a91f..a7cb543 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/of.h>
+
 struct pwm_device;
 
 /*
@@ -75,6 +77,14 @@ struct pwm_ops {
 };
 
 /**
+ * struct pwm_spec - device tree PWM specifier
+ * @period: PWM period (in nanoseconds)
+ */
+struct pwm_spec {
+	unsigned int period;
+};
+
+/**
  * struct pwm_chip - abstract a PWM controller
  * @dev: device providing the PWMs
  * @ops: callbacks for this PWM controller
@@ -89,6 +99,13 @@ struct pwm_chip {
 	unsigned int		npwm;
 
 	struct pwm_device	*pwms;
+
+#ifdef CONFIG_OF_PWM
+	int			(*of_xlate)(struct pwm_chip *pc,
+					    const struct of_phandle_args *args,
+					    struct pwm_spec *spec);
+	unsigned int		of_pwm_n_cells;
+#endif
 };
 
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds helpers to support device tree bindings for the generic
PWM API. Device tree binding documentation for PWM controllers is also
provided.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - none

Changes in v2:
  - add device tree binding documentation
  - add of_xlate to parse controller-specific PWM-specifier

 Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
 drivers/of/Kconfig                            |    6 +
 drivers/of/Makefile                           |    1 +
 drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
 include/linux/of_pwm.h                        |   51 ++++++++++
 include/linux/pwm.h                           |   17 +++
 6 files changed, 253 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt
 create mode 100644 drivers/of/pwm.c
 create mode 100644 include/linux/of_pwm.h

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
new file mode 100644
index 0000000..9421fe7
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -0,0 +1,48 @@
+Specifying PWM information for devices
+======================================
+
+1) PWM user nodes
+-----------------
+
+PWM users should specify a list of PWM devices that they want to use
+with a property containing a 'pwm-list':
+
+	pwm-list ::= <single-pwm> [pwm-list]
+	single-pwm ::= <pwm-phandle> <pwm-specifier>
+	pwm-phandle : phandle to PWM controller node
+	pwm-specifier : array of #pwm-cells specifying the given PWM
+			(controller specific)
+
+PWM properties should be named "[<name>-]pwms". Exact meaning of each
+pwms property must be documented in the device tree binding for each
+device.
+
+The following example could be used to describe a PWM-based backlight
+device:
+
+	pwm: pwm {
+		#pwm-cells = <2>;
+	};
+
+	[...]
+
+	bl: backlight {
+		pwms = <&pwm 0 5000000>;
+	};
+
+pwm-specifier typically encodes the chip-relative PWM number and the PWM
+period in nanoseconds.
+
+2) PWM controller nodes
+-----------------------
+
+PWM controller nodes must specify the number of cells used for the
+specifier using the '#pwm-cells' property.
+
+An example PWM controller might look like this:
+
+	pwm: pwm at 7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 6ea51dc..d47b8ee 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -57,6 +57,12 @@ config OF_GPIO
 	help
 	  OpenFirmware GPIO accessors
 
+config OF_PWM
+	def_bool y
+	depends on PWM
+	help
+	  OpenFirmware PWM accessors
+
 config OF_I2C
 	def_tristate I2C
 	depends on I2C && !SPARC
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index a73f5a5..3dd13e3 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_OF_ADDRESS)  += address.o
 obj-$(CONFIG_OF_IRQ)    += irq.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
+obj-$(CONFIG_OF_PWM)	+= pwm.o
 obj-$(CONFIG_OF_I2C)	+= of_i2c.o
 obj-$(CONFIG_OF_NET)	+= of_net.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
diff --git a/drivers/of/pwm.c b/drivers/of/pwm.c
new file mode 100644
index 0000000..d6f7f33
--- /dev/null
+++ b/drivers/of/pwm.c
@@ -0,0 +1,130 @@
+/*
+ * OF helpers for the PWM API
+ *
+ * Copyright (c) 2011 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pwm.h>
+
+static int of_pwmchip_is_match(struct pwm_chip *chip, void *data)
+{
+	return chip->dev ? chip->dev->of_node == data : 0;
+}
+
+/**
+ * of_node_to_pwmchip() - finds the PWM chip associated with a device node
+ * @np: device node of the PWM chip
+ *
+ * Returns a pointer to the PWM chip associated with the specified device
+ * node or NULL if the device node doesn't represent a PWM chip.
+ */
+struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+	return pwmchip_find(np, of_pwmchip_is_match);
+}
+
+int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
+			struct pwm_spec *spec)
+{
+	if (pc->of_pwm_n_cells < 2)
+		return -EINVAL;
+
+	if (args->args_count < pc->of_pwm_n_cells)
+		return -EINVAL;
+
+	if (args->args[0] >= pc->npwm)
+		return -EINVAL;
+
+	if (spec)
+		spec->period = args->args[1];
+
+	return args->args[0];
+}
+
+void of_pwmchip_add(struct pwm_chip *chip)
+{
+	if (!chip->dev || !chip->dev->of_node)
+		return;
+
+	if (!chip->of_xlate) {
+		chip->of_xlate = of_pwm_simple_xlate;
+		chip->of_pwm_n_cells = 2;
+	}
+
+	of_node_get(chip->dev->of_node);
+}
+
+void of_pwmchip_remove(struct pwm_chip *chip)
+{
+	if (chip->dev && chip->dev->of_node)
+		of_node_put(chip->dev->of_node);
+}
+
+/**
+ * of_get_named_pwm() - get a PWM number and period to use with the PWM API
+ * @np: device node to get the PWM from
+ * @propname: property name containing PWM specifier(s)
+ * @index: index of the PWM
+ * @spec: a pointer to a struct pwm_spec to fill in
+ *
+ * Returns PWM number to use with the Linux generic PWM API or a negative
+ * error code on failure. If @spec is not NULL the function fills in the
+ * values parsed from the device tree.
+ */
+int of_get_named_pwm(struct device_node *np, const char *propname,
+		     int index, struct pwm_spec *spec)
+{
+	struct of_phandle_args args;
+	struct pwm_chip *pc;
+	int ret;
+
+	ret = of_parse_phandle_with_args(np, propname, "#pwm-cells", index,
+					  &args);
+	if (ret) {
+		pr_debug("%s(): can't parse pwms property\n", __func__);
+		goto out;
+	}
+
+	pc = of_node_to_pwmchip(args.np);
+	if (!pc) {
+		ret = -ENODEV;
+		goto put;
+	}
+
+	if (args.args_count != pc->of_pwm_n_cells) {
+		pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
+			 args.np->full_name);
+		ret = -EINVAL;
+		goto put;
+	}
+
+	/*
+	 * reset the specifier structure since .of_xlate might decide not to
+	 * fill it in
+	 */
+	if (spec)
+		spec->period = 0;
+
+	ret = pc->of_xlate(pc, &args, spec);
+	if (ret < 0)
+		goto put;
+
+	ret += pc->base;
+
+put:
+	of_node_put(args.np);
+out:
+	pr_debug("%s() exited with status %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(of_get_named_pwm);
diff --git a/include/linux/of_pwm.h b/include/linux/of_pwm.h
new file mode 100644
index 0000000..a6af951
--- /dev/null
+++ b/include/linux/of_pwm.h
@@ -0,0 +1,51 @@
+/*
+ * OF helpers for the PWM API
+ *
+ * Copyright (c) 2011 Avionic Design GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_OF_PWM_H
+#define __LINUX_OF_PWM_H
+
+#include <linux/pwm.h>
+
+struct device_node;
+
+#ifdef CONFIG_OF_PWM
+
+struct pwm_chip *of_node_to_pwmchip(struct device_node *np);
+int of_get_named_pwm(struct device_node *np, const char *propname,
+		     int index, struct pwm_spec *spec);
+void of_pwmchip_add(struct pwm_chip *pc);
+void of_pwmchip_remove(struct pwm_chip *pc);
+
+#else
+
+static inline struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+	return NULL;
+}
+
+static inline int of_get_named_pwm(struct device_node *np,
+				   const char *propname, int index,
+				   unsigned int *period_ns)
+{
+	return -ENOSYS;
+}
+
+static inline void of_pwmchip_add(struct pwm_chip *pc)
+{
+}
+
+static inline void of_pwmchip_remove(struct pwm_chip *pc)
+{
+}
+
+#endif /* CONFIG_OF_PWM */
+
+#endif /* __LINUX_OF_PWM_H */
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index b00a91f..a7cb543 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/of.h>
+
 struct pwm_device;
 
 /*
@@ -75,6 +77,14 @@ struct pwm_ops {
 };
 
 /**
+ * struct pwm_spec - device tree PWM specifier
+ * @period: PWM period (in nanoseconds)
+ */
+struct pwm_spec {
+	unsigned int period;
+};
+
+/**
  * struct pwm_chip - abstract a PWM controller
  * @dev: device providing the PWMs
  * @ops: callbacks for this PWM controller
@@ -89,6 +99,13 @@ struct pwm_chip {
 	unsigned int		npwm;
 
 	struct pwm_device	*pwms;
+
+#ifdef CONFIG_OF_PWM
+	int			(*of_xlate)(struct pwm_chip *pc,
+					    const struct of_phandle_args *args,
+					    struct pwm_spec *spec);
+	unsigned int		of_pwm_n_cells;
+#endif
 };
 
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: Simon Que, Bill Huang,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

From: Simon Que <sque-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

PWM clock source registers in Tegra 2 have different clock source selection bit
fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
are located at bit field bit[30:28] while others are at bit field bit[31:30] in
their respective clock source register.

This patch updates the clock programming to correctly reflect that, by adding a
flag to indicate the alternate bit field format and checking for it when
selecting a clock source (parent clock).

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
Signed-off-by: Bill Huang <bilhuang-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Simon Que <sque-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 arch/arm/mach-tegra/clock.h         |    1 +
 arch/arm/mach-tegra/tegra2_clocks.c |   28 ++++++++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bc30065..e18d77e 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -49,6 +49,7 @@
 #define PLLM                    (1 << 20)
 #define DIV_U71_INT             (1 << 21)
 #define DIV_U71_IDLE            (1 << 22)
+#define PERIPH_SOURCE_CLK_4BIT	(1 << 23)
 #define ENABLE_ON_INIT		(1 << 28)
 #define PERIPH_ON_APB           (1 << 29)
 
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 74d314f..379f201 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -69,6 +69,8 @@
 
 #define PERIPH_CLK_SOURCE_MASK		(3<<30)
 #define PERIPH_CLK_SOURCE_SHIFT		30
+#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
 #define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
 #define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
 #define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
@@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
 	u32 val = clk_readl(c->reg);
 	const struct clk_mux_sel *mux = NULL;
 	const struct clk_mux_sel *sel;
+	u32 shift;
+
+	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
+		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
+	else
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+
 	if (c->flags & MUX) {
 		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
+			if (val >> shift == sel->value)
 				mux = sel;
 		}
 		BUG_ON(!mux);
@@ -1023,12 +1032,23 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
 {
 	u32 val;
 	const struct clk_mux_sel *sel;
+	u32 mask, shift;
+
 	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+	if (c->flags & PERIPH_SOURCE_CLK_4BIT) {
+		mask = PERIPH_CLK_SOURCE_4BIT_MASK;
+		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
+	} else {
+		mask = PERIPH_CLK_SOURCE_MASK;
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+	}
+
 	for (sel = c->inputs; sel->input != NULL; sel++) {
 		if (sel->input == p) {
 			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_MASK;
-			val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
+			val &= ~mask;
+			val |= (sel->value) << shift;
 
 			if (c->refcnt)
 				clk_enable(p);
@@ -2126,7 +2146,7 @@ static struct clk tegra_list_clks[] = {
 	PERIPH_CLK("i2s2",	"tegra-i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
-	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
+	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | PERIPH_SOURCE_CLK_4BIT),
 	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

From: Simon Que <sque@chromium.org>

PWM clock source registers in Tegra 2 have different clock source selection bit
fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
are located at bit field bit[30:28] while others are at bit field bit[31:30] in
their respective clock source register.

This patch updates the clock programming to correctly reflect that, by adding a
flag to indicate the alternate bit field format and checking for it when
selecting a clock source (parent clock).

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Signed-off-by: Bill Huang <bilhuang@nvidia.com>
Signed-off-by: Simon Que <sque@chromium.org>
---
 arch/arm/mach-tegra/clock.h         |    1 +
 arch/arm/mach-tegra/tegra2_clocks.c |   28 ++++++++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bc30065..e18d77e 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -49,6 +49,7 @@
 #define PLLM                    (1 << 20)
 #define DIV_U71_INT             (1 << 21)
 #define DIV_U71_IDLE            (1 << 22)
+#define PERIPH_SOURCE_CLK_4BIT	(1 << 23)
 #define ENABLE_ON_INIT		(1 << 28)
 #define PERIPH_ON_APB           (1 << 29)
 
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 74d314f..379f201 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -69,6 +69,8 @@
 
 #define PERIPH_CLK_SOURCE_MASK		(3<<30)
 #define PERIPH_CLK_SOURCE_SHIFT		30
+#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
 #define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
 #define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
 #define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
@@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
 	u32 val = clk_readl(c->reg);
 	const struct clk_mux_sel *mux = NULL;
 	const struct clk_mux_sel *sel;
+	u32 shift;
+
+	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
+		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
+	else
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+
 	if (c->flags & MUX) {
 		for (sel = c->inputs; sel->input != NULL; sel++) {
-			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
+			if (val >> shift == sel->value)
 				mux = sel;
 		}
 		BUG_ON(!mux);
@@ -1023,12 +1032,23 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
 {
 	u32 val;
 	const struct clk_mux_sel *sel;
+	u32 mask, shift;
+
 	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+	if (c->flags & PERIPH_SOURCE_CLK_4BIT) {
+		mask = PERIPH_CLK_SOURCE_4BIT_MASK;
+		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
+	} else {
+		mask = PERIPH_CLK_SOURCE_MASK;
+		shift = PERIPH_CLK_SOURCE_SHIFT;
+	}
+
 	for (sel = c->inputs; sel->input != NULL; sel++) {
 		if (sel->input == p) {
 			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_MASK;
-			val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
+			val &= ~mask;
+			val |= (sel->value) << shift;
 
 			if (c->refcnt)
 				clk_enable(p);
@@ -2126,7 +2146,7 @@ static struct clk tegra_list_clks[] = {
 	PERIPH_CLK("i2s2",	"tegra-i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
-	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
+	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71 | PERIPH_SOURCE_CLK_4BIT),
 	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
 	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 05/10] arm/tegra: Provide clock for only one PWM controller
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

A subsequent patch will add a generic PWM API driver for the Tegra2 PWFM
controller, supporting all four PWM devices with a single PWM chip. The
device will be named tegra-pwm and only one clock needs to be provided.

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
Changes in v3:
  - none

Changes in v2:
  - none

 arch/arm/mach-tegra/tegra2_clocks.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 379f201..6eec82d 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2245,10 +2245,7 @@ static struct clk_duplicate tegra_clk_duplicates[] = {
 	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
 	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
 	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("pwm", "tegra_pwm.0", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+	CLK_DUPLICATE("pwm", "tegra-pwm", NULL),
 	CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
 	CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
 	CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 05/10] arm/tegra: Provide clock for only one PWM controller
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

A subsequent patch will add a generic PWM API driver for the Tegra2 PWFM
controller, supporting all four PWM devices with a single PWM chip. The
device will be named tegra-pwm and only one clock needs to be provided.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Acked-by: Stephen Warren <swarren@nvidia.com>
---
Changes in v3:
  - none

Changes in v2:
  - none

 arch/arm/mach-tegra/tegra2_clocks.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 379f201..6eec82d 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2245,10 +2245,7 @@ static struct clk_duplicate tegra_clk_duplicates[] = {
 	CLK_DUPLICATE("usbd", "tegra-otg", NULL),
 	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
 	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
-	CLK_DUPLICATE("pwm", "tegra_pwm.0", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
-	CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+	CLK_DUPLICATE("pwm", "tegra-pwm", NULL),
 	CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
 	CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
 	CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

This commit adds a generic PWM framework driver for the PWFM controller
found on NVIDIA Tegra SoCs. The driver is based on code from the
Chromium kernel tree and was originally written by Gary King (NVIDIA)
and later modified by Simon Que (Chromium).

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - use pwm_device.hwpwm instead of recomputing it
  - update pwm_ops for changes in patch 2

Changes in v2:
  - set pwm_chip.dev field
  - rename clk_enb to enable
  - introduce NUM_PWM macro instead of hard-coding the number of PWM
    devices
  - update comment in tegra_pwm_config
  - fix coding-style for multi-line comments
  - use module_platform_driver
  - change license to GPL

 drivers/pwm/Kconfig     |   10 ++
 drivers/pwm/Makefile    |    1 +
 drivers/pwm/pwm-tegra.c |  263 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+), 0 deletions(-)
 create mode 100644 drivers/pwm/pwm-tegra.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 93c1052..bda6f23 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -9,4 +9,14 @@ menuconfig PWM
 
 if PWM
 
+config PWM_TEGRA
+	tristate "NVIDIA Tegra PWM support"
+	depends on ARCH_TEGRA
+	help
+	  Generic PWM framework driver for the PWFM controller found on NVIDIA
+	  Tegra SoCs.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-tegra.
+
 endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 3469c3d..12300f5 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_PWM)		+= core.o
+obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
new file mode 100644
index 0000000..1c95e08
--- /dev/null
+++ b/drivers/pwm/pwm-tegra.c
@@ -0,0 +1,263 @@
+/*
+ * drivers/pwm/pwm-tegra.c
+ *
+ * Tegra pulse-width-modulation controller driver
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pwm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PWM_ENABLE	(1 << 31)
+#define PWM_DUTY_WIDTH	8
+#define PWM_DUTY_SHIFT	16
+#define PWM_SCALE_WIDTH	13
+#define PWM_SCALE_SHIFT	0
+
+#define NUM_PWM 4
+
+struct tegra_pwm_chip {
+	struct pwm_chip		chip;
+	struct device		*dev;
+
+	struct clk		*clk;
+
+	int			enable[NUM_PWM];
+	void __iomem		*mmio_base;
+};
+
+static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct tegra_pwm_chip, chip);
+}
+
+static inline int pwm_writel(struct tegra_pwm_chip *chip, unsigned int num,
+		unsigned long val)
+{
+	unsigned long offset = num << 4;
+	int rc;
+
+	rc = clk_enable(chip->clk);
+	if (WARN_ON(rc))
+		return rc;
+
+	writel(val, chip->mmio_base + offset);
+	clk_disable(chip->clk);
+
+	return 0;
+}
+
+static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+		int duty_ns, int period_ns)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+	unsigned long long c;
+	unsigned long rate, hz;
+	u32 val = 0;
+
+	/*
+	 * Convert from duty_ns / period_ns to a fixed number of duty
+	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
+	 */
+	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);
+	do_div(c, period_ns);
+
+	val = (u32)c << PWM_DUTY_SHIFT;
+
+	/*
+	 * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
+	 * cycles at the PWM clock rate will take period_ns nanoseconds.
+	 */
+	rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
+	hz = 1000000000ul / period_ns;
+
+	rate = (rate + (hz / 2)) / hz;
+
+	/*
+	 * Since the actual PWM divider is the register's frequency divider
+	 * field minus 1, we need to decrement to get the correct value to
+	 * write to the register.
+	 */
+	if (rate > 0)
+		rate--;
+
+	/*
+	 * Make sure that the rate will fit in the register's frequency
+	 * divider field.
+	 */
+	if (rate >> PWM_SCALE_WIDTH)
+		return -EINVAL;
+
+	val |= (rate << PWM_SCALE_SHIFT);
+
+	/* If the PWM channel is enabled, keep it enabled */
+	if (pc->enable[pwm->hwpwm])
+		val |= PWM_ENABLE;
+
+	return pwm_writel(pc, pwm->hwpwm, val);
+}
+
+static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+	int rc = 0;
+
+	if (!pc->enable[pwm->hwpwm]) {
+		rc = clk_enable(pc->clk);
+		if (!rc) {
+			unsigned long offset = pwm->hwpwm << 4;
+			u32 val;
+
+			val = readl(pc->mmio_base + offset);
+			val |= PWM_ENABLE;
+			writel(val, pc->mmio_base + offset);
+
+			pc->enable[pwm->hwpwm] = 1;
+		}
+	}
+
+	return 0;
+}
+
+static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+
+	if (pc->enable[pwm->hwpwm]) {
+		unsigned long offset = pwm->hwpwm << 4;
+		u32 val;
+
+		val = readl(pc->mmio_base + offset);
+		val &= ~PWM_ENABLE;
+		writel(val, pc->mmio_base + offset);
+
+		clk_disable(pc->clk);
+		pc->enable[pwm->hwpwm] = 0;
+	}
+}
+
+static struct pwm_ops tegra_pwm_ops = {
+	.config = tegra_pwm_config,
+	.enable = tegra_pwm_enable,
+	.disable = tegra_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int tegra_pwm_probe(struct platform_device *pdev)
+{
+	struct tegra_pwm_chip *pwm;
+	struct resource *r;
+	int ret;
+
+	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no memory resources defined\n");
+		return -ENODEV;
+	}
+
+	r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+			pdev->name);
+	if (!r) {
+		dev_err(&pdev->dev, "failed to request memory\n");
+		return -EBUSY;
+	}
+
+	pwm->mmio_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!pwm->mmio_base) {
+		dev_err(&pdev->dev, "failed to ioremap() region\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+
+	pwm->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pwm->clk))
+		return PTR_ERR(pwm->clk);
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &tegra_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = NUM_PWM;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		clk_put(pwm->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit tegra_pwm_remove(struct platform_device *pdev)
+{
+	struct tegra_pwm_chip *pwm = platform_get_drvdata(pdev);
+	int i;
+
+	if (WARN_ON(!pwm))
+		return -ENODEV;
+
+	pwmchip_remove(&pwm->chip);
+
+	for (i = 0; i < NUM_PWM; i++) {
+		pwm_writel(pwm, i, 0);
+
+		if (pwm->enable[i])
+			clk_disable(pwm->clk);
+	}
+
+	clk_put(pwm->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id tegra_pwm_of_match[] = {
+	{ .compatible = "nvidia,tegra20-pwm" },
+	{ }
+};
+#endif
+
+static struct platform_driver tegra_pwm_driver = {
+	.driver		= {
+		.name		= "tegra-pwm",
+		.of_match_table	= of_match_ptr(tegra_pwm_of_match),
+	},
+	.probe		= tegra_pwm_probe,
+	.remove		= __devexit_p(tegra_pwm_remove),
+};
+
+module_platform_driver(tegra_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NVIDIA Corporation");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

This commit adds a generic PWM framework driver for the PWFM controller
found on NVIDIA Tegra SoCs. The driver is based on code from the
Chromium kernel tree and was originally written by Gary King (NVIDIA)
and later modified by Simon Que (Chromium).

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - use pwm_device.hwpwm instead of recomputing it
  - update pwm_ops for changes in patch 2

Changes in v2:
  - set pwm_chip.dev field
  - rename clk_enb to enable
  - introduce NUM_PWM macro instead of hard-coding the number of PWM
    devices
  - update comment in tegra_pwm_config
  - fix coding-style for multi-line comments
  - use module_platform_driver
  - change license to GPL

 drivers/pwm/Kconfig     |   10 ++
 drivers/pwm/Makefile    |    1 +
 drivers/pwm/pwm-tegra.c |  263 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+), 0 deletions(-)
 create mode 100644 drivers/pwm/pwm-tegra.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 93c1052..bda6f23 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -9,4 +9,14 @@ menuconfig PWM
 
 if PWM
 
+config PWM_TEGRA
+	tristate "NVIDIA Tegra PWM support"
+	depends on ARCH_TEGRA
+	help
+	  Generic PWM framework driver for the PWFM controller found on NVIDIA
+	  Tegra SoCs.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-tegra.
+
 endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 3469c3d..12300f5 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_PWM)		+= core.o
+obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
new file mode 100644
index 0000000..1c95e08
--- /dev/null
+++ b/drivers/pwm/pwm-tegra.c
@@ -0,0 +1,263 @@
+/*
+ * drivers/pwm/pwm-tegra.c
+ *
+ * Tegra pulse-width-modulation controller driver
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pwm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PWM_ENABLE	(1 << 31)
+#define PWM_DUTY_WIDTH	8
+#define PWM_DUTY_SHIFT	16
+#define PWM_SCALE_WIDTH	13
+#define PWM_SCALE_SHIFT	0
+
+#define NUM_PWM 4
+
+struct tegra_pwm_chip {
+	struct pwm_chip		chip;
+	struct device		*dev;
+
+	struct clk		*clk;
+
+	int			enable[NUM_PWM];
+	void __iomem		*mmio_base;
+};
+
+static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct tegra_pwm_chip, chip);
+}
+
+static inline int pwm_writel(struct tegra_pwm_chip *chip, unsigned int num,
+		unsigned long val)
+{
+	unsigned long offset = num << 4;
+	int rc;
+
+	rc = clk_enable(chip->clk);
+	if (WARN_ON(rc))
+		return rc;
+
+	writel(val, chip->mmio_base + offset);
+	clk_disable(chip->clk);
+
+	return 0;
+}
+
+static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+		int duty_ns, int period_ns)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+	unsigned long long c;
+	unsigned long rate, hz;
+	u32 val = 0;
+
+	/*
+	 * Convert from duty_ns / period_ns to a fixed number of duty
+	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
+	 */
+	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);
+	do_div(c, period_ns);
+
+	val = (u32)c << PWM_DUTY_SHIFT;
+
+	/*
+	 * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
+	 * cycles@the PWM clock rate will take period_ns nanoseconds.
+	 */
+	rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
+	hz = 1000000000ul / period_ns;
+
+	rate = (rate + (hz / 2)) / hz;
+
+	/*
+	 * Since the actual PWM divider is the register's frequency divider
+	 * field minus 1, we need to decrement to get the correct value to
+	 * write to the register.
+	 */
+	if (rate > 0)
+		rate--;
+
+	/*
+	 * Make sure that the rate will fit in the register's frequency
+	 * divider field.
+	 */
+	if (rate >> PWM_SCALE_WIDTH)
+		return -EINVAL;
+
+	val |= (rate << PWM_SCALE_SHIFT);
+
+	/* If the PWM channel is enabled, keep it enabled */
+	if (pc->enable[pwm->hwpwm])
+		val |= PWM_ENABLE;
+
+	return pwm_writel(pc, pwm->hwpwm, val);
+}
+
+static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+	int rc = 0;
+
+	if (!pc->enable[pwm->hwpwm]) {
+		rc = clk_enable(pc->clk);
+		if (!rc) {
+			unsigned long offset = pwm->hwpwm << 4;
+			u32 val;
+
+			val = readl(pc->mmio_base + offset);
+			val |= PWM_ENABLE;
+			writel(val, pc->mmio_base + offset);
+
+			pc->enable[pwm->hwpwm] = 1;
+		}
+	}
+
+	return 0;
+}
+
+static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+
+	if (pc->enable[pwm->hwpwm]) {
+		unsigned long offset = pwm->hwpwm << 4;
+		u32 val;
+
+		val = readl(pc->mmio_base + offset);
+		val &= ~PWM_ENABLE;
+		writel(val, pc->mmio_base + offset);
+
+		clk_disable(pc->clk);
+		pc->enable[pwm->hwpwm] = 0;
+	}
+}
+
+static struct pwm_ops tegra_pwm_ops = {
+	.config = tegra_pwm_config,
+	.enable = tegra_pwm_enable,
+	.disable = tegra_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int tegra_pwm_probe(struct platform_device *pdev)
+{
+	struct tegra_pwm_chip *pwm;
+	struct resource *r;
+	int ret;
+
+	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no memory resources defined\n");
+		return -ENODEV;
+	}
+
+	r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+			pdev->name);
+	if (!r) {
+		dev_err(&pdev->dev, "failed to request memory\n");
+		return -EBUSY;
+	}
+
+	pwm->mmio_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!pwm->mmio_base) {
+		dev_err(&pdev->dev, "failed to ioremap() region\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+
+	pwm->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pwm->clk))
+		return PTR_ERR(pwm->clk);
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &tegra_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = NUM_PWM;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		clk_put(pwm->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit tegra_pwm_remove(struct platform_device *pdev)
+{
+	struct tegra_pwm_chip *pwm = platform_get_drvdata(pdev);
+	int i;
+
+	if (WARN_ON(!pwm))
+		return -ENODEV;
+
+	pwmchip_remove(&pwm->chip);
+
+	for (i = 0; i < NUM_PWM; i++) {
+		pwm_writel(pwm, i, 0);
+
+		if (pwm->enable[i])
+			clk_disable(pwm->clk);
+	}
+
+	clk_put(pwm->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id tegra_pwm_of_match[] = {
+	{ .compatible = "nvidia,tegra20-pwm" },
+	{ }
+};
+#endif
+
+static struct platform_driver tegra_pwm_driver = {
+	.driver		= {
+		.name		= "tegra-pwm",
+		.of_match_table	= of_match_ptr(tegra_pwm_of_match),
+	},
+	.probe		= tegra_pwm_probe,
+	.remove		= __devexit_p(tegra_pwm_remove),
+};
+
+module_platform_driver(tegra_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NVIDIA Corporation");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17   ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss
  Cc: Mitch Bradley, Mark Brown, Mike Frysinger, Ryan Mallon,
	Arnd Bergmann, Sascha Hauer, Colin Cross, Rob Herring,
	Grant Likely, Olof Johansson, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra, Eric Miao, linux-arm-kernel,
	Kurt Van Dijck

Add auxdata to instantiate a device tree for the PWFM controller and
include a corresponding node in the device tree.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - add missing include for mach/iomap.h

Changes in v2:
  - none

 arch/arm/boot/dts/tegra20.dtsi         |    6 ++++++
 arch/arm/boot/dts/tegra30.dtsi         |    6 ++++++
 arch/arm/mach-tegra/board-dt-tegra20.c |    1 +
 arch/arm/mach-tegra/board-dt-tegra30.c |    3 +++
 4 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index ec1f010..c34e6c3 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -148,6 +148,12 @@
 		interrupts = < 0 91 0x04 >;
 	};
 
+	pwm: pwm@7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
+
 	emc@7000f400 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index ac4b75c..77bd985 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -146,6 +146,12 @@
 		interrupts = < 0 91 0x04 >;
 	};
 
+	pwm: pwm@7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
+
 	sdhci@78000000 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000000 0x200>;
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 7a95e0b..bad0dd1 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -73,6 +73,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
 		       &tegra_ehci2_device.dev.platform_data),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
 		       &tegra_ehci3_device.dev.platform_data),
+	OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index b4124b1..194ae1e 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -33,6 +33,8 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
+#include <mach/iomap.h>
+
 #include "board.h"
 #include "clock.h"
 
@@ -51,6 +53,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
 	{}
 };
 
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-02-22 15:17   ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

Add auxdata to instantiate a device tree for the PWFM controller and
include a corresponding node in the device tree.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - add missing include for mach/iomap.h

Changes in v2:
  - none

 arch/arm/boot/dts/tegra20.dtsi         |    6 ++++++
 arch/arm/boot/dts/tegra30.dtsi         |    6 ++++++
 arch/arm/mach-tegra/board-dt-tegra20.c |    1 +
 arch/arm/mach-tegra/board-dt-tegra30.c |    3 +++
 4 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index ec1f010..c34e6c3 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -148,6 +148,12 @@
 		interrupts = < 0 91 0x04 >;
 	};
 
+	pwm: pwm at 7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
+
 	emc at 7000f400 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index ac4b75c..77bd985 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -146,6 +146,12 @@
 		interrupts = < 0 91 0x04 >;
 	};
 
+	pwm: pwm at 7000a000 {
+		compatible = "nvidia,tegra20-pwm";
+		reg = <0x7000a000 0x100>;
+		#pwm-cells = <2>;
+	};
+
 	sdhci at 78000000 {
 		compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
 		reg = <0x78000000 0x200>;
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 7a95e0b..bad0dd1 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -73,6 +73,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
 		       &tegra_ehci2_device.dev.platform_data),
 	OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
 		       &tegra_ehci3_device.dev.platform_data),
+	OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index b4124b1..194ae1e 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -33,6 +33,8 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
+#include <mach/iomap.h>
+
 #include "board.h"
 #include "clock.h"
 
@@ -51,6 +53,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
 	OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+	OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
 	{}
 };
 
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 08/10] pwm: Add Blackfin support
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - update PWM ops for changes in patch 2

 arch/blackfin/Kconfig         |   10 ---
 arch/blackfin/kernel/Makefile |    1 -
 arch/blackfin/kernel/pwm.c    |  100 -------------------------
 drivers/pwm/Kconfig           |    9 ++
 drivers/pwm/Makefile          |    1 +
 drivers/pwm/pwm-bfin.c        |  164 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 174 insertions(+), 111 deletions(-)
 delete mode 100644 arch/blackfin/kernel/pwm.c
 create mode 100644 drivers/pwm/pwm-bfin.c

diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index c1269a1..e08f39b 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -950,16 +950,6 @@ config BFIN_GPTIMERS
 	  To compile this driver as a module, choose M here: the module
 	  will be called gptimers.
 
-config HAVE_PWM
-	tristate "Enable PWM API support"
-	depends on BFIN_GPTIMERS
-	help
-	  Enable support for the Pulse Width Modulation framework (as
-	  found in linux/pwm.h).
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called pwm.
-
 choice
 	prompt "Uncached DMA region"
 	default DMA_UNCACHED_1M
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 1f88edd..03f60a6 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_FUNCTION_TRACER)        += ftrace-entry.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)  += ftrace.o
 CFLAGS_REMOVE_ftrace.o = -pg
 
-obj-$(CONFIG_HAVE_PWM)               += pwm.o
 obj-$(CONFIG_IPIPE)                  += ipipe.o
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_CPLB_INFO)              += cplbinfo.o
diff --git a/arch/blackfin/kernel/pwm.c b/arch/blackfin/kernel/pwm.c
deleted file mode 100644
index 33f5942..0000000
--- a/arch/blackfin/kernel/pwm.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Blackfin Pulse Width Modulation (PWM) core
- *
- * Copyright (c) 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/pwm.h>
-#include <linux/slab.h>
-
-#include <asm/gptimers.h>
-#include <asm/portmux.h>
-
-struct pwm_device {
-	unsigned id;
-	unsigned short pin;
-};
-
-static const unsigned short pwm_to_gptimer_per[] = {
-	P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
-	P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
-};
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	struct pwm_device *pwm;
-	int ret;
-
-	/* XXX: pwm_id really should be unsigned */
-	if (pwm_id < 0)
-		return NULL;
-
-	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
-	if (!pwm)
-		return pwm;
-
-	pwm->id = pwm_id;
-	if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per))
-		goto err;
-
-	pwm->pin = pwm_to_gptimer_per[pwm->id];
-	ret = peripheral_request(pwm->pin, label);
-	if (ret)
-		goto err;
-
-	return pwm;
- err:
-	kfree(pwm);
-	return NULL;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-	peripheral_free(pwm->pin);
-	kfree(pwm);
-}
-EXPORT_SYMBOL(pwm_free);
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	unsigned long period, duty;
-	unsigned long long val;
-
-	if (duty_ns < 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	val = (unsigned long long)get_sclk() * period_ns;
-	do_div(val, NSEC_PER_SEC);
-	period = val;
-
-	val = (unsigned long long)period * duty_ns;
-	do_div(val, period_ns);
-	duty = period - val;
-
-	if (duty >= period)
-		duty = period - 1;
-
-	set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
-	set_gptimer_pwidth(pwm->id, duty);
-	set_gptimer_period(pwm->id, period);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	enable_gptimer(pwm->id);
-	return 0;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-	disable_gptimer(pwm->id);
-}
-EXPORT_SYMBOL(pwm_disable);
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bda6f23..eb54042 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -9,6 +9,15 @@ menuconfig PWM
 
 if PWM
 
+config PWM_BFIN
+	tristate "Blackfin PWM support"
+	depends on BFIN_GPTIMERS
+	help
+	  Generic PWM framework driver for Blackfin.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-bfin.
+
 config PWM_TEGRA
 	tristate "NVIDIA Tegra PWM support"
 	depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 12300f5..251b8d2 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PWM)		+= core.o
+obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
new file mode 100644
index 0000000..a0c6bf9
--- /dev/null
+++ b/drivers/pwm/pwm-bfin.c
@@ -0,0 +1,164 @@
+/*
+ * Blackfin Pulse Width Modulation (PWM) core
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include <asm/gptimers.h>
+#include <asm/portmux.h>
+
+struct bfin_pwm_chip {
+	struct pwm_chip chip;
+};
+
+struct bfin_pwm {
+	unsigned short pin;
+};
+
+static const unsigned short pwm_to_gptimer_per[] = {
+	P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
+	P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
+};
+
+static int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv;
+	int ret;
+
+	if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per))
+		return -EINVAL;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->pin = pwm_to_gptimer_per[pwm->hwpwm];
+
+	ret = peripheral_request(priv->pin, NULL);
+	if (ret) {
+		kfree(priv);
+		return ret;
+	}
+
+	pwm_set_chip_data(pwm, priv);
+
+	return 0;
+}
+
+static void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	if (priv) {
+		peripheral_free(priv->pin);
+		kfree(priv);
+	}
+}
+
+static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+		int duty_ns, int period_ns)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+	unsigned long period, duty;
+	unsigned long long val;
+
+	if (duty_ns < 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	val = (unsigned long long)get_sclk() * period_ns;
+	do_div(val, NSEC_PER_SEC);
+	period = val;
+
+	val = (unsigned long long)period * duty_ns;
+	do_div(val, period_ns);
+	duty = period - val;
+
+	if (duty >= period)
+		duty = period - 1;
+
+	set_gptimer_config(priv->pin, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
+	set_gptimer_pwidth(priv->pin, duty);
+	set_gptimer_period(priv->pin, period);
+
+	return 0;
+}
+
+static int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	enable_gptimer(priv->pin);
+
+	return 0;
+}
+
+static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	disable_gptimer(priv->pin);
+}
+
+static struct pwm_ops bfin_pwm_ops = {
+	.request = bfin_pwm_request,
+	.free = bfin_pwm_free,
+	.config = bfin_pwm_config,
+	.enable = bfin_pwm_enable,
+	.disable = bfin_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int bfin_pwm_probe(struct platform_device *pdev)
+{
+	struct bfin_pwm_chip *pwm;
+	int ret;
+
+	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &bfin_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = 12;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit bfin_pwm_remove(struct platform_device *pdev)
+{
+	struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+	pwmchip_remove(&pwm->chip);
+
+	return 0;
+}
+
+static struct platform_driver bfin_pwm_driver = {
+	.driver = {
+		.name = "bfin-pwm",
+	},
+	.probe = bfin_pwm_probe,
+	.remove = __devexit_p(bfin_pwm_remove),
+};
+
+module_platform_driver(bfin_pwm_driver);
+
+MODULE_LICENSE("GPL");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 08/10] pwm: Add Blackfin support
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - update PWM ops for changes in patch 2

 arch/blackfin/Kconfig         |   10 ---
 arch/blackfin/kernel/Makefile |    1 -
 arch/blackfin/kernel/pwm.c    |  100 -------------------------
 drivers/pwm/Kconfig           |    9 ++
 drivers/pwm/Makefile          |    1 +
 drivers/pwm/pwm-bfin.c        |  164 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 174 insertions(+), 111 deletions(-)
 delete mode 100644 arch/blackfin/kernel/pwm.c
 create mode 100644 drivers/pwm/pwm-bfin.c

diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index c1269a1..e08f39b 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -950,16 +950,6 @@ config BFIN_GPTIMERS
 	  To compile this driver as a module, choose M here: the module
 	  will be called gptimers.
 
-config HAVE_PWM
-	tristate "Enable PWM API support"
-	depends on BFIN_GPTIMERS
-	help
-	  Enable support for the Pulse Width Modulation framework (as
-	  found in linux/pwm.h).
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called pwm.
-
 choice
 	prompt "Uncached DMA region"
 	default DMA_UNCACHED_1M
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 1f88edd..03f60a6 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_FUNCTION_TRACER)        += ftrace-entry.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)  += ftrace.o
 CFLAGS_REMOVE_ftrace.o = -pg
 
-obj-$(CONFIG_HAVE_PWM)               += pwm.o
 obj-$(CONFIG_IPIPE)                  += ipipe.o
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_CPLB_INFO)              += cplbinfo.o
diff --git a/arch/blackfin/kernel/pwm.c b/arch/blackfin/kernel/pwm.c
deleted file mode 100644
index 33f5942..0000000
--- a/arch/blackfin/kernel/pwm.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Blackfin Pulse Width Modulation (PWM) core
- *
- * Copyright (c) 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/pwm.h>
-#include <linux/slab.h>
-
-#include <asm/gptimers.h>
-#include <asm/portmux.h>
-
-struct pwm_device {
-	unsigned id;
-	unsigned short pin;
-};
-
-static const unsigned short pwm_to_gptimer_per[] = {
-	P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
-	P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
-};
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	struct pwm_device *pwm;
-	int ret;
-
-	/* XXX: pwm_id really should be unsigned */
-	if (pwm_id < 0)
-		return NULL;
-
-	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
-	if (!pwm)
-		return pwm;
-
-	pwm->id = pwm_id;
-	if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per))
-		goto err;
-
-	pwm->pin = pwm_to_gptimer_per[pwm->id];
-	ret = peripheral_request(pwm->pin, label);
-	if (ret)
-		goto err;
-
-	return pwm;
- err:
-	kfree(pwm);
-	return NULL;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-	peripheral_free(pwm->pin);
-	kfree(pwm);
-}
-EXPORT_SYMBOL(pwm_free);
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	unsigned long period, duty;
-	unsigned long long val;
-
-	if (duty_ns < 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	val = (unsigned long long)get_sclk() * period_ns;
-	do_div(val, NSEC_PER_SEC);
-	period = val;
-
-	val = (unsigned long long)period * duty_ns;
-	do_div(val, period_ns);
-	duty = period - val;
-
-	if (duty >= period)
-		duty = period - 1;
-
-	set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
-	set_gptimer_pwidth(pwm->id, duty);
-	set_gptimer_period(pwm->id, period);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	enable_gptimer(pwm->id);
-	return 0;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-	disable_gptimer(pwm->id);
-}
-EXPORT_SYMBOL(pwm_disable);
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bda6f23..eb54042 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -9,6 +9,15 @@ menuconfig PWM
 
 if PWM
 
+config PWM_BFIN
+	tristate "Blackfin PWM support"
+	depends on BFIN_GPTIMERS
+	help
+	  Generic PWM framework driver for Blackfin.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-bfin.
+
 config PWM_TEGRA
 	tristate "NVIDIA Tegra PWM support"
 	depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 12300f5..251b8d2 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PWM)		+= core.o
+obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
new file mode 100644
index 0000000..a0c6bf9
--- /dev/null
+++ b/drivers/pwm/pwm-bfin.c
@@ -0,0 +1,164 @@
+/*
+ * Blackfin Pulse Width Modulation (PWM) core
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include <asm/gptimers.h>
+#include <asm/portmux.h>
+
+struct bfin_pwm_chip {
+	struct pwm_chip chip;
+};
+
+struct bfin_pwm {
+	unsigned short pin;
+};
+
+static const unsigned short pwm_to_gptimer_per[] = {
+	P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
+	P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
+};
+
+static int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv;
+	int ret;
+
+	if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per))
+		return -EINVAL;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->pin = pwm_to_gptimer_per[pwm->hwpwm];
+
+	ret = peripheral_request(priv->pin, NULL);
+	if (ret) {
+		kfree(priv);
+		return ret;
+	}
+
+	pwm_set_chip_data(pwm, priv);
+
+	return 0;
+}
+
+static void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	if (priv) {
+		peripheral_free(priv->pin);
+		kfree(priv);
+	}
+}
+
+static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+		int duty_ns, int period_ns)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+	unsigned long period, duty;
+	unsigned long long val;
+
+	if (duty_ns < 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	val = (unsigned long long)get_sclk() * period_ns;
+	do_div(val, NSEC_PER_SEC);
+	period = val;
+
+	val = (unsigned long long)period * duty_ns;
+	do_div(val, period_ns);
+	duty = period - val;
+
+	if (duty >= period)
+		duty = period - 1;
+
+	set_gptimer_config(priv->pin, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
+	set_gptimer_pwidth(priv->pin, duty);
+	set_gptimer_period(priv->pin, period);
+
+	return 0;
+}
+
+static int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	enable_gptimer(priv->pin);
+
+	return 0;
+}
+
+static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+	disable_gptimer(priv->pin);
+}
+
+static struct pwm_ops bfin_pwm_ops = {
+	.request = bfin_pwm_request,
+	.free = bfin_pwm_free,
+	.config = bfin_pwm_config,
+	.enable = bfin_pwm_enable,
+	.disable = bfin_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int bfin_pwm_probe(struct platform_device *pdev)
+{
+	struct bfin_pwm_chip *pwm;
+	int ret;
+
+	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &bfin_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = 12;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit bfin_pwm_remove(struct platform_device *pdev)
+{
+	struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+	pwmchip_remove(&pwm->chip);
+
+	return 0;
+}
+
+static struct platform_driver bfin_pwm_driver = {
+	.driver = {
+		.name = "bfin-pwm",
+	},
+	.probe = bfin_pwm_probe,
+	.remove = __devexit_p(bfin_pwm_remove),
+};
+
+module_platform_driver(bfin_pwm_driver);
+
+MODULE_LICENSE("GPL");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 09/10] pwm: Add PXA support
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - update PWM ops for changes in patch 2

 arch/arm/plat-pxa/Makefile |    1 -
 arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
 drivers/pwm/Kconfig        |    9 ++
 drivers/pwm/Makefile       |    1 +
 drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
 5 files changed, 254 insertions(+), 305 deletions(-)
 delete mode 100644 arch/arm/plat-pxa/pwm.c
 create mode 100644 drivers/pwm/pwm-pxa.c

diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index f302d04..af8e484 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx)		+= mfp.o
 obj-$(CONFIG_PXA95x)		+= mfp.o
 obj-$(CONFIG_ARCH_MMP)		+= mfp.o
 
-obj-$(CONFIG_HAVE_PWM)		+= pwm.o
 obj-$(CONFIG_PXA_SSP)		+= ssp.o
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
deleted file mode 100644
index ef32686..0000000
--- a/arch/arm/plat-pxa/pwm.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/pwm.c
- *
- * simple driver for PWM (Pulse Width Modulator) controller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 2008-02-13	initial version
- * 		eric miao <eric.miao-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-
-#define HAS_SECONDARY_PWM	0x10
-#define PWM_ID_BASE(d)		((d) & 0xf)
-
-static const struct platform_device_id pwm_id_table[] = {
-	/*   PWM    has_secondary_pwm? */
-	{ "pxa25x-pwm", 0 },
-	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
-	{ "pxa168-pwm", 1 },
-	{ "pxa910-pwm", 1 },
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, pwm_id_table);
-
-/* PWM registers and bits definitions */
-#define PWMCR		(0x00)
-#define PWMDCR		(0x04)
-#define PWMPCR		(0x08)
-
-#define PWMCR_SD	(1 << 6)
-#define PWMDCR_FD	(1 << 10)
-
-struct pwm_device {
-	struct list_head	node;
-	struct pwm_device	*secondary;
-	struct platform_device	*pdev;
-
-	const char	*label;
-	struct clk	*clk;
-	int		clk_enabled;
-	void __iomem	*mmio_base;
-
-	unsigned int	use_count;
-	unsigned int	pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	unsigned long long c;
-	unsigned long period_cycles, prescale, pv, dc;
-
-	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	c = clk_get_rate(pwm->clk);
-	c = c * period_ns;
-	do_div(c, 1000000000);
-	period_cycles = c;
-
-	if (period_cycles < 1)
-		period_cycles = 1;
-	prescale = (period_cycles - 1) / 1024;
-	pv = period_cycles / (prescale + 1) - 1;
-
-	if (prescale > 63)
-		return -EINVAL;
-
-	if (duty_ns == period_ns)
-		dc = PWMDCR_FD;
-	else
-		dc = (pv + 1) * duty_ns / period_ns;
-
-	/* NOTE: the clock to PWM has to be enabled first
-	 * before writing to the registers
-	 */
-	clk_enable(pwm->clk);
-	__raw_writel(prescale, pwm->mmio_base + PWMCR);
-	__raw_writel(dc, pwm->mmio_base + PWMDCR);
-	__raw_writel(pv, pwm->mmio_base + PWMPCR);
-	clk_disable(pwm->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	int rc = 0;
-
-	if (!pwm->clk_enabled) {
-		rc = clk_enable(pwm->clk);
-		if (!rc)
-			pwm->clk_enabled = 1;
-	}
-	return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-	if (pwm->clk_enabled) {
-		clk_disable(pwm->clk);
-		pwm->clk_enabled = 0;
-	}
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	struct pwm_device *pwm;
-	int found = 0;
-
-	mutex_lock(&pwm_lock);
-
-	list_for_each_entry(pwm, &pwm_list, node) {
-		if (pwm->pwm_id == pwm_id) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (found) {
-		if (pwm->use_count == 0) {
-			pwm->use_count++;
-			pwm->label = label;
-		} else
-			pwm = ERR_PTR(-EBUSY);
-	} else
-		pwm = ERR_PTR(-ENOENT);
-
-	mutex_unlock(&pwm_lock);
-	return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-
-	if (pwm->use_count) {
-		pwm->use_count--;
-		pwm->label = NULL;
-	} else
-		pr_warning("PWM device already freed\n");
-
-	mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-	list_add_tail(&pwm->node, &pwm_list);
-	mutex_unlock(&pwm_lock);
-}
-
-static int __devinit pwm_probe(struct platform_device *pdev)
-{
-	const struct platform_device_id *id = platform_get_device_id(pdev);
-	struct pwm_device *pwm, *secondary = NULL;
-	struct resource *r;
-	int ret = 0;
-
-	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-	if (pwm == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pwm->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(pwm->clk)) {
-		ret = PTR_ERR(pwm->clk);
-		goto err_free;
-	}
-	pwm->clk_enabled = 0;
-
-	pwm->use_count = 0;
-	pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
-	pwm->pdev = pdev;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
-	}
-
-	r = request_mem_region(r->start, resource_size(r), pdev->name);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto err_free_clk;
-	}
-
-	pwm->mmio_base = ioremap(r->start, resource_size(r));
-	if (pwm->mmio_base == NULL) {
-		dev_err(&pdev->dev, "failed to ioremap() registers\n");
-		ret = -ENODEV;
-		goto err_free_mem;
-	}
-
-	if (id->driver_data & HAS_SECONDARY_PWM) {
-		secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-		if (secondary == NULL) {
-			ret = -ENOMEM;
-			goto err_free_mem;
-		}
-
-		*secondary = *pwm;
-		pwm->secondary = secondary;
-
-		/* registers for the second PWM has offset of 0x10 */
-		secondary->mmio_base = pwm->mmio_base + 0x10;
-		secondary->pwm_id = pdev->id + 2;
-	}
-
-	__add_pwm(pwm);
-	if (secondary)
-		__add_pwm(secondary);
-
-	platform_set_drvdata(pdev, pwm);
-	return 0;
-
-err_free_mem:
-	release_mem_region(r->start, resource_size(r));
-err_free_clk:
-	clk_put(pwm->clk);
-err_free:
-	kfree(pwm);
-	return ret;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-	struct resource *r;
-
-	pwm = platform_get_drvdata(pdev);
-	if (pwm == NULL)
-		return -ENODEV;
-
-	mutex_lock(&pwm_lock);
-
-	if (pwm->secondary) {
-		list_del(&pwm->secondary->node);
-		kfree(pwm->secondary);
-	}
-
-	list_del(&pwm->node);
-	mutex_unlock(&pwm_lock);
-
-	iounmap(pwm->mmio_base);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, resource_size(r));
-
-	clk_put(pwm->clk);
-	kfree(pwm);
-	return 0;
-}
-
-static struct platform_driver pwm_driver = {
-	.driver		= {
-		.name	= "pxa25x-pwm",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= pwm_probe,
-	.remove		= __devexit_p(pwm_remove),
-	.id_table	= pwm_id_table,
-};
-
-static int __init pwm_init(void)
-{
-	return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-	platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index eb54042..0ef4f30 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,15 @@ config PWM_BFIN
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-bfin.
 
+config PWM_PXA
+	tristate "PXA PWM support"
+	depends on ARCH_PXA
+	help
+	  Generic PWM framework driver for PXA.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-pxa.
+
 config PWM_TEGRA
 	tristate "NVIDIA Tegra PWM support"
 	depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 251b8d2..e859c51 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_PWM)		+= core.o
 obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
+obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
new file mode 100644
index 0000000..0f3ef5c
--- /dev/null
+++ b/drivers/pwm/pwm-pxa.c
@@ -0,0 +1,244 @@
+/*
+ * linux/arch/arm/mach-pxa/pwm.c
+ *
+ * simple driver for PWM (Pulse Width Modulator) controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 2008-02-13	initial version
+ * 		eric miao <eric.miao-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+
+#define HAS_SECONDARY_PWM	0x10
+#define PWM_ID_BASE(d)		((d) & 0xf)
+
+static const struct platform_device_id pwm_id_table[] = {
+	/*   PWM    has_secondary_pwm? */
+	{ "pxa25x-pwm", 0 },
+	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
+	{ "pxa168-pwm", 1 },
+	{ "pxa910-pwm", 1 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
+/* PWM registers and bits definitions */
+#define PWMCR		(0x00)
+#define PWMDCR		(0x04)
+#define PWMPCR		(0x08)
+
+#define PWMCR_SD	(1 << 6)
+#define PWMDCR_FD	(1 << 10)
+
+struct pxa_pwm_chip {
+	struct pwm_chip	chip;
+	struct device	*dev;
+
+	struct clk	*clk;
+	int		clk_enabled;
+	void __iomem	*mmio_base;
+};
+
+static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct pxa_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			  int duty_ns, int period_ns)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+	unsigned long long c;
+	unsigned long period_cycles, prescale, pv, dc;
+	unsigned long offset;
+
+	if (period_ns == 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	offset = pwm->hwpwm ? 0x10 : 0;
+
+	c = clk_get_rate(pc->clk);
+	c = c * period_ns;
+	do_div(c, 1000000000);
+	period_cycles = c;
+
+	if (period_cycles < 1)
+		period_cycles = 1;
+	prescale = (period_cycles - 1) / 1024;
+	pv = period_cycles / (prescale + 1) - 1;
+
+	if (prescale > 63)
+		return -EINVAL;
+
+	if (duty_ns == period_ns)
+		dc = PWMDCR_FD;
+	else
+		dc = (pv + 1) * duty_ns / period_ns;
+
+	/* NOTE: the clock to PWM has to be enabled first
+	 * before writing to the registers
+	 */
+	clk_enable(pc->clk);
+	__raw_writel(prescale, pc->mmio_base + offset + PWMCR);
+	__raw_writel(dc, pc->mmio_base + offset + PWMDCR);
+	__raw_writel(pv, pc->mmio_base + offset + PWMPCR);
+	clk_disable(pc->clk);
+
+	return 0;
+}
+
+static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+	int rc = 0;
+
+	if (!pc->clk_enabled) {
+		rc = clk_enable(pc->clk);
+		if (!rc)
+			pc->clk_enabled++;
+	}
+	return rc;
+}
+
+static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+
+	if (pc->clk_enabled) {
+		clk_disable(pc->clk);
+		pc->clk_enabled--;
+	}
+}
+
+static struct pwm_ops pxa_pwm_ops = {
+	.config = pxa_pwm_config,
+	.enable = pxa_pwm_enable,
+	.disable = pxa_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct pxa_pwm_chip *pwm;
+	struct resource *r;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+	if (pwm == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pwm->clk)) {
+		ret = PTR_ERR(pwm->clk);
+		goto err_free;
+	}
+	pwm->clk_enabled = 0;
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &pxa_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		ret = -ENODEV;
+		goto err_free_clk;
+	}
+
+	r = request_mem_region(r->start, resource_size(r), pdev->name);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto err_free_clk;
+	}
+
+	pwm->mmio_base = ioremap(r->start, resource_size(r));
+	if (pwm->mmio_base == NULL) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+	return 0;
+
+err_free_mem:
+	release_mem_region(r->start, resource_size(r));
+err_free_clk:
+	clk_put(pwm->clk);
+err_free:
+	kfree(pwm);
+	return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+	struct pxa_pwm_chip *chip;
+	struct resource *r;
+
+	chip = platform_get_drvdata(pdev);
+	if (chip == NULL)
+		return -ENODEV;
+
+	pwmchip_remove(&chip->chip);
+
+	iounmap(chip->mmio_base);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, resource_size(r));
+
+	clk_put(chip->clk);
+	kfree(chip);
+	return 0;
+}
+
+static struct platform_driver pwm_driver = {
+	.driver		= {
+		.name	= "pxa25x-pwm",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pwm_probe,
+	.remove		= __devexit_p(pwm_remove),
+	.id_table	= pwm_id_table,
+};
+
+static int __init pwm_init(void)
+{
+	return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+	platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 09/10] pwm: Add PXA support
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - update PWM ops for changes in patch 2

 arch/arm/plat-pxa/Makefile |    1 -
 arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
 drivers/pwm/Kconfig        |    9 ++
 drivers/pwm/Makefile       |    1 +
 drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
 5 files changed, 254 insertions(+), 305 deletions(-)
 delete mode 100644 arch/arm/plat-pxa/pwm.c
 create mode 100644 drivers/pwm/pwm-pxa.c

diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index f302d04..af8e484 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx)		+= mfp.o
 obj-$(CONFIG_PXA95x)		+= mfp.o
 obj-$(CONFIG_ARCH_MMP)		+= mfp.o
 
-obj-$(CONFIG_HAVE_PWM)		+= pwm.o
 obj-$(CONFIG_PXA_SSP)		+= ssp.o
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
deleted file mode 100644
index ef32686..0000000
--- a/arch/arm/plat-pxa/pwm.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/pwm.c
- *
- * simple driver for PWM (Pulse Width Modulator) controller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 2008-02-13	initial version
- * 		eric miao <eric.miao@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-
-#define HAS_SECONDARY_PWM	0x10
-#define PWM_ID_BASE(d)		((d) & 0xf)
-
-static const struct platform_device_id pwm_id_table[] = {
-	/*   PWM    has_secondary_pwm? */
-	{ "pxa25x-pwm", 0 },
-	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
-	{ "pxa168-pwm", 1 },
-	{ "pxa910-pwm", 1 },
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, pwm_id_table);
-
-/* PWM registers and bits definitions */
-#define PWMCR		(0x00)
-#define PWMDCR		(0x04)
-#define PWMPCR		(0x08)
-
-#define PWMCR_SD	(1 << 6)
-#define PWMDCR_FD	(1 << 10)
-
-struct pwm_device {
-	struct list_head	node;
-	struct pwm_device	*secondary;
-	struct platform_device	*pdev;
-
-	const char	*label;
-	struct clk	*clk;
-	int		clk_enabled;
-	void __iomem	*mmio_base;
-
-	unsigned int	use_count;
-	unsigned int	pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	unsigned long long c;
-	unsigned long period_cycles, prescale, pv, dc;
-
-	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	c = clk_get_rate(pwm->clk);
-	c = c * period_ns;
-	do_div(c, 1000000000);
-	period_cycles = c;
-
-	if (period_cycles < 1)
-		period_cycles = 1;
-	prescale = (period_cycles - 1) / 1024;
-	pv = period_cycles / (prescale + 1) - 1;
-
-	if (prescale > 63)
-		return -EINVAL;
-
-	if (duty_ns == period_ns)
-		dc = PWMDCR_FD;
-	else
-		dc = (pv + 1) * duty_ns / period_ns;
-
-	/* NOTE: the clock to PWM has to be enabled first
-	 * before writing to the registers
-	 */
-	clk_enable(pwm->clk);
-	__raw_writel(prescale, pwm->mmio_base + PWMCR);
-	__raw_writel(dc, pwm->mmio_base + PWMDCR);
-	__raw_writel(pv, pwm->mmio_base + PWMPCR);
-	clk_disable(pwm->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-	int rc = 0;
-
-	if (!pwm->clk_enabled) {
-		rc = clk_enable(pwm->clk);
-		if (!rc)
-			pwm->clk_enabled = 1;
-	}
-	return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-	if (pwm->clk_enabled) {
-		clk_disable(pwm->clk);
-		pwm->clk_enabled = 0;
-	}
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	struct pwm_device *pwm;
-	int found = 0;
-
-	mutex_lock(&pwm_lock);
-
-	list_for_each_entry(pwm, &pwm_list, node) {
-		if (pwm->pwm_id == pwm_id) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (found) {
-		if (pwm->use_count == 0) {
-			pwm->use_count++;
-			pwm->label = label;
-		} else
-			pwm = ERR_PTR(-EBUSY);
-	} else
-		pwm = ERR_PTR(-ENOENT);
-
-	mutex_unlock(&pwm_lock);
-	return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-
-	if (pwm->use_count) {
-		pwm->use_count--;
-		pwm->label = NULL;
-	} else
-		pr_warning("PWM device already freed\n");
-
-	mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-	mutex_lock(&pwm_lock);
-	list_add_tail(&pwm->node, &pwm_list);
-	mutex_unlock(&pwm_lock);
-}
-
-static int __devinit pwm_probe(struct platform_device *pdev)
-{
-	const struct platform_device_id *id = platform_get_device_id(pdev);
-	struct pwm_device *pwm, *secondary = NULL;
-	struct resource *r;
-	int ret = 0;
-
-	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-	if (pwm == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	pwm->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(pwm->clk)) {
-		ret = PTR_ERR(pwm->clk);
-		goto err_free;
-	}
-	pwm->clk_enabled = 0;
-
-	pwm->use_count = 0;
-	pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
-	pwm->pdev = pdev;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
-	}
-
-	r = request_mem_region(r->start, resource_size(r), pdev->name);
-	if (r == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto err_free_clk;
-	}
-
-	pwm->mmio_base = ioremap(r->start, resource_size(r));
-	if (pwm->mmio_base == NULL) {
-		dev_err(&pdev->dev, "failed to ioremap() registers\n");
-		ret = -ENODEV;
-		goto err_free_mem;
-	}
-
-	if (id->driver_data & HAS_SECONDARY_PWM) {
-		secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-		if (secondary == NULL) {
-			ret = -ENOMEM;
-			goto err_free_mem;
-		}
-
-		*secondary = *pwm;
-		pwm->secondary = secondary;
-
-		/* registers for the second PWM has offset of 0x10 */
-		secondary->mmio_base = pwm->mmio_base + 0x10;
-		secondary->pwm_id = pdev->id + 2;
-	}
-
-	__add_pwm(pwm);
-	if (secondary)
-		__add_pwm(secondary);
-
-	platform_set_drvdata(pdev, pwm);
-	return 0;
-
-err_free_mem:
-	release_mem_region(r->start, resource_size(r));
-err_free_clk:
-	clk_put(pwm->clk);
-err_free:
-	kfree(pwm);
-	return ret;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-	struct pwm_device *pwm;
-	struct resource *r;
-
-	pwm = platform_get_drvdata(pdev);
-	if (pwm == NULL)
-		return -ENODEV;
-
-	mutex_lock(&pwm_lock);
-
-	if (pwm->secondary) {
-		list_del(&pwm->secondary->node);
-		kfree(pwm->secondary);
-	}
-
-	list_del(&pwm->node);
-	mutex_unlock(&pwm_lock);
-
-	iounmap(pwm->mmio_base);
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, resource_size(r));
-
-	clk_put(pwm->clk);
-	kfree(pwm);
-	return 0;
-}
-
-static struct platform_driver pwm_driver = {
-	.driver		= {
-		.name	= "pxa25x-pwm",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= pwm_probe,
-	.remove		= __devexit_p(pwm_remove),
-	.id_table	= pwm_id_table,
-};
-
-static int __init pwm_init(void)
-{
-	return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-	platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index eb54042..0ef4f30 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -18,6 +18,15 @@ config PWM_BFIN
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-bfin.
 
+config PWM_PXA
+	tristate "PXA PWM support"
+	depends on ARCH_PXA
+	help
+	  Generic PWM framework driver for PXA.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-pxa.
+
 config PWM_TEGRA
 	tristate "NVIDIA Tegra PWM support"
 	depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 251b8d2..e859c51 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_PWM)		+= core.o
 obj-$(CONFIG_PWM_BFIN)		+= pwm-bfin.o
+obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
new file mode 100644
index 0000000..0f3ef5c
--- /dev/null
+++ b/drivers/pwm/pwm-pxa.c
@@ -0,0 +1,244 @@
+/*
+ * linux/arch/arm/mach-pxa/pwm.c
+ *
+ * simple driver for PWM (Pulse Width Modulator) controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 2008-02-13	initial version
+ * 		eric miao <eric.miao@marvell.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+
+#define HAS_SECONDARY_PWM	0x10
+#define PWM_ID_BASE(d)		((d) & 0xf)
+
+static const struct platform_device_id pwm_id_table[] = {
+	/*   PWM    has_secondary_pwm? */
+	{ "pxa25x-pwm", 0 },
+	{ "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
+	{ "pxa168-pwm", 1 },
+	{ "pxa910-pwm", 1 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
+/* PWM registers and bits definitions */
+#define PWMCR		(0x00)
+#define PWMDCR		(0x04)
+#define PWMPCR		(0x08)
+
+#define PWMCR_SD	(1 << 6)
+#define PWMDCR_FD	(1 << 10)
+
+struct pxa_pwm_chip {
+	struct pwm_chip	chip;
+	struct device	*dev;
+
+	struct clk	*clk;
+	int		clk_enabled;
+	void __iomem	*mmio_base;
+};
+
+static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct pxa_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			  int duty_ns, int period_ns)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+	unsigned long long c;
+	unsigned long period_cycles, prescale, pv, dc;
+	unsigned long offset;
+
+	if (period_ns == 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	offset = pwm->hwpwm ? 0x10 : 0;
+
+	c = clk_get_rate(pc->clk);
+	c = c * period_ns;
+	do_div(c, 1000000000);
+	period_cycles = c;
+
+	if (period_cycles < 1)
+		period_cycles = 1;
+	prescale = (period_cycles - 1) / 1024;
+	pv = period_cycles / (prescale + 1) - 1;
+
+	if (prescale > 63)
+		return -EINVAL;
+
+	if (duty_ns == period_ns)
+		dc = PWMDCR_FD;
+	else
+		dc = (pv + 1) * duty_ns / period_ns;
+
+	/* NOTE: the clock to PWM has to be enabled first
+	 * before writing to the registers
+	 */
+	clk_enable(pc->clk);
+	__raw_writel(prescale, pc->mmio_base + offset + PWMCR);
+	__raw_writel(dc, pc->mmio_base + offset + PWMDCR);
+	__raw_writel(pv, pc->mmio_base + offset + PWMPCR);
+	clk_disable(pc->clk);
+
+	return 0;
+}
+
+static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+	int rc = 0;
+
+	if (!pc->clk_enabled) {
+		rc = clk_enable(pc->clk);
+		if (!rc)
+			pc->clk_enabled++;
+	}
+	return rc;
+}
+
+static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+
+	if (pc->clk_enabled) {
+		clk_disable(pc->clk);
+		pc->clk_enabled--;
+	}
+}
+
+static struct pwm_ops pxa_pwm_ops = {
+	.config = pxa_pwm_config,
+	.enable = pxa_pwm_enable,
+	.disable = pxa_pwm_disable,
+	.owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct pxa_pwm_chip *pwm;
+	struct resource *r;
+	int ret = 0;
+
+	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+	if (pwm == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	pwm->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pwm->clk)) {
+		ret = PTR_ERR(pwm->clk);
+		goto err_free;
+	}
+	pwm->clk_enabled = 0;
+
+	pwm->chip.dev = &pdev->dev;
+	pwm->chip.ops = &pxa_pwm_ops;
+	pwm->chip.base = -1;
+	pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		ret = -ENODEV;
+		goto err_free_clk;
+	}
+
+	r = request_mem_region(r->start, resource_size(r), pdev->name);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "failed to request memory resource\n");
+		ret = -EBUSY;
+		goto err_free_clk;
+	}
+
+	pwm->mmio_base = ioremap(r->start, resource_size(r));
+	if (pwm->mmio_base == NULL) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, pwm);
+	return 0;
+
+err_free_mem:
+	release_mem_region(r->start, resource_size(r));
+err_free_clk:
+	clk_put(pwm->clk);
+err_free:
+	kfree(pwm);
+	return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+	struct pxa_pwm_chip *chip;
+	struct resource *r;
+
+	chip = platform_get_drvdata(pdev);
+	if (chip == NULL)
+		return -ENODEV;
+
+	pwmchip_remove(&chip->chip);
+
+	iounmap(chip->mmio_base);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, resource_size(r));
+
+	clk_put(chip->clk);
+	kfree(chip);
+	return 0;
+}
+
+static struct platform_driver pwm_driver = {
+	.driver		= {
+		.name	= "pxa25x-pwm",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pwm_probe,
+	.remove		= __devexit_p(pwm_remove),
+	.id_table	= pwm_id_table,
+};
+
+static int __init pwm_init(void)
+{
+	return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+	platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 10/10] pwm-backlight: Add rudimentary device tree support
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 15:17     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

This commit adds very basic support for device tree probing. Currently,
only a PWM and a list of distinct brightness levels can be specified.
Enabling or disabling backlight power via GPIOs is not yet supported.

A pointer to the exit() callback is stored in the driver data to keep it
around until the driver is unloaded.

Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
---
Changes in v3:
  - use a list of distinct brightness levels instead of a linear range
    as discussed with Stephen Warren and Mitch Bradley

Changes in v2:
  - avoid oops by keeping a reference to the platform-specific exit()
    callback

TODO:
  - add regulator support for backlight enable/disable

 .../bindings/video/backlight/pwm-backlight         |   19 ++++
 drivers/video/backlight/Kconfig                    |    2 +-
 drivers/video/backlight/pwm_bl.c                   |  113 ++++++++++++++++++--
 include/linux/pwm_backlight.h                      |    1 +
 4 files changed, 124 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight

diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
new file mode 100644
index 0000000..79db3dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
@@ -0,0 +1,19 @@
+pwm-backlight bindings
+
+Required properties:
+  - compatible: "pwm-backlight"
+  - pwm: OF device-tree PWM specification
+  - num-brightness-levels: number of distinct brightness levels
+  - brightness-levels: array of distinct brightness levels
+  - default-brightness-level: the default brightness level
+
+Example:
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwm = <&pwm 0 5000000>;
+
+		num-brightness-levels = <8>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+	};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index ed68fde5..0003383 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -233,7 +233,7 @@ config BACKLIGHT_CARILLO_RANCH
 
 config BACKLIGHT_PWM
 	tristate "Generic PWM based Backlight Driver"
-	depends on HAVE_PWM
+	depends on HAVE_PWM || PWM
 	help
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 342b7d7..b65a0b6 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -17,6 +17,7 @@
 #include <linux/fb.h>
 #include <linux/backlight.h>
 #include <linux/err.h>
+#include <linux/of_pwm.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 #include <linux/slab.h>
@@ -26,11 +27,13 @@ struct pwm_bl_data {
 	struct device		*dev;
 	unsigned int		period;
 	unsigned int		lth_brightness;
+	unsigned int		*levels;
 	int			(*notify)(struct device *,
 					  int brightness);
 	void			(*notify_after)(struct device *,
 					int brightness);
 	int			(*check_fb)(struct device *, struct fb_info *);
+	void			(*exit)(struct device *);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -52,6 +55,11 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		pwm_config(pb->pwm, 0, pb->period);
 		pwm_disable(pb->pwm);
 	} else {
+		if (pb->levels) {
+			brightness = pb->levels[brightness];
+			max = pb->levels[max];
+		}
+
 		brightness = pb->lth_brightness +
 			(brightness * (pb->period - pb->lth_brightness) / max);
 		pwm_config(pb->pwm, brightness, pb->period);
@@ -83,17 +91,96 @@ static const struct backlight_ops pwm_backlight_ops = {
 	.check_fb	= pwm_backlight_check_fb,
 };
 
+#ifdef CONFIG_OF
+static int pwm_backlight_parse_dt(struct device *dev,
+				  struct platform_pwm_backlight_data *data)
+{
+	struct device_node *node = dev->of_node;
+	struct pwm_spec spec;
+	u32 value;
+	int ret;
+
+	if (!node)
+		return -ENODEV;
+
+	memset(data, 0, sizeof(*data));
+
+	ret = of_get_named_pwm(node, "pwm", 0, &spec);
+	if (ret < 0)
+		return ret;
+
+	data->pwm_period_ns = spec.period;
+	data->pwm_id = ret;
+
+	ret = of_property_read_u32(node, "num-brightness-levels", &value);
+	if (ret < 0)
+		return ret;
+
+	data->max_brightness = value;
+
+	if (data->max_brightness > 0) {
+		size_t size = sizeof(*data->levels) * data->max_brightness;
+
+		data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
+		if (!data->levels)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(node, "brightness-levels",
+						 data->levels,
+						 data->max_brightness);
+		if (ret < 0)
+			return ret;
+
+		ret = of_property_read_u32(node, "default-brightness-level",
+					   &value);
+		if (ret < 0)
+			return ret;
+
+		data->dft_brightness = value;
+		data->max_brightness--;
+	}
+
+	/*
+	 * TODO: Most users of this driver use a number of GPIOs to control
+	 *       backlight power. Support for specifying these needs to be
+	 *       added.
+	 */
+
+	return 0;
+}
+
+static struct of_device_id pwm_backlight_of_match[] = {
+	{ .compatible = "pwm-backlight" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
+#else
+static int pwm_backlight_parse_dt(struct device *dev,
+				  struct platform_pwm_backlight_data *data)
+{
+	return -ENODEV;
+}
+#endif
+
 static int pwm_backlight_probe(struct platform_device *pdev)
 {
 	struct backlight_properties props;
 	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+	struct platform_pwm_backlight_data defdata;
 	struct backlight_device *bl;
 	struct pwm_bl_data *pb;
+	unsigned int max;
 	int ret;
 
 	if (!data) {
-		dev_err(&pdev->dev, "failed to find platform data\n");
-		return -EINVAL;
+		ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to find platform data\n");
+			return ret;
+		}
+
+		data = &defdata;
 	}
 
 	if (data->init) {
@@ -109,12 +196,18 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		goto err_alloc;
 	}
 
+	if (data->levels) {
+		max = data->levels[data->max_brightness];
+		pb->levels = data->levels;
+	} else
+		max = data->max_brightness;
+
 	pb->period = data->pwm_period_ns;
 	pb->notify = data->notify;
 	pb->notify_after = data->notify_after;
 	pb->check_fb = data->check_fb;
-	pb->lth_brightness = data->lth_brightness *
-		(data->pwm_period_ns / data->max_brightness);
+	pb->exit = data->exit;
+	pb->lth_brightness = data->lth_brightness * (data->pwm_period_ns / max);
 	pb->dev = &pdev->dev;
 
 	pb->pwm = pwm_request(data->pwm_id, "backlight");
@@ -152,7 +245,6 @@ err_alloc:
 
 static int pwm_backlight_remove(struct platform_device *pdev)
 {
-	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
 	struct backlight_device *bl = platform_get_drvdata(pdev);
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
@@ -160,8 +252,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 	pwm_config(pb->pwm, 0, pb->period);
 	pwm_disable(pb->pwm);
 	pwm_free(pb->pwm);
-	if (data->exit)
-		data->exit(&pdev->dev);
+	if (pb->exit)
+		pb->exit(&pdev->dev);
 	return 0;
 }
 
@@ -195,11 +287,12 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
 
 static struct platform_driver pwm_backlight_driver = {
 	.driver		= {
-		.name	= "pwm-backlight",
-		.owner	= THIS_MODULE,
+		.name		= "pwm-backlight",
+		.owner		= THIS_MODULE,
 #ifdef CONFIG_PM
-		.pm	= &pwm_backlight_pm_ops,
+		.pm		= &pwm_backlight_pm_ops,
 #endif
+		.of_match_table	= of_match_ptr(pwm_backlight_of_match),
 	},
 	.probe		= pwm_backlight_probe,
 	.remove		= pwm_backlight_remove,
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 63d2df4..56f4a86 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -12,6 +12,7 @@ struct platform_pwm_backlight_data {
 	unsigned int dft_brightness;
 	unsigned int lth_brightness;
 	unsigned int pwm_period_ns;
+	unsigned int *levels;
 	int (*init)(struct device *dev);
 	int (*notify)(struct device *dev, int brightness);
 	void (*notify_after)(struct device *dev, int brightness);
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v3 10/10] pwm-backlight: Add rudimentary device tree support
@ 2012-02-22 15:17     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-22 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

This commit adds very basic support for device tree probing. Currently,
only a PWM and a list of distinct brightness levels can be specified.
Enabling or disabling backlight power via GPIOs is not yet supported.

A pointer to the exit() callback is stored in the driver data to keep it
around until the driver is unloaded.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
---
Changes in v3:
  - use a list of distinct brightness levels instead of a linear range
    as discussed with Stephen Warren and Mitch Bradley

Changes in v2:
  - avoid oops by keeping a reference to the platform-specific exit()
    callback

TODO:
  - add regulator support for backlight enable/disable

 .../bindings/video/backlight/pwm-backlight         |   19 ++++
 drivers/video/backlight/Kconfig                    |    2 +-
 drivers/video/backlight/pwm_bl.c                   |  113 ++++++++++++++++++--
 include/linux/pwm_backlight.h                      |    1 +
 4 files changed, 124 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight

diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
new file mode 100644
index 0000000..79db3dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
@@ -0,0 +1,19 @@
+pwm-backlight bindings
+
+Required properties:
+  - compatible: "pwm-backlight"
+  - pwm: OF device-tree PWM specification
+  - num-brightness-levels: number of distinct brightness levels
+  - brightness-levels: array of distinct brightness levels
+  - default-brightness-level: the default brightness level
+
+Example:
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwm = <&pwm 0 5000000>;
+
+		num-brightness-levels = <8>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+	};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index ed68fde5..0003383 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -233,7 +233,7 @@ config BACKLIGHT_CARILLO_RANCH
 
 config BACKLIGHT_PWM
 	tristate "Generic PWM based Backlight Driver"
-	depends on HAVE_PWM
+	depends on HAVE_PWM || PWM
 	help
 	  If you have a LCD backlight adjustable by PWM, say Y to enable
 	  this driver.
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 342b7d7..b65a0b6 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -17,6 +17,7 @@
 #include <linux/fb.h>
 #include <linux/backlight.h>
 #include <linux/err.h>
+#include <linux/of_pwm.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 #include <linux/slab.h>
@@ -26,11 +27,13 @@ struct pwm_bl_data {
 	struct device		*dev;
 	unsigned int		period;
 	unsigned int		lth_brightness;
+	unsigned int		*levels;
 	int			(*notify)(struct device *,
 					  int brightness);
 	void			(*notify_after)(struct device *,
 					int brightness);
 	int			(*check_fb)(struct device *, struct fb_info *);
+	void			(*exit)(struct device *);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -52,6 +55,11 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
 		pwm_config(pb->pwm, 0, pb->period);
 		pwm_disable(pb->pwm);
 	} else {
+		if (pb->levels) {
+			brightness = pb->levels[brightness];
+			max = pb->levels[max];
+		}
+
 		brightness = pb->lth_brightness +
 			(brightness * (pb->period - pb->lth_brightness) / max);
 		pwm_config(pb->pwm, brightness, pb->period);
@@ -83,17 +91,96 @@ static const struct backlight_ops pwm_backlight_ops = {
 	.check_fb	= pwm_backlight_check_fb,
 };
 
+#ifdef CONFIG_OF
+static int pwm_backlight_parse_dt(struct device *dev,
+				  struct platform_pwm_backlight_data *data)
+{
+	struct device_node *node = dev->of_node;
+	struct pwm_spec spec;
+	u32 value;
+	int ret;
+
+	if (!node)
+		return -ENODEV;
+
+	memset(data, 0, sizeof(*data));
+
+	ret = of_get_named_pwm(node, "pwm", 0, &spec);
+	if (ret < 0)
+		return ret;
+
+	data->pwm_period_ns = spec.period;
+	data->pwm_id = ret;
+
+	ret = of_property_read_u32(node, "num-brightness-levels", &value);
+	if (ret < 0)
+		return ret;
+
+	data->max_brightness = value;
+
+	if (data->max_brightness > 0) {
+		size_t size = sizeof(*data->levels) * data->max_brightness;
+
+		data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
+		if (!data->levels)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(node, "brightness-levels",
+						 data->levels,
+						 data->max_brightness);
+		if (ret < 0)
+			return ret;
+
+		ret = of_property_read_u32(node, "default-brightness-level",
+					   &value);
+		if (ret < 0)
+			return ret;
+
+		data->dft_brightness = value;
+		data->max_brightness--;
+	}
+
+	/*
+	 * TODO: Most users of this driver use a number of GPIOs to control
+	 *       backlight power. Support for specifying these needs to be
+	 *       added.
+	 */
+
+	return 0;
+}
+
+static struct of_device_id pwm_backlight_of_match[] = {
+	{ .compatible = "pwm-backlight" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
+#else
+static int pwm_backlight_parse_dt(struct device *dev,
+				  struct platform_pwm_backlight_data *data)
+{
+	return -ENODEV;
+}
+#endif
+
 static int pwm_backlight_probe(struct platform_device *pdev)
 {
 	struct backlight_properties props;
 	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+	struct platform_pwm_backlight_data defdata;
 	struct backlight_device *bl;
 	struct pwm_bl_data *pb;
+	unsigned int max;
 	int ret;
 
 	if (!data) {
-		dev_err(&pdev->dev, "failed to find platform data\n");
-		return -EINVAL;
+		ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to find platform data\n");
+			return ret;
+		}
+
+		data = &defdata;
 	}
 
 	if (data->init) {
@@ -109,12 +196,18 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		goto err_alloc;
 	}
 
+	if (data->levels) {
+		max = data->levels[data->max_brightness];
+		pb->levels = data->levels;
+	} else
+		max = data->max_brightness;
+
 	pb->period = data->pwm_period_ns;
 	pb->notify = data->notify;
 	pb->notify_after = data->notify_after;
 	pb->check_fb = data->check_fb;
-	pb->lth_brightness = data->lth_brightness *
-		(data->pwm_period_ns / data->max_brightness);
+	pb->exit = data->exit;
+	pb->lth_brightness = data->lth_brightness * (data->pwm_period_ns / max);
 	pb->dev = &pdev->dev;
 
 	pb->pwm = pwm_request(data->pwm_id, "backlight");
@@ -152,7 +245,6 @@ err_alloc:
 
 static int pwm_backlight_remove(struct platform_device *pdev)
 {
-	struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
 	struct backlight_device *bl = platform_get_drvdata(pdev);
 	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
@@ -160,8 +252,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 	pwm_config(pb->pwm, 0, pb->period);
 	pwm_disable(pb->pwm);
 	pwm_free(pb->pwm);
-	if (data->exit)
-		data->exit(&pdev->dev);
+	if (pb->exit)
+		pb->exit(&pdev->dev);
 	return 0;
 }
 
@@ -195,11 +287,12 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
 
 static struct platform_driver pwm_backlight_driver = {
 	.driver		= {
-		.name	= "pwm-backlight",
-		.owner	= THIS_MODULE,
+		.name		= "pwm-backlight",
+		.owner		= THIS_MODULE,
 #ifdef CONFIG_PM
-		.pm	= &pwm_backlight_pm_ops,
+		.pm		= &pwm_backlight_pm_ops,
 #endif
+		.of_match_table	= of_match_ptr(pwm_backlight_of_match),
 	},
 	.probe		= pwm_backlight_probe,
 	.remove		= pwm_backlight_remove,
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 63d2df4..56f4a86 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -12,6 +12,7 @@ struct platform_pwm_backlight_data {
 	unsigned int dft_brightness;
 	unsigned int lth_brightness;
 	unsigned int pwm_period_ns;
+	unsigned int *levels;
 	int (*init)(struct device *dev);
 	int (*notify)(struct device *dev, int brightness);
 	void (*notify_after)(struct device *dev, int brightness);
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 09/10] pwm: Add PXA support
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-22 15:40         ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 15:40 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Wednesday 22 February 2012, Thierry Reding wrote:
> 
> Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> ---
> Changes in v3:
>   - update PWM ops for changes in patch 2
> 
>  arch/arm/plat-pxa/Makefile |    1 -
>  arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
>  drivers/pwm/Kconfig        |    9 ++
>  drivers/pwm/Makefile       |    1 +
>  drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
>  5 files changed, 254 insertions(+), 305 deletions(-)
>  delete mode 100644 arch/arm/plat-pxa/pwm.c
>  create mode 100644 drivers/pwm/pwm-pxa.c

Since most of this patch is a move of one file, it would help to use the -M
flag to git-format-patch so we can see the actual change.

To make it even more explicit, you could separate the patches that move the
files around from the ones that convert the drivers to the new API.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 09/10] pwm: Add PXA support
@ 2012-02-22 15:40         ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 22 February 2012, Thierry Reding wrote:
> 
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> ---
> Changes in v3:
>   - update PWM ops for changes in patch 2
> 
>  arch/arm/plat-pxa/Makefile |    1 -
>  arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
>  drivers/pwm/Kconfig        |    9 ++
>  drivers/pwm/Makefile       |    1 +
>  drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
>  5 files changed, 254 insertions(+), 305 deletions(-)
>  delete mode 100644 arch/arm/plat-pxa/pwm.c
>  create mode 100644 drivers/pwm/pwm-pxa.c

Since most of this patch is a move of one file, it would help to use the -M
flag to git-format-patch so we can see the actual change.

To make it even more explicit, you could separate the patches that move the
files around from the ones that convert the drivers to the new API.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 00/10] Add PWM framework and device tree support.
  2012-02-22 15:17 ` Thierry Reding
@ 2012-02-22 16:02     ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:02 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Wednesday 22 February 2012, Thierry Reding wrote:
> This patch series adds very rudimentary device-tree support for PWM
> devices. With all of these patches applied (plus one board-specific
> patch that is not included), I'm able to control the backlight on the
> device I'm working on using the sysfs interface provided by the pwm-bl
> driver and the backlight class.
> 
> This series is based on Sascha Hauer's series of patches[0] to add a
> generic PWM framework. The first patch in this series is taken from
> Sascha's branch, while the second patch enables each PWM chip to provide
> multiple PWM devices (the Blackfin and PXA drivers have been ported to
> the framework for reference). When this series is ready I think it would
> be best to merge patches 1 and 2. Currently a global namespace is still
> provided to keep backwards-compatibility with the legacy PWM API. In
> order to achieve this, the number of global PWM devices is limited to
> 1024. However, patch 2 introduces per-chip indexing of PWM devices in
> the core, so it should be easy to add an API to request a PWM device on
> a per-chip basis and get rid of the global namespace eventually. The
> device tree support code does not use the global namespace.

Hi Thierry,

I've just had a chance to look at your series and I think this looks
very good overall, great work!

I probably wouldn't bother merging patches 1 and 2 as you listed
in the TODO section, in order to keep the authorship of each
part obvious.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 00/10] Add PWM framework and device tree support.
@ 2012-02-22 16:02     ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 22 February 2012, Thierry Reding wrote:
> This patch series adds very rudimentary device-tree support for PWM
> devices. With all of these patches applied (plus one board-specific
> patch that is not included), I'm able to control the backlight on the
> device I'm working on using the sysfs interface provided by the pwm-bl
> driver and the backlight class.
> 
> This series is based on Sascha Hauer's series of patches[0] to add a
> generic PWM framework. The first patch in this series is taken from
> Sascha's branch, while the second patch enables each PWM chip to provide
> multiple PWM devices (the Blackfin and PXA drivers have been ported to
> the framework for reference). When this series is ready I think it would
> be best to merge patches 1 and 2. Currently a global namespace is still
> provided to keep backwards-compatibility with the legacy PWM API. In
> order to achieve this, the number of global PWM devices is limited to
> 1024. However, patch 2 introduces per-chip indexing of PWM devices in
> the core, so it should be easy to add an API to request a PWM device on
> a per-chip basis and get rid of the global namespace eventually. The
> device tree support code does not use the global namespace.

Hi Thierry,

I've just had a chance to look at your series and I think this looks
very good overall, great work!

I probably wouldn't bother merging patches 1 and 2 as you listed
in the TODO section, in order to keep the authorship of each
part obvious.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-22 16:15         ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:15 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Wednesday 22 February 2012, Thierry Reding wrote:
> This patch adds helpers to support device tree bindings for the generic
> PWM API. Device tree binding documentation for PWM controllers is also
> provided.
> 
> Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> 
>  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
>  drivers/of/Kconfig                            |    6 +
>  drivers/of/Makefile                           |    1 +
>  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
>  include/linux/of_pwm.h                        |   51 ++++++++++
>  include/linux/pwm.h                           |   17 +++

I think it would make more sense to stick the device tree specific parts
into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
preference on my part.

> @@ -0,0 +1,48 @@
> +Specifying PWM information for devices
> +======================================
> +
> +1) PWM user nodes
> +-----------------
> +
> +PWM users should specify a list of PWM devices that they want to use
> +with a property containing a 'pwm-list':
> +
> +	pwm-list ::= <single-pwm> [pwm-list]
> +	single-pwm ::= <pwm-phandle> <pwm-specifier>
> +	pwm-phandle : phandle to PWM controller node
> +	pwm-specifier : array of #pwm-cells specifying the given PWM
> +			(controller specific)
> +
> +PWM properties should be named "[<name>-]pwms". Exact meaning of each
> +pwms property must be documented in the device tree binding for each
> +device.
> +
> +The following example could be used to describe a PWM-based backlight
> +device:
> +
> +	pwm: pwm {
> +		#pwm-cells = <2>;
> +	};
> +
> +	[...]
> +
> +	bl: backlight {
> +		pwms = <&pwm 0 5000000>;
> +	};
> +
> +pwm-specifier typically encodes the chip-relative PWM number and the PWM
> +period in nanoseconds.

I like these bindings, this looks very straightforward to use while also
able to describe all possible cases.

> +/**
> + * of_node_to_pwmchip() - finds the PWM chip associated with a device node
> + * @np: device node of the PWM chip
> + *
> + * Returns a pointer to the PWM chip associated with the specified device
> + * node or NULL if the device node doesn't represent a PWM chip.
> + */
> +struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
> +{
> +	return pwmchip_find(np, of_pwmchip_is_match);
> +}
> +
> +int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
> +			struct pwm_spec *spec)
> +{
> +	if (pc->of_pwm_n_cells < 2)
> +		return -EINVAL;
> +
> +	if (args->args_count < pc->of_pwm_n_cells)
> +		return -EINVAL;
> +
> +	if (args->args[0] >= pc->npwm)
> +		return -EINVAL;
> +
> +	if (spec)
> +		spec->period = args->args[1];
> +
> +	return args->args[0];
> +}

I'm not sure why these functions are global. They are clearly marked
so in your header file, but it seems that these are an implementation
detail that neither a pwm controller driver not a driver using one
would need to use directly.

> +/**
> + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> + * @np: device node to get the PWM from
> + * @propname: property name containing PWM specifier(s)
> + * @index: index of the PWM
> + * @spec: a pointer to a struct pwm_spec to fill in
> + *
> + * Returns PWM number to use with the Linux generic PWM API or a negative
> + * error code on failure. If @spec is not NULL the function fills in the
> + * values parsed from the device tree.
> + */
> +int of_get_named_pwm(struct device_node *np, const char *propname,
> +		     int index, struct pwm_spec *spec)
> +{

This interface does not feel right to me, in multiple ways:

* I would expect to pass a struct device in, not a device_node.

* Why not include the pwm_request() call in this and return the
  pwm_device directly? You said that you want to get rid of the
  pwm_id eventually, which is a good idea, but this interface still
  forces one to use it.

* It is not clear what a pwm_spec is used for, or why a device
  driver would need to be bothered by this. Maybe it just needs
  more explanation, but it seems to me that if you do the previous
  change, the pwm_spec would not be needed either.

> +EXPORT_SYMBOL(of_get_named_pwm);

EXPORT_SYMBOL_GPL?

> +static inline int of_get_named_pwm(struct device_node *np,
> +                                  const char *propname, int index,
> +                                  unsigned int *period_ns)
> +{

The function prototype does not match.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-22 16:15         ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 22 February 2012, Thierry Reding wrote:
> This patch adds helpers to support device tree bindings for the generic
> PWM API. Device tree binding documentation for PWM controllers is also
> provided.
> 
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> 
>  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
>  drivers/of/Kconfig                            |    6 +
>  drivers/of/Makefile                           |    1 +
>  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
>  include/linux/of_pwm.h                        |   51 ++++++++++
>  include/linux/pwm.h                           |   17 +++

I think it would make more sense to stick the device tree specific parts
into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
preference on my part.

> @@ -0,0 +1,48 @@
> +Specifying PWM information for devices
> +======================================
> +
> +1) PWM user nodes
> +-----------------
> +
> +PWM users should specify a list of PWM devices that they want to use
> +with a property containing a 'pwm-list':
> +
> +	pwm-list ::= <single-pwm> [pwm-list]
> +	single-pwm ::= <pwm-phandle> <pwm-specifier>
> +	pwm-phandle : phandle to PWM controller node
> +	pwm-specifier : array of #pwm-cells specifying the given PWM
> +			(controller specific)
> +
> +PWM properties should be named "[<name>-]pwms". Exact meaning of each
> +pwms property must be documented in the device tree binding for each
> +device.
> +
> +The following example could be used to describe a PWM-based backlight
> +device:
> +
> +	pwm: pwm {
> +		#pwm-cells = <2>;
> +	};
> +
> +	[...]
> +
> +	bl: backlight {
> +		pwms = <&pwm 0 5000000>;
> +	};
> +
> +pwm-specifier typically encodes the chip-relative PWM number and the PWM
> +period in nanoseconds.

I like these bindings, this looks very straightforward to use while also
able to describe all possible cases.

> +/**
> + * of_node_to_pwmchip() - finds the PWM chip associated with a device node
> + * @np: device node of the PWM chip
> + *
> + * Returns a pointer to the PWM chip associated with the specified device
> + * node or NULL if the device node doesn't represent a PWM chip.
> + */
> +struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
> +{
> +	return pwmchip_find(np, of_pwmchip_is_match);
> +}
> +
> +int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
> +			struct pwm_spec *spec)
> +{
> +	if (pc->of_pwm_n_cells < 2)
> +		return -EINVAL;
> +
> +	if (args->args_count < pc->of_pwm_n_cells)
> +		return -EINVAL;
> +
> +	if (args->args[0] >= pc->npwm)
> +		return -EINVAL;
> +
> +	if (spec)
> +		spec->period = args->args[1];
> +
> +	return args->args[0];
> +}

I'm not sure why these functions are global. They are clearly marked
so in your header file, but it seems that these are an implementation
detail that neither a pwm controller driver not a driver using one
would need to use directly.

> +/**
> + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> + * @np: device node to get the PWM from
> + * @propname: property name containing PWM specifier(s)
> + * @index: index of the PWM
> + * @spec: a pointer to a struct pwm_spec to fill in
> + *
> + * Returns PWM number to use with the Linux generic PWM API or a negative
> + * error code on failure. If @spec is not NULL the function fills in the
> + * values parsed from the device tree.
> + */
> +int of_get_named_pwm(struct device_node *np, const char *propname,
> +		     int index, struct pwm_spec *spec)
> +{

This interface does not feel right to me, in multiple ways:

* I would expect to pass a struct device in, not a device_node.

* Why not include the pwm_request() call in this and return the
  pwm_device directly? You said that you want to get rid of the
  pwm_id eventually, which is a good idea, but this interface still
  forces one to use it.

* It is not clear what a pwm_spec is used for, or why a device
  driver would need to be bothered by this. Maybe it just needs
  more explanation, but it seems to me that if you do the previous
  change, the pwm_spec would not be needed either.

> +EXPORT_SYMBOL(of_get_named_pwm);

EXPORT_SYMBOL_GPL?

> +static inline int of_get_named_pwm(struct device_node *np,
> +                                  const char *propname, int index,
> +                                  unsigned int *period_ns)
> +{

The function prototype does not match.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-22 16:34         ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:34 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Wednesday 22 February 2012, Thierry Reding wrote:

>  #include <linux/module.h>
> +#include <linux/of_pwm.h>
>  #include <linux/pwm.h>

You should probably reorder the patches for bisectability, or move the
of_* related changes out of this patch into patch 3. At the point
where patch 2 is applied, linux/of_pwm.h does not exist yet.

>  
> +/**
> + * pwmchip_find() - iterator for locating a specific pwm_chip
> + * @data: data to pass to match function
> + * @match: callback function to check pwm_chip
> + */
> +struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
> +						       void *data))
> +{
> +	struct pwm_chip *ret = NULL;
> +	struct pwm_chip *chip;
> +
> +	mutex_lock(&pwm_lock);
> +
> +	list_for_each_entry(chip, &pwm_chips, list) {
> +		if (match(chip, data)) {
> +			ret = chip;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&pwm_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(pwmchip_find);

Is this only used for the device tree functions? If so, I would recommend
making it less generic and always search for a device node.

> +static int pwm_show(struct seq_file *s, void *unused)
> +{
> +	const char *prefix = "";
> +	struct pwm_chip *chip;
> +
> +	list_for_each_entry(chip, &pwm_chips, list) {
> +		struct device *dev = chip->dev;
> +
> +		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
> +			   dev->bus ? dev->bus->name : "no-bus",
> +			   dev_name(dev), chip->npwm);
> +
> +		if (chip->ops->dbg_show)
> +			chip->ops->dbg_show(chip, s);
> +		else
> +			pwm_dbg_show(chip, s);
> +
> +		prefix = "\n";
> +	}
> +
> +	return 0;
> +}
> +
> +static int pwm_open(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, pwm_show, NULL);
> +}

When you have a seq_file with a (possibly long) list of entries, better
use seq_open instead of single_open and print each item in the
->next() callback function.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-02-22 16:34         ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-22 16:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 22 February 2012, Thierry Reding wrote:

>  #include <linux/module.h>
> +#include <linux/of_pwm.h>
>  #include <linux/pwm.h>

You should probably reorder the patches for bisectability, or move the
of_* related changes out of this patch into patch 3. At the point
where patch 2 is applied, linux/of_pwm.h does not exist yet.

>  
> +/**
> + * pwmchip_find() - iterator for locating a specific pwm_chip
> + * @data: data to pass to match function
> + * @match: callback function to check pwm_chip
> + */
> +struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
> +						       void *data))
> +{
> +	struct pwm_chip *ret = NULL;
> +	struct pwm_chip *chip;
> +
> +	mutex_lock(&pwm_lock);
> +
> +	list_for_each_entry(chip, &pwm_chips, list) {
> +		if (match(chip, data)) {
> +			ret = chip;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&pwm_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(pwmchip_find);

Is this only used for the device tree functions? If so, I would recommend
making it less generic and always search for a device node.

> +static int pwm_show(struct seq_file *s, void *unused)
> +{
> +	const char *prefix = "";
> +	struct pwm_chip *chip;
> +
> +	list_for_each_entry(chip, &pwm_chips, list) {
> +		struct device *dev = chip->dev;
> +
> +		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
> +			   dev->bus ? dev->bus->name : "no-bus",
> +			   dev_name(dev), chip->npwm);
> +
> +		if (chip->ops->dbg_show)
> +			chip->ops->dbg_show(chip, s);
> +		else
> +			pwm_dbg_show(chip, s);
> +
> +		prefix = "\n";
> +	}
> +
> +	return 0;
> +}
> +
> +static int pwm_open(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, pwm_show, NULL);
> +}

When you have a seq_file with a (possibly long) list of entries, better
use seq_open instead of single_open and print each item in the
->next() callback function.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-23  1:47         ` Ryan Mallon
  -1 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-23  1:47 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen

On 23/02/12 02:17, Thierry Reding wrote:

> This commit adds a generic PWM framework driver for the PWFM controller
> found on NVIDIA Tegra SoCs. The driver is based on code from the
> Chromium kernel tree and was originally written by Gary King (NVIDIA)
> and later modified by Simon Que (Chromium).
> 
> Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> ---

<snip>

> +
> +	pwm->chip.dev = &pdev->dev;
> +	pwm->chip.ops = &tegra_pwm_ops;
> +	pwm->chip.base = -1;
> +	pwm->chip.npwm = NUM_PWM;

> +
> +	ret = pwmchip_add(&pwm->chip);


If a driver fails to initialise the pwm_chip structure correctly it can
cause problems in the pwm core. For example, if the dev field doesn't
get set, then you will get an oops if you try to cat the pwm debugfs file.

pwmchip_add should probably verify that the initialisation of the
pwm_chip structure is sane to avoid problems like this.

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-23  1:47         ` Ryan Mallon
  0 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-23  1:47 UTC (permalink / raw)
  To: linux-arm-kernel

On 23/02/12 02:17, Thierry Reding wrote:

> This commit adds a generic PWM framework driver for the PWFM controller
> found on NVIDIA Tegra SoCs. The driver is based on code from the
> Chromium kernel tree and was originally written by Gary King (NVIDIA)
> and later modified by Simon Que (Chromium).
> 
> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> ---

<snip>

> +
> +	pwm->chip.dev = &pdev->dev;
> +	pwm->chip.ops = &tegra_pwm_ops;
> +	pwm->chip.base = -1;
> +	pwm->chip.npwm = NUM_PWM;

> +
> +	ret = pwmchip_add(&pwm->chip);


If a driver fails to initialise the pwm_chip structure correctly it can
cause problems in the pwm core. For example, if the dev field doesn't
get set, then you will get an oops if you try to cat the pwm debugfs file.

pwmchip_add should probably verify that the initialisation of the
pwm_chip structure is sane to avoid problems like this.

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 09/10] pwm: Add PXA support
  2012-02-22 15:40         ` Arnd Bergmann
@ 2012-02-23  6:10             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  6:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1344 bytes --]

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > 
> > Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> > ---
> > Changes in v3:
> >   - update PWM ops for changes in patch 2
> > 
> >  arch/arm/plat-pxa/Makefile |    1 -
> >  arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
> >  drivers/pwm/Kconfig        |    9 ++
> >  drivers/pwm/Makefile       |    1 +
> >  drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
> >  5 files changed, 254 insertions(+), 305 deletions(-)
> >  delete mode 100644 arch/arm/plat-pxa/pwm.c
> >  create mode 100644 drivers/pwm/pwm-pxa.c
> 
> Since most of this patch is a move of one file, it would help to use the -M
> flag to git-format-patch so we can see the actual change.

Okay, I'll make a note and see how that works out in the next version.

> To make it even more explicit, you could separate the patches that move the
> files around from the ones that convert the drivers to the new API.

Sascha already mentioned that he has all of the in-tree drivers converted to
the PWM framework, so if it is acceptable I'll leave that up to him. This
series ports the Blackfin and PXA drivers merely as reference drivers to test
the framework.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 09/10] pwm: Add PXA support
@ 2012-02-23  6:10             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  6:10 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > 
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > ---
> > Changes in v3:
> >   - update PWM ops for changes in patch 2
> > 
> >  arch/arm/plat-pxa/Makefile |    1 -
> >  arch/arm/plat-pxa/pwm.c    |  304 --------------------------------------------
> >  drivers/pwm/Kconfig        |    9 ++
> >  drivers/pwm/Makefile       |    1 +
> >  drivers/pwm/pwm-pxa.c      |  244 +++++++++++++++++++++++++++++++++++
> >  5 files changed, 254 insertions(+), 305 deletions(-)
> >  delete mode 100644 arch/arm/plat-pxa/pwm.c
> >  create mode 100644 drivers/pwm/pwm-pxa.c
> 
> Since most of this patch is a move of one file, it would help to use the -M
> flag to git-format-patch so we can see the actual change.

Okay, I'll make a note and see how that works out in the next version.

> To make it even more explicit, you could separate the patches that move the
> files around from the ones that convert the drivers to the new API.

Sascha already mentioned that he has all of the in-tree drivers converted to
the PWM framework, so if it is acceptable I'll leave that up to him. This
series ports the Blackfin and PXA drivers merely as reference drivers to test
the framework.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/2ca01bd4/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 00/10] Add PWM framework and device tree support.
  2012-02-22 16:02     ` Arnd Bergmann
@ 2012-02-23  7:29         ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  7:29 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > This patch series adds very rudimentary device-tree support for PWM
> > devices. With all of these patches applied (plus one board-specific
> > patch that is not included), I'm able to control the backlight on the
> > device I'm working on using the sysfs interface provided by the pwm-bl
> > driver and the backlight class.
> > 
> > This series is based on Sascha Hauer's series of patches[0] to add a
> > generic PWM framework. The first patch in this series is taken from
> > Sascha's branch, while the second patch enables each PWM chip to provide
> > multiple PWM devices (the Blackfin and PXA drivers have been ported to
> > the framework for reference). When this series is ready I think it would
> > be best to merge patches 1 and 2. Currently a global namespace is still
> > provided to keep backwards-compatibility with the legacy PWM API. In
> > order to achieve this, the number of global PWM devices is limited to
> > 1024. However, patch 2 introduces per-chip indexing of PWM devices in
> > the core, so it should be easy to add an API to request a PWM device on
> > a per-chip basis and get rid of the global namespace eventually. The
> > device tree support code does not use the global namespace.
> 
> Hi Thierry,
> 
> I've just had a chance to look at your series and I think this looks
> very good overall, great work!
> 
> I probably wouldn't bother merging patches 1 and 2 as you listed
> in the TODO section, in order to keep the authorship of each
> part obvious.

Okay, no problem.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 00/10] Add PWM framework and device tree support.
@ 2012-02-23  7:29         ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  7:29 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > This patch series adds very rudimentary device-tree support for PWM
> > devices. With all of these patches applied (plus one board-specific
> > patch that is not included), I'm able to control the backlight on the
> > device I'm working on using the sysfs interface provided by the pwm-bl
> > driver and the backlight class.
> > 
> > This series is based on Sascha Hauer's series of patches[0] to add a
> > generic PWM framework. The first patch in this series is taken from
> > Sascha's branch, while the second patch enables each PWM chip to provide
> > multiple PWM devices (the Blackfin and PXA drivers have been ported to
> > the framework for reference). When this series is ready I think it would
> > be best to merge patches 1 and 2. Currently a global namespace is still
> > provided to keep backwards-compatibility with the legacy PWM API. In
> > order to achieve this, the number of global PWM devices is limited to
> > 1024. However, patch 2 introduces per-chip indexing of PWM devices in
> > the core, so it should be easy to add an API to request a PWM device on
> > a per-chip basis and get rid of the global namespace eventually. The
> > device tree support code does not use the global namespace.
> 
> Hi Thierry,
> 
> I've just had a chance to look at your series and I think this looks
> very good overall, great work!
> 
> I probably wouldn't bother merging patches 1 and 2 as you listed
> in the TODO section, in order to keep the authorship of each
> part obvious.

Okay, no problem.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/8a98f07f/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-22 16:15         ` Arnd Bergmann
@ 2012-02-23  7:55             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  7:55 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Brown, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Colin Cross,
	Rob Herring, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck


[-- Attachment #1.1: Type: text/plain, Size: 6172 bytes --]

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > This patch adds helpers to support device tree bindings for the generic
> > PWM API. Device tree binding documentation for PWM controllers is also
> > provided.
> > 
> > Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> > 
> >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> >  drivers/of/Kconfig                            |    6 +
> >  drivers/of/Makefile                           |    1 +
> >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> >  include/linux/of_pwm.h                        |   51 ++++++++++
> >  include/linux/pwm.h                           |   17 +++
> 
> I think it would make more sense to stick the device tree specific parts
> into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> preference on my part.

I was just following what everybody else seemed to be doing. drivers/of/
already has support code for GPIO, IRQ, I2C, PCI and whatnot.

[...]
> > +/**
> > + * of_node_to_pwmchip() - finds the PWM chip associated with a device node
> > + * @np: device node of the PWM chip
> > + *
> > + * Returns a pointer to the PWM chip associated with the specified device
> > + * node or NULL if the device node doesn't represent a PWM chip.
> > + */
> > +struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
> > +{
> > +	return pwmchip_find(np, of_pwmchip_is_match);
> > +}
> > +
> > +int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
> > +			struct pwm_spec *spec)
> > +{
> > +	if (pc->of_pwm_n_cells < 2)
> > +		return -EINVAL;
> > +
> > +	if (args->args_count < pc->of_pwm_n_cells)
> > +		return -EINVAL;
> > +
> > +	if (args->args[0] >= pc->npwm)
> > +		return -EINVAL;
> > +
> > +	if (spec)
> > +		spec->period = args->args[1];
> > +
> > +	return args->args[0];
> > +}
> 
> I'm not sure why these functions are global. They are clearly marked
> so in your header file, but it seems that these are an implementation
> detail that neither a pwm controller driver not a driver using one
> would need to use directly.

Yes, I think both can be made static. of_pwm_simple_xlate() is supposed to be
the fallback when a chip doesn't explicitly specify one so it really isn't
necessary to export it (for that to be useful it is missing an EXPORT_SYMBOL
anyway).

> > +/**
> > + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> > + * @np: device node to get the PWM from
> > + * @propname: property name containing PWM specifier(s)
> > + * @index: index of the PWM
> > + * @spec: a pointer to a struct pwm_spec to fill in
> > + *
> > + * Returns PWM number to use with the Linux generic PWM API or a negative
> > + * error code on failure. If @spec is not NULL the function fills in the
> > + * values parsed from the device tree.
> > + */
> > +int of_get_named_pwm(struct device_node *np, const char *propname,
> > +		     int index, struct pwm_spec *spec)
> > +{
> 
> This interface does not feel right to me, in multiple ways:
> 
> * I would expect to pass a struct device in, not a device_node.

I was following the GPIO DT support code here. The corresponding
of_get_named_gpio_flags() takes a struct device_node. I guess that makes it
more generic since you can potentially have a struct device_node without a
corresponding struct device, right?

> * Why not include the pwm_request() call in this and return the
>   pwm_device directly? You said that you want to get rid of the
>   pwm_id eventually, which is a good idea, but this interface still
>   forces one to use it.

Okay, that sounds sensible. I propose to rename the function to something like
of_request_pwm(). It would of course need an additional parameter (name) to
forward to pwm_request().

> * It is not clear what a pwm_spec is used for, or why a device
>   driver would need to be bothered by this. Maybe it just needs
>   more explanation, but it seems to me that if you do the previous
>   change, the pwm_spec would not be needed either.

pwm_spec is pretty much what the of_xlate() callback parses out of the data
provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
period (in ns) but the idea was that if at some point in the future it was
decided to provide more than the period via the device tree it could be
extended without changing every call to of_get_named_pwm(). As I said, it also
plays quite nicely with the concept of the of_xlate() callback and sort of
serves as interface between the lower layer that retrieves PWM parameters and
the upper layers that use it.

Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
Also to avoid breakage or confusion if fields get added it may be good to
provide a bitmask of valid fields filled in by the of_xlate() callback.

	enum {
		PWM_PARAMS_PERIOD,
		...
	};

	struct pwm_params {
		unsigned long fields;
		unsigned int period;
	};

Then again, maybe that's just over-engineering and directly returning via an
unsigned int *period_ns parameter would be better?

> > +EXPORT_SYMBOL(of_get_named_pwm);
> 
> EXPORT_SYMBOL_GPL?

It was brought up at some point that it might be nice to allow non-GPL
drivers to use the PWM framework as well. I don't remember any discussion
resulting from the comment. Perhaps we should have that discussion now and
decide whether or not we want to keep it GPL-only or not.

> > +static inline int of_get_named_pwm(struct device_node *np,
> > +                                  const char *propname, int index,
> > +                                  unsigned int *period_ns)
> > +{
> 
> The function prototype does not match.

Yes, I must have forgotten to convert that when I changed that to struct
pwm_spec described above. Quite frankly I'm not sure about what is the best
alternative. Can anybody come up with more advantages or disadvantages for
both variations? Or perhaps there is even a better solution.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-23  7:55             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> > This patch adds helpers to support device tree bindings for the generic
> > PWM API. Device tree binding documentation for PWM controllers is also
> > provided.
> > 
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > 
> >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> >  drivers/of/Kconfig                            |    6 +
> >  drivers/of/Makefile                           |    1 +
> >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> >  include/linux/of_pwm.h                        |   51 ++++++++++
> >  include/linux/pwm.h                           |   17 +++
> 
> I think it would make more sense to stick the device tree specific parts
> into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> preference on my part.

I was just following what everybody else seemed to be doing. drivers/of/
already has support code for GPIO, IRQ, I2C, PCI and whatnot.

[...]
> > +/**
> > + * of_node_to_pwmchip() - finds the PWM chip associated with a device node
> > + * @np: device node of the PWM chip
> > + *
> > + * Returns a pointer to the PWM chip associated with the specified device
> > + * node or NULL if the device node doesn't represent a PWM chip.
> > + */
> > +struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
> > +{
> > +	return pwmchip_find(np, of_pwmchip_is_match);
> > +}
> > +
> > +int of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args,
> > +			struct pwm_spec *spec)
> > +{
> > +	if (pc->of_pwm_n_cells < 2)
> > +		return -EINVAL;
> > +
> > +	if (args->args_count < pc->of_pwm_n_cells)
> > +		return -EINVAL;
> > +
> > +	if (args->args[0] >= pc->npwm)
> > +		return -EINVAL;
> > +
> > +	if (spec)
> > +		spec->period = args->args[1];
> > +
> > +	return args->args[0];
> > +}
> 
> I'm not sure why these functions are global. They are clearly marked
> so in your header file, but it seems that these are an implementation
> detail that neither a pwm controller driver not a driver using one
> would need to use directly.

Yes, I think both can be made static. of_pwm_simple_xlate() is supposed to be
the fallback when a chip doesn't explicitly specify one so it really isn't
necessary to export it (for that to be useful it is missing an EXPORT_SYMBOL
anyway).

> > +/**
> > + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> > + * @np: device node to get the PWM from
> > + * @propname: property name containing PWM specifier(s)
> > + * @index: index of the PWM
> > + * @spec: a pointer to a struct pwm_spec to fill in
> > + *
> > + * Returns PWM number to use with the Linux generic PWM API or a negative
> > + * error code on failure. If @spec is not NULL the function fills in the
> > + * values parsed from the device tree.
> > + */
> > +int of_get_named_pwm(struct device_node *np, const char *propname,
> > +		     int index, struct pwm_spec *spec)
> > +{
> 
> This interface does not feel right to me, in multiple ways:
> 
> * I would expect to pass a struct device in, not a device_node.

I was following the GPIO DT support code here. The corresponding
of_get_named_gpio_flags() takes a struct device_node. I guess that makes it
more generic since you can potentially have a struct device_node without a
corresponding struct device, right?

> * Why not include the pwm_request() call in this and return the
>   pwm_device directly? You said that you want to get rid of the
>   pwm_id eventually, which is a good idea, but this interface still
>   forces one to use it.

Okay, that sounds sensible. I propose to rename the function to something like
of_request_pwm(). It would of course need an additional parameter (name) to
forward to pwm_request().

> * It is not clear what a pwm_spec is used for, or why a device
>   driver would need to be bothered by this. Maybe it just needs
>   more explanation, but it seems to me that if you do the previous
>   change, the pwm_spec would not be needed either.

pwm_spec is pretty much what the of_xlate() callback parses out of the data
provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
period (in ns) but the idea was that if at some point in the future it was
decided to provide more than the period via the device tree it could be
extended without changing every call to of_get_named_pwm(). As I said, it also
plays quite nicely with the concept of the of_xlate() callback and sort of
serves as interface between the lower layer that retrieves PWM parameters and
the upper layers that use it.

Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
Also to avoid breakage or confusion if fields get added it may be good to
provide a bitmask of valid fields filled in by the of_xlate() callback.

	enum {
		PWM_PARAMS_PERIOD,
		...
	};

	struct pwm_params {
		unsigned long fields;
		unsigned int period;
	};

Then again, maybe that's just over-engineering and directly returning via an
unsigned int *period_ns parameter would be better?

> > +EXPORT_SYMBOL(of_get_named_pwm);
> 
> EXPORT_SYMBOL_GPL?

It was brought up at some point that it might be nice to allow non-GPL
drivers to use the PWM framework as well. I don't remember any discussion
resulting from the comment. Perhaps we should have that discussion now and
decide whether or not we want to keep it GPL-only or not.

> > +static inline int of_get_named_pwm(struct device_node *np,
> > +                                  const char *propname, int index,
> > +                                  unsigned int *period_ns)
> > +{
> 
> The function prototype does not match.

Yes, I must have forgotten to convert that when I changed that to struct
pwm_spec described above. Quite frankly I'm not sure about what is the best
alternative. Can anybody come up with more advantages or disadvantages for
both variations? Or perhaps there is even a better solution.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/53285309/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-22 16:34         ` Arnd Bergmann
@ 2012-02-23  8:12             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  8:12 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Brown, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Colin Cross,
	Rob Herring, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck


[-- Attachment #1.1: Type: text/plain, Size: 2959 bytes --]

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> 
> >  #include <linux/module.h>
> > +#include <linux/of_pwm.h>
> >  #include <linux/pwm.h>
> 
> You should probably reorder the patches for bisectability, or move the
> of_* related changes out of this patch into patch 3. At the point
> where patch 2 is applied, linux/of_pwm.h does not exist yet.

You're right. The correct thing would be to move the include into patch 3.
I'll make sure to check for bisectability in the next series.

> > +/**
> > + * pwmchip_find() - iterator for locating a specific pwm_chip
> > + * @data: data to pass to match function
> > + * @match: callback function to check pwm_chip
> > + */
> > +struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
> > +						       void *data))
> > +{
> > +	struct pwm_chip *ret = NULL;
> > +	struct pwm_chip *chip;
> > +
> > +	mutex_lock(&pwm_lock);
> > +
> > +	list_for_each_entry(chip, &pwm_chips, list) {
> > +		if (match(chip, data)) {
> > +			ret = chip;
> > +			break;
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&pwm_lock);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(pwmchip_find);
> 
> Is this only used for the device tree functions? If so, I would recommend
> making it less generic and always search for a device node.

It is currently only used to look up a struct pwm_chip for a given struct
device_node, yes. But I can see other uses for this. For instance this could
be useful if we ever want to provide an alternative way of requesting a PWM
on a per-chip basis.

> > +static int pwm_show(struct seq_file *s, void *unused)
> > +{
> > +	const char *prefix = "";
> > +	struct pwm_chip *chip;
> > +
> > +	list_for_each_entry(chip, &pwm_chips, list) {
> > +		struct device *dev = chip->dev;
> > +
> > +		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
> > +			   dev->bus ? dev->bus->name : "no-bus",
> > +			   dev_name(dev), chip->npwm);
> > +
> > +		if (chip->ops->dbg_show)
> > +			chip->ops->dbg_show(chip, s);
> > +		else
> > +			pwm_dbg_show(chip, s);
> > +
> > +		prefix = "\n";
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int pwm_open(struct inode *inode, struct file *file)
> > +{
> > +	return single_open(file, pwm_show, NULL);
> > +}
> 
> When you have a seq_file with a (possibly long) list of entries, better
> use seq_open instead of single_open and print each item in the
> ->next() callback function.

Yes, that should work better. I just noticed that pwm_show() is actually
missing mutex_lock() and mutex_unlock() to protect against chip removal. With
the iterator interface that should be easy to add.

I was again basically looking at gpiolib for inspiration (maybe I should stop
doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
interface as well? Just in case anybody else turns to gpiolib for
inspiration.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-02-23  8:12             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  8:12 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Wednesday 22 February 2012, Thierry Reding wrote:
> 
> >  #include <linux/module.h>
> > +#include <linux/of_pwm.h>
> >  #include <linux/pwm.h>
> 
> You should probably reorder the patches for bisectability, or move the
> of_* related changes out of this patch into patch 3. At the point
> where patch 2 is applied, linux/of_pwm.h does not exist yet.

You're right. The correct thing would be to move the include into patch 3.
I'll make sure to check for bisectability in the next series.

> > +/**
> > + * pwmchip_find() - iterator for locating a specific pwm_chip
> > + * @data: data to pass to match function
> > + * @match: callback function to check pwm_chip
> > + */
> > +struct pwm_chip *pwmchip_find(void *data, int (*match)(struct pwm_chip *chip,
> > +						       void *data))
> > +{
> > +	struct pwm_chip *ret = NULL;
> > +	struct pwm_chip *chip;
> > +
> > +	mutex_lock(&pwm_lock);
> > +
> > +	list_for_each_entry(chip, &pwm_chips, list) {
> > +		if (match(chip, data)) {
> > +			ret = chip;
> > +			break;
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&pwm_lock);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(pwmchip_find);
> 
> Is this only used for the device tree functions? If so, I would recommend
> making it less generic and always search for a device node.

It is currently only used to look up a struct pwm_chip for a given struct
device_node, yes. But I can see other uses for this. For instance this could
be useful if we ever want to provide an alternative way of requesting a PWM
on a per-chip basis.

> > +static int pwm_show(struct seq_file *s, void *unused)
> > +{
> > +	const char *prefix = "";
> > +	struct pwm_chip *chip;
> > +
> > +	list_for_each_entry(chip, &pwm_chips, list) {
> > +		struct device *dev = chip->dev;
> > +
> > +		seq_printf(s, "%s%s/%s, %d PWM devices\n", prefix,
> > +			   dev->bus ? dev->bus->name : "no-bus",
> > +			   dev_name(dev), chip->npwm);
> > +
> > +		if (chip->ops->dbg_show)
> > +			chip->ops->dbg_show(chip, s);
> > +		else
> > +			pwm_dbg_show(chip, s);
> > +
> > +		prefix = "\n";
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int pwm_open(struct inode *inode, struct file *file)
> > +{
> > +	return single_open(file, pwm_show, NULL);
> > +}
> 
> When you have a seq_file with a (possibly long) list of entries, better
> use seq_open instead of single_open and print each item in the
> ->next() callback function.

Yes, that should work better. I just noticed that pwm_show() is actually
missing mutex_lock() and mutex_unlock() to protect against chip removal. With
the iterator interface that should be easy to add.

I was again basically looking at gpiolib for inspiration (maybe I should stop
doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
interface as well? Just in case anybody else turns to gpiolib for
inspiration.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/3dca4417/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-23  1:47         ` Ryan Mallon
@ 2012-02-23  8:14             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  8:14 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: Mark Brown, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Colin Cross, Rob Herring, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck


[-- Attachment #1.1: Type: text/plain, Size: 1196 bytes --]

* Ryan Mallon wrote:
> On 23/02/12 02:17, Thierry Reding wrote:
> 
> > This commit adds a generic PWM framework driver for the PWFM controller
> > found on NVIDIA Tegra SoCs. The driver is based on code from the
> > Chromium kernel tree and was originally written by Gary King (NVIDIA)
> > and later modified by Simon Que (Chromium).
> > 
> > Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> > ---
> 
> <snip>
> 
> > +
> > +	pwm->chip.dev = &pdev->dev;
> > +	pwm->chip.ops = &tegra_pwm_ops;
> > +	pwm->chip.base = -1;
> > +	pwm->chip.npwm = NUM_PWM;
> 
> > +
> > +	ret = pwmchip_add(&pwm->chip);
> 
> 
> If a driver fails to initialise the pwm_chip structure correctly it can
> cause problems in the pwm core. For example, if the dev field doesn't
> get set, then you will get an oops if you try to cat the pwm debugfs file.
> 
> pwmchip_add should probably verify that the initialisation of the
> pwm_chip structure is sane to avoid problems like this.

Absolutely. What would be the best response to an invalid struct pwm_chip? I
suppose at least returning -EINVAL, perhaps complemented with WARN_ON?

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-23  8:14             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23  8:14 UTC (permalink / raw)
  To: linux-arm-kernel

* Ryan Mallon wrote:
> On 23/02/12 02:17, Thierry Reding wrote:
> 
> > This commit adds a generic PWM framework driver for the PWFM controller
> > found on NVIDIA Tegra SoCs. The driver is based on code from the
> > Chromium kernel tree and was originally written by Gary King (NVIDIA)
> > and later modified by Simon Que (Chromium).
> > 
> > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > ---
> 
> <snip>
> 
> > +
> > +	pwm->chip.dev = &pdev->dev;
> > +	pwm->chip.ops = &tegra_pwm_ops;
> > +	pwm->chip.base = -1;
> > +	pwm->chip.npwm = NUM_PWM;
> 
> > +
> > +	ret = pwmchip_add(&pwm->chip);
> 
> 
> If a driver fails to initialise the pwm_chip structure correctly it can
> cause problems in the pwm core. For example, if the dev field doesn't
> get set, then you will get an oops if you try to cat the pwm debugfs file.
> 
> pwmchip_add should probably verify that the initialisation of the
> pwm_chip structure is sane to avoid problems like this.

Absolutely. What would be the best response to an invalid struct pwm_chip? I
suppose at least returning -EINVAL, perhaps complemented with WARN_ON?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/9a5b0415/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-23  8:14             ` Thierry Reding
@ 2012-02-23  9:25                 ` Ryan Mallon
  -1 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-23  9:25 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen

On 23/02/12 19:14, Thierry Reding wrote:

> * Ryan Mallon wrote:
>> On 23/02/12 02:17, Thierry Reding wrote:
>>
>>> This commit adds a generic PWM framework driver for the PWFM controller
>>> found on NVIDIA Tegra SoCs. The driver is based on code from the
>>> Chromium kernel tree and was originally written by Gary King (NVIDIA)
>>> and later modified by Simon Que (Chromium).
>>>
>>> Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
>>> ---
>>
>> <snip>
>>
>>> +
>>> +	pwm->chip.dev = &pdev->dev;
>>> +	pwm->chip.ops = &tegra_pwm_ops;
>>> +	pwm->chip.base = -1;
>>> +	pwm->chip.npwm = NUM_PWM;
>>
>>> +
>>> +	ret = pwmchip_add(&pwm->chip);
>>
>>
>> If a driver fails to initialise the pwm_chip structure correctly it can
>> cause problems in the pwm core. For example, if the dev field doesn't
>> get set, then you will get an oops if you try to cat the pwm debugfs file.
>>
>> pwmchip_add should probably verify that the initialisation of the
>> pwm_chip structure is sane to avoid problems like this.
> 
> Absolutely. What would be the best response to an invalid struct pwm_chip? I
> suppose at least returning -EINVAL, perhaps complemented with WARN_ON?


Just returning -EINVAL should be okay. I don't think you need a WARN_ON,
since failing to register the hardware should be enough of a reason for
a user to report a problem.

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-23  9:25                 ` Ryan Mallon
  0 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-23  9:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 23/02/12 19:14, Thierry Reding wrote:

> * Ryan Mallon wrote:
>> On 23/02/12 02:17, Thierry Reding wrote:
>>
>>> This commit adds a generic PWM framework driver for the PWFM controller
>>> found on NVIDIA Tegra SoCs. The driver is based on code from the
>>> Chromium kernel tree and was originally written by Gary King (NVIDIA)
>>> and later modified by Simon Que (Chromium).
>>>
>>> Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
>>> ---
>>
>> <snip>
>>
>>> +
>>> +	pwm->chip.dev = &pdev->dev;
>>> +	pwm->chip.ops = &tegra_pwm_ops;
>>> +	pwm->chip.base = -1;
>>> +	pwm->chip.npwm = NUM_PWM;
>>
>>> +
>>> +	ret = pwmchip_add(&pwm->chip);
>>
>>
>> If a driver fails to initialise the pwm_chip structure correctly it can
>> cause problems in the pwm core. For example, if the dev field doesn't
>> get set, then you will get an oops if you try to cat the pwm debugfs file.
>>
>> pwmchip_add should probably verify that the initialisation of the
>> pwm_chip structure is sane to avoid problems like this.
> 
> Absolutely. What would be the best response to an invalid struct pwm_chip? I
> suppose at least returning -EINVAL, perhaps complemented with WARN_ON?


Just returning -EINVAL should be okay. I don't think you need a WARN_ON,
since failing to register the hardware should be enough of a reason for
a user to report a problem.

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-23  7:55             ` Thierry Reding
@ 2012-02-23 14:03                 ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-23 14:03 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Thursday 23 February 2012, Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Wednesday 22 February 2012, Thierry Reding wrote:
> > > This patch adds helpers to support device tree bindings for the generic
> > > PWM API. Device tree binding documentation for PWM controllers is also
> > > provided.
> > > 
> > > Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> > > 
> > >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> > >  drivers/of/Kconfig                            |    6 +
> > >  drivers/of/Makefile                           |    1 +
> > >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> > >  include/linux/of_pwm.h                        |   51 ++++++++++
> > >  include/linux/pwm.h                           |   17 +++
> > 
> > I think it would make more sense to stick the device tree specific parts
> > into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> > preference on my part.
> 
> I was just following what everybody else seemed to be doing. drivers/of/
> already has support code for GPIO, IRQ, I2C, PCI and whatnot.

Yes, as I said, it's not entirely clear what's best here, and it would
be nice if other people could weigh in when they have a strong opinion
one way or another.

> > > +/**
> > > + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> > > + * @np: device node to get the PWM from
> > > + * @propname: property name containing PWM specifier(s)
> > > + * @index: index of the PWM
> > > + * @spec: a pointer to a struct pwm_spec to fill in
> > > + *
> > > + * Returns PWM number to use with the Linux generic PWM API or a negative
> > > + * error code on failure. If @spec is not NULL the function fills in the
> > > + * values parsed from the device tree.
> > > + */
> > > +int of_get_named_pwm(struct device_node *np, const char *propname,
> > > +		     int index, struct pwm_spec *spec)
> > > +{
> > 
> > This interface does not feel right to me, in multiple ways:
> > 
> > * I would expect to pass a struct device in, not a device_node.
> 
> I was following the GPIO DT support code here. The corresponding
> of_get_named_gpio_flags() takes a struct device_node. I guess that makes it
> more generic since you can potentially have a struct device_node without a
> corresponding struct device, right?

Yes, but I don't see that as important here.

> > * Why not include the pwm_request() call in this and return the
> >   pwm_device directly? You said that you want to get rid of the
> >   pwm_id eventually, which is a good idea, but this interface still
> >   forces one to use it.
> 
> Okay, that sounds sensible. I propose to rename the function to something like
> of_request_pwm().

Sounds good.

> It would of course need an additional parameter (name) to
> forward to pwm_request().

Not necessarily, it could use the dev_name(device) or the name
of the property, or a combination of the two.

> > * It is not clear what a pwm_spec is used for, or why a device
> >   driver would need to be bothered by this. Maybe it just needs
> >   more explanation, but it seems to me that if you do the previous
> >   change, the pwm_spec would not be needed either.
> 
> pwm_spec is pretty much what the of_xlate() callback parses out of the data
> provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
> period (in ns) but the idea was that if at some point in the future it was
> decided to provide more than the period via the device tree it could be
> extended without changing every call to of_get_named_pwm(). As I said, it also
> plays quite nicely with the concept of the of_xlate() callback and sort of
> serves as interface between the lower layer that retrieves PWM parameters and
> the upper layers that use it.
> 
> Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
> Also to avoid breakage or confusion if fields get added it may be good to
> provide a bitmask of valid fields filled in by the of_xlate() callback.
> 
> 	enum {
> 		PWM_PARAMS_PERIOD,
> 		...
> 	};
> 
> 	struct pwm_params {
> 		unsigned long fields;
> 		unsigned int period;
> 	};
> 
> Then again, maybe that's just over-engineering and directly returning via an
> unsigned int *period_ns parameter would be better?

It certainly sounds like over-engineering to me. Why not keep all that
information hidden inside the struct pwm_device and provide accessor
functions like this?

unsigned int pwm_get_period(struct pwm_device *pwm);

> > > +EXPORT_SYMBOL(of_get_named_pwm);
> > 
> > EXPORT_SYMBOL_GPL?
> 
> It was brought up at some point that it might be nice to allow non-GPL
> drivers to use the PWM framework as well. I don't remember any discussion
> resulting from the comment. Perhaps we should have that discussion now and
> decide whether or not we want to keep it GPL-only or not.

I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
replaces an earlier interface that was available as EXPORT_SYMBOL.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-23 14:03                 ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-23 14:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 23 February 2012, Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Wednesday 22 February 2012, Thierry Reding wrote:
> > > This patch adds helpers to support device tree bindings for the generic
> > > PWM API. Device tree binding documentation for PWM controllers is also
> > > provided.
> > > 
> > > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > > 
> > >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> > >  drivers/of/Kconfig                            |    6 +
> > >  drivers/of/Makefile                           |    1 +
> > >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> > >  include/linux/of_pwm.h                        |   51 ++++++++++
> > >  include/linux/pwm.h                           |   17 +++
> > 
> > I think it would make more sense to stick the device tree specific parts
> > into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> > preference on my part.
> 
> I was just following what everybody else seemed to be doing. drivers/of/
> already has support code for GPIO, IRQ, I2C, PCI and whatnot.

Yes, as I said, it's not entirely clear what's best here, and it would
be nice if other people could weigh in when they have a strong opinion
one way or another.

> > > +/**
> > > + * of_get_named_pwm() - get a PWM number and period to use with the PWM API
> > > + * @np: device node to get the PWM from
> > > + * @propname: property name containing PWM specifier(s)
> > > + * @index: index of the PWM
> > > + * @spec: a pointer to a struct pwm_spec to fill in
> > > + *
> > > + * Returns PWM number to use with the Linux generic PWM API or a negative
> > > + * error code on failure. If @spec is not NULL the function fills in the
> > > + * values parsed from the device tree.
> > > + */
> > > +int of_get_named_pwm(struct device_node *np, const char *propname,
> > > +		     int index, struct pwm_spec *spec)
> > > +{
> > 
> > This interface does not feel right to me, in multiple ways:
> > 
> > * I would expect to pass a struct device in, not a device_node.
> 
> I was following the GPIO DT support code here. The corresponding
> of_get_named_gpio_flags() takes a struct device_node. I guess that makes it
> more generic since you can potentially have a struct device_node without a
> corresponding struct device, right?

Yes, but I don't see that as important here.

> > * Why not include the pwm_request() call in this and return the
> >   pwm_device directly? You said that you want to get rid of the
> >   pwm_id eventually, which is a good idea, but this interface still
> >   forces one to use it.
> 
> Okay, that sounds sensible. I propose to rename the function to something like
> of_request_pwm().

Sounds good.

> It would of course need an additional parameter (name) to
> forward to pwm_request().

Not necessarily, it could use the dev_name(device) or the name
of the property, or a combination of the two.

> > * It is not clear what a pwm_spec is used for, or why a device
> >   driver would need to be bothered by this. Maybe it just needs
> >   more explanation, but it seems to me that if you do the previous
> >   change, the pwm_spec would not be needed either.
> 
> pwm_spec is pretty much what the of_xlate() callback parses out of the data
> provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
> period (in ns) but the idea was that if at some point in the future it was
> decided to provide more than the period via the device tree it could be
> extended without changing every call to of_get_named_pwm(). As I said, it also
> plays quite nicely with the concept of the of_xlate() callback and sort of
> serves as interface between the lower layer that retrieves PWM parameters and
> the upper layers that use it.
> 
> Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
> Also to avoid breakage or confusion if fields get added it may be good to
> provide a bitmask of valid fields filled in by the of_xlate() callback.
> 
> 	enum {
> 		PWM_PARAMS_PERIOD,
> 		...
> 	};
> 
> 	struct pwm_params {
> 		unsigned long fields;
> 		unsigned int period;
> 	};
> 
> Then again, maybe that's just over-engineering and directly returning via an
> unsigned int *period_ns parameter would be better?

It certainly sounds like over-engineering to me. Why not keep all that
information hidden inside the struct pwm_device and provide accessor
functions like this?

unsigned int pwm_get_period(struct pwm_device *pwm);

> > > +EXPORT_SYMBOL(of_get_named_pwm);
> > 
> > EXPORT_SYMBOL_GPL?
> 
> It was brought up at some point that it might be nice to allow non-GPL
> drivers to use the PWM framework as well. I don't remember any discussion
> resulting from the comment. Perhaps we should have that discussion now and
> decide whether or not we want to keep it GPL-only or not.

I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
replaces an earlier interface that was available as EXPORT_SYMBOL.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-23  8:12             ` Thierry Reding
@ 2012-02-23 14:07                 ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-23 14:07 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Thursday 23 February 2012, Thierry Reding wrote:
> > Is this only used for the device tree functions? If so, I would recommend
> > making it less generic and always search for a device node.
> 
> It is currently only used to look up a struct pwm_chip for a given struct
> device_node, yes. But I can see other uses for this. For instance this could
> be useful if we ever want to provide an alternative way of requesting a PWM
> on a per-chip basis.

Nah, just keep it simple for now. If we need it later, we can still
add something like this back, but for now it's just a source of
confusion and possible bugs.

> I was again basically looking at gpiolib for inspiration (maybe I should stop
> doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
> interface as well? Just in case anybody else turns to gpiolib for
> inspiration.

Good idea. Would you be able to send a patch for that, too? I would guess
converting both at the same time would be easier for you than splitting
the work between two people.

	ARnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-02-23 14:07                 ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-23 14:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 23 February 2012, Thierry Reding wrote:
> > Is this only used for the device tree functions? If so, I would recommend
> > making it less generic and always search for a device node.
> 
> It is currently only used to look up a struct pwm_chip for a given struct
> device_node, yes. But I can see other uses for this. For instance this could
> be useful if we ever want to provide an alternative way of requesting a PWM
> on a per-chip basis.

Nah, just keep it simple for now. If we need it later, we can still
add something like this back, but for now it's just a source of
confusion and possible bugs.

> I was again basically looking at gpiolib for inspiration (maybe I should stop
> doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
> interface as well? Just in case anybody else turns to gpiolib for
> inspiration.

Good idea. Would you be able to send a patch for that, too? I would guess
converting both at the same time would be easier for you than splitting
the work between two people.

	ARnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-23 14:07                 ` Arnd Bergmann
@ 2012-02-23 16:04                     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23 16:04 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1199 bytes --]

* Arnd Bergmann wrote:
> On Thursday 23 February 2012, Thierry Reding wrote:
> > > Is this only used for the device tree functions? If so, I would recommend
> > > making it less generic and always search for a device node.
> > 
> > It is currently only used to look up a struct pwm_chip for a given struct
> > device_node, yes. But I can see other uses for this. For instance this could
> > be useful if we ever want to provide an alternative way of requesting a PWM
> > on a per-chip basis.
> 
> Nah, just keep it simple for now. If we need it later, we can still
> add something like this back, but for now it's just a source of
> confusion and possible bugs.

Will do.

> > I was again basically looking at gpiolib for inspiration (maybe I should stop
> > doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
> > interface as well? Just in case anybody else turns to gpiolib for
> > inspiration.
> 
> Good idea. Would you be able to send a patch for that, too? I would guess
> converting both at the same time would be easier for you than splitting
> the work between two people.

I'll take a shot at it. It may take some time, though.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-02-23 16:04                     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-23 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Thursday 23 February 2012, Thierry Reding wrote:
> > > Is this only used for the device tree functions? If so, I would recommend
> > > making it less generic and always search for a device node.
> > 
> > It is currently only used to look up a struct pwm_chip for a given struct
> > device_node, yes. But I can see other uses for this. For instance this could
> > be useful if we ever want to provide an alternative way of requesting a PWM
> > on a per-chip basis.
> 
> Nah, just keep it simple for now. If we need it later, we can still
> add something like this back, but for now it's just a source of
> confusion and possible bugs.

Will do.

> > I was again basically looking at gpiolib for inspiration (maybe I should stop
> > doing that :-). Maybe gpiolib should be reworked to use seq_file's iterator
> > interface as well? Just in case anybody else turns to gpiolib for
> > inspiration.
> 
> Good idea. Would you be able to send a patch for that, too? I would guess
> converting both at the same time would be easier for you than splitting
> the work between two people.

I'll take a shot at it. It may take some time, though.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120223/bf3ef144/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-23 14:03                 ` Arnd Bergmann
@ 2012-02-24  6:47                     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-24  6:47 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 5454 bytes --]

* Arnd Bergmann wrote:
> On Thursday 23 February 2012, Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Wednesday 22 February 2012, Thierry Reding wrote:
> > > > This patch adds helpers to support device tree bindings for the generic
> > > > PWM API. Device tree binding documentation for PWM controllers is also
> > > > provided.
> > > > 
> > > > Signed-off-by: Thierry Reding <thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
> > > > 
> > > >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> > > >  drivers/of/Kconfig                            |    6 +
> > > >  drivers/of/Makefile                           |    1 +
> > > >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> > > >  include/linux/of_pwm.h                        |   51 ++++++++++
> > > >  include/linux/pwm.h                           |   17 +++
> > > 
> > > I think it would make more sense to stick the device tree specific parts
> > > into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> > > preference on my part.
> > 
> > I was just following what everybody else seemed to be doing. drivers/of/
> > already has support code for GPIO, IRQ, I2C, PCI and whatnot.
> 
> Yes, as I said, it's not entirely clear what's best here, and it would
> be nice if other people could weigh in when they have a strong opinion
> one way or another.

Okay, I'll wait some more for others to join in.

[...]
> > > * Why not include the pwm_request() call in this and return the
> > >   pwm_device directly? You said that you want to get rid of the
> > >   pwm_id eventually, which is a good idea, but this interface still
> > >   forces one to use it.
> > 
> > Okay, that sounds sensible. I propose to rename the function to something like
> > of_request_pwm().
> 
> Sounds good.
> 
> > It would of course need an additional parameter (name) to
> > forward to pwm_request().
> 
> Not necessarily, it could use the dev_name(device) or the name
> of the property, or a combination of the two.

The problem with that is that usually the device would be named something
generic like "pwm", while in case where the PWM is used for the backlight
it makes sense to label the PWM device "backlight".

Looking at debugfs and seeing an entry "backlight" is much more straight-
forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
really, does it?

> > > * It is not clear what a pwm_spec is used for, or why a device
> > >   driver would need to be bothered by this. Maybe it just needs
> > >   more explanation, but it seems to me that if you do the previous
> > >   change, the pwm_spec would not be needed either.
> > 
> > pwm_spec is pretty much what the of_xlate() callback parses out of the data
> > provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
> > period (in ns) but the idea was that if at some point in the future it was
> > decided to provide more than the period via the device tree it could be
> > extended without changing every call to of_get_named_pwm(). As I said, it also
> > plays quite nicely with the concept of the of_xlate() callback and sort of
> > serves as interface between the lower layer that retrieves PWM parameters and
> > the upper layers that use it.
> > 
> > Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
> > Also to avoid breakage or confusion if fields get added it may be good to
> > provide a bitmask of valid fields filled in by the of_xlate() callback.
> > 
> > 	enum {
> > 		PWM_PARAMS_PERIOD,
> > 		...
> > 	};
> > 
> > 	struct pwm_params {
> > 		unsigned long fields;
> > 		unsigned int period;
> > 	};
> > 
> > Then again, maybe that's just over-engineering and directly returning via an
> > unsigned int *period_ns parameter would be better?
> 
> It certainly sounds like over-engineering to me. Why not keep all that
> information hidden inside the struct pwm_device and provide accessor
> functions like this?
> 
> unsigned int pwm_get_period(struct pwm_device *pwm);

Heh, I like that. It is the obvious thing to do. Why didn't I think of it?
:-)

> > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > 
> > > EXPORT_SYMBOL_GPL?
> > 
> > It was brought up at some point that it might be nice to allow non-GPL
> > drivers to use the PWM framework as well. I don't remember any discussion
> > resulting from the comment. Perhaps we should have that discussion now and
> > decide whether or not we want to keep it GPL-only or not.
> 
> I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> replaces an earlier interface that was available as EXPORT_SYMBOL.

I just grepped the code and noticed this:

	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);

It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
Also does it make sense to have something like of_request_pwm() GPL when the
rest of the API isn't?

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-24  6:47                     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-24  6:47 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Thursday 23 February 2012, Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Wednesday 22 February 2012, Thierry Reding wrote:
> > > > This patch adds helpers to support device tree bindings for the generic
> > > > PWM API. Device tree binding documentation for PWM controllers is also
> > > > provided.
> > > > 
> > > > Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
> > > > 
> > > >  Documentation/devicetree/bindings/pwm/pwm.txt |   48 +++++++++
> > > >  drivers/of/Kconfig                            |    6 +
> > > >  drivers/of/Makefile                           |    1 +
> > > >  drivers/of/pwm.c                              |  130 +++++++++++++++++++++++++
> > > >  include/linux/of_pwm.h                        |   51 ++++++++++
> > > >  include/linux/pwm.h                           |   17 +++
> > > 
> > > I think it would make more sense to stick the device tree specific parts
> > > into drivers/pwm/of.c instead of drivers/of/pwm.c, but it's not a strong
> > > preference on my part.
> > 
> > I was just following what everybody else seemed to be doing. drivers/of/
> > already has support code for GPIO, IRQ, I2C, PCI and whatnot.
> 
> Yes, as I said, it's not entirely clear what's best here, and it would
> be nice if other people could weigh in when they have a strong opinion
> one way or another.

Okay, I'll wait some more for others to join in.

[...]
> > > * Why not include the pwm_request() call in this and return the
> > >   pwm_device directly? You said that you want to get rid of the
> > >   pwm_id eventually, which is a good idea, but this interface still
> > >   forces one to use it.
> > 
> > Okay, that sounds sensible. I propose to rename the function to something like
> > of_request_pwm().
> 
> Sounds good.
> 
> > It would of course need an additional parameter (name) to
> > forward to pwm_request().
> 
> Not necessarily, it could use the dev_name(device) or the name
> of the property, or a combination of the two.

The problem with that is that usually the device would be named something
generic like "pwm", while in case where the PWM is used for the backlight
it makes sense to label the PWM device "backlight".

Looking at debugfs and seeing an entry "backlight" is much more straight-
forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
really, does it?

> > > * It is not clear what a pwm_spec is used for, or why a device
> > >   driver would need to be bothered by this. Maybe it just needs
> > >   more explanation, but it seems to me that if you do the previous
> > >   change, the pwm_spec would not be needed either.
> > 
> > pwm_spec is pretty much what the of_xlate() callback parses out of the data
> > provided by the device tree. Currently, of_pwm_simple_xlate() only parses the
> > period (in ns) but the idea was that if at some point in the future it was
> > decided to provide more than the period via the device tree it could be
> > extended without changing every call to of_get_named_pwm(). As I said, it also
> > plays quite nicely with the concept of the of_xlate() callback and sort of
> > serves as interface between the lower layer that retrieves PWM parameters and
> > the upper layers that use it.
> > 
> > Thinking about it, perhaps renaming it to pwm_params may be more descriptive.
> > Also to avoid breakage or confusion if fields get added it may be good to
> > provide a bitmask of valid fields filled in by the of_xlate() callback.
> > 
> > 	enum {
> > 		PWM_PARAMS_PERIOD,
> > 		...
> > 	};
> > 
> > 	struct pwm_params {
> > 		unsigned long fields;
> > 		unsigned int period;
> > 	};
> > 
> > Then again, maybe that's just over-engineering and directly returning via an
> > unsigned int *period_ns parameter would be better?
> 
> It certainly sounds like over-engineering to me. Why not keep all that
> information hidden inside the struct pwm_device and provide accessor
> functions like this?
> 
> unsigned int pwm_get_period(struct pwm_device *pwm);

Heh, I like that. It is the obvious thing to do. Why didn't I think of it?
:-)

> > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > 
> > > EXPORT_SYMBOL_GPL?
> > 
> > It was brought up at some point that it might be nice to allow non-GPL
> > drivers to use the PWM framework as well. I don't remember any discussion
> > resulting from the comment. Perhaps we should have that discussion now and
> > decide whether or not we want to keep it GPL-only or not.
> 
> I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> replaces an earlier interface that was available as EXPORT_SYMBOL.

I just grepped the code and noticed this:

	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);

It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
Also does it make sense to have something like of_request_pwm() GPL when the
rest of the API isn't?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120224/69fe359d/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-23  9:25                 ` Ryan Mallon
@ 2012-02-24  6:48                     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-24  6:48 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen

[-- Attachment #1: Type: text/plain, Size: 612 bytes --]

* Ryan Mallon wrote:
> On 23/02/12 19:14, Thierry Reding wrote:
> > * Ryan Mallon wrote:
[...]
> >> pwmchip_add should probably verify that the initialisation of the
> >> pwm_chip structure is sane to avoid problems like this.
> > 
> > Absolutely. What would be the best response to an invalid struct pwm_chip? I
> > suppose at least returning -EINVAL, perhaps complemented with WARN_ON?
> 
> Just returning -EINVAL should be okay. I don't think you need a WARN_ON,
> since failing to register the hardware should be enough of a reason for
> a user to report a problem.

Okay, will do.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-24  6:48                     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-02-24  6:48 UTC (permalink / raw)
  To: linux-arm-kernel

* Ryan Mallon wrote:
> On 23/02/12 19:14, Thierry Reding wrote:
> > * Ryan Mallon wrote:
[...]
> >> pwmchip_add should probably verify that the initialisation of the
> >> pwm_chip structure is sane to avoid problems like this.
> > 
> > Absolutely. What would be the best response to an invalid struct pwm_chip? I
> > suppose at least returning -EINVAL, perhaps complemented with WARN_ON?
> 
> Just returning -EINVAL should be okay. I don't think you need a WARN_ON,
> since failing to register the hardware should be enough of a reason for
> a user to report a problem.

Okay, will do.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120224/2036d092/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-24  6:47                     ` Thierry Reding
@ 2012-02-24 16:58                         ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-24 16:58 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Friday 24 February 2012, Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Thursday 23 February 2012, Thierry Reding wrote:
> > > * Arnd Bergmann wrote:

> [...]
> > > > * Why not include the pwm_request() call in this and return the
> > > >   pwm_device directly? You said that you want to get rid of the
> > > >   pwm_id eventually, which is a good idea, but this interface still
> > > >   forces one to use it.
> > > 
> > > Okay, that sounds sensible. I propose to rename the function to something like
> > > of_request_pwm().
> > 
> > Sounds good.

On second thought, I would actually prefer starting the name with pwm_ and
making it independent of device tree. There might be other ways how to
find the pwm_device from a struct device in the future, but it should always
be possible using a device together with a string and/or numeric identifier,
much in the same way that we can get a resource from a platform_device.

Ideally, there would be a common theme behind finding a memory region,
irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
that requires a link between two device nodes.

> > > It would of course need an additional parameter (name) to
> > > forward to pwm_request().
> > 
> > Not necessarily, it could use the dev_name(device) or the name
> > of the property, or a combination of the two.
> 
> The problem with that is that usually the device would be named something
> generic like "pwm", while in case where the PWM is used for the backlight
> it makes sense to label the PWM device "backlight".
> 
> Looking at debugfs and seeing an entry "backlight" is much more straight-
> forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
> really, does it?

But the device name would be from the device using the pwm, not the
pwm controller, so it should be something more helpful, no?

> > > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > > 
> > > > EXPORT_SYMBOL_GPL?
> > > 
> > > It was brought up at some point that it might be nice to allow non-GPL
> > > drivers to use the PWM framework as well. I don't remember any discussion
> > > resulting from the comment. Perhaps we should have that discussion now and
> > > decide whether or not we want to keep it GPL-only or not.
> > 
> > I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> > replaces an earlier interface that was available as EXPORT_SYMBOL.
> 
> I just grepped the code and noticed this:
> 
> 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
> 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
> 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
> 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
> 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
> 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
> 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
> 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
> 
> It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
> Also does it make sense to have something like of_request_pwm() GPL when the
> rest of the API isn't?

I guess the choice is to make between you and Sascha. The implementation is
new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
keep to the current API.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-24 16:58                         ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-02-24 16:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 24 February 2012, Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Thursday 23 February 2012, Thierry Reding wrote:
> > > * Arnd Bergmann wrote:

> [...]
> > > > * Why not include the pwm_request() call in this and return the
> > > >   pwm_device directly? You said that you want to get rid of the
> > > >   pwm_id eventually, which is a good idea, but this interface still
> > > >   forces one to use it.
> > > 
> > > Okay, that sounds sensible. I propose to rename the function to something like
> > > of_request_pwm().
> > 
> > Sounds good.

On second thought, I would actually prefer starting the name with pwm_ and
making it independent of device tree. There might be other ways how to
find the pwm_device from a struct device in the future, but it should always
be possible using a device together with a string and/or numeric identifier,
much in the same way that we can get a resource from a platform_device.

Ideally, there would be a common theme behind finding a memory region,
irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
that requires a link between two device nodes.

> > > It would of course need an additional parameter (name) to
> > > forward to pwm_request().
> > 
> > Not necessarily, it could use the dev_name(device) or the name
> > of the property, or a combination of the two.
> 
> The problem with that is that usually the device would be named something
> generic like "pwm", while in case where the PWM is used for the backlight
> it makes sense to label the PWM device "backlight".
> 
> Looking at debugfs and seeing an entry "backlight" is much more straight-
> forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
> really, does it?

But the device name would be from the device using the pwm, not the
pwm controller, so it should be something more helpful, no?

> > > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > > 
> > > > EXPORT_SYMBOL_GPL?
> > > 
> > > It was brought up at some point that it might be nice to allow non-GPL
> > > drivers to use the PWM framework as well. I don't remember any discussion
> > > resulting from the comment. Perhaps we should have that discussion now and
> > > decide whether or not we want to keep it GPL-only or not.
> > 
> > I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> > replaces an earlier interface that was available as EXPORT_SYMBOL.
> 
> I just grepped the code and noticed this:
> 
> 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
> 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
> 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
> 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
> 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
> 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
> 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
> 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
> 
> It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
> Also does it make sense to have something like of_request_pwm() GPL when the
> rest of the API isn't?

I guess the choice is to make between you and Sascha. The implementation is
new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
keep to the current API.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-24 16:58                         ` Arnd Bergmann
@ 2012-02-25 12:33                             ` Sascha Hauer
  -1 siblings, 0 replies; 92+ messages in thread
From: Sascha Hauer @ 2012-02-25 12:33 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Thierry Reding, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Matthias Kaehlcke,
	Kurt Van Dijck, Rob Herring, Grant Likely, Colin Cross,
	Olof Johansson, Richard Purdie, Mark Brown, Mitch Bradley,
	Mike Frysinger, Eric Miao, Lars-Peter Clausen, Ryan Mallon

On Fri, Feb 24, 2012 at 04:58:31PM +0000, Arnd Bergmann wrote:
> On Friday 24 February 2012, Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > * Arnd Bergmann wrote:
> 
> > [...]
> > > > > * Why not include the pwm_request() call in this and return the
> > > > >   pwm_device directly? You said that you want to get rid of the
> > > > >   pwm_id eventually, which is a good idea, but this interface still
> > > > >   forces one to use it.
> > > > 
> > > > Okay, that sounds sensible. I propose to rename the function to something like
> > > > of_request_pwm().
> > > 
> > > Sounds good.
> 
> On second thought, I would actually prefer starting the name with pwm_ and
> making it independent of device tree. There might be other ways how to
> find the pwm_device from a struct device in the future, but it should always
> be possible using a device together with a string and/or numeric identifier,
> much in the same way that we can get a resource from a platform_device.
> 
> Ideally, there would be a common theme behind finding a memory region,
> irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
> that requires a link between two device nodes.
> 
> > > > It would of course need an additional parameter (name) to
> > > > forward to pwm_request().
> > > 
> > > Not necessarily, it could use the dev_name(device) or the name
> > > of the property, or a combination of the two.
> > 
> > The problem with that is that usually the device would be named something
> > generic like "pwm", while in case where the PWM is used for the backlight
> > it makes sense to label the PWM device "backlight".
> > 
> > Looking at debugfs and seeing an entry "backlight" is much more straight-
> > forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
> > really, does it?
> 
> But the device name would be from the device using the pwm, not the
> pwm controller, so it should be something more helpful, no?
> 
> > > > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > > > 
> > > > > EXPORT_SYMBOL_GPL?
> > > > 
> > > > It was brought up at some point that it might be nice to allow non-GPL
> > > > drivers to use the PWM framework as well. I don't remember any discussion
> > > > resulting from the comment. Perhaps we should have that discussion now and
> > > > decide whether or not we want to keep it GPL-only or not.
> > > 
> > > I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> > > replaces an earlier interface that was available as EXPORT_SYMBOL.
> > 
> > I just grepped the code and noticed this:
> > 
> > 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
> > 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
> > 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
> > 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
> > 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
> > 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
> > 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
> > 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
> > 
> > It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
> > Also does it make sense to have something like of_request_pwm() GPL when the
> > rest of the API isn't?
> 
> I guess the choice is to make between you and Sascha. The implementation is
> new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
> keep to the current API.

I tend to use _GPL, but I have no strong objection using the non GPL
variant.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-25 12:33                             ` Sascha Hauer
  0 siblings, 0 replies; 92+ messages in thread
From: Sascha Hauer @ 2012-02-25 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 24, 2012 at 04:58:31PM +0000, Arnd Bergmann wrote:
> On Friday 24 February 2012, Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > * Arnd Bergmann wrote:
> 
> > [...]
> > > > > * Why not include the pwm_request() call in this and return the
> > > > >   pwm_device directly? You said that you want to get rid of the
> > > > >   pwm_id eventually, which is a good idea, but this interface still
> > > > >   forces one to use it.
> > > > 
> > > > Okay, that sounds sensible. I propose to rename the function to something like
> > > > of_request_pwm().
> > > 
> > > Sounds good.
> 
> On second thought, I would actually prefer starting the name with pwm_ and
> making it independent of device tree. There might be other ways how to
> find the pwm_device from a struct device in the future, but it should always
> be possible using a device together with a string and/or numeric identifier,
> much in the same way that we can get a resource from a platform_device.
> 
> Ideally, there would be a common theme behind finding a memory region,
> irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
> that requires a link between two device nodes.
> 
> > > > It would of course need an additional parameter (name) to
> > > > forward to pwm_request().
> > > 
> > > Not necessarily, it could use the dev_name(device) or the name
> > > of the property, or a combination of the two.
> > 
> > The problem with that is that usually the device would be named something
> > generic like "pwm", while in case where the PWM is used for the backlight
> > it makes sense to label the PWM device "backlight".
> > 
> > Looking at debugfs and seeing an entry "backlight" is much more straight-
> > forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
> > really, does it?
> 
> But the device name would be from the device using the pwm, not the
> pwm controller, so it should be something more helpful, no?
> 
> > > > > > +EXPORT_SYMBOL(of_get_named_pwm);
> > > > > 
> > > > > EXPORT_SYMBOL_GPL?
> > > > 
> > > > It was brought up at some point that it might be nice to allow non-GPL
> > > > drivers to use the PWM framework as well. I don't remember any discussion
> > > > resulting from the comment. Perhaps we should have that discussion now and
> > > > decide whether or not we want to keep it GPL-only or not.
> > > 
> > > I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
> > > replaces an earlier interface that was available as EXPORT_SYMBOL.
> > 
> > I just grepped the code and noticed this:
> > 
> > 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
> > 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
> > 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
> > 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
> > 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
> > 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
> > 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
> > 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
> > 
> > It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
> > Also does it make sense to have something like of_request_pwm() GPL when the
> > rest of the API isn't?
> 
> I guess the choice is to make between you and Sascha. The implementation is
> new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
> keep to the current API.

I tend to use _GPL, but I have no strong objection using the non GPL
variant.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 03/10] of: Add PWM support.
  2012-02-25 12:33                             ` Sascha Hauer
@ 2012-02-25 23:08                                 ` Ryan Mallon
  -1 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-25 23:08 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Arnd Bergmann, Thierry Reding,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Matthias Kaehlcke,
	Kurt Van Dijck, Rob Herring, Grant Likely, Colin Cross,
	Olof Johansson, Richard Purdie, Mark Brown, Mitch Bradley,
	Mike Frysinger, Eric Miao, Lars-Peter Clausen

On 25/02/12 23:33, Sascha Hauer wrote:

> On Fri, Feb 24, 2012 at 04:58:31PM +0000, Arnd Bergmann wrote:
>> On Friday 24 February 2012, Thierry Reding wrote:
>>> * Arnd Bergmann wrote:
>>>> On Thursday 23 February 2012, Thierry Reding wrote:
>>>>> * Arnd Bergmann wrote:
>>
>>> [...]
>>>>>> * Why not include the pwm_request() call in this and return the
>>>>>>   pwm_device directly? You said that you want to get rid of the
>>>>>>   pwm_id eventually, which is a good idea, but this interface still
>>>>>>   forces one to use it.
>>>>>
>>>>> Okay, that sounds sensible. I propose to rename the function to something like
>>>>> of_request_pwm().
>>>>
>>>> Sounds good.
>>
>> On second thought, I would actually prefer starting the name with pwm_ and
>> making it independent of device tree. There might be other ways how to
>> find the pwm_device from a struct device in the future, but it should always
>> be possible using a device together with a string and/or numeric identifier,
>> much in the same way that we can get a resource from a platform_device.
>>
>> Ideally, there would be a common theme behind finding a memory region,
>> irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
>> that requires a link between two device nodes.
>>
>>>>> It would of course need an additional parameter (name) to
>>>>> forward to pwm_request().
>>>>
>>>> Not necessarily, it could use the dev_name(device) or the name
>>>> of the property, or a combination of the two.
>>>
>>> The problem with that is that usually the device would be named something
>>> generic like "pwm", while in case where the PWM is used for the backlight
>>> it makes sense to label the PWM device "backlight".
>>>
>>> Looking at debugfs and seeing an entry "backlight" is much more straight-
>>> forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
>>> really, does it?
>>
>> But the device name would be from the device using the pwm, not the
>> pwm controller, so it should be something more helpful, no?
>>
>>>>>>> +EXPORT_SYMBOL(of_get_named_pwm);
>>>>>>
>>>>>> EXPORT_SYMBOL_GPL?
>>>>>
>>>>> It was brought up at some point that it might be nice to allow non-GPL
>>>>> drivers to use the PWM framework as well. I don't remember any discussion
>>>>> resulting from the comment. Perhaps we should have that discussion now and
>>>>> decide whether or not we want to keep it GPL-only or not.
>>>>
>>>> I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
>>>> replaces an earlier interface that was available as EXPORT_SYMBOL.
>>>
>>> I just grepped the code and noticed this:
>>>
>>> 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
>>> 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
>>> 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
>>> 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
>>> 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
>>>
>>> It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
>>> Also does it make sense to have something like of_request_pwm() GPL when the
>>> rest of the API isn't?
>>
>> I guess the choice is to make between you and Sascha. The implementation is
>> new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
>> keep to the current API.
> 
> I tend to use _GPL, but I have no strong objection using the non GPL
> variant.


I raised the question last time round. My understanding in that internal
interfaces, those which should never be used by external modules, should
be EXPORT_SYMBOL_GPL, but public interfaces should be EXPORT_SYMBOL. I'm
not hugely against making the entire interface _GPL, I just wanted to
make sure it was intended that way, and not just cut and paste :-).

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 03/10] of: Add PWM support.
@ 2012-02-25 23:08                                 ` Ryan Mallon
  0 siblings, 0 replies; 92+ messages in thread
From: Ryan Mallon @ 2012-02-25 23:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 25/02/12 23:33, Sascha Hauer wrote:

> On Fri, Feb 24, 2012 at 04:58:31PM +0000, Arnd Bergmann wrote:
>> On Friday 24 February 2012, Thierry Reding wrote:
>>> * Arnd Bergmann wrote:
>>>> On Thursday 23 February 2012, Thierry Reding wrote:
>>>>> * Arnd Bergmann wrote:
>>
>>> [...]
>>>>>> * Why not include the pwm_request() call in this and return the
>>>>>>   pwm_device directly? You said that you want to get rid of the
>>>>>>   pwm_id eventually, which is a good idea, but this interface still
>>>>>>   forces one to use it.
>>>>>
>>>>> Okay, that sounds sensible. I propose to rename the function to something like
>>>>> of_request_pwm().
>>>>
>>>> Sounds good.
>>
>> On second thought, I would actually prefer starting the name with pwm_ and
>> making it independent of device tree. There might be other ways how to
>> find the pwm_device from a struct device in the future, but it should always
>> be possible using a device together with a string and/or numeric identifier,
>> much in the same way that we can get a resource from a platform_device.
>>
>> Ideally, there would be a common theme behind finding a memory region,
>> irq, gpio pin, clock, regulator, dma-channel and pwm or anything else
>> that requires a link between two device nodes.
>>
>>>>> It would of course need an additional parameter (name) to
>>>>> forward to pwm_request().
>>>>
>>>> Not necessarily, it could use the dev_name(device) or the name
>>>> of the property, or a combination of the two.
>>>
>>> The problem with that is that usually the device would be named something
>>> generic like "pwm", while in case where the PWM is used for the backlight
>>> it makes sense to label the PWM device "backlight".
>>>
>>> Looking at debugfs and seeing an entry "backlight" is much more straight-
>>> forward than "pwm.0". I mean "pwm.0" doesn't carry any useful information
>>> really, does it?
>>
>> But the device name would be from the device using the pwm, not the
>> pwm controller, so it should be something more helpful, no?
>>
>>>>>>> +EXPORT_SYMBOL(of_get_named_pwm);
>>>>>>
>>>>>> EXPORT_SYMBOL_GPL?
>>>>>
>>>>> It was brought up at some point that it might be nice to allow non-GPL
>>>>> drivers to use the PWM framework as well. I don't remember any discussion
>>>>> resulting from the comment. Perhaps we should have that discussion now and
>>>>> decide whether or not we want to keep it GPL-only or not.
>>>>
>>>> I would definitely use EXPORT_SYMBOL_GPL for all new code unless it
>>>> replaces an earlier interface that was available as EXPORT_SYMBOL.
>>>
>>> I just grepped the code and noticed this:
>>>
>>> 	$ $ git grep -n 'EXPORT_SYMBOL.*(pwm_request)'
>>> 	arch/arm/mach-vt8500/pwm.c:139:EXPORT_SYMBOL(pwm_request);
>>> 	arch/arm/plat-mxc/pwm.c:183:EXPORT_SYMBOL(pwm_request);
>>> 	arch/arm/plat-samsung/pwm.c:83:EXPORT_SYMBOL(pwm_request);
>>> 	arch/unicore32/kernel/pwm.c:132:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/mfd/twl6030-pwm.c:156:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/misc/ab8500-pwm.c:108:EXPORT_SYMBOL(pwm_request);
>>> 	drivers/pwm/core.c:262:EXPORT_SYMBOL_GPL(pwm_request);
>>>
>>> It seems like the legacy PWM API used to be non-GPL. Should I switch it back?
>>> Also does it make sense to have something like of_request_pwm() GPL when the
>>> rest of the API isn't?
>>
>> I guess the choice is to make between you and Sascha. The implementation is
>> new, so you could pick EXPORT_SYMBOL_GPL, but you could also try to
>> keep to the current API.
> 
> I tend to use _GPL, but I have no strong objection using the non GPL
> variant.


I raised the question last time round. My understanding in that internal
interfaces, those which should never be used by external modules, should
be EXPORT_SYMBOL_GPL, but public interfaces should be EXPORT_SYMBOL. I'm
not hugely against making the entire interface _GPL, I just wanted to
make sure it was intended that way, and not just cut and paste :-).

~Ryan

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-28 21:01         ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:01 UTC (permalink / raw)
  To: Thierry Reding, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: Simon Que, Bill Huang,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> PWM clock source registers in Tegra 2 have different clock source selection bit
> fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> their respective clock source register.
> 
> This patch updates the clock programming to correctly reflect that, by adding a
> flag to indicate the alternate bit field format and checking for it when
> selecting a clock source (parent clock).

tegra30_clocks.c needs this change too, although on Tegra30, it's bits
29:28 for the PWM, and bits 31:30 for non-PWM.

> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c

+#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28

Why is this (and the flag that enables it) called "4 bit"; the existing
code supports a 2-bit mux field (4-values), whereas this new code supports
a 3-bit field (potentially 8 values, but only 5 actually assigned).
Can this be renamed something more accurate, especially since on Tegra30
the difference is only the bit position of the field, not the number of
bits in the field.

> @@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
>  	u32 val = clk_readl(c->reg);
>  	const struct clk_mux_sel *mux = NULL;
>  	const struct clk_mux_sel *sel;
> +	u32 shift;
> +
> +	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
> +		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
> +	else
> +		shift = PERIPH_CLK_SOURCE_SHIFT;

I think you should assign a "mask" variable here too...

> +
>  	if (c->flags & MUX) {
>  		for (sel = c->inputs; sel->input != NULL; sel++) {
> -			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
> +			if (val >> shift == sel->value)
>  				mux = sel;

Because in the new case, bit 31 isn't part of the field, so just
shifting doesn't isolate the mux field. In practice, this probably isn't
an issue since bit 31 is undefined, but better to be safe than sorry...

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
@ 2012-02-28 21:01         ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:01 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> PWM clock source registers in Tegra 2 have different clock source selection bit
> fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> their respective clock source register.
> 
> This patch updates the clock programming to correctly reflect that, by adding a
> flag to indicate the alternate bit field format and checking for it when
> selecting a clock source (parent clock).

tegra30_clocks.c needs this change too, although on Tegra30, it's bits
29:28 for the PWM, and bits 31:30 for non-PWM.

> diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c

+#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
+#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28

Why is this (and the flag that enables it) called "4 bit"; the existing
code supports a 2-bit mux field (4-values), whereas this new code supports
a 3-bit field (potentially 8 values, but only 5 actually assigned).
Can this be renamed something more accurate, especially since on Tegra30
the difference is only the bit position of the field, not the number of
bits in the field.

> @@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
>  	u32 val = clk_readl(c->reg);
>  	const struct clk_mux_sel *mux = NULL;
>  	const struct clk_mux_sel *sel;
> +	u32 shift;
> +
> +	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
> +		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
> +	else
> +		shift = PERIPH_CLK_SOURCE_SHIFT;

I think you should assign a "mask" variable here too...

> +
>  	if (c->flags & MUX) {
>  		for (sel = c->inputs; sel->input != NULL; sel++) {
> -			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
> +			if (val >> shift == sel->value)
>  				mux = sel;

Because in the new case, bit 31 isn't part of the field, so just
shifting doesn't isolate the mux field. In practice, this probably isn't
an issue since bit 31 is undefined, but better to be safe than sorry...

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-22 15:17     ` Thierry Reding
@ 2012-02-28 21:14         ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:14 UTC (permalink / raw)
  To: Thierry Reding, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> This commit adds a generic PWM framework driver for the PWFM controller
> found on NVIDIA Tegra SoCs. The driver is based on code from the
> Chromium kernel tree and was originally written by Gary King (NVIDIA)
> and later modified by Simon Que (Chromium).

> diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c

> +static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,

> +	/*
> +	 * Convert from duty_ns / period_ns to a fixed number of duty
> +	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
> +	 */
> +	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);

The driver in ChromeOS has the following extra line here:

    c += (period_ns / 2);

and the following extra line in the comment above:

    Also, make sure to round to the nearest integer during division.

I don't know the HW well enough to know if that line should be present?

Otherwise, this looks similar enough to the ChromeOS driver, so:

Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-02-28 21:14         ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:14 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> This commit adds a generic PWM framework driver for the PWFM controller
> found on NVIDIA Tegra SoCs. The driver is based on code from the
> Chromium kernel tree and was originally written by Gary King (NVIDIA)
> and later modified by Simon Que (Chromium).

> diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c

> +static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,

> +	/*
> +	 * Convert from duty_ns / period_ns to a fixed number of duty
> +	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
> +	 */
> +	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);

The driver in ChromeOS has the following extra line here:

    c += (period_ns / 2);

and the following extra line in the comment above:

    Also, make sure to round to the nearest integer during division.

I don't know the HW well enough to know if that line should be present?

Otherwise, this looks similar enough to the ChromeOS driver, so:

Acked-by: Stephen Warren <swarren@nvidia.com>

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-02-22 15:17   ` Thierry Reding
@ 2012-02-28 21:20       ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:20 UTC (permalink / raw)
  To: Thierry Reding, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> Add auxdata to instantiate a device tree for the PWFM controller and
> include a corresponding node in the device tree.

> diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi

> +	pwm: pwm@7000a000 {
> +		compatible = "nvidia,tegra20-pwm";
> +		reg = <0x7000a000 0x100>;
> +		#pwm-cells = <2>;
> +	};

The compatible value probably should list both Tegra30 and Tegra20, so
we can know exactly which HW is present, just in case we need to turn
on some bug-fix only for one of the variants:

    compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

Could you also write binding documentation, in particular explaining
what the two pwm-cells are specifically for Tegra:

Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt

(although perhaps that'd be part of the previous patch which implements
the driver)

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-02-28 21:20       ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-02-28 21:20 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> Add auxdata to instantiate a device tree for the PWFM controller and
> include a corresponding node in the device tree.

> diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi

> +	pwm: pwm at 7000a000 {
> +		compatible = "nvidia,tegra20-pwm";
> +		reg = <0x7000a000 0x100>;
> +		#pwm-cells = <2>;
> +	};

The compatible value probably should list both Tegra30 and Tegra20, so
we can know exactly which HW is present, just in case we need to turn
on some bug-fix only for one of the variants:

    compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

Could you also write binding documentation, in particular explaining
what the two pwm-cells are specifically for Tegra:

Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt

(although perhaps that'd be part of the previous patch which implements
the driver)

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-02-23 16:04                     ` Thierry Reding
@ 2012-03-03 19:32                         ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 19:32 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1064 bytes --]

* Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > Is this only used for the device tree functions? If so, I would recommend
> > > > making it less generic and always search for a device node.
> > > 
> > > It is currently only used to look up a struct pwm_chip for a given struct
> > > device_node, yes. But I can see other uses for this. For instance this could
> > > be useful if we ever want to provide an alternative way of requesting a PWM
> > > on a per-chip basis.
> > 
> > Nah, just keep it simple for now. If we need it later, we can still
> > add something like this back, but for now it's just a source of
> > confusion and possible bugs.
> 
> Will do.

I turns out that this is not as easy to do as I thought. The problem is that
if I remove the pwmchip_find() from the core and move the lookup
functionality into the OF support code I no longer have access to the list of
PWM chips. So I guess it will have to stay in to keep things encapsulated
properly.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-03-03 19:32                         ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 19:32 UTC (permalink / raw)
  To: linux-arm-kernel

* Thierry Reding wrote:
> * Arnd Bergmann wrote:
> > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > Is this only used for the device tree functions? If so, I would recommend
> > > > making it less generic and always search for a device node.
> > > 
> > > It is currently only used to look up a struct pwm_chip for a given struct
> > > device_node, yes. But I can see other uses for this. For instance this could
> > > be useful if we ever want to provide an alternative way of requesting a PWM
> > > on a per-chip basis.
> > 
> > Nah, just keep it simple for now. If we need it later, we can still
> > add something like this back, but for now it's just a source of
> > confusion and possible bugs.
> 
> Will do.

I turns out that this is not as easy to do as I thought. The problem is that
if I remove the pwmchip_find() from the core and move the lookup
functionality into the OF support code I no longer have access to the list of
PWM chips. So I guess it will have to stay in to keep things encapsulated
properly.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120303/fe4881d7/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-02-28 21:14         ` Stephen Warren
@ 2012-03-03 22:42             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:42 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1338 bytes --]

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > This commit adds a generic PWM framework driver for the PWFM controller
> > found on NVIDIA Tegra SoCs. The driver is based on code from the
> > Chromium kernel tree and was originally written by Gary King (NVIDIA)
> > and later modified by Simon Que (Chromium).
> 
> > diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
> 
> > +static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> 
> > +	/*
> > +	 * Convert from duty_ns / period_ns to a fixed number of duty
> > +	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
> > +	 */
> > +	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);
> 
> The driver in ChromeOS has the following extra line here:
> 
>     c += (period_ns / 2);
> 
> and the following extra line in the comment above:
> 
>     Also, make sure to round to the nearest integer during division.
> 
> I don't know the HW well enough to know if that line should be present?
> 
> Otherwise, this looks similar enough to the ChromeOS driver, so:
> 
> Acked-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Those probably weren't there yet when I prepared the first series. I'll have
another look will sync up with it after testing that it still works.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-03-03 22:42             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:42 UTC (permalink / raw)
  To: linux-arm-kernel

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > This commit adds a generic PWM framework driver for the PWFM controller
> > found on NVIDIA Tegra SoCs. The driver is based on code from the
> > Chromium kernel tree and was originally written by Gary King (NVIDIA)
> > and later modified by Simon Que (Chromium).
> 
> > diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
> 
> > +static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> 
> > +	/*
> > +	 * Convert from duty_ns / period_ns to a fixed number of duty
> > +	 * ticks per (1 << PWM_DUTY_WIDTH) cycles.
> > +	 */
> > +	c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1);
> 
> The driver in ChromeOS has the following extra line here:
> 
>     c += (period_ns / 2);
> 
> and the following extra line in the comment above:
> 
>     Also, make sure to round to the nearest integer during division.
> 
> I don't know the HW well enough to know if that line should be present?
> 
> Otherwise, this looks similar enough to the ChromeOS driver, so:
> 
> Acked-by: Stephen Warren <swarren@nvidia.com>

Those probably weren't there yet when I prepared the first series. I'll have
another look will sync up with it after testing that it still works.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120303/ab9fcace/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
  2012-02-28 21:01         ` Stephen Warren
@ 2012-03-03 22:47             ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:47 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Mark Brown, Lars-Peter Clausen, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Bill Huang,
	Rob Herring, Simon Que, Colin Cross, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck


[-- Attachment #1.1: Type: text/plain, Size: 2646 bytes --]

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > PWM clock source registers in Tegra 2 have different clock source selection bit
> > fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> > are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> > their respective clock source register.
> > 
> > This patch updates the clock programming to correctly reflect that, by adding a
> > flag to indicate the alternate bit field format and checking for it when
> > selecting a clock source (parent clock).
> 
> tegra30_clocks.c needs this change too, although on Tegra30, it's bits
> 29:28 for the PWM, and bits 31:30 for non-PWM.

Okay, I'll add code for Tegra30 in the next version. I won't be able to test
that at all because I don't have any Tegra30 hardware.

> > diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> 
> +#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
> +#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
> 
> Why is this (and the flag that enables it) called "4 bit"; the existing
> code supports a 2-bit mux field (4-values), whereas this new code supports
> a 3-bit field (potentially 8 values, but only 5 actually assigned).
> Can this be renamed something more accurate, especially since on Tegra30
> the difference is only the bit position of the field, not the number of
> bits in the field.

This is taken directly from the Chromium tree, so I don't really know why
that name was chosen. But since the PWM clock source register seems to be the
only exception, how about calling the flag PWM_CLK and prefix the shift and
mask with PWM_CLK_SOURCE_ instead?

> > @@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
> >  	u32 val = clk_readl(c->reg);
> >  	const struct clk_mux_sel *mux = NULL;
> >  	const struct clk_mux_sel *sel;
> > +	u32 shift;
> > +
> > +	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
> > +		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
> > +	else
> > +		shift = PERIPH_CLK_SOURCE_SHIFT;
> 
> I think you should assign a "mask" variable here too...
> 
> > +
> >  	if (c->flags & MUX) {
> >  		for (sel = c->inputs; sel->input != NULL; sel++) {
> > -			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
> > +			if (val >> shift == sel->value)
> >  				mux = sel;
> 
> Because in the new case, bit 31 isn't part of the field, so just
> shifting doesn't isolate the mux field. In practice, this probably isn't
> an issue since bit 31 is undefined, but better to be safe than sorry...

Okay, I'll fix that as well.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
@ 2012-03-03 22:47             ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:47 UTC (permalink / raw)
  To: linux-arm-kernel

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > PWM clock source registers in Tegra 2 have different clock source selection bit
> > fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> > are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> > their respective clock source register.
> > 
> > This patch updates the clock programming to correctly reflect that, by adding a
> > flag to indicate the alternate bit field format and checking for it when
> > selecting a clock source (parent clock).
> 
> tegra30_clocks.c needs this change too, although on Tegra30, it's bits
> 29:28 for the PWM, and bits 31:30 for non-PWM.

Okay, I'll add code for Tegra30 in the next version. I won't be able to test
that at all because I don't have any Tegra30 hardware.

> > diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> 
> +#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
> +#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
> 
> Why is this (and the flag that enables it) called "4 bit"; the existing
> code supports a 2-bit mux field (4-values), whereas this new code supports
> a 3-bit field (potentially 8 values, but only 5 actually assigned).
> Can this be renamed something more accurate, especially since on Tegra30
> the difference is only the bit position of the field, not the number of
> bits in the field.

This is taken directly from the Chromium tree, so I don't really know why
that name was chosen. But since the PWM clock source register seems to be the
only exception, how about calling the flag PWM_CLK and prefix the shift and
mask with PWM_CLK_SOURCE_ instead?

> > @@ -908,9 +910,16 @@ static void tegra2_periph_clk_init(struct clk *c)
> >  	u32 val = clk_readl(c->reg);
> >  	const struct clk_mux_sel *mux = NULL;
> >  	const struct clk_mux_sel *sel;
> > +	u32 shift;
> > +
> > +	if (c->flags & PERIPH_SOURCE_CLK_4BIT)
> > +		shift = PERIPH_CLK_SOURCE_4BIT_SHIFT;
> > +	else
> > +		shift = PERIPH_CLK_SOURCE_SHIFT;
> 
> I think you should assign a "mask" variable here too...
> 
> > +
> >  	if (c->flags & MUX) {
> >  		for (sel = c->inputs; sel->input != NULL; sel++) {
> > -			if (val >> PERIPH_CLK_SOURCE_SHIFT == sel->value)
> > +			if (val >> shift == sel->value)
> >  				mux = sel;
> 
> Because in the new case, bit 31 isn't part of the field, so just
> shifting doesn't isolate the mux field. In practice, this probably isn't
> an issue since bit 31 is undefined, but better to be safe than sorry...

Okay, I'll fix that as well.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120303/d7a69d55/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-02-28 21:20       ` Stephen Warren
@ 2012-03-03 22:54           ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:54 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 1447 bytes --]

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > Add auxdata to instantiate a device tree for the PWFM controller and
> > include a corresponding node in the device tree.
> 
> > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> 
> > +	pwm: pwm@7000a000 {
> > +		compatible = "nvidia,tegra20-pwm";
> > +		reg = <0x7000a000 0x100>;
> > +		#pwm-cells = <2>;
> > +	};
> 
> The compatible value probably should list both Tegra30 and Tegra20, so
> we can know exactly which HW is present, just in case we need to turn
> on some bug-fix only for one of the variants:
> 
>     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

I'm confused. If I know exactly that the hardware is Tegra30 (which it
definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
as compatible?

Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

> Could you also write binding documentation, in particular explaining
> what the two pwm-cells are specifically for Tegra:
> 
> Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> 
> (although perhaps that'd be part of the previous patch which implements
> the driver)

Actually for Tegra the values would be those documented in the generic
binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
add a Tegra-specific binding?

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-03-03 22:54           ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-03 22:54 UTC (permalink / raw)
  To: linux-arm-kernel

* Stephen Warren wrote:
> Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > Add auxdata to instantiate a device tree for the PWFM controller and
> > include a corresponding node in the device tree.
> 
> > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> 
> > +	pwm: pwm at 7000a000 {
> > +		compatible = "nvidia,tegra20-pwm";
> > +		reg = <0x7000a000 0x100>;
> > +		#pwm-cells = <2>;
> > +	};
> 
> The compatible value probably should list both Tegra30 and Tegra20, so
> we can know exactly which HW is present, just in case we need to turn
> on some bug-fix only for one of the variants:
> 
>     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

I'm confused. If I know exactly that the hardware is Tegra30 (which it
definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
as compatible?

Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

> Could you also write binding documentation, in particular explaining
> what the two pwm-cells are specifically for Tegra:
> 
> Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> 
> (although perhaps that'd be part of the previous patch which implements
> the driver)

Actually for Tegra the values would be those documented in the generic
binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
add a Tegra-specific binding?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120303/3cd16269/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-03-03 22:54           ` Thierry Reding
@ 2012-03-04 20:39               ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-03-04 20:39 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Brown, Eric Miao, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Colin Cross,
	Rob Herring, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck

On Saturday 03 March 2012, Thierry Reding wrote:
> Not enough information to check signature validity.  Show Details
>   * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > Add auxdata to instantiate a device tree for the PWFM controller and
> > > include a corresponding node in the device tree.
> > 
> > > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> > 
> > > +   pwm: pwm@7000a000 {
> > > +           compatible = "nvidia,tegra20-pwm";
> > > +           reg = <0x7000a000 0x100>;
> > > +           #pwm-cells = <2>;
> > > +   };
> > 
> > The compatible value probably should list both Tegra30 and Tegra20, so
> > we can know exactly which HW is present, just in case we need to turn
> > on some bug-fix only for one of the variants:
> > 
> >     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
> 
> I'm confused. If I know exactly that the hardware is Tegra30 (which it
> definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> as compatible?
> 
> Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

We generally list the oldest version of the device that a specific version
is compatible to, in order to use the same driver unmodified.

E.g. an ns16550a serial port would list both ns16550a and i8250 in its
compatible fields so it works with operating systems that only know about
i8250.

It's not actually all that useful when you add device tree support for
two versions of the same device at the same time, but I think that
it's good style anyway, in particular when you consider other users of
the device tree data besides the Linux kernel.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-03-04 20:39               ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-03-04 20:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Saturday 03 March 2012, Thierry Reding wrote:
> Not enough information to check signature validity.  Show Details
>   * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > Add auxdata to instantiate a device tree for the PWFM controller and
> > > include a corresponding node in the device tree.
> > 
> > > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> > 
> > > +   pwm: pwm at 7000a000 {
> > > +           compatible = "nvidia,tegra20-pwm";
> > > +           reg = <0x7000a000 0x100>;
> > > +           #pwm-cells = <2>;
> > > +   };
> > 
> > The compatible value probably should list both Tegra30 and Tegra20, so
> > we can know exactly which HW is present, just in case we need to turn
> > on some bug-fix only for one of the variants:
> > 
> >     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
> 
> I'm confused. If I know exactly that the hardware is Tegra30 (which it
> definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> as compatible?
> 
> Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

We generally list the oldest version of the device that a specific version
is compatible to, in order to use the same driver unmodified.

E.g. an ns16550a serial port would list both ns16550a and i8250 in its
compatible fields so it works with operating systems that only know about
i8250.

It's not actually all that useful when you add device tree support for
two versions of the same device at the same time, but I think that
it's good style anyway, in particular when you consider other users of
the device tree data besides the Linux kernel.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-03-03 22:42             ` Thierry Reding
@ 2012-03-05  3:39                 ` Olof Johansson
  -1 siblings, 0 replies; 92+ messages in thread
From: Olof Johansson @ 2012-03-05  3:39 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stephen Warren, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Richard Purdie, Mark Brown, Mitch Bradley,
	Mike Frysinger, Eric Miao, Lars-Peter Clausen, Ryan Mallon

On Sat, Mar 03, 2012 at 11:42:12PM +0100, Thierry Reding wrote:

> Those probably weren't there yet when I prepared the first series. I'll have
> another look will sync up with it after testing that it still works.


Yep, the patch in question is from Simon, and it's at:

http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel.git;a=commitdiff;h=7778c724bf3211c534f9bcef7b26afc6cb067a82

Essentially, the driver accidentally rounded down a backlight setting of
'1' which is how it was found.


-Olof

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-03-05  3:39                 ` Olof Johansson
  0 siblings, 0 replies; 92+ messages in thread
From: Olof Johansson @ 2012-03-05  3:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Mar 03, 2012 at 11:42:12PM +0100, Thierry Reding wrote:

> Those probably weren't there yet when I prepared the first series. I'll have
> another look will sync up with it after testing that it still works.


Yep, the patch in question is from Simon, and it's at:

http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel.git;a=commitdiff;h=7778c724bf3211c534f9bcef7b26afc6cb067a82

Essentially, the driver accidentally rounded down a backlight setting of
'1' which is how it was found.


-Olof

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
  2012-03-05  3:39                 ` Olof Johansson
@ 2012-03-05  7:00                     ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-05  7:00 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Mark Brown, Eric Miao, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Colin Cross,
	Rob Herring, Lars-Peter Clausen, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck


[-- Attachment #1.1: Type: text/plain, Size: 650 bytes --]

* Olof Johansson wrote:
> On Sat, Mar 03, 2012 at 11:42:12PM +0100, Thierry Reding wrote:
> 
> > Those probably weren't there yet when I prepared the first series. I'll have
> > another look will sync up with it after testing that it still works.
> 
> 
> Yep, the patch in question is from Simon, and it's at:
> 
> http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel.git;a=commitdiff;h=7778c724bf3211c534f9bcef7b26afc6cb067a82
> 
> Essentially, the driver accidentally rounded down a backlight setting of
> '1' which is how it was found.

Thanks for the link, I'll squash it into this patch in the next version.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support
@ 2012-03-05  7:00                     ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-05  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

* Olof Johansson wrote:
> On Sat, Mar 03, 2012 at 11:42:12PM +0100, Thierry Reding wrote:
> 
> > Those probably weren't there yet when I prepared the first series. I'll have
> > another look will sync up with it after testing that it still works.
> 
> 
> Yep, the patch in question is from Simon, and it's at:
> 
> http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel.git;a=commitdiff;h=7778c724bf3211c534f9bcef7b26afc6cb067a82
> 
> Essentially, the driver accidentally rounded down a backlight setting of
> '1' which is how it was found.

Thanks for the link, I'll squash it into this patch in the next version.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120305/966b89ca/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
  2012-03-03 22:47             ` Thierry Reding
@ 2012-03-05 17:33                 ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 17:33 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mark Brown, Lars-Peter Clausen, Ryan Mallon,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Bill Huang,
	Rob Herring, Simon Que, Colin Cross, Richard Purdie,
	Matthias Kaehlcke, linux-tegra-u79uwXL29TY76Z2rM5mHXA, Eric Miao,
	Sascha Hauer, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Kurt Van Dijck

Thierry Reding wrote at Saturday, March 03, 2012 3:48 PM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > PWM clock source registers in Tegra 2 have different clock source selection bit
> > > fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> > > are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> > > their respective clock source register.
> > >
> > > This patch updates the clock programming to correctly reflect that, by adding a
> > > flag to indicate the alternate bit field format and checking for it when
> > > selecting a clock source (parent clock).
> >
> > tegra30_clocks.c needs this change too, although on Tegra30, it's bits
> > 29:28 for the PWM, and bits 31:30 for non-PWM.
> 
> Okay, I'll add code for Tegra30 in the next version. I won't be able to test
> that at all because I don't have any Tegra30 hardware.

It looks like Tegra30 is already taken care of; see periph_clk_source_mask()
in tegra30_clocks.c, assuming that tegra_list_clks[] has the correct flags
set of each entry anyway. PWM does at least.

> > > diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> >
> > +#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
> > +#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
> >
> > Why is this (and the flag that enables it) called "4 bit"; the existing
> > code supports a 2-bit mux field (4-values), whereas this new code supports
> > a 3-bit field (potentially 8 values, but only 5 actually assigned).
> > Can this be renamed something more accurate, especially since on Tegra30
> > the difference is only the bit position of the field, not the number of
> > bits in the field.
> 
> This is taken directly from the Chromium tree, so I don't really know why
> that name was chosen. But since the PWM clock source register seems to be the
> only exception, how about calling the flag PWM_CLK and prefix the shift and
> mask with PWM_CLK_SOURCE_ instead?

That sounds reasonable.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 04/10] arm/tegra: Fix PWM clock programming
@ 2012-03-05 17:33                 ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 17:33 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Saturday, March 03, 2012 3:48 PM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > PWM clock source registers in Tegra 2 have different clock source selection bit
> > > fields than other registers.  PWM clock source bits in CLK_SOURCE_PWM_0 register
> > > are located at bit field bit[30:28] while others are at bit field bit[31:30] in
> > > their respective clock source register.
> > >
> > > This patch updates the clock programming to correctly reflect that, by adding a
> > > flag to indicate the alternate bit field format and checking for it when
> > > selecting a clock source (parent clock).
> >
> > tegra30_clocks.c needs this change too, although on Tegra30, it's bits
> > 29:28 for the PWM, and bits 31:30 for non-PWM.
> 
> Okay, I'll add code for Tegra30 in the next version. I won't be able to test
> that at all because I don't have any Tegra30 hardware.

It looks like Tegra30 is already taken care of; see periph_clk_source_mask()
in tegra30_clocks.c, assuming that tegra_list_clks[] has the correct flags
set of each entry anyway. PWM does at least.

> > > diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
> >
> > +#define PERIPH_CLK_SOURCE_4BIT_MASK	(7<<28)
> > +#define PERIPH_CLK_SOURCE_4BIT_SHIFT	28
> >
> > Why is this (and the flag that enables it) called "4 bit"; the existing
> > code supports a 2-bit mux field (4-values), whereas this new code supports
> > a 3-bit field (potentially 8 values, but only 5 actually assigned).
> > Can this be renamed something more accurate, especially since on Tegra30
> > the difference is only the bit position of the field, not the number of
> > bits in the field.
> 
> This is taken directly from the Chromium tree, so I don't really know why
> that name was chosen. But since the PWM clock source register seems to be the
> only exception, how about calling the flag PWM_CLK and prefix the shift and
> mask with PWM_CLK_SOURCE_ instead?

That sounds reasonable.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-03-03 22:54           ` Thierry Reding
@ 2012-03-05 17:51               ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 17:51 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > Add auxdata to instantiate a device tree for the PWFM controller and
> > > include a corresponding node in the device tree.
> >
> > > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> >
> > > +	pwm: pwm@7000a000 {
> > > +		compatible = "nvidia,tegra20-pwm";
> > > +		reg = <0x7000a000 0x100>;
> > > +		#pwm-cells = <2>;
> > > +	};
> >
> > The compatible value probably should list both Tegra30 and Tegra20, so
> > we can know exactly which HW is present, just in case we need to turn
> > on some bug-fix only for one of the variants:
> >
> >     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
> 
> I'm confused. If I know exactly that the hardware is Tegra30 (which it
> definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> as compatible?
> 
> Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

Standard practice is to list the exact model of the HW as the first entry
in compatible in the .dts file:

    nvidia,tegra30-pwm

This is so that the DT always describes exactly which HW model is actually
present, so that if HW-model-specific WARs/... are required in the future,
the DT already lists that information up-front.

Then additionally list any older HW models that this HW is also compatible
with:

    nvidia,tegra20-pwm


This allows the driver to list just nvidia,tegra20-pwm but still bind
to DT nodes that are for later HW.

So, in other words, you end up with the following in the .dts/.dtsi file:

    compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

> > Could you also write binding documentation, in particular explaining
> > what the two pwm-cells are specifically for Tegra:
> >
> > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> >
> > (although perhaps that'd be part of the previous patch which implements
> > the driver)
> 
> Actually for Tegra the values would be those documented in the generic
> binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> add a Tegra-specific binding?

There should still be a Tegra-specific binding. Without it, there's no
definite way to know whether the "standard" properties actually apply,
or someone simply forgot to document it.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-03-05 17:51               ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 17:51 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Wednesday, February 22, 2012 8:17 AM:
> > > Add auxdata to instantiate a device tree for the PWFM controller and
> > > include a corresponding node in the device tree.
> >
> > > diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
> >
> > > +	pwm: pwm at 7000a000 {
> > > +		compatible = "nvidia,tegra20-pwm";
> > > +		reg = <0x7000a000 0x100>;
> > > +		#pwm-cells = <2>;
> > > +	};
> >
> > The compatible value probably should list both Tegra30 and Tegra20, so
> > we can know exactly which HW is present, just in case we need to turn
> > on some bug-fix only for one of the variants:
> >
> >     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
> 
> I'm confused. If I know exactly that the hardware is Tegra30 (which it
> definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> as compatible?
> 
> Or did you mean to list tegra30-pwm as compatible value in the PWM driver?

Standard practice is to list the exact model of the HW as the first entry
in compatible in the .dts file:

    nvidia,tegra30-pwm

This is so that the DT always describes exactly which HW model is actually
present, so that if HW-model-specific WARs/... are required in the future,
the DT already lists that information up-front.

Then additionally list any older HW models that this HW is also compatible
with:

    nvidia,tegra20-pwm


This allows the driver to list just nvidia,tegra20-pwm but still bind
to DT nodes that are for later HW.

So, in other words, you end up with the following in the .dts/.dtsi file:

    compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

> > Could you also write binding documentation, in particular explaining
> > what the two pwm-cells are specifically for Tegra:
> >
> > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> >
> > (although perhaps that'd be part of the previous patch which implements
> > the driver)
> 
> Actually for Tegra the values would be those documented in the generic
> binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> add a Tegra-specific binding?

There should still be a Tegra-specific binding. Without it, there's no
definite way to know whether the "standard" properties actually apply,
or someone simply forgot to document it.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-03-05 17:51               ` Stephen Warren
@ 2012-03-05 18:15                   ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-05 18:15 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 2191 bytes --]

* Stephen Warren wrote:
> Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
> > I'm confused. If I know exactly that the hardware is Tegra30 (which it
> > definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> > as compatible?
> > 
> > Or did you mean to list tegra30-pwm as compatible value in the PWM driver?
> 
> Standard practice is to list the exact model of the HW as the first entry
> in compatible in the .dts file:
> 
>     nvidia,tegra30-pwm
> 
> This is so that the DT always describes exactly which HW model is actually
> present, so that if HW-model-specific WARs/... are required in the future,
> the DT already lists that information up-front.
> 
> Then additionally list any older HW models that this HW is also compatible
> with:
> 
>     nvidia,tegra20-pwm
> 
> 
> This allows the driver to list just nvidia,tegra20-pwm but still bind
> to DT nodes that are for later HW.
> 
> So, in other words, you end up with the following in the .dts/.dtsi file:
> 
>     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

Okay, that makes sense now. For some reason I thought you were suggesting to
put the same into tegra20.dtsi as well. I'll add nvidia,tegra30-pwm to the
compatible list in the driver and list both values in the tegra30.dtsi.
Thanks for explaining.

> > > Could you also write binding documentation, in particular explaining
> > > what the two pwm-cells are specifically for Tegra:
> > >
> > > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> > >
> > > (although perhaps that'd be part of the previous patch which implements
> > > the driver)
> > 
> > Actually for Tegra the values would be those documented in the generic
> > binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> > add a Tegra-specific binding?
> 
> There should still be a Tegra-specific binding. Without it, there's no
> definite way to know whether the "standard" properties actually apply,
> or someone simply forgot to document it.

Understood. I assume that both the Tegra20 and Tegra30 variants should have
explicit bindings then as well, right?

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-03-05 18:15                   ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-05 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

* Stephen Warren wrote:
> Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
> > I'm confused. If I know exactly that the hardware is Tegra30 (which it
> > definitely should be if I include tegra30.dtsi), then why list "tegra20-pwm"
> > as compatible?
> > 
> > Or did you mean to list tegra30-pwm as compatible value in the PWM driver?
> 
> Standard practice is to list the exact model of the HW as the first entry
> in compatible in the .dts file:
> 
>     nvidia,tegra30-pwm
> 
> This is so that the DT always describes exactly which HW model is actually
> present, so that if HW-model-specific WARs/... are required in the future,
> the DT already lists that information up-front.
> 
> Then additionally list any older HW models that this HW is also compatible
> with:
> 
>     nvidia,tegra20-pwm
> 
> 
> This allows the driver to list just nvidia,tegra20-pwm but still bind
> to DT nodes that are for later HW.
> 
> So, in other words, you end up with the following in the .dts/.dtsi file:
> 
>     compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";

Okay, that makes sense now. For some reason I thought you were suggesting to
put the same into tegra20.dtsi as well. I'll add nvidia,tegra30-pwm to the
compatible list in the driver and list both values in the tegra30.dtsi.
Thanks for explaining.

> > > Could you also write binding documentation, in particular explaining
> > > what the two pwm-cells are specifically for Tegra:
> > >
> > > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> > >
> > > (although perhaps that'd be part of the previous patch which implements
> > > the driver)
> > 
> > Actually for Tegra the values would be those documented in the generic
> > binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> > add a Tegra-specific binding?
> 
> There should still be a Tegra-specific binding. Without it, there's no
> definite way to know whether the "standard" properties actually apply,
> or someone simply forgot to document it.

Understood. I assume that both the Tegra20 and Tegra30 variants should have
explicit bindings then as well, right?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120305/e22d2f46/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

* RE: [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
  2012-03-05 18:15                   ` Thierry Reding
@ 2012-03-05 18:39                       ` Stephen Warren
  -1 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 18:39 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer, Arnd Bergmann,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

Thierry Reding wrote at Monday, March 05, 2012 11:16 AM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
...
> > > > Could you also write binding documentation, in particular explaining
> > > > what the two pwm-cells are specifically for Tegra:
> > > >
> > > > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> > > >
> > > > (although perhaps that'd be part of the previous patch which implements
> > > > the driver)
> > >
> > > Actually for Tegra the values would be those documented in the generic
> > > binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> > > add a Tegra-specific binding?
> >
> > There should still be a Tegra-specific binding. Without it, there's no
> > definite way to know whether the "standard" properties actually apply,
> > or someone simply forgot to document it.
> 
> Understood. I assume that both the Tegra20 and Tegra30 variants should have
> explicit bindings then as well, right?

To date, the bindings for the two chips have been similar enough we've
only written a single bindings document that covers both. For the
different compatible values, I've been assuming that's such a base part
of standard DT usage that those differences didn't even require
documenting in the individual bindings. For example, I've written e.g.:

Required properties:
- compatible : "nvidia,tegra20-i2s"

Or:

Required properties:
- compatible: Should be "nvidia,<chip>-apbdma"

And assumed these would be expanded as appropriate by the DT author.

Of course, if there were significant bindings differences (rather than
HW differences that were largely transparent to bindings) then yes I'd
expected separate nvidia,tegra20-foo.txt and nvidia,tegra30-foo.txt.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing
@ 2012-03-05 18:39                       ` Stephen Warren
  0 siblings, 0 replies; 92+ messages in thread
From: Stephen Warren @ 2012-03-05 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

Thierry Reding wrote at Monday, March 05, 2012 11:16 AM:
> * Stephen Warren wrote:
> > Thierry Reding wrote at Saturday, March 03, 2012 3:54 PM:
...
> > > > Could you also write binding documentation, in particular explaining
> > > > what the two pwm-cells are specifically for Tegra:
> > > >
> > > > Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
> > > >
> > > > (although perhaps that'd be part of the previous patch which implements
> > > > the driver)
> > >
> > > Actually for Tegra the values would be those documented in the generic
> > > binding because Tegra uses of_pwm_simple_xlate(). Does it still make sense to
> > > add a Tegra-specific binding?
> >
> > There should still be a Tegra-specific binding. Without it, there's no
> > definite way to know whether the "standard" properties actually apply,
> > or someone simply forgot to document it.
> 
> Understood. I assume that both the Tegra20 and Tegra30 variants should have
> explicit bindings then as well, right?

To date, the bindings for the two chips have been similar enough we've
only written a single bindings document that covers both. For the
different compatible values, I've been assuming that's such a base part
of standard DT usage that those differences didn't even require
documenting in the individual bindings. For example, I've written e.g.:

Required properties:
- compatible : "nvidia,tegra20-i2s"

Or:

Required properties:
- compatible: Should be "nvidia,<chip>-apbdma"

And assumed these would be expanded as appropriate by the DT author.

Of course, if there were significant bindings differences (rather than
HW differences that were largely transparent to bindings) then yes I'd
expected separate nvidia,tegra20-foo.txt and nvidia,tegra30-foo.txt.

-- 
nvpublic

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-03-03 19:32                         ` Thierry Reding
@ 2012-03-06 15:38                             ` Arnd Bergmann
  -1 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-03-06 15:38 UTC (permalink / raw)
  To: Thierry Reding
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

On Saturday 03 March 2012, Thierry Reding wrote:
>   * Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > > Is this only used for the device tree functions? If so, I would recommend
> > > > > making it less generic and always search for a device node.
> > > > 
> > > > It is currently only used to look up a struct pwm_chip for a given struct
> > > > device_node, yes. But I can see other uses for this. For instance this could
> > > > be useful if we ever want to provide an alternative way of requesting a PWM
> > > > on a per-chip basis.
> > > 
> > > Nah, just keep it simple for now. If we need it later, we can still
> > > add something like this back, but for now it's just a source of
> > > confusion and possible bugs.
> > 
> > Will do.
> 
> I turns out that this is not as easy to do as I thought. The problem is that
> if I remove the pwmchip_find() from the core and move the lookup
> functionality into the OF support code I no longer have access to the list of
> PWM chips. So I guess it will have to stay in to keep things encapsulated
> properly.

Well, or you move everything into the one file. If you have the device tree
support function in the same file as everything else, you no longer need
the additional complexity.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-03-06 15:38                             ` Arnd Bergmann
  0 siblings, 0 replies; 92+ messages in thread
From: Arnd Bergmann @ 2012-03-06 15:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Saturday 03 March 2012, Thierry Reding wrote:
>   * Thierry Reding wrote:
> > * Arnd Bergmann wrote:
> > > On Thursday 23 February 2012, Thierry Reding wrote:
> > > > > Is this only used for the device tree functions? If so, I would recommend
> > > > > making it less generic and always search for a device node.
> > > > 
> > > > It is currently only used to look up a struct pwm_chip for a given struct
> > > > device_node, yes. But I can see other uses for this. For instance this could
> > > > be useful if we ever want to provide an alternative way of requesting a PWM
> > > > on a per-chip basis.
> > > 
> > > Nah, just keep it simple for now. If we need it later, we can still
> > > add something like this back, but for now it's just a source of
> > > confusion and possible bugs.
> > 
> > Will do.
> 
> I turns out that this is not as easy to do as I thought. The problem is that
> if I remove the pwmchip_find() from the core and move the lookup
> functionality into the OF support code I no longer have access to the list of
> PWM chips. So I guess it will have to stay in to keep things encapsulated
> properly.

Well, or you move everything into the one file. If you have the device tree
support function in the same file as everything else, you no longer need
the additional complexity.

	Arnd

^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
  2012-03-06 15:38                             ` Arnd Bergmann
@ 2012-03-06 19:17                                 ` Thierry Reding
  -1 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-06 19:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
	Matthias Kaehlcke, Kurt Van Dijck, Rob Herring, Grant Likely,
	Colin Cross, Olof Johansson, Richard Purdie, Mark Brown,
	Mitch Bradley, Mike Frysinger, Eric Miao, Lars-Peter Clausen,
	Ryan Mallon

[-- Attachment #1: Type: text/plain, Size: 792 bytes --]

* Arnd Bergmann wrote:
> On Saturday 03 March 2012, Thierry Reding wrote:
> > I turns out that this is not as easy to do as I thought. The problem is that
> > if I remove the pwmchip_find() from the core and move the lookup
> > functionality into the OF support code I no longer have access to the list of
> > PWM chips. So I guess it will have to stay in to keep things encapsulated
> > properly.
> 
> Well, or you move everything into the one file. If you have the device tree
> support function in the same file as everything else, you no longer need
> the additional complexity.

Okay, I think it makes the most sense to move all of the OF support code into
drivers/pwm/core.c. That way we can also check off the discussion about the
OF support code's location.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs.
@ 2012-03-06 19:17                                 ` Thierry Reding
  0 siblings, 0 replies; 92+ messages in thread
From: Thierry Reding @ 2012-03-06 19:17 UTC (permalink / raw)
  To: linux-arm-kernel

* Arnd Bergmann wrote:
> On Saturday 03 March 2012, Thierry Reding wrote:
> > I turns out that this is not as easy to do as I thought. The problem is that
> > if I remove the pwmchip_find() from the core and move the lookup
> > functionality into the OF support code I no longer have access to the list of
> > PWM chips. So I guess it will have to stay in to keep things encapsulated
> > properly.
> 
> Well, or you move everything into the one file. If you have the device tree
> support function in the same file as everything else, you no longer need
> the additional complexity.

Okay, I think it makes the most sense to move all of the OF support code into
drivers/pwm/core.c. That way we can also check off the discussion about the
OF support code's location.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120306/09ec7a2e/attachment.sig>

^ permalink raw reply	[flat|nested] 92+ messages in thread

end of thread, other threads:[~2012-03-06 19:17 UTC | newest]

Thread overview: 92+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-22 15:17 [PATCH v3 00/10] Add PWM framework and device tree support Thierry Reding
2012-02-22 15:17 ` Thierry Reding
     [not found] ` <1329923841-32017-1-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-22 15:17   ` [PATCH v3 01/10] PWM: add pwm framework support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 02/10] pwm: Allow chips to support multiple PWMs Thierry Reding
2012-02-22 15:17     ` Thierry Reding
     [not found]     ` <1329923841-32017-3-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-22 16:34       ` Arnd Bergmann
2012-02-22 16:34         ` Arnd Bergmann
     [not found]         ` <201202221634.45159.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-23  8:12           ` Thierry Reding
2012-02-23  8:12             ` Thierry Reding
     [not found]             ` <20120223081235.GC8621-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-02-23 14:07               ` Arnd Bergmann
2012-02-23 14:07                 ` Arnd Bergmann
     [not found]                 ` <201202231407.12981.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-23 16:04                   ` Thierry Reding
2012-02-23 16:04                     ` Thierry Reding
     [not found]                     ` <20120223160420.GA9899-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-03-03 19:32                       ` Thierry Reding
2012-03-03 19:32                         ` Thierry Reding
     [not found]                         ` <20120303193249.GA22021-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-03-06 15:38                           ` Arnd Bergmann
2012-03-06 15:38                             ` Arnd Bergmann
     [not found]                             ` <201203061538.11709.arnd-r2nGTMty4D4@public.gmane.org>
2012-03-06 19:17                               ` Thierry Reding
2012-03-06 19:17                                 ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 03/10] of: Add PWM support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
     [not found]     ` <1329923841-32017-4-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-22 16:15       ` Arnd Bergmann
2012-02-22 16:15         ` Arnd Bergmann
     [not found]         ` <201202221615.11605.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-23  7:55           ` Thierry Reding
2012-02-23  7:55             ` Thierry Reding
     [not found]             ` <20120223075537.GB8621-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-02-23 14:03               ` Arnd Bergmann
2012-02-23 14:03                 ` Arnd Bergmann
     [not found]                 ` <201202231403.01614.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-24  6:47                   ` Thierry Reding
2012-02-24  6:47                     ` Thierry Reding
     [not found]                     ` <20120224064749.GB18786-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-02-24 16:58                       ` Arnd Bergmann
2012-02-24 16:58                         ` Arnd Bergmann
     [not found]                         ` <201202241658.32062.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-25 12:33                           ` Sascha Hauer
2012-02-25 12:33                             ` Sascha Hauer
     [not found]                             ` <20120225123357.GU3852-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2012-02-25 23:08                               ` Ryan Mallon
2012-02-25 23:08                                 ` Ryan Mallon
2012-02-22 15:17   ` [PATCH v3 04/10] arm/tegra: Fix PWM clock programming Thierry Reding
2012-02-22 15:17     ` Thierry Reding
     [not found]     ` <1329923841-32017-5-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-28 21:01       ` Stephen Warren
2012-02-28 21:01         ` Stephen Warren
     [not found]         ` <74CDBE0F657A3D45AFBB94109FB122FF17BDDF1E52-C7FfzLzN0UxDw2glCA4ptUEOCMrvLtNR@public.gmane.org>
2012-03-03 22:47           ` Thierry Reding
2012-03-03 22:47             ` Thierry Reding
     [not found]             ` <20120303224751.GB6661-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-03-05 17:33               ` Stephen Warren
2012-03-05 17:33                 ` Stephen Warren
2012-02-22 15:17   ` [PATCH v3 05/10] arm/tegra: Provide clock for only one PWM controller Thierry Reding
2012-02-22 15:17     ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 06/10] pwm: Add NVIDIA Tegra SoC support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
     [not found]     ` <1329923841-32017-7-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-23  1:47       ` Ryan Mallon
2012-02-23  1:47         ` Ryan Mallon
     [not found]         ` <4F459A94.4030104-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2012-02-23  8:14           ` Thierry Reding
2012-02-23  8:14             ` Thierry Reding
     [not found]             ` <20120223081459.GD8621-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-02-23  9:25               ` Ryan Mallon
2012-02-23  9:25                 ` Ryan Mallon
     [not found]                 ` <4F460616.3080400-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2012-02-24  6:48                   ` Thierry Reding
2012-02-24  6:48                     ` Thierry Reding
2012-02-28 21:14       ` Stephen Warren
2012-02-28 21:14         ` Stephen Warren
     [not found]         ` <74CDBE0F657A3D45AFBB94109FB122FF17BDDF1E63-C7FfzLzN0UxDw2glCA4ptUEOCMrvLtNR@public.gmane.org>
2012-03-03 22:42           ` Thierry Reding
2012-03-03 22:42             ` Thierry Reding
     [not found]             ` <20120303224212.GA6661-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-03-05  3:39               ` Olof Johansson
2012-03-05  3:39                 ` Olof Johansson
     [not found]                 ` <20120305033935.GA32675-O5ziIzlqnXUVNXGz7ipsyg@public.gmane.org>
2012-03-05  7:00                   ` Thierry Reding
2012-03-05  7:00                     ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 08/10] pwm: Add Blackfin support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 09/10] pwm: Add PXA support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
     [not found]     ` <1329923841-32017-10-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-22 15:40       ` Arnd Bergmann
2012-02-22 15:40         ` Arnd Bergmann
     [not found]         ` <201202221540.16897.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-23  6:10           ` Thierry Reding
2012-02-23  6:10             ` Thierry Reding
2012-02-22 15:17   ` [PATCH v3 10/10] pwm-backlight: Add rudimentary device tree support Thierry Reding
2012-02-22 15:17     ` Thierry Reding
2012-02-22 16:02   ` [PATCH v3 00/10] Add PWM framework and " Arnd Bergmann
2012-02-22 16:02     ` Arnd Bergmann
     [not found]     ` <201202221602.09116.arnd-r2nGTMty4D4@public.gmane.org>
2012-02-23  7:29       ` Thierry Reding
2012-02-23  7:29         ` Thierry Reding
2012-02-22 15:17 ` [PATCH v3 07/10] arm/tegra: Add PWFM controller device tree probing Thierry Reding
2012-02-22 15:17   ` Thierry Reding
     [not found]   ` <1329923841-32017-8-git-send-email-thierry.reding-RM9K5IK7kjKj5M59NBduVrNAH6kLmebB@public.gmane.org>
2012-02-28 21:20     ` Stephen Warren
2012-02-28 21:20       ` Stephen Warren
     [not found]       ` <74CDBE0F657A3D45AFBB94109FB122FF17BDDF1E67-C7FfzLzN0UxDw2glCA4ptUEOCMrvLtNR@public.gmane.org>
2012-03-03 22:54         ` Thierry Reding
2012-03-03 22:54           ` Thierry Reding
     [not found]           ` <20120303225404.GC6661-RM9K5IK7kjIQXX3q8xo1gnVAuStQJXxyR5q1nwbD4aMs9pC9oP6+/A@public.gmane.org>
2012-03-04 20:39             ` Arnd Bergmann
2012-03-04 20:39               ` Arnd Bergmann
2012-03-05 17:51             ` Stephen Warren
2012-03-05 17:51               ` Stephen Warren
     [not found]               ` <74CDBE0F657A3D45AFBB94109FB122FF17BE861C46-C7FfzLzN0UxDw2glCA4ptUEOCMrvLtNR@public.gmane.org>
2012-03-05 18:15                 ` Thierry Reding
2012-03-05 18:15                   ` Thierry Reding
     [not found]                   ` <20120305181555.GA22459-RM9K5IK7kjIyiCvfTdI0JKcOhU4Rzj621B7CTYaBSLdn68oJJulU0Q@public.gmane.org>
2012-03-05 18:39                     ` Stephen Warren
2012-03-05 18:39                       ` Stephen Warren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.