On Tue, May 15, 2012 at 10:26:48AM -0400, Jenny TC wrote: > Currently drivers are using custom APIs to communicate with ADC driver. > So it make sense to have generic APIs to commnicate with ADC drivers. > This patch introduces generic APIs to communicate with ADC drivers. > > Signed-off-by: Jenny TC <jenny.tc@xxxxxxxxx> Hi Jenny, Do you have a practical use case ? Also, shouldn't those generic ADCs rather be supported through the IO subsystem ? After all, hwmon is all about hardware monitoring, not to provide generic ADC access. Thanks, Guenter > --- > drivers/hwmon/Kconfig | 9 ++ > drivers/hwmon/Makefile | 1 + > drivers/hwmon/hwmon-adc.c | 212 +++++++++++++++++++++++++++++++++++++++++++++ > include/linux/hwmon-adc.h | 47 ++++++++++ > 4 files changed, 269 insertions(+), 0 deletions(-) > create mode 100644 drivers/hwmon/hwmon-adc.c > create mode 100644 include/linux/hwmon-adc.h > > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig > index 8deedc1..203ed9d 100644 > --- a/drivers/hwmon/Kconfig > +++ b/drivers/hwmon/Kconfig > @@ -37,6 +37,15 @@ config HWMON_DEBUG_CHIP > a problem with I2C support and want to see more of what is going > on. > > +config HWMON_ADC > + bool "Hardware Monitoring Generic ADC support" > + default n > + help > + Say Y here if you want the generic ADC support for Hardware Monitoring > + Subsystem. Select this to enable the generic ADC driver APIs. > + This enables a set of APIs to register an ADC device with hwmon > + subsystem along with generic APIs to communicate with ADC driver > + > comment "Native drivers" > > config SENSORS_ABITUGURU > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile > index 6d3f11f..d91450f 100644 > --- a/drivers/hwmon/Makefile > +++ b/drivers/hwmon/Makefile > @@ -4,6 +4,7 @@ > > obj-$(CONFIG_HWMON) += hwmon.o > obj-$(CONFIG_HWMON_VID) += hwmon-vid.o > +obj-$(CONFIG_HWMON_ADC) += hwmon-adc.o > > # APCI drivers > obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o > diff --git a/drivers/hwmon/hwmon-adc.c b/drivers/hwmon/hwmon-adc.c > new file mode 100644 > index 0000000..53c910e > --- /dev/null > +++ b/drivers/hwmon/hwmon-adc.c > @@ -0,0 +1,212 @@ > +/* > + * hwmon-adc.c - Generic adc support for hardware monitoring subsystem. > + * > + * Copyright (C) 2012 Intel Corp > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * > + * 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; version 2 of the License. > + * > + * 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., > + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * Author : Jenny TC <jenny.tc@xxxxxxxxx> > + */ > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/device.h> > +#include <linux/hwmon.h> > +#include <linux/hwmon-adc.h> > + > +LIST_HEAD(adc_lst); > +DEFINE_MUTEX(list_lock); > + > +struct hwmon_adc { > + struct device *hwdev; > + struct hwmon_adc_ops *adc_ops; > + struct list_head list; > +}; > + > +/** > + * hwmon_adc_device_register - register adc device w/ hwmon > + * @dev: the device to register > + * > + * hwmon_adc_device_unregister() must be called when the device is no > + * longer needed. > + * > + * Returns the pointer to the new device. > + */ > +struct device *hwmon_adc_device_register(struct device *dev, > + struct hwmon_adc_ops *adc_ops) > +{ > + struct hwmon_adc *adc_node; > + struct device *hwdev; > + > + hwdev = hwmon_device_register(dev); > + if (IS_ERR(hwdev)) > + return hwdev; > + > + adc_node = kzalloc(sizeof(struct hwmon_adc), GFP_ATOMIC); > + adc_node->hwdev = hwdev; > + adc_node->adc_ops = adc_ops; > + mutex_lock(&list_lock); > + list_add(&adc_node->list, &adc_lst); > + mutex_unlock(&list_lock); > + > + return hwdev; > +} > +EXPORT_SYMBOL(hwmon_adc_device_register); > + > +/** > + * hwmon_adc_device_unregister - removes the previously registered hwmon class device > + * > + * @dev: the class device to destroy > + */ > +void hwmon_adc_device_unregister(struct device *hwdev) > +{ > + > + struct list_head *p, *n; > + struct hwmon_adc *tmp; > + > + mutex_lock(&list_lock); > + list_for_each_safe(p, n, &adc_lst) { > + tmp = list_entry(p, struct hwmon_adc, list); > + if (tmp->hwdev == hwdev) { > + hwmon_device_unregister(hwdev); > + list_del(&tmp->list); > + kfree(tmp); > + break; > + } > + } > + mutex_unlock(&list_lock); > +} > +EXPORT_SYMBOL(hwmon_adc_device_unregister); > + > +static struct hwmon_adc_ops *__get_ops_byname(char *name) > +{ > + struct list_head *l; > + struct hwmon_adc *tmp; > + struct hwmon_adc_ops *ops = NULL; > + > + mutex_lock(&list_lock); > + list_for_each(l, &adc_lst) { > + tmp = list_entry(l, struct hwmon_adc, list); > + if (!strcmp(dev_driver_string(tmp->hwdev->parent), name)) { > + ops = tmp->adc_ops; > + break; > + } > + } > + mutex_unlock(&list_lock); > + return ops; > +} > + > +/** > + * hwmon_adc_read_adc_channel - read an ADC channel > + * @adc_name : adc device name > + * @channel : channel to read > + * @adc_val : pointer to store adc value > + * > + * Returns the return value from read_adc callback function on success > + * else return -ENODEV > + */ > +int hwmon_adc_read_channel(char *adc_name, int channel, unsigned int *adc_val) > +{ > + struct hwmon_adc_ops *adc_ops; > + > + adc_ops = __get_ops_byname(adc_name); > + > + if (adc_ops && adc_ops->read_adc) > + return adc_ops->read_adc(channel, adc_val); > + > + return -ENODEV; > +} > +EXPORT_SYMBOL(hwmon_adc_read_channel); > + > +/** > + * hwmon_adc_read_adc_channel - read multiple ADC channels > + * @adc_name : adc device name > + * @channel : channels to read > + * @adc_val : pointer to store adc values > + * @count : number of channels to read > + * > + * Returns the return value from read_adc_multi callback function on success > + * else return -ENODEV > + */ > +int hwmon_adc_read_channel_multi(char *adc_name, int *channel, > + unsigned int *adc_val, int count) > +{ > + struct hwmon_adc_ops *adc_ops; > + > + adc_ops = __get_ops_byname(adc_name); > + > + if (adc_ops && adc_ops->read_adc_multi) > + return adc_ops->read_adc_multi(channel, adc_val, count); > + > + return -ENODEV; > +} > +EXPORT_SYMBOL(hwmon_adc_read_channel_multi); > + > +/** > + * hwmon_adc_convert_channel - convert raw ADC value > + * to voltage/current/temperature etc. > + * > + * @adc_name : adc device name > + * @channel : channel to convert > + * @adc_val : adc value to convert > + * @cvtd_val : pointer to store converted value > + * > + * Returns the return value from convert_adcval callback function on success > + * else return -ENODEV > + */ > +int hwmon_adc_convert_adcval(char *adc_name, int channel, unsigned int adc_val, > + int *cvtd_val) > +{ > + struct hwmon_adc_ops *adc_ops; > + > + adc_ops = __get_ops_byname(adc_name); > + > + if (adc_ops && adc_ops->convert_adcval) > + return adc_ops->convert_adcval(channel, adc_val, cvtd_val); > + > + return -ENODEV; > + > +} > +EXPORT_SYMBOL(hwmon_adc_convert_adcval); > + > +/** > + * hwmon_adc_convert_channel - convert raw ADC value > + * to voltage/current/temperature etc. > + * > + * @adc_name : adc device name > + * @channel : channels to convert > + * @adc_val : adc values to convert > + * @cvtd_val : pointer to store converted values > + * @count : number of channels to convert > + * > + * Returns the return value from convert_adcval_multi callback function on > + * success else return -ENODEV > + */ > +int hwmon_adc_convert_adcval_multi(char *adc_name, int *channel, > + unsigned int *adc_val, int *cvtd_val, int count) > +{ > + > + struct hwmon_adc_ops *adc_ops; > + > + adc_ops = __get_ops_byname(adc_name); > + > + if (adc_ops && adc_ops->convert_adcval_multi) > + return adc_ops->convert_adcval_multi(channel, adc_val, cvtd_val, > + count); > + return -ENODEV; > +} > +EXPORT_SYMBOL(hwmon_adc_convert_adcval_multi); > diff --git a/include/linux/hwmon-adc.h b/include/linux/hwmon-adc.h > new file mode 100644 > index 0000000..c4e9fc0 > --- /dev/null > +++ b/include/linux/hwmon-adc.h > @@ -0,0 +1,47 @@ > +/* > + * hwmon-adc.h - Header file for hardware monitoring generic adc support. > + * > + * This file declares helper functions for generic adc support for hardware > + * monitoring subsystem. > + * > + * Copyright (C) 2012 Intel Corp > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * > + * 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; version 2 of the License. > + * > + * 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., > + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * Author : Jenny TC <jenny.tc@xxxxxxxxx> > + */ > +#ifndef _LINUX_HWMON_ADC_H > +#define _LINUX_HWMON_ADC_H > +struct hwmon_adc_ops { > + int (*read_adc) (int channel, unsigned int *adc_val); > + int (*read_adc_multi) (int *channel, unsigned int *adc_val, int count); > + int (*convert_adcval) (int channel, unsigned int adc_val, > + int *cvtd_val); > + int (*convert_adcval_multi) (int *channel, unsigned int *adc_val, > + int *cvtd_val, int count); > +}; > +struct device *hwmon_adc_device_register(struct device *dev, > + struct hwmon_adc_ops *adc_ops); > +void hwmon_adc_device_unregister(struct device *dev); > +int hwmon_adc_read_channel(char *adc_name, int channel, unsigned int *adc_val); > +int hwmon_adc_read_channel_multi(char *adc_name, int *channel, > + unsigned int *adc_val, int count); > +int hwmon_adc_convert_adcval(char *adc_name, int channel, unsigned int adc_val, > + int *cvtd_val); > +int hwmon_adc_convert_adcval_multi(char *adc_name, int *channel, > + unsigned int *adc_val, int *cvtd_val, int count); > +#endif > -- > 1.7.1 > _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors