/* PS interrupt routine */ static void apds9130_work_handler(struct work_struct *work) { struct apds9130_data *data = container_of(work, struct apds9130_data, dwork.work); struct i2c_client *client=data->client; int status; int enable; if(wake_lock_active(&data->ps_wlock)) wake_unlock(&data->ps_wlock); wake_lock_timeout(&data->ps_wlock, 2 * HZ); status = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS9130_STATUS_REG); enable = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG); i2c_smbus_write_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG, 1); /* disable 9130 first */ printk(KERN_INFO"status = %x\n", status); if ((status & enable & 0x30) == 0x30) { /* both PS and ALS are interrupted - never happened*/ if ( (status&0x40) != 0x40 ) // no PSAT bit set apds9130_change_ps_threshold(client); else { if (data->ps_detection == 1) { apds9130_change_ps_threshold(client); } else { printk(KERN_INFO"Triggered by background ambient noise\n"); } } apds9130_set_command(client, 2); /* 2 = CMD_CLR_PS_ALS_INT */ } else if ((status & enable & 0x20) == 0x20) { /* only PS is interrupted */ if ( (status&0x40) != 0x40 ) // no PSAT bit set apds9130_change_ps_threshold(client); // far-to-near else { if (data->ps_detection == 1) { apds9130_change_ps_threshold(client); // near-to-far } else { printk(KERN_INFO"Triggered by background ambient noise\n"); } } apds9130_set_command(client, 0); /* 0 = CMD_CLR_PS_INT */ } else if ((status & enable & 0x10) == 0x10) { /* only ALS is interrupted - will never happened*/ apds9130_set_command(client, 1); /* 1 = CMD_CLR_ALS_INT */ } i2c_smbus_write_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG, data->enable); }
#ifdef CONFIG_PM static int apds9130_suspend(struct i2c_client *client, pm_message_t mesg) { #if 1 #else struct apds9130_data *data = i2c_get_clientdata(client); if(data->sw_mode == PROX_STAT_SHUTDOWN) return 0; apds9130_set_enable(client, 0); apds9130_set_command(client, 2); __cancel_delayed_work(&data->dwork); flush_delayed_work(&data->dwork); flush_workqueue(apds9130_workqueue); data->sw_mode = PROX_STAT_SHUTDOWN; disable_irq(client->irq); /* err = pdata->power(0); if(err < 0) { printk(KERN_INFO "%s, Proximity Power Off Fail in susped\n",__func__); return err; } */ irq_set_irq_wake(client->irq, 0); if(NULL != apds9130_workqueue){ destroy_workqueue(apds9130_workqueue); printk(KERN_INFO "%s, Destroy workqueue\n",__func__); apds9130_workqueue = NULL; } #endif
} static int apds9130_resume(struct i2c_client *client) { #if 1 #else struct apds9130_data *data = i2c_get_clientdata(client); int ret; int err = 0; if(apds9130_workqueue == NULL) { apds9130_workqueue = create_workqueue("proximity"); if(NULL == apds9130_workqueue) return -ENOMEM; } printk(KERN_INFO"apds9190_resume \n"); if(data->sw_mode == PROX_STAT_OPERATING) return 0; enable_irq(client->irq); mdelay(50); err = apds9130_set_enable(client, 0x2D); if(err < 0){ printk(KERN_INFO "%s, enable set Fail\n",__func__); return -1; } data->sw_mode = PROX_STAT_OPERATING; ret = irq_set_irq_wake(client->irq, 1); if(ret) irq_set_irq_wake(client->irq, 0); apds9130_set_command(client, 0); #endif
/* PS polling routine */ static void apds9130_ps_polling_work_handler(struct work_struct *work) { struct apds9130_data *data = container_of(work, struct apds9130_data, ps_dwork.work); struct i2c_client *client=data->client; int status; status = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS9130_STATUS_REG); data->ps_data = i2c_smbus_read_word_data(client, CMD_WORD|APDS9130_PDATAL_REG); // check PS under bright light if ( (data->ps_data > data->ps_threshold) && (data->ps_detection == 0) && ((status&0x40)==0x00) ) { /* far-to-near detected */ data->ps_detection = 1; input_report_abs(data->input_dev_ps, ABS_DISTANCE, 0);/* FAR-to-NEAR detection */ input_sync(data->input_dev_ps); printk("[ProximitySensor] far-to-NEAR\n"); } else if ( (data->ps_data < data->ps_hysteresis_threshold) && (data->ps_detection == 1) && ((status&0x40)==0x00) ) { // PS was previously in far-to-near condition /* near-to-far detected */ data->ps_detection = 0; input_report_abs(data->input_dev_ps, ABS_DISTANCE, 1);/* NEAR-to-FAR detection */ input_sync(data->input_dev_ps); printk("[ProximitySensor] near-to-FAR\n"); } else { printk("* Triggered by background ambient noise\n"); } if ( (status&0x40) == 0x40 ) { // need to clear psat bit if it is set apds9130_set_command(client, 0); /* 0 = CMD_CLR_PS_INT */ } schedule_delayed_work(&data->ps_dwork, msecs_to_jiffies(data->ps_poll_delay)); // restart timer }
/* PS interrupt routine */ static void apds9130_work_handler(struct work_struct *work) { struct apds9130_data *data = container_of(work, struct apds9130_data, dwork.work); struct i2c_client *client=data->client; int status; int enable; int err = 0; status = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS9130_STATUS_REG); enable = i2c_smbus_read_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG); err = i2c_smbus_write_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG, 1); if(err) { printk("[ProximitySensor_E] %s : i2c_write fail(%d) at (%d)\n", __func__, err, __LINE__); return; } printk("[ProximitySensor] %s : [status:0x%02x][enable:0x%02x]\n", __func__, status, enable); if ((status & enable & 0x30) == 0x30) { /* both PS and ALS are interrupted - never happened*/ if ( (status&0x40) != 0x40 ) // no PSAT bit set apds9130_change_ps_threshold(client); else { if (data->ps_detection == 1) { apds9130_change_ps_threshold(client); } else { printk("* Triggered by background ambient noise\n"); } } err = apds9130_set_command(client, 2); /* 2 = CMD_CLR_PS_ALS_INT */ } else if ((status & enable & 0x20) == 0x20) { /* only PS is interrupted */ if ( (status&0x40) != 0x40 ) // no PSAT bit set apds9130_change_ps_threshold(client); // far-to-near else { if (data->ps_detection == 1) { apds9130_change_ps_threshold(client); // near-to-far } else { printk("* Triggered by background ambient noise\n"); } } err = apds9130_set_command(client, 0); /* 0 = CMD_CLR_PS_INT */ } else if ((status & enable & 0x10) == 0x10) { /* only ALS is interrupted - will never happened*/ err = apds9130_set_command(client, 1); /* 1 = CMD_CLR_ALS_INT */ } if(err) { printk("[ProximitySensor_E] %s : i2c_write fail(%d) at (%d)\n", __func__, err, __LINE__); return; } err = i2c_smbus_write_byte_data(client, CMD_BYTE|APDS9130_ENABLE_REG, data->enable); if(err) { printk("[ProximitySensor_E] %s : i2c_write fail(%d) at (%d)\n", __func__, err, __LINE__); return; } }