linux/drivers/iio/light/cm32181.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Capella Microsystems Inc.
   3 * Author: Kevin Tsai <ktsai@capellamicro.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2, as published
   7 * by the Free Software Foundation.
   8 */
   9
  10#include <linux/delay.h>
  11#include <linux/err.h>
  12#include <linux/i2c.h>
  13#include <linux/mutex.h>
  14#include <linux/module.h>
  15#include <linux/interrupt.h>
  16#include <linux/regulator/consumer.h>
  17#include <linux/iio/iio.h>
  18#include <linux/iio/sysfs.h>
  19#include <linux/iio/events.h>
  20#include <linux/init.h>
  21
  22/* Registers Address */
  23#define CM32181_REG_ADDR_CMD            0x00
  24#define CM32181_REG_ADDR_ALS            0x04
  25#define CM32181_REG_ADDR_STATUS         0x06
  26#define CM32181_REG_ADDR_ID             0x07
  27
  28/* Number of Configurable Registers */
  29#define CM32181_CONF_REG_NUM            0x01
  30
  31/* CMD register */
  32#define CM32181_CMD_ALS_ENABLE          0x00
  33#define CM32181_CMD_ALS_DISABLE         0x01
  34#define CM32181_CMD_ALS_INT_EN          0x02
  35
  36#define CM32181_CMD_ALS_IT_SHIFT        6
  37#define CM32181_CMD_ALS_IT_MASK         (0x0F << CM32181_CMD_ALS_IT_SHIFT)
  38#define CM32181_CMD_ALS_IT_DEFAULT      (0x00 << CM32181_CMD_ALS_IT_SHIFT)
  39
  40#define CM32181_CMD_ALS_SM_SHIFT        11
  41#define CM32181_CMD_ALS_SM_MASK         (0x03 << CM32181_CMD_ALS_SM_SHIFT)
  42#define CM32181_CMD_ALS_SM_DEFAULT      (0x01 << CM32181_CMD_ALS_SM_SHIFT)
  43
  44#define CM32181_MLUX_PER_BIT            5       /* ALS_SM=01 IT=800ms */
  45#define CM32181_MLUX_PER_BIT_BASE_IT    800000  /* Based on IT=800ms */
  46#define CM32181_CALIBSCALE_DEFAULT      1000
  47#define CM32181_CALIBSCALE_RESOLUTION   1000
  48#define MLUX_PER_LUX                    1000
  49
  50static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
  51        CM32181_REG_ADDR_CMD,
  52};
  53
  54static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
  55static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
  56        800000};
  57
  58struct cm32181_chip {
  59        struct i2c_client *client;
  60        struct mutex lock;
  61        u16 conf_regs[CM32181_CONF_REG_NUM];
  62        int calibscale;
  63};
  64
  65/**
  66 * cm32181_reg_init() - Initialize CM32181 registers
  67 * @cm32181:    pointer of struct cm32181.
  68 *
  69 * Initialize CM32181 ambient light sensor register to default values.
  70 *
  71 * Return: 0 for success; otherwise for error code.
  72 */
  73static int cm32181_reg_init(struct cm32181_chip *cm32181)
  74{
  75        struct i2c_client *client = cm32181->client;
  76        int i;
  77        s32 ret;
  78
  79        ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
  80        if (ret < 0)
  81                return ret;
  82
  83        /* check device ID */
  84        if ((ret & 0xFF) != 0x81)
  85                return -ENODEV;
  86
  87        /* Default Values */
  88        cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE |
  89                        CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
  90        cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
  91
  92        /* Initialize registers*/
  93        for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
  94                ret = i2c_smbus_write_word_data(client, cm32181_reg[i],
  95                        cm32181->conf_regs[i]);
  96                if (ret < 0)
  97                        return ret;
  98        }
  99
 100        return 0;
 101}
 102
 103/**
 104 *  cm32181_read_als_it() - Get sensor integration time (ms)
 105 *  @cm32181:   pointer of struct cm32181
 106 *  @val2:      pointer of int to load the als_it value.
 107 *
 108 *  Report the current integartion time by millisecond.
 109 *
 110 *  Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
 111 */
 112static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
 113{
 114        u16 als_it;
 115        int i;
 116
 117        als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
 118        als_it &= CM32181_CMD_ALS_IT_MASK;
 119        als_it >>= CM32181_CMD_ALS_IT_SHIFT;
 120        for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
 121                if (als_it == als_it_bits[i]) {
 122                        *val2 = als_it_value[i];
 123                        return IIO_VAL_INT_PLUS_MICRO;
 124                }
 125        }
 126
 127        return -EINVAL;
 128}
 129
 130/**
 131 * cm32181_write_als_it() - Write sensor integration time
 132 * @cm32181:    pointer of struct cm32181.
 133 * @val:        integration time by millisecond.
 134 *
 135 * Convert integration time (ms) to sensor value.
 136 *
 137 * Return: i2c_smbus_write_word_data command return value.
 138 */
 139static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
 140{
 141        struct i2c_client *client = cm32181->client;
 142        u16 als_it;
 143        int ret, i, n;
 144
 145        n = ARRAY_SIZE(als_it_value);
 146        for (i = 0; i < n; i++)
 147                if (val <= als_it_value[i])
 148                        break;
 149        if (i >= n)
 150                i = n - 1;
 151
 152        als_it = als_it_bits[i];
 153        als_it <<= CM32181_CMD_ALS_IT_SHIFT;
 154
 155        mutex_lock(&cm32181->lock);
 156        cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
 157                ~CM32181_CMD_ALS_IT_MASK;
 158        cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
 159                als_it;
 160        ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
 161                        cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
 162        mutex_unlock(&cm32181->lock);
 163
 164        return ret;
 165}
 166
 167/**
 168 * cm32181_get_lux() - report current lux value
 169 * @cm32181:    pointer of struct cm32181.
 170 *
 171 * Convert sensor raw data to lux.  It depends on integration
 172 * time and calibscale variable.
 173 *
 174 * Return: Positive value is lux, otherwise is error code.
 175 */
 176static int cm32181_get_lux(struct cm32181_chip *cm32181)
 177{
 178        struct i2c_client *client = cm32181->client;
 179        int ret;
 180        int als_it;
 181        unsigned long lux;
 182
 183        ret = cm32181_read_als_it(cm32181, &als_it);
 184        if (ret < 0)
 185                return -EINVAL;
 186
 187        lux = CM32181_MLUX_PER_BIT;
 188        lux *= CM32181_MLUX_PER_BIT_BASE_IT;
 189        lux /= als_it;
 190
 191        ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
 192        if (ret < 0)
 193                return ret;
 194
 195        lux *= ret;
 196        lux *= cm32181->calibscale;
 197        lux /= CM32181_CALIBSCALE_RESOLUTION;
 198        lux /= MLUX_PER_LUX;
 199
 200        if (lux > 0xFFFF)
 201                lux = 0xFFFF;
 202
 203        return lux;
 204}
 205
 206static int cm32181_read_raw(struct iio_dev *indio_dev,
 207                            struct iio_chan_spec const *chan,
 208                            int *val, int *val2, long mask)
 209{
 210        struct cm32181_chip *cm32181 = iio_priv(indio_dev);
 211        int ret;
 212
 213        switch (mask) {
 214        case IIO_CHAN_INFO_PROCESSED:
 215                ret = cm32181_get_lux(cm32181);
 216                if (ret < 0)
 217                        return ret;
 218                *val = ret;
 219                return IIO_VAL_INT;
 220        case IIO_CHAN_INFO_CALIBSCALE:
 221                *val = cm32181->calibscale;
 222                return IIO_VAL_INT;
 223        case IIO_CHAN_INFO_INT_TIME:
 224                *val = 0;
 225                ret = cm32181_read_als_it(cm32181, val2);
 226                return ret;
 227        }
 228
 229        return -EINVAL;
 230}
 231
 232static int cm32181_write_raw(struct iio_dev *indio_dev,
 233                             struct iio_chan_spec const *chan,
 234                             int val, int val2, long mask)
 235{
 236        struct cm32181_chip *cm32181 = iio_priv(indio_dev);
 237        int ret;
 238
 239        switch (mask) {
 240        case IIO_CHAN_INFO_CALIBSCALE:
 241                cm32181->calibscale = val;
 242                return val;
 243        case IIO_CHAN_INFO_INT_TIME:
 244                ret = cm32181_write_als_it(cm32181, val2);
 245                return ret;
 246        }
 247
 248        return -EINVAL;
 249}
 250
 251/**
 252 * cm32181_get_it_available() - Get available ALS IT value
 253 * @dev:        pointer of struct device.
 254 * @attr:       pointer of struct device_attribute.
 255 * @buf:        pointer of return string buffer.
 256 *
 257 * Display the available integration time values by millisecond.
 258 *
 259 * Return: string length.
 260 */
 261static ssize_t cm32181_get_it_available(struct device *dev,
 262                        struct device_attribute *attr, char *buf)
 263{
 264        int i, n, len;
 265
 266        n = ARRAY_SIZE(als_it_value);
 267        for (i = 0, len = 0; i < n; i++)
 268                len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
 269        return len + sprintf(buf + len, "\n");
 270}
 271
 272static const struct iio_chan_spec cm32181_channels[] = {
 273        {
 274                .type = IIO_LIGHT,
 275                .info_mask_separate =
 276                        BIT(IIO_CHAN_INFO_PROCESSED) |
 277                        BIT(IIO_CHAN_INFO_CALIBSCALE) |
 278                        BIT(IIO_CHAN_INFO_INT_TIME),
 279        }
 280};
 281
 282static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
 283                        S_IRUGO, cm32181_get_it_available, NULL, 0);
 284
 285static struct attribute *cm32181_attributes[] = {
 286        &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
 287        NULL,
 288};
 289
 290static const struct attribute_group cm32181_attribute_group = {
 291        .attrs = cm32181_attributes
 292};
 293
 294static const struct iio_info cm32181_info = {
 295        .driver_module          = THIS_MODULE,
 296        .read_raw               = &cm32181_read_raw,
 297        .write_raw              = &cm32181_write_raw,
 298        .attrs                  = &cm32181_attribute_group,
 299};
 300
 301static int cm32181_probe(struct i2c_client *client,
 302                        const struct i2c_device_id *id)
 303{
 304        struct cm32181_chip *cm32181;
 305        struct iio_dev *indio_dev;
 306        int ret;
 307
 308        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
 309        if (!indio_dev) {
 310                dev_err(&client->dev, "devm_iio_device_alloc failed\n");
 311                return -ENOMEM;
 312        }
 313
 314        cm32181 = iio_priv(indio_dev);
 315        i2c_set_clientdata(client, indio_dev);
 316        cm32181->client = client;
 317
 318        mutex_init(&cm32181->lock);
 319        indio_dev->dev.parent = &client->dev;
 320        indio_dev->channels = cm32181_channels;
 321        indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
 322        indio_dev->info = &cm32181_info;
 323        indio_dev->name = id->name;
 324        indio_dev->modes = INDIO_DIRECT_MODE;
 325
 326        ret = cm32181_reg_init(cm32181);
 327        if (ret) {
 328                dev_err(&client->dev,
 329                        "%s: register init failed\n",
 330                        __func__);
 331                return ret;
 332        }
 333
 334        ret = devm_iio_device_register(&client->dev, indio_dev);
 335        if (ret) {
 336                dev_err(&client->dev,
 337                        "%s: regist device failed\n",
 338                        __func__);
 339                return ret;
 340        }
 341
 342        return 0;
 343}
 344
 345static const struct i2c_device_id cm32181_id[] = {
 346        { "cm32181", 0 },
 347        { }
 348};
 349
 350MODULE_DEVICE_TABLE(i2c, cm32181_id);
 351
 352static const struct of_device_id cm32181_of_match[] = {
 353        { .compatible = "capella,cm32181" },
 354        { }
 355};
 356MODULE_DEVICE_TABLE(of, cm32181_of_match);
 357
 358static struct i2c_driver cm32181_driver = {
 359        .driver = {
 360                .name   = "cm32181",
 361                .of_match_table = of_match_ptr(cm32181_of_match),
 362        },
 363        .id_table       = cm32181_id,
 364        .probe          = cm32181_probe,
 365};
 366
 367module_i2c_driver(cm32181_driver);
 368
 369MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
 370MODULE_DESCRIPTION("CM32181 ambient light sensor driver");
 371MODULE_LICENSE("GPL");
 372