Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}