Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Support for ON Semiconductor NOA1305 ambient light sensor
0004  *
0005  * Copyright (C) 2016 Emcraft Systems
0006  * Copyright (C) 2019 Collabora Ltd.
0007  */
0008 
0009 #include <linux/delay.h>
0010 #include <linux/err.h>
0011 #include <linux/i2c.h>
0012 #include <linux/iio/iio.h>
0013 #include <linux/iio/sysfs.h>
0014 #include <linux/module.h>
0015 #include <linux/regmap.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #define NOA1305_REG_POWER_CONTROL   0x0
0019 #define   NOA1305_POWER_CONTROL_DOWN    0x00
0020 #define   NOA1305_POWER_CONTROL_ON  0x08
0021 #define NOA1305_REG_RESET       0x1
0022 #define   NOA1305_RESET_RESET       0x10
0023 #define NOA1305_REG_INTEGRATION_TIME    0x2
0024 #define   NOA1305_INTEGR_TIME_800MS 0x00
0025 #define   NOA1305_INTEGR_TIME_400MS 0x01
0026 #define   NOA1305_INTEGR_TIME_200MS 0x02
0027 #define   NOA1305_INTEGR_TIME_100MS 0x03
0028 #define   NOA1305_INTEGR_TIME_50MS  0x04
0029 #define   NOA1305_INTEGR_TIME_25MS  0x05
0030 #define   NOA1305_INTEGR_TIME_12_5MS    0x06
0031 #define   NOA1305_INTEGR_TIME_6_25MS    0x07
0032 #define NOA1305_REG_INT_SELECT      0x3
0033 #define   NOA1305_INT_SEL_ACTIVE_HIGH   0x01
0034 #define   NOA1305_INT_SEL_ACTIVE_LOW    0x02
0035 #define   NOA1305_INT_SEL_INACTIVE  0x03
0036 #define NOA1305_REG_INT_THRESH_LSB  0x4
0037 #define NOA1305_REG_INT_THRESH_MSB  0x5
0038 #define NOA1305_REG_ALS_DATA_LSB    0x6
0039 #define NOA1305_REG_ALS_DATA_MSB    0x7
0040 #define NOA1305_REG_DEVICE_ID_LSB   0x8
0041 #define NOA1305_REG_DEVICE_ID_MSB   0x9
0042 
0043 #define NOA1305_DEVICE_ID   0x0519
0044 #define NOA1305_DRIVER_NAME "noa1305"
0045 
0046 struct noa1305_priv {
0047     struct i2c_client *client;
0048     struct regmap *regmap;
0049     struct regulator *vin_reg;
0050 };
0051 
0052 static int noa1305_measure(struct noa1305_priv *priv)
0053 {
0054     __le16 data;
0055     int ret;
0056 
0057     ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data,
0058                    2);
0059     if (ret < 0)
0060         return ret;
0061 
0062     return le16_to_cpu(data);
0063 }
0064 
0065 static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2)
0066 {
0067     int data;
0068     int ret;
0069 
0070     ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data);
0071     if (ret < 0)
0072         return ret;
0073 
0074     /*
0075      * Lux = count / (<Integration Constant> * <Integration Time>)
0076      *
0077      * Integration Constant = 7.7
0078      * Integration Time in Seconds
0079      */
0080     switch (data) {
0081     case NOA1305_INTEGR_TIME_800MS:
0082         *val = 100;
0083         *val2 = 77 * 8;
0084         break;
0085     case NOA1305_INTEGR_TIME_400MS:
0086         *val = 100;
0087         *val2 = 77 * 4;
0088         break;
0089     case NOA1305_INTEGR_TIME_200MS:
0090         *val = 100;
0091         *val2 = 77 * 2;
0092         break;
0093     case NOA1305_INTEGR_TIME_100MS:
0094         *val = 100;
0095         *val2 = 77;
0096         break;
0097     case NOA1305_INTEGR_TIME_50MS:
0098         *val = 1000;
0099         *val2 = 77 * 5;
0100         break;
0101     case NOA1305_INTEGR_TIME_25MS:
0102         *val = 10000;
0103         *val2 = 77 * 25;
0104         break;
0105     case NOA1305_INTEGR_TIME_12_5MS:
0106         *val = 100000;
0107         *val2 = 77 * 125;
0108         break;
0109     case NOA1305_INTEGR_TIME_6_25MS:
0110         *val = 1000000;
0111         *val2 = 77 * 625;
0112         break;
0113     default:
0114         return -EINVAL;
0115     }
0116 
0117     return IIO_VAL_FRACTIONAL;
0118 }
0119 
0120 static const struct iio_chan_spec noa1305_channels[] = {
0121     {
0122         .type = IIO_LIGHT,
0123         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0124         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
0125     }
0126 };
0127 
0128 static int noa1305_read_raw(struct iio_dev *indio_dev,
0129                 struct iio_chan_spec const *chan,
0130                 int *val, int *val2, long mask)
0131 {
0132     int ret = -EINVAL;
0133     struct noa1305_priv *priv = iio_priv(indio_dev);
0134 
0135     switch (mask) {
0136     case IIO_CHAN_INFO_RAW:
0137         switch (chan->type) {
0138         case IIO_LIGHT:
0139             ret = noa1305_measure(priv);
0140             if (ret < 0)
0141                 return ret;
0142             *val = ret;
0143             return IIO_VAL_INT;
0144         default:
0145             break;
0146         }
0147         break;
0148     case IIO_CHAN_INFO_SCALE:
0149         switch (chan->type) {
0150         case IIO_LIGHT:
0151             return noa1305_scale(priv, val, val2);
0152         default:
0153             break;
0154         }
0155         break;
0156     default:
0157         break;
0158     }
0159 
0160     return ret;
0161 }
0162 
0163 static const struct iio_info noa1305_info = {
0164     .read_raw = noa1305_read_raw,
0165 };
0166 
0167 static bool noa1305_writable_reg(struct device *dev, unsigned int reg)
0168 {
0169     switch (reg) {
0170     case NOA1305_REG_POWER_CONTROL:
0171     case NOA1305_REG_RESET:
0172     case NOA1305_REG_INTEGRATION_TIME:
0173     case NOA1305_REG_INT_SELECT:
0174     case NOA1305_REG_INT_THRESH_LSB:
0175     case NOA1305_REG_INT_THRESH_MSB:
0176         return true;
0177     default:
0178         return false;
0179     }
0180 }
0181 
0182 static const struct regmap_config noa1305_regmap_config = {
0183     .name = NOA1305_DRIVER_NAME,
0184     .reg_bits = 8,
0185     .val_bits = 8,
0186     .max_register = NOA1305_REG_DEVICE_ID_MSB,
0187     .writeable_reg = noa1305_writable_reg,
0188 };
0189 
0190 static void noa1305_reg_remove(void *data)
0191 {
0192     struct noa1305_priv *priv = data;
0193 
0194     regulator_disable(priv->vin_reg);
0195 }
0196 
0197 static int noa1305_probe(struct i2c_client *client,
0198              const struct i2c_device_id *id)
0199 {
0200     struct noa1305_priv *priv;
0201     struct iio_dev *indio_dev;
0202     struct regmap *regmap;
0203     __le16 data;
0204     unsigned int dev_id;
0205     int ret;
0206 
0207     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv));
0208     if (!indio_dev)
0209         return -ENOMEM;
0210 
0211     regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config);
0212     if (IS_ERR(regmap)) {
0213         dev_err(&client->dev, "Regmap initialization failed.\n");
0214         return PTR_ERR(regmap);
0215     }
0216 
0217     priv = iio_priv(indio_dev);
0218 
0219     priv->vin_reg = devm_regulator_get(&client->dev, "vin");
0220     if (IS_ERR(priv->vin_reg))
0221         return dev_err_probe(&client->dev, PTR_ERR(priv->vin_reg),
0222                      "get regulator vin failed\n");
0223 
0224     ret = regulator_enable(priv->vin_reg);
0225     if (ret) {
0226         dev_err(&client->dev, "enable regulator vin failed\n");
0227         return ret;
0228     }
0229 
0230     ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
0231     if (ret) {
0232         dev_err(&client->dev, "addition of devm action failed\n");
0233         return ret;
0234     }
0235 
0236     i2c_set_clientdata(client, indio_dev);
0237     priv->client = client;
0238     priv->regmap = regmap;
0239 
0240     ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2);
0241     if (ret < 0) {
0242         dev_err(&client->dev, "ID reading failed: %d\n", ret);
0243         return ret;
0244     }
0245 
0246     dev_id = le16_to_cpu(data);
0247     if (dev_id != NOA1305_DEVICE_ID) {
0248         dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id);
0249         return -ENODEV;
0250     }
0251 
0252     ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL,
0253                NOA1305_POWER_CONTROL_ON);
0254     if (ret < 0) {
0255         dev_err(&client->dev, "Enabling power control failed\n");
0256         return ret;
0257     }
0258 
0259     ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET);
0260     if (ret < 0) {
0261         dev_err(&client->dev, "Device reset failed\n");
0262         return ret;
0263     }
0264 
0265     ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME,
0266                NOA1305_INTEGR_TIME_800MS);
0267     if (ret < 0) {
0268         dev_err(&client->dev, "Setting integration time failed\n");
0269         return ret;
0270     }
0271 
0272     indio_dev->info = &noa1305_info;
0273     indio_dev->channels = noa1305_channels;
0274     indio_dev->num_channels = ARRAY_SIZE(noa1305_channels);
0275     indio_dev->name = NOA1305_DRIVER_NAME;
0276     indio_dev->modes = INDIO_DIRECT_MODE;
0277 
0278     ret = devm_iio_device_register(&client->dev, indio_dev);
0279     if (ret)
0280         dev_err(&client->dev, "registering device failed\n");
0281 
0282     return ret;
0283 }
0284 
0285 static const struct of_device_id noa1305_of_match[] = {
0286     { .compatible = "onnn,noa1305" },
0287     { }
0288 };
0289 MODULE_DEVICE_TABLE(of, noa1305_of_match);
0290 
0291 static const struct i2c_device_id noa1305_ids[] = {
0292     { "noa1305", 0 },
0293     { }
0294 };
0295 MODULE_DEVICE_TABLE(i2c, noa1305_ids);
0296 
0297 static struct i2c_driver noa1305_driver = {
0298     .driver = {
0299         .name       = NOA1305_DRIVER_NAME,
0300         .of_match_table = noa1305_of_match,
0301     },
0302     .probe      = noa1305_probe,
0303     .id_table   = noa1305_ids,
0304 };
0305 
0306 module_i2c_driver(noa1305_driver);
0307 
0308 MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>");
0309 MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com");
0310 MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor");
0311 MODULE_LICENSE("GPL");