lkml.org 
[lkml]   [2012]   [May]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH] hwmon: Generic ADC support for hwmon
    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@intel.com>

    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@intel.com>
    > + */
    > +
    > +#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@intel.com>
    > + */
    > +#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
    >


    \
     
     \ /
      Last update: 2012-05-15 15:02    [W:0.048 / U:0.232 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site