// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ #define pr_fmt(fmt) "[ALS/PS] " fmt #include "alspshub.h" #include #include #include #include "SCP_power_monitor.h" #include #define ALSPSHUB_DEV_NAME "alsps_hub_pl" struct alspshub_ipi_data { struct work_struct init_done_work; atomic_t first_ready_after_boot; /*misc */ atomic_t als_suspend; atomic_t ps_suspend; atomic_t trace; atomic_t scp_init_done; /*data */ u16 als; u8 ps; int ps_cali; atomic_t als_cali; atomic_t ps_thd_val_high; atomic_t ps_thd_val_low; ulong enable; ulong pending_intr; bool als_factory_enable; bool ps_factory_enable; bool als_android_enable; bool ps_android_enable; struct wakeup_source *ps_wake_lock; }; static struct alspshub_ipi_data *obj_ipi_data; static int ps_get_data(int *value, int *status); static int alspshub_local_init(void); static int alspshub_local_remove(void); static int alspshub_init_flag = -1; static struct alsps_init_info alspshub_init_info = { .name = "alsps_hub", .init = alspshub_local_init, .uninit = alspshub_local_remove, }; static DEFINE_MUTEX(alspshub_mutex); static DEFINE_SPINLOCK(calibration_lock); enum { CMC_BIT_ALS = 1, CMC_BIT_PS = 2, } CMC_BIT; enum { CMC_TRC_ALS_DATA = 0x0001, CMC_TRC_PS_DATA = 0x0002, CMC_TRC_EINT = 0x0004, CMC_TRC_IOCTL = 0x0008, CMC_TRC_I2C = 0x0010, CMC_TRC_CVT_ALS = 0x0020, CMC_TRC_CVT_PS = 0x0040, CMC_TRC_DEBUG = 0x8000, } CMC_TRC; long alspshub_read_ps(u8 *ps) { long res; struct alspshub_ipi_data *obj = obj_ipi_data; struct data_unit_t data_t; res = sensor_get_data_from_hub(ID_PROXIMITY, &data_t); if (res < 0) { *ps = -1; pr_err("sensor_get_data_from_hub fail, (ID: %d)\n", ID_PROXIMITY); return -1; } if (data_t.proximity_t.steps < obj->ps_cali) *ps = 0; else *ps = data_t.proximity_t.steps - obj->ps_cali; return 0; } long alspshub_read_als(u16 *als) { long res = 0; struct data_unit_t data_t; res = sensor_get_data_from_hub(ID_LIGHT, &data_t); if (res < 0) { *als = -1; pr_err_ratelimited("sensor_get_data_from_hub fail, (ID: %d)\n", ID_LIGHT); return -1; } *als = data_t.light; return 0; } static ssize_t trace_show(struct device_driver *ddri, char *buf) { ssize_t res = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (!obj_ipi_data) { pr_err("obj_ipi_data is null!!\n"); return 0; } res = snprintf(buf, PAGE_SIZE, "0x%04X\n", atomic_read(&obj->trace)); return res; } static ssize_t trace_store(struct device_driver *ddri, const char *buf, size_t count) { int trace = 0; struct alspshub_ipi_data *obj = obj_ipi_data; int res = 0; int ret = 0; if (!obj) { pr_err("obj_ipi_data is null!!\n"); return 0; } ret = sscanf(buf, "0x%x", &trace); if (ret != 1) { pr_err("invalid content: '%s', length = %zu\n", buf, count); return count; } atomic_set(&obj->trace, trace); res = sensor_set_cmd_to_hub(ID_PROXIMITY, CUST_ACTION_SET_TRACE, &trace); if (res < 0) { pr_err("sensor_set_cmd_to_hub fail,(ID: %d),(action: %d)\n", ID_PROXIMITY, CUST_ACTION_SET_TRACE); return 0; } return count; } static ssize_t als_show(struct device_driver *ddri, char *buf) { int res = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (!obj) { pr_err("obj_ipi_data is null!!\n"); return 0; } res = alspshub_read_als(&obj->als); if (res) return snprintf(buf, PAGE_SIZE, "ERROR: %d\n", res); else return snprintf(buf, PAGE_SIZE, "0x%04X\n", obj->als); } static ssize_t ps_show(struct device_driver *ddri, char *buf) { ssize_t res = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (!obj) { pr_err("cm3623_obj is null!!\n"); return 0; } res = alspshub_read_ps(&obj->ps); if (res) return snprintf(buf, PAGE_SIZE, "ERROR: %d\n", (int)res); else return snprintf(buf, PAGE_SIZE, "0x%04X\n", obj->ps); } static ssize_t reg_show(struct device_driver *ddri, char *buf) { int res = 0; res = sensor_set_cmd_to_hub(ID_PROXIMITY, CUST_ACTION_SHOW_REG, buf); if (res < 0) { pr_err("sensor_set_cmd_to_hub fail,(ID: %d),(action: %d)\n", ID_PROXIMITY, CUST_ACTION_SHOW_REG); return 0; } return res; } static ssize_t alslv_show(struct device_driver *ddri, char *buf) { int res = 0; res = sensor_set_cmd_to_hub(ID_LIGHT, CUST_ACTION_SHOW_ALSLV, buf); if (res < 0) { pr_err("sensor_set_cmd_to_hub fail,(ID: %d),(action: %d)\n", ID_LIGHT, CUST_ACTION_SHOW_ALSLV); return 0; } return res; } static ssize_t alsval_show(struct device_driver *ddri, char *buf) { int res = 0; res = sensor_set_cmd_to_hub(ID_LIGHT, CUST_ACTION_SHOW_ALSVAL, buf); if (res < 0) { pr_err("sensor_set_cmd_to_hub fail,(ID: %d),(action: %d)\n", ID_LIGHT, CUST_ACTION_SHOW_ALSVAL); return 0; } return res; } static DRIVER_ATTR_RO(als); static DRIVER_ATTR_RO(ps); static DRIVER_ATTR_RO(alslv); static DRIVER_ATTR_RO(alsval); static DRIVER_ATTR_RW(trace); static DRIVER_ATTR_RO(reg); static struct driver_attribute *alspshub_attr_list[] = { &driver_attr_als, &driver_attr_ps, &driver_attr_trace, /*trace log */ &driver_attr_alslv, &driver_attr_alsval, &driver_attr_reg, }; static int alspshub_create_attr(struct device_driver *driver) { int idx = 0, err = 0; int num = (int)(ARRAY_SIZE(alspshub_attr_list)); if (driver == NULL) return -EINVAL; for (idx = 0; idx < num; idx++) { err = driver_create_file(driver, alspshub_attr_list[idx]); if (err) { pr_err("driver_create_file (%s) = %d\n", alspshub_attr_list[idx]->attr.name, err); break; } } return err; } static int alspshub_delete_attr(struct device_driver *driver) { int idx = 0, err = 0; int num = (int)(ARRAY_SIZE(alspshub_attr_list)); if (!driver) return -EINVAL; for (idx = 0; idx < num; idx++) driver_remove_file(driver, alspshub_attr_list[idx]); return err; } static void alspshub_init_done_work(struct work_struct *work) { struct alspshub_ipi_data *obj = obj_ipi_data; int err = 0; #ifndef MTK_OLD_FACTORY_CALIBRATION int32_t cfg_data[2] = {0}; #endif if (atomic_read(&obj->scp_init_done) == 0) { pr_err("wait for nvram to set calibration\n"); return; } if (atomic_xchg(&obj->first_ready_after_boot, 1) == 0) return; #ifdef MTK_OLD_FACTORY_CALIBRATION err = sensor_set_cmd_to_hub(ID_PROXIMITY, CUST_ACTION_SET_CALI, &obj->ps_cali); if (err < 0) pr_err("sensor_set_cmd_to_hub fail,(ID: %d),(action: %d)\n", ID_PROXIMITY, CUST_ACTION_SET_CALI); #else spin_lock(&calibration_lock); cfg_data[0] = atomic_read(&obj->ps_thd_val_high); cfg_data[1] = atomic_read(&obj->ps_thd_val_low); spin_unlock(&calibration_lock); err = sensor_cfg_to_hub(ID_PROXIMITY, (uint8_t *)cfg_data, sizeof(cfg_data)); if (err < 0) pr_err("sensor_cfg_to_hub ps fail\n"); spin_lock(&calibration_lock); cfg_data[0] = atomic_read(&obj->als_cali); spin_unlock(&calibration_lock); err = sensor_cfg_to_hub(ID_LIGHT, (uint8_t *)cfg_data, sizeof(cfg_data)); if (err < 0) pr_err("sensor_cfg_to_hub als fail\n"); #endif } static int ps_recv_data(struct data_unit_t *event, void *reserved) { int err = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (!obj) return 0; if (event->flush_action == FLUSH_ACTION) err = ps_flush_report(); else if (event->flush_action == DATA_ACTION && READ_ONCE(obj->ps_android_enable) == true) { __pm_wakeup_event(obj->ps_wake_lock, msecs_to_jiffies(100)); err = ps_data_report_t(event->proximity_t.oneshot, SENSOR_STATUS_ACCURACY_HIGH, (int64_t)event->time_stamp); } else if (event->flush_action == CALI_ACTION) { spin_lock(&calibration_lock); atomic_set(&obj->ps_thd_val_high, event->data[0]); atomic_set(&obj->ps_thd_val_low, event->data[1]); spin_unlock(&calibration_lock); err = ps_cali_report(event->data); } return err; } static int als_recv_data(struct data_unit_t *event, void *reserved) { int err = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (!obj) return 0; if (event->flush_action == FLUSH_ACTION) err = als_flush_report(); else if ((event->flush_action == DATA_ACTION) && READ_ONCE(obj->als_android_enable) == true) err = als_data_report_t(event->light, SENSOR_STATUS_ACCURACY_MEDIUM, (int64_t)event->time_stamp); else if (event->flush_action == CALI_ACTION) { spin_lock(&calibration_lock); atomic_set(&obj->als_cali, event->data[0]); spin_unlock(&calibration_lock); err = als_cali_report(event->data); } return err; } static int rgbw_recv_data(struct data_unit_t *event, void *reserved) { int err = 0; if (event->flush_action == FLUSH_ACTION) err = rgbw_flush_report(); else if (event->flush_action == DATA_ACTION) err = rgbw_data_report_t(event->data, (int64_t)event->time_stamp); return err; } static int alshub_factory_enable_sensor(bool enable_disable, int64_t sample_periods_ms) { int err = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (enable_disable == true) WRITE_ONCE(obj->als_factory_enable, true); else WRITE_ONCE(obj->als_factory_enable, false); if (enable_disable == true) { err = sensor_set_delay_to_hub(ID_LIGHT, sample_periods_ms); if (err) { pr_err("sensor_set_delay_to_hub failed!\n"); return -1; } } err = sensor_enable_to_hub(ID_LIGHT, enable_disable); if (err) { pr_err("sensor_enable_to_hub failed!\n"); return -1; } mutex_lock(&alspshub_mutex); if (enable_disable) set_bit(CMC_BIT_ALS, &obj->enable); else clear_bit(CMC_BIT_ALS, &obj->enable); mutex_unlock(&alspshub_mutex); return 0; } static int alshub_factory_get_data(int32_t *data) { int err = 0; struct data_unit_t data_t; err = sensor_get_data_from_hub(ID_LIGHT, &data_t); if (err < 0) return -1; *data = data_t.light; return 0; } static int alshub_factory_get_raw_data(int32_t *data) { return alshub_factory_get_data(data); } static int alshub_factory_enable_calibration(void) { return sensor_calibration_to_hub(ID_LIGHT); } static int alshub_factory_clear_cali(void) { return 0; } static int alshub_factory_set_cali(int32_t offset) { struct alspshub_ipi_data *obj = obj_ipi_data; int err = 0; int32_t cfg_data; cfg_data = offset; err = sensor_cfg_to_hub(ID_LIGHT, (uint8_t *)&cfg_data, sizeof(cfg_data)); if (err < 0) pr_err("sensor_cfg_to_hub fail\n"); atomic_set(&obj->als_cali, offset); als_cali_report(&cfg_data); return err; } static int alshub_factory_get_cali(int32_t *offset) { struct alspshub_ipi_data *obj = obj_ipi_data; *offset = atomic_read(&obj->als_cali); return 0; } static int pshub_factory_enable_sensor(bool enable_disable, int64_t sample_periods_ms) { int err = 0; struct alspshub_ipi_data *obj = obj_ipi_data; if (enable_disable == true) { err = sensor_set_delay_to_hub(ID_PROXIMITY, sample_periods_ms); if (err) { pr_err("sensor_set_delay_to_hub failed!\n"); return -1; } } err = sensor_enable_to_hub(ID_PROXIMITY, enable_disable); if (err) { pr_err("sensor_enable_to_hub failed!\n"); return -1; } mutex_lock(&alspshub_mutex); if (enable_disable) set_bit(CMC_BIT_PS, &obj->enable); else clear_bit(CMC_BIT_PS, &obj->enable); mutex_unlock(&alspshub_mutex); return 0; } static int pshub_factory_get_data(int32_t *data) { int err = 0, status = 0; err = ps_get_data(data, &status); if (err < 0) return -1; return 0; } static int pshub_factory_get_raw_data(int32_t *data) { int err = 0; struct data_unit_t data_t; err = sensor_get_data_from_hub(ID_PROXIMITY, &data_t); if (err < 0) return -1; *data = data_t.proximity_t.steps; return 0; } static int pshub_factory_enable_calibration(void) { return sensor_calibration_to_hub(ID_PROXIMITY); } static int pshub_factory_clear_cali(void) { #ifdef MTK_OLD_FACTORY_CALIBRATION int err = 0; #endif struct alspshub_ipi_data *obj = obj_ipi_data; obj->ps_cali = 0; #ifdef MTK_OLD_FACTORY_CALIBRATION err = sensor_set_cmd_to_hub(ID_PROXIMITY, CUST_ACTION_RESET_CALI, &obj->ps_cali); if (err < 0) { pr_err("sensor_set_cmd_to_hub fail, (ID: %d),(action: %d)\n", ID_PROXIMITY, CUST_ACTION_RESET_CALI); return -1; } #endif return 0; } static int pshub_factory_set_cali(int32_t offset) { struct alspshub_ipi_data *obj = obj_ipi_data; obj->ps_cali = offset; return 0; } static int pshub_factory_get_cali(int32_t *offset) { struct alspshub_ipi_data *obj = obj_ipi_data; *offset = obj->ps_cali; return 0; } static int pshub_factory_set_threshold(int32_t threshold[2]) { int err = 0; struct alspshub_ipi_data *obj = obj_ipi_data; #ifndef MTK_OLD_FACTORY_CALIBRATION int32_t cfg_data[2] = {0}; #endif if (threshold[0] < threshold[1] || threshold[0] <= 0 || threshold[1] <= 0) { pr_err("PS set threshold fail! invalid value:[%d, %d]\n", threshold[0], threshold[1]); return -1; } spin_lock(&calibration_lock); atomic_set(&obj->ps_thd_val_high, (threshold[0] + obj->ps_cali)); atomic_set(&obj->ps_thd_val_low, (threshold[1] + obj->ps_cali)); spin_unlock(&calibration_lock); #ifdef MTK_OLD_FACTORY_CALIBRATION err = sensor_set_cmd_to_hub(ID_PROXIMITY, CUST_ACTION_SET_PS_THRESHOLD, threshold); if (err < 0) pr_err("sensor_set_cmd_to_hub fail, (ID:%d),(action:%d)\n", ID_PROXIMITY, CUST_ACTION_SET_PS_THRESHOLD); #else spin_lock(&calibration_lock); cfg_data[0] = atomic_read(&obj->ps_thd_val_high); cfg_data[1] = atomic_read(&obj->ps_thd_val_low); spin_unlock(&calibration_lock); err = sensor_cfg_to_hub(ID_PROXIMITY, (uint8_t *)cfg_data, sizeof(cfg_data)); if (err < 0) pr_err("sensor_cfg_to_hub fail\n"); ps_cali_report(cfg_data); #endif return err; } static int pshub_factory_get_threshold(int32_t threshold[2]) { struct alspshub_ipi_data *obj = obj_ipi_data; spin_lock(&calibration_lock); threshold[0] = atomic_read(&obj->ps_thd_val_high) - obj->ps_cali; threshold[1] = atomic_read(&obj->ps_thd_val_low) - obj->ps_cali; spin_unlock(&calibration_lock); return 0; } static struct alsps_factory_fops alspshub_factory_fops = { .als_enable_sensor = alshub_factory_enable_sensor, .als_get_data = alshub_factory_get_data, .als_get_raw_data = alshub_factory_get_raw_data, .als_enable_calibration = alshub_factory_enable_calibration, .als_clear_cali = alshub_factory_clear_cali, .als_set_cali = alshub_factory_set_cali, .als_get_cali = alshub_factory_get_cali, .ps_enable_sensor = pshub_factory_enable_sensor, .ps_get_data = pshub_factory_get_data, .ps_get_raw_data = pshub_factory_get_raw_data, .ps_enable_calibration = pshub_factory_enable_calibration, .ps_clear_cali = pshub_factory_clear_cali, .ps_set_cali = pshub_factory_set_cali, .ps_get_cali = pshub_factory_get_cali, .ps_set_threshold = pshub_factory_set_threshold, .ps_get_threshold = pshub_factory_get_threshold, }; static struct alsps_factory_public alspshub_factory_device = { .gain = 1, .sensitivity = 1, .fops = &alspshub_factory_fops, }; static int als_open_report_data(int open) { return 0; } static int als_enable_nodata(int en) { int res = 0; struct alspshub_ipi_data *obj = obj_ipi_data; pr_debug("obj_ipi_data als enable value = %d\n", en); if (en == true) WRITE_ONCE(obj->als_android_enable, true); else WRITE_ONCE(obj->als_android_enable, false); res = sensor_enable_to_hub(ID_LIGHT, en); if (res < 0) { pr_err("%s is failed!!\n", __func__); return -1; } mutex_lock(&alspshub_mutex); if (en) set_bit(CMC_BIT_ALS, &obj_ipi_data->enable); else clear_bit(CMC_BIT_ALS, &obj_ipi_data->enable); mutex_unlock(&alspshub_mutex); return 0; } static int als_set_delay(u64 ns) { #if defined CONFIG_MTK_SCP_SENSORHUB_V1 int err = 0; unsigned int delayms = 0; delayms = (unsigned int)ns / 1000 / 1000; err = sensor_set_delay_to_hub(ID_LIGHT, delayms); if (err) { pr_err("%s fail!\n", __func__); return err; } pr_debug("%s (%d)\n", __func__, delayms); return 0; #elif defined CONFIG_NANOHUB return 0; #else return 0; #endif } static int als_batch(int flag, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { #if defined CONFIG_MTK_SCP_SENSORHUB_V1 als_set_delay(samplingPeriodNs); #endif return sensor_batch_to_hub(ID_LIGHT, flag, samplingPeriodNs, maxBatchReportLatencyNs); } static int als_flush(void) { return sensor_flush_to_hub(ID_LIGHT); } static int als_set_cali(uint8_t *data, uint8_t count) { int32_t *buf = (int32_t *)data; struct alspshub_ipi_data *obj = obj_ipi_data; spin_lock(&calibration_lock); atomic_set(&obj->als_cali, buf[0]); spin_unlock(&calibration_lock); return sensor_cfg_to_hub(ID_LIGHT, data, count); } static int rgbw_enable(int en) { int res = 0; res = sensor_enable_to_hub(ID_RGBW, en); if (res < 0) { pr_err("%s is failed!!\n", __func__); return -1; } return 0; } static int rgbw_batch(int flag, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { return sensor_batch_to_hub(ID_RGBW, flag, samplingPeriodNs, maxBatchReportLatencyNs); } static int rgbw_flush(void) { return sensor_flush_to_hub(ID_RGBW); } static int als_get_data(int *value, int *status) { int err = 0; struct data_unit_t data; uint64_t time_stamp = 0; err = sensor_get_data_from_hub(ID_LIGHT, &data); if (err) { pr_err("sensor_get_data_from_hub fail!\n"); } else { time_stamp = data.time_stamp; *value = data.light; *status = SENSOR_STATUS_ACCURACY_MEDIUM; } if (atomic_read(&obj_ipi_data->trace) & CMC_TRC_PS_DATA) pr_debug("value = %d\n", *value); return 0; } static int ps_open_report_data(int open) { return 0; } static int ps_enable_nodata(int en) { int res = 0; struct alspshub_ipi_data *obj = obj_ipi_data; pr_debug("obj_ipi_data als enable value = %d\n", en); if (en == true) WRITE_ONCE(obj->ps_android_enable, true); else WRITE_ONCE(obj->ps_android_enable, false); res = sensor_enable_to_hub(ID_PROXIMITY, en); if (res < 0) { pr_err("als_enable_nodata is failed!!\n"); return -1; } mutex_lock(&alspshub_mutex); if (en) set_bit(CMC_BIT_PS, &obj_ipi_data->enable); else clear_bit(CMC_BIT_PS, &obj_ipi_data->enable); mutex_unlock(&alspshub_mutex); return 0; } static int ps_set_delay(u64 ns) { #if defined CONFIG_MTK_SCP_SENSORHUB_V1 int err = 0; unsigned int delayms = 0; delayms = (unsigned int)ns / 1000 / 1000; err = sensor_set_delay_to_hub(ID_PROXIMITY, delayms); if (err < 0) { pr_err("%s fail!\n", __func__); return err; } pr_debug("%s (%d)\n", __func__, delayms); return 0; #elif defined CONFIG_NANOHUB return 0; #else return 0; #endif } static int ps_batch(int flag, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { #if defined CONFIG_MTK_SCP_SENSORHUB_V1 ps_set_delay(samplingPeriodNs); #endif return sensor_batch_to_hub(ID_PROXIMITY, flag, samplingPeriodNs, maxBatchReportLatencyNs); } static int ps_flush(void) { return sensor_flush_to_hub(ID_PROXIMITY); } static int ps_get_data(int *value, int *status) { int err = 0; struct data_unit_t data; uint64_t time_stamp = 0; err = sensor_get_data_from_hub(ID_PROXIMITY, &data); if (err < 0) { pr_err("sensor_get_data_from_hub fail!\n"); *value = -1; err = -1; } else { time_stamp = data.time_stamp; *value = data.proximity_t.oneshot; *status = SENSOR_STATUS_ACCURACY_MEDIUM; } if (atomic_read(&obj_ipi_data->trace) & CMC_TRC_PS_DATA) pr_debug("value = %d\n", *value); return err; } static int ps_set_cali(uint8_t *data, uint8_t count) { int32_t *buf = (int32_t *)data; struct alspshub_ipi_data *obj = obj_ipi_data; spin_lock(&calibration_lock); atomic_set(&obj->ps_thd_val_high, buf[0]); atomic_set(&obj->ps_thd_val_low, buf[1]); spin_unlock(&calibration_lock); return sensor_cfg_to_hub(ID_PROXIMITY, data, count); } static int scp_ready_event(uint8_t event, void *ptr) { struct alspshub_ipi_data *obj = obj_ipi_data; switch (event) { case SENSOR_POWER_UP: atomic_set(&obj->scp_init_done, 1); schedule_work(&obj->init_done_work); break; case SENSOR_POWER_DOWN: atomic_set(&obj->scp_init_done, 0); break; } return 0; } static struct scp_power_monitor scp_ready_notifier = { .name = "alsps", .notifier_call = scp_ready_event, }; static int alspshub_probe(struct platform_device *pdev) { struct alspshub_ipi_data *obj; struct platform_driver *paddr = alspshub_init_info.platform_diver_addr; int err = 0; struct als_control_path als_ctl = { 0 }; struct als_data_path als_data = { 0 }; struct ps_control_path ps_ctl = { 0 }; struct ps_data_path ps_data = { 0 }; pr_debug("%s\n", __func__); obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) { err = -ENOMEM; goto exit; } memset(obj, 0, sizeof(*obj)); obj_ipi_data = obj; INIT_WORK(&obj->init_done_work, alspshub_init_done_work); platform_set_drvdata(pdev, obj); atomic_set(&obj->als_suspend, 0); atomic_set(&obj->scp_init_done, 0); atomic_set(&obj->first_ready_after_boot, 0); obj->enable = 0; obj->pending_intr = 0; obj->ps_cali = 0; atomic_set(&obj->ps_thd_val_low, 21); atomic_set(&obj->ps_thd_val_high, 28); WRITE_ONCE(obj->als_factory_enable, false); WRITE_ONCE(obj->als_android_enable, false); WRITE_ONCE(obj->ps_factory_enable, false); WRITE_ONCE(obj->ps_android_enable, false); clear_bit(CMC_BIT_ALS, &obj->enable); clear_bit(CMC_BIT_PS, &obj->enable); scp_power_monitor_register(&scp_ready_notifier); err = scp_sensorHub_data_registration(ID_PROXIMITY, ps_recv_data); if (err < 0) { pr_err("scp_sensorHub_data_registration failed\n"); goto exit_kfree; } err = scp_sensorHub_data_registration(ID_LIGHT, als_recv_data); if (err < 0) { pr_err("scp_sensorHub_data_registration failed\n"); goto exit_kfree; } err = scp_sensorHub_data_registration(ID_RGBW, rgbw_recv_data); if (err < 0) { pr_err("scp_sensorHub_data_registration failed\n"); goto exit_kfree; } err = alsps_factory_device_register(&alspshub_factory_device); if (err) { pr_err("alsps_factory_device_register register failed\n"); goto exit_kfree; } pr_debug("alspshub_misc_device misc_register OK!\n"); als_ctl.is_use_common_factory = false; ps_ctl.is_use_common_factory = false; err = alspshub_create_attr(&paddr->driver); if (err) { pr_err("create attribute err = %d\n", err); goto exit_create_attr_failed; } als_ctl.open_report_data = als_open_report_data; als_ctl.enable_nodata = als_enable_nodata; als_ctl.set_delay = als_set_delay; als_ctl.batch = als_batch; als_ctl.flush = als_flush; als_ctl.set_cali = als_set_cali; als_ctl.rgbw_enable = rgbw_enable; als_ctl.rgbw_batch = rgbw_batch; als_ctl.rgbw_flush = rgbw_flush; als_ctl.is_report_input_direct = false; als_ctl.is_support_batch = false; err = als_register_control_path(&als_ctl); if (err) { pr_err("register fail = %d\n", err); goto exit_create_attr_failed; } als_data.get_data = als_get_data; als_data.vender_div = 100; err = als_register_data_path(&als_data); if (err) { pr_err("tregister fail = %d\n", err); goto exit_create_attr_failed; } ps_ctl.open_report_data = ps_open_report_data; ps_ctl.enable_nodata = ps_enable_nodata; ps_ctl.set_delay = ps_set_delay; ps_ctl.batch = ps_batch; ps_ctl.flush = ps_flush; ps_ctl.set_cali = ps_set_cali; ps_ctl.is_report_input_direct = false; ps_ctl.is_support_batch = false; err = ps_register_control_path(&ps_ctl); if (err) { pr_err("register fail = %d\n", err); goto exit_create_attr_failed; } ps_data.get_data = ps_get_data; ps_data.vender_div = 100; err = ps_register_data_path(&ps_data); if (err) { pr_err("tregister fail = %d\n", err); goto exit_create_attr_failed; } obj->ps_wake_lock = wakeup_source_register(NULL, "ps_wake_lock"); if (!obj->ps_wake_lock) { pr_err("wakeup source init fail\n"); err = -ENOMEM; goto exit_create_attr_failed; } alspshub_init_flag = 0; pr_debug("%s: OK\n", __func__); return 0; exit_create_attr_failed: alspshub_delete_attr(&(alspshub_init_info.platform_diver_addr->driver)); exit_kfree: kfree(obj); obj_ipi_data = NULL; exit: pr_err("%s: err = %d\n", __func__, err); alspshub_init_flag = -1; return err; } static int alspshub_remove(struct platform_device *pdev) { int err = 0; struct platform_driver *paddr = alspshub_init_info.platform_diver_addr; struct alspshub_ipi_data *obj = obj_ipi_data; if (obj) wakeup_source_unregister(obj->ps_wake_lock); err = alspshub_delete_attr(&paddr->driver); if (err) pr_err("alspshub_delete_attr fail: %d\n", err); alsps_factory_device_deregister(&alspshub_factory_device); kfree(platform_get_drvdata(pdev)); return 0; } static int alspshub_suspend(struct platform_device *pdev, pm_message_t msg) { pr_debug("%s\n", __func__); return 0; } static int alspshub_resume(struct platform_device *pdev) { pr_debug("%s\n", __func__); return 0; } static struct platform_device alspshub_device = { .name = ALSPSHUB_DEV_NAME, .id = -1, }; static struct platform_driver alspshub_driver = { .probe = alspshub_probe, .remove = alspshub_remove, .suspend = alspshub_suspend, .resume = alspshub_resume, .driver = { .name = ALSPSHUB_DEV_NAME, }, }; static int alspshub_local_init(void) { if (platform_driver_register(&alspshub_driver)) { pr_err("add driver error\n"); return -1; } if (-1 == alspshub_init_flag) return -1; return 0; } static int alspshub_local_remove(void) { platform_driver_unregister(&alspshub_driver); return 0; } static int __init alspshub_init(void) { if (platform_device_register(&alspshub_device)) { pr_err("alsps platform device error\n"); return -1; } alsps_driver_add(&alspshub_init_info); return 0; } static void __exit alspshub_exit(void) { pr_debug("%s\n", __func__); } module_init(alspshub_init); module_exit(alspshub_exit); MODULE_AUTHOR("hongxu.zhao@mediatek.com"); MODULE_DESCRIPTION("alspshub driver"); MODULE_LICENSE("GPL");