Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * lv0104cs.c: LV0104CS Ambient Light Sensor Driver
0004  *
0005  * Copyright (C) 2018
0006  * Author: Jeff LaBundy <jeff@labundy.com>
0007  *
0008  * 7-bit I2C slave address: 0x13
0009  *
0010  * Link to data sheet: https://www.onsemi.com/pub/Collateral/LV0104CS-D.PDF
0011  */
0012 
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/i2c.h>
0016 #include <linux/err.h>
0017 #include <linux/mutex.h>
0018 #include <linux/delay.h>
0019 #include <linux/iio/iio.h>
0020 #include <linux/iio/sysfs.h>
0021 
0022 #define LV0104CS_REGVAL_MEASURE     0xE0
0023 #define LV0104CS_REGVAL_SLEEP       0x00
0024 
0025 #define LV0104CS_SCALE_0_25X        0
0026 #define LV0104CS_SCALE_1X       1
0027 #define LV0104CS_SCALE_2X       2
0028 #define LV0104CS_SCALE_8X       3
0029 #define LV0104CS_SCALE_SHIFT        3
0030 
0031 #define LV0104CS_INTEG_12_5MS       0
0032 #define LV0104CS_INTEG_100MS        1
0033 #define LV0104CS_INTEG_200MS        2
0034 #define LV0104CS_INTEG_SHIFT        1
0035 
0036 #define LV0104CS_CALIBSCALE_UNITY   31
0037 
0038 struct lv0104cs_private {
0039     struct i2c_client *client;
0040     struct mutex lock;
0041     u8 calibscale;
0042     u8 scale;
0043     u8 int_time;
0044 };
0045 
0046 struct lv0104cs_mapping {
0047     int val;
0048     int val2;
0049     u8 regval;
0050 };
0051 
0052 static const struct lv0104cs_mapping lv0104cs_calibscales[] = {
0053     { 0, 666666, 0x81 },
0054     { 0, 800000, 0x82 },
0055     { 0, 857142, 0x83 },
0056     { 0, 888888, 0x84 },
0057     { 0, 909090, 0x85 },
0058     { 0, 923076, 0x86 },
0059     { 0, 933333, 0x87 },
0060     { 0, 941176, 0x88 },
0061     { 0, 947368, 0x89 },
0062     { 0, 952380, 0x8A },
0063     { 0, 956521, 0x8B },
0064     { 0, 960000, 0x8C },
0065     { 0, 962962, 0x8D },
0066     { 0, 965517, 0x8E },
0067     { 0, 967741, 0x8F },
0068     { 0, 969696, 0x90 },
0069     { 0, 971428, 0x91 },
0070     { 0, 972972, 0x92 },
0071     { 0, 974358, 0x93 },
0072     { 0, 975609, 0x94 },
0073     { 0, 976744, 0x95 },
0074     { 0, 977777, 0x96 },
0075     { 0, 978723, 0x97 },
0076     { 0, 979591, 0x98 },
0077     { 0, 980392, 0x99 },
0078     { 0, 981132, 0x9A },
0079     { 0, 981818, 0x9B },
0080     { 0, 982456, 0x9C },
0081     { 0, 983050, 0x9D },
0082     { 0, 983606, 0x9E },
0083     { 0, 984126, 0x9F },
0084     { 1, 0, 0x80 },
0085     { 1, 16129, 0xBF },
0086     { 1, 16666, 0xBE },
0087     { 1, 17241, 0xBD },
0088     { 1, 17857, 0xBC },
0089     { 1, 18518, 0xBB },
0090     { 1, 19230, 0xBA },
0091     { 1, 20000, 0xB9 },
0092     { 1, 20833, 0xB8 },
0093     { 1, 21739, 0xB7 },
0094     { 1, 22727, 0xB6 },
0095     { 1, 23809, 0xB5 },
0096     { 1, 24999, 0xB4 },
0097     { 1, 26315, 0xB3 },
0098     { 1, 27777, 0xB2 },
0099     { 1, 29411, 0xB1 },
0100     { 1, 31250, 0xB0 },
0101     { 1, 33333, 0xAF },
0102     { 1, 35714, 0xAE },
0103     { 1, 38461, 0xAD },
0104     { 1, 41666, 0xAC },
0105     { 1, 45454, 0xAB },
0106     { 1, 50000, 0xAA },
0107     { 1, 55555, 0xA9 },
0108     { 1, 62500, 0xA8 },
0109     { 1, 71428, 0xA7 },
0110     { 1, 83333, 0xA6 },
0111     { 1, 100000, 0xA5 },
0112     { 1, 125000, 0xA4 },
0113     { 1, 166666, 0xA3 },
0114     { 1, 250000, 0xA2 },
0115     { 1, 500000, 0xA1 },
0116 };
0117 
0118 static const struct lv0104cs_mapping lv0104cs_scales[] = {
0119     { 0, 250000, LV0104CS_SCALE_0_25X << LV0104CS_SCALE_SHIFT },
0120     { 1, 0, LV0104CS_SCALE_1X << LV0104CS_SCALE_SHIFT },
0121     { 2, 0, LV0104CS_SCALE_2X << LV0104CS_SCALE_SHIFT },
0122     { 8, 0, LV0104CS_SCALE_8X << LV0104CS_SCALE_SHIFT },
0123 };
0124 
0125 static const struct lv0104cs_mapping lv0104cs_int_times[] = {
0126     { 0, 12500, LV0104CS_INTEG_12_5MS << LV0104CS_INTEG_SHIFT },
0127     { 0, 100000, LV0104CS_INTEG_100MS << LV0104CS_INTEG_SHIFT },
0128     { 0, 200000, LV0104CS_INTEG_200MS << LV0104CS_INTEG_SHIFT },
0129 };
0130 
0131 static int lv0104cs_write_reg(struct i2c_client *client, u8 regval)
0132 {
0133     int ret;
0134 
0135     ret = i2c_master_send(client, (char *)&regval, sizeof(regval));
0136     if (ret < 0)
0137         return ret;
0138     if (ret != sizeof(regval))
0139         return -EIO;
0140 
0141     return 0;
0142 }
0143 
0144 static int lv0104cs_read_adc(struct i2c_client *client, u16 *adc_output)
0145 {
0146     __be16 regval;
0147     int ret;
0148 
0149     ret = i2c_master_recv(client, (char *)&regval, sizeof(regval));
0150     if (ret < 0)
0151         return ret;
0152     if (ret != sizeof(regval))
0153         return -EIO;
0154 
0155     *adc_output = be16_to_cpu(regval);
0156 
0157     return 0;
0158 }
0159 
0160 static int lv0104cs_get_lux(struct lv0104cs_private *lv0104cs,
0161                 int *val, int *val2)
0162 {
0163     u8 regval = LV0104CS_REGVAL_MEASURE;
0164     u16 adc_output;
0165     int ret;
0166 
0167     regval |= lv0104cs_scales[lv0104cs->scale].regval;
0168     regval |= lv0104cs_int_times[lv0104cs->int_time].regval;
0169     ret = lv0104cs_write_reg(lv0104cs->client, regval);
0170     if (ret)
0171         return ret;
0172 
0173     /* wait for integration time to pass (with margin) */
0174     switch (lv0104cs->int_time) {
0175     case LV0104CS_INTEG_12_5MS:
0176         msleep(50);
0177         break;
0178 
0179     case LV0104CS_INTEG_100MS:
0180         msleep(150);
0181         break;
0182 
0183     case LV0104CS_INTEG_200MS:
0184         msleep(250);
0185         break;
0186 
0187     default:
0188         return -EINVAL;
0189     }
0190 
0191     ret = lv0104cs_read_adc(lv0104cs->client, &adc_output);
0192     if (ret)
0193         return ret;
0194 
0195     ret = lv0104cs_write_reg(lv0104cs->client, LV0104CS_REGVAL_SLEEP);
0196     if (ret)
0197         return ret;
0198 
0199     /* convert ADC output to lux */
0200     switch (lv0104cs->scale) {
0201     case LV0104CS_SCALE_0_25X:
0202         *val = adc_output * 4;
0203         *val2 = 0;
0204         return 0;
0205 
0206     case LV0104CS_SCALE_1X:
0207         *val = adc_output;
0208         *val2 = 0;
0209         return 0;
0210 
0211     case LV0104CS_SCALE_2X:
0212         *val = adc_output / 2;
0213         *val2 = (adc_output % 2) * 500000;
0214         return 0;
0215 
0216     case LV0104CS_SCALE_8X:
0217         *val = adc_output / 8;
0218         *val2 = (adc_output % 8) * 125000;
0219         return 0;
0220 
0221     default:
0222         return -EINVAL;
0223     }
0224 }
0225 
0226 static int lv0104cs_read_raw(struct iio_dev *indio_dev,
0227                 struct iio_chan_spec const *chan,
0228                 int *val, int *val2, long mask)
0229 {
0230     struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
0231     int ret;
0232 
0233     if (chan->type != IIO_LIGHT)
0234         return -EINVAL;
0235 
0236     mutex_lock(&lv0104cs->lock);
0237 
0238     switch (mask) {
0239     case IIO_CHAN_INFO_PROCESSED:
0240         ret = lv0104cs_get_lux(lv0104cs, val, val2);
0241         if (ret)
0242             goto err_mutex;
0243         ret = IIO_VAL_INT_PLUS_MICRO;
0244         break;
0245 
0246     case IIO_CHAN_INFO_CALIBSCALE:
0247         *val = lv0104cs_calibscales[lv0104cs->calibscale].val;
0248         *val2 = lv0104cs_calibscales[lv0104cs->calibscale].val2;
0249         ret = IIO_VAL_INT_PLUS_MICRO;
0250         break;
0251 
0252     case IIO_CHAN_INFO_SCALE:
0253         *val = lv0104cs_scales[lv0104cs->scale].val;
0254         *val2 = lv0104cs_scales[lv0104cs->scale].val2;
0255         ret = IIO_VAL_INT_PLUS_MICRO;
0256         break;
0257 
0258     case IIO_CHAN_INFO_INT_TIME:
0259         *val = lv0104cs_int_times[lv0104cs->int_time].val;
0260         *val2 = lv0104cs_int_times[lv0104cs->int_time].val2;
0261         ret = IIO_VAL_INT_PLUS_MICRO;
0262         break;
0263 
0264     default:
0265         ret = -EINVAL;
0266     }
0267 
0268 err_mutex:
0269     mutex_unlock(&lv0104cs->lock);
0270 
0271     return ret;
0272 }
0273 
0274 static int lv0104cs_set_calibscale(struct lv0104cs_private *lv0104cs,
0275                 int val, int val2)
0276 {
0277     int calibscale = val * 1000000 + val2;
0278     int floor, ceil, mid;
0279     int ret, i, index;
0280 
0281     /* round to nearest quantized calibscale (sensitivity) */
0282     for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales) - 1; i++) {
0283         floor = lv0104cs_calibscales[i].val * 1000000
0284                 + lv0104cs_calibscales[i].val2;
0285         ceil = lv0104cs_calibscales[i + 1].val * 1000000
0286                 + lv0104cs_calibscales[i + 1].val2;
0287         mid = (floor + ceil) / 2;
0288 
0289         /* round down */
0290         if (calibscale >= floor && calibscale < mid) {
0291             index = i;
0292             break;
0293         }
0294 
0295         /* round up */
0296         if (calibscale >= mid && calibscale <= ceil) {
0297             index = i + 1;
0298             break;
0299         }
0300     }
0301 
0302     if (i == ARRAY_SIZE(lv0104cs_calibscales) - 1)
0303         return -EINVAL;
0304 
0305     mutex_lock(&lv0104cs->lock);
0306 
0307     /* set calibscale (sensitivity) */
0308     ret = lv0104cs_write_reg(lv0104cs->client,
0309             lv0104cs_calibscales[index].regval);
0310     if (ret)
0311         goto err_mutex;
0312 
0313     lv0104cs->calibscale = index;
0314 
0315 err_mutex:
0316     mutex_unlock(&lv0104cs->lock);
0317 
0318     return ret;
0319 }
0320 
0321 static int lv0104cs_set_scale(struct lv0104cs_private *lv0104cs,
0322                 int val, int val2)
0323 {
0324     int i;
0325 
0326     /* hard matching */
0327     for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
0328         if (val != lv0104cs_scales[i].val)
0329             continue;
0330 
0331         if (val2 == lv0104cs_scales[i].val2)
0332             break;
0333     }
0334 
0335     if (i == ARRAY_SIZE(lv0104cs_scales))
0336         return -EINVAL;
0337 
0338     mutex_lock(&lv0104cs->lock);
0339     lv0104cs->scale = i;
0340     mutex_unlock(&lv0104cs->lock);
0341 
0342     return 0;
0343 }
0344 
0345 static int lv0104cs_set_int_time(struct lv0104cs_private *lv0104cs,
0346                 int val, int val2)
0347 {
0348     int i;
0349 
0350     /* hard matching */
0351     for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
0352         if (val != lv0104cs_int_times[i].val)
0353             continue;
0354 
0355         if (val2 == lv0104cs_int_times[i].val2)
0356             break;
0357     }
0358 
0359     if (i == ARRAY_SIZE(lv0104cs_int_times))
0360         return -EINVAL;
0361 
0362     mutex_lock(&lv0104cs->lock);
0363     lv0104cs->int_time = i;
0364     mutex_unlock(&lv0104cs->lock);
0365 
0366     return 0;
0367 }
0368 
0369 static int lv0104cs_write_raw(struct iio_dev *indio_dev,
0370                 struct iio_chan_spec const *chan,
0371                 int val, int val2, long mask)
0372 {
0373     struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
0374 
0375     if (chan->type != IIO_LIGHT)
0376         return -EINVAL;
0377 
0378     switch (mask) {
0379     case IIO_CHAN_INFO_CALIBSCALE:
0380         return lv0104cs_set_calibscale(lv0104cs, val, val2);
0381 
0382     case IIO_CHAN_INFO_SCALE:
0383         return lv0104cs_set_scale(lv0104cs, val, val2);
0384 
0385     case IIO_CHAN_INFO_INT_TIME:
0386         return lv0104cs_set_int_time(lv0104cs, val, val2);
0387 
0388     default:
0389         return -EINVAL;
0390     }
0391 }
0392 
0393 static ssize_t lv0104cs_show_calibscale_avail(struct device *dev,
0394                 struct device_attribute *attr, char *buf)
0395 {
0396     ssize_t len = 0;
0397     int i;
0398 
0399     for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales); i++) {
0400         len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
0401                 lv0104cs_calibscales[i].val,
0402                 lv0104cs_calibscales[i].val2);
0403     }
0404 
0405     buf[len - 1] = '\n';
0406 
0407     return len;
0408 }
0409 
0410 static ssize_t lv0104cs_show_scale_avail(struct device *dev,
0411                 struct device_attribute *attr, char *buf)
0412 {
0413     ssize_t len = 0;
0414     int i;
0415 
0416     for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
0417         len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
0418                 lv0104cs_scales[i].val,
0419                 lv0104cs_scales[i].val2);
0420     }
0421 
0422     buf[len - 1] = '\n';
0423 
0424     return len;
0425 }
0426 
0427 static ssize_t lv0104cs_show_int_time_avail(struct device *dev,
0428                 struct device_attribute *attr, char *buf)
0429 {
0430     ssize_t len = 0;
0431     int i;
0432 
0433     for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
0434         len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
0435                 lv0104cs_int_times[i].val,
0436                 lv0104cs_int_times[i].val2);
0437     }
0438 
0439     buf[len - 1] = '\n';
0440 
0441     return len;
0442 }
0443 
0444 static IIO_DEVICE_ATTR(calibscale_available, 0444,
0445                 lv0104cs_show_calibscale_avail, NULL, 0);
0446 static IIO_DEVICE_ATTR(scale_available, 0444,
0447                 lv0104cs_show_scale_avail, NULL, 0);
0448 static IIO_DEV_ATTR_INT_TIME_AVAIL(lv0104cs_show_int_time_avail);
0449 
0450 static struct attribute *lv0104cs_attributes[] = {
0451     &iio_dev_attr_calibscale_available.dev_attr.attr,
0452     &iio_dev_attr_scale_available.dev_attr.attr,
0453     &iio_dev_attr_integration_time_available.dev_attr.attr,
0454     NULL
0455 };
0456 
0457 static const struct attribute_group lv0104cs_attribute_group = {
0458     .attrs = lv0104cs_attributes,
0459 };
0460 
0461 static const struct iio_info lv0104cs_info = {
0462     .attrs = &lv0104cs_attribute_group,
0463     .read_raw = &lv0104cs_read_raw,
0464     .write_raw = &lv0104cs_write_raw,
0465 };
0466 
0467 static const struct iio_chan_spec lv0104cs_channels[] = {
0468     {
0469         .type = IIO_LIGHT,
0470         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
0471                       BIT(IIO_CHAN_INFO_CALIBSCALE) |
0472                       BIT(IIO_CHAN_INFO_SCALE) |
0473                       BIT(IIO_CHAN_INFO_INT_TIME),
0474     },
0475 };
0476 
0477 static int lv0104cs_probe(struct i2c_client *client,
0478                 const struct i2c_device_id *id)
0479 {
0480     struct iio_dev *indio_dev;
0481     struct lv0104cs_private *lv0104cs;
0482     int ret;
0483 
0484     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*lv0104cs));
0485     if (!indio_dev)
0486         return -ENOMEM;
0487 
0488     lv0104cs = iio_priv(indio_dev);
0489 
0490     i2c_set_clientdata(client, lv0104cs);
0491     lv0104cs->client = client;
0492 
0493     mutex_init(&lv0104cs->lock);
0494 
0495     lv0104cs->calibscale = LV0104CS_CALIBSCALE_UNITY;
0496     lv0104cs->scale = LV0104CS_SCALE_1X;
0497     lv0104cs->int_time = LV0104CS_INTEG_200MS;
0498 
0499     ret = lv0104cs_write_reg(lv0104cs->client,
0500             lv0104cs_calibscales[LV0104CS_CALIBSCALE_UNITY].regval);
0501     if (ret)
0502         return ret;
0503 
0504     indio_dev->modes = INDIO_DIRECT_MODE;
0505     indio_dev->channels = lv0104cs_channels;
0506     indio_dev->num_channels = ARRAY_SIZE(lv0104cs_channels);
0507     indio_dev->name = client->name;
0508     indio_dev->info = &lv0104cs_info;
0509 
0510     return devm_iio_device_register(&client->dev, indio_dev);
0511 }
0512 
0513 static const struct i2c_device_id lv0104cs_id[] = {
0514     { "lv0104cs", 0 },
0515     { }
0516 };
0517 MODULE_DEVICE_TABLE(i2c, lv0104cs_id);
0518 
0519 static struct i2c_driver lv0104cs_i2c_driver = {
0520     .driver = {
0521         .name   = "lv0104cs",
0522     },
0523     .id_table   = lv0104cs_id,
0524     .probe      = lv0104cs_probe,
0525 };
0526 module_i2c_driver(lv0104cs_i2c_driver);
0527 
0528 MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
0529 MODULE_DESCRIPTION("LV0104CS Ambient Light Sensor Driver");
0530 MODULE_LICENSE("GPL");