summaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk.c
AgeCommit message (Collapse)Author
2013-01-24clk: add common of_clk_init() functionPrashant Gaikwad
Modify of_clk_init function so that it will determine which driver to initialize based on device tree instead of each driver registering to it. Based on a similar patch for drivers/irqchip by Thomas Petazzoni and drivers/clocksource by Stephen Warren. Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com> Tested-by: Tony Prisk <linux@prisktech.co.nz> Tested-by: Pawel Moll <pawel.moll@arm.com> Tested-by: Rob Herring <rob.herring@calxeda.com> Tested-by: Josh Cartwright <josh.cartwright@ni.com> Reviewed-by: Josh Cartwright <josh.cartwright@ni.com> Acked-by: Maxime Ripard <maxime.ripard@anandra.org> Signed-off-by: Mike Turquette <mturquette@linaro.org> [mturquette@linaro.org: merge conflict from missing CLKSRC_OF_TABLES()] Signed-off-by: Mike Turquette <mturquette@linaro.org>
2013-01-21clk: Deduplicate exit code in clk_set_rateNestor Ovroy
On non-out case 'return ret;' is equivalent to 'return 0;' as the ret variable is initialized at 0 and never changed. Signed-off-by: Nestor Ovroy <novroy@riseup.net>
2013-01-11clk: JSON debugfs clock tree summaryPrashant Gaikwad
Clock information is dumped in JSON format which is easy for machines to parse. Each clock is represented as an object which has same name as clock and following properties - enable_count - prepare_count - rate Output is verified using online JSON editor. Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2013-01-11clk: human-readable debugfs clock tree summaryPrashant Gaikwad
Adds debug file "clk_summary" in /sys/kernel/debug/clk dir. It helps to view all the clock registered in human-readable format. For example: clock enable_cnt prepare_cnt rate --------------------------------------------------------------------- i2s0_sync 0 0 24000000 spdif_in_sync 0 0 24000000 spdif_mux 0 0 24000000 spdif 0 0 24000000 spdif_doubler 0 0 48000000 spdif_div 0 0 48000000 spdif_2x 0 0 48000000 clk_32k 2 2 32768 blink_override 1 1 32768 blink 1 1 32768 clk_m 2 2 12000000 clk_out_3_mux 0 0 12000000 clk_out_3 0 0 12000000 pll_ref 3 3 12000000 pll_e_mux 0 0 12000000 pll_e 0 0 100000000 cml0 0 0 100000000 cml1 0 0 100000000 pciex 0 0 100000000 pll_d2 0 0 1000000 pll_d2_out0 0 0 500000 pll_d 0 0 1000000 pll_d_out0 0 0 500000 dsib_mux 0 0 500000 dsib 0 0 500000 dsia 0 0 500000 Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2013-01-11clk: export __clk_get_name for re-use in imx-ipu-v3 and othersNiels de Vos
This fixes the following error when building for arm-imx: > ERROR: "__clk_get_name" [drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.ko] undefined! > make[1]: *** [__modpost] Error 1 > make: *** [modules] Error 2 There are valid usecases to get the name of a clock, be it for debugging purposes or to register a children of a clock like done in this IPU driver. Therefore exporting __clk_get_name() and make it available for others makes sense. Reported-by: Peter Robinson <pbrobinson@gmail.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Mike Turquette <mturquette@linaro.org> Signed-off-by: Niels de Vos <ndevos@redhat.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> [mturquette@linaro.org: removal of inline made redundant by 65800b2]
2013-01-11clk: Don't mark shared helper functions as inlineRuss Dill
The helper functions that access the opaque struct clk should not be marked inline since they are contained in clk.c, but expected to be used by other compilation units. This causes compile errors under gcc-4.7 In file included from arch/arm/mach-omap2/clockdomain.c:25:0: arch/arm/mach-omap2/clockdomain.c: In function ‘clkdm_clk_disable’: include/linux/clk-provider.h:338:12: error: inlining failed in call to always_inline ‘__clk_get_enable_count’: function body not available arch/arm/mach-omap2/clockdomain.c:1001:28: error: called from here make[1]: *** [arch/arm/mach-omap2/clockdomain.o] Error 1 make: *** [arch/arm/mach-omap2] Error 2 Signed-off-by: Russ Dill <Russ.Dill@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> [mturquette@linaro.org: removed fixes made redundant by commit 93532c8a] [mturquette@linaro.org: improved $SUBJECT]
2012-12-10clk: introduce optional disable_unused callbackMike Turquette
Some gate clocks have special needs which must be handled during the disable-unused clocks sequence. These needs might be driven by software due to the fact that we're disabling a clock outside of the normal clk_disable path and a clk's enable_count will not be accurate. On the other hand a specific hardware programming sequence might need to be followed for this corner case. This change is needed for the upcoming OMAP port to the common clock framework. Specifically, it is undesirable to treat the disable-unused path identically to the normal clk_disable path since other software layers are involved. In this case OMAP's clockdomain code throws WARNs and bails early due to the clock's enable_count being set to zero. A custom callback mitigates this problem nicely. Cc: Paul Walmsley <paul@pwsan.com> Acked-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-11-26clk: clock multiplexers may register out of orderMartin Fuzzey
When a clock, C is initialised any orphan clocks listing C as a possible parent are reparented to it regardless of the parent requested by the orphan's get_parent() operation. This means that multiplexers registered before their parents are reparented to the first parent subsequently declared, regardless of the selection made by the hardware registers. For example: static const char *sel[] = { "srcA", "srcB", "dummy", "srcC" }; child = clk_register_mux(NULL, "child", sel, ARRAY_SIZE(sel), ...); clk_register_fixed(NULL, "dummy", ...); clk_register_fixed(NULL, "srcA", ...); clk_register_fixed(NULL, "srcB", ...); clk_register_fixed(NULL, "srcC", ...); Causes child's parent to always be "dummy". To fix this, when an orphanned clock has a get_parent() operation, only reparent to the clock indicated by get_parent(). Signed-off-by: Martin Fuzzey <mfuzzey@parkeon.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> [mturquette@linaro.org: improve $SUBJECT]
2012-10-29clk: Add devm_clk_{register,unregister}()Stephen Boyd
Some clock drivers can be simplified if devres takes care of unregistering any registered clocks along error paths. Introduce devm_clk_register() so that clock drivers get unregistration for free along with simplified error paths. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-10-29clk: Don't return negative numbers for unsigned values with !clkStephen Boyd
Some of the helper functions return negative error codes if passed a NULL clock. This can lead to confusing behavior when the expected return value is unsigned. Fix up these accessors so that they return unsigned values (or bool in the case of is_enabled). This way we can't interpret NULL clocks as having valid and interesting values. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-09-07clk: add of_clk_src_onecell_get() supportShawn Guo
For those SoCs that have hundreds of clock outputs, their clock DT bindings could reasonably define #clock-cells as 1 and require the client device specify the index of the clock it consumes in the cell of its "clocks" phandle. Add a generic of_clk_src_onecell_get() function for this purpose. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Reviewed-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-09-06clk: Provide option for clk_get_rate to issue hw for new rateUlf Hansson
By using CLK_GET_RATE_NOCACHE flag, we tell the clk_get_rate API to issue the hw for an updated clock rate. This can be used for a clock which rate may be updated without a client necessary modifying it. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-07-30clk: validate pointer in __clk_disable()Fengguang Wu
clk_get() returns -ENOENT on error and some careless caller might dereference it without error checking: In mxc_rnga_remove(): struct clk *clk = clk_get(&pdev->dev, "rng"); // ... clk_disable(clk); Since it's insane to audit the lots of existing and future clk users, let's add a check in the callee to avoid kernel panic and warn about any buggy user. Cc: Russell King <rmk@arm.linux.org.uk> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Viresh Kumar <viresh.kumar@st.com> Cc: viresh kumar <viresh.linux@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-07-11clk: add DT clock binding supportGrant Likely
Based on work 1st by Ben Herrenschmidt and Jeremy Kerr, then by Grant Likely, this patch adds support to clk_get to allow drivers to retrieve clock data from the device tree. Platforms scan for clocks in DT with of_clk_init and a match table, and the register a provider through of_clk_add_provider. The provider's clk_src_get function will be called when a device references the provider's OF node for a clock reference. v6 (Rob Herring): - Return error values instead of NULL to match clock framework expectations v5 (Rob Herring): - Move from drivers/of into common clock subsystem - Squashed "dt/clock: add a simple provider get function" and "dt/clock: add function to get parent clock name" - Rebase to 3.4-rc1 - Drop CONFIG_OF_CLOCK and just use CONFIG_OF - Add missing EXPORT_SYMBOL to various functions - s/clock-output-name/clock-output-names/ - Define that fixed-clock binding is a single output v4 (Rob Herring): - Rework for common clk subsystem - Add of_clk_get_parent_name function v3: - Clarified documentation v2: - fixed errant ';' causing compile error - Editorial fixes from Shawn Guo - merged in adding lookup to clkdev - changed property names to match established convention. After working with the binding a bit it really made more sense to follow the lead of 'reg', 'gpios' and 'interrupts' by making the input simply 'clocks' & 'clock-names' instead of 'clock-input-*', and to only use clock-output* for the producer nodes. (Sorry Shawn, this will mean you need to change some code, but it should be trivial) - Add ability to inherit clocks from parent nodes by using an empty 'clock-ranges' property. Useful for busses. I could use some feedback on the new property name, 'clock-ranges' doesn't feel right to me. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Rob Herring <rob.herring@calxeda.com> Reviewed-by: Shawn Guo <shawn.guo@freescale.com> Cc: Sascha Hauer <kernel@pengutronix.de> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-07-11clk: cache parent clocks only for muxesRajendra Nayak
caching parent clocks makes sense only when a clock has more than one parent (mux clocks). Avoid doing this for every other clock. Signed-off-by: Rajendra Nayak <rnayak@ti.com> [mturquette@linaro.org: removed extra parentheses] Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-07-03clk: fix parent validation in __clk_set_parent()Rajendra Nayak
The below commit introduced a bug in __clk_set_parent() which could cause it to *skip* the parent validation which makes sure the parent passed to the api is a valid one. commit 7975059db572eb47f0fb272a62afeae272a4b209 Author: Rajendra Nayak <rnayak@ti.com> Date: Wed Jun 6 14:41:31 2012 +0530 clk: Allow late cache allocation for clk->parents This was identified by the following compiler warning.. drivers/clk/clk.c: In function '__clk_set_parent': drivers/clk/clk.c:1083:5: warning: 'i' may be used uninitialized in this function [-Wuninitialized] .. as reported by Marc Kleine-Budde. There were various options discussed on how to fix this, one being initing 'i' to clk->num_parents, but the below approach was found to be more appropriate as it also makes the 'parent validation' code simpler to read. Reported-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> Cc: stable@kernel.org
2012-06-25clk: Check parent for NULL in clk_change_ratePawel Moll
clk_change_rate() is accessing parent's rate without checking if the parent exists at all. In case of root clocks this will cause NULL pointer dereference. This patch follows what clk_calc_new_rates() does in such situation. Signed-off-by: Pawel Moll <pawel.moll@arm.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> Cc: stable@kernel.org
2012-06-25clk: Allow late cache allocation for clk->parentsRajendra Nayak
Parent clocks for muxes are cached in clk->parents to avoid frequent lookups, however the cache allocation happens only during clock registeration and later clk_set_parent() assumes a cache space available and allocated. This is not entirely true for platforms which do early clock registerations wherein the cache allocation using kzalloc could fail during clock registeration. Allow cache allocation to happen later as part of clk_set_parent() to help such cases and avoid crashes assuming a cache being available. While here also replace existing kmalloc() with kzalloc() in the file. Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org> Cc: stable@kernel.org
2012-05-15clk: Fix CLK_SET_RATE_GATE flag validation in clk_set_rate().Saravana Kannan
The clk_set_rate() code shouldn't check the clock's enable count when validating CLK_SET_RATE_GATE flag since the enable count could change after the validation. Similar to clk_set_parent(), it should instead check the prepare count. The prepare count should go to zero only when the end user expects the clock to not be enabled in the future. Since the code already grabs the prepare count before validation, it's not possible for prepare count to change after validation and by association not possible for a well behaving end user to enable the clock while the set rate is in progress. Signed-off-by: Saravana Kannan <skannan@codeaurora.org> Reviewed-by: Richard Zhao <richard.zhao@freescale.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-05-15clk: Provide dummy clk_unregister()Mark Brown
While there's no actual implementation behind it having the call to use in drivers makes them feel neater from a driver author point of view. An actual implementation can wait for someone who needs to use the function in a real system. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> [mturquette@linaro.org: void return type instead of int -EINVAL] Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-05-08clk: remove COMMON_CLK_DISABLE_UNUSEDMike Turquette
Exposing this option generates confusion and incorrect behavior for single-image builds across platforms. Enable this behavior permanently. Signed-off-by: Mike Turquette <mturquette@linaro.org> Acked-by: Saravana Kannan <skannan@codeaurora.org>
2012-05-08clk: prevent spurious parent rate propagationMike Turquette
Patch 'clk: always pass parent_rate into .round_rate' made a subtle change to the semantics of .round_rate. It is now expected for the parent's rate to always be passed in, simplifying the implemenation of various .round_rate callback definitions. However the patch also introduced a bug in clk_calc_new_rates whereby a clock without the CLK_SET_RATE_PARENT flag set could still propagate a rate change up to a parent clock if the the .round_rate callback modified the &best_parent_rate value in any way. This patch fixes the issue at the framework level (in clk_calc_new_rates) by specifically handling the case where the CLK_SET_RATE_PARENT flag is not set. Signed-off-by: Mike Turquette <mturquette@linaro.org> Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
2012-05-01clk: clk_set_rate() must fail if CLK_SET_RATE_GATE is set and clk is enabledViresh Kumar
This is well documented but isn't implemented. clk_set_rate() must check if flags have CLK_SET_RATE_GATE bit set and is enabled too. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-05-01clk: Use a separate struct for holding init data.Saravana Kannan
Create a struct clk_init_data to hold all data that needs to be passed from the platfrom specific driver to the common clock framework during clock registration. Add a pointer to this struct inside clk_hw. This has several advantages: * Completely hides struct clk from many clock platform drivers and static clock initialization code that don't care for static initialization of the struct clks. * For platforms that want to do complete static initialization, it removed the need to directly mess with the struct clk's fields while still allowing to statically allocate struct clk. This keeps the code more future proof even if they include clk-private.h. * Simplifies the generic clk_register() function and allows adding optional fields in the future without modifying the function signature. * Simplifies the static initialization of clocks on all platforms by removing the need for forward delcarations or convoluted macros. Signed-off-by: Saravana Kannan <skannan@codeaurora.org> [mturquette@linaro.org: kept DEFINE_CLK_* macros and __clk_init] Signed-off-by: Mike Turquette <mturquette@linaro.org> Cc: Andrew Lunn <andrew@lunn.ch> Cc: Rob Herring <rob.herring@calxeda.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Jeremy Kerr <jeremy.kerr@canonical.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Arnd Bergman <arnd.bergmann@linaro.org> Cc: Paul Walmsley <paul@pwsan.com> Cc: Shawn Guo <shawn.guo@freescale.com> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Jamie Iles <jamie@jamieiles.com> Cc: Richard Zhao <richard.zhao@linaro.org> Cc: Saravana Kannan <skannan@codeaurora.org> Cc: Magnus Damm <magnus.damm@gmail.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Linus Walleij <linus.walleij@stericsson.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Amit Kucheria <amit.kucheria@linaro.org> Cc: Deepak Saxena <dsaxena@linaro.org> Cc: Grant Likely <grant.likely@secretlab.ca>
2012-04-24clk: Don't set clk->new_rate twiceViresh Kumar
if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) is true, then we don't need to set clk->new_rate here, as we will call clk_calc_subtree() afterwards and it also sets clk->new_rate. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: propagate round_rate for CLK_SET_RATE_PARENT caseShawn Guo
Need to propagate round_rate call for the clk that has no .round_rate operation but with flag CLK_SET_RATE_PARENT set. For example, clk_mux is a clk with no .round_rate operation. However, it could likely be in a clk_set_rate propagation path, saying it has parent clk who has .round_rate and .set_rate operations. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: pass parent_rate into .set_rateShawn Guo
For most of .set_rate implementation, parent_rate will be used, so just like passing parent_rate into .recalc_rate, let's pass parent_rate into .set_rate too. It also updates the kernel doc for .set_rate ops. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: always pass parent_rate into .round_rateShawn Guo
The parent_rate will likely be used by most .round_rate implementation no matter whether flag CLK_SET_RATE_PARENT is set or not, so let's always pass parent_rate into .round_rate. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: core: copy parent_names & return error codesMike Turquette
This patch cleans up clk_register and solves a few bugs by teaching clk_register and __clk_init to return error codes (instead of just NULL) to better align with the existing clk.h api. Along with that change this patch also introduces a new behavior whereby clk_register copies the parent_names array, thus allowing platforms to declare their parent_names arrays as __initdata. Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: Constify parent name arraysMark Brown
Drivers should be able to declare their arrays of parent names as const so the APIs need to accept const arguments. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> [mturquette@linaro.org: constified gate] Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: Make clk_get_rate() return 0 on errorRajendra Nayak
Most users of clk_get_rate() actually assume a non zero return value as a valid rate returned. Returing -EINVAL might confuse such users, so make it instead return zero on error. Besides the return value of clk_get_rate seems to be 'unsigned long'. Signed-off-by: Rajendra nayak <rnayak@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: core: enforce clk_ops consistencyMike Turquette
Documentation/clk.txt has some handsome ASCII art outlining which clk_ops are mandatory for a given clock, given the capability of the hardware. Enforce those mandates with sanity checks in __clk_init. Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: core: clk_calc_new_rates handles NULL parentsMike Turquette
It is possible to call clk_set_rate on a clock with a NULL parent. One such example is an adjustable-rate root clock. Ensure that clk_calc_new_rates does not dereference parent without checking first and also handle the corner cases gracefully. Reported-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: core: remove dead code pathsMike Turquette
Some static inline dummy functions were left over from before the clock core was consolidated from several C files down to one. Remove them. Reported-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-04-24clk: core: correct clk_set_rate kerneldocMike Turquette
Remove old and misleading documentation from the previous clk_set_rate implementaion. Reported-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
2012-03-16clk: introduce the common clock frameworkMike Turquette
The common clock framework defines a common struct clk useful across most platforms as well as an implementation of the clk api that drivers can use safely for managing clocks. The net result is consolidation of many different struct clk definitions and platform-specific clock framework implementations. This patch introduces the common struct clk, struct clk_ops and an implementation of the well-known clock api in include/clk/clk.h. Platforms may define their own hardware-specific clock structure and their own clock operation callbacks, so long as it wraps an instance of struct clk_hw. See Documentation/clk.txt for more details. This patch is based on the work of Jeremy Kerr, which in turn was based on the work of Ben Herrenschmidt. Signed-off-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Mike Turquette <mturquette@ti.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Rob Herring <rob.herring <at> calxeda.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Jeremy Kerr <jeremy.kerr@canonical.com> Cc: Arnd Bergman <arnd.bergmann@linaro.org> Cc: Paul Walmsley <paul@pwsan.com> Cc: Shawn Guo <shawn.guo@freescale.com> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Richard Zhao <richard.zhao@linaro.org> Cc: Saravana Kannan <skannan@codeaurora.org> Cc: Magnus Damm <magnus.damm@gmail.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Linus Walleij <linus.walleij@stericsson.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Amit Kucheria <amit.kucheria@linaro.org> Cc: Deepak Saxena <dsaxena@linaro.org> Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Arnd Bergmann <arnd@arndb.de>