root/drivers/iio/light/al3320a.c

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

DEFINITIONS

This source file includes following definitions.
  1. al3320a_init
  2. al3320a_read_raw
  3. al3320a_write_raw
  4. al3320a_probe
  5. al3320a_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * AL3320A - Dyna Image Ambient Light Sensor
   4  *
   5  * Copyright (c) 2014, Intel Corporation.
   6  *
   7  * IIO driver for AL3320A (7-bit I2C slave address 0x1C).
   8  *
   9  * TODO: interrupt support, thresholds
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/init.h>
  14 #include <linux/i2c.h>
  15 
  16 #include <linux/iio/iio.h>
  17 #include <linux/iio/sysfs.h>
  18 
  19 #define AL3320A_DRV_NAME "al3320a"
  20 
  21 #define AL3320A_REG_CONFIG              0x00
  22 #define AL3320A_REG_STATUS              0x01
  23 #define AL3320A_REG_INT                 0x02
  24 #define AL3320A_REG_WAIT                0x06
  25 #define AL3320A_REG_CONFIG_RANGE        0x07
  26 #define AL3320A_REG_PERSIST             0x08
  27 #define AL3320A_REG_MEAN_TIME           0x09
  28 #define AL3320A_REG_ADUMMY              0x0A
  29 #define AL3320A_REG_DATA_LOW            0x22
  30 
  31 #define AL3320A_REG_LOW_THRESH_LOW      0x30
  32 #define AL3320A_REG_LOW_THRESH_HIGH     0x31
  33 #define AL3320A_REG_HIGH_THRESH_LOW     0x32
  34 #define AL3320A_REG_HIGH_THRESH_HIGH    0x33
  35 
  36 #define AL3320A_CONFIG_DISABLE          0x00
  37 #define AL3320A_CONFIG_ENABLE           0x01
  38 
  39 #define AL3320A_GAIN_SHIFT              1
  40 #define AL3320A_GAIN_MASK               (BIT(2) | BIT(1))
  41 
  42 /* chip params default values */
  43 #define AL3320A_DEFAULT_MEAN_TIME       4
  44 #define AL3320A_DEFAULT_WAIT_TIME       0 /* no waiting */
  45 
  46 #define AL3320A_SCALE_AVAILABLE "0.512 0.128 0.032 0.01"
  47 
  48 enum al3320a_range {
  49         AL3320A_RANGE_1, /* 33.28 Klx */
  50         AL3320A_RANGE_2, /* 8.32 Klx  */
  51         AL3320A_RANGE_3, /* 2.08 Klx  */
  52         AL3320A_RANGE_4  /* 0.65 Klx  */
  53 };
  54 
  55 static const int al3320a_scales[][2] = {
  56         {0, 512000}, {0, 128000}, {0, 32000}, {0, 10000}
  57 };
  58 
  59 struct al3320a_data {
  60         struct i2c_client *client;
  61 };
  62 
  63 static const struct iio_chan_spec al3320a_channels[] = {
  64         {
  65                 .type   = IIO_LIGHT,
  66                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  67                                       BIT(IIO_CHAN_INFO_SCALE),
  68         }
  69 };
  70 
  71 static IIO_CONST_ATTR(in_illuminance_scale_available, AL3320A_SCALE_AVAILABLE);
  72 
  73 static struct attribute *al3320a_attributes[] = {
  74         &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
  75         NULL,
  76 };
  77 
  78 static const struct attribute_group al3320a_attribute_group = {
  79         .attrs = al3320a_attributes,
  80 };
  81 
  82 static int al3320a_init(struct al3320a_data *data)
  83 {
  84         int ret;
  85 
  86         /* power on */
  87         ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG,
  88                                         AL3320A_CONFIG_ENABLE);
  89         if (ret < 0)
  90                 return ret;
  91 
  92         ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE,
  93                                         AL3320A_RANGE_3 << AL3320A_GAIN_SHIFT);
  94         if (ret < 0)
  95                 return ret;
  96 
  97         ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME,
  98                                         AL3320A_DEFAULT_MEAN_TIME);
  99         if (ret < 0)
 100                 return ret;
 101 
 102         ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT,
 103                                         AL3320A_DEFAULT_WAIT_TIME);
 104         if (ret < 0)
 105                 return ret;
 106 
 107         return 0;
 108 }
 109 
 110 static int al3320a_read_raw(struct iio_dev *indio_dev,
 111                             struct iio_chan_spec const *chan, int *val,
 112                             int *val2, long mask)
 113 {
 114         struct al3320a_data *data = iio_priv(indio_dev);
 115         int ret;
 116 
 117         switch (mask) {
 118         case IIO_CHAN_INFO_RAW:
 119                 /*
 120                  * ALS ADC value is stored in two adjacent registers:
 121                  * - low byte of output is stored at AL3320A_REG_DATA_LOW
 122                  * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1
 123                  */
 124                 ret = i2c_smbus_read_word_data(data->client,
 125                                                AL3320A_REG_DATA_LOW);
 126                 if (ret < 0)
 127                         return ret;
 128                 *val = ret;
 129                 return IIO_VAL_INT;
 130         case IIO_CHAN_INFO_SCALE:
 131                 ret = i2c_smbus_read_byte_data(data->client,
 132                                                AL3320A_REG_CONFIG_RANGE);
 133                 if (ret < 0)
 134                         return ret;
 135 
 136                 ret = (ret & AL3320A_GAIN_MASK) >> AL3320A_GAIN_SHIFT;
 137                 *val = al3320a_scales[ret][0];
 138                 *val2 = al3320a_scales[ret][1];
 139 
 140                 return IIO_VAL_INT_PLUS_MICRO;
 141         }
 142         return -EINVAL;
 143 }
 144 
 145 static int al3320a_write_raw(struct iio_dev *indio_dev,
 146                              struct iio_chan_spec const *chan, int val,
 147                              int val2, long mask)
 148 {
 149         struct al3320a_data *data = iio_priv(indio_dev);
 150         int i;
 151 
 152         switch (mask) {
 153         case IIO_CHAN_INFO_SCALE:
 154                 for (i = 0; i < ARRAY_SIZE(al3320a_scales); i++) {
 155                         if (val == al3320a_scales[i][0] &&
 156                             val2 == al3320a_scales[i][1])
 157                                 return i2c_smbus_write_byte_data(data->client,
 158                                         AL3320A_REG_CONFIG_RANGE,
 159                                         i << AL3320A_GAIN_SHIFT);
 160                 }
 161                 break;
 162         }
 163         return -EINVAL;
 164 }
 165 
 166 static const struct iio_info al3320a_info = {
 167         .read_raw       = al3320a_read_raw,
 168         .write_raw      = al3320a_write_raw,
 169         .attrs          = &al3320a_attribute_group,
 170 };
 171 
 172 static int al3320a_probe(struct i2c_client *client,
 173                          const struct i2c_device_id *id)
 174 {
 175         struct al3320a_data *data;
 176         struct iio_dev *indio_dev;
 177         int ret;
 178 
 179         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 180         if (!indio_dev)
 181                 return -ENOMEM;
 182 
 183         data = iio_priv(indio_dev);
 184         i2c_set_clientdata(client, indio_dev);
 185         data->client = client;
 186 
 187         indio_dev->dev.parent = &client->dev;
 188         indio_dev->info = &al3320a_info;
 189         indio_dev->name = AL3320A_DRV_NAME;
 190         indio_dev->channels = al3320a_channels;
 191         indio_dev->num_channels = ARRAY_SIZE(al3320a_channels);
 192         indio_dev->modes = INDIO_DIRECT_MODE;
 193 
 194         ret = al3320a_init(data);
 195         if (ret < 0) {
 196                 dev_err(&client->dev, "al3320a chip init failed\n");
 197                 return ret;
 198         }
 199         return devm_iio_device_register(&client->dev, indio_dev);
 200 }
 201 
 202 static int al3320a_remove(struct i2c_client *client)
 203 {
 204         return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG,
 205                                          AL3320A_CONFIG_DISABLE);
 206 }
 207 
 208 static const struct i2c_device_id al3320a_id[] = {
 209         {"al3320a", 0},
 210         {}
 211 };
 212 MODULE_DEVICE_TABLE(i2c, al3320a_id);
 213 
 214 static struct i2c_driver al3320a_driver = {
 215         .driver = {
 216                 .name = AL3320A_DRV_NAME,
 217         },
 218         .probe          = al3320a_probe,
 219         .remove         = al3320a_remove,
 220         .id_table       = al3320a_id,
 221 };
 222 
 223 module_i2c_driver(al3320a_driver);
 224 
 225 MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
 226 MODULE_DESCRIPTION("AL3320A Ambient Light Sensor driver");
 227 MODULE_LICENSE("GPL v2");

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