All of lore.kernel.org
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: linux-arm-kernel@lists.infradead.org
Subject: Re: [lm-sensors] [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
Date: Tue, 18 Sep 2012 15:24:30 +0000	[thread overview]
Message-ID: <20120918152430.GA5911@roeck-us.net> (raw)
In-Reply-To: <1347977875-16855-4-git-send-email-pawel.moll@arm.com>

On Tue, Sep 18, 2012 at 03:17:45PM +0100, Pawel Moll wrote:
> hwmon framework driver for Versatile Express sensors, providing
> information about board level voltage (only when regulator driver
> is not configured), currents, temperature and power/energy usage.
> Labels for the values can be defined as DT properties.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  drivers/hwmon/Kconfig    |    8 ++
>  drivers/hwmon/Makefile   |    1 +
>  drivers/hwmon/vexpress.c |  330 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 339 insertions(+)
>  create mode 100644 drivers/hwmon/vexpress.c
> 
> Hi Jean, Guenter,
> 
> Would you be able to merge this in time for 3.7? (if it looks fine, that is)
> 
> Regards
> 
> Pawel
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index b0a2e4c..7359a07 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1187,6 +1187,14 @@ config SENSORS_TWL4030_MADC
>  	This driver can also be built as a module. If so it will be called
>  	twl4030-madc-hwmon.
>  
> +config SENSORS_VEXPRESS
> +	tristate "Versatile Express"
> +	depends on VEXPRESS_CONFIG
> +	help
> +	  This driver provides support for hardware sensors available on
> +	  the ARM Ltd's Versatile Express platform. It can provide wide
> +	  range of information like temperature, power, energy.
> +
>  config SENSORS_VIA_CPUTEMP
>  	tristate "VIA CPU temperature sensor"
>  	depends on X86
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 7aa9811..e719a7d 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -120,6 +120,7 @@ obj-$(CONFIG_SENSORS_TMP102)	+= tmp102.o
>  obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
>  obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
>  obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
> +obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress.o
>  obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
>  obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
>  obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
> diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
> new file mode 100644
> index 0000000..fe80c63
> --- /dev/null
> +++ b/drivers/hwmon/vexpress.c
> @@ -0,0 +1,330 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + * Copyright (C) 2012 ARM Limited
> + */
> +
> +#define DRVNAME "vexpress-hwmon"
> +#define pr_fmt(fmt) DRVNAME ": " fmt
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/hwmon.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/vexpress.h>
> +
> +static struct device *vexpress_hwmon_dev;
> +static int vexpress_hwmon_dev_refcount;
> +static DEFINE_SPINLOCK(vexpress_hwmon_dev_lock);
> +
> +static ssize_t vexpress_hwmon_name_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	return sprintf(buffer, "%s\n", DRVNAME);
> +}
> +
> +static struct device_attribute vexpress_hwmon_name_attr > +		__ATTR(name, 0444, vexpress_hwmon_name_show, NULL);
> +
> +struct vexpress_hwmon_attrs {
> +	struct vexpress_config_func *func;
> +	const char *label;
> +	struct device_attribute label_attr;
> +	char label_name[16];
> +	struct device_attribute input_attr;
> +	char input_name[16];
> +	u32 divisor;
> +};
> +
> +static ssize_t vexpress_hwmon_label_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, label_attr);
> +
> +	return snprintf(buffer, PAGE_SIZE, "%s\n", attrs->label);
> +}
> +
> +static ssize_t vexpress_hwmon_u32_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%u\n", value / attrs->divisor);
> +}
> +
> +static ssize_t vexpress_hwmon_u64_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value_hi, value_lo;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value_lo);
> +	if (err)
> +		return err;
> +
> +	err = vexpress_config_read(attrs->func, 1, &value_hi);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%llu\n",
> +			div_u64(((u64)value_hi << 32) | value_lo,
> +			attrs->divisor));
> +}
> +
> +static struct device *vexpress_hwmon_dev_get(void)
> +{
> +	struct device *result;
> +
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (vexpress_hwmon_dev) {
> +		result = vexpress_hwmon_dev;
> +	} else {
> +		int err;
> +
> +		result = hwmon_device_register(NULL);
> +		if (IS_ERR(result))
> +			goto out;
> +
> +		err = device_create_file(result, &vexpress_hwmon_name_attr);
> +		if (err) {
> +			result = ERR_PTR(err);
> +			hwmon_device_unregister(result);
> +			goto out;
> +		}
> +
> +		vexpress_hwmon_dev = result;
> +	}
> +
> +	vexpress_hwmon_dev_refcount++;
> +
> +out:
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +
> +	return result;
> +}
> +
> +static void vexpress_hwmon_dev_put(void)
> +{
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (--vexpress_hwmon_dev_refcount = 0) {
> +		hwmon_device_unregister(vexpress_hwmon_dev);
> +		vexpress_hwmon_dev = NULL;
> +	}
> +
> +	WARN_ON(vexpress_hwmon_dev_refcount < 0);
> +
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +}
> +
This is a highly unusual means to register a hwmon driver (and you are leaking
the name attribute on remove as far as I can see).

> +struct vexpress_hwmon_func {
> +	const char *name;
> +	bool wide;
> +	u32 divisor;
> +	atomic_t index;
> +};
> +
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +static struct vexpress_hwmon_func vexpress_hwmon_volt = {
> +	.name = "in",
> +	.divisor = 1000,
> +};
> +#endif
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_amp = {
> +	.name = "curr",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_temp = {
> +	.name = "temp",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_power = {
> +	.name = "power",
> +	.divisor = 1,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_energy = {
> +	.name = "energy",
> +	.wide = true,
> +	.divisor = 1,
> +};
> +
> +static struct of_device_id vexpress_hwmon_of_match[] = {
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +	{
> +		.compatible = "arm,vexpress-volt",
> +		.data = &vexpress_hwmon_volt,
> +	},
> +#endif
> +	{
> +		.compatible = "arm,vexpress-amp",
> +		.data = &vexpress_hwmon_amp,
> +	}, {
> +		.compatible = "arm,vexpress-temp",
> +		.data = &vexpress_hwmon_temp,
> +	}, {
> +		.compatible = "arm,vexpress-power",
> +		.data = &vexpress_hwmon_power,
> +	}, {
> +		.compatible = "arm,vexpress-energy",
> +		.data = &vexpress_hwmon_energy,
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
> +
> +static int vexpress_hwmon_probe(struct platform_device *pdev)
> +{
> +	int err;
> +	const struct of_device_id *match;
> +	struct vexpress_hwmon_func *hwmon_func;
> +	struct device *hwmon_dev;
> +	struct vexpress_hwmon_attrs *attrs;
> +	const char *attr_name;
> +	int attr_index;
> +
> +	match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	if (!match) {
> +		err = -EINVAL;
> +		goto error_match_device;
> +	}
> +	hwmon_func = match->data;
> +
> +	hwmon_dev = vexpress_hwmon_dev_get();
> +	if (IS_ERR(hwmon_dev)) {
> +		err = PTR_ERR(hwmon_dev);
> +		goto error_hwmon_dev_get;
> +	}
> +
> +	attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
> +	if (!attrs) {
> +		err = -ENOMEM;
> +		goto error_kzalloc;
> +	}
> +
> +	attrs->func = vexpress_config_func_get_by_dev(&pdev->dev);
> +	if (!attrs->func) {
> +		err = -ENXIO;
> +		goto error_get_func;
> +	}
> +
> +	err = sysfs_create_link(&pdev->dev.kobj, &hwmon_dev->kobj, "hwmon");
> +	if (err)
> +		goto error_create_link;
> +
> +	attr_index = atomic_inc_return(&hwmon_func->index);
> +	attr_name = hwmon_func->name;
> +
> +	snprintf(attrs->input_name, sizeof(attrs->input_name),
> +			"%s%d_input", attr_name, attr_index);
> +	attrs->input_attr.attr.name = attrs->input_name;
> +	attrs->input_attr.attr.mode = 0444;
> +	if (hwmon_func->wide)
> +		attrs->input_attr.show = vexpress_hwmon_u64_show;
> +	else
> +		attrs->input_attr.show = vexpress_hwmon_u32_show;
> +	sysfs_attr_init(&attrs->input_attr.attr);
> +	err = device_create_file(hwmon_dev, &attrs->input_attr);
> +	if (err)
> +		goto error_create_input;
> +
and a highly unusual way of, as much as I understand of it, bypass the hwmon
infrastructure as much as possible.

I don't even understand what you are trying to do, much less why you don't
just use the existing infrastructure, and I don't have time to try to figure
it out. Maybe Jean has time to review this driver, but not me.

So, no, for my part I don't think it would be a good idea to rush this driver
into 3.7.

Really, I would suggest to submit a standard hwmon driver (there are lots of
examples out there).

Guenter

> +	attrs->label = of_get_property(pdev->dev.of_node, "label", NULL);
> +	if (attrs->label) {
> +		snprintf(attrs->label_name, sizeof(attrs->label_name),
> +				"%s%d_label", attr_name, attr_index);
> +		attrs->label_attr.attr.name = attrs->label_name;
> +		attrs->label_attr.attr.mode = 0444;
> +		attrs->label_attr.show = vexpress_hwmon_label_show;
> +		sysfs_attr_init(&attrs->label_attr.attr);
> +		err = device_create_file(hwmon_dev, &attrs->label_attr);
> +		if (err)
> +			goto error_create_label;
> +	}
> +
> +	attrs->divisor = hwmon_func->divisor;
> +
> +	platform_set_drvdata(pdev, attrs);
> +
> +	return 0;
> +
> +error_create_label:
> +	device_remove_file(hwmon_dev, &attrs->input_attr);
> +error_create_input:
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +error_create_link:
> +	vexpress_config_func_put(attrs->func);
> +error_get_func:
> +error_kzalloc:
> +	vexpress_hwmon_dev_put();
> +error_hwmon_dev_get:
> +error_match_device:
> +	return err;
> +}
> +
> +static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
> +{
> +	struct vexpress_hwmon_attrs *attrs = platform_get_drvdata(pdev);
> +	const struct of_device_id *match > +		of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	struct vexpress_hwmon_func *hwmon_func = match->data;
> +
> +	if (attrs->label)
> +		device_remove_file(vexpress_hwmon_dev, &attrs->label_attr);
> +	device_remove_file(vexpress_hwmon_dev, &attrs->input_attr);
> +	atomic_dec(&hwmon_func->index);
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +	vexpress_config_func_put(attrs->func);
> +	vexpress_hwmon_dev_put();
> +
> +	return 0;
> +}
> +
> +static struct platform_driver vexpress_hwmon_driver = {
> +	.probe = vexpress_hwmon_probe,
> +	.remove = __devexit_p(vexpress_hwmon_remove),
> +	.driver	= {
> +		.name = DRVNAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = vexpress_hwmon_of_match,
> +	},
> +};
> +
> +static int __init vexpress_hwmon_init(void)
> +{
> +	return platform_driver_register(&vexpress_hwmon_driver);
> +}
> +
> +static void __exit vexpress_hwmon_exit(void)
> +{
> +	platform_driver_unregister(&vexpress_hwmon_driver);
> +}
> +
> +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
> +MODULE_DESCRIPTION("Versatile Express hwmon");
> +MODULE_LICENSE("GPL");
> +
> +module_init(vexpress_hwmon_init);
> +module_exit(vexpress_hwmon_exit);
> -- 
> 1.7.9.5
> 
> 
> 

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

WARNING: multiple messages have this Message-ID (diff)
From: linux@roeck-us.net (Guenter Roeck)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 03/13] hwmon: Versatile Express hwmon driver
Date: Tue, 18 Sep 2012 08:24:30 -0700	[thread overview]
Message-ID: <20120918152430.GA5911@roeck-us.net> (raw)
In-Reply-To: <1347977875-16855-4-git-send-email-pawel.moll@arm.com>

On Tue, Sep 18, 2012 at 03:17:45PM +0100, Pawel Moll wrote:
> hwmon framework driver for Versatile Express sensors, providing
> information about board level voltage (only when regulator driver
> is not configured), currents, temperature and power/energy usage.
> Labels for the values can be defined as DT properties.
> 
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
>  drivers/hwmon/Kconfig    |    8 ++
>  drivers/hwmon/Makefile   |    1 +
>  drivers/hwmon/vexpress.c |  330 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 339 insertions(+)
>  create mode 100644 drivers/hwmon/vexpress.c
> 
> Hi Jean, Guenter,
> 
> Would you be able to merge this in time for 3.7? (if it looks fine, that is)
> 
> Regards
> 
> Pawel
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index b0a2e4c..7359a07 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1187,6 +1187,14 @@ config SENSORS_TWL4030_MADC
>  	This driver can also be built as a module. If so it will be called
>  	twl4030-madc-hwmon.
>  
> +config SENSORS_VEXPRESS
> +	tristate "Versatile Express"
> +	depends on VEXPRESS_CONFIG
> +	help
> +	  This driver provides support for hardware sensors available on
> +	  the ARM Ltd's Versatile Express platform. It can provide wide
> +	  range of information like temperature, power, energy.
> +
>  config SENSORS_VIA_CPUTEMP
>  	tristate "VIA CPU temperature sensor"
>  	depends on X86
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 7aa9811..e719a7d 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -120,6 +120,7 @@ obj-$(CONFIG_SENSORS_TMP102)	+= tmp102.o
>  obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
>  obj-$(CONFIG_SENSORS_TMP421)	+= tmp421.o
>  obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
> +obj-$(CONFIG_SENSORS_VEXPRESS)	+= vexpress.o
>  obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
>  obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
>  obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
> diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c
> new file mode 100644
> index 0000000..fe80c63
> --- /dev/null
> +++ b/drivers/hwmon/vexpress.c
> @@ -0,0 +1,330 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + * Copyright (C) 2012 ARM Limited
> + */
> +
> +#define DRVNAME "vexpress-hwmon"
> +#define pr_fmt(fmt) DRVNAME ": " fmt
> +
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/hwmon.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/vexpress.h>
> +
> +static struct device *vexpress_hwmon_dev;
> +static int vexpress_hwmon_dev_refcount;
> +static DEFINE_SPINLOCK(vexpress_hwmon_dev_lock);
> +
> +static ssize_t vexpress_hwmon_name_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	return sprintf(buffer, "%s\n", DRVNAME);
> +}
> +
> +static struct device_attribute vexpress_hwmon_name_attr =
> +		__ATTR(name, 0444, vexpress_hwmon_name_show, NULL);
> +
> +struct vexpress_hwmon_attrs {
> +	struct vexpress_config_func *func;
> +	const char *label;
> +	struct device_attribute label_attr;
> +	char label_name[16];
> +	struct device_attribute input_attr;
> +	char input_name[16];
> +	u32 divisor;
> +};
> +
> +static ssize_t vexpress_hwmon_label_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, label_attr);
> +
> +	return snprintf(buffer, PAGE_SIZE, "%s\n", attrs->label);
> +}
> +
> +static ssize_t vexpress_hwmon_u32_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%u\n", value / attrs->divisor);
> +}
> +
> +static ssize_t vexpress_hwmon_u64_show(struct device *dev,
> +		struct device_attribute *dev_attr, char *buffer)
> +{
> +	struct vexpress_hwmon_attrs *attrs = container_of(dev_attr,
> +			struct vexpress_hwmon_attrs, input_attr);
> +	int err;
> +	u32 value_hi, value_lo;
> +
> +	err = vexpress_config_read(attrs->func, 0, &value_lo);
> +	if (err)
> +		return err;
> +
> +	err = vexpress_config_read(attrs->func, 1, &value_hi);
> +	if (err)
> +		return err;
> +
> +	return snprintf(buffer, PAGE_SIZE, "%llu\n",
> +			div_u64(((u64)value_hi << 32) | value_lo,
> +			attrs->divisor));
> +}
> +
> +static struct device *vexpress_hwmon_dev_get(void)
> +{
> +	struct device *result;
> +
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (vexpress_hwmon_dev) {
> +		result = vexpress_hwmon_dev;
> +	} else {
> +		int err;
> +
> +		result = hwmon_device_register(NULL);
> +		if (IS_ERR(result))
> +			goto out;
> +
> +		err = device_create_file(result, &vexpress_hwmon_name_attr);
> +		if (err) {
> +			result = ERR_PTR(err);
> +			hwmon_device_unregister(result);
> +			goto out;
> +		}
> +
> +		vexpress_hwmon_dev = result;
> +	}
> +
> +	vexpress_hwmon_dev_refcount++;
> +
> +out:
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +
> +	return result;
> +}
> +
> +static void vexpress_hwmon_dev_put(void)
> +{
> +	spin_lock(&vexpress_hwmon_dev_lock);
> +
> +	if (--vexpress_hwmon_dev_refcount == 0) {
> +		hwmon_device_unregister(vexpress_hwmon_dev);
> +		vexpress_hwmon_dev = NULL;
> +	}
> +
> +	WARN_ON(vexpress_hwmon_dev_refcount < 0);
> +
> +	spin_unlock(&vexpress_hwmon_dev_lock);
> +}
> +
This is a highly unusual means to register a hwmon driver (and you are leaking
the name attribute on remove as far as I can see).

> +struct vexpress_hwmon_func {
> +	const char *name;
> +	bool wide;
> +	u32 divisor;
> +	atomic_t index;
> +};
> +
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +static struct vexpress_hwmon_func vexpress_hwmon_volt = {
> +	.name = "in",
> +	.divisor = 1000,
> +};
> +#endif
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_amp = {
> +	.name = "curr",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_temp = {
> +	.name = "temp",
> +	.divisor = 1000,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_power = {
> +	.name = "power",
> +	.divisor = 1,
> +};
> +
> +static struct vexpress_hwmon_func vexpress_hwmon_energy = {
> +	.name = "energy",
> +	.wide = true,
> +	.divisor = 1,
> +};
> +
> +static struct of_device_id vexpress_hwmon_of_match[] = {
> +#if !defined(CONFIG_REGULATOR_VEXPRESS)
> +	{
> +		.compatible = "arm,vexpress-volt",
> +		.data = &vexpress_hwmon_volt,
> +	},
> +#endif
> +	{
> +		.compatible = "arm,vexpress-amp",
> +		.data = &vexpress_hwmon_amp,
> +	}, {
> +		.compatible = "arm,vexpress-temp",
> +		.data = &vexpress_hwmon_temp,
> +	}, {
> +		.compatible = "arm,vexpress-power",
> +		.data = &vexpress_hwmon_power,
> +	}, {
> +		.compatible = "arm,vexpress-energy",
> +		.data = &vexpress_hwmon_energy,
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, vexpress_hwmon_of_match);
> +
> +static int vexpress_hwmon_probe(struct platform_device *pdev)
> +{
> +	int err;
> +	const struct of_device_id *match;
> +	struct vexpress_hwmon_func *hwmon_func;
> +	struct device *hwmon_dev;
> +	struct vexpress_hwmon_attrs *attrs;
> +	const char *attr_name;
> +	int attr_index;
> +
> +	match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	if (!match) {
> +		err = -EINVAL;
> +		goto error_match_device;
> +	}
> +	hwmon_func = match->data;
> +
> +	hwmon_dev = vexpress_hwmon_dev_get();
> +	if (IS_ERR(hwmon_dev)) {
> +		err = PTR_ERR(hwmon_dev);
> +		goto error_hwmon_dev_get;
> +	}
> +
> +	attrs = devm_kzalloc(&pdev->dev, sizeof(*attrs), GFP_KERNEL);
> +	if (!attrs) {
> +		err = -ENOMEM;
> +		goto error_kzalloc;
> +	}
> +
> +	attrs->func = vexpress_config_func_get_by_dev(&pdev->dev);
> +	if (!attrs->func) {
> +		err = -ENXIO;
> +		goto error_get_func;
> +	}
> +
> +	err = sysfs_create_link(&pdev->dev.kobj, &hwmon_dev->kobj, "hwmon");
> +	if (err)
> +		goto error_create_link;
> +
> +	attr_index = atomic_inc_return(&hwmon_func->index);
> +	attr_name = hwmon_func->name;
> +
> +	snprintf(attrs->input_name, sizeof(attrs->input_name),
> +			"%s%d_input", attr_name, attr_index);
> +	attrs->input_attr.attr.name = attrs->input_name;
> +	attrs->input_attr.attr.mode = 0444;
> +	if (hwmon_func->wide)
> +		attrs->input_attr.show = vexpress_hwmon_u64_show;
> +	else
> +		attrs->input_attr.show = vexpress_hwmon_u32_show;
> +	sysfs_attr_init(&attrs->input_attr.attr);
> +	err = device_create_file(hwmon_dev, &attrs->input_attr);
> +	if (err)
> +		goto error_create_input;
> +
and a highly unusual way of, as much as I understand of it, bypass the hwmon
infrastructure as much as possible.

I don't even understand what you are trying to do, much less why you don't
just use the existing infrastructure, and I don't have time to try to figure
it out. Maybe Jean has time to review this driver, but not me.

So, no, for my part I don't think it would be a good idea to rush this driver
into 3.7.

Really, I would suggest to submit a standard hwmon driver (there are lots of
examples out there).

Guenter

> +	attrs->label = of_get_property(pdev->dev.of_node, "label", NULL);
> +	if (attrs->label) {
> +		snprintf(attrs->label_name, sizeof(attrs->label_name),
> +				"%s%d_label", attr_name, attr_index);
> +		attrs->label_attr.attr.name = attrs->label_name;
> +		attrs->label_attr.attr.mode = 0444;
> +		attrs->label_attr.show = vexpress_hwmon_label_show;
> +		sysfs_attr_init(&attrs->label_attr.attr);
> +		err = device_create_file(hwmon_dev, &attrs->label_attr);
> +		if (err)
> +			goto error_create_label;
> +	}
> +
> +	attrs->divisor = hwmon_func->divisor;
> +
> +	platform_set_drvdata(pdev, attrs);
> +
> +	return 0;
> +
> +error_create_label:
> +	device_remove_file(hwmon_dev, &attrs->input_attr);
> +error_create_input:
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +error_create_link:
> +	vexpress_config_func_put(attrs->func);
> +error_get_func:
> +error_kzalloc:
> +	vexpress_hwmon_dev_put();
> +error_hwmon_dev_get:
> +error_match_device:
> +	return err;
> +}
> +
> +static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
> +{
> +	struct vexpress_hwmon_attrs *attrs = platform_get_drvdata(pdev);
> +	const struct of_device_id *match =
> +		of_match_device(vexpress_hwmon_of_match, &pdev->dev);
> +	struct vexpress_hwmon_func *hwmon_func = match->data;
> +
> +	if (attrs->label)
> +		device_remove_file(vexpress_hwmon_dev, &attrs->label_attr);
> +	device_remove_file(vexpress_hwmon_dev, &attrs->input_attr);
> +	atomic_dec(&hwmon_func->index);
> +	sysfs_remove_link(&pdev->dev.kobj, "hwmon");
> +	vexpress_config_func_put(attrs->func);
> +	vexpress_hwmon_dev_put();
> +
> +	return 0;
> +}
> +
> +static struct platform_driver vexpress_hwmon_driver = {
> +	.probe = vexpress_hwmon_probe,
> +	.remove = __devexit_p(vexpress_hwmon_remove),
> +	.driver	= {
> +		.name = DRVNAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = vexpress_hwmon_of_match,
> +	},
> +};
> +
> +static int __init vexpress_hwmon_init(void)
> +{
> +	return platform_driver_register(&vexpress_hwmon_driver);
> +}
> +
> +static void __exit vexpress_hwmon_exit(void)
> +{
> +	platform_driver_unregister(&vexpress_hwmon_driver);
> +}
> +
> +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
> +MODULE_DESCRIPTION("Versatile Express hwmon");
> +MODULE_LICENSE("GPL");
> +
> +module_init(vexpress_hwmon_init);
> +module_exit(vexpress_hwmon_exit);
> -- 
> 1.7.9.5
> 
> 
> 

  reply	other threads:[~2012-09-18 15:24 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-18 14:17 [PATCH v2 00/13] Versatile Express infrastructure Pawel Moll
2012-09-18 14:17 ` [PATCH v2 01/13] input: ambakmi: (Un)prepare clocks when (dis)enabling Pawel Moll
2012-09-18 14:17   ` Pawel Moll
2012-09-18 14:17 ` [PATCH v2 02/13] video: Versatile Express display output driver Pawel Moll
2012-09-18 14:17   ` Pawel Moll
2012-09-18 14:17 ` [lm-sensors] [PATCH v2 03/13] hwmon: Versatile Express hwmon driver Pawel Moll
2012-09-18 14:17   ` Pawel Moll
2012-09-18 15:24   ` Guenter Roeck [this message]
2012-09-18 15:24     ` Guenter Roeck
2012-09-18 15:45     ` [lm-sensors] " Jean Delvare
2012-09-18 15:45       ` Jean Delvare
2012-09-18 20:59       ` [lm-sensors] " Guenter Roeck
2012-09-18 20:59         ` Guenter Roeck
2012-09-19 17:04     ` [lm-sensors] " Pawel Moll
2012-09-19 17:04       ` Pawel Moll
2012-09-20  2:03       ` [lm-sensors] " Guenter Roeck
2012-09-20  2:03         ` Guenter Roeck
2012-09-18 14:17 ` [PATCH v2 04/13] regulators: Versatile Express regulator driver Pawel Moll
2012-09-18 15:02   ` Mark Brown
2012-09-18 15:44     ` Pawel Moll
2012-09-18 16:09       ` Mark Brown
2012-09-18 17:03         ` Pawel Moll
2012-09-19  2:21           ` Mark Brown
2012-09-19 16:58             ` Pawel Moll
2012-09-20 13:01               ` Mark Brown
2012-09-20 17:34                 ` Pawel Moll
2012-09-20 18:15                   ` Mark Brown
2012-09-18 14:17 ` [PATCH v2 05/13] clk: Versatile Express clock generators ("osc") driver Pawel Moll
2012-10-29 17:44   ` Mike Turquette
2012-09-18 14:17 ` [PATCH v2 06/13] clk: Common clocks implementation for Versatile Express Pawel Moll
2012-09-18 14:17 ` [PATCH v2 07/13] misc: Versatile Express config infrastructure Pawel Moll
2012-09-19 13:08   ` Arnd Bergmann
2012-09-20 12:06     ` Pawel Moll
2012-09-20 12:36       ` Arnd Bergmann
2012-09-20 12:37         ` Pawel Moll
2012-09-18 14:17 ` [PATCH v2 08/13] mfd: Versatile Express system registers driver Pawel Moll
2012-09-18 15:24   ` Arnd Bergmann
2012-09-19 10:53     ` Pawel Moll
2012-09-19 11:17       ` Arnd Bergmann
2012-09-19 11:17         ` Arnd Bergmann
2012-09-19 11:45         ` Pawel Moll
2012-09-19 11:45           ` Pawel Moll
2012-09-18 14:17 ` [PATCH v2 09/13] ARM: vexpress: Reset driver Pawel Moll
2012-09-18 14:17 ` [PATCH v2 10/13] ARM: vexpress: Add config bus components and clocks to DTs Pawel Moll
2012-09-18 14:17 ` [PATCH v2 11/13] ARM: vexpress: Start using new Versatile Express infrastructure Pawel Moll
2012-09-18 14:17 ` [PATCH v2 12/13] ARM: vexpress: Remove motherboard dependencies in the DTS files Pawel Moll
2012-09-18 14:17 ` [PATCH v2 13/13] ARM: vexpress: Make the DEBUG_LL UART detection more specific Pawel Moll

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120918152430.GA5911@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.