static int apds990x_configure(struct apds990x_chip *chip) { /* It is recommended to use disabled mode during these operations */ apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL); /* conversion and wait times for different state machince states */ apds990x_write_byte(chip, APDS990X_PTIME, APDS990X_PTIME_DEFAULT); apds990x_write_byte(chip, APDS990X_WTIME, APDS990X_WTIME_DEFAULT); apds990x_set_atime(chip, APDS_LUX_AVERAGING_TIME); apds990x_write_byte(chip, APDS990X_CONFIG, 0); /* Persistence levels */ apds990x_write_byte(chip, APDS990X_PERS, (chip->lux_persistence << APDS990X_APERS_SHIFT) | (chip->prox_persistence << APDS990X_PPERS_SHIFT)); apds990x_write_byte(chip, APDS990X_PPCOUNT, chip->pdata->ppcount); /* Start with relatively small gain */ chip->again_meas = 1; chip->again_next = 1; apds990x_write_byte(chip, APDS990X_CONTROL, (chip->pdrive << 6) | (chip->pdiode << 4) | (chip->pgain << 2) | (chip->again_next << 0)); return 0; }
static int apds990x_init_client(struct i2c_client *client) { struct apds990x_data *data = i2c_get_clientdata(client); int err; int id; data->enable_ps_sensor = 1; data->enable_als_sensor = 1; err = apds990x_set_enable(client, 0); if (err < 0) return err; id = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS990x_ID_REG); if (id == 0x20) { APDS_DEBUG_LOG("APDS-9901\n"); } else if (id == 0x29) { APDS_DEBUG_LOG("APDS-990x\n"); } else { APDS_DEBUG_LOG("Neither APDS-9901 nor APDS-9901\n"); return -EIO; } apds990x_set_atime(client, 0xC0); apds990x_set_ptime(client, 0xFF); apds990x_set_wtime(client, 0xE8); apds990x_set_ppcount(client, 0x04); apds990x_set_config(client, 0); apds990x_set_control(client, 0x20); apds990x_set_pilt(client, 0); apds990x_set_piht(client, guc_nv_proximity_sensor_near[0]); data->ps_threshold = guc_nv_proximity_sensor_near[0]; data->ps_hysteresis_threshold = guc_nv_proximity_sensor_far[0]; apds990x_set_ailt(client, 0); apds990x_set_aiht(client, 0xFFFF); apds990x_set_pers(client, 0x22); data->enable_ps_sensor = 0; data->enable_als_sensor = 0; err = apds990x_set_enable(client, 0); return 0; }
static int apds990x_init_client(struct i2c_client *client) { struct apds990x_data *data = i2c_get_clientdata(client); int err; int id; err = apds990x_set_enable(client, 0); if (err < 0) return err; id = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS990x_ID_REG); if (id == 0x20) { printk("APDS-9901\n"); } else if (id == 0x29) { printk("APDS-990x\n"); } else { printk("Neither APDS-9901 nor APDS-9901\n"); return -EIO; } apds990x_set_atime(client, 0xDB); // 100.64ms ALS integration time apds990x_set_ptime(client, 0xFF); // 2.72ms Prox integration time apds990x_set_wtime(client, 0xFF); // 2.72ms Wait time apds990x_set_ppcount(client, 0x08); // 8-Pulse for proximity apds990x_set_config(client, 0); // no long wait apds990x_set_control(client, 0x60); // 100mA, IR-diode, 1X PGAIN, 1X AGAIN apds990x_set_pilt(client, 0); // init threshold for proximity apds990x_set_piht(client, APDS990x_PS_DETECTION_THRESHOLD); data->ps_threshold = APDS990x_PS_DETECTION_THRESHOLD; data->ps_hysteresis_threshold = APDS990x_PS_HSYTERESIS_THRESHOLD; apds990x_set_ailt(client, 0); // init threshold for als apds990x_set_aiht(client, 0xFFFF); apds990x_set_pers(client, 0x22); // 2 consecutive Interrupt persistence // sensor is in disabled mode but all the configurations are preset return 0; }
static ssize_t apds990x_store_als_poll_delay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct apds990x_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); // int ret; // int poll_delay=0; // unsigned long flags; if (val<5000) val = 5000; // minimum 5ms data->als_poll_delay = val/1000; // convert us => ms #if 0 poll_delay = 256 - (val/2720); // the minimum is 2.72ms = 2720 us, maximum is 696.32ms if (poll_delay >= 256) data->als_atime = 255; else if (poll_delay < 0) data->als_atime = 0; else data->als_atime = poll_delay; ret = apds990x_set_atime(client, data->als_atime); if (ret < 0) return ret; /* we need this polling timer routine for sunlight canellation */ spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); // 100ms spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); #endif return count; }
static ssize_t apds990x_store_enable_als_sensor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct apds990x_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long flags; printk("%s: enable als sensor ( %ld)\n", __func__, val); if ((val != 0) && (val != 1)) { printk("%s: enable als sensor=%ld\n", __func__, val); return count; } if(val == 1) { //turn on light sensor if (data->enable_als_sensor==0) { data->enable_als_sensor = 1; apds990x_set_enable(client,0); /* Power Off */ apds990x_set_atime(client, data->als_atime); /* 100.64ms */ apds990x_set_ailt( client, 0); apds990x_set_aiht( client, 0xffff); apds990x_set_control(client, data->control); /* 100mA, IR-diode, 1X PGAIN, 1X AGAIN */ apds990x_set_pers(client, 0x33); /* 3 persistence */ if (data->enable_ps_sensor) { apds990x_set_ptime(client, 0xff); /* 2.72ms */ apds990x_set_ppcount(client, 8); /* 8-pulse */ apds990x_set_enable(client, 0x27); /* if prox sensor was activated previously */ } else { apds990x_set_enable(client, 0x3); /* only enable light sensor */ } spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } } else { //turn off light sensor // what if the p sensor is active? data->enable_als_sensor = 0; if (data->enable_ps_sensor) { apds990x_set_enable(client,0); /* Power Off */ apds990x_set_atime(client, 0xf6); /* 27.2ms */ apds990x_set_ptime(client, 0xff); /* 2.72ms */ apds990x_set_ppcount(client, 8); /* 8-pulse */ apds990x_set_control(client, data->control); /* 100mA, IR-diode, 1X PGAIN, 1X AGAIN */ //apds990x_set_piht(client, 0); //apds990x_set_piht(client, APDS990x_PS_DETECTION_THRESHOLD); apds990x_set_ailt( client, 0); apds990x_set_aiht( client, 0xffff); apds990x_set_pers(client, 0x33); /* 3 persistence */ apds990x_set_enable(client, 0x27); /* only enable prox sensor with interrupt */ } else { apds990x_set_enable(client, 0); } spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } return count; }
static ssize_t apds990x_store_enable_ps_sensor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct apds990x_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long flags; printk("%s: enable ps senosr ( %ld)\n", __func__, val); if ((val != 0) && (val != 1)) { printk("%s:store unvalid value=%ld\n", __func__, val); return count; } if(val == 1) { //turn on p sensor if (data->enable_ps_sensor==0) { data->enable_ps_sensor= 1; apds990x_set_enable(client,0); /* Power Off */ apds990x_set_atime(client, 0xf6); /* 27.2ms */ apds990x_set_ptime(client, 0xff); /* 2.72ms */ apds990x_set_ppcount(client, 8); /* 8-pulse */ apds990x_set_control(client, data->control); /* 100mA, IR-diode, 1X PGAIN, 1X AGAIN */ apds990x_set_pilt(client, 0); // init threshold for proximity apds990x_set_piht(client, APDS990x_PS_DETECTION_THRESHOLD); data->ps_threshold = APDS990x_PS_DETECTION_THRESHOLD; data->ps_hysteresis_threshold = APDS990x_PS_HSYTERESIS_THRESHOLD; apds990x_set_ailt( client, 0); apds990x_set_aiht( client, 0xffff); apds990x_set_pers(client, 0x33); /* 3 persistence */ if (data->enable_als_sensor==0) { /* we need this polling timer routine for sunlight canellation */ spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); // 100ms spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } apds990x_set_enable(client, 0x27); /* only enable PS interrupt */ } } else { //turn off p sensor - kk 25 Apr 2011 we can't turn off the entire sensor, the light sensor may be needed by HAL data->enable_ps_sensor = 0; if (data->enable_als_sensor) { // reconfigute light sensor setting apds990x_set_enable(client,0); /* Power Off */ apds990x_set_atime(client, data->als_atime); /* previous als poll delay */ apds990x_set_ailt( client, 0); apds990x_set_aiht( client, 0xffff); apds990x_set_control(client, data->control); /* 100mA, IR-diode, 1X PGAIN, 1X AGAIN */ apds990x_set_pers(client, 0x33); /* 3 persistence */ apds990x_set_enable(client, 0x3); /* only enable light sensor */ spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); // 100ms spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } else { apds990x_set_enable(client, 0); spin_lock_irqsave(&data->update_lock.wait_lock, flags); /* * If work is already scheduled then subsequent schedules will not * change the scheduled time that's why we have to cancel it first. */ __cancel_delayed_work(&data->als_dwork); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } } return count; }
static ssize_t apds990x_store_enable_als_sensor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct apds990x_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long flags; APDS_DEBUG_LOG("%s: enable als sensor ( %ld)\n", __func__, val); if ((val != 0) && (val != 1)) { APDS_DEBUG_LOG("%s: enable als sensor=%ld\n", __func__, val); return count; } if(val == 1) { if (data->enable_als_sensor<=0) { data->enable_als_sensor = 1; if (data->enable_ps_sensor<=0) { apds990x_set_enable(client,0); apds990x_set_atime(client, 0xC0); apds990x_set_ptime(client, 0xff); apds990x_set_wtime(client, 0xE8); apds990x_set_ppcount(client, 0x04); apds990x_set_control(client, 0x20); apds990x_set_pers(client, 0x22); apds990x_set_config(client, 0x00); apds990x_set_enable(client, 0x0B); } spin_lock_irqsave(&data->update_lock.wait_lock, flags); __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } else { data->enable_als_sensor++; } } else { data->enable_als_sensor--; if( data->enable_als_sensor > 0) { ; } else { if (data->enable_ps_sensor<=0) { apds990x_set_enable(client, 0); } spin_lock_irqsave(&data->update_lock.wait_lock, flags); __cancel_delayed_work(&data->als_dwork); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); data->als_polling_cnt_reset |= ALS_POLLING_CNT_RESET_DISABLE; } } return count; }
static ssize_t apds990x_store_enable_ps_sensor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct apds990x_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long flags; APDS_DEBUG_LOG("%s: enable ps senosr ( %ld)\n", __func__, val); if ((val != 0) && (val != 1)) { APDS_DEBUG_LOG("%s:store unvalid value=%ld\n", __func__, val); return count; } if(val == 1) { if (data->enable_ps_sensor<=0) { data->enable_ps_sensor=1; if (data->enable_als_sensor<=0) { apds990x_set_enable(client,0); apds990x_set_atime(client, 0xC0); apds990x_set_ptime(client, 0xff); apds990x_set_ppcount(client, 0x04); apds990x_set_pers(client, 0x22); apds990x_set_config(client, 0x00); } apds990x_set_wtime(client, 0xE5); apds990x_set_ailt(client, guc_nv_photo_sensor_dark[0]); apds990x_set_aiht(client, 0xffff); apds990x_set_pilt(client, 0); apds990x_set_piht(client, guc_nv_proximity_sensor_near[0]); if( data->als_gain == APDS990X_ALS_GAIN_1X ) { apds990x_set_control(client, 0x20); } else { apds990x_set_control(client, 0x20); msleep(250); } data->ps_threshold = guc_nv_proximity_sensor_near[0]; data->ps_hysteresis_threshold = guc_nv_proximity_sensor_far[0]; data->ps_detection = 0; apds990x_set_enable(client, 0x2F); apds990x_enable_ps_irq(data); } else { data->enable_ps_sensor++; } } else { data->enable_ps_sensor--; if (data->enable_ps_sensor>0) { ; } else if(data->enable_als_sensor) { apds990x_disable_ps_irq(data); apds990x_set_enable(client, 0x0A); i2c_smbus_write_byte(client, CMD_SPECIAL|0x07); apds990x_set_wtime(client, 0xE8); apds990x_set_enable(client, 0xB); if( data->ps_detection != 0 ) { data->ps_detection = 0; input_report_abs(data->input_dev_ps, ABS_DISTANCE, 0); input_sync(data->input_dev_ps); } spin_lock_irqsave(&data->update_lock.wait_lock, flags); __cancel_delayed_work(&data->als_dwork); schedule_delayed_work(&data->als_dwork, msecs_to_jiffies(data->als_poll_delay)); spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); } else { apds990x_disable_ps_irq(data); i2c_smbus_write_byte_data(client, CMD_BYTE|APDS990x_ENABLE_REG, 0x08); i2c_smbus_write_byte(client, CMD_SPECIAL|0x07); apds990x_set_wtime(client, 0xE8); apds990x_set_enable(client, 0); if( data->ps_detection != 0 ) { data->ps_detection = 0; input_report_abs(data->input_dev_ps, ABS_DISTANCE, 0); input_sync(data->input_dev_ps); } } } return count; }