static int isl29018_chip_init(struct i2c_client *client) { struct isl29018_chip *chip = i2c_get_clientdata(client); bool status; int i; int new_adc_bit; unsigned int new_range; for (i = 0; i < ARRAY_SIZE(chip->reg_cache); i++) { chip->reg_cache[i] = 0; } /* set defaults */ isl29018_write_data(client, ISL29018_REG_TEST, 0x00, 0xFF, 0); isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0x00, 0xFF, 0); msleep(1); status = isl29018_set_range(client, chip->range, &new_range); if (status) status = isl29018_set_resolution(client, chip->adc_bit, &new_adc_bit); if (!status) { dev_err(&client->dev, "Init of isl29018 fails\n"); return -ENODEV; } return 0; }
static int isl29018_read_sensor_input(struct i2c_client *client, int mode) { int status; int lsb; int msb; /* Set mode */ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); if (status) { dev_err(&client->dev, "Error in setting operating mode\n"); return status; } msleep(CONVERSION_TIME_MS); lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); if (lsb < 0) { dev_err(&client->dev, "Error in reading LSB DATA\n"); return lsb; } msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); if (msb < 0) { dev_err(&client->dev, "Error in reading MSB DATA\n"); return msb; } dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); return (msb << 8) | lsb; }
static bool isl29018_set_range(struct i2c_client *client, unsigned long range, unsigned int *new_range) { unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; int i; for (i = 0; i < (ARRAY_SIZE(supp_ranges) -1); ++i) { if (range <= supp_ranges[i]) break; } *new_range = (unsigned int)supp_ranges[i]; return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); }
static bool isl29018_set_resolution(struct i2c_client *client, unsigned long adcbit, unsigned int *conf_adc_bit) { unsigned long supp_adcbit[] = {16, 12, 8, 4}; int i; for (i = 0; i < (ARRAY_SIZE(supp_adcbit)); ++i) { if (adcbit == supp_adcbit[i]) break; } *conf_adc_bit = (unsigned int)supp_adcbit[i]; return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, i, COMMANDII_RESOLUTION_MASK, COMMANDII_RESOLUTION_SHIFT); }
static bool isl29018_set_current (struct i2c_client *client, unsigned long curr, unsigned int *new_current) { unsigned long supp_currents[] = {12500, 25000, 50000, 100000}; int i; for (i = 0; i < (ARRAY_SIZE(supp_currents) -1); ++i) { if (curr <= supp_currents[i]) break; } *new_current = (unsigned int)supp_currents[i]; return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, i, COMMANDII_CURRSRC_MASK, COMMANDII_CURRSRC_SHIFT); }
static bool isl29018_read_lux(struct i2c_client *client, int *hb_lux, int *lb_lux) { int lux_data; bool status = 0; int lsb = 0; int msb = 0; struct isl29018_chip *chip = i2c_get_clientdata(client); if(!chip->enable_ls || chip->suspend) return true; /* Set mode */ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, COMMMAND1_OPMODE_ALS_ONCE, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); if (!status) { dev_err(&client->dev, "Error in setting operating mode\n"); return false; } msleep(CONVERSION_TIME_MS); if(!chip->enable_ls || chip->suspend) return true; lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); if (lsb < 0) { dev_err(&client->dev, "Error in reading LSB DATA\n"); return false; } msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); if (msb < 0) { dev_err(&client->dev, "Error in reading MSB DATA\n"); return false; } lux_data = ((msb << 8) | lsb); if (lux_data > 0) { *hb_lux = msb; *lb_lux = lsb; return true; } else { printk("isl29018_read_lux error / re-init chip... lux:%#x", lux_data); isl29018_chip_init(client); } return false; }
static int isl29018_set_range(struct i2c_client *client, unsigned long range, unsigned int *new_range) { static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; int i; for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) { if (range <= supp_ranges[i]) { *new_range = (unsigned int)supp_ranges[i]; break; } } if (i >= ARRAY_SIZE(supp_ranges)) return -EINVAL; return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); }
static int isl29018_set_resolution(struct i2c_client *client, unsigned long adcbit, unsigned int *conf_adc_bit) { static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; int i; for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) { if (adcbit >= supp_adcbit[i]) { *conf_adc_bit = (unsigned int)supp_adcbit[i]; break; } } if (i >= ARRAY_SIZE(supp_adcbit)) return -EINVAL; return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, i, COMMANDII_RESOLUTION_MASK, COMMANDII_RESOLUTION_SHIFT); }
static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, int *near_ir) { int status; int prox_data = -1; int ir_data = -1; /* Do proximity sensing with required scheme */ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); if (status) { dev_err(&client->dev, "Error in setting operating mode\n"); return status; } prox_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_PROX_ONCE); if (prox_data < 0) return prox_data; if (scheme == 1) { *near_ir = prox_data; return 0; } ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); if (ir_data < 0) return ir_data; if (prox_data >= ir_data) *near_ir = prox_data - ir_data; else *near_ir = 0; return 0; }
static int isl29018_read_sensor_input(struct i2c_client *client, int mode) { int status; int lux; /* Set mode */ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); if (status) { dev_err(&client->dev, "Error in setting operating mode\n"); return status; } integration_wait(iio_priv(i2c_get_clientdata(client))); status = i2c_smbus_read_word_data(client, ISL29018_REG_ADD_DATA_LSB); if (status < 0) { dev_err(&client->dev, "Error in reading Lux DATA\n"); return status; } lux = le16_to_cpu(status); dev_vdbg(&client->dev, "lux = %u\n", lux); return lux; }
static int isl29018_chip_init(struct i2c_client *client) { struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); int status; int new_adc_bit; unsigned int new_range; memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); /* Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD * recovers to 2.25V (or greater), the part may thus be in an * unknown mode of operation. The user can return the part to * a known mode of operation either by (a) setting VDD = 0V for * 1 second or more and then powering back up with a slew rate * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX * conversions, clear the test registers, and then rewrite all * registers to the desired values. * ... * FOR ISL29011, ISL29018, ISL29021, ISL29023 * 1. Write 0x00 to register 0x08 (TEST) * 2. Write 0x00 to register 0x00 (CMD1) * 3. Rewrite all registers to the desired values * * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says * the same thing EXCEPT the data sheet asks for a 1ms delay after * writing the CMD1 register. */ status = isl29018_write_data(client, ISL29018_REG_TEST, 0, ISL29018_TEST_MASK, ISL29018_TEST_SHIFT); if (status < 0) { dev_err(&client->dev, "Failed to clear isl29018 TEST reg." "(%d)\n", status); return status; } /* See Intersil AN1534 comments above. * "Operating Mode" (COMMAND1) register is reprogrammed when * data is read from the device. */ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0, 0xff, 0); if (status < 0) { dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg." "(%d)\n", status); return status; } msleep(1); /* per data sheet, page 10 */ /* set defaults */ status = isl29018_set_range(client, chip->range, &new_range); if (status < 0) { dev_err(&client->dev, "Init of isl29018 fails\n"); return status; } status = isl29018_set_resolution(client, chip->adc_bit, &new_adc_bit); return 0; }