static int cm3663_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -ENODEV; struct input_dev *input_dev; struct cm3663_data *cm3663; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: i2c functionality check failed!\n", __func__); return ret; } cm3663 = kzalloc(sizeof(struct cm3663_data), GFP_KERNEL); if (!cm3663) { pr_err("%s: failed to alloc memory for module data\n", __func__); return -ENOMEM; } cm3663->pdata = client->dev.platform_data; cm3663->i2c_client = client; i2c_set_clientdata(client, cm3663); /* wake lock init */ wake_lock_init(&cm3663->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); mutex_init(&cm3663->power_lock); /* setup initial registers */ ret = cm3663_setup_reg(cm3663); if (ret < 0) { pr_err("%s: could not setup regs\n", __func__); goto err_setup_reg; } ret = cm3663_setup_irq(cm3663); if (ret) { pr_err("%s: could not setup irq\n", __func__); goto err_setup_irq; } /* allocate proximity input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); goto err_input_allocate_device_proximity; } cm3663->proximity_input_dev = input_dev; input_set_drvdata(input_dev, cm3663); input_dev->name = "proximity_sensor"; input_set_capability(input_dev, EV_ABS, ABS_DISTANCE); input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_proximity; } ret = sysfs_create_group(&input_dev->dev.kobj, &proximity_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_proximity; } /* light_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); cm3663->light_timer.function = cm3663_light_timer_func; /* prox_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC); cm3663->prox_timer.function = cm3663_prox_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm3663->light_wq = create_singlethread_workqueue("cm3663_light_wq"); if (!cm3663->light_wq) { ret = -ENOMEM; pr_err("%s: could not create light workqueue\n", __func__); goto err_create_light_workqueue; } cm3663->prox_wq = create_singlethread_workqueue("cm3663_prox_wq"); if (!cm3663->prox_wq) { ret = -ENOMEM; pr_err("%s: could not create prox workqueue\n", __func__); goto err_create_prox_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm3663->work_light, cm3663_work_func_light); INIT_WORK(&cm3663->work_prox, cm3663_work_func_prox); /* allocate lightsensor-level input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); ret = -ENOMEM; goto err_input_allocate_device_light; } input_set_drvdata(input_dev, cm3663); input_dev->name = "light_sensor"; input_set_capability(input_dev, EV_ABS, ABS_MISC); input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_light; } cm3663->light_input_dev = input_dev; ret = sysfs_create_group(&input_dev->dev.kobj, &light_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_light; } /* set sysfs for proximity sensor */ cm3663->proximity_class = class_create(THIS_MODULE, "proximity"); if (IS_ERR(cm3663->proximity_class)) { pr_err("%s: could not create proximity_class\n", __func__); goto err_proximity_class_create; } cm3663->proximity_dev = device_create(cm3663->proximity_class, NULL, 0, NULL, "proximity"); if (IS_ERR(cm3663->proximity_dev)) { pr_err("%s: could not create proximity_dev\n", __func__); goto err_proximity_device_create; } if (device_create_file(cm3663->proximity_dev, &dev_attr_proximity_state) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_proximity_state.attr.name); goto err_proximity_device_create_file1; } if (device_create_file(cm3663->proximity_dev, &dev_attr_proximity_avg) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_proximity_avg.attr.name); goto err_proximity_device_create_file2; } dev_set_drvdata(cm3663->proximity_dev, cm3663); /* set sysfs for light sensor */ cm3663->lightsensor_class = class_create(THIS_MODULE, "lightsensor"); if (IS_ERR(cm3663->lightsensor_class)) { pr_err("%s: could not create lightsensor_class\n", __func__); goto err_light_class_create; } cm3663->switch_cmd_dev = device_create(cm3663->lightsensor_class, NULL, 0, NULL, "switch_cmd"); if (IS_ERR(cm3663->switch_cmd_dev)) { pr_err("%s: could not create switch_cmd_dev\n", __func__); goto err_light_device_create; } if (device_create_file(cm3663->switch_cmd_dev, &dev_attr_lightsensor_file_state) < 0) { pr_err("%s: could not create device file(%s)!\n", __func__, dev_attr_lightsensor_file_state.attr.name); goto err_light_device_create_file; } dev_set_drvdata(cm3663->switch_cmd_dev, cm3663); #ifdef CONFIG_AOSP_ROM /* 07-28-2011 codeworkx: set initial proximity value as 1 */ input_report_abs(cm3663->proximity_input_dev, ABS_DISTANCE, 1); input_sync(cm3663->proximity_input_dev); #endif goto done; /* error, unwind it all */ err_light_device_create_file: device_destroy(cm3663->lightsensor_class, 0); err_light_device_create: class_destroy(cm3663->lightsensor_class); err_light_class_create: device_remove_file(cm3663->proximity_dev, &dev_attr_proximity_avg); err_proximity_device_create_file2: device_remove_file(cm3663->proximity_dev, &dev_attr_proximity_state); err_proximity_device_create_file1: device_destroy(cm3663->proximity_class, 0); err_proximity_device_create: class_destroy(cm3663->proximity_class); err_proximity_class_create: sysfs_remove_group(&input_dev->dev.kobj, &light_attribute_group); err_sysfs_create_group_light: input_unregister_device(cm3663->light_input_dev); err_input_register_device_light: err_input_allocate_device_light: destroy_workqueue(cm3663->prox_wq); err_create_prox_workqueue: destroy_workqueue(cm3663->light_wq); err_create_light_workqueue: sysfs_remove_group(&cm3663->proximity_input_dev->dev.kobj, &proximity_attribute_group); err_sysfs_create_group_proximity: input_unregister_device(cm3663->proximity_input_dev); err_input_register_device_proximity: err_input_allocate_device_proximity: free_irq(cm3663->irq, 0); err_setup_irq: err_setup_reg: mutex_destroy(&cm3663->power_lock); wake_lock_destroy(&cm3663->prx_wake_lock); kfree(cm3663); done: return ret; }
/* * probe function */ static int cm3663_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = -ENODEV; struct input_dev *input_dev; struct cm3663_data *cm3663; u8 tmp; int cnt = 3; int i = 0; int adc = sizeof(adc_step_table)/sizeof(int); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { pr_err("%s: i2c functionality check failed!\n", __func__); return ret; } cm3663 = kzalloc(sizeof(struct cm3663_data), GFP_KERNEL); if (!cm3663) { pr_err("%s: failed to alloc memory for module data\n", __func__); return -ENOMEM; } cm3663->pdata = client->dev.platform_data; cm3663->i2c_client = client; i2c_set_clientdata(client, cm3663); cm3663_gdata = cm3663; /* wake lock init */ wake_lock_init(&cm3663->prx_wake_lock, WAKE_LOCK_SUSPEND, "prx_wake_lock"); mutex_init(&cm3663->power_lock); ret = cm3663_setup_irq(cm3663); if (ret) { pr_err("%s: could not setup irq\n", __func__); goto err_setup_irq; } /* allocate proximity input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); goto err_input_allocate_device_proximity; } cm3663->proximity_input_dev = input_dev; input_set_drvdata(input_dev, cm3663); input_dev->name = "proximity_sensor"; input_set_capability(input_dev, EV_ABS, ABS_DISTANCE); input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_proximity; } ret = sysfs_create_group(&input_dev->dev.kobj, &proximity_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_proximity; } /* hrtimer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->light_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC); cm3663->light_timer.function = cm3663_light_timer_func; /* prox_timer settings. we poll for light values using a timer. */ hrtimer_init(&cm3663->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); cm3663->prox_poll_delay = ns_to_ktime(2000 * NSEC_PER_MSEC); cm3663->prox_timer.function = cm3663_prox_timer_func; /* the timer just fires off a work queue request. we need a thread to read the i2c (can be slow and blocking). */ cm3663->light_wq = create_singlethread_workqueue("cm3663_light_wq"); if (!cm3663->light_wq) { ret = -ENOMEM; pr_err("%s: could not create light workqueue\n", __func__); goto err_create_light_workqueue; } cm3663->prox_wq = create_singlethread_workqueue("cm3663_prox_wq"); if (!cm3663->prox_wq) { ret = -ENOMEM; pr_err("%s: could not create prox workqueue\n", __func__); goto err_create_prox_workqueue; } /* this is the thread function we run on the work queue */ INIT_WORK(&cm3663->work_light, cm3663_work_func_light); INIT_WORK(&cm3663->work_prox, cm3663_work_func_prox); /* allocate lightsensor-level input_device */ input_dev = input_allocate_device(); if (!input_dev) { pr_err("%s: could not allocate input device\n", __func__); ret = -ENOMEM; goto err_input_allocate_device_light; } input_set_drvdata(input_dev, cm3663); input_dev->name = "light_sensor"; input_set_capability(input_dev, EV_ABS, ABS_MISC); input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); ret = input_register_device(input_dev); if (ret < 0) { pr_err("%s: could not register input device\n", __func__); input_free_device(input_dev); goto err_input_register_device_light; } cm3663->light_input_dev = input_dev; ret = sysfs_create_group(&input_dev->dev.kobj, &light_attribute_group); if (ret) { pr_err("%s: could not create sysfs group\n", __func__); goto err_sysfs_create_group_light; } ret = sensors_register(cm3663->light_sensor_device, cm3663, additional_light_attrs, "light_sensor"); if (ret) { pr_err("%s: cound not register sensor device\n", __func__); goto err_sysfs_create_group_light; } ret = sensors_register(cm3663->proximity_sensor_device, cm3663, additional_proximity_attrs, "proximity_sensor"); if (ret) { pr_err("%s: cound not register sensor device\n", __func__); goto err_sysfs_create_group_light; } /* print inital proximity value with no contact */ mutex_lock(&cm3663->power_lock); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); cm3663_i2c_read(cm3663, REGS_ARA, &tmp); do { ret = cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]); cnt--; if ((!cnt) && (ret < 0)) goto err_i2c_failed; } while (ret < 0); ret = 0; cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]); cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]); msleep(100); cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp); pr_info("%s: initial proximity value = %d\n", __func__, tmp); cm3663_i2c_write(cm3663, REGS_PS_CMD, 0x01); mutex_unlock(&cm3663->power_lock); /* set initial proximity value as 1 */ input_report_abs(cm3663->proximity_input_dev, ABS_DISTANCE, 1); input_sync(cm3663->proximity_input_dev); pr_info("CM3663 probe ok!!!\n"); goto done; /* error, unwind it all */ err_i2c_failed: sysfs_remove_group(&cm3663->light_input_dev->dev.kobj, &light_attribute_group); err_sysfs_create_group_light: input_unregister_device(cm3663->light_input_dev); err_input_register_device_light: err_input_allocate_device_light: destroy_workqueue(cm3663->prox_wq); err_create_prox_workqueue: destroy_workqueue(cm3663->light_wq); err_create_light_workqueue: sysfs_remove_group(&cm3663->proximity_input_dev->dev.kobj, &proximity_attribute_group); err_sysfs_create_group_proximity: input_unregister_device(cm3663->proximity_input_dev); err_input_register_device_proximity: err_input_allocate_device_proximity: err_setup_irq: mutex_destroy(&cm3663->power_lock); wake_lock_destroy(&cm3663->prx_wake_lock); kfree(cm3663); pr_info("CM3663 probe fail!!!\n"); done: return ret; }