root/drivers/iio/light/noa1305.c

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

DEFINITIONS

This source file includes following definitions.
  1. noa1305_measure
  2. noa1305_scale
  3. noa1305_read_raw
  4. noa1305_writable_reg
  5. noa1305_reg_remove
  6. noa1305_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Support for ON Semiconductor NOA1305 ambient light sensor
   4  *
   5  * Copyright (C) 2016 Emcraft Systems
   6  * Copyright (C) 2019 Collabora Ltd.
   7  */
   8 
   9 #include <linux/delay.h>
  10 #include <linux/err.h>
  11 #include <linux/i2c.h>
  12 #include <linux/iio/iio.h>
  13 #include <linux/iio/sysfs.h>
  14 #include <linux/module.h>
  15 #include <linux/regmap.h>
  16 #include <linux/regulator/consumer.h>
  17 
  18 #define NOA1305_REG_POWER_CONTROL       0x0
  19 #define   NOA1305_POWER_CONTROL_DOWN    0x00
  20 #define   NOA1305_POWER_CONTROL_ON      0x08
  21 #define NOA1305_REG_RESET               0x1
  22 #define   NOA1305_RESET_RESET           0x10
  23 #define NOA1305_REG_INTEGRATION_TIME    0x2
  24 #define   NOA1305_INTEGR_TIME_800MS     0x00
  25 #define   NOA1305_INTEGR_TIME_400MS     0x01
  26 #define   NOA1305_INTEGR_TIME_200MS     0x02
  27 #define   NOA1305_INTEGR_TIME_100MS     0x03
  28 #define   NOA1305_INTEGR_TIME_50MS      0x04
  29 #define   NOA1305_INTEGR_TIME_25MS      0x05
  30 #define   NOA1305_INTEGR_TIME_12_5MS    0x06
  31 #define   NOA1305_INTEGR_TIME_6_25MS    0x07
  32 #define NOA1305_REG_INT_SELECT          0x3
  33 #define   NOA1305_INT_SEL_ACTIVE_HIGH   0x01
  34 #define   NOA1305_INT_SEL_ACTIVE_LOW    0x02
  35 #define   NOA1305_INT_SEL_INACTIVE      0x03
  36 #define NOA1305_REG_INT_THRESH_LSB      0x4
  37 #define NOA1305_REG_INT_THRESH_MSB      0x5
  38 #define NOA1305_REG_ALS_DATA_LSB        0x6
  39 #define NOA1305_REG_ALS_DATA_MSB        0x7
  40 #define NOA1305_REG_DEVICE_ID_LSB       0x8
  41 #define NOA1305_REG_DEVICE_ID_MSB       0x9
  42 
  43 #define NOA1305_DEVICE_ID       0x0519
  44 #define NOA1305_DRIVER_NAME     "noa1305"
  45 
  46 struct noa1305_priv {
  47         struct i2c_client *client;
  48         struct regmap *regmap;
  49         struct regulator *vin_reg;
  50 };
  51 
  52 static int noa1305_measure(struct noa1305_priv *priv)
  53 {
  54         __le16 data;
  55         int ret;
  56 
  57         ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data,
  58                                2);
  59         if (ret < 0)
  60                 return ret;
  61 
  62         return le16_to_cpu(data);
  63 }
  64 
  65 static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2)
  66 {
  67         int data;
  68         int ret;
  69 
  70         ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data);
  71         if (ret < 0)
  72                 return ret;
  73 
  74         /*
  75          * Lux = count / (<Integration Constant> * <Integration Time>)
  76          *
  77          * Integration Constant = 7.7
  78          * Integration Time in Seconds
  79          */
  80         switch (data) {
  81         case NOA1305_INTEGR_TIME_800MS:
  82                 *val = 100;
  83                 *val2 = 77 * 8;
  84                 break;
  85         case NOA1305_INTEGR_TIME_400MS:
  86                 *val = 100;
  87                 *val2 = 77 * 4;
  88                 break;
  89         case NOA1305_INTEGR_TIME_200MS:
  90                 *val = 100;
  91                 *val2 = 77 * 2;
  92                 break;
  93         case NOA1305_INTEGR_TIME_100MS:
  94                 *val = 100;
  95                 *val2 = 77;
  96                 break;
  97         case NOA1305_INTEGR_TIME_50MS:
  98                 *val = 1000;
  99                 *val2 = 77 * 5;
 100                 break;
 101         case NOA1305_INTEGR_TIME_25MS:
 102                 *val = 10000;
 103                 *val2 = 77 * 25;
 104                 break;
 105         case NOA1305_INTEGR_TIME_12_5MS:
 106                 *val = 100000;
 107                 *val2 = 77 * 125;
 108                 break;
 109         case NOA1305_INTEGR_TIME_6_25MS:
 110                 *val = 1000000;
 111                 *val2 = 77 * 625;
 112                 break;
 113         default:
 114                 return -EINVAL;
 115         }
 116 
 117         return IIO_VAL_FRACTIONAL;
 118 }
 119 
 120 static const struct iio_chan_spec noa1305_channels[] = {
 121         {
 122                 .type = IIO_LIGHT,
 123                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 124                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
 125         }
 126 };
 127 
 128 static int noa1305_read_raw(struct iio_dev *indio_dev,
 129                                 struct iio_chan_spec const *chan,
 130                                 int *val, int *val2, long mask)
 131 {
 132         int ret = -EINVAL;
 133         struct noa1305_priv *priv = iio_priv(indio_dev);
 134 
 135         switch (mask) {
 136         case IIO_CHAN_INFO_RAW:
 137                 switch (chan->type) {
 138                 case IIO_LIGHT:
 139                         ret = noa1305_measure(priv);
 140                         if (ret < 0)
 141                                 return ret;
 142                         *val = ret;
 143                         return IIO_VAL_INT;
 144                 default:
 145                         break;
 146                 }
 147                 break;
 148         case IIO_CHAN_INFO_SCALE:
 149                 switch (chan->type) {
 150                 case IIO_LIGHT:
 151                         return noa1305_scale(priv, val, val2);
 152                 default:
 153                         break;
 154                 }
 155                 break;
 156         default:
 157                 break;
 158         }
 159 
 160         return ret;
 161 }
 162 
 163 static const struct iio_info noa1305_info = {
 164         .read_raw = noa1305_read_raw,
 165 };
 166 
 167 static bool noa1305_writable_reg(struct device *dev, unsigned int reg)
 168 {
 169         switch (reg) {
 170         case NOA1305_REG_POWER_CONTROL:
 171         case NOA1305_REG_RESET:
 172         case NOA1305_REG_INTEGRATION_TIME:
 173         case NOA1305_REG_INT_SELECT:
 174         case NOA1305_REG_INT_THRESH_LSB:
 175         case NOA1305_REG_INT_THRESH_MSB:
 176                 return true;
 177         default:
 178                 return false;
 179         }
 180 }
 181 
 182 static const struct regmap_config noa1305_regmap_config = {
 183         .name = NOA1305_DRIVER_NAME,
 184         .reg_bits = 8,
 185         .val_bits = 8,
 186         .max_register = NOA1305_REG_DEVICE_ID_MSB,
 187         .writeable_reg = noa1305_writable_reg,
 188 };
 189 
 190 static void noa1305_reg_remove(void *data)
 191 {
 192         struct noa1305_priv *priv = data;
 193 
 194         regulator_disable(priv->vin_reg);
 195 }
 196 
 197 static int noa1305_probe(struct i2c_client *client,
 198                          const struct i2c_device_id *id)
 199 {
 200         struct noa1305_priv *priv;
 201         struct iio_dev *indio_dev;
 202         struct regmap *regmap;
 203         __le16 data;
 204         unsigned int dev_id;
 205         int ret;
 206 
 207         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv));
 208         if (!indio_dev)
 209                 return -ENOMEM;
 210 
 211         regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config);
 212         if (IS_ERR(regmap)) {
 213                 dev_err(&client->dev, "Regmap initialization failed.\n");
 214                 return PTR_ERR(regmap);
 215         }
 216 
 217         priv = iio_priv(indio_dev);
 218 
 219         priv->vin_reg = devm_regulator_get(&client->dev, "vin");
 220         if (IS_ERR(priv->vin_reg)) {
 221                 dev_err(&client->dev, "get regulator vin failed\n");
 222                 return PTR_ERR(priv->vin_reg);
 223         }
 224 
 225         ret = regulator_enable(priv->vin_reg);
 226         if (ret) {
 227                 dev_err(&client->dev, "enable regulator vin failed\n");
 228                 return ret;
 229         }
 230 
 231         ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
 232         if (ret) {
 233                 dev_err(&client->dev, "addition of devm action failed\n");
 234                 return ret;
 235         }
 236 
 237         i2c_set_clientdata(client, indio_dev);
 238         priv->client = client;
 239         priv->regmap = regmap;
 240 
 241         ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2);
 242         if (ret < 0) {
 243                 dev_err(&client->dev, "ID reading failed: %d\n", ret);
 244                 return ret;
 245         }
 246 
 247         dev_id = le16_to_cpu(data);
 248         if (dev_id != NOA1305_DEVICE_ID) {
 249                 dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id);
 250                 return -ENODEV;
 251         }
 252 
 253         ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL,
 254                            NOA1305_POWER_CONTROL_ON);
 255         if (ret < 0) {
 256                 dev_err(&client->dev, "Enabling power control failed\n");
 257                 return ret;
 258         }
 259 
 260         ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET);
 261         if (ret < 0) {
 262                 dev_err(&client->dev, "Device reset failed\n");
 263                 return ret;
 264         }
 265 
 266         ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME,
 267                            NOA1305_INTEGR_TIME_800MS);
 268         if (ret < 0) {
 269                 dev_err(&client->dev, "Setting integration time failed\n");
 270                 return ret;
 271         }
 272 
 273         indio_dev->dev.parent = &client->dev;
 274         indio_dev->info = &noa1305_info;
 275         indio_dev->channels = noa1305_channels;
 276         indio_dev->num_channels = ARRAY_SIZE(noa1305_channels);
 277         indio_dev->name = NOA1305_DRIVER_NAME;
 278         indio_dev->modes = INDIO_DIRECT_MODE;
 279 
 280         ret = devm_iio_device_register(&client->dev, indio_dev);
 281         if (ret)
 282                 dev_err(&client->dev, "registering device failed\n");
 283 
 284         return ret;
 285 }
 286 
 287 static const struct of_device_id noa1305_of_match[] = {
 288         { .compatible = "onnn,noa1305" },
 289         { }
 290 };
 291 MODULE_DEVICE_TABLE(of, noa1305_of_match);
 292 
 293 static const struct i2c_device_id noa1305_ids[] = {
 294         { "noa1305", 0 },
 295         { }
 296 };
 297 MODULE_DEVICE_TABLE(i2c, noa1305_ids);
 298 
 299 static struct i2c_driver noa1305_driver = {
 300         .driver = {
 301                 .name           = NOA1305_DRIVER_NAME,
 302                 .of_match_table = noa1305_of_match,
 303         },
 304         .probe          = noa1305_probe,
 305         .id_table       = noa1305_ids,
 306 };
 307 
 308 module_i2c_driver(noa1305_driver);
 309 
 310 MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>");
 311 MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com");
 312 MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor");
 313 MODULE_LICENSE("GPL");

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