linux/drivers/hwmon/mc13783-adc.c
<<
>>
Prefs
   1/*
   2 * Driver for the Freescale Semiconductor MC13783 adc.
   3 *
   4 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
   5 * Copyright (C) 2009 Sascha Hauer, Pengutronix
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version 2
  10 * of the License, or (at your option) any later version.
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program; if not, write to the Free Software Foundation, Inc., 51
  18 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19 */
  20
  21#include <linux/mfd/mc13783.h>
  22#include <linux/platform_device.h>
  23#include <linux/hwmon-sysfs.h>
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/hwmon.h>
  27#include <linux/slab.h>
  28#include <linux/init.h>
  29#include <linux/err.h>
  30
  31#define MC13783_ADC_NAME        "mc13783-adc"
  32
  33struct mc13783_adc_priv {
  34        struct mc13783 *mc13783;
  35        struct device *hwmon_dev;
  36};
  37
  38static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
  39                              *devattr, char *buf)
  40{
  41        return sprintf(buf, "mc13783_adc\n");
  42}
  43
  44static int mc13783_adc_read(struct device *dev,
  45                struct device_attribute *devattr, unsigned int *val)
  46{
  47        struct platform_device *pdev = to_platform_device(dev);
  48        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
  49        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  50        unsigned int channel = attr->index;
  51        unsigned int sample[4];
  52        int ret;
  53
  54        ret = mc13783_adc_do_conversion(priv->mc13783,
  55                        MC13783_ADC_MODE_MULT_CHAN,
  56                        channel, sample);
  57        if (ret)
  58                return ret;
  59
  60        channel &= 0x7;
  61
  62        *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
  63
  64        return 0;
  65}
  66
  67static ssize_t mc13783_adc_read_bp(struct device *dev,
  68                struct device_attribute *devattr, char *buf)
  69{
  70        unsigned val;
  71        int ret = mc13783_adc_read(dev, devattr, &val);
  72
  73        if (ret)
  74                return ret;
  75
  76        /*
  77         * BP (channel 2) reports with offset 2.4V to the actual value to fit
  78         * the input range of the ADC.  unit = 2.25mV = 9/4 mV.
  79         */
  80        val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
  81
  82        return sprintf(buf, "%u\n", val);
  83}
  84
  85static ssize_t mc13783_adc_read_gp(struct device *dev,
  86                struct device_attribute *devattr, char *buf)
  87{
  88        unsigned val;
  89        int ret = mc13783_adc_read(dev, devattr, &val);
  90
  91        if (ret)
  92                return ret;
  93
  94        /*
  95         * input range is [0, 2.3V], val has 10 bits, so each bit
  96         * is worth 9/4 mV.
  97         */
  98        val = DIV_ROUND_CLOSEST(val * 9, 4);
  99
 100        return sprintf(buf, "%u\n", val);
 101}
 102
 103static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
 104static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
 105static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
 106static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
 107static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
 108static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
 109static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
 110static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
 111static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
 112static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
 113static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
 114static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
 115static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
 116
 117static struct attribute *mc13783_attr[] = {
 118        &dev_attr_name.attr,
 119        &sensor_dev_attr_in2_input.dev_attr.attr,
 120        &sensor_dev_attr_in5_input.dev_attr.attr,
 121        &sensor_dev_attr_in6_input.dev_attr.attr,
 122        &sensor_dev_attr_in7_input.dev_attr.attr,
 123        &sensor_dev_attr_in8_input.dev_attr.attr,
 124        &sensor_dev_attr_in9_input.dev_attr.attr,
 125        &sensor_dev_attr_in10_input.dev_attr.attr,
 126        &sensor_dev_attr_in11_input.dev_attr.attr,
 127        NULL
 128};
 129
 130static const struct attribute_group mc13783_group = {
 131        .attrs = mc13783_attr,
 132};
 133
 134/* last four channels may be occupied by the touchscreen */
 135static struct attribute *mc13783_attr_ts[] = {
 136        &sensor_dev_attr_in12_input.dev_attr.attr,
 137        &sensor_dev_attr_in13_input.dev_attr.attr,
 138        &sensor_dev_attr_in14_input.dev_attr.attr,
 139        &sensor_dev_attr_in15_input.dev_attr.attr,
 140        NULL
 141};
 142
 143static const struct attribute_group mc13783_group_ts = {
 144        .attrs = mc13783_attr_ts,
 145};
 146
 147static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
 148{
 149        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 150        unsigned flags = mc13783_get_flags(priv->mc13783);
 151
 152        return flags & MC13783_USE_TOUCHSCREEN;
 153}
 154
 155static int __init mc13783_adc_probe(struct platform_device *pdev)
 156{
 157        struct mc13783_adc_priv *priv;
 158        int ret;
 159
 160        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 161        if (!priv)
 162                return -ENOMEM;
 163
 164        priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
 165
 166        platform_set_drvdata(pdev, priv);
 167
 168        /* Register sysfs hooks */
 169        ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
 170        if (ret)
 171                goto out_err_create1;
 172
 173        if (!mc13783_adc_use_touchscreen(pdev)) {
 174                ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
 175                if (ret)
 176                        goto out_err_create2;
 177        }
 178
 179        priv->hwmon_dev = hwmon_device_register(&pdev->dev);
 180        if (IS_ERR(priv->hwmon_dev)) {
 181                ret = PTR_ERR(priv->hwmon_dev);
 182                dev_err(&pdev->dev,
 183                                "hwmon_device_register failed with %d.\n", ret);
 184                goto out_err_register;
 185        }
 186
 187
 188        return 0;
 189
 190out_err_register:
 191
 192        if (!mc13783_adc_use_touchscreen(pdev))
 193                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 194out_err_create2:
 195
 196        sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
 197out_err_create1:
 198
 199        platform_set_drvdata(pdev, NULL);
 200        kfree(priv);
 201
 202        return ret;
 203}
 204
 205static int __devexit mc13783_adc_remove(struct platform_device *pdev)
 206{
 207        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 208
 209        hwmon_device_unregister(priv->hwmon_dev);
 210
 211        if (!mc13783_adc_use_touchscreen(pdev))
 212                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 213
 214        sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
 215
 216        platform_set_drvdata(pdev, NULL);
 217        kfree(priv);
 218
 219        return 0;
 220}
 221
 222static struct platform_driver mc13783_adc_driver = {
 223        .remove         = __devexit_p(mc13783_adc_remove),
 224        .driver         = {
 225                .owner  = THIS_MODULE,
 226                .name   = MC13783_ADC_NAME,
 227        },
 228};
 229
 230static int __init mc13783_adc_init(void)
 231{
 232        return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
 233}
 234
 235static void __exit mc13783_adc_exit(void)
 236{
 237        platform_driver_unregister(&mc13783_adc_driver);
 238}
 239
 240module_init(mc13783_adc_init);
 241module_exit(mc13783_adc_exit);
 242
 243MODULE_DESCRIPTION("MC13783 ADC driver");
 244MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 245MODULE_LICENSE("GPL");
 246MODULE_ALIAS("platform:" MC13783_ADC_NAME);
 247