Add PWM framework and device tree support.
Subsystems (10)
v4 cover Add PWM framework and device tree support.
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). 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 and adds an API to request a PWM device given the PWM chip or the struct device associated with a PWM chip. They are supposed to eventually replace pwm_request() and allow to get rid of the global namespace. 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. If the no corresponding PWM chip is available yet, the code returns EPROBE_DEFER to have users automatically probed again later when the PWM provider may have become available. 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 20120314. I think I've addressed all of the concerns raised in the first three 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.
pwm: Add device tree support
ARM: tegra: Provide clock for only one PWM controller
pwm: Add NVIDIA Tegra SoC support
pwm: tegra: Add device tree support
pwm: Add Blackfin support
pwm: Add PXA support
pwm-backlight: Add rudimentary device tree support
Documentation/devicetree/bindings/pwm/pwm.txt | 48 ++ .../devicetree/bindings/pwm/tegra-pwm.txt | 18 + .../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/tegra2_clocks.c | 37 +- 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/pwm/Kconfig | 40 ++ drivers/pwm/Makefile | 4 + drivers/pwm/core.c | 557 ++++++++++++++++++++ drivers/pwm/pwm-bfin.c | 164 ++++++ drivers/pwm/pwm-pxa.c | 244 +++++++++ drivers/pwm/pwm-tegra.c | 267 ++++++++++ drivers/video/backlight/Kconfig | 2 +- drivers/video/backlight/pwm_bl.c | 136 ++++- include/linux/of_pwm.h | 36 ++ include/linux/pwm.h | 97 ++++ include/linux/pwm_backlight.h | 2 + 29 files changed, 1732 insertions(+), 442 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt create mode 100644 Documentation/devicetree/bindings/pwm/tegra-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/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
Signature · 1 line
1.7.9.4
PATCH v4 1/10 PWM: add pwm framework support
From: Sascha Hauer <[email protected]>
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.
--- 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(+) 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
Documentation/pwm.txt new file +56 -0
@@ -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.
MAINTAINERS +6 -0
@@ -5403,6 +5403,12 @@ S: Maintained F: Documentation/video4linux/README.pvrusb2 F: drivers/media/video/pvrusb2/ +PPWM core +M: Sascha Hauer <[email protected]> +L: linux-kernel at vger.kernel.org +S: Maintained +F: drivers/pwm/ + PXA2xx/PXA3xx SUPPORT M: Eric Miao <[email protected]> M: Russell King <[email protected]>
drivers/Kconfig +2 -0
@@ -142,4 +142,6 @@ source "drivers/devfreq/Kconfig" source "drivers/modem_shm/Kconfig" +source "drivers/pwm/Kconfig" + endmenu
drivers/Makefile +1 -0
@@ -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/
drivers/pwm/Kconfig new file +12 -0
@@ -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
drivers/pwm/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_PWM) += core.o
drivers/pwm/core.c new file +220 -0
220 lines not on this page · raw message
include/linux/pwm.h +37 -0
@@ -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 */
Signature · 1 line
1.7.9.4
PATCH v4 1/10 PWM: add pwm framework support
include/linux/pwm.h int pwm_enable(struct pwm_device *pwm); · line 61
Quoted 5 lines · Thierry Reding
[...]
include/linux/pwm.h +4
-0+struct pwm_chip { +int pwm_id; +const char *label; +struct pwm_ops *ops;
Nothing major, but if you are going for another round it would be good to see ops made const.
Quoted 1 line
+};
PATCH v4 1/10 PWM: add pwm framework support
Quoted 9 lines · Lars-Peter Clausen
include/linux/pwm.h int pwm_enable(struct pwm_device *pwm); · line 61
Quoted 5 lines · Thierry Reding
[...]
include/linux/pwm.h +4
-0+struct pwm_chip { +int pwm_id; +const char *label; +struct pwm_ops *ops;Nothing major, but if you are going for another round it would be good to see ops made const.
I'll go for another round because I just noticed that I still have two open TODO items that I forgot to fix from last round's review.
I'll take a note to make it const.
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/20120314/5fdebc1d/attachment.sig>
PATCH v4 1/10 PWM: add pwm framework support
In reply to Thierry RedingOn Wed, Mar 14, 2012 at 04:56:24PM +0100, Thierry Reding wrote:
...
Quoted 1 line
+PPWM core
s/PPWM/PWM?
Quoted 5 lines
MAINTAINERS +5
-0+M: Sascha Hauer <[email protected]> +L: linux-kernel at vger.kernel.org +S: Maintained +F: drivers/pwm/ +
Signature · 2 lines
Regards, Shawn
PATCH v4 1/10 PWM: add pwm framework support
Quoted 5 lines · Shawn Guo
On Wed, Mar 14, 2012 at 04:56:24PM +0100, Thierry Reding wrote:
...Quoted 1 line
+PPWM core
s/PPWM/PWM?
Yes, I noticed that as well just yesterday.
Thanks,
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/20120316/f083da3e/attachment.sig>
PATCH v4 1/10 PWM: add pwm framework support
In reply to Thierry RedingQuoted 3 lines · Thierry Reding
From: Sascha Hauer <[email protected]>
This patch adds framework support for PWM (pulse width modulation) devices.
...
Quoted 1 line
drivers/pwm/core.c +0
-0
...
Quoted 7 lines
+/**
+ *pwmchip_add()- register a new pwm
+ * @chip: the pwm
+ *
+ * register a new pwm.pwm->pwm_idmust be initialized. ifpwm_id< 0 then
+ * a dynamically assigned id will be used, otherwise the id specified,
+ */
I don't see anywhere in the code that implements "if pwm_id < 0 then a dynamically assigned id will be used".
PATCH v4 1/10 PWM: add pwm framework support
Quoted 15 lines · Stephen Warren
Quoted 3 lines · Thierry Reding
From: Sascha Hauer <[email protected]>
This patch adds framework support for PWM (pulse width modulation) devices.
...
Quoted 1 line
drivers/pwm/core.c +0
-0...
Quoted 7 lines
+/**
+ *pwmchip_add()- register a new pwm
+ * @chip: the pwm
+ *
+ * register a new pwm.pwm->pwm_idmust be initialized. ifpwm_id< 0 then
+ * a dynamically assigned id will be used, otherwise the id specified,
+ */
Quoted 2 lines
I don't see anywhere in the code that implements "if
pwm_id< 0 then a dynamically assigned id will be used".
The second patch in the series fixes up this comment when the functionality is properly implemented. I still wanted to go over the first patch and fix up some minor things, so maybe I'll fix this up as I go along.
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/20120320/f86a1fb5/attachment.sig>
PATCH v4 2/10 pwm: Allow chips to support multiple PWMs.
In reply to Thierry RedingMany 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 argument that specified the PWM number (it can be converted to a per-chip index by subtracting the chip's base).
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.
---
Changes in v4:
- remove OF-specific code to preserve bisectability
- add pwm_request_from_device() and pwm_request_from_chip() functions
- refactor PWM requesting code
- store period in struct pwm_device and get rid of the unused struct pwm_spec
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
drivers/pwm/core.c | 376 +++++++++++++++++++++++++++++++++++++++------------ include/linux/pwm.h | 78 +++++++++-- 2 files changed, 358 insertions(+), 96 deletions(-)
drivers/pwm/core.c +293 -83
@@ -2,6 +2,7 @@* Generic pwmlib implementation * * Copyright (C) 2011 Sascha Hauer <[email protected]> +* Copyright (C) 2011-2012 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
@@ -17,105 +18,207 @@* 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/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 1024static 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; + +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); + } + +bitmap_clear (allocated_pwms, chip->base, chip->npwm); + +kfree (chip->pwms); + chip->pwms =NULL ; +} + +static struct pwm_chip *device_to_pwmchip (struct device *dev) +{ +struct pwm_chip *chip; + +mutex_lock (&pwm_lock); + +list_for_each_entry (chip, &pwm_chips, list) +if (chip->dev == dev) { +mutex_unlock (&pwm_lock); +return chip; + } + +mutex_unlock (&pwm_lock); + +return ERR_PTR (-ENODEV ); +} + +static int pwm_device_request (struct pwm_device *pwm,const char *label) +{ +int err; + +if (test_bit (PWMF_REQUESTED , &pwm->flags)) +return -EBUSY ; + +if (!try_module_get (pwm->chip->ops->owner)) +return -ENODEV ; -list_for_each_entry (pwm, &pwm_list, node) { -if (pwm->chip->pwm_id == pwm_id) -return pwm; +if (pwm->chip->ops->request) { + err = pwm->chip->ops->request (pwm->chip, pwm); +if (err) { +module_put (pwm->chip->ops->owner); +return err; + } } -return NULL ; +set_bit (PWMF_REQUESTED , &pwm->flags); + pwm->label = label; + +return 0 ; +} + +/** +* 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); +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); +free_pwms (chip); -kfree (pwm); out:mutex_unlock (&pwm_lock); -return ret; }EXPORT_SYMBOL_GPL (pwmchip_remove);
@@ -123,50 +226,89 @@ 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_request (int pwm,const char *label) { -struct pwm_device *pwm; -int ret; +struct pwm_device *dev; +int err; + +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 ); - goto out; - } + err =pwm_device_request (dev, label); +if (err <0 ) + dev =ERR_PTR (err); -if (!try_module_get (pwm->chip->ops->owner)) { - pwm =ERR_PTR (-ENODEV ); - goto out; - } +out: +mutex_unlock (&pwm_lock); -if (pwm->chip->ops->request) { - ret = pwm->chip->ops->request (pwm->chip); -if (ret) { - pwm =ERR_PTR (ret); - goto out_put; - } - } +return dev; +} +EXPORT_SYMBOL_GPL (pwm_request); - pwm->label = label; -set_bit (FLAG_REQUESTED , &pwm->flags); +/** +* pwm_request_from_device() - request a PWM device relative to a device +* @dev: device representing a PWM chip +* @index: per-chip index of the PWM to request +* @label: a literal description string of this PWM +* +* Returns the PWM at the given index of the PWM chip represented by the +* given device. A negative error code is returned if the device does not +* represent a PWM chip, the index is not valid for the specified PWM chip +* or if the PWM device cannot be requested. +*/ +struct pwm_device *pwm_request_from_device (struct device *dev, +unsigned int index, +const char *label) +{ +struct pwm_chip *chip; - goto out; + chip =device_to_pwmchip (dev); +if (IS_ERR (chip)) +return ERR_CAST (chip); -out_put: -module_put (pwm->chip->ops->owner); -out: -mutex_unlock (&pwm_lock); +return pwm_request_from_chip (chip, index, label); +} +EXPORT_SYMBOL_GPL (pwm_request_from_device); + +/** +* pwm_request_from_chip() - request a PWM device relative to a PWM chip +* @chip: PWM chip +* @index: per-chip index of the PWM to request +* @label: a literal description string of this PWM +* +* Returns the PWM at the given index of the given PWM chip. A negative error +* code is returned if the index is not valid for the specified PWM chip or +* if the PWM device cannot be requested. +*/ +struct pwm_device *pwm_request_from_chip (struct pwm_chip *chip, +unsigned int index, +const char *label) +{ +struct pwm_device *pwm; +int err; + +if (index >= chip->npwm) +return ERR_PTR (-EINVAL ); + +mutex_lock (&pwm_lock); + pwm = &chip->pwms[index]; + + err =pwm_device_request (pwm, label); +if (err <0 ) + pwm =ERR_PTR (err); +mutex_unlock (&pwm_lock);return pwm; } -EXPORT_SYMBOL_GPL (pwm_request); +EXPORT_SYMBOL_GPL (pwm_request_from_chip);/* * pwm_free - free a PWM device
@@ -175,11 +317,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 +338,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 +347,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 +359,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 */
include/linux/pwm.h +65 -13
103 lines not on this page · raw message
Signature · 1 line
1.7.9.4
PATCH v4 2/10 pwm: Allow chips to support multiple PWMs.
Quoted 23 lines · Thierry Reding
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 thepwm_opsstructure gets an additional argument that specified the PWM number (it can be converted to a per-chip index by subtracting the chip's base).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.
Signed-off-by Thierry Reding <[email protected]>---
<snip>
Quoted 4 lines
include/linux/pwm.h +0
-0
<snip>
Quoted 23 lines
/**
- * structpwm_ops- PWM operations
+ * structpwm_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 */
structpwm_ops{include/linux/pwm.h +5
-6-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,
include/linux/pwm.h void pwm_disable(struct pwm_device *pwm); · line 86
Quoted 10 lines
include/linux/pwm.h +10
-0+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
This doesn't compile...
include/linux/pwm.h:87: warning: 'struct seq_file' declared inside parameter list include/linux/pwm.h:87: warning: its scope is only this definition or declaration, which is probably not what you want
Regards,
Hartley
PATCH v4 2/10 pwm: Allow chips to support multiple PWMs.
Quoted 1 line · H Hartley Sweeten
On Wednesday, March 14, 2012 8:56 AM, Thierry Reding wrote:
[...]
Quoted 9 lines
include/linux/pwm.h void pwm_disable(struct pwm_device *pwm); · line 86
Quoted 4 lines
include/linux/pwm.h +4
-0+#ifdef CONFIG_DEBUG_FS +void (*dbg_show)(struct pwm_chip *chip, +struct seq_file *s); +#endif This doesn't compile...
include/linux/pwm.h:87: warning: 'structseq_file' declared inside parameter listinclude/linux/pwm.h:87: warning: its scope is only this definition or declaration, which is probably not what you want
Okay, pwm.h probably needs a seq_file.h include. Thanks for noticing.
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/20120314/31768589/attachment.sig>
PATCH v4 2/10 pwm: Allow chips to support multiple PWMs.
Quoted 10 lines · Thierry Reding
Quoted 1 line · H Hartley Sweeten
On Wednesday, March 14, 2012 8:56 AM, Thierry Reding wrote:
[...]
Quoted 7 lines
include/linux/pwm.h void pwm_disable(struct pwm_device *pwm); · line 86
Quoted 4 lines
include/linux/pwm.h +4
-0+#ifdef CONFIG_DEBUG_FS +void (*dbg_show)(struct pwm_chip *chip, +struct seq_file *s); +#endif This doesn't compile...
Quoted 4 lines
Quoted 2 lines
include/linux/pwm.h:87: warning: 'structseq_file' declared inside parameter listinclude/linux/pwm.h:87: warning: its scope is only this definition or declaration, which is probably not what you wantOkay,
pwm.hprobably needs aseq_file.hinclude. Thanks for noticing.
Or just a:
struct seq_file;
Regards,
Hartley
PATCH v4 3/10 pwm: Add device tree support
In reply to Thierry RedingThis patch adds helpers to support device tree bindings for the generic PWM API. Device tree binding documentation for PWM controllers is also provided.
---
Changes in v4:
- add OF-specific code removed from patch 2
- make of_node_to_pwmchip() and of_pwm_simple_xlate() static
- rename of_get_named_pwm() to of_pwm_request(), return a struct pwm_device, get rid of the now unused spec parameter and use the device_node.name field as the PWM's name
- return a requested struct pwm_device from pwm_chip.of_xlate and drop the now unused spec parameter
- move OF support code into drivers/pwm/core.c
- used deferred probing if a PWM chip is not available yet
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/pwm/core.c | 127 +++++++++++++++++++++++++ include/linux/of_pwm.h | 36 +++++++ include/linux/pwm.h | 8 ++ 5 files changed, 225 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt create mode 100644 include/linux/of_pwm.h
Documentation/devicetree/bindings/pwm/pwm.txt new file +48 -0
@@ -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>; + };
drivers/of/Kconfig +6 -0
@@ -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
drivers/pwm/core.c +127 -0
157 lines not on this page · raw message
include/linux/of_pwm.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* OF helpers for the PWM API +* +* Copyright (c) 2011-2012 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/err.h> +#include <linux/pwm.h> + +struct device_node ; + +#ifdef CONFIG_OF_PWM + +struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname,int index); + +#else + +static inline struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname, +int index); +{ +return ERR_PTR (-ENOSYS ); +} + +#endif /* CONFIG_OF_PWM */ + +#endif /* __LINUX_OF_PWM_H */
include/linux/pwm.h +8 -0
@@ -1,6 +1,8 @@#ifndef __LINUX_PWM_H#define __LINUX_PWM_H +#include <linux/of.h> +struct pwm_device ;/*
@@ -102,6 +104,12 @@ struct pwm_chip {unsigned int npwm;struct pwm_device *pwms; + +#ifdef CONFIG_OF_PWM +struct pwm_device * (*of_xlate)(struct pwm_chip *pc, +const struct of_phandle_args *args); +unsigned int of_pwm_n_cells; +#endif };int pwm_set_chip_data (struct pwm_device *pwm,void *data);
Signature · 1 line
1.7.9.4
PATCH v4 3/10 pwm: Add device tree support
Quoted 292 lines · Thierry Reding
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 <[email protected]>---
Changes in v4:
- add OF-specific code removed from patch 2
- makeof_node_to_pwmchip()andof_pwm_simple_xlate()static
- renameof_get_named_pwm()toof_pwm_request(), return a structpwm_device, get rid of the now unused spec parameter and use the device_node.name field as the PWM's name
- return a requested structpwm_devicefrom pwm_chip.of_xlate and drop the now unused spec parameter
- move OF support code intodrivers/pwm/core.c
- used deferred probing if a PWM chip is not available yetChanges in v2:
- add device tree binding documentation
- addof_xlateto parse controller-specific PWM-specifierDocumentation/devicetree/bindings/pwm/pwm.txt | 48 ++++++++++ drivers/of/Kconfig | 6 ++ drivers/pwm/core.c | 127 +++++++++++++++++++++++++ include/linux/of_pwm.h | 36 +++++++ include/linux/pwm.h | 8 ++ 5 files changed, 225 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pwm.txt create mode 100644 include/linux/of_pwm.hDocumentation/devicetree/bindings/pwm/pwm.txt new file +48
-0@@ -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>; + };drivers/of/Kconfig +6
-0@@ -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 && !SPARCdrivers/pwm/core.c +127
-0@@ -20,6 +20,7 @@*/ #include <linux/module.h> +#include <linux/of_pwm.h> #include <linux/pwm.h> #include <linux/radix-tree.h> #include <linux/list.h> @@ -121,6 +122,75 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)return 0 ; } +#ifdef CONFIG_OF_PWM +static struct pwm_chip *of_node_to_pwmchip (struct device_node *np) +{ +struct pwm_chip *chip; + +mutex_lock (&pwm_lock); + +list_for_each_entry (chip, &pwm_chips, list) +if (chip->dev && chip->dev->of_node == np) { +mutex_unlock (&pwm_lock); +return chip; + } + +mutex_unlock (&pwm_lock); + +return ERR_PTR (-EPROBE_DEFER ); +} + +static struct pwm_device *of_pwm_simple_xlate (struct pwm_chip *pc, +const struct of_phandle_args *args) +{ +struct pwm_device *pwm; + +if (pc->of_pwm_n_cells <2 ) +return ERR_PTR (-EINVAL ); + +if (args->args_count < pc->of_pwm_n_cells) +return ERR_PTR (-EINVAL ); + +if (args->args[0 ] >= pc->npwm) +return ERR_PTR (-EINVAL ); + + pwm =pwm_request_from_device (pc->dev, args->args[0 ],NULL ); +if (IS_ERR (pwm)) +return ERR_PTR (-ENODEV ); + +pwm_set_period (pwm, args->args[1 ]); + +return pwm; +} + +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); +} +#else +static inline void of_pwmchip_add (struct pwm_chip *pc) +{ +} + +static inline void of_pwmchip_remove (struct pwm_chip *pc) +{ +} +#endif /* CONFIG_OF_PWM */ +/** * pwm_set_chip_data - set private chip data for a PWM * @pwm: PWM device @@ -184,6 +254,7 @@ int pwmchip_add(struct pwm_chip *chip)INIT_LIST_HEAD (&chip->list);list_add (&chip->list, &pwm_chips); +of_pwmchip_add (chip); out:mutex_unlock (&pwm_lock);@@ -215,6 +286,7 @@ int pwmchip_remove(struct pwm_chip *chip) }list_del_init (&chip->list); +of_pwmchip_remove (chip);free_pwms (chip); out:@@ -364,6 +436,61 @@ void pwm_disable(struct pwm_device *pwm) }EXPORT_SYMBOL_GPL (pwm_disable); +#ifdef CONFIG_OF +/** +* of_pwm_request() - request a PWM via the PWM framework +* @np: device node to get the PWM from +* @propname: property name containing PWM specifier(s) +* @index: index of the PWM +* +* Returns the PWM device parsed from the phandle specified in the given +* property of a device tree node or NULL on failure. Values parsed from +* the device tree are stored in the returned PWM device object. +*/ +struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname,int index) +{ +struct pwm_device *pwm =NULL ; +struct of_phandle_args args; +struct pwm_chip *pc; +int err; + + err =of_parse_phandle_with_args (np, propname,"#pwm-cells" , index, + &args); +if (err) { +pr_debug ("%s(): can't parse property \"%s\"\n" , __func__, + propname); +return ERR_PTR (err); + } + + pc =of_node_to_pwmchip (args.np); +if (IS_ERR (pc)) { +pr_debug ("%s(): PWM chip not found\n" , __func__); + pwm =ERR_CAST (pc); + 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); + pwm =ERR_PTR (-EINVAL ); + goto put; + } + + pwm = pc->of_xlate (pc, &args); +if (IS_ERR (pwm)) + goto put; + + pwm->label = np->name; + +put: +of_node_put (args.np); + +return pwm; +} +EXPORT_SYMBOL (of_pwm_request); +#endif +#ifdef CONFIG_DEBUG_FS static void pwm_dbg_show (struct pwm_chip *chip,struct seq_file *s) {include/linux/of_pwm.h new file +19
-0@@ -0,0 +1,36 @@ +/* +* OF helpers for the PWM API +* +* Copyright (c) 2011-2012 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/err.h> +#include <linux/pwm.h> + +struct device_node ; +
include/linux/of_pwm.h line 29
Quoted 10 lines
include/linux/of_pwm.h new file +10
-0+#ifdef CONFIG_OF_PWM + +struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname,int index); + +#else + +static inline struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname, +int index);
^^^
No semicolon here please.
Sascha
Signature · 4 lines
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 |
PATCH v4 3/10 pwm: Add device tree support
Quoted 7 lines · Sascha Hauer
include/linux/of_pwm.h line 29
Quoted 3 lines · Thierry Reding
include/linux/of_pwm.h new file +3
-0+static inline struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname, +int index);^^^No semicolon here please.
Ugh. I've been doing extra compile tests to make sure the series stays bisectible, but I guess I need to add further tests with !PWM and !OF configurations.
Thanks,
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/20120314/cbeae2b2/attachment.sig>
PATCH v4 3/10 pwm: Add device tree support
In reply to Thierry RedingQuoted 17 lines · Thierry Reding
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 <[email protected]>---
Changes in v4:
- add OF-specific code removed from patch 2
- makeof_node_to_pwmchip()andof_pwm_simple_xlate()static
- renameof_get_named_pwm()toof_pwm_request(), return a structpwm_device, get rid of the now unused spec parameter and use the device_node.name field as the PWM's name
- return a requested structpwm_devicefrom pwm_chip.of_xlate and drop the now unused spec parameter
- move OF support code intodrivers/pwm/core.c
- used deferred probing if a PWM chip is not available yet
Quoted 3 lines
Changes in v2:
- add device tree binding documentation
- addof_xlateto parse controller-specific PWM-specifier
Looks very cool now, and much simpler!
Quoted 7 lines
drivers/of/Kconfig +0
-0@@ -57,6 +57,12 @@ config OF_GPIO help OpenFirmware GPIO accessors
drivers/of/Kconfig config OF_GPIO · line 68
Quoted 10 lines
drivers/of/Kconfig +6
-0+config OF_PWM + def_bool y + depends on PWM + help + OpenFirmware PWM accessors + config OF_I2C def_tristate I2C depends on I2C && !SPARC
You might want to remove this one now and just use CONFIG_OF in the driver, unless there is a reason to keep it here.
Quoted 7 lines
drivers/of/Kconfig +7
-0+#ifdef CONFIG_OF_PWM +static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) +{ + struct pwm_chip *chip; + + mutex_lock(&pwm_lock); +
drivers/of/Kconfig
Quoted 10 lines
drivers/of/Kconfig +10
-0+ list_for_each_entry(chip, &pwm_chips, list) + if (chip->dev && chip->dev->of_node == np) { + mutex_unlock(&pwm_lock); + return chip; + } + + mutex_unlock(&pwm_lock); + + return ERR_PTR(-EPROBE_DEFER); +}
EPROBE_DEFER doesn't exist yet in my kernel, and I wonder if it's actually safe to be used this way, because it can result in arbitrary drivers using this to be put on the defered probe list. It certainly sounds like the right thing to do in the long run though.
Quoted 14 lines
drivers/of/Kconfig +10
-0+#else +static inline void of_pwmchip_add(struct pwm_chip *pc) +{ +} + +static inline void of_pwmchip_remove(struct pwm_chip *pc) +{ +} +#endif /* CONFIG_OF_PWM */ + /** * pwm_set_chip_data - set private chip data for a PWM * @pwm: PWM device
drivers/of/Kconfig int pwmchip_add(struct pwm_chip *chip) · line 260
Quoted 7 lines
drivers/of/Kconfig +1
-0@@ -184,6 +254,7 @@ int pwmchip_add(struct pwm_chip *chip) INIT_LIST_HEAD(&chip->list); list_add(&chip->list, &pwm_chips); + of_pwmchip_add(chip); out: mutex_unlock(&pwm_lock);
You could express the same thing using
if (IS_ENABLED(CONFIG_OF_PWM)) of_pwmchip_add(chip);
The advantage of this is that you always get compile coverage for the entire file, but the function is automatically discarded by the compiler when the condition is false at compile time. That obviously doesn't work for exported functions.
Quoted 11 lines
drivers/of/Kconfig +11
-0+#ifdef CONFIG_OF +/** + * of_pwm_request() - request a PWM via the PWM framework + * @np: device node to get the PWM from + * @propname: property name containing PWM specifier(s) + * @index: index of the PWM + * + * Returns the PWM device parsed from the phandle specified in the given + * property of a device tree node or NULL on failure. Values parsed from + * the device tree are stored in the returned PWM device object. + */
drivers/of/Kconfig
Quoted 10 lines
drivers/of/Kconfig +10
-0+struct pwm_device *of_pwm_request(struct device_node *np, + const char *propname, int index) +{ + struct pwm_device *pwm = NULL; + struct of_phandle_args args; + struct pwm_chip *pc; + int err; + + err = of_parse_phandle_with_args(np, propname, "#pwm-cells", index, + &args);
Wow, I just looked up what of_parse_phandle_with_args() does and that is extremely helpful indeed.
Quoted 4 lines
/*
drivers/of/Kconfig +0
-0@@ -102,6 +104,12 @@ struct pwm_chip { unsigned int npwm;
drivers/of/Kconfig struct pwm_chip { · line 115
Quoted 10 lines
drivers/of/Kconfig +6
-0struct pwm_device *pwms; + +#ifdef CONFIG_OF_PWM + struct pwm_device * (*of_xlate)(struct pwm_chip *pc, + const struct of_phandle_args *args); + unsigned int of_pwm_n_cells; +#endif }; int pwm_set_chip_data(struct pwm_device *pwm, void *data);
If you use IS_ENABLED() as I suggested above, this #ifdef will have to go away, too, which is a very small size overhead.
Arnd
PATCH v4 3/10 pwm: Add device tree support
Quoted 5 lines · Arnd Bergmann
Quoted 2 lines · Thierry Reding
(quoted diff) +2
-0+static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) +{
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ return ERR_PTR(-EPROBE_DEFER); +}
EPROBE_DEFERdoesn't exist yet in my kernel, and I wonder if it's actually safe to be used this way, because it can result in arbitrary drivers using this to be put on the defered probe list. It certainly sounds like the right thing to do in the long run though.
Similar code is going in for regulators in 3.4 along with the core -EPROBE_DEFER change (though not OF specific) and I sent a similar patch for GPIOs too, hopefully Grant will ack it in time for it to make it in.
My theory is that since you need to explicitly know that the thing you're requesting is there in order to request it (eg, have a PWM number or DT link) the overwhemlingly common case for a failure to request will be that the provider didn't register yet which is exactly the case where deferral is desired. It therefore seems sensible to have the framework default the drivers to retrying rather than have almost every individual driver look at the failure, figure out if it was a missing provider, and then retry. Drivers that have a good reason to fail can always check for -EPROBE_DEFER and override it.
The result should be that we can take advantage of probe deferral over
large areas of the kernel without having to go and explicitly modify so
many drivers - if the frameworks like GPIO, clk and regulator can do
this that ought to cover 90% of the cases where probe deferral will be
needed without having to do anything more than have good error handling
paths on probe which is a good idea anyway.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120315/09137da3/attachment.sig>
PATCH v4 3/10 pwm: Add device tree support
Quoted 14 lines · Mark Brown
Similar code is going in for regulators in 3.4 along with the core -EPROBE_DEFER change (though not OF specific) and I sent a similar patch for GPIOs too, hopefully Grant will ack it in time for it to make it in.
My theory is that since you need to explicitly know that the thing you're requesting is there in order to request it (eg, have a PWM number or DT link) the overwhemlingly common case for a failure to request will be that the provider didn't register yet which is exactly the case where deferral is desired. It therefore seems sensible to have the framework default the drivers to retrying rather than have almost every individual driver look at the failure, figure out if it was a missing provider, and then retry. Drivers that have a good reason to fail can always check for -EPROBE_DEFER and override it.
Quoted 6 lines
The result should be that we can take advantage of probe deferral over large areas of the kernel without having to go and explicitly modify so many drivers - if the frameworks like GPIO, clk and regulator can do this that ought to cover 90% of the cases where probe deferral will be needed without having to do anything more than have good error handling paths on probe which is a good idea anyway.
Ok, makes sense.
Thanks,
Arnd
PATCH v4 3/10 pwm: Add device tree support
In reply to Thierry RedingQuoted 3 lines · Thierry Reding
This patch adds helpers to support device tree bindings for the generic PWM API. Device tree binding documentation for PWM controllers is also provided.
...
Quoted 2 lines
drivers/pwm/core.c +2
-0+static struct pwm_device *of_pwm_simple_xlate (struct pwm_chip *pc, +const struct of_phandle_args *args)
...
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (args->args_count < pc->of_pwm_n_cells) + return ERR_PTR(-EINVAL);
I think you can drop that error-check given the code quoted below?
(and if not, shouldn't it be != not >= ?)
Quoted 2 lines
drivers/pwm/core.c +2
-0+struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname,int index)
...
Quoted 8 lines
drivers/pwm/core.c +8
-0+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); + pwm =ERR_PTR (-EINVAL ); + goto put; + } + + pwm = pc->of_xlate (pc, &args);
PATCH v4 3/10 pwm: Add device tree support
Quoted 18 lines · Stephen Warren
Quoted 3 lines · Thierry Reding
This patch adds helpers to support device tree bindings for the generic PWM API. Device tree binding documentation for PWM controllers is also provided.
...
Quoted 2 lines
drivers/pwm/core.c +2
-0+static struct pwm_device *of_pwm_simple_xlate (struct pwm_chip *pc, +const struct of_phandle_args *args)...
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (args->args_count < pc->of_pwm_n_cells) + return ERR_PTR(-EINVAL);I think you can drop that error-check given the code quoted below?
(and if not, shouldn't it be != not >= ?)
Quoted 2 lines
drivers/pwm/core.c +2
-0+struct pwm_device *of_pwm_request (struct device_node *np, +const char *propname,int index)...
Quoted 8 lines
drivers/pwm/core.c void pwm_disable(struct pwm_device *pwm) · line 480
Quoted 8 lines
drivers/pwm/core.c +8
-0+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); + pwm =ERR_PTR (-EINVAL ); + goto put; + } + + pwm = pc->of_xlate (pc, &args);
Yes, you're right. It is completely redundant.
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/20120320/657e8c0e/attachment.sig>
PATCH v4 4/10 ARM: tegra: Fix PWM clock programming
In reply to Thierry RedingFrom: Simon Que <[email protected]>
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).
---
Changes in v4:
- reuse PWM flag from Tegra 30 clock programming
- mask out bit 31 explicitly
arch/arm/mach-tegra/tegra2_clocks.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +28 -4
@@ -69,6 +69,8 @@#define PERIPH_CLK_SOURCE_MASK (3<<30)#define PERIPH_CLK_SOURCE_SHIFT 30 +#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28) +#define PERIPH_CLK_SOURCE_PWM_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,20 @@ 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; +u32 mask; + +if (c->flags &MUX_PWM ) { + shift =PERIPH_CLK_SOURCE_PWM_SHIFT ; + mask =PERIPH_CLK_SOURCE_PWM_MASK ; + }else { + shift =PERIPH_CLK_SOURCE_SHIFT ; + mask =PERIPH_CLK_SOURCE_MASK ; + } +if (c->flags &MUX ) {for (sel = c->inputs; sel->input !=NULL ; sel++) { -if (val >>PERIPH_CLK_SOURCE_SHIFT == sel->value) +if ((val & mask) >> shift == sel->value) mux = sel; }BUG_ON (!mux);
@@ -1023,12 +1036,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 &MUX_PWM ) { + shift =PERIPH_CLK_SOURCE_PWM_SHIFT ; + mask =PERIPH_CLK_SOURCE_PWM_MASK ; + }else { + shift =PERIPH_CLK_SOURCE_SHIFT ; + mask =PERIPH_CLK_SOURCE_MASK ; + } +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);
@@ -2146,7 +2170,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 |MUX_PWM ),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),
Signature · 1 line
1.7.9.4
PATCH v4 4/10 ARM: tegra: Fix PWM clock programming
Quoted 7 lines · Thierry Reding
From: Simon Que <[email protected]>
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_0register are located at bit field bit[30:28] while others are at bit field bit[31:30] in their respective clock source register.
Quoted 7 lines
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 <[email protected]>Signed-off-by Bill Huang <[email protected]>Signed-off-by Simon Que <[email protected]>
PATCH v4 5/10 ARM: tegra: Provide clock for only one PWM controller
In reply to Thierry RedingA subsequent patch will add a generic PWM API driver for the Tegra 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.
--- arch/arm/mach-tegra/tegra2_clocks.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
arch/arm/mach-tegra/tegra2_clocks.c +1 -4
@@ -2269,10 +2269,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"),
Signature · 1 line
1.7.9.4
PATCH v4 5/10 ARM: tegra: Provide clock for only one PWM controller
Quoted 6 lines · Thierry Reding
A subsequent patch will add a generic PWM API driver for the Tegra 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 <[email protected]>Acked-by Stephen Warren <[email protected]>
...
arch/arm/mach-tegra/tegra2_clocks.c static struct clk_duplicate tegra_clk_duplicates[] = { · line 2272
Quoted 5 lines
arch/arm/mach-tegra/tegra2_clocks.c +1
-4-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),
I thought harder about this: Why not delete /all/ the CLK_DUPLICATE()s for PWM, and change the second parameter to PERIPH_CLK for PWM from "pwm" to "tegra-pwm"?
PATCH v4 5/10 ARM: tegra: Provide clock for only one PWM controller
Quoted 8 lines · Stephen Warren
Quoted 6 lines · Thierry Reding
A subsequent patch will add a generic PWM API driver for the Tegra 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 <[email protected]>Acked-by Stephen Warren <[email protected]>...
Quoted 9 lines
arch/arm/mach-tegra/tegra2_clocks.c static struct clk_duplicate tegra_clk_duplicates[] = { · line 2272
Quoted 5 lines
arch/arm/mach-tegra/tegra2_clocks.c +1
-4-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),I thought harder about this: Why not delete /all/ the CLK_DUPLICATE()s for PWM, and change the second parameter to
PERIPH_CLKfor PWM from "pwm" to "tegra-pwm"?
I think that should work. I'll retest and will update the patch accordingly. I assume that you're Acked-by will remain valid after those changes?
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/20120320/a12bb98b/attachment-0001.sig>
PATCH v4 5/10 ARM: tegra: Provide clock for only one PWM controller
Quoted 19 lines · Thierry Reding
Quoted 8 lines · Stephen Warren
Quoted 6 lines · Thierry Reding
A subsequent patch will add a generic PWM API driver for the Tegra 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 <[email protected]>Acked-by Stephen Warren <[email protected]>...
Quoted 9 lines
arch/arm/mach-tegra/tegra2_clocks.c static struct clk_duplicate tegra_clk_duplicates[] = { · line 2272
Quoted 5 lines
arch/arm/mach-tegra/tegra2_clocks.c +1
-4-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),I thought harder about this: Why not delete /all/ the CLK_DUPLICATE()s for PWM, and change the second parameter to
PERIPH_CLKfor PWM from "pwm" to "tegra-pwm"?
Quoted 2 lines
I think that should work. I'll retest and will update the patch accordingly. I assume that you're Acked-by will remain valid after those changes?
Yes in this case, assuming the patch looks like what I think it will:-)
PATCH v4 6/10 pwm: Add NVIDIA Tegra SoC support
In reply to Thierry RedingThis 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).
---
Changes in v4:
- merge patch from ChromiumOS kernel to fix a rounding issue
- move DT code to patch 7
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 | 256 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/pwm/pwm-tegra.c
drivers/pwm/Kconfig +10 -0
@@ -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
drivers/pwm/Makefile +1 -0
@@ -1 +1,2 @@ obj-$(CONFIG_PWM) += core.o +obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
drivers/pwm/pwm-tegra.c new file +256 -0
256 lines not on this page · raw message
Signature · 1 line
1.7.9.4
PATCH v4 6/10 pwm: Add NVIDIA Tegra SoC support
Quoted 132 lines · Thierry Reding
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 <[email protected]>---
Changes in v4:
- merge patch from ChromiumOS kernel to fix a rounding issue
- move DT code to patch 7Changes in v3:
- use pwm_device.hwpwm instead of recomputing it
- updatepwm_opsfor changes in patch 2Changes in v2:
- set pwm_chip.dev field
- renameclk_enbto enable
- introduceNUM_PWMmacro instead of hard-coding the number of PWM devices
- update comment integra_pwm_config
- fix coding-style for multi-line comments
- usemodule_platform_driver
- change license to GPLdrivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-tegra.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/pwm/pwm-tegra.cdrivers/pwm/Kconfig +10
-0@@ -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. + endifdrivers/pwm/Makefile +1
-0@@ -1 +1,2 @@ obj-$(CONFIG_PWM) += core.o +obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.odrivers/pwm/pwm-tegra.c new file +69
-0@@ -0,0 +1,256 @@ +/* +* 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 <[email protected]> +* +* 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 ;
drivers/pwm/pwm-tegra.c line 79
Quoted 10 lines
drivers/pwm/pwm-tegra.c new file +10
-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 ; +
Every pwm driver I have been looking at has some validation on parameters here, something like:
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) return -EINVAL;
It's not needed for tegra, or the check on those platforms is unnecessary?
Quoted 112 lines
drivers/pwm/pwm-tegra.c new file +112
-0+/* +* Convert from duty_ns / period_ns to a fixed number of duty ticks +* per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the +* nearest integer during division. +*/ + c = duty_ns * ((1 <<PWM_DUTY_WIDTH ) -1 ) + period_ns /2 ; +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) {
drivers/pwm/pwm-tegra.c line 201
Quoted 10 lines
drivers/pwm/pwm-tegra.c new file +10
-0+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 ; + } +
The helper devm_request_and_ioremap() can help here?
Quoted 41 lines
drivers/pwm/pwm-tegra.c new file +41
-0+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 ;
drivers/pwm/pwm-tegra.c line 252
Quoted 10 lines
drivers/pwm/pwm-tegra.c new file +10
-0+} + +static struct platform_driver tegra_pwm_driver = { + .driver = { + .name ="tegra-pwm" , + }, + .probe = tegra_pwm_probe, + .remove =__devexit_p (tegra_pwm_remove), +}; +
I would remove this blank line.
drivers/pwm/pwm-tegra.c line 253
Quoted 1 line
drivers/pwm/pwm-tegra.c new file +1
-0+module_platform_driver (tegra_pwm_driver);
Regards,
Shawn
Quoted 10 lines
drivers/pwm/pwm-tegra.c new file +3
-0+ +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("NVIDIA Corporation" );Signature · 6 lines
1.7.9.4 _______________________________________________ devicetree-discuss mailing list devicetree-discuss at lists.ozlabs.org https://lists.ozlabs.org/listinfo/devicetree-discuss
PATCH v4 6/10 pwm: Add NVIDIA Tegra SoC support
Quoted 147 lines · Shawn Guo
Quoted 132 lines · Thierry Reding
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 <[email protected]>---
Changes in v4:
- merge patch from ChromiumOS kernel to fix a rounding issue
- move DT code to patch 7Changes in v3:
- use pwm_device.hwpwm instead of recomputing it
- updatepwm_opsfor changes in patch 2Changes in v2:
- set pwm_chip.dev field
- renameclk_enbto enable
- introduceNUM_PWMmacro instead of hard-coding the number of PWM devices
- update comment integra_pwm_config
- fix coding-style for multi-line comments
- usemodule_platform_driver
- change license to GPLdrivers/pwm/Kconfig | 10 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-tegra.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/pwm/pwm-tegra.cdrivers/pwm/Kconfig +10
-0@@ -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. + endifdrivers/pwm/Makefile +1
-0@@ -1 +1,2 @@ obj-$(CONFIG_PWM) += core.o +obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.odrivers/pwm/pwm-tegra.c new file +69
-0@@ -0,0 +1,256 @@ +/* +* 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 <[email protected]> +* +* 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 ;drivers/pwm/pwm-tegra.c line 79
Quoted 10 lines
drivers/pwm/pwm-tegra.c new file +10
-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 ; +Every pwm driver I have been looking at has some validation on parameters here, something like:
Quoted 5 lines
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) return -EINVAL;It's not needed for tegra, or the check on those platforms is unnecessary?
Yes, I should add similar checks for the Tegra driver. On the other hand maybe the checks should be pushed into the core. At least those checks that are truly general sanity checks. Off the top of my head, I can think of the following general preconditions:
pwm != NULL period_ns > 0 duty_ns >= 0 duty_ns <= period_ns
Of course duty_ns >= 0 could be done away with by just making the duty_ns and period_ns parameters unsigned. But such changes were actually supposed to be added incrementally once the framework had been merged.
Quoted 7 lines
Quoted 7 lines
drivers/pwm/pwm-tegra.c new file +7
-0+ 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 ; + } +
Quoted 8 lines
drivers/pwm/pwm-tegra.c line 201
Quoted 6 lines
drivers/pwm/pwm-tegra.c new file +6
-0+ 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 ; + } +The helper
devm_request_and_ioremap()can help here?
Yes, absolutely.
Quoted 11 lines
drivers/pwm/pwm-tegra.c line 252
Quoted 8 lines
drivers/pwm/pwm-tegra.c new file +8
-0+static struct platform_driver tegra_pwm_driver = { + .driver = { + .name ="tegra-pwm" , + }, + .probe = tegra_pwm_probe, + .remove =__devexit_p (tegra_pwm_remove), +}; +I would remove this blank line.
Quoted 1 line
drivers/pwm/pwm-tegra.c new file +1
-0+module_platform_driver (tegra_pwm_driver);
I don't know; I think it makes the code cluttered.
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/20120316/c81c92be/attachment.sig>
PATCH v4 6/10 pwm: Add NVIDIA Tegra SoC support
In reply to Thierry RedingQuoted 3 lines · Thierry Reding
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)
...
Quoted 1 line
drivers/pwm/pwm-tegra.c +0
-0
...
drivers/pwm/pwm-tegra.c line 128
Quoted 6 lines
drivers/pwm/pwm-tegra.c +6
-0+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]) {
IIRC, the new PWM core only calls the enable() op for a disabled -> enabled transition, so this driver probably doesn't need to check the same thing, and you can get rid of tegra_pwm_chip.enable[] and have tegra_pwm_config() read the enable flag from the core pwm device instead.
drivers/pwm/pwm-tegra.c line 136
Quoted 8 lines
drivers/pwm/pwm-tegra.c +8
-0+ 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);
It seems a little of for the driver to define a pwm_writel() function but only use it in some places but not others. I guess it's because in some places the code knows the clock is on, so doesn't need the clk_enable()/disable() helper in pwm_writel(), but I'd tend towards always using pwm_readl()/pwm_writel() throughout the driver, and lifting the clock management out of those low-level functions myself.
Quoted 5 lines
drivers/pwm/pwm-tegra.c +5
-0+static int __devexit tegra_pwm_remove(struct platform_device *pdev) +{ +struct tegra_pwm_chip *pwm =platform_get_drvdata (pdev); +int i; +
drivers/pwm/pwm-tegra.c line 237
Quoted 10 lines
drivers/pwm/pwm-tegra.c +10
-0+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);
Should the core call the disable() op before the remove() op so drivers don't need to check this? I'm a little in two minds about this; if this decision is deferred to drivers (as the code above assumes), then I suppose the whole remove() path might be marginally more efficient.
PATCH v4 7/10 pwm: tegra: Add device tree support
In reply to Thierry RedingAdd auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
---
Changes in v4:
- add DT binding documentation
- allow nvidia,tegra20-pwm as fallback for nvidia,tegra30-pwm
- export OF device table (for module auto-loading)
Changes in v3:
- add missing include for mach/iomap.h
.../devicetree/bindings/pwm/tegra-pwm.txt | 18 ++++++++++++++++++ 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 +++ drivers/pwm/pwm-tegra.c | 11 +++++++++++ 6 files changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/tegra-pwm.txt
Documentation/devicetree/bindings/pwm/tegra-pwm.txt new file +18 -0
@@ -0,0 +1,18 @@ +Tegra SoC PWFM controller + +Required properties: +- compatible: should be one of: + - "nvidia,tegra20-pwm" + - "nvidia,tegra30-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The + first cell specifies the per-chip index of the PWM to use and the second + cell is the duty cycle in nanoseconds. + +Example: + + pwm: pwm at 7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + };
arch/arm/boot/dts/tegra20.dtsi +6 -0
@@ -154,6 +154,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>;
arch/arm/boot/dts/tegra30.dtsi +6 -0
@@ -154,6 +154,12 @@ interrupts = < 0 91 0x04 >; }; + pwm: pwm at 7000a000 { + compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; + sdhci at 78000000 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000000 0x200>;
arch/arm/mach-tegra/board-dt-tegra20.c +1 -0
@@ -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), {} };
arch/arm/mach-tegra/board-dt-tegra30.c +3 -0
@@ -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,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), {} };
drivers/pwm/pwm-tegra.c +11 -0
@@ -242,9 +242,20 @@ static int __devexit tegra_pwm_remove(struct platform_device *pdev)return 0 ; } +#ifdef CONFIG_OF +static struct of_device_id tegra_pwm_of_match[] = { + { .compatible ="nvidia,tegra20-pwm" }, + { .compatible ="nvidia,tegra30-pwm" }, + { } +}; + +MODULE_DEVICE_TABLE (of, tegra_pwm_of_match); +#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),
Signature · 1 line
1.7.9.4
PATCH v4 7/10 pwm: tegra: Add device tree support
Quoted 7 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Signed-off-by Thierry Reding <[email protected]>+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txt
Can this please be named nvidia,tegra20-pwm.txt so that if we need different bindings for any future Tegra PWM, we won't have any filename conflicts?
Aside from that,
PATCH v4 7/10 pwm: tegra: Add device tree support
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Quoted 7 lines
Quoted 3 lines
Signed-off-by Thierry Reding <[email protected]>+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txtCan this please be named nvidia,tegra20-pwm.txt so that if we need different bindings for any future Tegra PWM, we won't have any filename conflicts?
That file already documents the bindings for Tegra 20 and Tegra 30, that's why I chose the move generic name. Could this perhaps be documented within the file instead? Or should I rather add a nvidia,tegra30-pwm.txt with a reference to the nvidia,tegra20-pwm.txt?
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/20120320/5482017f/attachment.sig>
PATCH v4 7/10 pwm: tegra: Add device tree support
Quoted 14 lines · Thierry Reding
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Quoted 7 lines
Quoted 3 lines
Signed-off-by Thierry Reding <[email protected]>+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txtCan this please be named nvidia,tegra20-pwm.txt so that if we need different bindings for any future Tegra PWM, we won't have any filename conflicts?
Quoted 4 lines
That file already documents the bindings for Tegra 20 and Tegra 30, that's why I chose the move generic name. Could this perhaps be documented within the file instead? Or should I rather add a nvidia,tegra30-pwm.txt with a reference to the nvidia,tegra20-pwm.txt?
I think it's fine for a file of name nvidia,tegra20-pwm.txt to document both Tegra20 and Tegra30; the file is named after the first/earliest compatible value it documents. The issue is more that /if/ say TegraNN needs a different binding, I want the naming consistent (e.g. nvidia,tegraNN-pwm.txt) rather than having the old file with one style and the new file named using a different style.
PATCH v4 7/10 pwm: tegra: Add device tree support
Quoted 20 lines · Stephen Warren
Quoted 14 lines · Thierry Reding
Quoted 5 lines · Stephen Warren
Quoted 4 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Quoted 7 lines
Quoted 3 lines
Signed-off-by Thierry Reding <[email protected]>+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txtCan this please be named nvidia,tegra20-pwm.txt so that if we need different bindings for any future Tegra PWM, we won't have any filename conflicts?
Quoted 4 lines
That file already documents the bindings for Tegra 20 and Tegra 30, that's why I chose the move generic name. Could this perhaps be documented within the file instead? Or should I rather add a nvidia,tegra30-pwm.txt with a reference to the nvidia,tegra20-pwm.txt?
Quoted 6 lines
I think it's fine for a file of name nvidia,tegra20-pwm.txt to document both Tegra20 and Tegra30; the file is named after the first/earliest compatible value it documents. The issue is more that /if/ say TegraNN needs a different binding, I want the naming consistent (e.g. nvidia,tegraNN-pwm.txt) rather than having the old file with one style and the new file named using a different style.
Understood. I'll rename it for 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/20120320/acc4ba5e/attachment.sig>
PATCH v4 7/10 pwm: tegra: Add device tree support
In reply to Stephen WarrenQuoted 10 lines · Stephen Warren
Quoted 7 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Signed-off-by Thierry Reding <[email protected]>+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txtCan this please be named nvidia,tegra20-pwm.txt so that if we need
Is it necessary to have even the vendor prefix in the file name? The file will look exceptional among all these binding documents under Documentation/devicetree/bindings.
Quoted 2 lines
different bindings for any future Tegra PWM, we won't have any filename conflicts?
Signature · 2 lines
Regards, Shawn
PATCH v4 7/10 pwm: tegra: Add device tree support
Quoted 8 lines · Shawn Guo
Quoted 7 lines · Stephen Warren
Quoted 5 lines · Thierry Reding
Add auxdata to instantiate the PWFM controller from a device tree, include the corresponding nodes in the dtsi files for Tegra 20 and Tegra 30 and add binding documentation.
Signed-off-by Thierry Reding <[email protected]>
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
+++
b/Documentation/devicetree/bindings/pwm/tegra-pwm.txtCan this please be named nvidia,tegra20-pwm.txt so that if we need
Is it necessary to have even the vendor prefix in the file name? The file will look exceptional among all these binding documents under
Documentation/devicetree/bindings.
It would look exceptional now, but I've had it in the back of my mind to suggest renaming all the binding docs in line with their full compatible value. Then, it'd just look consistent ;-P.
PATCH v4 8/10 pwm: Add Blackfin support
In reply to Thierry Reding---
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
arch/blackfin/Kconfig +0 -10
@@ -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
arch/blackfin/kernel/Makefile +0 -1
@@ -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
arch/blackfin/kernel/pwm.c deleted +0 -100
100 lines not on this page · raw message
drivers/pwm/Kconfig +9 -0
@@ -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
drivers/pwm/Makefile +1 -0
@@ -1,2 +1,3 @@ obj-$(CONFIG_PWM) += core.o +obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
drivers/pwm/pwm-bfin.c new file +164 -0
164 lines not on this page · raw message
Signature · 1 line
1.7.9.4
PATCH v4 9/10 pwm: Add PXA support
In reply to Thierry Reding---
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
arch/arm/plat-pxa/Makefile +0 -1
@@ -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
arch/arm/plat-pxa/pwm.c deleted +0 -304
304 lines not on this page · raw message
drivers/pwm/Kconfig +9 -0
@@ -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
drivers/pwm/Makefile +1 -0
@@ -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
drivers/pwm/pwm-pxa.c new file +244 -0
244 lines not on this page · raw message
Signature · 1 line
1.7.9.4
PATCH v4 9/10 pwm: Add PXA support
Quoted 4 lines · Thierry Reding
Signed-off-by Thierry Reding <[email protected]>---
Changes in v3:
- update PWM ops for changes in patch 2
Couple of quick notes, mostly for future work.
drivers/pwm/pwm-pxa.c line 98
Quoted 4 lines
drivers/pwm/pwm-pxa.c new file +4
-0+/* NOTE: the clock to PWM has to be enabled first +* before writing to the registers +*/ +clk_enable (pc->clk);
Should be fixed to also call clk_prepare (and clk_unprepare after clk_disable). Could be done in a follow up patch.
drivers/pwm/pwm-pxa.c line 101
Quoted 3 lines
drivers/pwm/pwm-pxa.c new file +3
-0+__raw_writel (prescale, pc->mmio_base + offset +PWMCR ); +__raw_writel (dc, pc->mmio_base + offset +PWMDCR ); +__raw_writel (pv, pc->mmio_base + offset +PWMPCR );
Should we fix this driver to use readl/writel instead of the __raw variants? The memory is properly ioremaped, and to my understanding the __raw memory accessors should be avoided outside of core code. This could be done in a follow up patch if you want to keep this patch as mostly just a move of the code.
~Ryan
PATCH v4 9/10 pwm: Add PXA support
Quoted 18 lines · Ryan Mallon
Quoted 4 lines · Thierry Reding
Signed-off-by Thierry Reding <[email protected]>---
Changes in v3:
- update PWM ops for changes in patch 2Couple of quick notes, mostly for future work.
drivers/pwm/pwm-pxa.c line 98
Quoted 4 lines
drivers/pwm/pwm-pxa.c new file +4
-0+/* NOTE: the clock to PWM has to be enabled first +* before writing to the registers +*/ +clk_enable (pc->clk);Should be fixed to also call
clk_prepare(andclk_unprepareafterclk_disable). Could be done in a follow up patch.
Quoted 10 lines
drivers/pwm/pwm-pxa.c line 101
Quoted 3 lines
drivers/pwm/pwm-pxa.c new file +3
-0+__raw_writel (prescale, pc->mmio_base + offset +PWMCR ); +__raw_writel (dc, pc->mmio_base + offset +PWMDCR ); +__raw_writel (pv, pc->mmio_base + offset +PWMPCR );Should we fix this driver to use readl/writel instead of the
__rawvariants? The memory is properly ioremaped, and to my understanding the__rawmemory accessors should be avoided outside of core code. This could be done in a follow up patch if you want to keep this patch as mostly just a move of the code.
Actually I wasn't planning on keeping this patch at all. Sascha already has the existing PWM providers converted to his original framework and offered to rebase them onto this series once the dust settles. I only used them as testbed to see how the driver interface works out for different hardware. But I also think that if Sascha hasn't cleaned the driver up yet it should either be done in his conversion patches or as follow ups.
Sascha: how do you plan on going forward with this? It seems like the driver interface is pretty much done now and I expect the next round to be the last, unless I forget to properly work through the TODO list again. If you are busy with other stuff I can probably find some time to help with porting your converted drivers.
I'm also wondering which tree this will go in through. Does it make sense to have an extra tree just for the PWM framework or can it go in via some other general purpose tree? Who do I need to prod?
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/20120315/b37c86ec/attachment.sig>
PATCH v4 9/10 pwm: Add PXA support
Quoted 30 lines · Thierry Reding
Quoted 18 lines · Ryan Mallon
Quoted 4 lines · Thierry Reding
Signed-off-by Thierry Reding <[email protected]>---
Changes in v3:
- update PWM ops for changes in patch 2Couple of quick notes, mostly for future work.
drivers/pwm/pwm-pxa.c line 98
Quoted 4 lines
drivers/pwm/pwm-pxa.c new file +4
-0+/* NOTE: the clock to PWM has to be enabled first +* before writing to the registers +*/ +clk_enable (pc->clk);Should be fixed to also call
clk_prepare(andclk_unprepareafterclk_disable). Could be done in a follow up patch.Quoted 10 lines
drivers/pwm/pwm-pxa.c line 101
Quoted 3 lines
drivers/pwm/pwm-pxa.c new file +3
-0+__raw_writel (prescale, pc->mmio_base + offset +PWMCR ); +__raw_writel (dc, pc->mmio_base + offset +PWMDCR ); +__raw_writel (pv, pc->mmio_base + offset +PWMPCR );Should we fix this driver to use readl/writel instead of the
__rawvariants? The memory is properly ioremaped, and to my understanding the__rawmemory accessors should be avoided outside of core code. This could be done in a follow up patch if you want to keep this patch as mostly just a move of the code.
Quoted 6 lines
Actually I wasn't planning on keeping this patch at all. Sascha already has the existing PWM providers converted to his original framework and offered to rebase them onto this series once the dust settles. I only used them as testbed to see how the driver interface works out for different hardware. But I also think that if Sascha hasn't cleaned the driver up yet it should either be done in his conversion patches or as follow ups.
All I have is a simple conversion to the new framework, nothing more. I rebased my patches yesterday onto this series (unfortunately due to the additional argument pwm_device the patches do not look like just moving the drivers anymore). I also skipped the PXA patch since I saw that you already have this one. I just posted the patches to the list.
Quoted 6 lines
Sascha: how do you plan on going forward with this? It seems like the driver interface is pretty much done now and I expect the next round to be the last, unless I forget to properly work through the TODO list again. If you are busy with other stuff I can probably find some time to help with porting your converted drivers.
I haven't done drivers/mfd/twl6030-pwm.c. This one needs a bit more work as it currently does not register itself as a subdriver to the twl6030 but just uses a globally available twl_i2c_write_u8() function. So if you have some time to spare it would be great if you could do this.
Quoted 4 lines
I'm also wondering which tree this will go in through. Does it make sense to have an extra tree just for the PWM framework or can it go in via some other general purpose tree? Who do I need to prod?
Good question, I don't know.
Sascha
Signature · 4 lines
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 |
PATCH v4 9/10 pwm: Add PXA support
Quoted 8 lines · Sascha Hauer
Quoted 6 lines · Thierry Reding
Actually I wasn't planning on keeping this patch at all. Sascha already has the existing PWM providers converted to his original framework and offered to rebase them onto this series once the dust settles. I only used them as testbed to see how the driver interface works out for different hardware. But I also think that if Sascha hasn't cleaned the driver up yet it should either be done in his conversion patches or as follow ups.
Quoted 5 lines
All I have is a simple conversion to the new framework, nothing more. I rebased my patches yesterday onto this series (unfortunately due to the additional argument
pwm_devicethe patches do not look like just moving the drivers anymore). I also skipped the PXA patch since I saw that you already have this one. I just posted the patches to the list.
Okay, I'll keep my Blackfin and PXA converted drivers then and will fix the issues with the PXA driver brought up by Ryan. Would you be okay if I took your conversion patches and added them to my series? I was trying to avoid the additional work but I think it might make things easier if they are part of the same series.
Quoted 10 lines
Quoted 5 lines
Sascha: how do you plan on going forward with this? It seems like the driver interface is pretty much done now and I expect the next round to be the last, unless I forget to properly work through the TODO list again. If you are busy with other stuff I can probably find some time to help with porting your converted drivers.
I haven't done
drivers/mfd/twl6030-pwm.c. This one needs a bit more work as it currently does not register itself as a subdriver to the twl6030 but just uses a globally availabletwl_i2c_write_u8()function. So if you have some time to spare it would be great if you could do this.
Okay, I'll have a look. I guess the next round won't be the last after all. :-)
Quoted 5 lines
Quoted 3 lines
I'm also wondering which tree this will go in through. Does it make sense to have an extra tree just for the PWM framework or can it go in via some other general purpose tree? Who do I need to prod?
Good question, I don't know.
Okay, maybe Arnd can comment on it.
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/20120315/d0cf8fb3/attachment.sig>
PATCH v4 9/10 pwm: Add PXA support
Quoted 15 lines · Thierry Reding
Quoted 8 lines · Sascha Hauer
Quoted 6 lines · Thierry Reding
Actually I wasn't planning on keeping this patch at all. Sascha already has the existing PWM providers converted to his original framework and offered to rebase them onto this series once the dust settles. I only used them as testbed to see how the driver interface works out for different hardware. But I also think that if Sascha hasn't cleaned the driver up yet it should either be done in his conversion patches or as follow ups.
Quoted 5 lines
All I have is a simple conversion to the new framework, nothing more. I rebased my patches yesterday onto this series (unfortunately due to the additional argument
pwm_devicethe patches do not look like just moving the drivers anymore). I also skipped the PXA patch since I saw that you already have this one. I just posted the patches to the list.
Quoted 3 lines
Okay, I'll keep my Blackfin and PXA converted drivers then and will fix the issues with the PXA driver brought up by Ryan. Would you be okay if I took your conversion patches and added them to my series?
Sure, go ahead.
Sascha
Signature · 4 lines
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 |
PATCH v4 9/10 pwm: Add PXA support
In reply to Thierry RedingQuoted 5 lines · Thierry Reding
Signed-off-by Thierry Reding <[email protected]>---
Changes in v3:
- update PWM ops for changes in patch 2
Quoted 9 lines
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
The patch should be generated with "git format-patch -M", so that we can see the diff like below.
--- a/arch/arm/plat-pxa/pwm.c
+++ b/drivers/pwm/pwm-pxa.c
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +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 (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+ if (period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
Then I will have a question why "pwm == NULL" check is removed?
Regards,
Shawn
PATCH v4 9/10 pwm: Add PXA support
drivers/pwm/pwm-pxa.c
Quoted 20 lines · Shawn Guo
Quoted 5 lines · Thierry Reding
Signed-off-by Thierry Reding <[email protected]>---
Changes in v3:
- update PWM ops for changes in patch 2Quoted 9 lines
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.cThe patch should be generated with "git format-patch -M", so that we can see the diff like below.
drivers/pwm/pwm-pxa.c renamed from arch/arm/plat-pxa/pwm.c +0
-0
Yes, Arnd already mentioned that in the last round but I forgot. It usually takes me a couple of weeks to prepare the next version and I try to keep a list of TODOs but that doesn't seem to be efficient enough yet.
Quoted 13 lines
drivers/pwm/pwm-pxa.c renamed from arch/arm/plat-pxa/pwm.c +5
-2-int pwm_config (struct pwm_device *pwm,int duty_ns,int period_ns) +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 (pwm ==NULL || period_ns ==0 || duty_ns > period_ns) +if (period_ns ==0 || duty_ns > period_ns)return -EINVAL ;
Quoted 1 line
Then I will have a question why "pwm == NULL" check is removed?
Actually, as I mentioned in another mail the idea was to put these kinds of checks into the core. They are still missing from the core, 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/20120316/208f5b30/attachment-0001.sig>
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
In reply to Thierry RedingThis 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.
---
Changes in v4:
- store a PWM requested with of_pwm_request() in the platform data
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 fixed-regulator support for backlight enable/disable
.../bindings/video/backlight/pwm-backlight | 19 +++ drivers/video/backlight/Kconfig | 2 +- drivers/video/backlight/pwm_bl.c | 136 +++++++++++++++++--- include/linux/pwm_backlight.h | 2 + 4 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 Documentation/devicetree/bindings/video/backlight/pwm-backlight
Documentation/devicetree/bindings/video/backlight/pwm-backlight new file +19 -0
@@ -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>; + };
drivers/video/backlight/Kconfig +1 -1
@@ -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.
drivers/video/backlight/pwm_bl.c +119 -17
206 lines not on this page · raw message
include/linux/pwm_backlight.h +2 -0
@@ -7,11 +7,13 @@#include <linux/backlight.h> struct platform_pwm_backlight_data { +struct pwm_device *pwm;int pwm_id;unsigned int max_brightness;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);
Signature · 1 line
1.7.9.4
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
drivers/video/backlight/pwm_bl.c static const struct backlight_ops pwm_backlight_ops = { · line 108
Quoted 4 lines · Thierry Reding
drivers/video/backlight/pwm_bl.c +4
-0+ + pwm =of_pwm_request (node,"pwm" ,0 ); +if (IS_ERR (pwm)) +return PTR_ERR (pwm);
It's interesting that the (so far) only user of of_pwm_request() doesn't actually give a meaningful argument as the name of the pwm property.
Maybe rename that function to of_pwm_request_named() and provide a helper that just does this:?
static inline struct pwm_device *of_pwm_request(struct device_node *np, int index)
{
return of_pwm_request_named(np, "pwm", index);
}Any device that just has needs one pwm or uses more than one but has no reason to name them can just use this helper then and use the default pwm property name.
Arnd
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
In reply to Thierry RedingQuoted 9 lines · Thierry Reding
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.+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
Documentation/devicetree/bindings/video/backlight/pwm-backlight line 7
Quoted 7 lines
Documentation/devicetree/bindings/video/backlight/pwm-backlight new file +7
-0+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
I assume the values in this array are 0 (darkest/off) to 255 (max brightness)? The doc should probably specify this.
Quoted 1 line
+ - default-brightness-level: the default brightness level
Likewise, this is an index into the default-brightness-level? Again, it'd be best to explicitly state this.
...
Quoted 6 lines
drivers/video/backlight/pwm_bl.c +4
-0+ brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; +static int pwm_backlight_parse_dt (struct device *dev, +struct platform_pwm_backlight_data *data)
...
drivers/video/backlight/pwm_bl.c static const struct backlight_ops pwm_backlight_ops = { · line 138
Quoted 4 lines
drivers/video/backlight/pwm_bl.c +4
-0+ ret =of_property_read_u32 (node,"default-brightness-level" , + &value); +if (ret <0 ) + goto free;
Range-check that against max_brightness?
Quoted 1 line
static int
pwm_backlight_probe(struct platform_device *pdev)
...
Quoted 6 lines
drivers/video/backlight/pwm_bl.c +0
-6- pb->pwm =pwm_request (data->pwm_id,"backlight" ); -if (IS_ERR (pb->pwm)) { -dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); - ret =PTR_ERR (pb->pwm); - goto err_alloc; - }else
drivers/video/backlight/pwm_bl.c static int pwm_backlight_probe(struct platform_device *pdev) · line 228
Quoted 10 lines
drivers/video/backlight/pwm_bl.c +9
-1-dev_dbg (&pdev->dev,"got pwm for backlight\n" ); +if (!pb->pwm) { + pb->pwm =pwm_request (data->pwm_id,"backlight" ); +if (IS_ERR (pb->pwm)) { +dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); + ret =PTR_ERR (pb->pwm); + goto err_alloc; + }else +dev_dbg (&pdev->dev,"got pwm for backlight\n" ); + }
Hmmm. It'd be more consistent if pwm_backlight_parse_dt() called something like of_pwm_get() instead of of_pwm_request(), so that this code could always call pwm_request() on the PWM and hence operate the same irrespective of DT vs non-DT. GPIOs work that way at least.
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
Quoted 10 lines · Stephen Warren
Quoted 8 lines · Thierry Reding
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.+++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight
Quoted 10 lines
Documentation/devicetree/bindings/video/backlight/pwm-backlight line 7
Quoted 7 lines
Documentation/devicetree/bindings/video/backlight/pwm-backlight new file +7
-0+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 levelsI assume the values in this array are 0 (darkest/off) to 255 (max brightness)? The doc should probably specify this.
Typically yes. Although I haven't tested this it should work for pretty much any range starting from 0 because the last value will be used to interpolate ("scale") the PWM duty cycle. So it really is 0 (darkest/off) to <last item> (max brightness). I should document this, of course.
Quoted 4 lines
Quoted 1 line
+ - default-brightness-level: the default brightness level
Likewise, this is an index into the default-brightness-level? Again, it'd be best to explicitly state this.
Yes. Correct.
Quoted 8 lines
...
Quoted 6 lines
drivers/video/backlight/pwm_bl.c +4
-0+ brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; +static int pwm_backlight_parse_dt (struct device *dev, +struct platform_pwm_backlight_data *data)...
Quoted 6 lines
drivers/video/backlight/pwm_bl.c static const struct backlight_ops pwm_backlight_ops = { · line 138
Quoted 4 lines
drivers/video/backlight/pwm_bl.c +4
-0+ ret =of_property_read_u32 (node,"default-brightness-level" , + &value); +if (ret <0 ) + goto free;Range-check that against
max_brightness?
Yes, that would be good. I guess logging a warning and falling back to max_brightness would be the proper action?
Quoted 15 lines
Quoted 1 line
static int
pwm_backlight_probe(struct platform_device *pdev)...
Quoted 13 lines
drivers/video/backlight/pwm_bl.c +6
-7- pb->pwm =pwm_request (data->pwm_id,"backlight" ); -if (IS_ERR (pb->pwm)) { -dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); - ret =PTR_ERR (pb->pwm); - goto err_alloc; - }else -dev_dbg (&pdev->dev,"got pwm for backlight\n" ); +if (!pb->pwm) { + pb->pwm =pwm_request (data->pwm_id,"backlight" ); +if (IS_ERR (pb->pwm)) { +dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); + ret =PTR_ERR (pb->pwm); + goto err_alloc;
Quoted 8 lines
drivers/video/backlight/pwm_bl.c static int pwm_backlight_probe(struct platform_device *pdev) · line 228
Quoted 3 lines
drivers/video/backlight/pwm_bl.c +3
-0+ }else +dev_dbg (&pdev->dev,"got pwm for backlight\n" ); + }Hmmm. It'd be more consistent if
pwm_backlight_parse_dt()called something likeof_pwm_get()instead ofof_pwm_request(), so that this code could always callpwm_request()on the PWM and hence operate the same irrespective of DT vs non-DT. GPIOs work that way at least.
That's actually what the initial patch had. Unfortunately that's pretty much the opposite direction of where the PWM framework is headed because it would involve getting a global index to request the PWM. I think in the long run it would be much better to get rid of pwm_request() altogether and unify by having the non-DT case request the PWM device on a per-chip basis.
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/20120320/89ee5a2d/attachment.sig>
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Stephen Warren
Quoted 6 lines · Thierry Reding
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.
...
Quoted 24 lines
Quoted 15 lines
Quoted 1 line
static int
pwm_backlight_probe(struct platform_device *pdev)...
Quoted 13 lines
drivers/video/backlight/pwm_bl.c +6
-7- pb->pwm =pwm_request (data->pwm_id,"backlight" ); -if (IS_ERR (pb->pwm)) { -dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); - ret =PTR_ERR (pb->pwm); - goto err_alloc; - }else -dev_dbg (&pdev->dev,"got pwm for backlight\n" ); +if (!pb->pwm) { + pb->pwm =pwm_request (data->pwm_id,"backlight" ); +if (IS_ERR (pb->pwm)) { +dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); + ret =PTR_ERR (pb->pwm); + goto err_alloc;Quoted 8 lines
drivers/video/backlight/pwm_bl.c static int pwm_backlight_probe(struct platform_device *pdev) · line 228
Quoted 3 lines
drivers/video/backlight/pwm_bl.c +3
-0+ }else +dev_dbg (&pdev->dev,"got pwm for backlight\n" ); + }Hmmm. It'd be more consistent if
pwm_backlight_parse_dt()called something likeof_pwm_get()instead ofof_pwm_request(), so that this code could always callpwm_request()on the PWM and hence operate the same irrespective of DT vs non-DT. GPIOs work that way at least.
Quoted 3 lines
That's actually what the initial patch had. Unfortunately that's pretty much the opposite direction of where the PWM framework is headed because it would involve getting a global index to request the PWM.
Not necessarily; get() could return a controller+index pair, which could then be passed to request().
Quoted 3 lines
I think in the long run it
would be much better to get rid ofpwm_request()altogether and unify by having the non-DT case request the PWM device on a per-chip basis.
That might also work.
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
Quoted 34 lines · Stephen Warren
Quoted 8 lines · Thierry Reding
Quoted 7 lines · Stephen Warren
Quoted 6 lines · Thierry Reding
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....
Quoted 24 lines
Quoted 23 lines
Quoted 1 line
static int
pwm_backlight_probe(struct platform_device *pdev)...
Quoted 6 lines
drivers/video/backlight/pwm_bl.c +0
-6- pb->pwm =pwm_request (data->pwm_id,"backlight" ); -if (IS_ERR (pb->pwm)) { -dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); - ret =PTR_ERR (pb->pwm); - goto err_alloc; - }else drivers/video/backlight/pwm_bl.c static int pwm_backlight_probe(struct platform_device *pdev) · line 228
Quoted 10 lines
drivers/video/backlight/pwm_bl.c +9
-1-dev_dbg (&pdev->dev,"got pwm for backlight\n" ); +if (!pb->pwm) { + pb->pwm =pwm_request (data->pwm_id,"backlight" ); +if (IS_ERR (pb->pwm)) { +dev_err (&pdev->dev,"unable to request PWM for backlight\n" ); + ret =PTR_ERR (pb->pwm); + goto err_alloc; + }else +dev_dbg (&pdev->dev,"got pwm for backlight\n" ); + }Hmmm. It'd be more consistent if
pwm_backlight_parse_dt()called something likeof_pwm_get()instead ofof_pwm_request(), so that this code could always callpwm_request()on the PWM and hence operate the same irrespective of DT vs non-DT. GPIOs work that way at least.
Quoted 6 lines
Quoted 3 lines
That's actually what the initial patch had. Unfortunately that's pretty much the opposite direction of where the PWM framework is headed because it would involve getting a global index to request the PWM.
Not necessarily;
get()could return a controller+index pair, which could then be passed torequest().
This is pretty much what of_pwm_request() does internally (actually via the of_xlate() function), and it goes one step further by requesting the corresponding PWM.
I don't really like the fact that the DT parsing code needs to store a requested PWM device in the platform data. The only other solution would be, as you suggest, to obtain two indices and request based on them. However that comes with a whole lot of problems of its own (race between getting the controller index and the actual requesting of the PWM device, ...).
One other alternative could be to not pass the PWM device via platform data but rather return it from the pwm_backlight_parse_dt() function (either via the return value or an output parameter).
Quoted 5 lines
Quoted 3 lines
I think in the long run it
would be much better to get rid ofpwm_request()altogether and unify by having the non-DT case request the PWM device on a per-chip basis.That might also work.
What I'm not sure about is how to represent this in the non-DT case. The problem would be how to identify the individual PWM chips. From a quick glance, pinctrl seems to do this purely on a name lookup basis, similar to the clock framework.
What would be a good way to represent this in platform data?
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/20120320/3c131345/attachment.sig>
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
Quoted 2 lines · Thierry Reding
Quoted 1 line · Stephen Warren
On 03/20/2012 02:39 AM, Thierry Reding wrote:
...
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
I think in the long run it
would be much better to get rid ofpwm_request()altogether and unify by having the non-DT case request the PWM device on a per-chip basis.
Quoted 8 lines
Quoted 1 line
That might also work.
What I'm not sure about is how to represent this in the non-DT case. The problem would be how to identify the individual PWM chips. From a quick glance, pinctrl seems to do this purely on a name lookup basis, similar to the clock framework.
What would be a good way to represent this in platform data?
I think most get subsystems have a get API that works for both DT and non-DT, rather than using platform data:
# works in DT right now IIRC: regulator_get(dev, supply_name)
# patches posted to make this work in DT. Near checkin: p = pinctrl_get(dev); s = pinctrl_lookup_state(p, state_name)
# patches posted to make this work in DT. I'm not sure how # near they are to check-in. clk_get(dev, clk_name)
That way, there could be a pwm_get(dev, name) for both non-DT (use some table registered by board files) and DT (use the OF lookup code you've written).
Admittedly, GPIOs don't work quite this way. Interrupts kinda do via the platform resources.
For board files, this would rely on some table which mapped from the get parameters to the returned object. IIRC, most of these tables are indexed by (dev_name(dev), name) and probably return the dev_name() of the providing device (or whatever internally makes sense to identify the device) plus some subsystem-specific data (e.g. PWM index).
PATCH v4 10/10 pwm-backlight: Add rudimentary device tree support
Quoted 6 lines · Stephen Warren
Quoted 1 line · Thierry Reding
What would be a good way to represent this in platform data?
I think most get subsystems have a get API that works for both DT and non-DT, rather than using platform data:
Yes, please - having to have explict handling in drivers to select a mechanism to look up stuff in the subsystem would be very sad.
Quoted 2 lines
# works in DT right now IIRC: regulator_get(dev, supply_name)
Yes, that's totally transparent to the device.
Quoted 5 lines
For board files, this would rely on some table which mapped from the get parameters to the returned object. IIRC, most of these tables are indexed by (
dev_name(dev), name) and probably return thedev_name()of the providing device (or whatever internally makes sense to identify the device) plus some subsystem-specific data (e.g. PWM index).
That's how regulator and clk do it (I think pinctrl too, and IIO also
does this though it's in staging) - the consumer works with the struct
device and the name of the thing it's requesting and the things doing
the mapping (boards, SoCs, whatever) map this onto the actual device
with a lookup table which works in terms of dev_name() for the
requesting device. We use dev_name() because many buses don't make a
struct device available until very late in system startup.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120320/ed4944f1/attachment.sig>
v4 cover Add PWM framework and device tree support.
In reply to Thierry RedingQuoted 6 lines · Thierry Reding
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.
Hello Thierry,
Are you planning on adding a sysfs interface for generic userspace access to the PWM devices?
I have tested your patches (with a couple fixes already mentioned) on a ep93xx board and have converted the drivers/misc/ep93xx_pwm.c driver to use the framework. Everything "seems" to work but my use for the PWM is from userspace so I can't really test anything.
I have hacked in the sysfs interface from the ep93xx_pwm driver but it is a hack... It's not really using the framework to control the PWM since all the sysfs knobs are directly accessing the pwm registers.
Anyway, I would be happy to convert the current driver to the new framework and get it out of drivers/misc and into a proper location. But, before I can do that, I need to be able to control the PWM from userspace somehow.
Maybe an interface similar to the one gpiolib provides with CONFIG_GPIO_SYSFS?
Regards,
Hartley
v4 cover Add PWM framework and device tree support.
Quoted 2 lines · H Hartley Sweeten
Are you planning on adding a sysfs interface for generic userspace access to the PWM devices?
I wasn't planning to, but really only because I have no need for it. You could of course add one yourself.
Quoted 3 lines
Anyway, I would be happy to convert the current driver to the new framework and get it out of
drivers/miscand into a proper location. But, before I can do that, I need to be able to control the PWM from userspace somehow.
You should probably coordinate with Sascha Hauer who I think already has most (if not all) of the PWM drivers converted to his first version of the framework and said he was going to rebase them on top of this series.
Quoted 1 line
Maybe an interface similar to the one gpiolib provides with
CONFIG_GPIO_SYSFS?
I think the most challenging part will be figuring out how to export PWM devices via sysfs on a per-chip basis. Since the goal of the series is to eventually get rid of the global namespace, using an export file like gpiolib won't work in the long run. Perhaps something like the following would:
/sys/class/pwm/ pwmchipX/ export unexport pwmY/ label duty period
That way you get a reference to the device associated with a PWM chip and you can use the new pwm_request_from_device() function to request and export the PWM device.
Again, I have no direct use for this and you probably know the requirements better than me so it's probably better if you add the interface. I'm happy to review patches, 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/20120315/289252b2/attachment.sig>