0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/i2c.h>
0009 #include <linux/err.h>
0010 #include <linux/delay.h>
0011 #include <linux/regmap.h>
0012 #include <linux/interrupt.h>
0013
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/events.h>
0016
0017 #define VCNL3020_PROD_ID 0x21
0018
0019 #define VCNL_COMMAND 0x80
0020 #define VCNL_PROD_REV 0x81
0021 #define VCNL_PROXIMITY_RATE 0x82
0022 #define VCNL_LED_CURRENT 0x83
0023 #define VCNL_PS_RESULT_HI 0x87
0024 #define VCNL_PS_RESULT_LO 0x88
0025 #define VCNL_PS_ICR 0x89
0026 #define VCNL_PS_LO_THR_HI 0x8a
0027 #define VCNL_PS_LO_THR_LO 0x8b
0028 #define VCNL_PS_HI_THR_HI 0x8c
0029 #define VCNL_PS_HI_THR_LO 0x8d
0030 #define VCNL_ISR 0x8e
0031 #define VCNL_PS_MOD_ADJ 0x8f
0032
0033
0034 #define VCNL_PS_RDY BIT(5)
0035 #define VCNL_PS_OD BIT(3)
0036
0037
0038
0039
0040 #define VCNL_PS_EN BIT(1)
0041
0042
0043 #define VCNL_PS_SELFTIMED_EN BIT(0)
0044
0045
0046
0047
0048 #define VCNL_ICR_THRES_EN BIT(1)
0049
0050
0051 #define VCNL_INT_TH_HI BIT(0)
0052 #define VCNL_INT_TH_LOW BIT(1)
0053
0054 #define VCNL_ON_DEMAND_TIMEOUT_US 100000
0055 #define VCNL_POLL_US 20000
0056
0057 static const int vcnl3020_prox_sampling_frequency[][2] = {
0058 {1, 950000},
0059 {3, 906250},
0060 {7, 812500},
0061 {16, 625000},
0062 {31, 250000},
0063 {62, 500000},
0064 {125, 0},
0065 {250, 0},
0066 };
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 struct vcnl3020_data {
0077 struct regmap *regmap;
0078 struct device *dev;
0079 u8 rev;
0080 struct mutex lock;
0081 __be16 buf;
0082 };
0083
0084
0085
0086
0087
0088
0089
0090 struct vcnl3020_property {
0091 const char *name;
0092 u32 reg;
0093 u32 (*conversion_func)(u32 *val);
0094 };
0095
0096 static u32 microamp_to_reg(u32 *val)
0097 {
0098
0099
0100
0101
0102 return *val /= 10000;
0103 };
0104
0105 static struct vcnl3020_property vcnl3020_led_current_property = {
0106 .name = "vishay,led-current-microamp",
0107 .reg = VCNL_LED_CURRENT,
0108 .conversion_func = microamp_to_reg,
0109 };
0110
0111 static int vcnl3020_get_and_apply_property(struct vcnl3020_data *data,
0112 struct vcnl3020_property prop)
0113 {
0114 int rc;
0115 u32 val;
0116
0117 rc = device_property_read_u32(data->dev, prop.name, &val);
0118 if (rc)
0119 return 0;
0120
0121 if (prop.conversion_func)
0122 prop.conversion_func(&val);
0123
0124 rc = regmap_write(data->regmap, prop.reg, val);
0125 if (rc) {
0126 dev_err(data->dev, "Error (%d) setting property (%s)\n",
0127 rc, prop.name);
0128 }
0129
0130 return rc;
0131 }
0132
0133 static int vcnl3020_init(struct vcnl3020_data *data)
0134 {
0135 int rc;
0136 unsigned int reg;
0137
0138 rc = regmap_read(data->regmap, VCNL_PROD_REV, ®);
0139 if (rc) {
0140 dev_err(data->dev,
0141 "Error (%d) reading product revision\n", rc);
0142 return rc;
0143 }
0144
0145 if (reg != VCNL3020_PROD_ID) {
0146 dev_err(data->dev,
0147 "Product id (%x) did not match vcnl3020 (%x)\n", reg,
0148 VCNL3020_PROD_ID);
0149 return -ENODEV;
0150 }
0151
0152 data->rev = reg;
0153 mutex_init(&data->lock);
0154
0155 return vcnl3020_get_and_apply_property(data,
0156 vcnl3020_led_current_property);
0157 };
0158
0159 static bool vcnl3020_is_in_periodic_mode(struct vcnl3020_data *data)
0160 {
0161 int rc;
0162 unsigned int cmd;
0163
0164 rc = regmap_read(data->regmap, VCNL_COMMAND, &cmd);
0165 if (rc) {
0166 dev_err(data->dev,
0167 "Error (%d) reading command register\n", rc);
0168 return false;
0169 }
0170
0171 return !!(cmd & VCNL_PS_SELFTIMED_EN);
0172 }
0173
0174 static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
0175 {
0176 int rc;
0177 unsigned int reg;
0178
0179 mutex_lock(&data->lock);
0180
0181
0182 if (vcnl3020_is_in_periodic_mode(data)) {
0183 rc = -EBUSY;
0184 goto err_unlock;
0185 }
0186
0187 rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD);
0188 if (rc)
0189 goto err_unlock;
0190
0191
0192 rc = regmap_read_poll_timeout(data->regmap, VCNL_COMMAND, reg,
0193 reg & VCNL_PS_RDY, VCNL_POLL_US,
0194 VCNL_ON_DEMAND_TIMEOUT_US);
0195 if (rc) {
0196 dev_err(data->dev,
0197 "Error (%d) reading vcnl3020 command register\n", rc);
0198 goto err_unlock;
0199 }
0200
0201
0202 rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &data->buf,
0203 sizeof(data->buf));
0204 if (rc)
0205 goto err_unlock;
0206
0207 *val = be16_to_cpu(data->buf);
0208
0209 err_unlock:
0210 mutex_unlock(&data->lock);
0211
0212 return rc;
0213 }
0214
0215 static int vcnl3020_read_proxy_samp_freq(struct vcnl3020_data *data, int *val,
0216 int *val2)
0217 {
0218 int rc;
0219 unsigned int prox_rate;
0220
0221 rc = regmap_read(data->regmap, VCNL_PROXIMITY_RATE, &prox_rate);
0222 if (rc)
0223 return rc;
0224
0225 if (prox_rate >= ARRAY_SIZE(vcnl3020_prox_sampling_frequency))
0226 return -EINVAL;
0227
0228 *val = vcnl3020_prox_sampling_frequency[prox_rate][0];
0229 *val2 = vcnl3020_prox_sampling_frequency[prox_rate][1];
0230
0231 return 0;
0232 }
0233
0234 static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
0235 int val2)
0236 {
0237 unsigned int i;
0238 int index = -1;
0239 int rc;
0240
0241 mutex_lock(&data->lock);
0242
0243
0244 if (vcnl3020_is_in_periodic_mode(data)) {
0245 rc = -EBUSY;
0246 goto err_unlock;
0247 }
0248
0249 for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
0250 if (val == vcnl3020_prox_sampling_frequency[i][0] &&
0251 val2 == vcnl3020_prox_sampling_frequency[i][1]) {
0252 index = i;
0253 break;
0254 }
0255 }
0256
0257 if (index < 0) {
0258 rc = -EINVAL;
0259 goto err_unlock;
0260 }
0261
0262 rc = regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
0263 if (rc)
0264 dev_err(data->dev,
0265 "Error (%d) writing proximity rate register\n", rc);
0266
0267 err_unlock:
0268 mutex_unlock(&data->lock);
0269
0270 return rc;
0271 }
0272
0273 static bool vcnl3020_is_thr_enabled(struct vcnl3020_data *data)
0274 {
0275 int rc;
0276 unsigned int icr;
0277
0278 rc = regmap_read(data->regmap, VCNL_PS_ICR, &icr);
0279 if (rc) {
0280 dev_err(data->dev,
0281 "Error (%d) reading ICR register\n", rc);
0282 return false;
0283 }
0284
0285 return !!(icr & VCNL_ICR_THRES_EN);
0286 }
0287
0288 static int vcnl3020_read_event(struct iio_dev *indio_dev,
0289 const struct iio_chan_spec *chan,
0290 enum iio_event_type type,
0291 enum iio_event_direction dir,
0292 enum iio_event_info info,
0293 int *val, int *val2)
0294 {
0295 int rc;
0296 struct vcnl3020_data *data = iio_priv(indio_dev);
0297
0298 switch (info) {
0299 case IIO_EV_INFO_VALUE:
0300 switch (dir) {
0301 case IIO_EV_DIR_RISING:
0302 rc = regmap_bulk_read(data->regmap, VCNL_PS_HI_THR_HI,
0303 &data->buf, sizeof(data->buf));
0304 if (rc < 0)
0305 return rc;
0306 *val = be16_to_cpu(data->buf);
0307 return IIO_VAL_INT;
0308 case IIO_EV_DIR_FALLING:
0309 rc = regmap_bulk_read(data->regmap, VCNL_PS_LO_THR_HI,
0310 &data->buf, sizeof(data->buf));
0311 if (rc < 0)
0312 return rc;
0313 *val = be16_to_cpu(data->buf);
0314 return IIO_VAL_INT;
0315 default:
0316 return -EINVAL;
0317 }
0318 default:
0319 return -EINVAL;
0320 }
0321 }
0322
0323 static int vcnl3020_write_event(struct iio_dev *indio_dev,
0324 const struct iio_chan_spec *chan,
0325 enum iio_event_type type,
0326 enum iio_event_direction dir,
0327 enum iio_event_info info,
0328 int val, int val2)
0329 {
0330 int rc;
0331 struct vcnl3020_data *data = iio_priv(indio_dev);
0332
0333 mutex_lock(&data->lock);
0334
0335 switch (info) {
0336 case IIO_EV_INFO_VALUE:
0337 switch (dir) {
0338 case IIO_EV_DIR_RISING:
0339
0340 data->buf = cpu_to_be16(val);
0341 rc = regmap_bulk_write(data->regmap, VCNL_PS_HI_THR_HI,
0342 &data->buf, sizeof(data->buf));
0343 if (rc < 0)
0344 goto err_unlock;
0345 rc = IIO_VAL_INT;
0346 goto err_unlock;
0347 case IIO_EV_DIR_FALLING:
0348 data->buf = cpu_to_be16(val);
0349 rc = regmap_bulk_write(data->regmap, VCNL_PS_LO_THR_HI,
0350 &data->buf, sizeof(data->buf));
0351 if (rc < 0)
0352 goto err_unlock;
0353 rc = IIO_VAL_INT;
0354 goto err_unlock;
0355 default:
0356 rc = -EINVAL;
0357 goto err_unlock;
0358 }
0359 default:
0360 rc = -EINVAL;
0361 goto err_unlock;
0362 }
0363 err_unlock:
0364 mutex_unlock(&data->lock);
0365
0366 return rc;
0367 }
0368
0369 static int vcnl3020_enable_periodic(struct iio_dev *indio_dev,
0370 struct vcnl3020_data *data)
0371 {
0372 int rc;
0373 int cmd;
0374
0375 mutex_lock(&data->lock);
0376
0377
0378 cmd = VCNL_PS_EN | VCNL_PS_SELFTIMED_EN;
0379
0380 rc = regmap_write(data->regmap, VCNL_COMMAND, cmd);
0381 if (rc) {
0382 dev_err(data->dev,
0383 "Error (%d) writing command register\n", rc);
0384 goto err_unlock;
0385 }
0386
0387
0388
0389
0390
0391 rc = regmap_write(data->regmap, VCNL_PS_ICR, VCNL_ICR_THRES_EN);
0392 if (rc)
0393 dev_err(data->dev,
0394 "Error (%d) reading ICR register\n", rc);
0395
0396 err_unlock:
0397 mutex_unlock(&data->lock);
0398
0399 return rc;
0400 }
0401
0402 static int vcnl3020_disable_periodic(struct iio_dev *indio_dev,
0403 struct vcnl3020_data *data)
0404 {
0405 int rc;
0406
0407 mutex_lock(&data->lock);
0408
0409 rc = regmap_write(data->regmap, VCNL_COMMAND, 0);
0410 if (rc) {
0411 dev_err(data->dev,
0412 "Error (%d) writing command register\n", rc);
0413 goto err_unlock;
0414 }
0415
0416 rc = regmap_write(data->regmap, VCNL_PS_ICR, 0);
0417 if (rc) {
0418 dev_err(data->dev,
0419 "Error (%d) writing ICR register\n", rc);
0420 goto err_unlock;
0421 }
0422
0423
0424 rc = regmap_write(data->regmap, VCNL_ISR, 0);
0425 if (rc)
0426 dev_err(data->dev,
0427 "Error (%d) writing ISR register\n", rc);
0428
0429 err_unlock:
0430 mutex_unlock(&data->lock);
0431
0432 return rc;
0433 }
0434
0435 static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
0436 {
0437 struct vcnl3020_data *data = iio_priv(indio_dev);
0438
0439 if (state) {
0440 return vcnl3020_enable_periodic(indio_dev, data);
0441 } else {
0442 if (!vcnl3020_is_thr_enabled(data))
0443 return 0;
0444 return vcnl3020_disable_periodic(indio_dev, data);
0445 }
0446 }
0447
0448 static int vcnl3020_write_event_config(struct iio_dev *indio_dev,
0449 const struct iio_chan_spec *chan,
0450 enum iio_event_type type,
0451 enum iio_event_direction dir,
0452 int state)
0453 {
0454 switch (chan->type) {
0455 case IIO_PROXIMITY:
0456 return vcnl3020_config_threshold(indio_dev, state);
0457 default:
0458 return -EINVAL;
0459 }
0460 }
0461
0462 static int vcnl3020_read_event_config(struct iio_dev *indio_dev,
0463 const struct iio_chan_spec *chan,
0464 enum iio_event_type type,
0465 enum iio_event_direction dir)
0466 {
0467 struct vcnl3020_data *data = iio_priv(indio_dev);
0468
0469 switch (chan->type) {
0470 case IIO_PROXIMITY:
0471 return vcnl3020_is_thr_enabled(data);
0472 default:
0473 return -EINVAL;
0474 }
0475 }
0476
0477 static const struct iio_event_spec vcnl3020_event_spec[] = {
0478 {
0479 .type = IIO_EV_TYPE_THRESH,
0480 .dir = IIO_EV_DIR_RISING,
0481 .mask_separate = BIT(IIO_EV_INFO_VALUE),
0482 }, {
0483 .type = IIO_EV_TYPE_THRESH,
0484 .dir = IIO_EV_DIR_FALLING,
0485 .mask_separate = BIT(IIO_EV_INFO_VALUE),
0486 }, {
0487 .type = IIO_EV_TYPE_THRESH,
0488 .dir = IIO_EV_DIR_EITHER,
0489 .mask_separate = BIT(IIO_EV_INFO_ENABLE),
0490 },
0491 };
0492
0493 static const struct iio_chan_spec vcnl3020_channels[] = {
0494 {
0495 .type = IIO_PROXIMITY,
0496 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0497 BIT(IIO_CHAN_INFO_SAMP_FREQ),
0498 .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
0499 .event_spec = vcnl3020_event_spec,
0500 .num_event_specs = ARRAY_SIZE(vcnl3020_event_spec),
0501 },
0502 };
0503
0504 static int vcnl3020_read_raw(struct iio_dev *indio_dev,
0505 struct iio_chan_spec const *chan, int *val,
0506 int *val2, long mask)
0507 {
0508 int rc;
0509 struct vcnl3020_data *data = iio_priv(indio_dev);
0510
0511 switch (mask) {
0512 case IIO_CHAN_INFO_RAW:
0513 rc = vcnl3020_measure_proximity(data, val);
0514 if (rc)
0515 return rc;
0516 return IIO_VAL_INT;
0517 case IIO_CHAN_INFO_SAMP_FREQ:
0518 rc = vcnl3020_read_proxy_samp_freq(data, val, val2);
0519 if (rc < 0)
0520 return rc;
0521 return IIO_VAL_INT_PLUS_MICRO;
0522 default:
0523 return -EINVAL;
0524 }
0525 }
0526
0527 static int vcnl3020_write_raw(struct iio_dev *indio_dev,
0528 struct iio_chan_spec const *chan,
0529 int val, int val2, long mask)
0530 {
0531 struct vcnl3020_data *data = iio_priv(indio_dev);
0532
0533 switch (mask) {
0534 case IIO_CHAN_INFO_SAMP_FREQ:
0535 return vcnl3020_write_proxy_samp_freq(data, val, val2);
0536 default:
0537 return -EINVAL;
0538 }
0539 }
0540
0541 static int vcnl3020_read_avail(struct iio_dev *indio_dev,
0542 struct iio_chan_spec const *chan,
0543 const int **vals, int *type, int *length,
0544 long mask)
0545 {
0546 switch (mask) {
0547 case IIO_CHAN_INFO_SAMP_FREQ:
0548 *vals = (int *)vcnl3020_prox_sampling_frequency;
0549 *type = IIO_VAL_INT_PLUS_MICRO;
0550 *length = 2 * ARRAY_SIZE(vcnl3020_prox_sampling_frequency);
0551 return IIO_AVAIL_LIST;
0552 default:
0553 return -EINVAL;
0554 }
0555 }
0556
0557 static const struct iio_info vcnl3020_info = {
0558 .read_raw = vcnl3020_read_raw,
0559 .write_raw = vcnl3020_write_raw,
0560 .read_avail = vcnl3020_read_avail,
0561 .read_event_value = vcnl3020_read_event,
0562 .write_event_value = vcnl3020_write_event,
0563 .read_event_config = vcnl3020_read_event_config,
0564 .write_event_config = vcnl3020_write_event_config,
0565 };
0566
0567 static const struct regmap_config vcnl3020_regmap_config = {
0568 .reg_bits = 8,
0569 .val_bits = 8,
0570 .max_register = VCNL_PS_MOD_ADJ,
0571 };
0572
0573 static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p)
0574 {
0575 struct iio_dev *indio_dev = p;
0576 struct vcnl3020_data *data = iio_priv(indio_dev);
0577 unsigned int isr;
0578 int rc;
0579
0580 rc = regmap_read(data->regmap, VCNL_ISR, &isr);
0581 if (rc) {
0582 dev_err(data->dev, "Error (%d) reading reg (0x%x)\n",
0583 rc, VCNL_ISR);
0584 return IRQ_HANDLED;
0585 }
0586
0587 if (!(isr & VCNL_ICR_THRES_EN))
0588 return IRQ_NONE;
0589
0590 iio_push_event(indio_dev,
0591 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
0592 IIO_EV_TYPE_THRESH,
0593 IIO_EV_DIR_RISING),
0594 iio_get_time_ns(indio_dev));
0595
0596 rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN);
0597 if (rc)
0598 dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n",
0599 rc, VCNL_ISR);
0600
0601 return IRQ_HANDLED;
0602 }
0603
0604 static int vcnl3020_probe(struct i2c_client *client)
0605 {
0606 struct vcnl3020_data *data;
0607 struct iio_dev *indio_dev;
0608 struct regmap *regmap;
0609 int rc;
0610
0611 regmap = devm_regmap_init_i2c(client, &vcnl3020_regmap_config);
0612 if (IS_ERR(regmap)) {
0613 dev_err(&client->dev, "regmap_init failed\n");
0614 return PTR_ERR(regmap);
0615 }
0616
0617 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0618 if (!indio_dev)
0619 return -ENOMEM;
0620
0621 data = iio_priv(indio_dev);
0622 i2c_set_clientdata(client, indio_dev);
0623 data->regmap = regmap;
0624 data->dev = &client->dev;
0625
0626 rc = vcnl3020_init(data);
0627 if (rc)
0628 return rc;
0629
0630 indio_dev->info = &vcnl3020_info;
0631 indio_dev->channels = vcnl3020_channels;
0632 indio_dev->num_channels = ARRAY_SIZE(vcnl3020_channels);
0633 indio_dev->name = "vcnl3020";
0634 indio_dev->modes = INDIO_DIRECT_MODE;
0635
0636 if (client->irq) {
0637 rc = devm_request_threaded_irq(&client->dev, client->irq,
0638 NULL, vcnl3020_handle_irq_thread,
0639 IRQF_ONESHOT, indio_dev->name,
0640 indio_dev);
0641 if (rc) {
0642 dev_err(&client->dev,
0643 "Error (%d) irq request failed (%u)\n", rc,
0644 client->irq);
0645 return rc;
0646 }
0647 }
0648
0649 return devm_iio_device_register(&client->dev, indio_dev);
0650 }
0651
0652 static const struct of_device_id vcnl3020_of_match[] = {
0653 {
0654 .compatible = "vishay,vcnl3020",
0655 },
0656 {}
0657 };
0658 MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
0659
0660 static struct i2c_driver vcnl3020_driver = {
0661 .driver = {
0662 .name = "vcnl3020",
0663 .of_match_table = vcnl3020_of_match,
0664 },
0665 .probe_new = vcnl3020_probe,
0666 };
0667 module_i2c_driver(vcnl3020_driver);
0668
0669 MODULE_AUTHOR("Ivan Mikhaylov <i.mikhaylov@yadro.com>");
0670 MODULE_DESCRIPTION("Vishay VCNL3020 proximity sensor driver");
0671 MODULE_LICENSE("GPL");