Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752297AbZA1TU0 (ORCPT ); Wed, 28 Jan 2009 14:20:26 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751155AbZA1TUM (ORCPT ); Wed, 28 Jan 2009 14:20:12 -0500 Received: from mail-ew0-f21.google.com ([209.85.219.21]:40107 "EHLO mail-ew0-f21.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751133AbZA1TUK (ORCPT ); Wed, 28 Jan 2009 14:20:10 -0500 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; b=SPYPLjyXH93BV/b57nXr8a3ubvLRhIqXOzChnFTpKtbLT8g+FH4RuMi2NcjF2LqO7T Hpq3ZRGwR+vTzBjOScnotL4pzfFxFoqkyNT8jwL7mzth9TT+izMishhoOFD/1tn1By++ FWLcH3GgE/6D37HWcwlR7pG0CCe6N5PFUMuCg= MIME-Version: 1.0 In-Reply-To: <20090108163024.GB26413@suse.de> References: <8447d6730901080149l4146139an9fad00fd88d72fb9@mail.gmail.com> <20090108112741.GA3053@local> <8447d6730901080806r238354c7u81071a28d8b483ff@mail.gmail.com> <20090108163024.GB26413@suse.de> Date: Wed, 28 Jan 2009 20:20:07 +0100 Message-ID: <8447d6730901281120k1153f682oa4e8f3e6249eee7b@mail.gmail.com> Subject: Re: [PATCH 1/3] Driver for user access to internal clocks From: Davide Rizzo To: Greg KH Cc: "Hans J. Koch" , linux-kernel@vger.kernel.org, ben-linux@fluff.org, linux-api@vger.kernel.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7870 Lines: 267 > Same comments here as for your "timer.c" file: > - too generic of a name > - needs proper documentation > - send any kernel api changes also to linux-api@vger.kernel.org > > thanks, > > greg k-h > Here is the modified user mode clock access driver. I moved it in /drivers/misc and reorganized virtual files under /sys/class/clock This driver is for user level programs to interact with system clocks. It allows to read and modify rates and parents, using virtual files. It requires the implementation of 2 additional functions in the clk interface: clk_for_each() and clk_name(). Actually I implemented that functions only for Samsung S3C24xx platform. Signed-off-by: Davide Rizzo --- diff -urpN linux-2.6.29-rc2/drivers/misc/Kconfig linux-2.6.29-rc2.elpa/drivers/misc/Kconfig --- linux-2.6.29-rc2/drivers/misc/Kconfig 2009-01-17 11:32:40.000000000 +0100 +++ linux-2.6.29-rc2.elpa/drivers/misc/Kconfig 2009-01-28 19:21:43.000000000 +0100 @@ -232,4 +232,19 @@ config DELL_LAPTOP source "drivers/misc/c2port/Kconfig" +config UM_CLOCK + bool "User mode clock driver" + depends on SYSFS + default n + ---help--- + Allows user mode programs to configure and control internal clocks' + rates and parents through virtual files in sysfs. + This driver requires implementation of some additional functions + in architecture specific low-level drivers: clk_for_each() and + clk_get_name(). Moreover, it requires clk_get() to recognize the + "name.id" format + Currently they're implemented only on Samsung S3C24xx platforms. + + If unsure, say N. + endif # MISC_DEVICES diff -urpN linux-2.6.29-rc2/drivers/misc/Makefile linux-2.6.29-rc2.elpa/drivers/misc/Makefile --- linux-2.6.29-rc2/drivers/misc/Makefile 2009-01-17 11:32:40.000000000 +0100 +++ linux-2.6.29-rc2.elpa/drivers/misc/Makefile 2009-01-28 19:21:43.000000000 +0100 @@ -20,3 +20,4 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_C2PORT) += c2port/ +obj-$(CONFIG_UM_CLOCK) += um_clock.o diff -urpN linux-2.6.29-rc2/drivers/misc/um_clock.c linux-2.6.29-rc2.elpa/drivers/misc/um_clock.c --- linux-2.6.29-rc2/drivers/misc/um_clock.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.29-rc2.elpa/drivers/misc/um_clock.c 2009-01-28 19:21:43.000000000 +0100 @@ -0,0 +1,174 @@ +/* + driver/misc/clock.c + + Written Feb 2008 by Davide Rizzo + + This driver allows to read and modify internal clocks' rates using + virtual files. User can also read and modify parents. + + This driver requires implementation of clk_name() and clk_enum() functions + in architecture specific clock.c + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +static DEFINE_MUTEX(mutex); + +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + unsigned long rate; + struct clk *clk; + + clk = dev_get_drvdata(dev); + rate = 0; + + mutex_lock(&mutex); + + rate = clk_get_rate(clk); + + mutex_unlock(&mutex); + + return sprintf(buffer, "%ld\n", rate); +} + +static ssize_t rate_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t count) +{ + unsigned long rate; + struct clk *clk; + int err; + + clk = dev_get_drvdata(dev); + err = strict_strtoul(buffer, 10, &rate); + if (err) + return err; + + mutex_lock(&mutex); + + if (rate != 0) { + clk_set_rate(clk, clk_round_rate(clk, rate)); + clk_enable(clk); + } else + clk_disable(clk); + + mutex_unlock(&mutex); + + return count; +} + +static ssize_t parent_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct clk *parent, *clk; + + clk = dev_get_drvdata(dev); + + mutex_lock(&mutex); + + parent = clk_get_parent(clk); + if (parent && !IS_ERR(parent)) { + const char *name = clk_get_name(parent); + if (IS_ERR(name)) { + mutex_unlock(&mutex); + return PTR_ERR(name); + } + strlcpy(buffer, name, PAGE_SIZE); + } else + buffer[0] = '\0'; + strlcat(buffer, "\n", PAGE_SIZE); + + mutex_unlock(&mutex); + + return strlen(buffer); +} + +static ssize_t parent_store(struct device *dev, + struct device_attribute *attr, const char *buffer, size_t count) +{ + struct clk *parent; + + char *s = kstrdup(buffer, GFP_KERNEL); + + if (!s) + return -ENOMEM; + if (s[strlen(s) - 1] == '\n') + s[strlen(s) - 1] = '\0'; + parent = clk_get(dev, s); + kfree(s); + if (IS_ERR(parent)) + return PTR_ERR(parent); + + mutex_lock(&mutex); + + clk_set_parent(dev_get_drvdata(dev), parent); + + mutex_unlock(&mutex); + + clk_put(parent); + return count; +} + +static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, rate_show, rate_store); +static DEVICE_ATTR(parent, S_IRUGO | S_IWUSR, parent_show, parent_store); + +static const struct attribute *clock_attrs[] = { + &dev_attr_rate.attr, + &dev_attr_parent.attr, + NULL, +}; + +static const struct attribute_group clock_attr_group = { + .attrs = (struct attribute **) clock_attrs, +}; + +static struct class gpclock_class = { + .name = "clock", + .owner = THIS_MODULE, +}; + +static int create_clock_attr(struct clk *clk, void *data) +{ + struct device *dev; + const char *name; + + name = clk_get_name(clk); + if (name == NULL || IS_ERR(name)) { + pr_debug("Invalid clock's name\n"); + return PTR_ERR(name); + } + dev = device_create(&gpclock_class, (struct device *)data, MKDEV(0, 0), + clk, name); + if (!dev) + return -ENODEV; + return sysfs_create_group(&dev->kobj, &clock_attr_group); +} + +static int __init gpclock_init(void) +{ + int ret; + + ret = class_register(&gpclock_class); + if (ret >= 0) + ret = clk_for_each(create_clock_attr, NULL); + return ret; +} +subsys_initcall(gpclock_init); + diff -urpN linux-2.6.29-rc2/Documentation/ABI/testing/sysfs-class-clock linux-2.6.29-rc2.elpa/Documentation/ABI/testing/sysfs-class-clock --- linux-2.6.29-rc2/Documentation/ABI/testing/sysfs-class-clock 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.29-rc2.elpa/Documentation/ABI/testing/sysfs-class-clock 2009-01-28 19:21:43.000000000 +0100 @@ -0,0 +1,20 @@ +What: /sys/class/clock +Date: January 2009 +Contact: Davide Rizzo +Description: + The /sys/class/clock directory will consist of a group of + subdirectories each one describing an internal clock in the kernel. + The name of the subdirectory is the clock's name. + If a clock is device specific, its name is in the form "name.id". + In each directory there are 2 virtual files: rate and parent. + Both these files are r/w, but there can be some architecture-dependent + limitations on write access on one or both of them. + For this interface to work, it needs some low-level implementations (look + at include/linux/clk.h): + - clk_for_each() + - clk_name() + - clk_get() should recognize also the "name.id" format + Actually I implemented these only for Samsung S3C SoC in + arch/arm/plat-s3c/clock.c + +Users: -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/