linux/drivers/hwmon/mc13783-adc.c
<<
>>
Prefs
   1/*
   2 * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
   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/mc13xxx.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 DRIVER_NAME     "mc13783-adc"
  32
  33/* platform device id driver data */
  34#define MC13783_ADC_16CHANS     1
  35#define MC13783_ADC_BPDIV2      2
  36
  37struct mc13783_adc_priv {
  38        struct mc13xxx *mc13xxx;
  39        struct device *hwmon_dev;
  40        char name[10];
  41};
  42
  43static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
  44                              *devattr, char *buf)
  45{
  46        struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
  47
  48        return sprintf(buf, "%s\n", priv->name);
  49}
  50
  51static int mc13783_adc_read(struct device *dev,
  52                struct device_attribute *devattr, unsigned int *val)
  53{
  54        struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
  55        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  56        unsigned int channel = attr->index;
  57        unsigned int sample[4];
  58        int ret;
  59
  60        ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
  61                        MC13XXX_ADC_MODE_MULT_CHAN,
  62                        channel, 0, 0, sample);
  63        if (ret)
  64                return ret;
  65
  66        channel &= 0x7;
  67
  68        *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
  69
  70        return 0;
  71}
  72
  73static ssize_t mc13783_adc_read_bp(struct device *dev,
  74                struct device_attribute *devattr, char *buf)
  75{
  76        unsigned val;
  77        struct platform_device *pdev = to_platform_device(dev);
  78        kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
  79        int ret = mc13783_adc_read(dev, devattr, &val);
  80
  81        if (ret)
  82                return ret;
  83
  84        if (driver_data & MC13783_ADC_BPDIV2)
  85                val = DIV_ROUND_CLOSEST(val * 9, 2);
  86        else
  87                /*
  88                 * BP (channel 2) reports with offset 2.4V to the actual value
  89                 * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
  90                 */
  91                val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
  92
  93        return sprintf(buf, "%u\n", val);
  94}
  95
  96static ssize_t mc13783_adc_read_gp(struct device *dev,
  97                struct device_attribute *devattr, char *buf)
  98{
  99        unsigned val;
 100        int ret = mc13783_adc_read(dev, devattr, &val);
 101
 102        if (ret)
 103                return ret;
 104
 105        /*
 106         * input range is [0, 2.3V], val has 10 bits, so each bit
 107         * is worth 9/4 mV.
 108         */
 109        val = DIV_ROUND_CLOSEST(val * 9, 4);
 110
 111        return sprintf(buf, "%u\n", val);
 112}
 113
 114static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
 115static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
 116static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
 117static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
 118static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
 119static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
 120static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
 121static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
 122static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
 123static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
 124static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
 125static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
 126static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
 127
 128static struct attribute *mc13783_attr_base[] = {
 129        &dev_attr_name.attr,
 130        &sensor_dev_attr_in2_input.dev_attr.attr,
 131        &sensor_dev_attr_in5_input.dev_attr.attr,
 132        &sensor_dev_attr_in6_input.dev_attr.attr,
 133        &sensor_dev_attr_in7_input.dev_attr.attr,
 134        NULL
 135};
 136
 137static const struct attribute_group mc13783_group_base = {
 138        .attrs = mc13783_attr_base,
 139};
 140
 141/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
 142static struct attribute *mc13783_attr_16chans[] = {
 143        &sensor_dev_attr_in8_input.dev_attr.attr,
 144        &sensor_dev_attr_in9_input.dev_attr.attr,
 145        &sensor_dev_attr_in10_input.dev_attr.attr,
 146        &sensor_dev_attr_in11_input.dev_attr.attr,
 147        NULL
 148};
 149
 150static const struct attribute_group mc13783_group_16chans = {
 151        .attrs = mc13783_attr_16chans,
 152};
 153
 154/* last four channels may be occupied by the touchscreen */
 155static struct attribute *mc13783_attr_ts[] = {
 156        &sensor_dev_attr_in12_input.dev_attr.attr,
 157        &sensor_dev_attr_in13_input.dev_attr.attr,
 158        &sensor_dev_attr_in14_input.dev_attr.attr,
 159        &sensor_dev_attr_in15_input.dev_attr.attr,
 160        NULL
 161};
 162
 163static const struct attribute_group mc13783_group_ts = {
 164        .attrs = mc13783_attr_ts,
 165};
 166
 167static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
 168{
 169        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 170        unsigned flags = mc13xxx_get_flags(priv->mc13xxx);
 171
 172        return flags & MC13XXX_USE_TOUCHSCREEN;
 173}
 174
 175static int __init mc13783_adc_probe(struct platform_device *pdev)
 176{
 177        struct mc13783_adc_priv *priv;
 178        int ret;
 179        const struct platform_device_id *id = platform_get_device_id(pdev);
 180        char *dash;
 181
 182        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 183        if (!priv)
 184                return -ENOMEM;
 185
 186        priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
 187        snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
 188        dash = strchr(priv->name, '-');
 189        if (dash)
 190                *dash = '\0';
 191
 192        platform_set_drvdata(pdev, priv);
 193
 194        /* Register sysfs hooks */
 195        ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
 196        if (ret)
 197                return ret;
 198
 199        if (id->driver_data & MC13783_ADC_16CHANS) {
 200                ret = sysfs_create_group(&pdev->dev.kobj,
 201                                &mc13783_group_16chans);
 202                if (ret)
 203                        goto out_err_create_16chans;
 204        }
 205
 206        if (!mc13783_adc_use_touchscreen(pdev)) {
 207                ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
 208                if (ret)
 209                        goto out_err_create_ts;
 210        }
 211
 212        priv->hwmon_dev = hwmon_device_register(&pdev->dev);
 213        if (IS_ERR(priv->hwmon_dev)) {
 214                ret = PTR_ERR(priv->hwmon_dev);
 215                dev_err(&pdev->dev,
 216                                "hwmon_device_register failed with %d.\n", ret);
 217                goto out_err_register;
 218        }
 219
 220        return 0;
 221
 222out_err_register:
 223
 224        if (!mc13783_adc_use_touchscreen(pdev))
 225                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 226out_err_create_ts:
 227
 228        if (id->driver_data & MC13783_ADC_16CHANS)
 229                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
 230out_err_create_16chans:
 231
 232        sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 233        return ret;
 234}
 235
 236static int mc13783_adc_remove(struct platform_device *pdev)
 237{
 238        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
 239        kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
 240
 241        hwmon_device_unregister(priv->hwmon_dev);
 242
 243        if (!mc13783_adc_use_touchscreen(pdev))
 244                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 245
 246        if (driver_data & MC13783_ADC_16CHANS)
 247                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
 248
 249        sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 250
 251        return 0;
 252}
 253
 254static const struct platform_device_id mc13783_adc_idtable[] = {
 255        {
 256                .name = "mc13783-adc",
 257                .driver_data = MC13783_ADC_16CHANS,
 258        }, {
 259                .name = "mc13892-adc",
 260                .driver_data = MC13783_ADC_BPDIV2,
 261        }, {
 262                /* sentinel */
 263        }
 264};
 265MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
 266
 267static struct platform_driver mc13783_adc_driver = {
 268        .remove         = mc13783_adc_remove,
 269        .driver         = {
 270                .owner  = THIS_MODULE,
 271                .name   = DRIVER_NAME,
 272        },
 273        .id_table       = mc13783_adc_idtable,
 274};
 275
 276module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
 277
 278MODULE_DESCRIPTION("MC13783 ADC driver");
 279MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 280MODULE_LICENSE("GPL");
 281
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.