root/drivers/iio/light/cm32181.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cm32181_reg_init
  2. cm32181_read_als_it
  3. cm32181_write_als_it
  4. cm32181_get_lux
  5. cm32181_read_raw
  6. cm32181_write_raw
  7. cm32181_get_it_available
  8. cm32181_probe

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

/* [<][>][^][v][top][bottom][index][help] */