static int __devinit apds990x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct apds990x_data *data; int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { err = -EIO; goto exit; } data = kzalloc(sizeof(struct apds990x_data), GFP_KERNEL); if (!data) { err = -ENOMEM; goto exit; } data->client = client; i2c_set_clientdata(client, data); data->enable = 0; /* default mode is standard */ data->ps_threshold = 0; data->ps_hysteresis_threshold = 0; data->ps_detection = 0; /* default to no detection */ data->enable_als_sensor = 0; // default to 0 data->enable_ps_sensor = 0; // default to 0 data->als_poll_delay = 100; // default to 100ms data->als_atime = 0xdb; // work in conjuction with als_poll_delay printk("enable = %x\n", data->enable); mutex_init(&data->update_lock); /* Initialize the APDS990x chip */ err = apds990x_init_client(client); if (err) goto exit_kfree; /* Register to Input Device */ data->input_dev_als = input_allocate_device(); if (!data->input_dev_als) { err = -ENOMEM; printk("Failed to allocate input device als\n"); goto exit_kfree; } data->input_dev_als->name = "Avago light sensor"; set_bit(EV_ABS, data->input_dev_als->evbit); set_bit(EV_SYN, data->input_dev_als->evbit); set_bit(ABS_MISC, data->input_dev_als->absbit); input_set_abs_params(data->input_dev_als, ABS_MISC, 0, 10000, 0, 0); err = input_register_device(data->input_dev_als); if (err) { err = -ENOMEM; printk("Unable to register input device als: %s\n", data->input_dev_als->name); goto exit_free_dev_als; } data->input_dev_ps = input_allocate_device(); if (!data->input_dev_ps) { err = -ENOMEM; printk("Failed to allocate input device ps\n"); goto exit_unregister_dev_als; } data->input_dev_ps->name = "Avago proximity sensor"; set_bit(EV_ABS, data->input_dev_ps->evbit); set_bit(EV_SYN, data->input_dev_ps->evbit); set_bit(ABS_DISTANCE, data->input_dev_ps->absbit); input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); err = input_register_device(data->input_dev_ps); if (err) { err = -ENOMEM; printk("Unable to register input device ps: %s\n", data->input_dev_ps->name); goto exit_free_dev_ps; } INIT_DELAYED_WORK(&data->dwork, apds990x_work_handler); INIT_DELAYED_WORK(&data->als_dwork, apds990x_als_polling_work_handler); // set gpio GPH1_3 function and request irq err = gpio_request(EXYNOS4_GPX0(1), "apds990x irq"); if (err) { printk("APDS990x fail to request irq gpio, return :%d\n", err); goto exit_unregister_dev_ps; } s3c_gpio_cfgpin(EXYNOS4_GPX0(1), S3C_GPIO_SFN(0x0F)); s3c_gpio_setpull(EXYNOS4_GPX0(1), S3C_GPIO_PULL_UP); wake_lock_init(&apds990x_wake_lock, WAKE_LOCK_SUSPEND, "apds990x_wake_lock"); if (request_irq(client->irq, apds990x_interrupt, IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING, APDS990x_DRV_NAME, (void *)client)) { printk("%s Could not allocate APDS990x_INT !\n", __func__); goto exit_unregister_dev_ps; } enable_irq_wake(client->irq); printk("%s interrupt is hooked\n", __func__); /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &apds990x_attr_group); if (err) goto exit_free_irq; printk("%s support ver. %s enabled\n", __func__, DRIVER_VERSION); printk("%s: low_threshold = %d, high_threshold = %d\n", \ __func__, APDS990x_PS_HSYTERESIS_THRESHOLD, APDS990x_PS_DETECTION_THRESHOLD); return 0; exit_free_irq: free_irq(client->irq, client); exit_unregister_dev_ps: input_unregister_device(data->input_dev_ps); exit_free_dev_ps: input_free_device(data->input_dev_ps); exit_unregister_dev_als: input_unregister_device(data->input_dev_als); exit_free_dev_als: input_free_device(data->input_dev_als); exit_kfree: kfree(data); exit: return err; }
static int __devinit apds990x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct apds990x_data *data; int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { err = -EIO; goto exit; } data = kzalloc(sizeof(struct apds990x_data), GFP_KERNEL); if (!data) { err = -ENOMEM; goto exit; } data->client = client; i2c_set_clientdata(client, data); data->enable = 0; data->ps_threshold = 0; data->ps_hysteresis_threshold = 0; data->ps_detection = 0; data->enable_als_sensor = 0; data->enable_ps_sensor = 0; data->als_poll_delay = 250; data->als_atime = 0xC0; memset( data->luxValue_table, 0, sizeof(data->luxValue_table) ); data->als_lux_ave = 0; data->als_polling_cnt = 0; data->als_mean_times = 4; data->als_polling_cnt_reset |= ALS_POLLING_CNT_RESET_INIT; APDS_DEBUG_LOG("enable = %x\n", data->enable); mutex_init(&data->update_lock); wake_lock_init( &apds_wake_lock, WAKE_LOCK_SUSPEND, "apds990x_ps" ); err = gpio_request(APDS_PROXIMITY_SENSOR_GPIO, APDS990x_DRV_NAME); if (err < 0) { APDS_DEBUG_LOG("[%s] failed to request GPIO=%d, ret=%d\n", __FUNCTION__, APDS_PROXIMITY_SENSOR_GPIO, err); goto exit_kfree; } err = gpio_direction_input(APDS_PROXIMITY_SENSOR_GPIO); if (err < 0) { APDS_DEBUG_LOG("[%s] failed to configure direction for GPIO=%d, ret=%d\n", __FUNCTION__, APDS_PROXIMITY_SENSOR_GPIO, err); goto exit_kfree; } data->ps_irq = gpio_to_irq(APDS_PROXIMITY_SENSOR_GPIO); err = request_any_context_irq(data->ps_irq, apds990x_interrupt, IRQ_TYPE_EDGE_FALLING, APDS990x_DRV_NAME, (void *)client); if(err < 0) { APDS_DEBUG_LOG("%s Could not allocate APDS990x_INT(%d) ! err=%d\n", __func__,APDS_PROXIMITY_SENSOR_GPIO,err); goto exit_kfree; } apds990x_ps_irq_cnt++; apds990x_disable_ps_irq(data); INIT_DELAYED_WORK(&data->dwork, apds990x_work_handler); INIT_DELAYED_WORK(&data->als_dwork, apds990x_als_polling_work_handler); APDS_DEBUG_LOG("%s interrupt is hooked\n", __func__); err = apds990x_init_client(client); if (err) goto exit_kfree; data->input_dev_als = input_allocate_device(); if (!data->input_dev_als) { err = -ENOMEM; APDS_DEBUG_LOG("Failed to allocate input device als\n"); goto exit_free_irq; } data->input_dev_ps = input_allocate_device(); if (!data->input_dev_ps) { err = -ENOMEM; APDS_DEBUG_LOG("Failed to allocate input device ps\n"); goto exit_free_dev_als; } set_bit(EV_ABS, data->input_dev_als->evbit); set_bit(EV_ABS, data->input_dev_ps->evbit); input_set_abs_params(data->input_dev_als, ABS_MISC, 0, APDS990X_LUXVALUE_MAX, 0, 0); input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0); data->input_dev_als->name = "Avago light sensor"; data->input_dev_ps->name = "Avago proximity sensor"; err = input_register_device(data->input_dev_als); if (err) { err = -ENOMEM; APDS_DEBUG_LOG("Unable to register input device als: %s\n", data->input_dev_als->name); goto exit_free_dev_ps; } err = input_register_device(data->input_dev_ps); if (err) { err = -ENOMEM; APDS_DEBUG_LOG("Unable to register input device ps: %s\n", data->input_dev_ps->name); goto exit_unregister_dev_als; } err = sysfs_create_group(&client->dev.kobj, &apds990x_attr_group); if (err) goto exit_unregister_dev_ps; device_init_wakeup(&client->dev, 1); atomic_set(&g_dev_status, APDS990X_DEV_STATUS_INIT); err = misc_register(&apds990x_device); if (err) { APDS_DEBUG_LOG(KERN_ERR "apds990x_probe: apds990x register failed\n"); goto exit_sysfs_remove; } APDS_DEBUG_LOG("%s support ver. %s enabled\n", __func__, DRIVER_VERSION); return 0; exit_sysfs_remove: sysfs_remove_group(&client->dev.kobj, &apds990x_attr_group); exit_unregister_dev_ps: input_unregister_device(data->input_dev_ps); exit_unregister_dev_als: input_unregister_device(data->input_dev_als); exit_free_dev_ps: input_free_device(data->input_dev_ps); exit_free_dev_als: input_free_device(data->input_dev_als); exit_free_irq: free_irq(data->ps_irq, client); exit_kfree: kfree(data); exit: return err; }