Re: [PATCH v5 4/5] hwmon: add MAX197 support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Le Wed, 1 Feb 2012 13:35:38 -0800,
Guenter Roeck <guenter.roeck@xxxxxxxxxxxx> a écrit :

> Hi Vivien,
> 
> On Wed, 2012-02-01 at 16:05 -0500, Vivien Didelot wrote:
> > Signed-off-by: Vivien Didelot <vivien.didelot@xxxxxxxxxxxxxxxxxxxx>
> 
> Nicely done. Looks pretty good. Couple of minor comments below.
> 
> > ---
> >  Documentation/hwmon/max197 |   54 ++++++
> >  drivers/hwmon/Kconfig      |    9 +
> >  drivers/hwmon/Makefile     |    1 +
> >  drivers/hwmon/max197.c     |  403
> > ++++++++++++++++++++++++++++++++++++++++++++
> > include/linux/max197.h     |   22 +++ 5 files changed, 489
> > insertions(+), 0 deletions(-) create mode 100644
> > Documentation/hwmon/max197 create mode 100644 drivers/hwmon/max197.c
> >  create mode 100644 include/linux/max197.h
> > 
> > diff --git a/Documentation/hwmon/max197 b/Documentation/hwmon/max197
> > new file mode 100644
> > index 0000000..aa0934f
> > --- /dev/null
> > +++ b/Documentation/hwmon/max197
> > @@ -0,0 +1,54 @@
> > +Maxim MAX197 driver
> > +===================
> > +
> > +Author:
> > +  * Vivien Didelot <vivien.didelot@xxxxxxxxxxxxxxxxxxxx>
> > +
> > +Supported chips:
> > +  * Maxim MAX197
> > +    Prefix: 'max197'
> > +    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX197.pdf
> > +
> > +  * Maxim MAX199
> > +    Prefix: 'max199'
> > +    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX199.pdf
> > +
> > +Description
> > +-----------
> > +
> > +The A/D converters MAX197 and MAX199 are both 8-Channel,
> > Multi-Range, 5V, +12-Bit DAS with 8+4 Bus Interface and Fault
> > Protection. +
> > +The available ranges for the MAX197 are {0,-5V} to 5V, and
> > {0,-10V} to 10V, +while they are {0,-2V} to 2V, and {0,-4V} to 4V
> > on the MAX199. +
> > +Platform data
> > +-------------
> > +
> > +The MAX197 platform data (defined in linux/max197.h) should be
> > filled with two +function pointers:
> > +
> > +* start:
> > +  The function which writes the control byte to start a new
> > conversion. +* read:
> > +  The function used to read the raw value from the chip.
> > +
> > +Control-Byte Format:
> > +
> > +Bit    Name            Description
> > +7,6    PD1,PD0         Clock and Power-Down modes
> > +5      ACQMOD          Internal or External Controlled Acquisition
> > +4      RNG             Full-scale voltage magnitude at the input
> > +3      BIP             Unipolar or Bipolar conversion mode
> > +2,1,0  A2,A1,A0        Channel
> > +
> > +Sysfs interface
> > +---------------
> > +
> > +* in[0-7]_input: The conversion value for the corresponding
> > channel. +* in[0-7]_min:   The lower limit (in mV) for the
> > corresponding channel.
> > +                 It can be one value in -10000, -5000, -4000,
> > -2000, 0,
> > +                 depending on the chip.
> > +* in[0-7]_max:   The higher limit (in mV) for the corresponding
> > channel.
> > +                 It can be one value in 2000, 4000, 5000, 10000,
> > +                 depending on the chip.
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 91be41f..ccdf59b 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -1360,6 +1360,15 @@ config SENSORS_MC13783_ADC
> >          help
> >            Support for the A/D converter on MC13783 PMIC.
> > 
> > +config SENSORS_MAX197
> > +       tristate "Maxim MAX197 and compatibles."
> > +       help
> > +    If you say yes here you get support for the Maxim MAX197,
> > +    and MAX199 A/D converters.
> > +
> > +         This driver can also be built as a module.  If so, the
> > module
> > +         will be called max197.
> > +
> >  if ACPI
> > 
> >  comment "ACPI drivers"
> > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> > index 8251ce8..dfb73d9 100644
> > --- a/drivers/hwmon/Makefile
> > +++ b/drivers/hwmon/Makefile
> > @@ -125,6 +125,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)     +=
> > w83l785ts.o obj-$(CONFIG_SENSORS_W83L786NG)        += w83l786ng.o
> >  obj-$(CONFIG_SENSORS_WM831X)   += wm831x-hwmon.o
> >  obj-$(CONFIG_SENSORS_WM8350)   += wm8350-hwmon.o
> > +obj-$(CONFIG_SENSORS_MAX197)   += max197.o
> > 
> >  obj-$(CONFIG_PMBUS)            += pmbus/
> > 
> > diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
> > new file mode 100644
> > index 0000000..985615c
> > --- /dev/null
> > +++ b/drivers/hwmon/max197.c
> > @@ -0,0 +1,403 @@
> > +/*
> > + * Maxim MAX197 A/D Converter Driver
> > + *
> > + * Copyright (c) 2012 Savoir-faire Linux Inc.
> > + *          Vivien Didelot <vivien.didelot@xxxxxxxxxxxxxxxxxxxx>
> > + *
> > + * 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.
> > + *
> > + * For further information, see the Documentation/hwmon/max197
> > file.
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/device.h>
> > +#include <linux/delay.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/err.h>
> > +#include <linux/sysfs.h>
> > +#include <linux/hwmon.h>
> > +#include <linux/hwmon-sysfs.h>
> > +#include <linux/mutex.h>
> > +#include <linux/slab.h>
> > +#include <linux/io.h>
> > +#include <linux/max197.h>
> > +
> > +#define MAX199_LIMIT   4000    /* 4V */
> > +#define MAX197_LIMIT   10000   /* 10V */
> > +
> > +#define MAX197_NUM_CH  8       /* 8 Analog Input Channels */
> > +
> > +/* Control byte format */
> > +#define MAX197_A0      0x01    /* Channel bit 0 */
> > +#define MAX197_A1      0x02    /* Channel bit 1 */
> > +#define MAX197_A2      0x04    /* Channel bit 2 */
> > +#define MAX197_BIP     0x08    /* Bipolarity */
> > +#define MAX197_RNG     0x10    /* Full range */
> > +#define MAX197_ACQMOD  0x20    /* Internal/External controlled
> > acquisition */ +#define MAX197_PD0     0x40    /* Clock/Power-Down
> > modes bit 1 */ +#define MAX197_PD1     0x80    /* Clock/Power-Down
> > modes bit 2 */ +
> > +#define MAX197_SCALE   12207   /* Scale coefficient for raw data */
> > +
> > +/**
> > + * struct max197_chip - device instance specific data
> > + * @pdata:             Platform data.
> > + * @hwmon_dev:         The hwmon device.
> > + * @lock:              Read/Write mutex.
> > + * @limit:             Max range value (10V for MAX197, 4V for
> > MAX199).
> > + * @scale:             Need to scale.
> > + * @ctrl_bytes:                Channels control byte.
> > + */
> > +struct max197_chip {
> > +       struct max197_platform_data *pdata;
> > +       struct device *hwmon_dev;
> > +       struct mutex lock;
> > +       int limit;
> > +       bool scale;
> > +       u8 ctrl_bytes[MAX197_NUM_CH];
> > +};
> > +
> > +static inline void max197_set_unipolarity(struct max197_chip
> > *chip, int channel) +{
> > +       chip->ctrl_bytes[channel] &= ~MAX197_BIP;
> > +}
> > +
> > +static inline void max197_set_bipolarity(struct max197_chip *chip,
> > int channel) +{
> > +       chip->ctrl_bytes[channel] |= MAX197_BIP;
> > +}
> > +
> > +static inline void max197_set_half_range(struct max197_chip *chip,
> > int channel) +{
> > +       chip->ctrl_bytes[channel] &= ~MAX197_RNG;
> > +}
> > +
> > +static inline void max197_set_full_range(struct max197_chip *chip,
> > int channel) +{
> > +       chip->ctrl_bytes[channel] |= MAX197_RNG;
> > +}
> > +
> > +static inline bool max197_is_bipolar(struct max197_chip *chip, int
> > channel) +{
> > +       return !!(chip->ctrl_bytes[channel] & MAX197_BIP);
> > +}
> > +
> > +static inline bool max197_is_full_range(struct max197_chip *chip,
> > int channel) +{
> > +       return !!(chip->ctrl_bytes[channel] & MAX197_RNG);
> > +}
> > +
> Interestingly enough, you don't need the !!() above. The C language
> defines that the result of an operation assigned to a bool is always
> converted to either 0 or 1. Not that it matters, really - I personally
> actually prefer you style.

Thanks for the tip, I'll get rid of it.

> 
> > +/**
> > + * max197_show_range() - Display range on user output
> > + *
> > + * Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max}
> > + */
> > +static ssize_t max197_show_range(struct device *dev,
> > +                                struct device_attribute *devattr,
> > char *buf) +{
> > +       struct max197_chip *chip = dev_get_drvdata(dev);
> > +       struct sensor_device_attribute_2 *attr =
> > to_sensor_dev_attr_2(devattr);
> > +       int channel = attr->index;
> > +       bool is_min = attr->nr;
> > +       int range;
> > +
> > +       if (mutex_lock_interruptible(&chip->lock))
> > +               return -ERESTARTSYS;
> > +
> > +       range = max197_is_full_range(chip, channel) ?
> > +               chip->limit : chip->limit / 2;
> > +       if (is_min) {
> > +               if (max197_is_bipolar(chip, channel))
> > +                       range = -range;
> > +               else
> > +                       range = 0;
> > +       }
> > +
> > +       mutex_unlock(&chip->lock);
> > +
> > +       return sprintf(buf, "%d\n", range);
> > +}
> > +
> > +/**
> > + * max197_store_range() - Write range from user input
> > + *
> > + * Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max}
> > + */
> > +static ssize_t max197_store_range(struct device *dev,
> > +                                 struct device_attribute *devattr,
> > +                                 const char *buf, size_t count)
> > +{
> > +       struct max197_chip *chip = dev_get_drvdata(dev);
> > +       struct sensor_device_attribute_2 *attr =
> > to_sensor_dev_attr_2(devattr);
> > +       int channel = attr->index;
> > +       bool is_min = attr->nr;
> > +       long value;
> > +       int half = chip->limit / 2;
> > +       int full = chip->limit;
> > +
> > +       if (kstrtol(buf, 10, &value))
> > +               return -EINVAL;
> > +
> > +       if (is_min) {
> > +               if ((value != 0) && (value != -half) && (value !=
> > -full))
> > +                       return -EINVAL;
> > +       } else {
> > +               if ((value != half) && (value != full))
> > +                       return -EINVAL;
> > +       }
> > +
> Technically ok, except for the unnecessary ( ). Would be great if you
> could remove those.
> 
> Since the actual limits are chip dependent, and not easily to figure
> out for the ordinary user, it would be nice to either accept any
> number and adjust it to one of the accepted values, or to explicitly
> spell out the accepted the per-chip accepted values in the
> documentation (and not just say "depending on the chip"). I'll leave
> it up to you to decide which way to go.
> 
> Not too difficult - if you change the code, something like
> 
> 	if (is_min) {
> 		if (value <= -full)
> 			value = -full;
> 		else if (value < 0)
> 			value = -half;
> 		else value = 0;
> 	} else {
> 		if (value >= full)
> 			value = full;
> 		else
> 			value = half;
> 	}

It sounds better to accept any value and adjust it depending on the chip.

> 
> would be good enough.
> 
> Thanks,
> Guenter
> 
> 

BTW, about the TS-5500 ADC part, is a platform ts5500_adc.c file the
better solution, or should the device be declared in the ts5500.c
platform code?


Thanks!


-- 
Vivien Didelot
Savoir-faire Linux Inc.
Tel: (514) 276-5468 #149

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



[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux