vcnl4000.c revision 62a1efb9f868690d68b11ffb22dc598e547aa184
162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald/* 262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * vcnl4000.c - Support for Vishay VCNL4000 combined ambient light and 362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * proximity sensor 462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * 562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net> 662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * 762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * This file is subject to the terms and conditions of version 2 of 862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * the GNU General Public License. See the file COPYING in the main 962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * directory of this archive for more details. 1062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * 1162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * IIO driver for VCNL4000 (7-bit I2C slave address 0x13) 1262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * 1362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * TODO: 1462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * allow to adjust IR current 1562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald * proximity threshold and event handling 1662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald */ 1762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 1862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/module.h> 1962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/i2c.h> 2062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/err.h> 2162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/delay.h> 2262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 2362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/iio/iio.h> 2462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#include <linux/iio/sysfs.h> 2562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 2662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_DRV_NAME "vcnl4000" 2762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 2862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_COMMAND 0x80 /* Command register */ 2962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */ 3062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_LED_CURRENT 0x83 /* IR LED current for proximity mode */ 3162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_AL_PARAM 0x84 /* Ambient light parameter register */ 3262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_AL_RESULT_HI 0x85 /* Ambient light result register, MSB */ 3362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_AL_RESULT_LO 0x86 /* Ambient light result register, LSB */ 3462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_RESULT_HI 0x87 /* Proximity result register, MSB */ 3562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_RESULT_LO 0x88 /* Proximity result register, LSB */ 3662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */ 3762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */ 3862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 3962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald/* Bit masks for COMMAND register */ 4062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_AL_RDY 0x40 /* ALS data ready? */ 4162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_RDY 0x20 /* proximity data ready? */ 4262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_AL_OD 0x10 /* start on-demand ALS measurement */ 4362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald#define VCNL4000_PS_OD 0x08 /* start on-demand proximity measurement */ 4462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 4562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstruct vcnl4000_data { 4662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct i2c_client *client; 4762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald}; 4862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 4962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic const struct i2c_device_id vcnl4000_id[] = { 5062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald { "vcnl4000", 0 }, 5162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald { } 5262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald}; 5362a1efb9f868690d68b11ffb22dc598e547aa184Peter MeerwaldMODULE_DEVICE_TABLE(i2c, vcnl4000_id); 5462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 5562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, 5662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald u8 rdy_mask, u8 data_reg, int *val) 5762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald{ 5862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald int tries = 20; 5962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald u16 buf; 6062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald int ret; 6162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 6262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 6362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald req_mask); 6462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 6562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 6662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 6762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald /* wait for data to become ready */ 6862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald while (tries--) { 6962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND); 7062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 7162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 7262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret & rdy_mask) 7362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 7462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald msleep(20); /* measurement takes up to 100 ms */ 7562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 7662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 7762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (tries < 0) { 7862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald dev_err(&data->client->dev, 7962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald "vcnl4000_measure() failed, data not ready\n"); 8062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return -EIO; 8162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 8262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 8362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = i2c_smbus_read_i2c_block_data(data->client, 8462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald data_reg, sizeof(buf), (u8 *) &buf); 8562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 8662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 8762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 8862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald *val = be16_to_cpu(buf); 8962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 9062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return 0; 9162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald} 9262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 9362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic const struct iio_chan_spec vcnl4000_channels[] = { 9462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald { 9562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .type = IIO_LIGHT, 9662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | 9762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 9862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald }, { 9962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .type = IIO_PROXIMITY, 10062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, 10162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 10262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald}; 10362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 10462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic int vcnl4000_read_raw(struct iio_dev *indio_dev, 10562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct iio_chan_spec const *chan, 10662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald int *val, int *val2, long mask) 10762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald{ 10862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald int ret = -EINVAL; 10962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct vcnl4000_data *data = iio_priv(indio_dev); 11062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 11162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald switch (mask) { 11262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald case IIO_CHAN_INFO_RAW: 11362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald switch (chan->type) { 11462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald case IIO_LIGHT: 11562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = vcnl4000_measure(data, 11662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald VCNL4000_AL_OD, VCNL4000_AL_RDY, 11762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald VCNL4000_AL_RESULT_HI, val); 11862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 11962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 12062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = IIO_VAL_INT; 12162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 12262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald case IIO_PROXIMITY: 12362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = vcnl4000_measure(data, 12462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald VCNL4000_PS_OD, VCNL4000_PS_RDY, 12562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald VCNL4000_PS_RESULT_HI, val); 12662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 12762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 12862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = IIO_VAL_INT; 12962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 13062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald default: 13162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 13262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 13362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 13462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald case IIO_CHAN_INFO_SCALE: 13562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (chan->type == IIO_LIGHT) { 13662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald *val = 0; 13762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald *val2 = 250000; 13862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = IIO_VAL_INT_PLUS_MICRO; 13962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 14062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 14162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald default: 14262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald break; 14362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald } 14462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 14562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 14662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald} 14762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 14862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic const struct iio_info vcnl4000_info = { 14962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .read_raw = vcnl4000_read_raw, 15062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .driver_module = THIS_MODULE, 15162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald}; 15262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 15362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic int __devinit vcnl4000_probe(struct i2c_client *client, 15462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald const struct i2c_device_id *id) 15562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald{ 15662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct vcnl4000_data *data; 15762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct iio_dev *indio_dev; 15862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald int ret; 15962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 16062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev = iio_device_alloc(sizeof(*data)); 16162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (!indio_dev) 16262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return -ENOMEM; 16362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 16462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald data = iio_priv(indio_dev); 16562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald i2c_set_clientdata(client, indio_dev); 16662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald data->client = client; 16762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 16862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV); 16962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 17062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald goto error_free_dev; 17162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 17262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald dev_info(&client->dev, "VCNL4000 Ambient light/proximity sensor, Prod %02x, Rev: %02x\n", 17362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret >> 4, ret & 0xf); 17462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 17562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->dev.parent = &client->dev; 17662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->info = &vcnl4000_info; 17762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->channels = vcnl4000_channels; 17862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->num_channels = ARRAY_SIZE(vcnl4000_channels); 17962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->name = VCNL4000_DRV_NAME; 18062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 18162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 18262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald ret = iio_device_register(indio_dev); 18362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald if (ret < 0) 18462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald goto error_free_dev; 18562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 18662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return 0; 18762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 18862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwalderror_free_dev: 18962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald iio_device_free(indio_dev); 19062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return ret; 19162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald} 19262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 19362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic int __devexit vcnl4000_remove(struct i2c_client *client) 19462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald{ 19562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald struct iio_dev *indio_dev = i2c_get_clientdata(client); 19662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 19762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald iio_device_unregister(indio_dev); 19862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald iio_device_free(indio_dev); 19962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 20062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald return 0; 20162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald} 20262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 20362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldstatic struct i2c_driver vcnl4000_driver = { 20462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .driver = { 20562a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .name = VCNL4000_DRV_NAME, 20662a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .owner = THIS_MODULE, 20762a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald }, 20862a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .probe = vcnl4000_probe, 20962a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .remove = __devexit_p(vcnl4000_remove), 21062a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald .id_table = vcnl4000_id, 21162a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald}; 21262a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 21362a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwaldmodule_i2c_driver(vcnl4000_driver); 21462a1efb9f868690d68b11ffb22dc598e547aa184Peter Meerwald 21562a1efb9f868690d68b11ffb22dc598e547aa184Peter MeerwaldMODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 21662a1efb9f868690d68b11ffb22dc598e547aa184Peter MeerwaldMODULE_DESCRIPTION("Vishay VCNL4000 proximity/ambient light sensor driver"); 21762a1efb9f868690d68b11ffb22dc598e547aa184Peter MeerwaldMODULE_LICENSE("GPL"); 218