All of lore.kernel.org
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Lars-Peter Clausen <lars@metafoo.de>
Cc: Anthony Olech <anthony.olech.opensource@diasemi.com>,
	Jean Delvare <khali@linux-fr.org>,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Randy Dunlap <rdunlap@xenotime.net>,
	lm-sensors@lm-sensors.org, LKML <linux-kernel@vger.kernel.org>,
	David Dajun Chen <david.chen@diasemi.com>
Subject: Re: [lm-sensors] [NEW DRIVER V6 6/7] drivers/hwmon: DA9058 HWMON driver
Date: Sat, 20 Apr 2013 17:35:13 +0000	[thread overview]
Message-ID: <20130420173513.GA8275@roeck-us.net> (raw)
In-Reply-To: <51718BFE.7060409@metafoo.de>

On Fri, Apr 19, 2013 at 08:25:02PM +0200, Lars-Peter Clausen wrote:
> Same comment as before, I'd like to see this using the generic IIO to HWMON
> bridge instead of recreating it.
> 
... and I agree. Seems we are getting more and more of those, and at some point
it makes really sense to find a generic solution.

Anthony, can you please look into that ?

Thanks,
Guenter


> On 04/19/2013 06:56 PM, Anthony Olech wrote:
> > This patch is relative to next-20130419 of linux-next
> > 
> > This is the HWMON component driver of the Dialog DA9058 PMIC.
> > This driver is just one component of the whole DA9058 PMIC driver.
> > It depends on the CORE and ADC component drivers of the DA9058 MFD.
> > 
> > Please note that this driver does use regmap via the CORE and ADC
> > component drivers of the DA9058 MFD.
> > 
> > Changes relative to V5 of this patch:
> > - rebased to next-20130419 in git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
> > - removed redundant #include <linux/mfd/da9058/version.h>
> > - corrected dates on copyright statements
> > Documentation/hwmon/da9058
> > - removed trailing blank line to prevent 'git apply' warning
> > drivers/hwmon/da9058-hwmon.c
> > - put spaces aount the '*' multiply operator
> > - use the word 'extract' rather than 'recover' in a comment
> > - use da9058_labels[] in show_label instead of switch case
> > - use multiple exit points in functions when no common code
> >   is to be executed.
> > - aligned continuation lines to preceeding '(' or indent + 2 tabs
> > - removed redundant mutex hwmon_lock
> > - merged 6 duplicate lines from 2 branches of if statement
> > 
> > Signed-off-by: Anthony Olech <anthony.olech.opensource@diasemi.com>
> > Signed-off-by: David Dajun Chen <david.chen@diasemi.com>
> > ---
> >  Documentation/hwmon/da9058   |   38 +++++
> >  drivers/hwmon/Kconfig        |   10 ++
> >  drivers/hwmon/Makefile       |    3 +-
> >  drivers/hwmon/da9058-hwmon.c |  330 ++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 380 insertions(+), 1 deletion(-)
> >  create mode 100644 Documentation/hwmon/da9058
> >  create mode 100644 drivers/hwmon/da9058-hwmon.c
> > 
> > diff --git a/Documentation/hwmon/da9058 b/Documentation/hwmon/da9058
> > new file mode 100644
> > index 0000000..841148f
> > --- /dev/null
> > +++ b/Documentation/hwmon/da9058
> > @@ -0,0 +1,38 @@
> > +Kernel driver da9058-hwmon
> > +=============
> > +
> > +Supported chips:
> > +  * Dialog Semiconductor DA9058 PMIC
> > +    Prefix: 'da9058'
> > +    Datasheet:
> > +	http://www.dialog-semiconductor.com/products/power-management/da9058
> > +
> > +Authors: Opensource [Anthony Olech] <anthony.olech.opensource@diasemi.com>
> > +
> > +Description
> > +-----------
> > +
> > +The DA9058 PMIC contains a 5 channel ADC which can be used to monitor a
> > +range of system operating parameters, including the battery voltage and
> > +temperature.  The ADC measures voltage, but two of the ADC channels can
> > +be configured to supply a current, so that if an NTC termister is connected
> > +then the voltage reading can be converted to a temperature. Currently the
> > +driver provides reporting of all the input values but does not provide any
> > +alarms.
> > +
> > +Voltage Monitoring
> > +------------------
> > +
> > +Voltages are sampled in either 'automatic' or 'manual' mode, which is an
> > +initialization parameter set in the platform data by the machine driver.
> > +In manual mode the ADC conversion is 12 bit and in automatic mode it is
> > +10 bit. However all the raw readings are reported as 12 bit numbers.
> > +
> > +Physical Limits
> > +---------------
> > +
> > +vbat   2500 - 4500 milliVolts
> > +tbat   0    - 2500 milliVolts
> > +adc    0    - 2500 milliVolts
> > +vfpin  0    - 4095 milliVolts
> > +tjunc  there is a correction factor programmed during manufacturing
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 79bc431..cb074c4 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -337,6 +337,16 @@ config SENSORS_ATXP1
> >  	  This driver can also be built as a module.  If so, the module
> >  	  will be called atxp1.
> >  
> > +config SENSORS_DA9058
> > +	tristate "Dialog Semiconductor DA9058 ADC"
> > +	depends on MFD_DA9058 && DA9058_ADC
> > +	help
> > +	  If you say yes here you get support for the hardware monitoring
> > +	  functionality of the Dialog Semiconductor DA9058 PMIC.
> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called da9058-hwmon.
> > +
> >  config SENSORS_DS620
> >  	tristate "Dallas Semiconductor DS620"
> >  	depends on I2C
> > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> > index d17d3e6..6001549 100644
> > --- a/drivers/hwmon/Makefile
> > +++ b/drivers/hwmon/Makefile
> > @@ -47,7 +47,8 @@ obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
> >  obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
> >  obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
> >  obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
> > -obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
> > +obj-$(CONFIG_SENSORS_DA9055)	+= da9055-hwmon.o
> > +obj-$(CONFIG_SENSORS_DA9058)	+= da9058-hwmon.o
> >  obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
> >  obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
> >  obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
> > diff --git a/drivers/hwmon/da9058-hwmon.c b/drivers/hwmon/da9058-hwmon.c
> > new file mode 100644
> > index 0000000..ff3fcbf
> > --- /dev/null
> > +++ b/drivers/hwmon/da9058-hwmon.c
> > @@ -0,0 +1,330 @@
> > +/*
> > + *  Copyright (C) 2012, 2013 Dialog Semiconductor Ltd.
> > + *
> > + *  This program is free software; you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation; either version 2 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/err.h>
> > +#include <linux/hwmon.h>
> > +#include <linux/hwmon-sysfs.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mfd/core.h>
> > +
> > +#include <linux/mfd/da9058/registers.h>
> > +#include <linux/mfd/da9058/core.h>
> > +#include <linux/mfd/da9058/hwmon.h>
> > +
> > +static ssize_t da9058_vbat_show_adc(struct device *dev,
> > +				    struct device_attribute *devattr,
> > +				    char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 2500 .. 4500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_VBAT,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", 2500 + voltage * 2000 / 0xFFF);
> > +}
> > +
> > +static ssize_t da9058_tbat_show_type(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +
> > +	return sprintf(buf, "%d\n", hwmon->battery_sensor_type);
> > +}
> > +
> > +static ssize_t da9058_tbat_show_adc(struct device *dev,
> > +				    struct device_attribute *devattr,
> > +				    char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 0 .. 2500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_TEMP,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", voltage * 2500 / 0xFFF);
> > +}
> > +
> > +static ssize_t da9058_gp_show_adc(struct device *dev,
> > +				  struct device_attribute *devattr,
> > +				  char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* xFFF .. x800 = 0 .. 2500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_ADCIN,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", (0xFFF - voltage) * 2500 / 0x7FF);
> > +}
> > +
> > +static ssize_t da9058_tjunc_show_min(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", -(1708 * (s8)((u8)toffreg) + 108800));
> > +}
> > +
> > +static ssize_t da9058_tjunc_show_max(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", 1708 * (255 - (s8)((u8)toffreg)) - 108800);
> > +}
> > +
> > +/*
> > + *  The algorithm for converting the value is
> > + *  Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
> > + *  T_OFFSET is a trim value used to improve accuracy of the result
> > + */
> > +static ssize_t da9058_tjunc_show_adc(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	int tjunc;
> > +	unsigned int toffreg;
> > +	int ret;
> > +
> > +	ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_TJUNC,
> > +			      hwmon->use_automatic_adc, &tjunc);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	tjunc >>= 4;	/* extract most sig 8 bits as a pos/zero number */
> > +
> > +	return sprintf(buf, "%d\n",
> > +		       1708 * (tjunc - (s8)((u8)toffreg)) - 108800);
> > +}
> > +static ssize_t da9058_tjunc_show_offset(struct device *dev,
> > +					struct device_attribute *devattr,
> > +					char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret;
> > +
> > +	ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", -1708 * (s8)((u8)toffreg) - 108800);
> > +}
> > +
> > +static ssize_t da9058_vfpin_show_adc(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 0 .. 4095 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_VF,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", voltage);
> > +}
> > +
> > +static ssize_t da9058_hwmon_show_name(struct device *dev,
> > +				      struct device_attribute *devattr,
> > +				      char *buf)
> > +{
> > +	return sprintf(buf, "da9058\n");
> > +}
> > +
> > +static const char * const da9058_labels[] = {
> > +	"vbat", "tbat", "vfpin", "adc", "tjunc",
> > +};
> > +
> > +static ssize_t da9058_show_label(struct device *dev,
> > +				 struct device_attribute *devattr,
> > +				 char *buf)
> > +{
> > +	unsigned int channel = to_sensor_dev_attr(devattr)->index;
> > +
> > +	if (channel < ARRAY_SIZE(da9058_labels))
> > +		return sprintf(buf, "%s\n", da9058_labels[channel]);
> > +	else
> > +		return -EINVAL;
> > +}
> > +
> > +static DEVICE_ATTR(name, S_IRUGO, da9058_hwmon_show_name, NULL);
> > +
> > +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, da9058_show_label, NULL, 0);
> > +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9058_vbat_show_adc, NULL, 0);
> > +
> > +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, da9058_show_label, NULL, 1);
> > +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, da9058_tbat_show_type, NULL, 1);
> > +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9058_tbat_show_adc, NULL, 1);
> > +
> > +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, da9058_show_label, NULL, 2);
> > +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9058_vfpin_show_adc, NULL, 2);
> > +
> > +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, da9058_show_label, NULL, 3);
> > +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9058_gp_show_adc, NULL, 3);
> > +
> > +static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, da9058_show_label, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, da9058_tjunc_show_min, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, da9058_tjunc_show_max, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, da9058_tjunc_show_adc, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_offset, S_IRUGO, da9058_tjunc_show_offset, NULL,
> > +			  4);
> > +
> > +static struct attribute *da9058_attr[] = {
> > +	&dev_attr_name.attr,
> > +	&sensor_dev_attr_in0_label.dev_attr.attr,
> > +	&sensor_dev_attr_in0_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_label.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_type.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> > +	&sensor_dev_attr_in1_label.dev_attr.attr,
> > +	&sensor_dev_attr_in1_input.dev_attr.attr,
> > +	&sensor_dev_attr_in2_label.dev_attr.attr,
> > +	&sensor_dev_attr_in2_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_label.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_min.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_max.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_offset.dev_attr.attr,
> > +	NULL
> > +};
> > +
> > +static const struct attribute_group da9058_attr_group = {.attrs = da9058_attr};
> > +
> > +static int da9058_hwmon_probe(struct platform_device *pdev)
> > +{
> > +	struct da9058 *da9058 = dev_get_drvdata(pdev->dev.parent);
> > +	const struct mfd_cell *cell = mfd_get_cell(pdev);
> > +	struct da9058_hwmon_pdata *hwmon_pdata;
> > +	struct da9058_hwmon *hwmon;
> > +	unsigned int mode;
> > +	int ret;
> > +
> > +	if (cell = NULL)
> > +		return -ENODEV;
> > +
> > +	hwmon_pdata = cell->platform_data;
> > +
> > +	if (hwmon_pdata = NULL)
> > +		return -EINVAL;
> > +
> > +	if (hwmon_pdata->use_automatic_adc &&
> > +	    !hwmon_pdata->temp_adc_resistance)
> > +		return -EINVAL; /* impossible setting */
> > +
> > +	hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9058_hwmon),
> > +			     GFP_KERNEL);
> > +	if (!hwmon)
> > +		return -ENOMEM;
> > +
> > +	platform_set_drvdata(pdev, hwmon);
> > +
> > +	hwmon->da9058 = da9058;
> > +	hwmon->pdev = pdev;
> > +	hwmon->use_automatic_adc = hwmon_pdata->use_automatic_adc;
> > +	hwmon->temp_adc_resistance = hwmon_pdata->temp_adc_resistance;
> > +	hwmon->vf_adc_resistance = hwmon_pdata->vf_adc_resistance;
> > +	hwmon->battery_sensor_type = hwmon_pdata->battery_sensor_type;
> > +
> > +	if (hwmon->use_automatic_adc) {
> > +		mode = DA9058_ADCCONT_AUTOADCEN |
> > +				DA9058_ADCCONT_TEMPISRCEN |
> > +				DA9058_ADCCONT_AUTOVBATEN |
> > +				DA9058_ADCCONT_AUTOVFEN |
> > +				DA9058_ADCCONT_AUTOAINEN;
> > +	} else {
> > +		if (hwmon->temp_adc_resistance)
> > +			mode = DA9058_ADCCONT_TEMPISRCEN;
> > +		else
> > +			mode = 0;
> > +	}
> > +	if (hwmon->vf_adc_resistance)
> > +		mode |= DA9058_ADCCONT_VFISRCEN;
> > +
> > +	ret = da9058_reg_write(da9058, DA9058_ADCCONT_REG, mode);
> > +	if (ret)
> > +		return ret;
> > +
> > +	hwmon->class_device = hwmon_device_register(&pdev->dev);
> > +	if (IS_ERR(hwmon->class_device)) {
> > +		ret = PTR_ERR(hwmon->class_device);
> > +		goto failed_to_register_device;
> > +	}
> > +
> > +	ret = sysfs_create_group(&pdev->dev.kobj, &da9058_attr_group);
> > +	if (ret)
> > +		goto failed_to_create_sysfs_group;
> > +
> > +	return ret;
> > +
> > +failed_to_create_sysfs_group:
> > +	hwmon_device_unregister(hwmon->class_device);
> > +failed_to_register_device:
> > +	sysfs_remove_group(&pdev->dev.kobj, &da9058_attr_group);
> > +	return ret;
> > +}
> > +
> > +static int da9058_hwmon_remove(struct platform_device *pdev)
> > +{
> > +	struct da9058_hwmon *hwmon = platform_get_drvdata(pdev);
> > +
> > +	sysfs_remove_group(&pdev->dev.kobj, &da9058_attr_group);
> > +
> > +	hwmon_device_unregister(hwmon->class_device);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver da9058_hwmon_driver = {
> > +	.probe = da9058_hwmon_probe,
> > +	.remove = da9058_hwmon_remove,
> > +	.driver = {
> > +		.name = "da9058-hwmon",
> > +		.owner = THIS_MODULE,
> > +	},
> > +};
> > +
> > +module_platform_driver(da9058_hwmon_driver);
> > +
> > +MODULE_DESCRIPTION("Dialog DA9058 PMIC HardWare Monitor Driver");
> > +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_ALIAS("platform:da9058-hwmon");
> 
> 

_______________________________________________
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: Guenter Roeck <linux@roeck-us.net>
To: Lars-Peter Clausen <lars@metafoo.de>
Cc: Anthony Olech <anthony.olech.opensource@diasemi.com>,
	Jean Delvare <khali@linux-fr.org>,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Randy Dunlap <rdunlap@xenotime.net>,
	lm-sensors@lm-sensors.org, LKML <linux-kernel@vger.kernel.org>,
	David Dajun Chen <david.chen@diasemi.com>
Subject: Re: [NEW DRIVER V6 6/7] drivers/hwmon: DA9058 HWMON driver
Date: Sat, 20 Apr 2013 10:35:13 -0700	[thread overview]
Message-ID: <20130420173513.GA8275@roeck-us.net> (raw)
In-Reply-To: <51718BFE.7060409@metafoo.de>

On Fri, Apr 19, 2013 at 08:25:02PM +0200, Lars-Peter Clausen wrote:
> Same comment as before, I'd like to see this using the generic IIO to HWMON
> bridge instead of recreating it.
> 
... and I agree. Seems we are getting more and more of those, and at some point
it makes really sense to find a generic solution.

Anthony, can you please look into that ?

Thanks,
Guenter


> On 04/19/2013 06:56 PM, Anthony Olech wrote:
> > This patch is relative to next-20130419 of linux-next
> > 
> > This is the HWMON component driver of the Dialog DA9058 PMIC.
> > This driver is just one component of the whole DA9058 PMIC driver.
> > It depends on the CORE and ADC component drivers of the DA9058 MFD.
> > 
> > Please note that this driver does use regmap via the CORE and ADC
> > component drivers of the DA9058 MFD.
> > 
> > Changes relative to V5 of this patch:
> > - rebased to next-20130419 in git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
> > - removed redundant #include <linux/mfd/da9058/version.h>
> > - corrected dates on copyright statements
> > Documentation/hwmon/da9058
> > - removed trailing blank line to prevent 'git apply' warning
> > drivers/hwmon/da9058-hwmon.c
> > - put spaces aount the '*' multiply operator
> > - use the word 'extract' rather than 'recover' in a comment
> > - use da9058_labels[] in show_label instead of switch case
> > - use multiple exit points in functions when no common code
> >   is to be executed.
> > - aligned continuation lines to preceeding '(' or indent + 2 tabs
> > - removed redundant mutex hwmon_lock
> > - merged 6 duplicate lines from 2 branches of if statement
> > 
> > Signed-off-by: Anthony Olech <anthony.olech.opensource@diasemi.com>
> > Signed-off-by: David Dajun Chen <david.chen@diasemi.com>
> > ---
> >  Documentation/hwmon/da9058   |   38 +++++
> >  drivers/hwmon/Kconfig        |   10 ++
> >  drivers/hwmon/Makefile       |    3 +-
> >  drivers/hwmon/da9058-hwmon.c |  330 ++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 380 insertions(+), 1 deletion(-)
> >  create mode 100644 Documentation/hwmon/da9058
> >  create mode 100644 drivers/hwmon/da9058-hwmon.c
> > 
> > diff --git a/Documentation/hwmon/da9058 b/Documentation/hwmon/da9058
> > new file mode 100644
> > index 0000000..841148f
> > --- /dev/null
> > +++ b/Documentation/hwmon/da9058
> > @@ -0,0 +1,38 @@
> > +Kernel driver da9058-hwmon
> > +==========================
> > +
> > +Supported chips:
> > +  * Dialog Semiconductor DA9058 PMIC
> > +    Prefix: 'da9058'
> > +    Datasheet:
> > +	http://www.dialog-semiconductor.com/products/power-management/da9058
> > +
> > +Authors: Opensource [Anthony Olech] <anthony.olech.opensource@diasemi.com>
> > +
> > +Description
> > +-----------
> > +
> > +The DA9058 PMIC contains a 5 channel ADC which can be used to monitor a
> > +range of system operating parameters, including the battery voltage and
> > +temperature.  The ADC measures voltage, but two of the ADC channels can
> > +be configured to supply a current, so that if an NTC termister is connected
> > +then the voltage reading can be converted to a temperature. Currently the
> > +driver provides reporting of all the input values but does not provide any
> > +alarms.
> > +
> > +Voltage Monitoring
> > +------------------
> > +
> > +Voltages are sampled in either 'automatic' or 'manual' mode, which is an
> > +initialization parameter set in the platform data by the machine driver.
> > +In manual mode the ADC conversion is 12 bit and in automatic mode it is
> > +10 bit. However all the raw readings are reported as 12 bit numbers.
> > +
> > +Physical Limits
> > +---------------
> > +
> > +vbat   2500 - 4500 milliVolts
> > +tbat   0    - 2500 milliVolts
> > +adc    0    - 2500 milliVolts
> > +vfpin  0    - 4095 milliVolts
> > +tjunc  there is a correction factor programmed during manufacturing
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 79bc431..cb074c4 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -337,6 +337,16 @@ config SENSORS_ATXP1
> >  	  This driver can also be built as a module.  If so, the module
> >  	  will be called atxp1.
> >  
> > +config SENSORS_DA9058
> > +	tristate "Dialog Semiconductor DA9058 ADC"
> > +	depends on MFD_DA9058 && DA9058_ADC
> > +	help
> > +	  If you say yes here you get support for the hardware monitoring
> > +	  functionality of the Dialog Semiconductor DA9058 PMIC.
> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called da9058-hwmon.
> > +
> >  config SENSORS_DS620
> >  	tristate "Dallas Semiconductor DS620"
> >  	depends on I2C
> > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> > index d17d3e6..6001549 100644
> > --- a/drivers/hwmon/Makefile
> > +++ b/drivers/hwmon/Makefile
> > @@ -47,7 +47,8 @@ obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
> >  obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
> >  obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
> >  obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
> > -obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
> > +obj-$(CONFIG_SENSORS_DA9055)	+= da9055-hwmon.o
> > +obj-$(CONFIG_SENSORS_DA9058)	+= da9058-hwmon.o
> >  obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
> >  obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
> >  obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
> > diff --git a/drivers/hwmon/da9058-hwmon.c b/drivers/hwmon/da9058-hwmon.c
> > new file mode 100644
> > index 0000000..ff3fcbf
> > --- /dev/null
> > +++ b/drivers/hwmon/da9058-hwmon.c
> > @@ -0,0 +1,330 @@
> > +/*
> > + *  Copyright (C) 2012, 2013 Dialog Semiconductor Ltd.
> > + *
> > + *  This program is free software; you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation; either version 2 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/err.h>
> > +#include <linux/hwmon.h>
> > +#include <linux/hwmon-sysfs.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mfd/core.h>
> > +
> > +#include <linux/mfd/da9058/registers.h>
> > +#include <linux/mfd/da9058/core.h>
> > +#include <linux/mfd/da9058/hwmon.h>
> > +
> > +static ssize_t da9058_vbat_show_adc(struct device *dev,
> > +				    struct device_attribute *devattr,
> > +				    char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 2500 .. 4500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_VBAT,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", 2500 + voltage * 2000 / 0xFFF);
> > +}
> > +
> > +static ssize_t da9058_tbat_show_type(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +
> > +	return sprintf(buf, "%d\n", hwmon->battery_sensor_type);
> > +}
> > +
> > +static ssize_t da9058_tbat_show_adc(struct device *dev,
> > +				    struct device_attribute *devattr,
> > +				    char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 0 .. 2500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_TEMP,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", voltage * 2500 / 0xFFF);
> > +}
> > +
> > +static ssize_t da9058_gp_show_adc(struct device *dev,
> > +				  struct device_attribute *devattr,
> > +				  char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* xFFF .. x800 = 0 .. 2500 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_ADCIN,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", (0xFFF - voltage) * 2500 / 0x7FF);
> > +}
> > +
> > +static ssize_t da9058_tjunc_show_min(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", -(1708 * (s8)((u8)toffreg) + 108800));
> > +}
> > +
> > +static ssize_t da9058_tjunc_show_max(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", 1708 * (255 - (s8)((u8)toffreg)) - 108800);
> > +}
> > +
> > +/*
> > + *  The algorithm for converting the value is
> > + *  Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
> > + *  T_OFFSET is a trim value used to improve accuracy of the result
> > + */
> > +static ssize_t da9058_tjunc_show_adc(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	int tjunc;
> > +	unsigned int toffreg;
> > +	int ret;
> > +
> > +	ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_TJUNC,
> > +			      hwmon->use_automatic_adc, &tjunc);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	tjunc >>= 4;	/* extract most sig 8 bits as a pos/zero number */
> > +
> > +	return sprintf(buf, "%d\n",
> > +		       1708 * (tjunc - (s8)((u8)toffreg)) - 108800);
> > +}
> > +static ssize_t da9058_tjunc_show_offset(struct device *dev,
> > +					struct device_attribute *devattr,
> > +					char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int toffreg;
> > +	int ret;
> > +
> > +	ret = da9058_reg_read(hwmon->da9058, DA9058_TOFFSET_REG, &toffreg);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", -1708 * (s8)((u8)toffreg) - 108800);
> > +}
> > +
> > +static ssize_t da9058_vfpin_show_adc(struct device *dev,
> > +				     struct device_attribute *devattr,
> > +				     char *buf)
> > +{
> > +	struct da9058_hwmon *hwmon = dev_get_drvdata(dev);
> > +	unsigned int voltage; /* x000 .. xFFF = 0 .. 4095 mV */
> > +	int ret;
> > +
> > +	ret = da9058_adc_read(hwmon->da9058, DA9058_ADCMAN_MUXSEL_VF,
> > +			      hwmon->use_automatic_adc, &voltage);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%d\n", voltage);
> > +}
> > +
> > +static ssize_t da9058_hwmon_show_name(struct device *dev,
> > +				      struct device_attribute *devattr,
> > +				      char *buf)
> > +{
> > +	return sprintf(buf, "da9058\n");
> > +}
> > +
> > +static const char * const da9058_labels[] = {
> > +	"vbat", "tbat", "vfpin", "adc", "tjunc",
> > +};
> > +
> > +static ssize_t da9058_show_label(struct device *dev,
> > +				 struct device_attribute *devattr,
> > +				 char *buf)
> > +{
> > +	unsigned int channel = to_sensor_dev_attr(devattr)->index;
> > +
> > +	if (channel < ARRAY_SIZE(da9058_labels))
> > +		return sprintf(buf, "%s\n", da9058_labels[channel]);
> > +	else
> > +		return -EINVAL;
> > +}
> > +
> > +static DEVICE_ATTR(name, S_IRUGO, da9058_hwmon_show_name, NULL);
> > +
> > +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, da9058_show_label, NULL, 0);
> > +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9058_vbat_show_adc, NULL, 0);
> > +
> > +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, da9058_show_label, NULL, 1);
> > +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, da9058_tbat_show_type, NULL, 1);
> > +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9058_tbat_show_adc, NULL, 1);
> > +
> > +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, da9058_show_label, NULL, 2);
> > +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9058_vfpin_show_adc, NULL, 2);
> > +
> > +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, da9058_show_label, NULL, 3);
> > +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9058_gp_show_adc, NULL, 3);
> > +
> > +static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, da9058_show_label, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, da9058_tjunc_show_min, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, da9058_tjunc_show_max, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, da9058_tjunc_show_adc, NULL, 4);
> > +static SENSOR_DEVICE_ATTR(temp2_offset, S_IRUGO, da9058_tjunc_show_offset, NULL,
> > +			  4);
> > +
> > +static struct attribute *da9058_attr[] = {
> > +	&dev_attr_name.attr,
> > +	&sensor_dev_attr_in0_label.dev_attr.attr,
> > +	&sensor_dev_attr_in0_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_label.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_type.dev_attr.attr,
> > +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> > +	&sensor_dev_attr_in1_label.dev_attr.attr,
> > +	&sensor_dev_attr_in1_input.dev_attr.attr,
> > +	&sensor_dev_attr_in2_label.dev_attr.attr,
> > +	&sensor_dev_attr_in2_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_label.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_min.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_max.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_input.dev_attr.attr,
> > +	&sensor_dev_attr_temp2_offset.dev_attr.attr,
> > +	NULL
> > +};
> > +
> > +static const struct attribute_group da9058_attr_group = {.attrs = da9058_attr};
> > +
> > +static int da9058_hwmon_probe(struct platform_device *pdev)
> > +{
> > +	struct da9058 *da9058 = dev_get_drvdata(pdev->dev.parent);
> > +	const struct mfd_cell *cell = mfd_get_cell(pdev);
> > +	struct da9058_hwmon_pdata *hwmon_pdata;
> > +	struct da9058_hwmon *hwmon;
> > +	unsigned int mode;
> > +	int ret;
> > +
> > +	if (cell == NULL)
> > +		return -ENODEV;
> > +
> > +	hwmon_pdata = cell->platform_data;
> > +
> > +	if (hwmon_pdata == NULL)
> > +		return -EINVAL;
> > +
> > +	if (hwmon_pdata->use_automatic_adc &&
> > +	    !hwmon_pdata->temp_adc_resistance)
> > +		return -EINVAL; /* impossible setting */
> > +
> > +	hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9058_hwmon),
> > +			     GFP_KERNEL);
> > +	if (!hwmon)
> > +		return -ENOMEM;
> > +
> > +	platform_set_drvdata(pdev, hwmon);
> > +
> > +	hwmon->da9058 = da9058;
> > +	hwmon->pdev = pdev;
> > +	hwmon->use_automatic_adc = hwmon_pdata->use_automatic_adc;
> > +	hwmon->temp_adc_resistance = hwmon_pdata->temp_adc_resistance;
> > +	hwmon->vf_adc_resistance = hwmon_pdata->vf_adc_resistance;
> > +	hwmon->battery_sensor_type = hwmon_pdata->battery_sensor_type;
> > +
> > +	if (hwmon->use_automatic_adc) {
> > +		mode = DA9058_ADCCONT_AUTOADCEN |
> > +				DA9058_ADCCONT_TEMPISRCEN |
> > +				DA9058_ADCCONT_AUTOVBATEN |
> > +				DA9058_ADCCONT_AUTOVFEN |
> > +				DA9058_ADCCONT_AUTOAINEN;
> > +	} else {
> > +		if (hwmon->temp_adc_resistance)
> > +			mode = DA9058_ADCCONT_TEMPISRCEN;
> > +		else
> > +			mode = 0;
> > +	}
> > +	if (hwmon->vf_adc_resistance)
> > +		mode |= DA9058_ADCCONT_VFISRCEN;
> > +
> > +	ret = da9058_reg_write(da9058, DA9058_ADCCONT_REG, mode);
> > +	if (ret)
> > +		return ret;
> > +
> > +	hwmon->class_device = hwmon_device_register(&pdev->dev);
> > +	if (IS_ERR(hwmon->class_device)) {
> > +		ret = PTR_ERR(hwmon->class_device);
> > +		goto failed_to_register_device;
> > +	}
> > +
> > +	ret = sysfs_create_group(&pdev->dev.kobj, &da9058_attr_group);
> > +	if (ret)
> > +		goto failed_to_create_sysfs_group;
> > +
> > +	return ret;
> > +
> > +failed_to_create_sysfs_group:
> > +	hwmon_device_unregister(hwmon->class_device);
> > +failed_to_register_device:
> > +	sysfs_remove_group(&pdev->dev.kobj, &da9058_attr_group);
> > +	return ret;
> > +}
> > +
> > +static int da9058_hwmon_remove(struct platform_device *pdev)
> > +{
> > +	struct da9058_hwmon *hwmon = platform_get_drvdata(pdev);
> > +
> > +	sysfs_remove_group(&pdev->dev.kobj, &da9058_attr_group);
> > +
> > +	hwmon_device_unregister(hwmon->class_device);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver da9058_hwmon_driver = {
> > +	.probe = da9058_hwmon_probe,
> > +	.remove = da9058_hwmon_remove,
> > +	.driver = {
> > +		.name = "da9058-hwmon",
> > +		.owner = THIS_MODULE,
> > +	},
> > +};
> > +
> > +module_platform_driver(da9058_hwmon_driver);
> > +
> > +MODULE_DESCRIPTION("Dialog DA9058 PMIC HardWare Monitor Driver");
> > +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_ALIAS("platform:da9058-hwmon");
> 
> 

  reply	other threads:[~2013-04-20 17:35 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-19 16:56 [lm-sensors] [NEW DRIVER V6 6/7] drivers/hwmon: DA9058 HWMON driver Anthony Olech
2013-04-19 16:56 ` Anthony Olech
2013-04-19 16:56 ` [lm-sensors] " Anthony Olech
2013-04-19 16:56   ` Anthony Olech
2013-04-19 18:25   ` [lm-sensors] " Lars-Peter Clausen
2013-04-19 18:25     ` Lars-Peter Clausen
2013-04-20 17:35     ` Guenter Roeck [this message]
2013-04-20 17:35       ` Guenter Roeck
2013-04-22  1:14       ` [lm-sensors] " Opensource [Anthony Olech]
2013-04-22  1:14         ` Opensource [Anthony Olech]
2013-04-22  2:30         ` [lm-sensors] " Guenter Roeck
2013-04-22  2:30           ` Guenter Roeck

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=20130420173513.GA8275@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=anthony.olech.opensource@diasemi.com \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=david.chen@diasemi.com \
    --cc=khali@linux-fr.org \
    --cc=lars@metafoo.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lm-sensors@lm-sensors.org \
    --cc=rdunlap@xenotime.net \
    /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.