0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <linux/module.h>
0019 #include <linux/mod_devicetable.h>
0020 #include <linux/i2c.h>
0021 #include <linux/mutex.h>
0022 #include <linux/err.h>
0023 #include <linux/of.h>
0024 #include <linux/delay.h>
0025 #include <linux/util_macros.h>
0026
0027 #include <linux/iio/iio.h>
0028 #include <linux/iio/sysfs.h>
0029
0030 #define VL6180_DRV_NAME "vl6180"
0031
0032
0033 #define VL6180_MODEL_ID 0x000
0034 #define VL6180_MODEL_ID_VAL 0xb4
0035
0036
0037 #define VL6180_INTR_CONFIG 0x014
0038 #define VL6180_INTR_CLEAR 0x015
0039 #define VL6180_OUT_OF_RESET 0x016
0040 #define VL6180_HOLD 0x017
0041 #define VL6180_RANGE_START 0x018
0042 #define VL6180_ALS_START 0x038
0043 #define VL6180_ALS_GAIN 0x03f
0044 #define VL6180_ALS_IT 0x040
0045
0046
0047 #define VL6180_RANGE_STATUS 0x04d
0048 #define VL6180_ALS_STATUS 0x04e
0049 #define VL6180_INTR_STATUS 0x04f
0050
0051
0052 #define VL6180_ALS_VALUE 0x050
0053 #define VL6180_RANGE_VALUE 0x062
0054 #define VL6180_RANGE_RATE 0x066
0055
0056
0057 #define VL6180_MODE_CONT BIT(1)
0058 #define VL6180_STARTSTOP BIT(0)
0059
0060
0061 #define VL6180_ALS_READY BIT(5)
0062 #define VL6180_RANGE_READY BIT(2)
0063
0064
0065 #define VL6180_CLEAR_ERROR BIT(2)
0066 #define VL6180_CLEAR_ALS BIT(1)
0067 #define VL6180_CLEAR_RANGE BIT(0)
0068
0069
0070 #define VL6180_HOLD_ON BIT(0)
0071
0072
0073 #define VL6180_ALS_IT_100 0x63
0074
0075
0076 #define VL6180_ALS_GAIN_1 0x46
0077 #define VL6180_ALS_GAIN_1_25 0x45
0078 #define VL6180_ALS_GAIN_1_67 0x44
0079 #define VL6180_ALS_GAIN_2_5 0x43
0080 #define VL6180_ALS_GAIN_5 0x42
0081 #define VL6180_ALS_GAIN_10 0x41
0082 #define VL6180_ALS_GAIN_20 0x40
0083 #define VL6180_ALS_GAIN_40 0x47
0084
0085 struct vl6180_data {
0086 struct i2c_client *client;
0087 struct mutex lock;
0088 unsigned int als_gain_milli;
0089 unsigned int als_it_ms;
0090 };
0091
0092 enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
0093
0094
0095
0096
0097
0098
0099
0100
0101 struct vl6180_chan_regs {
0102 u8 drdy_mask;
0103 u16 start_reg, value_reg;
0104 bool word;
0105 };
0106
0107 static const struct vl6180_chan_regs vl6180_chan_regs_table[] = {
0108 [VL6180_ALS] = {
0109 .drdy_mask = VL6180_ALS_READY,
0110 .start_reg = VL6180_ALS_START,
0111 .value_reg = VL6180_ALS_VALUE,
0112 .word = true,
0113 },
0114 [VL6180_RANGE] = {
0115 .drdy_mask = VL6180_RANGE_READY,
0116 .start_reg = VL6180_RANGE_START,
0117 .value_reg = VL6180_RANGE_VALUE,
0118 .word = false,
0119 },
0120 [VL6180_PROX] = {
0121 .drdy_mask = VL6180_RANGE_READY,
0122 .start_reg = VL6180_RANGE_START,
0123 .value_reg = VL6180_RANGE_RATE,
0124 .word = true,
0125 },
0126 };
0127
0128 static int vl6180_read(struct i2c_client *client, u16 cmd, void *databuf,
0129 u8 len)
0130 {
0131 __be16 cmdbuf = cpu_to_be16(cmd);
0132 struct i2c_msg msgs[2] = {
0133 { .addr = client->addr, .len = sizeof(cmdbuf), .buf = (u8 *) &cmdbuf },
0134 { .addr = client->addr, .len = len, .buf = databuf,
0135 .flags = I2C_M_RD } };
0136 int ret;
0137
0138 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
0139 if (ret < 0)
0140 dev_err(&client->dev, "failed reading register 0x%04x\n", cmd);
0141
0142 return ret;
0143 }
0144
0145 static int vl6180_read_byte(struct i2c_client *client, u16 cmd)
0146 {
0147 u8 data;
0148 int ret;
0149
0150 ret = vl6180_read(client, cmd, &data, sizeof(data));
0151 if (ret < 0)
0152 return ret;
0153
0154 return data;
0155 }
0156
0157 static int vl6180_read_word(struct i2c_client *client, u16 cmd)
0158 {
0159 __be16 data;
0160 int ret;
0161
0162 ret = vl6180_read(client, cmd, &data, sizeof(data));
0163 if (ret < 0)
0164 return ret;
0165
0166 return be16_to_cpu(data);
0167 }
0168
0169 static int vl6180_write_byte(struct i2c_client *client, u16 cmd, u8 val)
0170 {
0171 u8 buf[3];
0172 struct i2c_msg msgs[1] = {
0173 { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
0174 int ret;
0175
0176 buf[0] = cmd >> 8;
0177 buf[1] = cmd & 0xff;
0178 buf[2] = val;
0179
0180 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
0181 if (ret < 0) {
0182 dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
0183 return ret;
0184 }
0185
0186 return 0;
0187 }
0188
0189 static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val)
0190 {
0191 __be16 buf[2];
0192 struct i2c_msg msgs[1] = {
0193 { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
0194 int ret;
0195
0196 buf[0] = cpu_to_be16(cmd);
0197 buf[1] = cpu_to_be16(val);
0198
0199 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
0200 if (ret < 0) {
0201 dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
0202 return ret;
0203 }
0204
0205 return 0;
0206 }
0207
0208 static int vl6180_measure(struct vl6180_data *data, int addr)
0209 {
0210 struct i2c_client *client = data->client;
0211 int tries = 20, ret;
0212 u16 value;
0213
0214 mutex_lock(&data->lock);
0215
0216 ret = vl6180_write_byte(client,
0217 vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP);
0218 if (ret < 0)
0219 goto fail;
0220
0221 while (tries--) {
0222 ret = vl6180_read_byte(client, VL6180_INTR_STATUS);
0223 if (ret < 0)
0224 goto fail;
0225
0226 if (ret & vl6180_chan_regs_table[addr].drdy_mask)
0227 break;
0228 msleep(20);
0229 }
0230
0231 if (tries < 0) {
0232 ret = -EIO;
0233 goto fail;
0234 }
0235
0236
0237 ret = vl6180_chan_regs_table[addr].word ?
0238 vl6180_read_word(client, vl6180_chan_regs_table[addr].value_reg) :
0239 vl6180_read_byte(client, vl6180_chan_regs_table[addr].value_reg);
0240 if (ret < 0)
0241 goto fail;
0242 value = ret;
0243
0244
0245 ret = vl6180_write_byte(client, VL6180_INTR_CLEAR,
0246 VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE);
0247 if (ret < 0)
0248 goto fail;
0249
0250 ret = value;
0251
0252 fail:
0253 mutex_unlock(&data->lock);
0254
0255 return ret;
0256 }
0257
0258 static const struct iio_chan_spec vl6180_channels[] = {
0259 {
0260 .type = IIO_LIGHT,
0261 .address = VL6180_ALS,
0262 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0263 BIT(IIO_CHAN_INFO_INT_TIME) |
0264 BIT(IIO_CHAN_INFO_SCALE) |
0265 BIT(IIO_CHAN_INFO_HARDWAREGAIN),
0266 }, {
0267 .type = IIO_DISTANCE,
0268 .address = VL6180_RANGE,
0269 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0270 BIT(IIO_CHAN_INFO_SCALE),
0271 }, {
0272 .type = IIO_PROXIMITY,
0273 .address = VL6180_PROX,
0274 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0275 }
0276 };
0277
0278
0279
0280
0281
0282 static const int vl6180_als_gain_tab[8] = {
0283 1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
0284 };
0285 static const u8 vl6180_als_gain_tab_bits[8] = {
0286 VL6180_ALS_GAIN_1, VL6180_ALS_GAIN_1_25,
0287 VL6180_ALS_GAIN_1_67, VL6180_ALS_GAIN_2_5,
0288 VL6180_ALS_GAIN_5, VL6180_ALS_GAIN_10,
0289 VL6180_ALS_GAIN_20, VL6180_ALS_GAIN_40
0290 };
0291
0292 static int vl6180_read_raw(struct iio_dev *indio_dev,
0293 struct iio_chan_spec const *chan,
0294 int *val, int *val2, long mask)
0295 {
0296 struct vl6180_data *data = iio_priv(indio_dev);
0297 int ret;
0298
0299 switch (mask) {
0300 case IIO_CHAN_INFO_RAW:
0301 ret = vl6180_measure(data, chan->address);
0302 if (ret < 0)
0303 return ret;
0304 *val = ret;
0305
0306 return IIO_VAL_INT;
0307 case IIO_CHAN_INFO_INT_TIME:
0308 *val = data->als_it_ms;
0309 *val2 = 1000;
0310
0311 return IIO_VAL_FRACTIONAL;
0312
0313 case IIO_CHAN_INFO_SCALE:
0314 switch (chan->type) {
0315 case IIO_LIGHT:
0316
0317 *val = 32000;
0318 *val2 = data->als_gain_milli * data->als_it_ms;
0319
0320 return IIO_VAL_FRACTIONAL;
0321
0322 case IIO_DISTANCE:
0323 *val = 0;
0324 *val2 = 1000;
0325 break;
0326 default:
0327 return -EINVAL;
0328 }
0329
0330 return IIO_VAL_INT_PLUS_MICRO;
0331 case IIO_CHAN_INFO_HARDWAREGAIN:
0332 *val = data->als_gain_milli;
0333 *val2 = 1000;
0334
0335 return IIO_VAL_FRACTIONAL;
0336
0337 default:
0338 return -EINVAL;
0339 }
0340 }
0341
0342 static IIO_CONST_ATTR(als_gain_available, "1 1.25 1.67 2.5 5 10 20 40");
0343
0344 static struct attribute *vl6180_attributes[] = {
0345 &iio_const_attr_als_gain_available.dev_attr.attr,
0346 NULL
0347 };
0348
0349 static const struct attribute_group vl6180_attribute_group = {
0350 .attrs = vl6180_attributes,
0351 };
0352
0353
0354 static int vl6180_hold(struct vl6180_data *data, bool hold)
0355 {
0356 return vl6180_write_byte(data->client, VL6180_HOLD,
0357 hold ? VL6180_HOLD_ON : 0);
0358 }
0359
0360 static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
0361 {
0362 int i, ret, gain;
0363
0364 if (val < 1 || val > 40)
0365 return -EINVAL;
0366
0367 gain = (val * 1000000 + val2) / 1000;
0368 if (gain < 1 || gain > 40000)
0369 return -EINVAL;
0370
0371 i = find_closest(gain, vl6180_als_gain_tab,
0372 ARRAY_SIZE(vl6180_als_gain_tab));
0373
0374 mutex_lock(&data->lock);
0375 ret = vl6180_hold(data, true);
0376 if (ret < 0)
0377 goto fail;
0378
0379 ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
0380 vl6180_als_gain_tab_bits[i]);
0381
0382 if (ret >= 0)
0383 data->als_gain_milli = vl6180_als_gain_tab[i];
0384
0385 fail:
0386 vl6180_hold(data, false);
0387 mutex_unlock(&data->lock);
0388 return ret;
0389 }
0390
0391 static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
0392 {
0393 int ret, it_ms;
0394
0395 it_ms = DIV_ROUND_CLOSEST(val2, 1000);
0396 if (val != 0 || it_ms < 1 || it_ms > 512)
0397 return -EINVAL;
0398
0399 mutex_lock(&data->lock);
0400 ret = vl6180_hold(data, true);
0401 if (ret < 0)
0402 goto fail;
0403
0404 ret = vl6180_write_word(data->client, VL6180_ALS_IT, it_ms - 1);
0405
0406 if (ret >= 0)
0407 data->als_it_ms = it_ms;
0408
0409 fail:
0410 vl6180_hold(data, false);
0411 mutex_unlock(&data->lock);
0412
0413 return ret;
0414 }
0415
0416 static int vl6180_write_raw(struct iio_dev *indio_dev,
0417 struct iio_chan_spec const *chan,
0418 int val, int val2, long mask)
0419 {
0420 struct vl6180_data *data = iio_priv(indio_dev);
0421
0422 switch (mask) {
0423 case IIO_CHAN_INFO_INT_TIME:
0424 return vl6180_set_it(data, val, val2);
0425
0426 case IIO_CHAN_INFO_HARDWAREGAIN:
0427 if (chan->type != IIO_LIGHT)
0428 return -EINVAL;
0429
0430 return vl6180_set_als_gain(data, val, val2);
0431 default:
0432 return -EINVAL;
0433 }
0434 }
0435
0436 static const struct iio_info vl6180_info = {
0437 .read_raw = vl6180_read_raw,
0438 .write_raw = vl6180_write_raw,
0439 .attrs = &vl6180_attribute_group,
0440 };
0441
0442 static int vl6180_init(struct vl6180_data *data)
0443 {
0444 struct i2c_client *client = data->client;
0445 int ret;
0446
0447 ret = vl6180_read_byte(client, VL6180_MODEL_ID);
0448 if (ret < 0)
0449 return ret;
0450
0451 if (ret != VL6180_MODEL_ID_VAL) {
0452 dev_err(&client->dev, "invalid model ID %02x\n", ret);
0453 return -ENODEV;
0454 }
0455
0456 ret = vl6180_hold(data, true);
0457 if (ret < 0)
0458 return ret;
0459
0460 ret = vl6180_read_byte(client, VL6180_OUT_OF_RESET);
0461 if (ret < 0)
0462 return ret;
0463
0464
0465
0466
0467
0468 if (ret != 0x01)
0469 dev_info(&client->dev, "device is not fresh out of reset\n");
0470
0471
0472 ret = vl6180_write_byte(client, VL6180_INTR_CONFIG,
0473 VL6180_ALS_READY | VL6180_RANGE_READY);
0474 if (ret < 0)
0475 return ret;
0476
0477
0478 data->als_it_ms = 100;
0479 ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
0480 if (ret < 0)
0481 return ret;
0482
0483
0484 data->als_gain_milli = 1000;
0485 ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
0486 if (ret < 0)
0487 return ret;
0488
0489 ret = vl6180_write_byte(client, VL6180_OUT_OF_RESET, 0x00);
0490 if (ret < 0)
0491 return ret;
0492
0493 return vl6180_hold(data, false);
0494 }
0495
0496 static int vl6180_probe(struct i2c_client *client,
0497 const struct i2c_device_id *id)
0498 {
0499 struct vl6180_data *data;
0500 struct iio_dev *indio_dev;
0501 int ret;
0502
0503 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0504 if (!indio_dev)
0505 return -ENOMEM;
0506
0507 data = iio_priv(indio_dev);
0508 i2c_set_clientdata(client, indio_dev);
0509 data->client = client;
0510 mutex_init(&data->lock);
0511
0512 indio_dev->info = &vl6180_info;
0513 indio_dev->channels = vl6180_channels;
0514 indio_dev->num_channels = ARRAY_SIZE(vl6180_channels);
0515 indio_dev->name = VL6180_DRV_NAME;
0516 indio_dev->modes = INDIO_DIRECT_MODE;
0517
0518 ret = vl6180_init(data);
0519 if (ret < 0)
0520 return ret;
0521
0522 return devm_iio_device_register(&client->dev, indio_dev);
0523 }
0524
0525 static const struct of_device_id vl6180_of_match[] = {
0526 { .compatible = "st,vl6180", },
0527 { },
0528 };
0529 MODULE_DEVICE_TABLE(of, vl6180_of_match);
0530
0531 static const struct i2c_device_id vl6180_id[] = {
0532 { "vl6180", 0 },
0533 { }
0534 };
0535 MODULE_DEVICE_TABLE(i2c, vl6180_id);
0536
0537 static struct i2c_driver vl6180_driver = {
0538 .driver = {
0539 .name = VL6180_DRV_NAME,
0540 .of_match_table = vl6180_of_match,
0541 },
0542 .probe = vl6180_probe,
0543 .id_table = vl6180_id,
0544 };
0545
0546 module_i2c_driver(vl6180_driver);
0547
0548 MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
0549 MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
0550 MODULE_DESCRIPTION("STMicro VL6180 ALS, range and proximity sensor driver");
0551 MODULE_LICENSE("GPL");