void apds_9190_proximity_handler(struct apds9190_data *data) { int pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); if((pdata > data->pilt) && (pdata >= data->piht)){ apds9190_set_enable(apds_9190_i2c_client,0); data->isNear = 0; apds9190_set_piht(apds_9190_i2c_client, 1023); #ifdef APDS9190_TUNE apds9190_set_pilt(apds_9190_i2c_client, g_pilt); #else apds9190_set_pilt(apds_9190_i2c_client, apds_proxi_low_threshold); #endif printk(KERN_INFO "%s, piht : %d\n",__func__, data->piht); printk(KERN_INFO "%s, pilt : %d\n",__func__, data->pilt); printk(KERN_INFO "%s, reg pdata : %d \n",__func__, pdata); } else if((pdata < data->piht) && (pdata <= data->pilt)) { apds9190_set_enable(apds_9190_i2c_client,0); data->isNear = 1; apds9190_set_pilt(apds_9190_i2c_client, 0); #ifdef APDS9190_TUNE apds9190_set_piht(apds_9190_i2c_client, g_piht); #else apds9190_set_piht(apds_9190_i2c_client, apds_proxi_high_threshold); #endif printk(KERN_INFO "%s, piht : %d\n",__func__, data->piht); printk(KERN_INFO "%s, pilt : %d\n",__func__, data->pilt); printk(KERN_INFO "%s, reg pdata : %d \n",__func__, pdata); } if(data->isNear != data->last_isNear){ apds9190_event_report(data->isNear); data->last_isNear = data->isNear; } }
static ssize_t apds9190_store_interrupt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { // this value should be same with the value in sensors.cpp #define STORE_INTERUPT_SELECT_PROXIMITY 0x02 struct i2c_client *client = to_i2c_client(dev); struct apds9190_data *data = i2c_get_clientdata(client); unsigned long rdata = simple_strtoul(buf, NULL, 10); int enable = (int)rdata; int ret; DEBUG_MSG("apds9190_store_interrupt = [%d] apds_9190_initlizatied [%d] \n",rdata, apds_9190_initlizatied); if(!apds_9190_initlizatied){ apds_9190_initialize(); apds_9190_initlizatied = 1; } if(enable & STORE_INTERUPT_SELECT_PROXIMITY) { if(enable & 0x01) // enable { data->enable |= (APDS9190_ENABLE_PIEN|APDS9190_ENABLE_PEN|APDS9190_ENABLE_PON); } else //disable { data->enable &= ~(APDS9190_ENABLE_PIEN|APDS9190_ENABLE_PEN); } } if(data->enable == 1) { data->enable = 0; } ret = apds9190_set_enable(client, data->enable); enable_status = data->enable; DEBUG_MSG("apds9190_store_interrupt enable_status = [%x] data->enable [%x] \n",enable_status, data->enable); if (ret < 0) return ret; return count; }
static int apds9190_suspend(struct i2c_client *client, pm_message_t mesg) { struct apds9190_data *data = i2c_get_clientdata(apds_9190_i2c_client); struct proximity_platform_data* pdata = NULL; int enable; int err; printk("apds9190_suspend [%d], proximity_wq=%d\n", data->enable, proximity_wq); if(!data->sw_mode) return 0; pdata = data->client->dev.platform_data; if(NULL == pdata){ printk(KERN_INFO "Platform data is NULL\n"); return -1; } apds9190_set_enable(client, 0); apds9190_set_command(apds_9190_i2c_client, 2); cancel_work_sync(&data->dwork); flush_work(&data->dwork); flush_workqueue(proximity_wq); enable_status = enable; data->sw_mode = PROX_STAT_SHUTDOWN; disable_irq(data->irq); err = pdata->power(0); if(err < 0) { printk(KERN_INFO "%s, Proximity Power Off Fail in susped\n",__func__); return err; } set_irq_wake(data->irq, 0); if(NULL != proximity_wq){ destroy_workqueue(proximity_wq); printk(KERN_INFO "%s, Destroy workqueue\n",__func__); proximity_wq = NULL; } return 0; }
static int apds9190_init_client(struct i2c_client *client) { struct apds9190_data *data = i2c_get_clientdata(apds_9190_i2c_client); int err; apds9190_set_enable(apds_9190_i2c_client, 0); mutex_lock(&data->update_lock); err = i2c_smbus_read_byte_data(apds_9190_i2c_client, APDS9190_ENABLE_REG); mutex_unlock(&data->update_lock); if (err != 0) return -ENODEV; DEBUG_MSG("apds9190_init_client\n"); data->enable = 0; return 0; }
static int __devexit apds9190_remove(struct i2c_client *client) { struct apds9190_data *data = i2c_get_clientdata(client); DEBUG_MSG("apds9190_remove\n"); apds9190_set_enable(client, 0); set_irq_wake(data->irq, 0); free_irq(data->irq, NULL); input_unregister_device(data->input_dev); input_free_device(data->input_dev); kfree(data); /* Power down the device */ sysfs_remove_group(&client->dev.kobj, &apds9190_attr_group); return 0; }
static int apds9190_init(struct td_device *device) { int ret; struct sba_device *dev = (struct sba_device *)device; struct apds9190_info *ir_dev = (struct apds9190_info *)device->priv; pr_debug(LOG_MODULE_DRV, "APDS9190 %d init", device->id); /* Create a taken semaphore for sba transfers */ if ((ir_dev->i2c_sync_sem = semaphore_create(0)) == NULL) { return -1; } /* Init sba_request struct */ ir_dev->req.addr.slave_addr = dev->addr.slave_addr; ir_dev->req.request_type = SBA_TX; ir_dev->irq_req.addr.slave_addr = dev->addr.slave_addr; ir_dev->irq_req.request_type = SBA_TX; ir_dev->irq_req.tx_buff = ir_dev->irq_tx_buff; ir_dev->irq_req.rx_len = 0; ir_dev->irq_req.priv_data = dev; /* Stop device */ ret = apds9190_set_enable(device, ENABLE_PON); if (ret != 0) { pr_error(LOG_MODULE_DRV, "apds9190 %d probe %d\n", device->id, ret); return ret; } /* Default state is detached */ ir_dev->prox = false; /* Enable comparator interrupt if available */ if (ir_dev->comp_pin < 0) { /* No comparator configured, use polling mode */ apds9190_update_config(device); goto apds_polling_mode; } ir_dev->comparator_device = (struct td_device *)&pf_device_soc_comparator; pr_info(LOG_MODULE_DRV, "apds: use interrupt mode"); apds9190_update_config(device); apds9190_set_threshold(device, 0, ir_dev->piht); /* Enable apds9190 device in interrupt mode */ apds9190_set_enable(device, ENABLE_PON | ENABLE_PIEN | ENABLE_WEN | ENABLE_PEN); apds9190_clear_irq(device); comp_configure(ir_dev->comparator_device, ir_dev->comp_pin, 1, 1, comparator_cb, device); return 0; apds_polling_mode: pr_info(LOG_MODULE_DRV, "apds: use polling mode"); /* Disable interrupt mode on apds device */ apds9190_set_enable(device, ENABLE_PON | ENABLE_WEN | ENABLE_PEN); /* Create / start timer */ timer_create(apds_timer_cb, (void *)device, 1000, true, true, NULL); return 0; }
static int apds_9190_initialize(void) { struct apds9190_data *data = i2c_get_clientdata(apds_9190_i2c_client); u8 enable; int err = 0; data->pDrive = apds_pdrive; enable = APDS9190_ENABLE_PIEN | APDS9190_ENABLE_AIEN | APDS9190_ENABLE_WEN | APDS9190_ENABLE_PEN | APDS9190_ENABLE_AEN | APDS9190_ENABLE_PON; err = apds9190_set_enable(apds_9190_i2c_client,enable); if(err < 0){ printk(KERN_INFO "%s, enable set Fail\n",__func__); goto EXIT; } err = apds9190_set_wtime(apds_9190_i2c_client, WTIME); if(err < 0){ printk(KERN_INFO "%s, wtime set Faile\n",__func__); goto EXIT; } err = apds9190_set_ptime(apds_9190_i2c_client, PTIME); if(err < 0){ printk(KERN_INFO "%s, ptime set Fail\n",__func__); goto EXIT; } #ifdef STRONG_LIGHT err = apds9190_set_atime(apds_9190_i2c_client, ATIME); if(err < 0){ printk(KERN_INFO "%s, atime set Fail\n",__func__); goto EXIT; } #endif err = apds9190_set_pers(apds_9190_i2c_client, 0x22); //Interrupt persistence if(err < 0){ printk(KERN_INFO "%s, pers set Fail\n",__func__); goto EXIT; } err = apds9190_set_config(apds_9190_i2c_client, 0x00); // Wait long timer <- no needs so set 0 if(err < 0){ printk(KERN_INFO "%s, config set Fail\n",__func__); goto EXIT; } err = apds9190_set_ppcount(apds_9190_i2c_client, apds_ppcount); // Pulse count for proximity if(err < 0){ printk(KERN_INFO "%s, ppcount set Fail\n",__func__); goto EXIT; } err = apds9190_set_control(apds_9190_i2c_client, data->pDrive| PDIODE | PGAIN | AGAIN); if(err < 0){ printk(KERN_INFO "%s, control set Fail\n",__func__); goto EXIT; } err = apds9190_set_pilt(apds_9190_i2c_client, 0); // init threshold for proximity if(err < 0){ printk(KERN_INFO "%s, pilt set Fail\n",__func__); goto EXIT; } err = apds9190_set_piht(apds_9190_i2c_client, apds_proxi_high_threshold); if(err < 0){ printk(KERN_INFO "%s, piht set Fail\n",__func__); goto EXIT; } #ifdef STRONG_LIGHT err = apds9190_set_aiht(apds_9190_i2c_client, (75*(1024*(256-data->atime)))/100); if(err < 0){ printk(KERN_INFO "%s, aiht set Fail\n",__func__); goto EXIT; } err = apds9190_set_ailt(apds_9190_i2c_client, 0); if(err < 0){ printk(KERN_INFO "%s, ailt set Fail\n",__func__); goto EXIT; } #endif enable_status = enable; data->pilt = 0; data->piht = apds_proxi_high_threshold; #ifdef APDS9190_TUNE g_pilt = apds_proxi_low_threshold; g_piht = apds_proxi_high_threshold; #endif return 0; EXIT: return err; }
void apds_9190_irq_work_func(struct work_struct *work) { struct apds9190_data *data = container_of(work, struct apds9190_data, dwork); struct proximity_platform_data *pdev = NULL; #ifdef STRONG_LIGHT int status, pdata, cdata; #else int status, pdata; #endif int org_enable = data->enable; pdev = data->client->dev.platform_data; if(pdev->methods){ status = i2c_smbus_read_byte_data(apds_9190_i2c_client, CMD_BYTE|APDS9190_STATUS_REG); #ifdef STRONG_LIGHT if((status & APDS9190_STATUS_PINT_AINT) == 0x30) { disable_irq(data->irq); cdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_CDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] status : %d, cdata : %d, isNear : %d\n",__func__, status, cdata, data->isNear); if((data->isNear == 0) && (cdata >= (75*(1024*(256-data->atime)))/100) ) { pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] cdata : %d, pdata : %d\n", __func__, cdata, pdata); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] status change Near to Far while Near status but couldn't recognize Far\n", __func__); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] Force status to change Far\n",__func__); data->isNear = 1; data->last_isNear = 0; apds9190_set_pilt(apds_9190_i2c_client, 0); #ifdef APDS9190_TUNE apds9190_set_piht(apds_9190_i2c_client,g_piht); #else apds9190_set_piht(apds_9190_i2c_client,apds_proxi_high_threshold); #endif if(data->isNear != data->last_isNear) { apds9190_event_report(data->isNear); data->last_isNear = data->isNear; } } else if((data->isNear == 1) && (cdata >= (75*(1024*(256-data->atime)))/100) ) { pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] cdata : %d, pdata : %d\n", __func__, cdata, pdata); } else if(cdata < (75*(1024*(256-data->atime)))/100) { apds_9190_proximity_handler(data); } else // Far state { pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); printk(KERN_ERR "%s, [APDS9190_STATUS_PINT_AINT] Triggered by background ambient noise pdata : %d isNear : %d\n", __func__, pdata, data->isNear); } apds9190_set_command(apds_9190_i2c_client, 2); data->enable = org_enable; apds9190_set_control(apds_9190_i2c_client, (data->pDrive | PDIODE | PGAIN | AGAIN)); apds9190_set_enable(apds_9190_i2c_client,org_enable); enable_irq(data->irq); } else if((status & APDS9190_STATUS_PINT) == 0x20) { disable_irq(data->irq); cdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_CDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT] status : %d, cdata : %d, isNear : %d\n",__func__, status, cdata, data->isNear); if((data->isNear == 0) && (cdata >= (75*(1024*(256-data->atime)))/100) ) // Near state light 75% { pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT] cdata : %d, pdata : %d\n", __func__, cdata, pdata); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT] status change Near to Far while Near status but couldn't recognize Far\n", __func__); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT] Force status to change Far\n",__func__); data->isNear = 1; data->last_isNear = 0; apds9190_set_pilt(apds_9190_i2c_client, 0); #ifdef APDS9190_TUNE apds9190_set_piht(apds_9190_i2c_client,g_piht); #else apds9190_set_piht(apds_9190_i2c_client,apds_proxi_high_threshold); #endif if(data->isNear != data->last_isNear) { apds9190_event_report(data->isNear); data->last_isNear = data->isNear; } } else if((data->isNear == 1) && (cdata >= (75*(1024*(256-data->atime)))/100) ) { pdata = i2c_smbus_read_word_data(apds_9190_i2c_client, CMD_WORD|APDS9190_PDATAL_REG); printk(KERN_INFO "%s, [APDS9190_STATUS_PINT_AINT] cdata : %d, pdata : %d\n", __func__, cdata, pdata); } else if(cdata < (75 * (1024 * (256 - data->atime))) / 100) { apds_9190_proximity_handler(data); } else // Far state { printk(KERN_ERR "%s, [APDS9190_STATUS_PINT] Triggered by background ambient noise pdata : %d isNear : %d\n", __func__, pdata, data->isNear); } apds9190_set_command(apds_9190_i2c_client, 0); data->enable = org_enable; apds9190_set_control(apds_9190_i2c_client, (data->pDrive | PDIODE | PGAIN | AGAIN)); apds9190_set_enable(apds_9190_i2c_client,org_enable); enable_irq(data->irq); } else if((status & APDS9190_STATUS_AINT) == 0x10) { apds9190_set_command(apds_9190_i2c_client, 1); } #else if((status & APDS9190_STATUS_PINT) == 0x20){ disable_irq(data->irq); apds_9190_proximity_handler(data); apds9190_set_command(apds_9190_i2c_client, 0); data->enable = org_enable; apds9190_set_control(apds_9190_i2c_client, (data->pDrive | PDIODE | PGAIN | AGAIN)); apds9190_set_enable(apds_9190_i2c_client,org_enable); printk(KERN_INFO "%s, irq num : %d\n",__func__,data->irq); printk(KERN_INFO "%s, enable irq\n",__func__); enable_irq(data->irq); } #endif } else{ mutex_lock(&data->update_lock); pdata = i2c_smbus_read_word_data(data->client, CMD_WORD|APDS9190_PDATAL_REG); i2c_smbus_write_byte(data->client, CMD_CLR_PS_INT); mutex_unlock(&data->update_lock); if(pdata > PROX_HIGH_TH) // near intr data->isNear = 0; else data->isNear = 1; // far intr, pdata<= PROX_INT_LOW_TH if(data->isNear != data->last_isNear) apds9190_event_report(data->isNear); data->enable = org_enable; apds9190_set_control(apds_9190_i2c_client, (data->pDrive | PDIODE | PGAIN | AGAIN)); apds9190_set_enable(apds_9190_i2c_client,org_enable); } }