sensors: import ASH drivers

Change-Id: I25085520ec10434c270cff80684d2d8676e00887
This commit is contained in:
Cosmin Tanislav 2022-02-09 19:40:09 +02:00 committed by Davide Garberi
parent 8d81bf7933
commit 755665a8e2
40 changed files with 22374 additions and 0 deletions

View File

@ -0,0 +1,183 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/******************************/
/* Asus Sensor Hub Attribute */
/*****************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/input/ASH.h>
static int g_devMajor = -1;
static struct class *g_property_class = NULL;
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_ATTR"
#undef dbg
#ifdef ASH_ATTR_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s]"fmt,MODULE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s]"fmt,MODULE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s]"fmt,MODULE_NAME,##args)
static int ASH_class_open(struct inode * inode, struct file * file)
{
return 0;
}
static const struct file_operations ASH_class_fops = {
.owner = THIS_MODULE,
.open = ASH_class_open,
};
static int create_ASH_chrdev(void)
{
/*create character device*/
g_devMajor = register_chrdev(0, "sensors", &ASH_class_fops);
if (g_devMajor < 0) {
err("%s: could not get major number\n", __FUNCTION__);
return g_devMajor;
}
return 0;
}
static int create_ASH_class(void)
{
/* create sys/class file node*/
g_property_class = class_create(THIS_MODULE, "sensors");
if (IS_ERR(g_property_class)) {
err("%s: class_create ERROR.\n", __FUNCTION__);
return PTR_ERR(g_property_class);
}
return 0;
}
/*
Return NULL for error handling
*/
struct device *ASH_ATTR_device_create(ASH_type type)
{
int ret = 0;
dev_t dev;
struct device *sensor_dev=NULL;
/*prepare character device and return for error handling*/
if(g_devMajor < 0){
ret=create_ASH_chrdev();
if(ret < 0)
return NULL;
}
/*prepare sys/class file node and return for error handling*/
if(g_property_class == NULL || IS_ERR(g_property_class) ){
ret=create_ASH_class();
if(ret < 0)
return NULL;
}
switch(type){
case psensor:
dev = MKDEV(g_devMajor, psensor);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "psensor");
break;
case psensor_2nd:
dev = MKDEV(g_devMajor, psensor_2nd);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "psensor_2nd");
break;
case lsensor:
dev = MKDEV(g_devMajor, lsensor);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "lsensor");
break;
case lsensor_2nd:
dev = MKDEV(g_devMajor, lsensor_2nd);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "lsensor_2nd");
break;
case frgbsensor:
dev = MKDEV(g_devMajor, frgbsensor);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "frgbsensor");
break;
case hallsensor:
dev = MKDEV(g_devMajor, hallsensor);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "hallsensor");
break;
case sarsensor:
dev = MKDEV(g_devMajor, sarsensor);
sensor_dev = device_create(g_property_class, NULL, dev, NULL, "%s", "sarsensor");
break;
default:
err("%s: Type ERROR.(%d)\n", __FUNCTION__, type);
}
if (IS_ERR(sensor_dev)) {
ret = PTR_ERR(sensor_dev);
err("%s: sensor_dev pointer is ERROR(%d). \n", __FUNCTION__, ret);
return NULL;
}
return sensor_dev;
}
EXPORT_SYMBOL(ASH_ATTR_device_create);
void ASH_ATTR_device_remove(ASH_type type)
{
dev_t dev;
switch(type){
case psensor:
dev = MKDEV(g_devMajor, psensor);
device_destroy(g_property_class, dev);
break;
case psensor_2nd:
dev = MKDEV(g_devMajor, psensor_2nd);
device_destroy(g_property_class, dev);
break;
case lsensor:
dev = MKDEV(g_devMajor, lsensor);
device_destroy(g_property_class, dev);
break;
case lsensor_2nd:
dev = MKDEV(g_devMajor, lsensor_2nd);
device_destroy(g_property_class, dev);
break;
case frgbsensor:
dev = MKDEV(g_devMajor, frgbsensor);
device_destroy(g_property_class, dev);
break;
case hallsensor:
dev = MKDEV(g_devMajor, hallsensor);
device_destroy(g_property_class, dev);
break;
case sarsensor:
dev = MKDEV(g_devMajor, sarsensor);
device_destroy(g_property_class, dev);
break;
default:
err("%s: ASH_ATTR_device_remove Type ERROR.(%d)\n", __FUNCTION__, type);
}
}
EXPORT_SYMBOL(ASH_ATTR_device_remove);

View File

@ -0,0 +1,504 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/****************************/
/* Light Sensor Atrribute */
/***************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/input/ASH.h>
#define RGB 1
#define BUF_SIZE (10)
static lsensor_ATTR *g_light_ATTR = NULL;
static struct device *g_lsensor_dev;
/*******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_ATTR"
#define SENSOR_TYPE_NAME "light"
#undef dbg
#ifdef ASH_ATTR_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static ssize_t ATT_light_show_vendor(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_light_ATTR->info_type->vendor, "") == 0) {
err("2nd Show vendor NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_light_ATTR->info_type->vendor);
}
static ssize_t ATT_light_show_module_number(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_light_ATTR->info_type->module_number, "") == 0) {
err("2nd Show module number NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_light_ATTR->info_type->module_number);
}
/**************************/
/*Calibration Function*/
/************************/
static ssize_t ATT_light_show_calibration(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_light_ATTR->ATTR_Calibration->light_show_calibration == NULL) {
err("2nd light_show_calibration NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_light_ATTR->ATTR_Calibration->light_show_calibration();
dbg("2nd Light Sensor show Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_light_store_calibration(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_light_ATTR->ATTR_Calibration->light_store_calibration == NULL) {
err("2nd light_store_calibration NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Light Sensor store Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("2nd Light Sensor store Calibration: %lu\n", calvalue);
if(g_light_ATTR->ATTR_Calibration->light_store_calibration(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_gain(struct device *dev,
struct device_attribute *attr, char *buf)
{
int gainvalue = 0;
if(g_light_ATTR->ATTR_Calibration->light_show_gain == NULL) {
err("2nd light_show_gain NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
gainvalue = g_light_ATTR->ATTR_Calibration->light_show_gain();
return sprintf(buf, "%d.%05d\n",
gainvalue/LIGHT_GAIN_ACCURACY_CALVALUE, gainvalue%LIGHT_GAIN_ACCURACY_CALVALUE);
}
static ssize_t ATT_light_show_adc(struct device *dev, struct device_attribute *attr, char *buf)
{
int adc = 0;
if(g_light_ATTR->ATTR_Calibration->light_show_adc == NULL) {
err("2nd light_show_adc NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
adc = g_light_ATTR->ATTR_Calibration->light_show_adc();
return sprintf(buf, "%d\n", adc);
}
/********************/
/*BMMI Function*/
/*******************/
static ssize_t ATT_light_show_atd_test(struct device *dev, struct device_attribute *attr, char *buf)
{
bool atd_test = false;
if(g_light_ATTR->ATTR_BMMI->light_show_atd_test== NULL) {
err("2nd light_show_atd_test NOT SUPPORT. \n");
return sprintf(buf, "%d\n", atd_test);
}
atd_test = g_light_ATTR->ATTR_BMMI->light_show_atd_test();
return sprintf(buf, "%d\n", atd_test);
}
/************************/
/*Hardware Function*/
/***********************/
static ssize_t ATT_light_show_read_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_light_ATTR->ATTR_Hardware->light_show_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
i2c_reg_addr = g_light_ATTR->ATTR_Hardware->show_reg_addr;
i2c_reg_value = g_light_ATTR->ATTR_Hardware->light_show_reg(i2c_reg_addr);
return sprintf(buf, "%d\n", i2c_reg_value);
}
static ssize_t ATT_light_store_read_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0;
if(g_light_ATTR->ATTR_Hardware->light_show_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x", &i2c_reg_addr);
g_light_ATTR->ATTR_Hardware->show_reg_addr=i2c_reg_addr;
return count;
}
static ssize_t ATT_light_store_write_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_light_ATTR->ATTR_Hardware->light_store_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x %d", &i2c_reg_addr, &i2c_reg_value);
log("2nd IRsensor_store_reg, addr=%02X, value=%02X\n", i2c_reg_addr, i2c_reg_value);
if(g_light_ATTR->ATTR_Hardware->light_store_reg(i2c_reg_addr, i2c_reg_value) < 0)
return -EINVAL;
return count;
}
/******************/
/*HAL Function*/
/*****************/
static ssize_t ATT_light_show_switch_onoff(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_light_ATTR->ATTR_HAL->light_show_switch_onoff== NULL) {
err("2nd light_show_switch_onoff NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_light_ATTR->ATTR_HAL->light_show_switch_onoff();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_light_store_switch_onoff(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_light_ATTR->ATTR_HAL->light_store_switch_onoff == NULL) {
err("2nd light_store_switch_onoff NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("2nd Light Sensor switch %s\n", bOn?"on":"off");
if(g_light_ATTR->ATTR_HAL->light_store_switch_onoff(bOn) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_lux(struct device *dev,
struct device_attribute *attr, char *buf)
{
int lux;
if(g_light_ATTR->ATTR_HAL->light_show_lux== NULL) {
err("2nd light_show_lux NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
lux = g_light_ATTR->ATTR_HAL->light_show_lux();
return sprintf(buf, "%d\n", lux);
}
/************************/
/*Extension Function*/
/***********************/
static ssize_t ATT_light_show_allreg(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool ret;
if(g_light_ATTR->ATTR_Extension->light_show_allreg== NULL) {
err("2nd IRsensor_show_allreg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret=g_light_ATTR->ATTR_Extension->light_show_allreg(dev, attr, buf);
return sprintf(buf, "%d\n", ret);
}
static ssize_t ATT_light_show_sensitivity(struct device *dev,
struct device_attribute *attr, char *buf)
{
int sensitivity = 0;
if(g_light_ATTR->ATTR_Extension->light_show_sensitivity == NULL) {
err("2nd light_show_sensitivity NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
sensitivity = g_light_ATTR->ATTR_Extension->light_show_sensitivity();
return sprintf(buf, "%d\n", sensitivity);
}
static ssize_t ATT_light_store_sensitivity(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long sensitivity;
if(g_light_ATTR->ATTR_Extension->light_store_sensitivity == NULL) {
err("2nd light_store_sensitivity NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &sensitivity) < 0))
return -EINVAL;
if(sensitivity < 0) {
err("2nd Light Sensor store Sensitivity with NEGATIVE value. (%lu) \n", sensitivity);
return -EINVAL;
}
log("2nd Light Sensor store Sensitivity: %lu\n", sensitivity);
if(g_light_ATTR->ATTR_Extension->light_store_sensitivity(sensitivity) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_log_threshold(struct device *dev,
struct device_attribute *attr, char *buf)
{
int log_threshold = 0;
if(g_light_ATTR->ATTR_Extension->light_show_log_threshold == NULL) {
err("2nd light_show_log_threshold NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
log_threshold = g_light_ATTR->ATTR_Extension->light_show_log_threshold();
return sprintf(buf, "%d\n", log_threshold);
}
static ssize_t ATT_light_store_log_threshold(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long log_threshold;
if(g_light_ATTR->ATTR_Extension->light_store_log_threshold == NULL) {
err("2nd light_store_log_threshold NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &log_threshold) < 0))
return -EINVAL;
if(log_threshold < 0) {
err("2nd Light Sensor store Log Threshold with NEGATIVE value. (%lu) \n", log_threshold);
return -EINVAL;
}
log("2nd Light Sensor store Log Threshold: %lu\n", log_threshold);
if(g_light_ATTR->ATTR_Extension->light_store_log_threshold(log_threshold) < 0)
return -EINVAL;
return count;
}
/* +++ For stress test debug +++ */
static ssize_t ATT_light_show_int_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int l_int_counter=0;
if(g_light_ATTR->ATTR_Extension->light_show_int_count == NULL) {
err("2nd light_show_int_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
l_int_counter = g_light_ATTR->ATTR_Extension->light_show_int_count();
return sprintf(buf, "%d\n", l_int_counter);
}
static ssize_t ATT_light_show_event_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int l_event_counter=0;
if(g_light_ATTR->ATTR_Extension->light_show_event_count == NULL) {
err("2nd light_show_event_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
l_event_counter = g_light_ATTR->ATTR_Extension->light_show_event_count();
return sprintf(buf, "%d\n", l_event_counter);
}
static ssize_t ATT_light_show_error_mesg(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
char* error_mesg=kzalloc(sizeof(char [ERROR_MESG_SIZE]), GFP_KERNEL);
if(g_light_ATTR->ATTR_Extension->light_show_error_mesg== NULL) {
err("2nd IRsensor_show_error_mesg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret = g_light_ATTR->ATTR_Extension->light_show_error_mesg(error_mesg);
return sprintf(buf, "%s\n", error_mesg);
}
/* --- For stress test debug --- */
/*For transition period from 3/5 to 2/4*/
static ssize_t ATT_light_show_selection(struct device *dev,
struct device_attribute *attr, char *buf)
{
int selection = 0;
if(g_light_ATTR->ATTR_Extension->light_show_selection == NULL) {
err("2nd light_show_selection NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
selection = g_light_ATTR->ATTR_Extension->light_show_selection();
return sprintf(buf, "%d\n", selection);
}
static ssize_t ATT_light_store_selection(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long selection;
if(g_light_ATTR->ATTR_Extension->light_store_selection == NULL) {
err("2nd light_store_selection NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &selection) < 0))
return -EINVAL;
if(selection < 0) {
err("2nd Light Sensor store selection with NEGATIVE value. (%lu) \n", selection);
return -EINVAL;
}
log("2nd Light Sensor store selection: %lu\n", selection);
if(g_light_ATTR->ATTR_Extension->light_store_selection(selection) < 0)
return -EINVAL;
return count;
}
static struct device_attribute light_property_attrs[] = {
/*read only*/
__ATTR(vendor, 0444, ATT_light_show_vendor, NULL),
__ATTR(module_number, 0444, ATT_light_show_module_number, NULL),
__ATTR(adc, 0444, ATT_light_show_adc, NULL),
__ATTR(gain, 0444, ATT_light_show_gain, NULL),
__ATTR(atd_status, 0444, ATT_light_show_atd_test, NULL),
__ATTR(lux, 0444, ATT_light_show_lux, NULL),
__ATTR(dump_reg, 0444, ATT_light_show_allreg, NULL),
/* +++ For stress test debug +++ */
__ATTR(int_counter, 0444, ATT_light_show_int_count, NULL),
__ATTR(event_counter, 0444, ATT_light_show_event_count, NULL),
__ATTR(error_mesg, 0444, ATT_light_show_error_mesg, NULL),
/* --- For stress test debug --- */
/*read/write*/
__ATTR(switch, 0664, ATT_light_show_switch_onoff, ATT_light_store_switch_onoff),
__ATTR(cal, 0664, ATT_light_show_calibration, ATT_light_store_calibration),
__ATTR(sensitivity, 0664, ATT_light_show_sensitivity, ATT_light_store_sensitivity),
__ATTR(read_reg, 0664, ATT_light_show_read_reg, ATT_light_store_read_reg),
__ATTR(write_reg, 0220, NULL, ATT_light_store_write_reg),
__ATTR(log_threshold, 0664, ATT_light_show_log_threshold, ATT_light_store_log_threshold),
/*For transition period from 3/5 to 2/4*/
__ATTR(selection, 0664, ATT_light_show_selection, ATT_light_store_selection),
};
int lsensor_ATTR_register_2nd(lsensor_ATTR *mATTR)
{
int ret = 0;
int ATTR_index;
g_light_ATTR=mATTR;
/*lsensor device*/
g_lsensor_dev = ASH_ATTR_device_create(lsensor_2nd);
if (IS_ERR(g_lsensor_dev) || g_lsensor_dev == NULL) {
err("%s: 2nd lsensor create ERROR.\n", __FUNCTION__);
ret = PTR_ERR(g_lsensor_dev);
return ret;
}
for (ATTR_index=0; ATTR_index < ARRAY_SIZE(light_property_attrs); ATTR_index++) {
ret = device_create_file(g_lsensor_dev, &light_property_attrs[ATTR_index]);
if (ret){
return ret;
}
}
return 0;
}
EXPORT_SYMBOL(lsensor_ATTR_register_2nd);
int lsensor_ATTR_unregister_2nd(void)
{
ASH_ATTR_device_remove(lsensor_2nd);
return 0;
}
EXPORT_SYMBOL(lsensor_ATTR_unregister_2nd);
int lsensor_ATTR_create_2nd(struct device_attribute *mlsensor_attr)
{
int ret = 0;
if(mlsensor_attr == NULL) {
err("%s: 2nd the device_attribute is NULL point. \n", __FUNCTION__);
return -EINVAL;
}
ret = device_create_file(g_lsensor_dev, mlsensor_attr);
if (ret){
err("%s: 2nd device_create_file ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL(lsensor_ATTR_create_2nd);

View File

@ -0,0 +1,502 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/****************************/
/* Light Sensor Atrribute */
/***************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/input/ASH.h>
#define RGB 1
#define BUF_SIZE (10)
static lsensor_ATTR *g_light_ATTR = NULL;
static struct device *g_lsensor_dev;
/*******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_ATTR"
#define SENSOR_TYPE_NAME "light"
#undef dbg
#ifdef ASH_ATTR_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static ssize_t ATT_light_show_vendor(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_light_ATTR->info_type->vendor, "") == 0) {
err("Show vendor NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_light_ATTR->info_type->vendor);
}
static ssize_t ATT_light_show_module_number(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_light_ATTR->info_type->module_number, "") == 0) {
err("Show module number NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_light_ATTR->info_type->module_number);
}
/**************************/
/*Calibration Function*/
/************************/
static ssize_t ATT_light_show_calibration(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_light_ATTR->ATTR_Calibration->light_show_calibration == NULL) {
err("light_show_calibration NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_light_ATTR->ATTR_Calibration->light_show_calibration();
dbg("Light Sensor show Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_light_store_calibration(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_light_ATTR->ATTR_Calibration->light_store_calibration == NULL) {
err("light_store_calibration NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Light Sensor store Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Light Sensor store Calibration: %lu\n", calvalue);
if(g_light_ATTR->ATTR_Calibration->light_store_calibration(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_gain(struct device *dev,
struct device_attribute *attr, char *buf)
{
int gainvalue = 0;
if(g_light_ATTR->ATTR_Calibration->light_show_gain == NULL) {
err("light_show_gain NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
gainvalue = g_light_ATTR->ATTR_Calibration->light_show_gain();
return sprintf(buf, "%d.%05d\n",
gainvalue/LIGHT_GAIN_ACCURACY_CALVALUE, gainvalue%LIGHT_GAIN_ACCURACY_CALVALUE);
}
static ssize_t ATT_light_show_adc(struct device *dev, struct device_attribute *attr, char *buf)
{
int adc = 0;
if(g_light_ATTR->ATTR_Calibration->light_show_adc == NULL) {
err("light_show_adc NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
adc = g_light_ATTR->ATTR_Calibration->light_show_adc();
return sprintf(buf, "%d\n", adc);
}
/********************/
/*BMMI Function*/
/*******************/
static ssize_t ATT_light_show_atd_test(struct device *dev, struct device_attribute *attr, char *buf)
{
bool atd_test = false;
if(g_light_ATTR->ATTR_BMMI->light_show_atd_test== NULL) {
err("light_show_atd_test NOT SUPPORT. \n");
return sprintf(buf, "%d\n", atd_test);
}
atd_test = g_light_ATTR->ATTR_BMMI->light_show_atd_test();
return sprintf(buf, "%d\n", atd_test);
}
/************************/
/*Hardware Function*/
/***********************/
static ssize_t ATT_light_show_read_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_light_ATTR->ATTR_Hardware->light_show_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
i2c_reg_addr = g_light_ATTR->ATTR_Hardware->show_reg_addr;
i2c_reg_value = g_light_ATTR->ATTR_Hardware->light_show_reg(i2c_reg_addr);
return sprintf(buf, "%d\n", i2c_reg_value);
}
static ssize_t ATT_light_store_read_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0;
if(g_light_ATTR->ATTR_Hardware->light_show_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x", &i2c_reg_addr);
g_light_ATTR->ATTR_Hardware->show_reg_addr=i2c_reg_addr;
return count;
}
static ssize_t ATT_light_store_write_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_light_ATTR->ATTR_Hardware->light_store_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x %d", &i2c_reg_addr, &i2c_reg_value);
log("IRsensor_store_reg, addr=%02X, value=%02X\n", i2c_reg_addr, i2c_reg_value);
if(g_light_ATTR->ATTR_Hardware->light_store_reg(i2c_reg_addr, i2c_reg_value) < 0)
return -EINVAL;
return count;
}
/******************/
/*HAL Function*/
/*****************/
static ssize_t ATT_light_show_switch_onoff(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_light_ATTR->ATTR_HAL->light_show_switch_onoff== NULL) {
err("light_show_switch_onoff NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_light_ATTR->ATTR_HAL->light_show_switch_onoff();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_light_store_switch_onoff(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_light_ATTR->ATTR_HAL->light_store_switch_onoff == NULL) {
err("light_store_switch_onoff NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("Light Sensor switch %s\n", bOn?"on":"off");
if(g_light_ATTR->ATTR_HAL->light_store_switch_onoff(bOn) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_lux(struct device *dev,
struct device_attribute *attr, char *buf)
{
int lux;
if(g_light_ATTR->ATTR_HAL->light_show_lux== NULL) {
err("light_show_lux NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
lux = g_light_ATTR->ATTR_HAL->light_show_lux();
return sprintf(buf, "%d\n", lux);
}
/************************/
/*Extension Function*/
/***********************/
static ssize_t ATT_light_show_allreg(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(g_light_ATTR->ATTR_Extension->light_show_allreg== NULL) {
err("IRsensor_show_allreg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
log("print all reg");
return g_light_ATTR->ATTR_Extension->light_show_allreg(dev, attr, buf);
}
static ssize_t ATT_light_show_sensitivity(struct device *dev,
struct device_attribute *attr, char *buf)
{
int sensitivity = 0;
if(g_light_ATTR->ATTR_Extension->light_show_sensitivity == NULL) {
err("light_show_sensitivity NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
sensitivity = g_light_ATTR->ATTR_Extension->light_show_sensitivity();
return sprintf(buf, "%d\n", sensitivity);
}
static ssize_t ATT_light_store_sensitivity(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long sensitivity;
if(g_light_ATTR->ATTR_Extension->light_store_sensitivity == NULL) {
err("light_store_sensitivity NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &sensitivity) < 0))
return -EINVAL;
if(sensitivity < 0) {
err("Light Sensor store Sensitivity with NEGATIVE value. (%lu) \n", sensitivity);
return -EINVAL;
}
log("Light Sensor store Sensitivity: %lu\n", sensitivity);
if(g_light_ATTR->ATTR_Extension->light_store_sensitivity(sensitivity) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_light_show_log_threshold(struct device *dev,
struct device_attribute *attr, char *buf)
{
int log_threshold = 0;
if(g_light_ATTR->ATTR_Extension->light_show_log_threshold == NULL) {
err("light_show_log_threshold NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
log_threshold = g_light_ATTR->ATTR_Extension->light_show_log_threshold();
return sprintf(buf, "%d\n", log_threshold);
}
static ssize_t ATT_light_store_log_threshold(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long log_threshold;
if(g_light_ATTR->ATTR_Extension->light_store_log_threshold == NULL) {
err("light_store_log_threshold NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &log_threshold) < 0))
return -EINVAL;
if(log_threshold < 0) {
err("Light Sensor store Log Threshold with NEGATIVE value. (%lu) \n", log_threshold);
return -EINVAL;
}
log("Light Sensor store Log Threshold: %lu\n", log_threshold);
if(g_light_ATTR->ATTR_Extension->light_store_log_threshold(log_threshold) < 0)
return -EINVAL;
return count;
}
/* +++ For stress test debug +++ */
static ssize_t ATT_light_show_int_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int l_int_counter=0;
if(g_light_ATTR->ATTR_Extension->light_show_int_count == NULL) {
err("light_show_int_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
l_int_counter = g_light_ATTR->ATTR_Extension->light_show_int_count();
return sprintf(buf, "%d\n", l_int_counter);
}
static ssize_t ATT_light_show_event_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int l_event_counter=0;
if(g_light_ATTR->ATTR_Extension->light_show_event_count == NULL) {
err("light_show_event_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
l_event_counter = g_light_ATTR->ATTR_Extension->light_show_event_count();
return sprintf(buf, "%d\n", l_event_counter);
}
static ssize_t ATT_light_show_error_mesg(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
char* error_mesg=kzalloc(sizeof(char [ERROR_MESG_SIZE]), GFP_KERNEL);
if(g_light_ATTR->ATTR_Extension->light_show_error_mesg== NULL) {
err("IRsensor_show_error_mesg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret = g_light_ATTR->ATTR_Extension->light_show_error_mesg(error_mesg);
return sprintf(buf, "%s\n", error_mesg);
}
/* --- For stress test debug --- */
/*For transition period from 3/5 to 2/4*/
static ssize_t ATT_light_show_selection(struct device *dev,
struct device_attribute *attr, char *buf)
{
int selection = 0;
if(g_light_ATTR->ATTR_Extension->light_show_selection == NULL) {
err("light_show_selection NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
selection = g_light_ATTR->ATTR_Extension->light_show_selection();
return sprintf(buf, "%d\n", selection);
}
static ssize_t ATT_light_store_selection(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long selection;
if(g_light_ATTR->ATTR_Extension->light_store_selection == NULL) {
err("light_store_selection NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &selection) < 0))
return -EINVAL;
if(selection < 0) {
err("Light Sensor store selection with NEGATIVE value. (%lu) \n", selection);
return -EINVAL;
}
log("Light Sensor store selection: %lu\n", selection);
if(g_light_ATTR->ATTR_Extension->light_store_selection(selection) < 0)
return -EINVAL;
return count;
}
static struct device_attribute light_property_attrs[] = {
/*read only*/
__ATTR(vendor, 0444, ATT_light_show_vendor, NULL),
__ATTR(module_number, 0444, ATT_light_show_module_number, NULL),
__ATTR(adc, 0444, ATT_light_show_adc, NULL),
__ATTR(gain, 0444, ATT_light_show_gain, NULL),
__ATTR(atd_status, 0444, ATT_light_show_atd_test, NULL),
__ATTR(lux, 0444, ATT_light_show_lux, NULL),
__ATTR(dump_reg, 0444, ATT_light_show_allreg, NULL),
/* +++ For stress test debug +++ */
__ATTR(int_counter, 0444, ATT_light_show_int_count, NULL),
__ATTR(event_counter, 0444, ATT_light_show_event_count, NULL),
__ATTR(error_mesg, 0444, ATT_light_show_error_mesg, NULL),
/* --- For stress test debug --- */
/*read/write*/
__ATTR(switch, 0664, ATT_light_show_switch_onoff, ATT_light_store_switch_onoff),
__ATTR(cal, 0664, ATT_light_show_calibration, ATT_light_store_calibration),
__ATTR(sensitivity, 0664, ATT_light_show_sensitivity, ATT_light_store_sensitivity),
__ATTR(read_reg, 0664, ATT_light_show_read_reg, ATT_light_store_read_reg),
__ATTR(write_reg, 0220, NULL, ATT_light_store_write_reg),
__ATTR(log_threshold, 0664, ATT_light_show_log_threshold, ATT_light_store_log_threshold),
/*For transition period from 3/5 to 2/4*/
__ATTR(selection, 0664, ATT_light_show_selection, ATT_light_store_selection),
};
int lsensor_ATTR_register(lsensor_ATTR *mATTR)
{
int ret = 0;
int ATTR_index;
g_light_ATTR=mATTR;
/*lsensor device*/
g_lsensor_dev = ASH_ATTR_device_create(lsensor);
if (IS_ERR(g_lsensor_dev) || g_lsensor_dev == NULL) {
err("%s: lsensor create ERROR.\n", __FUNCTION__);
ret = PTR_ERR(g_lsensor_dev);
return ret;
}
for (ATTR_index=0; ATTR_index < ARRAY_SIZE(light_property_attrs); ATTR_index++) {
ret = device_create_file(g_lsensor_dev, &light_property_attrs[ATTR_index]);
if (ret){
return ret;
}
}
return 0;
}
EXPORT_SYMBOL(lsensor_ATTR_register);
int lsensor_ATTR_unregister(void)
{
ASH_ATTR_device_remove(lsensor);
return 0;
}
EXPORT_SYMBOL(lsensor_ATTR_unregister);
int lsensor_ATTR_create(struct device_attribute *mlsensor_attr)
{
int ret = 0;
if(mlsensor_attr == NULL) {
err("%s: the device_attribute is NULL point. \n", __FUNCTION__);
return -EINVAL;
}
ret = device_create_file(g_lsensor_dev, mlsensor_attr);
if (ret){
err("%s: device_create_file ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL(lsensor_ATTR_create);

View File

@ -0,0 +1,794 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*********************************/
/* Proximity Sensor Atrribute */
/********************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/input/ASH.h>
#define RGB 1
#define BUF_SIZE (10)
static psensor_ATTR *g_psensor_ATTR = NULL;
static struct device *g_psensor_dev;
/*******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_ATTR"
#define SENSOR_TYPE_NAME "proximity_2nd"
#undef dbg
#ifdef ASH_ATTR_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static void proximity_onoff(struct work_struct *work);
static DECLARE_WORK(proximity_onoff_work, proximity_onoff);
static int g_psensor_on_flag = false;
bool g_Psensor2_load_cal_status = false;
static ssize_t ATT_proximity_show_vendor(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_psensor_ATTR->info_type->vendor, "") == 0) {
err("2nd Show vendor NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_psensor_ATTR->info_type->vendor);
}
static ssize_t ATT_proximity_show_module_number(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_psensor_ATTR->info_type->module_number, "") == 0) {
err("2nd Show module number NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_psensor_ATTR->info_type->module_number);
}
/**************************/
/*Calibration Function*/
/************************/
static ssize_t ATT_proximity_show_calibration_hi(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_hi== NULL) {
err("2nd proximity_show_calibration_hi NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_hi();
dbg("2nd Proximity show High Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_hi(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_hi == NULL) {
err("2nd proximity_store_calibration_hi NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("2nd Proximity store High Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("2nd Proximity store High Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_hi(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_calibration_lo(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_lo == NULL) {
err("2nd proximity_show_calibration_lo NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_lo();
dbg("2nd Proximity show Low Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_lo(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_lo == NULL) {
err("2nd proximity_store_calibration_lo NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("2nd Proximity store Low Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("2nd Proximity store Low Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_lo(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_calibration_inf(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_inf == NULL) {
err("2nd proximity_show_calibration_inf NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_inf();
dbg("2nd Proximity show Inf Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_inf(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_inf == NULL) {
err("2nd proximity_store_calibration_inf NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("2nd Proximity store Inf Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Proximity store Inf Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_inf(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_adc(struct device *dev, struct device_attribute *attr, char *buf)
{
int adc = 0;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_adc == NULL) {
err("2nd proximity_show_adc NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
adc = g_psensor_ATTR->ATTR_Calibration->proximity_show_adc();
return sprintf(buf, "%d\n", adc);
}
/********************/
/*BMMI Function*/
/*******************/
static ssize_t ATT_proximity_show_atd_test(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool atd_test = false;
if(g_psensor_ATTR->ATTR_BMMI->proximity_show_atd_test== NULL) {
err("2nd proximity_show_atd_test NOT SUPPORT. \n");
return sprintf(buf, "%d\n", atd_test);
}
atd_test = g_psensor_ATTR->ATTR_BMMI->proximity_show_atd_test();
return sprintf(buf, "%d\n", atd_test);
}
/************************/
/*Hardware Function*/
/***********************/
static ssize_t ATT_proximity_show_read_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_show_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
i2c_reg_addr = g_psensor_ATTR->ATTR_Hardware->show_reg_addr;
i2c_reg_value = g_psensor_ATTR->ATTR_Hardware->proximity_show_reg(i2c_reg_addr);
return sprintf(buf, "%d\n", i2c_reg_value);
}
static ssize_t ATT_proximity_store_read_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_show_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x", &i2c_reg_addr);
g_psensor_ATTR->ATTR_Hardware->show_reg_addr=i2c_reg_addr;
return count;
}
static ssize_t ATT_proximity_store_write_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_store_reg== NULL) {
err("2nd IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x %d", &i2c_reg_addr, &i2c_reg_value);
log("2nd IRsensor_store_reg, addr=%02X, value=%02X\n", i2c_reg_addr, i2c_reg_value);
if(g_psensor_ATTR->ATTR_Hardware->proximity_store_reg(i2c_reg_addr, i2c_reg_value) < 0)
return -EINVAL;
return count;
}
/******************/
/*HAL Function*/
/*****************/
static void proximity_onoff(struct work_struct *work){
log("2nd Proximity switch %s\n", g_psensor_on_flag?"on":"off");
g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff(g_psensor_on_flag);
}
static ssize_t ATT_proximity_show_switch_onoff(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_HAL->proximity_show_switch_onoff== NULL) {
err("2nd proximity_show_switch_onoff NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_HAL->proximity_show_switch_onoff();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_switch_onoff(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff == NULL) {
err("2nd proximity_store_switch_onoff NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3)){
bOn = false;
g_psensor_on_flag = false;
}else if (0 == strncmp(buf, "on", 2)){
bOn = true;
g_psensor_on_flag = true;
}else{
return -EINVAL;
}
log("2nd Proximity workqueue to switch %s\n", bOn?"on":"off");
schedule_work(&proximity_onoff_work);
/*
log("2nd Proximity switch %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff(bOn) < 0)
return -EINVAL;
*/
return count;
}
static ssize_t ATT_proximity_show_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool proximity_status;
if(g_psensor_ATTR->ATTR_HAL->proximity_show_status== NULL) {
err("2nd proximity_show_status NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
proximity_status = g_psensor_ATTR->ATTR_HAL->proximity_show_status();
if(proximity_status)
return sprintf(buf, "close\n");
else
return sprintf(buf, "away\n");
}
/************************/
/*Extension Function*/
/***********************/
static ssize_t ATT_proximity_show_allreg(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool ret;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_allreg== NULL) {
err("2nd IRsensor_show_allreg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret=g_psensor_ATTR->ATTR_Extension->proximity_show_allreg(dev, attr, buf);
return sprintf(buf, "%d\n", ret);
}
static ssize_t ATT_proximity_show_polling_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_polling_mode == NULL) {
err("2nd proximity_show_polling_mode NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_Extension->proximity_show_polling_mode();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_polling_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_polling_mode== NULL) {
err("2nd proximity_store_polling_mode NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("2nd Proximity polling mode %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_Extension->proximity_store_polling_mode(bOn) < 0)
return -EINVAL;
return count;
}
/* +++ For stress test debug +++ */
static ssize_t ATT_proximity_show_int_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int p_int_counter=0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_int_count == NULL) {
err("2nd proximity_show_int_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
p_int_counter = g_psensor_ATTR->ATTR_Extension->proximity_show_int_count();
return sprintf(buf, "%d\n", p_int_counter);
}
static ssize_t ATT_proximity_show_event_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int p_event_counter=0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_event_count == NULL) {
err("2nd proximity_show_event_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
p_event_counter = g_psensor_ATTR->ATTR_Extension->proximity_show_event_count();
return sprintf(buf, "%d\n", p_event_counter);
}
static ssize_t ATT_proximity_show_error_mesg(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
char* error_mesg=kzalloc(sizeof(char [ERROR_MESG_SIZE]), GFP_KERNEL);
if(g_psensor_ATTR->ATTR_Extension->proximity_show_error_mesg== NULL) {
err("2nd IRsensor_show_error_mesg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret = g_psensor_ATTR->ATTR_Extension->proximity_show_error_mesg(error_mesg);
return sprintf(buf, "%s\n", error_mesg);
}
/* --- For stress test debug --- */
/*For auto calibration*/
static ssize_t ATT_proximity_show_autok(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autok == NULL) {
err("2nd proximity_show_autok NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_Extension->proximity_show_autok();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_autok(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autok== NULL) {
err("2nd proximity_store_autok NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("2nd Proximity autok %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autok(bOn) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_autokmin(struct device *dev,
struct device_attribute *attr, char *buf)
{
int autokmin = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autokmin== NULL) {
err("2nd proximity_show_autokmin NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
autokmin = g_psensor_ATTR->ATTR_Extension->proximity_show_autokmin();
return sprintf(buf, "%d\n", autokmin);
}
static ssize_t ATT_proximity_store_autokmin(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long autokmin;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmin== NULL) {
err("2nd proximity_store_autokmin NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &autokmin) < 0))
return -EINVAL;
if(autokmin < 0) {
err("2nd Proximity store autokmin with NEGATIVE value. (%lu) \n", autokmin);
return -EINVAL;
}
log("2nd Proximity store autokmin: %lu\n", autokmin);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmin(autokmin) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_autokmax(struct device *dev,
struct device_attribute *attr, char *buf)
{
int autokmax = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autokmax== NULL) {
err("2nd proximity_show_autokmax NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
autokmax = g_psensor_ATTR->ATTR_Extension->proximity_show_autokmax();
return sprintf(buf, "%d\n", autokmax);
}
static ssize_t ATT_proximity_store_autokmax(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long autokmax;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmax== NULL) {
err("2nd proximity_store_autokmax NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &autokmax) < 0))
return -EINVAL;
if(autokmax < 0) {
err("2nd Proximity store autokmax with NEGATIVE value. (%lu) \n", autokmax);
return -EINVAL;
}
log("2nd Proximity store autokmax: %lu\n", autokmax);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmax(autokmax) < 0)
return -EINVAL;
return count;
}
/*For transition period from 3/5 to 2/4*/
static ssize_t ATT_proximity_show_selection(struct device *dev,
struct device_attribute *attr, char *buf)
{
int selection = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_selection== NULL) {
err("2nd proximity_show_selection NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
selection = g_psensor_ATTR->ATTR_Extension->proximity_show_selection();
return sprintf(buf, "%d\n", selection);
}
static ssize_t ATT_proximity_store_selection(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long selection;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_selection== NULL) {
err("2nd proximity_store_selection NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &selection) < 0))
return -EINVAL;
if(selection < 0) {
err("2nd Proximity store selection with NEGATIVE value. (%lu) \n", selection);
return -EINVAL;
}
log("2nd Proximity store selection: %lu\n", selection);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_selection(selection) < 0)
return -EINVAL;
return count;
}
/*For power key turn on screen and enable touch*/
static ssize_t ATT_proximity_show_enable_touch(struct device *dev,
struct device_attribute *attr, char *buf)
{
int touch_enable = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_touch_enable== NULL) {
err("2nd proximity_show_touch_enable NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
touch_enable = g_psensor_ATTR->ATTR_Extension->proximity_show_touch_enable();
return sprintf(buf, "%d\n", touch_enable);
}
static ssize_t ATT_proximity_store_enable_touch(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long touch_enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable== NULL) {
err("2nd proximity_store_touch_enable NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &touch_enable) < 0))
return -EINVAL;
if(touch_enable == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable(true) < 0)
return -EINVAL;
}else if(touch_enable == 0){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable(false) < 0)
return -EINVAL;
}else {
err("2nd Proximity store touch enable with NEGATIVE value. (%lu) \n", touch_enable);
return -EINVAL;
}
log("2nd Proximity store touch_enable: %lu\n", touch_enable);
return count;
}
/*For load calibration data*/
static ssize_t ATT_proximity_store_load_calibration_data(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long load_calibration_data;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_load_calibration_data== NULL) {
err("2nd proximity_store_load_calibration_data NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &load_calibration_data) < 0))
return -EINVAL;
g_Psensor2_load_cal_status = (bool)load_calibration_data;
log("2nd Proximity store load_calibration_data: %lu\n", load_calibration_data);
if(load_calibration_data == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_load_calibration_data() < 0)
return -EINVAL;
}else {
err("2nd Proximity store load calibration data is not 1. (%lu) \n", load_calibration_data);
return -EINVAL;
}
return count;
}
/*For enable anti-oil workaround*/
static ssize_t ATT_proximity_show_anti_oil_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
int anti_oil_enable = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_anti_oil_enable== NULL) {
err("2nd proximity_show_anti_oil_enable NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
anti_oil_enable = g_psensor_ATTR->ATTR_Extension->proximity_show_anti_oil_enable();
return sprintf(buf, "%d\n", anti_oil_enable);
}
static ssize_t ATT_proximity_store_anti_oil_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long anti_oil_enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable== NULL) {
err("2nd proximity_store_anti_oil_enable NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &anti_oil_enable) < 0))
return -EINVAL;
if(anti_oil_enable == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable(true) < 0)
return -EINVAL;
}else if(anti_oil_enable == 0){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable(false) < 0)
return -EINVAL;
}else {
err("2nd Proximity store anti-oil enable with NEGATIVE value. (%lu) \n", anti_oil_enable);
return -EINVAL;
}
log("2nd Proximity store anti_oil_enable: %lu\n", anti_oil_enable);
return count;
}
static struct device_attribute proximity_property_attrs[] = {
/*read only*/
__ATTR(vendor, 0444, ATT_proximity_show_vendor, NULL),
__ATTR(module_number, 0444, ATT_proximity_show_module_number, NULL),
__ATTR(proxm, 0444, ATT_proximity_show_adc, NULL),
__ATTR(atd_status, 0444, ATT_proximity_show_atd_test, NULL),
__ATTR(proxm_status, 0444, ATT_proximity_show_status, NULL),
__ATTR(dump_reg, 0444, ATT_proximity_show_allreg, NULL),
/* +++ For stress test debug +++ */
__ATTR(int_counter, 0444, ATT_proximity_show_int_count, NULL),
__ATTR(event_counter, 0444, ATT_proximity_show_event_count, NULL),
__ATTR(error_mesg, 0444, ATT_proximity_show_error_mesg, NULL),
/* --- For stress test debug --- */
/*read/write*/
__ATTR(switch, 0664, ATT_proximity_show_switch_onoff, ATT_proximity_store_switch_onoff),
__ATTR(hi_cal, 0664, ATT_proximity_show_calibration_hi, ATT_proximity_store_calibration_hi),
__ATTR(low_cal, 0664, ATT_proximity_show_calibration_lo, ATT_proximity_store_calibration_lo),
__ATTR(inf_cal, 0664, ATT_proximity_show_calibration_inf, ATT_proximity_store_calibration_inf),
__ATTR(poll_mode, 0664, ATT_proximity_show_polling_mode, ATT_proximity_store_polling_mode),
__ATTR(read_reg, 0664, ATT_proximity_show_read_reg, ATT_proximity_store_read_reg),
__ATTR(write_reg, 0220, NULL, ATT_proximity_store_write_reg),
__ATTR(autok, 0664, ATT_proximity_show_autok, ATT_proximity_store_autok),
__ATTR(autokmin, 0664, ATT_proximity_show_autokmin, ATT_proximity_store_autokmin),
__ATTR(autokmax, 0664, ATT_proximity_show_autokmax, ATT_proximity_store_autokmax),
/*For transition period from 3/5 to 2/4*/
__ATTR(selection, 0664, ATT_proximity_show_selection, ATT_proximity_store_selection),
/*For power key turn on screen and enable touch*/
__ATTR(enable_touch, 0664, ATT_proximity_show_enable_touch, ATT_proximity_store_enable_touch),
/*For load calibration data*/
__ATTR(load_cal, 0220, NULL, ATT_proximity_store_load_calibration_data),
/*For power key turn on screen and enable touch*/
__ATTR(enable_anti_oil, 0664, ATT_proximity_show_anti_oil_enable, ATT_proximity_store_anti_oil_enable),
};
int psensor_ATTR_register_2nd(psensor_ATTR *mATTR)
{
int ret = 0;
int ATTR_index;
g_psensor_ATTR=mATTR;
/* psensor device */
g_psensor_dev = ASH_ATTR_device_create(psensor_2nd);
if (IS_ERR(g_psensor_dev) || g_psensor_dev == NULL) {
ret = PTR_ERR(g_psensor_dev);
err("%s: 2nd psensor create ERROR.\n", __FUNCTION__);
return ret;
}
for (ATTR_index=0; ATTR_index < ARRAY_SIZE(proximity_property_attrs); ATTR_index++) {
ret = device_create_file(g_psensor_dev, &proximity_property_attrs[ATTR_index]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(psensor_ATTR_register_2nd);
int psensor_ATTR_unregister_2nd(void)
{
ASH_ATTR_device_remove(psensor_2nd);
return 0;
}
EXPORT_SYMBOL(psensor_ATTR_unregister_2nd);
int psensor_ATTR_create_2nd(struct device_attribute *mpsensor_attr)
{
int ret = 0;
if(mpsensor_attr == NULL) {
err("%s: 2nd the device_attribute is NULL point. \n", __FUNCTION__);
return -EINVAL;
}
ret = device_create_file(g_psensor_dev, mpsensor_attr);
if (ret){
err("%s: 2nd device_create_file ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL(psensor_ATTR_create_2nd);

View File

@ -0,0 +1,966 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*********************************/
/* Proximity Sensor Atrribute */
/********************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/input/ASH.h>
#define RGB 1
#define BUF_SIZE (10)
static psensor_ATTR *g_psensor_ATTR = NULL;
static struct device *g_psensor_dev;
/*******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_ATTR"
#define SENSOR_TYPE_NAME "proximity"
#undef dbg
#ifdef ASH_ATTR_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static void proximity_onoff(struct work_struct *work);
static DECLARE_WORK(proximity_onoff_work, proximity_onoff);
static int g_psensor_on_flag = false;
bool g_Psensor_load_cal_status = false;
static ssize_t ATT_proximity_show_vendor(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_psensor_ATTR->info_type->vendor, "") == 0) {
err("Show vendor NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_psensor_ATTR->info_type->vendor);
}
static ssize_t ATT_proximity_show_module_number(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(strcmp(g_psensor_ATTR->info_type->module_number, "") == 0) {
err("Show module number NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
return sprintf(buf, "%s\n", g_psensor_ATTR->info_type->module_number);
}
/**************************/
/*Calibration Function*/
/************************/
static ssize_t ATT_proximity_show_calibration_hi(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_hi== NULL) {
err("proximity_show_calibration_hi NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_hi();
dbg("Proximity show High Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_hi(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_hi == NULL) {
err("proximity_store_calibration_hi NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Proximity store High Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Proximity store High Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_hi(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_calibration_lo(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_lo == NULL) {
err("proximity_show_calibration_lo NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_lo();
dbg("Proximity show Low Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_lo(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_lo == NULL) {
err("proximity_store_calibration_lo NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Proximity store Low Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Proximity store Low Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_lo(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_calibration_inf(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_inf == NULL) {
err("proximity_show_calibration_inf NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_inf();
dbg("Proximity show Inf Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_inf(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_inf == NULL) {
err("proximity_store_calibration_inf NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Proximity store Inf Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Proximity store Inf Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_inf(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_adc(struct device *dev, struct device_attribute *attr, char *buf)
{
int adc = 0;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_adc == NULL) {
err("proximity_show_adc NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
adc = g_psensor_ATTR->ATTR_Calibration->proximity_show_adc();
return sprintf(buf, "%d\n", adc);
}
/********************/
/*BMMI Function*/
/*******************/
static ssize_t ATT_proximity_show_atd_test(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool atd_test = false;
if(g_psensor_ATTR->ATTR_BMMI->proximity_show_atd_test== NULL) {
err("proximity_show_atd_test NOT SUPPORT. \n");
return sprintf(buf, "%d\n", atd_test);
}
atd_test = g_psensor_ATTR->ATTR_BMMI->proximity_show_atd_test();
return sprintf(buf, "%d\n", atd_test);
}
/************************/
/*Hardware Function*/
/***********************/
static ssize_t ATT_proximity_show_read_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_show_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
i2c_reg_addr = g_psensor_ATTR->ATTR_Hardware->show_reg_addr;
i2c_reg_value = g_psensor_ATTR->ATTR_Hardware->proximity_show_reg(i2c_reg_addr);
return sprintf(buf, "0x%x\n", i2c_reg_value);
}
static ssize_t ATT_proximity_store_read_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_show_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x", &i2c_reg_addr);
g_psensor_ATTR->ATTR_Hardware->show_reg_addr=i2c_reg_addr;
return count;
}
static ssize_t ATT_proximity_store_write_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int i2c_reg_addr = 0, i2c_reg_value = 0;
if(g_psensor_ATTR->ATTR_Hardware->proximity_store_reg== NULL) {
err("IRsensor_store_reg NOT SUPPORT. \n");
return count;
}
sscanf(buf, "%x %x", &i2c_reg_addr, &i2c_reg_value);
log("IRsensor_store_reg, addr=0x%02X, value=0x%02X\n", i2c_reg_addr, i2c_reg_value);
if(g_psensor_ATTR->ATTR_Hardware->proximity_store_reg(i2c_reg_addr, (int)i2c_reg_value) < 0)
return -EINVAL;
return count;
}
/******************/
/*HAL Function*/
/*****************/
static void proximity_onoff(struct work_struct *work){
log("Proximity switch %s\n", g_psensor_on_flag?"on":"off");
g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff(g_psensor_on_flag);
}
static ssize_t ATT_proximity_show_switch_onoff(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_HAL->proximity_show_switch_onoff== NULL) {
err("proximity_show_switch_onoff NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_HAL->proximity_show_switch_onoff();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_switch_onoff(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff == NULL) {
err("proximity_store_switch_onoff NOT SUPPORT. \n");
return count;
}
if (0 == strncmp(buf, "off", 3)){
bOn = false;
g_psensor_on_flag = false;
}else if (0 == strncmp(buf, "on", 2)){
bOn = true;
g_psensor_on_flag = true;
}else
return -EINVAL;
log("Proximity workqueue to switch %s\n", bOn?"on":"off");
schedule_work(&proximity_onoff_work);
/*check input character*/
/*
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("Proximity switch %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_HAL->proximity_store_switch_onoff(bOn) < 0)
return -EINVAL;
*/
return count;
}
static ssize_t ATT_proximity_show_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool proximity_status;
if(g_psensor_ATTR->ATTR_HAL->proximity_show_status== NULL) {
err("proximity_show_status NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
proximity_status = g_psensor_ATTR->ATTR_HAL->proximity_show_status();
if(proximity_status)
return sprintf(buf, "close\n");
else
return sprintf(buf, "away\n");
}
/************************/
/*Extension Function*/
/***********************/
static ssize_t ATT_proximity_show_allreg(struct device *dev,
struct device_attribute *attr, char *buf)
{
if(g_psensor_ATTR->ATTR_Extension->proximity_show_allreg== NULL) {
err("IRsensor_show_allreg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
log("print all reg");
return g_psensor_ATTR->ATTR_Extension->proximity_show_allreg(dev, attr, buf);
}
static ssize_t ATT_proximity_show_polling_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_polling_mode == NULL) {
err("proximity_show_polling_mode NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_Extension->proximity_show_polling_mode();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_polling_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_polling_mode== NULL) {
err("proximity_store_polling_mode NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("Proximity polling mode %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_Extension->proximity_store_polling_mode(bOn) < 0)
return -EINVAL;
return count;
}
/* +++ For stress test debug +++ */
static ssize_t ATT_proximity_show_int_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int p_int_counter=0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_int_count == NULL) {
err("proximity_show_int_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
p_int_counter = g_psensor_ATTR->ATTR_Extension->proximity_show_int_count();
return sprintf(buf, "%d\n", p_int_counter);
}
static ssize_t ATT_proximity_show_event_count(struct device *dev,
struct device_attribute *attr, char *buf)
{
int p_event_counter=0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_event_count == NULL) {
err("proximity_show_event_count NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
p_event_counter = g_psensor_ATTR->ATTR_Extension->proximity_show_event_count();
return sprintf(buf, "%d\n", p_event_counter);
}
static ssize_t ATT_proximity_show_error_mesg(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
char* error_mesg=kzalloc(sizeof(char [ERROR_MESG_SIZE]), GFP_KERNEL);
if(g_psensor_ATTR->ATTR_Extension->proximity_show_error_mesg== NULL) {
err("IRsensor_show_error_mesg NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
ret = g_psensor_ATTR->ATTR_Extension->proximity_show_error_mesg(error_mesg);
return sprintf(buf, "%s\n", error_mesg);
}
/* --- For stress test debug --- */
/*For auto calibration*/
static ssize_t ATT_proximity_show_autok(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autok == NULL) {
err("proximity_show_autok NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
bOn = g_psensor_ATTR->ATTR_Extension->proximity_show_autok();
if(bOn)
return sprintf(buf, "on\n");
else
return sprintf(buf, "off\n");
}
static ssize_t ATT_proximity_store_autok(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
bool bOn;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autok== NULL) {
err("proximity_store_autok NOT SUPPORT. \n");
return count;
}
/*check input character*/
if (0 == strncmp(buf, "off", 3))
bOn = false;
else if (0 == strncmp(buf, "on", 2))
bOn = true;
else
return -EINVAL;
log("Proximity autok %s\n", bOn?"on":"off");
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autok(bOn) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_autokmin(struct device *dev,
struct device_attribute *attr, char *buf)
{
int autokmin = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autokmin== NULL) {
err("proximity_show_autokmin NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
autokmin = g_psensor_ATTR->ATTR_Extension->proximity_show_autokmin();
return sprintf(buf, "%d\n", autokmin);
}
static ssize_t ATT_proximity_store_autokmin(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long autokmin;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmin== NULL) {
err("proximity_store_autokmin NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &autokmin) < 0))
return -EINVAL;
if(autokmin < 0) {
err("Proximity store autokmin with NEGATIVE value. (%lu) \n", autokmin);
return -EINVAL;
}
log("Proximity store autokmin: %lu\n", autokmin);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmin(autokmin) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_autokmax(struct device *dev,
struct device_attribute *attr, char *buf)
{
int autokmax = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_autokmax== NULL) {
err("proximity_show_autokmax NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
autokmax = g_psensor_ATTR->ATTR_Extension->proximity_show_autokmax();
return sprintf(buf, "%d\n", autokmax);
}
static ssize_t ATT_proximity_store_autokmax(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long autokmax;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmax== NULL) {
err("proximity_store_autokmax NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &autokmax) < 0))
return -EINVAL;
if(autokmax < 0) {
err("Proximity store autokmax with NEGATIVE value. (%lu) \n", autokmax);
return -EINVAL;
}
log("Proximity store autokmax: %lu\n", autokmax);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_autokmax(autokmax) < 0)
return -EINVAL;
return count;
}
/*For transition period from 3/5 to 2/4*/
static ssize_t ATT_proximity_show_selection(struct device *dev,
struct device_attribute *attr, char *buf)
{
int selection = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_selection== NULL) {
err("proximity_show_selection NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
selection = g_psensor_ATTR->ATTR_Extension->proximity_show_selection();
return sprintf(buf, "%d\n", selection);
}
static ssize_t ATT_proximity_store_selection(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long selection;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_selection== NULL) {
err("proximity_store_selection NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &selection) < 0))
return -EINVAL;
if(selection < 0) {
err("Proximity store selection with NEGATIVE value. (%lu) \n", selection);
return -EINVAL;
}
log("Proximity store selection: %lu\n", selection);
if(g_psensor_ATTR->ATTR_Extension->proximity_store_selection(selection) < 0)
return -EINVAL;
return count;
}
/*For power key turn on screen and enable touch*/
static ssize_t ATT_proximity_show_enable_touch(struct device *dev,
struct device_attribute *attr, char *buf)
{
int touch_enable = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_touch_enable== NULL) {
err("proximity_show_touch_enable NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
touch_enable = g_psensor_ATTR->ATTR_Extension->proximity_show_touch_enable();
return sprintf(buf, "%d\n", touch_enable);
}
static ssize_t ATT_proximity_store_enable_touch(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long touch_enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable== NULL) {
err("proximity_store_touch_enable NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &touch_enable) < 0))
return -EINVAL;
if(touch_enable == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable(true) < 0)
return -EINVAL;
}else if(touch_enable == 0){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_touch_enable(false) < 0)
return -EINVAL;
}else {
err("Proximity store touch enable with NEGATIVE value. (%lu) \n", touch_enable);
return -EINVAL;
}
log("Proximity store touch_enable: %lu\n", touch_enable);
return count;
}
/*For load calibration data*/
static ssize_t ATT_proximity_store_load_calibration_data(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long load_calibration_data;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_load_calibration_data== NULL) {
err("proximity_store_load_calibration_data NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &load_calibration_data) < 0))
return -EINVAL;
g_Psensor_load_cal_status = (bool)load_calibration_data;
log("Proximity store load_calibration_data: %lu\n", load_calibration_data);
if(load_calibration_data == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_load_calibration_data() < 0)
return -EINVAL;
}else {
err("Proximity store load calibration data is not 1. (%lu) \n", load_calibration_data);
return -EINVAL;
}
return count;
}
/*For enable anti-oil workaround*/
static ssize_t ATT_proximity_show_anti_oil_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
int anti_oil_enable = 0;
if(g_psensor_ATTR->ATTR_Extension->proximity_show_anti_oil_enable== NULL) {
err("proximity_show_anti_oil_enable NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
anti_oil_enable = g_psensor_ATTR->ATTR_Extension->proximity_show_anti_oil_enable();
return sprintf(buf, "%d\n", anti_oil_enable);
}
static ssize_t ATT_proximity_store_anti_oil_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long anti_oil_enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable== NULL) {
err("proximity_store_anti_oil_enable NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &anti_oil_enable) < 0))
return -EINVAL;
if(anti_oil_enable == 1){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable(true) < 0)
return -EINVAL;
}else if(anti_oil_enable == 0){
if(g_psensor_ATTR->ATTR_Extension->proximity_store_anti_oil_enable(false) < 0)
return -EINVAL;
}else {
err("Proximity store anti-oil enable with NEGATIVE value. (%lu) \n", anti_oil_enable);
return -EINVAL;
}
log("Proximity store anti_oil_enable: %lu\n", anti_oil_enable);
return count;
}
static ssize_t ATT_proximity_show_calibration_offset(struct device *dev,
struct device_attribute *attr, char *buf)
{
int calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_offset == NULL) {
err("proximity_show_calibration_offset NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
calvalue = g_psensor_ATTR->ATTR_Calibration->proximity_show_calibration_offset();
dbg("Proximity show Inf Calibration: %d\n", calvalue);
return sprintf(buf, "%d\n", calvalue);
}
static ssize_t ATT_proximity_store_calibration_offset(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long calvalue;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_offset == NULL) {
err("proximity_store_calibration_offset NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &calvalue) < 0))
return -EINVAL;
if(calvalue < 0) {
err("Proximity store Inf Calibration with NEGATIVE value. (%lu) \n", calvalue);
return -EINVAL;
}
log("Proximity store Inf Calibration: %lu\n", calvalue);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_calibration_offset(calvalue) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_oil_flag(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned long flag;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_oil_flag == NULL) {
err("proximity_show oil_flag NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
flag = g_psensor_ATTR->ATTR_Calibration->proximity_show_oil_flag();
dbg("Proximity show oil_flag: %d\n", flag);
return sprintf(buf, "%d\n", flag);
}
static ssize_t ATT_proximity_store_oil_flag(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long flag;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_oil_flag == NULL) {
err("proximity_store_oil_flag NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &flag) < 0))
return -EINVAL;
if(flag < 0) {
err("Proximity store oil_flag with NEGATIVE value. (%d) \n", flag);
return -EINVAL;
}
log("Proximity store oil_flag: %d\n", flag);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_oil_flag(flag) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_show_oil_timer(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned long time;
if(g_psensor_ATTR->ATTR_Calibration->proximity_show_oil_timer == NULL) {
err("proximity_show oil_timer NOT SUPPORT. \n");
return sprintf(buf, "NOT SUPPORT\n");
}
time = g_psensor_ATTR->ATTR_Calibration->proximity_show_oil_timer();
dbg("Proximity show oil_timer: %d\n", time);
return sprintf(buf, "%d\n", time);
}
static ssize_t ATT_proximity_store_oil_timer(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long time;
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_oil_timer == NULL) {
err("proximity_store_oil_timer NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &time) < 0))
return -EINVAL;
if(time < 0) {
err("Proximity store oil_timer with NEGATIVE value. (%d) \n", time);
return -EINVAL;
}
log("Proximity store oil_timer: %d\n", time);
if(g_psensor_ATTR->ATTR_Calibration->proximity_store_oil_timer(time) < 0)
return -EINVAL;
return count;
}
static ssize_t ATT_proximity_store_chip_cal_en(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_chip_cal_en== NULL) {
err("proximity_store_anti_oil_enable NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &enable) < 0))
return -EINVAL;
g_psensor_ATTR->ATTR_Extension->proximity_chip_cal_en(enable);
log("Proximity store chip cal flag: %lu\n", enable);
return count;
}
static ssize_t ATT_proximity_store_pocket_en(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long enable;
if(g_psensor_ATTR->ATTR_Extension->proximity_store_pocket_en== NULL) {
err("proximity_store_pocket_en NOT SUPPORT. \n");
return count;
}
if ((kstrtoul(buf, 10, &enable) < 0))
return -EINVAL;
g_psensor_ATTR->ATTR_Extension->proximity_store_pocket_en(enable);
log("Proximity store pocket flag: %lu\n", enable);
return count;
}
static struct device_attribute proximity_property_attrs[] = {
/*read only*/
__ATTR(vendor, 0444, ATT_proximity_show_vendor, NULL),
__ATTR(module_number, 0444, ATT_proximity_show_module_number, NULL),
__ATTR(proxm, 0444, ATT_proximity_show_adc, NULL),
__ATTR(atd_status, 0444, ATT_proximity_show_atd_test, NULL),
__ATTR(proxm_status, 0444, ATT_proximity_show_status, NULL),
__ATTR(dump_reg, 0444, ATT_proximity_show_allreg, NULL),
/* +++ For stress test debug +++ */
__ATTR(int_counter, 0444, ATT_proximity_show_int_count, NULL),
__ATTR(event_counter, 0444, ATT_proximity_show_event_count, NULL),
__ATTR(error_mesg, 0444, ATT_proximity_show_error_mesg, NULL),
/* --- For stress test debug --- */
/*read/write*/
__ATTR(switch, 0664, ATT_proximity_show_switch_onoff, ATT_proximity_store_switch_onoff),
__ATTR(hi_cal, 0664, ATT_proximity_show_calibration_hi, ATT_proximity_store_calibration_hi),
__ATTR(low_cal, 0664, ATT_proximity_show_calibration_lo, ATT_proximity_store_calibration_lo),
__ATTR(inf_cal, 0664, ATT_proximity_show_calibration_inf, ATT_proximity_store_calibration_inf),
__ATTR(poll_mode, 0664, ATT_proximity_show_polling_mode, ATT_proximity_store_polling_mode),
__ATTR(read_reg, 0664, ATT_proximity_show_read_reg, ATT_proximity_store_read_reg),
__ATTR(write_reg, 0220, NULL, ATT_proximity_store_write_reg),
__ATTR(autok, 0664, ATT_proximity_show_autok, ATT_proximity_store_autok),
__ATTR(autokmin, 0664, ATT_proximity_show_autokmin, ATT_proximity_store_autokmin),
__ATTR(autokmax, 0664, ATT_proximity_show_autokmax, ATT_proximity_store_autokmax),
/*For transition period from 3/5 to 2/4*/
__ATTR(selection, 0664, ATT_proximity_show_selection, ATT_proximity_store_selection),
/*For power key turn on screen and enable touch*/
__ATTR(enable_touch, 0664, ATT_proximity_show_enable_touch, ATT_proximity_store_enable_touch),
/*For load calibration data*/
__ATTR(load_cal, 0220, NULL, ATT_proximity_store_load_calibration_data),
/*For power key turn on screen and enable touch*/
__ATTR(enable_anti_oil, 0664, ATT_proximity_show_anti_oil_enable, ATT_proximity_store_anti_oil_enable),
/* tmd2755 autok results */
__ATTR(offset_cal, 0664, ATT_proximity_show_calibration_offset, ATT_proximity_store_calibration_offset),
/* For oil issue during phone call */
__ATTR(oil_flag, 0664, ATT_proximity_show_oil_flag, ATT_proximity_store_oil_flag),
/* set oil timer to do oil check during phone call */
__ATTR(oil_timer, 0664, ATT_proximity_show_oil_timer, ATT_proximity_store_oil_timer),
/* tmd2755 autok behavior on/off */
__ATTR(chip_cal_en, 0220, NULL, ATT_proximity_store_chip_cal_en),
__ATTR(pocket_en, 0664, NULL, ATT_proximity_store_pocket_en),
};
int psensor_ATTR_register(psensor_ATTR *mATTR)
{
int ret = 0;
int ATTR_index;
g_psensor_ATTR=mATTR;
/* psensor device */
g_psensor_dev = ASH_ATTR_device_create(psensor);
if (IS_ERR(g_psensor_dev) || g_psensor_dev == NULL) {
ret = PTR_ERR(g_psensor_dev);
err("%s: psensor create ERROR.\n", __FUNCTION__);
return ret;
}
for (ATTR_index=0; ATTR_index < ARRAY_SIZE(proximity_property_attrs); ATTR_index++) {
ret = device_create_file(g_psensor_dev, &proximity_property_attrs[ATTR_index]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(psensor_ATTR_register);
int psensor_ATTR_unregister(void)
{
ASH_ATTR_device_remove(psensor);
return 0;
}
EXPORT_SYMBOL(psensor_ATTR_unregister);
int psensor_ATTR_create(struct device_attribute *mpsensor_attr)
{
int ret = 0;
if(mpsensor_attr == NULL) {
err("%s: the device_attribute is NULL point. \n", __FUNCTION__);
return -EINVAL;
}
ret = device_create_file(g_psensor_dev, mpsensor_attr);
if (ret){
err("%s: device_create_file ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
return ret;
}
EXPORT_SYMBOL(psensor_ATTR_create);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __LINUX_IRSENSOR_H
#define __LINUX_IRSENSOR_H
/**
* @LIGHT_CALVALUE_200LUX_DEFAULT :
* @LIGHT_CALVALUE_1000LUX_DEFAULT : The default value of 200/1000 lux calibration,
* which are independent of platforms and hardware.
*/
#define LIGHT_CALVALUE_200LUX_DEFAULT (200)
#define LIGHT_CALVALUE_1000LUX_DEFAULT (1000)
/**
* LIGHT_CHANGE_SENSITIVITY - These define the sensitivity of light sensor.
* @LIGHT_CHANGE_LOW_SENSITIVITY : >= 1000 lux.
* @LIGHT_CHANGE_MID_SENSITIVITY : < 1000 lux, > 200 lux.
* @LIGHT_CHANGE_HI_SENSITIVITY : <= 200 lux.
* @LIGHT_CHANGE_FACTORY_SENSITIVITY : for factory build.
* @LIGHT_CHANGE_MIN_SENSITIVITY : for dynamic change sensitivity.
*/
#define LIGHT_CHANGE_LOW_SENSITIVITY (10)
#define LIGHT_CHANGE_MID_SENSITIVITY (5)
#define LIGHT_CHANGE_HI_SENSITIVITY (2)
#define LIGHT_CHANGE_FACTORY_SENSITIVITY (0)
/**
* @LIGHT_MAX_LUX : Report 0~20000 Lux.
*/
#define LIGHT_MAX_LUX (20000)
/**
* @LIGHT_TURNON_DELAY_TIME : After light sensor turn on 250ms,
* driver will cat first correct adc/lux value.
*/
#if defined ASUS_SAKE_PROJECT
#define LIGHT_CALDATA_TRANSFER_RATIO1 (17)
#define LIGHT_CALDATA_TRANSFER_RATIO2 (10)
#define PROXIMITY_POCKET_MODE_RATIO (30)
#define PROXIMITY_POCKET_MODE_OFFSET_RATIO (25)
#define PROXIMITY_ADC_PER_OFFSET (11)
#else
#define PROXIMITY_POCKET_MODE_RATIO (100)
#endif
#ifdef CONFIG_TMD2755_FLAG
/* AMS proximity autok will change adc value, since autok need time, wait for ams chip */
#define PROXIMITY_CALIBRATION_DELAY (150)
#define LIGHT_TURNON_DELAY_TIME (10)
#else
#define PROXIMITY_CALIBRATION_DELAY (0)
#define LIGHT_TURNON_DELAY_TIME (10)
#endif
#define PROXIMITY_OIL_ALGO_DEFAULT_FLAG (false)
#define PROXIMITY_TURNON_DELAY_TIME (11)
#define PROXIMITY_POLLING_TIME (1000)
#define LIGHT_POLLING_TIME (500)
/**
* LIGHT_LOG_THRESHOLD : We print light sensor log
* when the current lux value change over 100 lux from the last lux.
*/
#define LIGHT_LOG_THRESHOLD (100)
#define LIGHT_LOG_LOW_LUX_THRESHOLD (20)
/**
* @ALSPS_DEFAULT_VALUE : Define the default value for driver data.
*/
#define ALSPS_DEFAULT_VALUE (-1)
#ifdef ONE_PL_CHIP
#define PROXIMITY_INF_ER_DEFAULT (85)
#define PROXIMITY_THDL_ER_DEFAULT (134)
#define PROXIMITY_THDH_ER_DEFAULT (249)
#define PROXIMITY_POCKET_ER_DEFAULT (4073)
#ifdef CONFIG_TMD2755_FLAG
#define PROXIMITY_POCKET_DEFAULT (3800)
#else
#define PROXIMITY_POCKET_DEFAULT (4073)
#endif //CONFIG_TMD2755_FLAG
#define PROXIMITY_NOISE_PERIOD (11)
#define LIGHT_ER_CALIBRATION_DEFAULT (1526)
/* ASUS BSP +++ Clay: shift lux to mitigate psensor noise when psensor on and lux < offset */
#define LIGHT_LOW_LUX_NOISE_OFFSET (0)
/* ASUS BSP--- */
/* ASUS BSP+++ Clay: average 5 lux for offset behavior to mitigate the low lux gap */
#define LIGHT_LOW_LUX_AVG_COUNT (5)
/* ASUS BSP--- */
#else
#define PROXIMITY_INF_ER_DEFAULT (513)
#define PROXIMITY_THDL_ER_DEFAULT (607)
#define PROXIMITY_THDH_ER_DEFAULT (879)
#define PROXIMITY_POCKET_ER_DEFAULT (4094)
#define PROXIMITY_INF_ER2_DEFAULT (466)
#define PROXIMITY_THDL_ER2_DEFAULT (547)
#define PROXIMITY_THDH_ER2_DEFAULT (788)
#define PROXIMITY_POCKET_ER2_DEFAULT (4093)
#define PROXIMITY_POCKET_DEFAULT (4091)
#define PROXIMITY_NOISE_PERIOD (20)
#define LIGHT_ER_CALIBRATION_DEFAULT (4563)
#define LIGHT_ER2_CALIBRATION_DEFAULT (3372)
/* ASUS BSP Clay: shift lux to mitigate psensor noise when psensor on and lux < offset +++ */
#define LIGHT_LOW_LUX_NOISE_OFFSET (30)
/* ASUS BSP Clay: shift lux to mitigate psensor noise when psensor on and lux < offset --- */
/* ASUS BSP Clay: average 5 lux for offset behavior to mitigate the low lux gap +++ */
#define LIGHT_LOW_LUX_AVG_COUNT (5)
/* ASUS BSP Clay: average 5 lux for offset behavior to mitigate the low lux gap --- */
#endif
#define PROXIMITY_BASIC_PERIOD (11)
#define CS_IT_400MS (3)
#define CS_IT_100MS (1)
#define CS_IT_50MS (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __LINUX_IRSENSOR_H
#define __LINUX_IRSENSOR_H
/**
* @LIGHT_CALVALUE_200LUX_DEFAULT :
* @LIGHT_CALVALUE_1000LUX_DEFAULT : The default value of 200/1000 lux calibration,
* which are independent of platforms and hardware.
*/
#define LIGHT_CALVALUE_200LUX_DEFAULT (200)
#define LIGHT_CALVALUE_1000LUX_DEFAULT (1000)
/**
* LIGHT_CHANGE_SENSITIVITY - These define the sensitivity of light sensor.
* @LIGHT_CHANGE_LOW_SENSITIVITY : >= 1000 lux.
* @LIGHT_CHANGE_MID_SENSITIVITY : < 1000 lux, > 200 lux.
* @LIGHT_CHANGE_HI_SENSITIVITY : <= 200 lux.
* @LIGHT_CHANGE_FACTORY_SENSITIVITY : for factory build.
* @LIGHT_CHANGE_MIN_SENSITIVITY : for dynamic change sensitivity.
*/
#define LIGHT_CHANGE_LOW_SENSITIVITY (10)
#define LIGHT_CHANGE_MID_SENSITIVITY (5)
#define LIGHT_CHANGE_HI_SENSITIVITY (2)
#define LIGHT_CHANGE_FACTORY_SENSITIVITY (0)
/**
* @LIGHT_MAX_LUX : Report 0~20000 Lux.
*/
#define LIGHT_MAX_LUX (20000)
/**
* @LIGHT_TURNON_DELAY_TIME : After light sensor turn on 250ms,
* driver will cat first correct adc/lux value.
*/
#define LIGHT_TURNON_DELAY_TIME (10)
#define PROXIMITY_TURNON_DELAY_TIME (50)
#define PROXIMITY_POLLING_TIME (1000)
#define LIGHT_POLLING_TIME (500)
/**
* LIGHT_LOG_THRESHOLD : We print light sensor log
* when the current lux value change over 100 lux from the last lux.
*/
#define LIGHT_LOG_THRESHOLD (100)
/**
* @ALSPS_DEFAULT_VALUE : Define the default value for driver data.
*/
#define ALSPS_DEFAULT_VALUE (-1)
#define PROXIMITY_INF_ER_DEFAULT (283)
#define PROXIMITY_THDL_ER_DEFAULT (534)
#define PROXIMITY_THDH_ER_DEFAULT (1237)
#define PROXIMITY_POCKET_ER_DEFAULT (4095)
#define PROXIMITY_INF_ER2_DEFAULT (358)
#define PROXIMITY_THDL_ER2_DEFAULT (582)
#define PROXIMITY_THDH_ER2_DEFAULT (1289)
#define PROXIMITY_POCKET_ER2_DEFAULT (4095)
#define PROXIMITY_POCKET_DEFAULT (4095)
#endif

View File

@ -0,0 +1,67 @@
/* include/linux/wakelock.h
*
* Copyright (C) 2007-2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_WAKELOCK_H
#define _LINUX_WAKELOCK_H
#include <linux/ktime.h>
#include <linux/device.h>
/* A wake_lock prevents the system from entering suspend or other low power
* states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
* prevents a full system suspend.
*/
enum {
WAKE_LOCK_SUSPEND, /* Prevent suspend */
WAKE_LOCK_TYPE_COUNT
};
struct wake_lock {
struct wakeup_source *ws;
};
static inline void wake_lock_init(struct wake_lock *lock, struct device *dev,
const char *name)
{
lock->ws = wakeup_source_register(dev, name);
}
static inline void wake_lock_destroy(struct wake_lock *lock)
{
wakeup_source_unregister(lock->ws);
}
static inline void wake_lock(struct wake_lock *lock)
{
__pm_stay_awake(lock->ws);
}
static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
{
__pm_wakeup_event(lock->ws, jiffies_to_msecs(timeout));
}
static inline void wake_unlock(struct wake_lock *lock)
{
__pm_relax(lock->ws);
}
static inline int wake_lock_active(struct wake_lock *lock)
{
return lock->ws->active;
}
#endif

View File

@ -0,0 +1,767 @@
/*
* Copyright (C) 2019 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/input.h>
//#include <linux/wakelock.h>
#include "ASH_Wakelock.h"
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_ALGO"
#define SENSOR_TYPE_NAME "SAR"
#undef dbg
#ifdef ASH_ALGO_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#define err(fmt, args...) do{ \
printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args); \
sprintf(g_error_mesg, "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args); \
}while(0)
/******************************/
/* SAR Sensor Global Variables */
/*****************************/
static int ASUS_SAR_SENSOR_IRQ;
//static int ASUS_SAR_SENSOR_INT_STATUS;
static struct ASUS_sar_sensor_data *g_sar_sensor_data;
static struct SAR_sensor_hw *sar_sensor_hw_client;
static struct workqueue_struct *SAR_sensor_workqueue;
static struct mutex g_sar_sensor_lock;
static struct wake_lock g_sar_sensor_wake_lock;
static struct i2c_client *g_i2c_client;
static char *g_error_mesg;
/***********************/
/* SAR Sensor Functions*/
/**********************/
/*Device Layer Part*/
static int SAR_sensor_turn_onoff(bool bOn);
/*Interrupt Service Routine Part*/
static void SAR_sensor_ist(struct work_struct *work);
/*Initialization Part*/
static int init_data(void);
/*Work Queue*/
static DECLARE_WORK(SAR_sensor_ist_work, SAR_sensor_ist);
/********************/
/* SAR sensor data structure */
/********************/
struct ASUS_sar_sensor_data
{
bool Device_switch_on; /* this var. means is turning on sensor or not */
int Device_Interrupt_detect_status; /* this var. means is for member detect status */
bool Device_detected_status[4]; /* this var. means is for which channels have detected near */
bool HAL_switch_on; /* this var. means if HAL is turning on sar or not */
};
/**********************************/
/* SAR sensor Info Type*/
/*********************************/
static SAR_sensor_info_type mSAR_sensor_info_type = {{0}};
/*=======================
*|| I2c Stress Test Part ||
*=======================
*/
/*====================
*|| Device Layer Part ||
*====================
*/
static int SAR_sensor_turn_onoff(bool bOn)
{
int ret=0;
/* Check Hardware Support First */
if(sar_sensor_hw_client->SAR_sensor_hw_turn_onoff == NULL) {
err("SAR_sensor_hw_turn_onoff NOT SUPPORT.\n");
return -ENOENT;
}
if (bOn == 1) { /* power on */
if(g_sar_sensor_data->Device_switch_on == false){
/* Power On */
ret = sar_sensor_hw_client->SAR_sensor_hw_turn_onoff(true);
if (ret < 0) {
err("SAR sensor turn on ERROR\n");
} else {
g_sar_sensor_data->Device_switch_on = bOn;
/* Enable IRQ */
log("[IRQ] Enable irq !!\n");
enable_irq(ASUS_SAR_SENSOR_IRQ);
/*change the Device Status*/
g_sar_sensor_data->Device_switch_on = true;
}
}
} else { /* power off */
if(g_sar_sensor_data->Device_switch_on == true){
/*disable IRQ before switch off*/
log("[IRQ] Disable irq !!\n");
disable_irq_nosync(ASUS_SAR_SENSOR_IRQ);
/*Power OFF*/
ret = sar_sensor_hw_client->SAR_sensor_hw_turn_onoff(false);
if (ret < 0) {
err("SAR sensor turn off ERROR\n");
}
g_sar_sensor_data->Device_switch_on = false;
/* reset global variable */
g_sar_sensor_data->Device_Interrupt_detect_status = -EBUSY;
g_sar_sensor_data->Device_detected_status[0] = false;
g_sar_sensor_data->Device_detected_status[1] = false;
g_sar_sensor_data->Device_detected_status[2] = false;
g_sar_sensor_data->Device_detected_status[3] = false;
}
}
return 0;
}
/*******************/
/*BMMI Function*/
/*******************/
bool mSAR_sensor_show_atd_test(void)
{
int ret = 0;
int round = 0;
mutex_lock(&g_sar_sensor_lock);
/* Check SAR sensor HW ID */
ret = sar_sensor_hw_client->SAR_sensor_hw_check_ID();
if (ret < 0) {
err("SAR sensor ATD test check ID ERROR\n");
goto SAR_sensor_atd_test_fail;
}
if(g_sar_sensor_data->Device_switch_on == false) {
/* Trun on SAR sensor */
ret = sar_sensor_hw_client->SAR_sensor_hw_turn_onoff(true);
if (ret < 0) {
err("SAR sensor ATD test turn on ERROR\n");
goto SAR_sensor_atd_test_fail;
}
}
/* Read SAR sensor raw data 4 time */
for(round = 0; round < 4; round++) {
ret = sar_sensor_hw_client->SAR_sensor_hw__get_proxuserful(round);
if (ret < 0) {
err("SAR sensor ATD test get raw data ERROR\n");
goto SAR_sensor_atd_test_fail;
}
msleep(100);
}
if(g_sar_sensor_data->HAL_switch_on == false) {
/* Trun off SAR sensor */
ret = sar_sensor_hw_client->SAR_sensor_hw_turn_onoff(false);
if(ret < 0) {
err("SAR sensor ATD test turn off ERROR\n");
goto SAR_sensor_atd_test_fail;
}
}
mutex_unlock(&g_sar_sensor_lock);
return true;
SAR_sensor_atd_test_fail:
return false;
}
int mSAR_sensor_show_raw_data(void)
{
int ret = 0;
if(sar_sensor_hw_client->SAR_sensor_hw_read_rawData == NULL) {
err("SAR_sensor_hw_read_rawData NOT SUPPORT.\n");
return -EINVAL;
}
mutex_lock(&g_sar_sensor_lock);
if(g_sar_sensor_data->Device_switch_on == false) {
SAR_sensor_turn_onoff(true);
}
/* Read SAR sensor raw data */
ret = sar_sensor_hw_client->SAR_sensor_hw_read_rawData();
if (ret < 0)
err("SAR sensor get raw data ERROR\n");
if(g_sar_sensor_data->HAL_switch_on == false) {
SAR_sensor_turn_onoff(false);
}
mutex_unlock(&g_sar_sensor_lock);
return ret;
}
/*****************************/
/* AP Interface Function*/
/*****************************/
bool mSAR_sensor_show_switch_onoff(void)
{
return g_sar_sensor_data->Device_switch_on;
}
int mSAR_sensor_store_switch_onoff(bool bOn)
{
mutex_lock(&g_sar_sensor_lock);
log("SAR switch = %d.\n", bOn);
if((g_sar_sensor_data->Device_switch_on != bOn)) {
if (bOn) {
/* Turn on SAR */
g_sar_sensor_data->HAL_switch_on = true;
SAR_sensor_turn_onoff(true);
} else {
/* Turn off SAR */
g_sar_sensor_data->HAL_switch_on = false;
SAR_sensor_turn_onoff(false);
}
} else {
log("SAR Sensor is already %s\n", bOn?"ON":"OFF");
}
mutex_unlock(&g_sar_sensor_lock);
return 0;
}
int mSAR_sensor_show_Interrupt_detect_status(void)
{
return g_sar_sensor_data->Device_Interrupt_detect_status;
}
/*************************/
/*Hardware Function*/
/*************************/
int mSAR_sensor_show_reg(uint8_t addr)
{
int value;
if (sar_sensor_hw_client->SAR_sensor_hw_get_register == NULL) {
err("SAR_sensor_hw_get_register NOT SUPPORT.\n");
return -EINVAL;
}
value = sar_sensor_hw_client->SAR_sensor_hw_get_register(addr);
log("mSAR_sensor_show_reg, addr=0X%02x, value=0x%x.\n", addr, value);
return value;
}
int mSAR_sensor_store_reg(uint8_t addr, int value)
{
if (sar_sensor_hw_client->SAR_sensor_hw_set_register == NULL) {
err("SAR_sensor_hw_set_register NOT SUPPORT.\n");
return -EINVAL;
}
sar_sensor_hw_client->SAR_sensor_hw_set_register(addr, value);
log("mSAR_sensor_store_reg, addr=0x%02x, value=0x%x.\n", addr, value);
return 0;
}
int mSAR_sensor_show_manual_offset_calibration(void)
{
int value;
if (sar_sensor_hw_client->SAR_sensor_hw_get_manual_offset_cal == NULL) {
err("SAR_sensor_hw_get_manual_offset_calibration NOT SUPPORT. \n");
return -EINVAL;
}
value = sar_sensor_hw_client->SAR_sensor_hw_get_manual_offset_cal();
log("SAR_sensor_hw_get_manual_offset_cal, value=0x%x.\n", value);
return value;
}
int mSAR_sensor_store_manual_offset_calibration(int value)
{
int ret = 0;
if (sar_sensor_hw_client->SAR_sensor_hw_manual_offset_cal == NULL) {
err("SAR_sensor_hw_manual_offset_calibration NOT SUPPORT. \n");
return -EINVAL;
}
ret = sar_sensor_hw_client->SAR_sensor_hw_manual_offset_cal(value);
log("SAR_sensor_hw_manual_offset_cal, value=%d.(ret=%d)\n", value, ret);
return ret;
}
/*=======================
*|| For Sar check status ||
*========================
*/
bool mSAR_sensor_show_sar_status(void)
{
int ret = 0;
int i = 0;
bool status = false;
mutex_unlock(&g_sar_sensor_lock);
if(g_sar_sensor_data->Device_switch_on == false) {
/* Trun on SAR sensor */
ret = SAR_sensor_turn_onoff(true);
if (ret < 0) {
err("SAR sensor status turn on ERROR\n");
goto SAR_sensor_status_fail;
}
} else {
log("Sar has been opened, Sar_check_status : %s",
g_sar_sensor_data->Device_Interrupt_detect_status?"Close":"Away");
status = (g_sar_sensor_data->Device_Interrupt_detect_status?true:false);
goto SAR_sensor_status_fail;
}
/* Check SAR sensor status */
for(i = 0; i < 5; i++){
if(g_sar_sensor_data->Device_Interrupt_detect_status == OBJECT_NEAR ||
g_sar_sensor_data->Device_Interrupt_detect_status == OBJECT_FAR){
log("Sar_check_status : %s",
g_sar_sensor_data->Device_Interrupt_detect_status?"Close":"Away");
status = g_sar_sensor_data->Device_Interrupt_detect_status;
break;
}
msleep(100);
}
if(g_sar_sensor_data->HAL_switch_on == false) {
/* Trun off SAR sensor */
ret = SAR_sensor_turn_onoff(false);
if(ret < 0) {
err("SAR sensor status turn off ERROR\n");
goto SAR_sensor_status_fail;
}
}
SAR_sensor_status_fail:
mutex_unlock(&g_sar_sensor_lock);
return status;
}
/**************************/
/* Extension Function */
/**************************/
bool mSAR_sensor_show_allreg(void)
{
if(sar_sensor_hw_client->SAR_sensor_hw_show_allreg == NULL) {
err("SAR_sensor_hw_show_allreg NOT SUPPORT.\n");
return false;
}
sar_sensor_hw_client->SAR_sensor_hw_show_allreg();
return true;
}
/****************** ATTR Structure ****************/
static SAR_sensor_ATTR_BMMI mSAR_sensor_ATTR_BMMI = {
.SAR_sensor_show_atd_test = mSAR_sensor_show_atd_test,
.SAR_sensor_show_raw_data = mSAR_sensor_show_raw_data,
};
static SAR_sensor_ATTR_HAL mSAR_sensor_ATTR_HAL = {
.SAR_sensor_show_switch_onoff = mSAR_sensor_show_switch_onoff,
.SAR_sensor_store_switch_onoff = mSAR_sensor_store_switch_onoff,
.SAR_sensor_show_Interrupt_detect_status = mSAR_sensor_show_Interrupt_detect_status,
.SAR_sensor_show_sar_status = mSAR_sensor_show_sar_status,
};
static SAR_sensor_ATTR_Hardware mSAR_sensor_ATTR_Hardware = {
.SAR_show_reg = mSAR_sensor_show_reg,
.SAR_store_reg = mSAR_sensor_store_reg,
.SAR_sensor_show_manual_offset_cal = mSAR_sensor_show_manual_offset_calibration,
.SAR_sensor_store_manual_offset_cal = mSAR_sensor_store_manual_offset_calibration,
};
static SAR_sensor_ATTR_Extension mSAR_sensor_ATTR_Extension = {
.SAR_sensor_show_allreg = mSAR_sensor_show_allreg,
};
static SAR_sensor_ATTR mSAR_sensor_ATTR = {
.info_type = &mSAR_sensor_info_type,
.ATTR_BMMI = &mSAR_sensor_ATTR_BMMI,
.ATTR_HAL = &mSAR_sensor_ATTR_HAL,
.ATTR_Hardware = &mSAR_sensor_ATTR_Hardware,
.ATTR_Extension = &mSAR_sensor_ATTR_Extension,
};
/*==========================
*|| Interrupt Service Routine Part ||
*===========================
*/
static void SAR_get_detected_cs(int irq_status, int sensor_status)
{
if(irq_status == OBJECT_NEAR){
if((sensor_status & PROXSTAT0) == PROXSTAT0 &&
g_sar_sensor_data->Device_detected_status[0] == false) {
log("SAR sensor CS0 is detected.\n");
g_sar_sensor_data->Device_detected_status[0] = true;
}
if((sensor_status & PROXSTAT1) == PROXSTAT1 &&
g_sar_sensor_data->Device_detected_status[1] == false) {
log("SAR sensor CS1 is detected.\n");
g_sar_sensor_data->Device_detected_status[1] = true;
}
if((sensor_status & PROXSTAT2) == PROXSTAT2 &&
g_sar_sensor_data->Device_detected_status[2] == false) {
log("SAR sensor CS2 is detected.\n");
g_sar_sensor_data->Device_detected_status[2] = true;
}
if((sensor_status & PROXSTAT3) == PROXSTAT3 &&
g_sar_sensor_data->Device_detected_status[3] == false) {
log("SAR sensor CS3 is detected.\n");
g_sar_sensor_data->Device_detected_status[3] = true;
}
} else if(irq_status == OBJECT_FAR){
if((sensor_status & PROXSTAT0) == 0x00 &&
g_sar_sensor_data->Device_detected_status[0] == true) {
log("SAR sensor CS0 is detected.\n");
g_sar_sensor_data->Device_detected_status[0] = false;
}
if((sensor_status & PROXSTAT1) == 0x00 &&
g_sar_sensor_data->Device_detected_status[1] == true) {
log("SAR sensor CS1 is detected.\n");
g_sar_sensor_data->Device_detected_status[1] = false;
}
if((sensor_status & PROXSTAT2) == 0x00 &&
g_sar_sensor_data->Device_detected_status[2] == true) {
log("SAR sensor CS2 is detected.\n");
g_sar_sensor_data->Device_detected_status[2] = false;
}
if((sensor_status & PROXSTAT3) == 0x00 &&
g_sar_sensor_data->Device_detected_status[3] == true) {
log("SAR sensor CS3 is detected.\n");
g_sar_sensor_data->Device_detected_status[3] = false;
}
}
}
static int SAR_sensor_work(void)
{
int sensor_status = 0, irq_status = 0;
sensor_status = sar_sensor_hw_client->SAR_sensor_hw_get_interrupt();
if (sensor_status < 0) {
err("sensor_status ERROR(err:%d)\n", sensor_status);
return sensor_status;
}
/* Clean interrupt */
irq_status = sar_sensor_hw_client->SAR_sensor_hw_read_regStat();
if (irq_status < 0) {
err("irq_status ERROR(err:%d)\n", irq_status);
return irq_status;
}
dbg("sensor status:0x%x, irq status:0x%x\n", sensor_status, irq_status);
if(irq_status == OBJECT_NEAR) {
if(g_sar_sensor_data->Device_Interrupt_detect_status != OBJECT_NEAR){
SAR_sensor_report_abs(SAR_SENSOR_REPORT_CLOSE);
log("SAR sensor Detect object Near.\n");
g_sar_sensor_data->Device_Interrupt_detect_status = OBJECT_NEAR;
}
} else if(irq_status == OBJECT_FAR) {
if(g_sar_sensor_data->Device_Interrupt_detect_status != OBJECT_FAR) {
SAR_sensor_report_abs(SAR_SENSOR_REPORT_AWAY);
log("SAR sensor Detect object Far.\n");
g_sar_sensor_data->Device_Interrupt_detect_status = OBJECT_FAR;
}
} else {
err("Unknown irq status(0x%02x)\n", irq_status);
}
SAR_get_detected_cs(irq_status, sensor_status);
return 0;
}
static void SAR_sensor_ist(struct work_struct *work)
{
mutex_lock(&g_sar_sensor_lock);
if (g_sar_sensor_data->Device_switch_on == false) {
err("SAR sensor are disabled and ignore IST.\n");
goto ist_err;
}
dbg("SAR sensor ist +++\n");
if (sar_sensor_hw_client == NULL) {
dbg("sar_sensor_hw_client is NULL\n");
goto ist_err;
}
/**************************************************/
/* Check IRQ Status and refresh status */
/* Read INT_FLAG will clean the interrupt */
/**************************************************/
SAR_sensor_work();
dbg("SAR sensor ist ---\n");
ist_err:
wake_unlock(&g_sar_sensor_wake_lock);
if (g_sar_sensor_data->Device_switch_on == true ) {
dbg("[IRQ] Enable irq !!\n");
enable_irq(ASUS_SAR_SENSOR_IRQ);
}
mutex_unlock(&g_sar_sensor_lock);
}
void SAR_sensor_irq_handler(void)
{
dbg("[IRQ] Disable irq !!\n");
disable_irq_nosync(ASUS_SAR_SENSOR_IRQ);
if(sar_sensor_hw_client->SAR_sensor_hw_get_interrupt == NULL) {
err("SAR_sensor_hw_get_interrupt NOT SUPPORT.\n");
goto irq_err;
}
/*Queue work will enbale IRQ and unlock wake_lock*/
queue_work(SAR_sensor_workqueue, &SAR_sensor_ist_work);
wake_lock(&g_sar_sensor_wake_lock);
return;
irq_err:
dbg("[IRQ] Enable irq !!\n");
enable_irq(ASUS_SAR_SENSOR_IRQ);
}
static SAR_sensor_GPIO mSAR_sensor_GPIO = {
.SAR_sensor_isr = SAR_sensor_irq_handler,
};
/*====================
*|| Initialization Part ||
*====================
*/
static int init_data(void)
{
int ret = 0;
log("sar sensor init_data");
/* Reset ASUS_SAR_sensor_data */
g_sar_sensor_data = kmalloc(sizeof(struct ASUS_sar_sensor_data), GFP_KERNEL);
if (!g_sar_sensor_data) {
err("g_sar_sensor_data kmalloc ERROR\n");
ret = -ENOMEM;
goto init_data_err;
}
memset(g_sar_sensor_data, 0, sizeof(struct ASUS_sar_sensor_data));
g_sar_sensor_data->Device_switch_on = false;
g_sar_sensor_data->HAL_switch_on = false;
g_sar_sensor_data->Device_Interrupt_detect_status = -EBUSY;
g_sar_sensor_data->Device_detected_status[0] = false;
g_sar_sensor_data->Device_detected_status[1] = false;
g_sar_sensor_data->Device_detected_status[2] = false;
g_sar_sensor_data->Device_detected_status[3] = false;
return 0;
init_data_err:
err("Init Data ERROR\n");
return ret;
}
void mSAR_sensor_algo_probe(struct i2c_client *client)
{
log("Driver PROBE +++\n");
/*check i2c client*/
if (client == NULL) {
err("i2c Client is NUll\n");
goto probe_err;
}
/*link driver data to i2c client*/
strlcpy(client->name, SENSOR_TYPE_NAME, I2C_NAME_SIZE);
i2c_set_clientdata(client, g_sar_sensor_data);
/* i2c client */
g_i2c_client = client;
if (ASUS_SAR_SENSOR_IRQ < 0)
goto probe_err;
log("Driver PROBE ---\n");
return ;
probe_err:
err("Driver PROBE ERROR ---\n");
return;
}
void SAR_sensor_algo_remove(void)
{
log("Driver REMOVE +++\n");
SAR_sensor_gpio_unregister(ASUS_SAR_SENSOR_IRQ);
log("Driver REMOVE ---\n");
return;
}
void mSAR_sensor_algo_shutdown(void)
{
log("Driver SHUTDOWN +++\n");
/* Disable sensor */
if (g_sar_sensor_data->Device_switch_on == true) {
log("turn off sar sensor");
SAR_sensor_turn_onoff(false);
}
log("Driver SHUTDOWN ---\n");
return;
}
void mSAR_sensor_algo_suspend(void)
{
log("Driver SUSPEND +++\n");
/* Disable SAR sensor IRQ */
log("[IRQ] Disable irq !!\n");
disable_irq_nosync(ASUS_SAR_SENSOR_IRQ);
log("Driver SUSPEND ---\n");
return;
}
void mSAR_sensor_algo_resume(void)
{
log("Driver RESUME +++\n");
/* Enable SAR sensor IRQ */
log("[IRQ] Enable irq !!\n");
enable_irq(ASUS_SAR_SENSOR_IRQ);
log("Driver RESUME ---\n");
return;
}
static SAR_sensor_I2C mSAR_sensor_I2C = {
.SAR_sensor_probe = mSAR_sensor_algo_probe,
.SAR_sensor_remove = SAR_sensor_algo_remove,
.SAR_sensor_shutdown = mSAR_sensor_algo_shutdown,
.SAR_sensor_suspend = mSAR_sensor_algo_suspend,
.SAR_sensor_resume = mSAR_sensor_algo_resume,
};
static int __init SAR_sensor_init(void)
{
int ret = 0;
log("Driver INIT +++\n");
/*Record the error message*/
g_error_mesg = kzalloc(sizeof(char [ERROR_MESG_SIZE]), GFP_KERNEL);
/* Work Queue */
SAR_sensor_workqueue = create_singlethread_workqueue(SENSOR_TYPE_NAME"_wq");
/* Initialize the Mutex */
mutex_init(&g_sar_sensor_lock);
/* Initialize the wake lock */
wake_lock_init(&g_sar_sensor_wake_lock, WAKE_LOCK_SUSPEND, "SAR_sensor_wake_lock");
/* i2c Registration for probe/suspend/resume */
ret = SAR_sensor_i2c_register(&mSAR_sensor_I2C);
if (ret < 0)
goto init_err;
/* Hardware Register Initialization */
sar_sensor_hw_client = SAR_sensor_hw_getHardware();
if(sar_sensor_hw_client == NULL)
goto init_err;
/* driver data structure initialize */
ret = init_data();
if (ret < 0)
goto init_err;
/* string copy the character of vendor and module number */
strcpy(mSAR_sensor_ATTR.info_type->vendor, sar_sensor_hw_client->vendor);
strcpy(mSAR_sensor_ATTR.info_type->module_number, sar_sensor_hw_client->module_number);
/* Attribute */
ret = SAR_sensor_ATTR_register(&mSAR_sensor_ATTR);
if (ret < 0)
goto init_err;
/* Input Device */
ret = SAR_sensor_report_register();
if (ret < 0)
goto init_err;
ASUS_SAR_SENSOR_IRQ = SAR_sensor_gpio_register(g_i2c_client, &mSAR_sensor_GPIO);
if (ASUS_SAR_SENSOR_IRQ < 0)
goto init_err;
log("Driver INIT ---\n");
return 0;
init_err:
err("Driver INIT ERROR ---\n");
return ret;
}
static void __exit SAR_sensor_exit(void)
{
log("Driver EXIT +++\n");
/* i2c Unregistration */
SAR_sensor_i2c_unregister();
/*Report Unregistration*/
SAR_sensor_report_unregister();
/*ATTR Unregistration*/
SAR_sensor_ATTR_unregister();
wake_lock_destroy(&g_sar_sensor_wake_lock);
mutex_destroy(&g_sar_sensor_lock);
kfree(g_sar_sensor_data);
destroy_workqueue(SAR_sensor_workqueue);
log("Driver EXIT ---\n");
}
module_init(SAR_sensor_init);
module_exit(SAR_sensor_exit);
MODULE_AUTHOR("Show_Cai <show_cai@asus.com>");
MODULE_DESCRIPTION("SAR sensor");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,484 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/************************************/
/* Light Sensor Factory Module */
/***********************************/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_Factory"
#define SENSOR_TYPE_NAME "light"
#undef dbg
#ifdef ASH_FACTORY_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/*******************************************/
/* Light Sensor read/write Calibration*/
/******************************************/
int lsensor_factory_read_200lux(const char *str)
{
struct file *fp = NULL;
loff_t pos_lsts = 0;
char buf[16];
int cal_val = 0, readlen = 0;
mm_segment_t old_fs;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor read 200lux Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 16, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Light Sensor read 200lux Calibration f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Light Sensor read 200lux Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Light Sensor read 200lux Calibration: Cal: %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(lsensor_factory_read_200lux);
bool lsensor_factory_write_200lux(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor write 200lux Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Light Sensor write 200lux Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Light Sensor write 200lux Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(lsensor_factory_write_200lux);
int lsensor_factory_read_1000lux(const char *str)
{
struct file *fp = NULL;
loff_t pos_lsts = 0;
char buf[16];
int cal_val = 0, readlen = 0;
mm_segment_t old_fs;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor read 1000lux Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 16, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Light Sensor read 1000lux Calibration f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Light Sensor read 1000lux Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Light Sensor read 1000lux Calibration: Cal: %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(lsensor_factory_read_1000lux);
bool lsensor_factory_write_1000lux(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor write 1000lux Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Light Sensor write 1000lux Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Light Sensor write 1000lux Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(lsensor_factory_write_1000lux);
int lsensor_factory_read(const char *str)
{
struct file *fp = NULL;
loff_t pos_lsts = 0;
char buf[16];
int cal_val = 0, readlen = 0;
mm_segment_t old_fs;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor read Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 16, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Light Sensor read Calibration f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Light Sensor read Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Light Sensor read Calibration: Cal: %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(lsensor_factory_read);
bool lsensor_factory_write(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor write Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Light Sensor write Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Light Sensor write Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(lsensor_factory_write);
/*For transition period from 100ms to 50ms +++*/
int lsensor_factory_read_50ms(const char *str)
{
struct file *fp = NULL;
loff_t pos_lsts = 0;
char buf[16];
int cal_val = 0, readlen = 0;
mm_segment_t old_fs;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor read 50MS Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 16, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Light Sensor read 50MS Calibration f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Light Sensor read 50MS Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Light Sensor read 50MS Calibration: Cal: %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(lsensor_factory_read_50ms);
bool lsensor_factory_write_50ms(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor write 50MS Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Light Sensor write 50MS Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Light Sensor write 50MS Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(lsensor_factory_write_50ms);
int lsensor_factory_read_100ms(const char *str)
{
struct file *fp = NULL;
loff_t pos_lsts = 0;
char buf[16];
int cal_val = 0, readlen = 0;
mm_segment_t old_fs;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor read 100MS Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 16, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Light Sensor read 100MS Calibration f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Light Sensor read 100MS Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Light Sensor read 100MS Calibration: Cal: %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(lsensor_factory_read_100ms);
bool lsensor_factory_write_100ms(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Light Sensor write 100MS Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Light Sensor write 100MS Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Light Sensor write 100MS Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(lsensor_factory_write_100ms);
/*For transition period from 100ms to 50ms ---*/

View File

@ -0,0 +1,759 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************/
/* Proximity Sensor Factory Module */
/****************************************/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_Factory"
#define SENSOR_TYPE_NAME "proximity"
#undef dbg
#ifdef ASH_FACTORY_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/***************************************/
/* Proximity read/write Calibration File*/
/**************************************/
int psensor_factory_read_high(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read High Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read High Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read High Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read High Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_high);
bool psensor_factory_write_high(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write High Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity Hi-Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write High Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_high);
int psensor_factory_read_low(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read Low Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read Low Calibration strlen f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read Low Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read Low Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_low);
bool psensor_factory_write_low(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write Low Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity Lo-Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write Low Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_low);
/********************************/
/* Proximity Inf calibration*/
/*******************************/
int psensor_factory_read_inf(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read INF Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read INF Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read INF Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read INF Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_inf);
bool psensor_factory_write_inf(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write INF Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity INF-Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write INF Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_inf);
/*For transition period from 3/5 to 2/4*/
int psensor_factory_read_2cm(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read 2CM Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read 2CM Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read 2CM Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read 2CM Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_2cm);
bool psensor_factory_write_2cm(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write 2CM Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity 2CM Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write 2CM Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_2cm);
int psensor_factory_read_4cm(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read 4CM Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read 4CM Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read 4CM Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read 4CM Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_4cm);
bool psensor_factory_write_4cm(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write 4CM Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity 4CM Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write 4CM Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_4cm);
int psensor_factory_read_3cm(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read 3CM Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read 3CM Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read 3CM Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read 3CM Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_3cm);
bool psensor_factory_write_3cm(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write 3CM Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity 3CM Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write 3CM Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_3cm);
int psensor_factory_read_5cm(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read 5CM Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read 5CM Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read 5CM Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read 5CM Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_5cm);
bool psensor_factory_write_5cm(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write 5CM Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity 5CM Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write 5CM Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_5cm);
int psensor_factory_read_1cm(const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
int cal_val = 0;
int readlen = 0;
fp = filp_open(str, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity read 1CM Calibration open (%s) fail\n", str);
return -ENOENT; /*No such file or directory*/
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
readlen = kernel_read(fp, buf, 16, &pos_lsts);
#else
readlen = vfs_read(fp, buf, 6, &pos_lsts);
#endif
buf[readlen] = '\0';
} else {
err("Proximity read 1CM Calibration strlen: f_op=NULL or op->read=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return -ENXIO; /*No such device or address*/
}
set_fs(old_fs);
filp_close(fp, NULL);
sscanf(buf, "%d", &cal_val);
if(cal_val < 0) {
err("Proximity read 1CM Calibration is FAIL. (%d)\n", cal_val);
return -EINVAL; /*Invalid argument*/
} else {
dbg("Proximity read 1CM Calibration : %d\n", cal_val);
}
return cal_val;
}
EXPORT_SYMBOL(psensor_factory_read_1cm);
bool psensor_factory_write_1cm(int calvalue, const char *str)
{
struct file *fp = NULL;
mm_segment_t old_fs;
loff_t pos_lsts = 0;
char buf[8];
sprintf(buf, "%d", calvalue);
fp = filp_open(str, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
if (IS_ERR_OR_NULL(fp)) {
err("Proximity write 1CM Calibration open (%s) fail\n", str);
return false;
}
/*For purpose that can use read/write system call*/
old_fs = get_fs();
set_fs(KERNEL_DS);
if (fp->f_op != NULL) {
pos_lsts = 0;
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)))
kernel_write(fp, buf, strlen(buf), &fp->f_pos);
#else
vfs_write(fp, buf, strlen(buf), &fp->f_pos);
#endif
} else {
err("Proximity 1CM Calibration strlen: f_op=NULL or op->write=NULL\n");
set_fs(old_fs);
filp_close(fp, NULL);
return false;
}
set_fs(old_fs);
filp_close(fp, NULL);
log("Proximity write 1CM Calibration : %s\n", buf);
return true;
}
EXPORT_SYMBOL(psensor_factory_write_1cm);

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*************************************/
/* ALSPS Sensor GPIO Module */
/************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/input/ASH.h>
#define ALSPS_INTEL_NAME "ALSPS_INT#"
#define ALSPS_QCOM_NAME "qcom,alsps-gpio"
#define ALSPS_IRQ_NAME "ALSPS_SENSOR_IRQ"
#define ALSPS_INT_NAME "ALSPS_SENSOR_INT"
static int ALSPS_SENSOR_GPIO;
static ALSPSsensor_GPIO * mALSPSsensor_GPIO;
/******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_GPIO"
#define SENSOR_TYPE_NAME "ALSPS"
static struct i2c_client * g_i2c_client = NULL;
#undef dbg
#ifdef ASH_GPIO_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static irqreturn_t ALSPSsensor_irq_handler(int irq, void *dev_id);
#include <linux/of_gpio.h>
#ifdef ALSP_GPIO_NO_PULL
#define GPIO_LOOKUP_STATE "alsps_gpio_no_pull"
#else
#define GPIO_LOOKUP_STATE "alsps_gpio_high"
#endif //ALSP_GPIO_NO_PULL
static void set_pinctrl(struct i2c_client *client)
{
int ret;
struct pinctrl *key_pinctrl;
struct pinctrl_state *set_state;
key_pinctrl = devm_pinctrl_get(&client->dev);
set_state = pinctrl_lookup_state(key_pinctrl, GPIO_LOOKUP_STATE);
ret = pinctrl_select_state(key_pinctrl, set_state);
if(ret < 0)
err("%s: pinctrl_select_state ERROR(%d).\n", __FUNCTION__, ret);
}
static int init_irq (void)
{
int ret = 0;
int irq = 0;
/* GPIO to IRQ */
irq = gpio_to_irq(ALSPS_SENSOR_GPIO);
if (irq < 0) {
err("%s: gpio_to_irq ERROR(%d). \n", __FUNCTION__, irq);
return irq;
}else {
log("gpio_to_irq IRQ %d successed on GPIO:%d\n", irq, ALSPS_SENSOR_GPIO);
}
ret = request_threaded_irq(irq, NULL, ALSPSsensor_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, ALSPS_INT_NAME, NULL);
if (ret < 0) {
err("%s: request_irq/request_threaded_irq ERROR(%d).\n", __FUNCTION__, ret);
return ret;
}else {
dbg("Disable irq !! \n");
disable_irq(irq);
}
return irq;
}
irqreturn_t ALSPSsensor_irq_handler(int irq, void *dev_id)
{
dbg("ALSPSensor isr");
mALSPSsensor_GPIO->ALSPSsensor_isr();
return IRQ_HANDLED;
}
int ALSPSsensor_gpio_register(struct i2c_client *client, ALSPSsensor_GPIO *gpio_ist)
{
int ret = 0;
int irq = 0;
g_i2c_client = client;
mALSPSsensor_GPIO = gpio_ist;
log("Qcom GPIO \n");
#ifdef ALSP_GPIO_NO_PULL
log("ALSP_GPIO_NO_PULL applied");
#else
log("ALSP_GPIO_HIGH applied");
#endif
set_pinctrl(client);
// ALSPS_SENSOR_GPIO = of_get_named_gpio_flags(client->dev.of_node, ALSPS_QCOM_NAME, 0, NULL);
ALSPS_SENSOR_GPIO = of_get_named_gpio(client->dev.of_node, ALSPS_QCOM_NAME, 0);
log("[GPIO] GPIO =%d(%d)\n", ALSPS_SENSOR_GPIO, gpio_get_value(ALSPS_SENSOR_GPIO));
/* GPIO Request */
ret = gpio_request(ALSPS_SENSOR_GPIO, ALSPS_IRQ_NAME);
if (ret) {
err("%s: gpio_request ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
/* GPIO Direction */
ret = gpio_direction_input(ALSPS_SENSOR_GPIO);
if (ret < 0) {
err("%s: gpio_direction_input ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
/*IRQ*/
irq = init_irq();
return irq;
}
EXPORT_SYMBOL(ALSPSsensor_gpio_register);
int ALSPSsensor_gpio_unregister(int irq)
{
free_irq(irq, NULL);
gpio_free(ALSPS_SENSOR_GPIO);
return 0;
}
EXPORT_SYMBOL(ALSPSsensor_gpio_unregister);

View File

@ -0,0 +1,141 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*************************************/
/* ALSPS Sensor GPIO Module */
/************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/input/ASH.h>
#define ALSPS_INTEL_NAME "ALSPS_INT#_2nd"
#define ALSPS_QCOM_NAME "qcom,alsps-gpio_2nd"
#define ALSPS_IRQ_NAME "ALSPS_SENSOR_IRQ_2nd"
#define ALSPS_INT_NAME "ALSPS_SENSOR_INT_2nd"
static int ALSPS_SENSOR_GPIO;
static ALSPSsensor_GPIO * mALSPSsensor_GPIO;
/******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_GPIO"
#define SENSOR_TYPE_NAME "ALSPS_2nd"
#undef dbg
#ifdef ASH_GPIO_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
static irqreturn_t ALSPSsensor_irq_handler(int irq, void *dev_id);
#include <linux/of_gpio.h>
#define GPIO_LOOKUP_STATE "alsps_gpio_high_2nd"
static void set_pinctrl(struct i2c_client *client)
{
int ret;
struct pinctrl *key_pinctrl;
struct pinctrl_state *set_state;
key_pinctrl = devm_pinctrl_get(&client->dev);
set_state = pinctrl_lookup_state(key_pinctrl, GPIO_LOOKUP_STATE);
ret = pinctrl_select_state(key_pinctrl, set_state);
if(ret < 0)
err("%s: pinctrl_select_state ERROR(%d).\n", __FUNCTION__, ret);
}
static int init_irq (void)
{
int ret = 0;
int irq = 0;
/* GPIO to IRQ */
irq = gpio_to_irq(ALSPS_SENSOR_GPIO);
if (irq < 0) {
err("%s: gpio_to_irq ERROR(%d). \n", __FUNCTION__, irq);
return irq;
}else {
log("gpio_to_irq IRQ %d successed on GPIO:%d\n", irq, ALSPS_SENSOR_GPIO);
}
/*Request IRQ*/
ret = request_threaded_irq(irq, NULL, ALSPSsensor_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, ALSPS_INT_NAME, NULL);
if (ret < 0) {
err("%s: request_irq/request_threaded_irq ERROR(%d).\n", __FUNCTION__, ret);
return ret;
}else {
dbg("Disable irq !! \n");
disable_irq(irq);
}
return irq;
}
irqreturn_t ALSPSsensor_irq_handler(int irq, void *dev_id)
{
mALSPSsensor_GPIO->ALSPSsensor_isr();
return IRQ_HANDLED;
}
int ALSPSsensor_gpio_register_2nd(struct i2c_client *client, ALSPSsensor_GPIO *gpio_ist)
{
int ret = 0;
int irq = 0;
mALSPSsensor_GPIO = gpio_ist;
/* GPIO */
log("Qcom GPIO \n");
set_pinctrl(client);
ALSPS_SENSOR_GPIO = of_get_named_gpio(client->dev.of_node, ALSPS_QCOM_NAME, 0);
dbg("[GPIO] GPIO =%d(%d)\n", ALSPS_SENSOR_GPIO, gpio_get_value(ALSPS_SENSOR_GPIO));
/* GPIO Request */
ret = gpio_request(ALSPS_SENSOR_GPIO, ALSPS_IRQ_NAME);
if (ret) {
err("%s: gpio_request ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
/* GPIO Direction */
ret = gpio_direction_input(ALSPS_SENSOR_GPIO);
if (ret < 0) {
err("%s: gpio_direction_input ERROR(%d). \n", __FUNCTION__, ret);
return ret;
}
/*IRQ*/
irq = init_irq();
return irq;
}
EXPORT_SYMBOL(ALSPSsensor_gpio_register_2nd);
int ALSPSsensor_gpio_unregister_2nd(int irq)
{
free_irq(irq, NULL);
gpio_free(ALSPS_SENSOR_GPIO);
return 0;
}
EXPORT_SYMBOL(ALSPSsensor_gpio_unregister_2nd);

View File

@ -0,0 +1,327 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/********************************/
/* ALSPS Sensor Hardware Module */
/******************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include "ALSPSsensor_Hardware.h"
#include <linux/input/ASH.h>
#include <linux/delay.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_HW"
#define SENSOR_TYPE_NAME "ALSPS"
#undef dbg
#ifdef ASH_HW_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/********************/
/* Global Variables */
/******************/
static ALSPS_I2C* g_ALSPS_I2C;
static struct i2c_client * g_i2c_client = NULL;
extern struct ALSPS_hw *g_ALSPS_hw_client;
static int mALSPS_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
if(g_ALSPS_I2C->ALSPS_probe == NULL){
err("ALSPS_probe NOT implement. \n");
return -EINVAL;
}
/* We use Probe function to get i2c client */
g_i2c_client = client;
g_ALSPS_I2C->ALSPS_probe(client);
return 0;
}
static int mALSPS_remove(struct i2c_client *client)
{
if(g_ALSPS_I2C->ALSPS_remove == NULL){
err("ALSPS_remove NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_remove();
return 0;
}
static void mALSPS_shutdown(struct i2c_client *client)
{
if(g_ALSPS_I2C->ALSPS_shutdown == NULL){
err("ALSPS_shutdown NOT implement. \n");
}
g_ALSPS_I2C->ALSPS_shutdown();
}
static int mALSPS_suspend(struct device *client)
{
if(g_ALSPS_I2C->ALSPS_suspend == NULL){
err("ALSPS_suspend NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_suspend();
return 0;
}
static int mALSPS_resume(struct device *client)
{
if(g_ALSPS_I2C->ALSPS_resume == NULL){
err("ALSPS_resume NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_resume();
return 0;
}
static const struct dev_pm_ops alsps_dev_pm_ops = {
.suspend = mALSPS_suspend,
.resume = mALSPS_resume,
};
static struct i2c_driver ALSPS_i2c_driver_client = {
.probe = mALSPS_probe,
.remove = mALSPS_remove,
.shutdown = mALSPS_shutdown,
.driver.pm = &alsps_dev_pm_ops,
};
int ALSPS_i2c_register(ALSPS_I2C *alsps_i2c)
{
if(alsps_i2c == NULL){
err("%s : ALSPS_I2C is NULL pointer. \n", __FUNCTION__);
return -EINVAL;
}
g_ALSPS_I2C = alsps_i2c;
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_register);
int ALSPS_i2c_unregister(void)
{
i2c_del_driver(&ALSPS_i2c_driver_client);
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_unregister);
/***********************/
/*VCNL36866 I2c Driver*/
/**********************/
#ifdef CONFIG_TMD2755_FLAG
static struct i2c_device_id tmd2755_idtable[] = {
{ "tmd2755", 0 },
{}
};
static const struct of_device_id tmd2755_of_match[] = {
{ .compatible = "ams,tmd2755" },
{}
};
#else
static const struct i2c_device_id vcnl36866_i2c_id[] = {
{"vcnl36866", 0},
{}
};
static struct of_device_id vcnl36866_match_table[] = {
{ .compatible = "qcom,vcnl36866",},
{},
};
#endif
static int ALSPS_hw_setI2cDriver(struct i2c_driver* i2c_driver_client,
int hardware_source)
{
switch(hardware_source) {
#ifdef CONFIG_TMD2755_FLAG
case ALSPS_hw_source_tmd2755:
log("set i2c client : tmd2755\n");
i2c_driver_client->driver.name = "tmd2755";
i2c_driver_client->driver.owner = THIS_MODULE;
i2c_driver_client->driver.of_match_table = tmd2755_of_match;
i2c_driver_client->id_table = tmd2755_idtable;
break;
#else
case ALSPS_hw_source_vcnl36866:
log("set i2c client : vcnl36866 \n");
i2c_driver_client->driver.name = "vcnl36866";
i2c_driver_client->driver.owner = THIS_MODULE;
i2c_driver_client->driver.of_match_table = vcnl36866_match_table;
i2c_driver_client->id_table = vcnl36866_i2c_id;
break;
#endif
default:
err("get hardware client ERROR : hardware enum=%d\n", hardware_source);
return -EINVAL;
}
return 0;
}
static ALSPS_hw* ALSPS_hw_getHardwareClient(int hardware_source)
{
ALSPS_hw* ALSPS_hw_client = NULL;
switch(hardware_source) {
#ifdef CONFIG_TMD2755_FLAG
case ALSPS_hw_source_tmd2755:
log("get hardware client : tmd2755 \n");
ALSPS_hw_client = ALSPS_hw_tmd2755_getHardware();
break;
#else
case ALSPS_hw_source_vcnl36866:
log("get hardware client : vcnl36866 \n");
ALSPS_hw_client = ALSPS_hw_vcnl36866_getHardware();
break;
#endif
default:
err("get hardware client ERROR : hardware enum=%d\n", hardware_source);
}
return ALSPS_hw_client;
}
int ALSPS_i2c_add_driver(void)
{
int ALSPS_sensor_source;
int ret = 0;
/*check i2c function pointer*/
if(g_ALSPS_I2C == NULL) {
err("g_ALSPS_I2C is NULL. Please use 'ALSPS_i2c_register' first. \n");
return -1;
}
/* i2c Registration */
for (ALSPS_sensor_source = 0; ALSPS_sensor_source < ALSPS_hw_source_max;
ALSPS_sensor_source++) {
/* i2c Registration and g_client will get i2c client */
ALSPS_hw_setI2cDriver(&ALSPS_i2c_driver_client, ALSPS_sensor_source);
ret = i2c_add_driver(&ALSPS_i2c_driver_client);
if ( ret != 0 ) {
err("%s: i2c_add_driver ERROR(%d). \n", __FUNCTION__, ret);
return -1;
}else{
log("%s %s add_driver Success. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
break;
}
/*
if(g_i2c_client == NULL){
err("%s: g_i2c_client is NULL pointer. \n", __FUNCTION__);
msleep(10000);
log("wait i2c client");
if(g_i2c_client == NULL){
err("%s: g_i2c_client is NULL pointer....... \n", __FUNCTION__);
return NULL;
}
}
// get hardware client and check the i2c status
ALSPS_hw_client = ALSPS_hw_getHardwareClient(ALSPS_sensor_source);
if(ALSPS_hw_client == NULL){
err("ALSPS_hw_client is NULL pointer. \n");
return NULL;
}
if(ALSPS_hw_client->ALSPS_hw_init == NULL){
err("ALSPS_hw_init is NULL pointer. \n");
return NULL;
}
ret = ALSPS_hw_client->ALSPS_hw_init(g_i2c_client);
if (ret < 0) {
i2c_del_driver(&ALSPS_i2c_driver_client);
log("%s %s Probe Fail. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
continue;
}else{
log("%s %s Probe Success. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
break;
}
*/
}
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_add_driver);
ALSPS_hw* ALSPS_hw_getHardware(void)
{
int ALSPS_sensor_source;
int ret = 0;
ALSPS_hw* ALSPS_hw_client = NULL;
/*check i2c function pointer*/
if(g_ALSPS_I2C == NULL) {
err("g_ALSPS_I2C is NULL. Please use 'ALSPS_i2c_register' first. \n");
return NULL;
}
/* i2c Registration */
for (ALSPS_sensor_source = 0; ALSPS_sensor_source < ALSPS_hw_source_max;
ALSPS_sensor_source++) {
if(g_i2c_client == NULL){
err("%s: g_i2c_client is NULL pointer. \n", __FUNCTION__);
return NULL;
}
// get hardware client and check the i2c status
ALSPS_hw_client = ALSPS_hw_getHardwareClient(ALSPS_sensor_source);
if(ALSPS_hw_client == NULL){
err("ALSPS_hw_client is NULL pointer. \n");
return NULL;
}
if(ALSPS_hw_client->ALSPS_hw_init == NULL){
err("ALSPS_hw_init is NULL pointer. \n");
return NULL;
}
ret = ALSPS_hw_client->ALSPS_hw_init(g_i2c_client);
if (ret < 0) {
//i2c_del_driver(&ALSPS_i2c_driver_client);
log("%s %s Probe Fail. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
return NULL ;
}else{
log("%s %s Probe Success. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
break;
}
}
if(ALSPS_sensor_source == ALSPS_hw_source_max) {
err("There is NO source can Probe.\n");
return NULL;
}
return ALSPS_hw_client;
}
EXPORT_SYMBOL(ALSPS_hw_getHardware);

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*******************************/
/* ALSPS Sensor Hardware Module */
/******************************/
#ifndef __LINUX_ALSPS_HARDWARE_H
#define __LINUX_ALSPS_HARDWARE_H
/****************************/
/* ALSPS Sensor Configuration */
/**************************/
#ifdef CONFIG_TMD2755_FLAG
enum hardware_source {
ALSPS_hw_source_tmd2755=0,
ALSPS_hw_source_max,
};
#else
enum hardware_source {
ALSPS_hw_source_vcnl36866=0,
ALSPS_hw_source_max,
};
#endif
#include <linux/input/ASH.h>
extern ALSPS_hw* ALSPS_hw_vcnl36866_getHardware(void);
extern ALSPS_hw* ALSPS_hw_vcnl36866_getHardware_2nd(void);
extern ALSPS_hw* ALSPS_hw_cm36686_getHardware(void);
extern ALSPS_hw* ALSPS_hw_ap3045_getHardware(void);
extern ALSPS_hw* ALSPS_hw_tmd2755_getHardware(void);
#endif

View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/********************************/
/* ALSPS Sensor Hardware Module */
/******************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include "ALSPSsensor_Hardware_2nd.h"
#include <linux/input/ASH.h>
#include <linux/delay.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_HW"
#define SENSOR_TYPE_NAME "ALSPS_2nd"
#undef dbg
#ifdef ASH_HW_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/********************/
/* Global Variables */
/******************/
static ALSPS_I2C* g_ALSPS_I2C;
static struct i2c_client * g_i2c_client = NULL;
extern struct ALSPS_hw *g_ALSPS_hw_client_2nd;
static int mALSPS_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
if(g_ALSPS_I2C->ALSPS_probe == NULL){
err("ALSPS_probe NOT implement. \n");
return -EINVAL;
}
/* We use Probe function to get i2c client */
g_i2c_client = client;
g_ALSPS_I2C->ALSPS_probe(client);
return 0;
}
static int mALSPS_remove(struct i2c_client *client)
{
if(g_ALSPS_I2C->ALSPS_remove == NULL){
err("ALSPS_remove NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_remove();
return 0;
}
static void mALSPS_shutdown(struct i2c_client *client)
{
if(g_ALSPS_I2C->ALSPS_shutdown == NULL){
err("ALSPS_shutdown NOT implement. \n");
}
g_ALSPS_I2C->ALSPS_shutdown();
}
static int mALSPS_suspend(struct device *client)
{
if(g_ALSPS_I2C->ALSPS_suspend == NULL){
err("ALSPS_suspend NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_suspend();
return 0;
}
static int mALSPS_resume(struct device *client)
{
if(g_ALSPS_I2C->ALSPS_resume == NULL){
err("ALSPS_resume NOT implement. \n");
return -EINVAL;
}
g_ALSPS_I2C->ALSPS_resume();
return 0;
}
static const struct dev_pm_ops alsps_dev_pm_ops = {
.suspend = mALSPS_suspend,
.resume = mALSPS_resume,
};
static struct i2c_driver ALSPS_i2c_driver_client = {
.probe = mALSPS_probe,
.remove = mALSPS_remove,
.shutdown = mALSPS_shutdown,
.driver.pm = &alsps_dev_pm_ops,
};
int ALSPS_i2c_register_2nd(ALSPS_I2C *alsps_i2c)
{
if(alsps_i2c == NULL){
err("%s : ALSPS_I2C is NULL pointer. \n", __FUNCTION__);
return -EINVAL;
}
g_ALSPS_I2C = alsps_i2c;
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_register_2nd);
int ALSPS_i2c_unregister_2nd(void)
{
i2c_del_driver(&ALSPS_i2c_driver_client);
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_unregister_2nd);
/***********************/
/*VCNL36866 I2c Driver*/
/**********************/
static const struct i2c_device_id vcnl36866_i2c_id[] = {
{"vcnl36866_2nd", 0},
{}
};
static struct of_device_id vcnl36866_match_table[] = {
{ .compatible = "qcom,vcnl36866_2nd",},
{},
};
static int ALSPS_hw_setI2cDriver(struct i2c_driver* i2c_driver_client,
int hardware_source)
{
switch(hardware_source) {
case ALSPS_hw_source_vcnl36866:
log("set i2c client : vcnl36866_2nd \n");
i2c_driver_client->driver.name = "vcnl36866_2nd";
i2c_driver_client->driver.owner = THIS_MODULE;
i2c_driver_client->driver.of_match_table = vcnl36866_match_table;
i2c_driver_client->id_table = vcnl36866_i2c_id;
break;
default:
err("get hardware client ERROR : hardware enum=%d\n", hardware_source);
return -EINVAL;
}
return 0;
}
static ALSPS_hw* ALSPS_hw_getHardwareClient(int hardware_source)
{
ALSPS_hw* ALSPS_hw_client = NULL;
switch(hardware_source) {
case ALSPS_hw_source_vcnl36866:
log("get hardware client : vcnl36866_2nd \n");
ALSPS_hw_client = ALSPS_hw_vcnl36866_getHardware_2nd();
break;
default:
err("get hardware client ERROR : hardware enum=%d\n", hardware_source);
}
return ALSPS_hw_client;
}
int ALSPS_i2c_add_driver_2nd(void)
{
int ALSPS_sensor_source;
int ret = 0;
/*check i2c function pointer*/
if(g_ALSPS_I2C == NULL) {
err("g_ALSPS_I2C is NULL. Please use 'ALSPS_i2c_register' first. \n");
return -1;
}
/* i2c Registration */
for (ALSPS_sensor_source = 0; ALSPS_sensor_source < ALSPS_hw_source_max;
ALSPS_sensor_source++) {
/* i2c Registration and g_client will get i2c client */
ALSPS_hw_setI2cDriver(&ALSPS_i2c_driver_client, ALSPS_sensor_source);
ret = i2c_add_driver(&ALSPS_i2c_driver_client);
if ( ret != 0 ) {
err("%s: i2c_add_driver ERROR(%d). \n", __FUNCTION__, ret);
return -1;
}
}
return 0;
}
EXPORT_SYMBOL(ALSPS_i2c_add_driver_2nd);
ALSPS_hw* ALSPS_hw_getHardware_2nd(void)
{
int ALSPS_sensor_source;
int ret = 0;
ALSPS_hw* ALSPS_hw_client = NULL;
/*check i2c function pointer*/
if(g_ALSPS_I2C == NULL) {
err("g_ALSPS_I2C is NULL. Please use 'ALSPS_i2c_register' first. \n");
return NULL;
}
/* i2c Registration */
for (ALSPS_sensor_source = 0; ALSPS_sensor_source < ALSPS_hw_source_max;
ALSPS_sensor_source++) {
if(g_i2c_client == NULL){
err("%s: g_i2c_client is NULL pointer. \n", __FUNCTION__);
return NULL;
}
// get hardware client and check the i2c status
ALSPS_hw_client = ALSPS_hw_getHardwareClient(ALSPS_sensor_source);
if(ALSPS_hw_client == NULL){
err("ALSPS_hw_client is NULL pointer. \n");
return NULL;
}
if(ALSPS_hw_client->ALSPS_hw_init == NULL){
err("ALSPS_hw_init is NULL pointer. \n");
return NULL;
}
ret = ALSPS_hw_client->ALSPS_hw_init(g_i2c_client);
if (ret < 0) {
//i2c_del_driver(&ALSPS_i2c_driver_client);
log("%s %s Probe Fail. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
continue;
}else{
log("%s %s Probe Success. \n", __FUNCTION__, ALSPS_i2c_driver_client.driver.name);
break;
}
}
if(ALSPS_sensor_source == ALSPS_hw_source_max) {
err("There is NO source can Probe.\n");
return NULL;
}
return ALSPS_hw_client;
}
EXPORT_SYMBOL(ALSPS_hw_getHardware_2nd);

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*******************************/
/* ALSPS Sensor Hardware Module */
/******************************/
#ifndef __LINUX_ALSPS_HARDWARE_H
#define __LINUX_ALSPS_HARDWARE_H
/****************************/
/* ALSPS Sensor Configuration */
/**************************/
enum hardware_source {
ALSPS_hw_source_vcnl36866=0,
ALSPS_hw_source_max,
};
#include <linux/input/ASH.h>
extern ALSPS_hw* ALSPS_hw_vcnl36866_getHardware(void);
extern ALSPS_hw* ALSPS_hw_vcnl36866_getHardware_2nd(void);
extern ALSPS_hw* ALSPS_hw_cm36686_getHardware(void);
extern ALSPS_hw* ALSPS_hw_ap3045_getHardware(void);
#endif

View File

@ -0,0 +1,234 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
#include <linux/i2c.h>
#include <linux/delay.h>
static int log_count_limit = 500;
int ams_i2c_blk_read(struct i2c_client *client, u8 reg, u8 *val, int size)
{
s32 ret;
static int log_count = 0;
ret = i2c_smbus_read_i2c_block_data(client, reg, size, val);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
return ret;
}
int ams_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
{
return ams_i2c_blk_read(client, reg, val, 1);
}
int ams_i2c_blk_read_direct(struct i2c_client *client, u8 reg, u8 *val, int size)
{
s32 ret;
static int log_count = 0;
ret = i2c_smbus_read_i2c_block_data(client, reg, size, val);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
return ret;
}
int ams_i2c_write_direct(struct i2c_client *client, u8 reg, u8 val)
{
int ret;
static int log_count = 0;
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0) {
mdelay(3);
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed to write register %x err= %d\n", __func__, reg, ret);
}
log_count++;
}
}
return ret;
}
int ams_i2c_write(struct i2c_client *client, u8 *shadow, u8 reg, u8 val)
{
int ret;
static int log_count = 0;
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0) {
mdelay(3);
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed to write register %x err= %d\n", __func__, reg, ret);
}
log_count++;
}
}
shadow[reg] = val;
return ret;
}
int ams_i2c_reg_blk_write(struct i2c_client *client, u8 reg, u8 *val, int size)
{
s32 ret;
static int log_count = 0;
ret = i2c_smbus_write_i2c_block_data(client, reg, size, val);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed 2X at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
return ret;
}
int ams_i2c_ram_blk_write(struct i2c_client *client, u8 reg, u8 *val, int size)
{
s32 ret = 0;
int i;
int bsize = 0;
int breg = reg;
int validx = 0;
int maxblocksize = 32;
static int log_count = 0;
for (i = 0; i < size; i += maxblocksize) {
if ((size - i) >= maxblocksize)
bsize = maxblocksize;
else
bsize = size - i;
ret = i2c_smbus_write_i2c_block_data(client, breg, bsize, &val[validx]);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
breg += bsize;
validx += bsize;
}
return ret;
}
int ams_i2c_ram_blk_read(struct i2c_client *client, u8 reg, u8 *val, int size)
{
s32 ret = 0;
int i;
int bsize = 0;
int breg = reg;
int validx = 0;
int maxblocksize = 32;
static int log_count = 0;
for (i = 0; i < size; i += maxblocksize) {
if ((size - i) >= maxblocksize)
bsize = maxblocksize;
else
bsize = size - i;
ret = i2c_smbus_read_i2c_block_data(client, breg, bsize, &val[validx]);
if (ret < 0)
ret = i2c_smbus_read_i2c_block_data(client, breg, bsize, &val[validx]);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed 2X at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
ret = i2c_smbus_write_i2c_block_data(client, breg, bsize, &val[validx]);
if (ret < 0){
if(log_count % log_count_limit == 0){
dev_err(&client->dev, "%s: failed at address %x (%d bytes)\n", __func__, reg, size);
}
log_count++;
}
breg += bsize;
validx += bsize;
}
return ret;
}
int ams_i2c_modify(struct i2c_client *client, u8 *shadow, u8 reg, u8 mask, u8 val)
{
int ret;
u8 temp;
ret = ams_i2c_read(client, reg, &temp);
temp &= ~mask;
temp |= val;
ret = ams_i2c_write(client, shadow, reg, temp);
shadow[reg] = temp;
return ret;
}
void ams_i2c_set_field(struct i2c_client *client, u8 *shadow, u8 reg, u8 pos, u8 nbits, u8 val)
{
u8 tmp;
u8 mask = (1 << nbits) - 1;
ams_i2c_read(client, reg, &tmp);
tmp &= ~(mask << pos);
tmp |= (val << pos);
ams_i2c_write(client, shadow, reg, tmp);
return;
}
void ams_i2c_get_field(struct i2c_client *client, u8 reg, u8 pos, u8 nbits, u8 *val)
{
u8 tmp;
u8 mask = (1 << nbits) - 1;
ams_i2c_read(client, reg, &tmp);
tmp &= mask << pos;
*val = tmp >> pos;
return;
}

View File

@ -0,0 +1,42 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
#ifndef __AMS_I2C_H__
#define __AMS_I2C_H__
int ams_i2c_blk_read(struct i2c_client *client, u8 reg, u8 *val, int size);
int ams_i2c_read(struct i2c_client *client, u8 reg, u8 *val);
int ams_i2c_blk_read_direct(struct i2c_client *client, u8 reg, u8 *val, int size);
int ams_i2c_write_direct(struct i2c_client *client, u8 reg, u8 val);
int ams_i2c_write(struct i2c_client *client, u8 *shadow, u8 reg, u8 val);
int ams_i2c_reg_blk_write(struct i2c_client *client, u8 reg, u8 *val, int size);
int ams_i2c_ram_blk_write(struct i2c_client *client, u8 reg, u8 *val, int size);
int ams_i2c_ram_blk_read(struct i2c_client *client, u8 reg, u8 *val, int size);
int ams_i2c_modify(struct i2c_client *client, u8 *shadow, u8 reg, u8 mask, u8 val);
void ams_i2c_set_field(struct i2c_client *client, u8 *shadow, u8 reg, u8 pos, u8 nbits, u8 val);
void ams_i2c_get_field(struct i2c_client *client, u8 reg, u8 pos, u8 nbits, u8 *val);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,472 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
/*! \file
* \brief Device driver for monitoring ambient light intensity in (lux)
* proximity detection (prox), and color temperature functionality within the
* AMS TMD2755 family of devices.
*/
#ifndef __AMS_TMD2755_H__
#define __AMS_TMD2755_H__
/* Linux Include Files */
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/completion.h>
#include <linux/input/ASH.h>
/***********************************************
* Flags for adding/removing code *
***********************************************/
/* Flag for enabling Debug input device dump */
/* and set all registers. */
#define DEBUG_ABI_SET_GET_REGISTERS
#define REMOVE_INPUT_DEVICE
extern void psensor_report_abs(int abs);
extern void lsensor_report_lux(int lux);
extern struct mutex g_alsps_lock;
extern tmd2755_status_param g_tmd2755_status_param;
/* Debugging Prox feature - during development */
#define DEBUG_PROX_FEATURE
// #define AMS_MUTEX_DEBUG
#if defined(AMS_MUTEX_DEBUG)
#define AMS_MUTEX_LOCK(m) { \
printk(KERN_INFO "%s:%s() --> Mutex Lock\n", __FILE__, __func__); \
mutex_lock(m); \
}
#define AMS_MUTEX_UNLOCK(m) { \
printk(KERN_INFO "%s:%s() --> Mutex Unlock\n", __FILE__, __func__); \
mutex_unlock(m); \
}
#else
#define AMS_MUTEX_LOCK(m) { \
mutex_lock(m); \
}
#define AMS_MUTEX_UNLOCK(m) { \
mutex_unlock(m); \
}
#endif
#define MIN_KERNEL_LOG_LEN (28)
#define MAX_KERNEL_LOG_LEN MIN_KERNEL_LOG_LEN
#define LINE_NUM_KERNEL_LOG_LEN (3)
#define MAX_REGS 256
#define BASE_10 (10)
/* Mandatory register values */
#define CFG8_REG_REQUIRED_VAL 0x29
#define TST3_REG_REQUIRED_VAL 0x04 /* changed 4/13/2020 */
#define TST9_REG_REQUIRED_VAL 0x02 /* changed from 0x0B per Whitney 11/13/2019 */
enum tmd2755_regs {
TMD2755_REG_ENABLE = 0x80,
TMD2755_REG_ATIME = 0x81,
TMD2755_REG_PRATE = 0x82, /* PTIME, PRATE */
TMD2755_REG_AWTIME = 0x83,
TMD2755_REG_AILTL = 0x84,
TMD2755_REG_AILTH = 0x85,
TMD2755_REG_AIHTL = 0x86,
TMD2755_REG_AIHTH = 0x87,
TMD2755_REG_PILTL = 0x88,
TMD2755_REG_PILTH = 0x89,
TMD2755_REG_PIHTL = 0x8A,
TMD2755_REG_PIHTH = 0x8B,
TMD2755_REG_PERS = 0x8C, /* als and prox interrupt pers*/
TMD2755_REG_CFG0 = 0x8D,
TMD2755_REG_PCFG0 = 0x8E,
TMD2755_REG_PCFG1 = 0x8F,
TMD2755_REG_PCFG2 = 0x90,
TMD2755_REG_CFG1 = 0x91,
TMD2755_REG_REVID = 0x92,
TMD2755_REG_DEVICEID = 0x93,
TMD2755_REG_STATUS = 0x94,
TMD2755_REG_ALSL = 0x95,
TMD2755_REG_ALSH = 0x96,
TMD2755_REG_IRL = 0x97,
TMD2755_REG_IRH = 0x98,
TMD2755_REG_PDATAL = 0x99,
TMD2755_REG_PDATAH = 0x9A,
TMD2755_REG_REVID2 = 0xA6,
TMD2755_REG_SOFTRST = 0xA8,
TMD2755_REG_PWTIME = 0xA9,
TMD2755_REG_CFG8 = 0xAA,
TMD2755_REG_CFG3 = 0xAB,
TMD2755_REG_CFG6 = 0xAE,
TMD2755_REG_POFFSET_L = 0xC0,
TMD2755_REG_POFFSET_H = 0xC1,
TMD2755_REG_CALIB = 0xD7,
TMD2755_REG_CALIB_OFF = 0xD8,
TMD2755_REG_CALIBCFG = 0xD9,
TMD2755_REG_CALIBSTAT = 0xDC,
TMD2755_REG_INTENAB = 0xDD,
TMD2755_REG_FAC_L = 0xE6,
TMD2755_REG_FAC_H = 0xE7,
/* TODO remove me after new datasheet rev */
TMD2755_REG_TEST3 = 0xF3,
TMD2755_REG_TEST9 = 0xF9,
TMD2755_REG_LAST = 0xFF,
};
enum tmd2755_mask_shift_reg {
TMD2755_MASK_DEVICEID = 0xFC,
TMD2755_SHIFT_DEVICEID = 2,
TMD2755_MASK_REVID = 0x07,
TMD2755_SHIFT_REVID = 0,
TMD2755_MASK_REVID2 = 0x0F,
TMD2755_SHIFT_REVID2 = 0,
TMD2755_MASK_PGAIN1 = 0xC0,
TMD2755_SHIFT_PGAIN1 = 6,
TMD2755_MASK_PGAIN2 = 0x60,
TMD2755_SHIFT_PGAIN2 = 5,
TMD2755_MASK_PPULSE = 0x3F,
TMD2755_SHIFT_PPULSE = 0,
TMD2755_MASK_PILTL = 0xFF,
TMD2755_SHIFT_PILTL = 0,
TMD2755_MASK_PILTH = 0x3F,
TMD2755_SHIFT_PILTH = 0,
TMD2755_MASK_PIHTL = 0xFF,
TMD2755_SHIFT_PIHTL = 0,
TMD2755_MASK_PIHTH = 0x3F,
TMD2755_SHIFT_PIHTH = 0,
TMD2755_MASK_PROX_PERS = 0xF0,
TMD2755_SHIFT_PROX_PERS = 4,
TMD2755_MASK_START_OFFSET_CALIB = 0x01,
TMD2755_SHIFT_START_OFFSET_CALIB = 0,
TMD2755_MASK_CALPRATE_CALIB = 0x10,
TMD2755_SHIFT_CALPRATE_CALIB = 4,
TMD2755_MASK_ELEC_OPTO_CALIB = 0x20,
TMD2755_SHIFT_ELEC_OPTO_CALIB = 5,
TMD2755_MASK_CALAVG_CALIB = 0x80,
TMD2755_SHIFT_CALAVG_CALIB = 7,
TMD2755_MASK_ENABLE_ORE = 0x20,
TMD2755_SHIFT_ENABLE_ORE = 5,
TMD2755_MASK_ORE = 0x1F,
TMD2755_SHIFT_ORE = 0,
TMD2755_MASK_BINSRCH_TARGET = 0xE0,
TMD2755_SHIFT_BINSRCH_TARGET = 5,
TMD2755_MASK_PROX_AUTO_OFFSET_ADJUST = 0x08,
TMD2755_SHIFT_PROX_AUTO_OFFSET_ADJUST = 3,
TMD2755_MASK_PROX_DATA_AVG = 0x07,
TMD2755_SHIFT_PROX_DATA_AVG = 0,
TMD2755_MASK_POFFSET_H = 0x01,
TMD2755_SHIFT_POFFSET_H = 0,
TMD2755_MASK_PPULSE_LEN_L = 0x0FF,
TMD2755_SHIFT_PPULSE_LEN_L = 0,
TMD2755_MASK_REG_PPULSE_LEN_H = 0xC0, // mask for register PCFG1
TMD2755_MASK_DATA_PPULSE_LEN_H = 0x300, // mask for data structure - 10 bit value
TMD2755_SHIFT_PPULSE_LEN_H = 2,
TMD2755_MASK_APC = 0x40,
TMD2755_SHIFT_APC = 6,
TMD2755_MASK_AGAIN = 0x1F,
TMD2755_SHIFT_AGAIN = 0,
TMD2755_MASK_AWLONG = 0x04,
TMD2755_SHIFT_AWLONG = 2,
TMD2755_MASK_ALS_PERS = 0x0F,
TMD2755_SHIFT_ALS_PERS = 0,
};
enum tmd2755_pwr_state {
POWER_ON,
POWER_OFF,
POWER_STANDBY,
};
enum tmd2755_prox_state {
PROX_STATE_NONE = 0,
PROX_STATE_INIT,
PROX_STATE_CALIB,
PROX_STATE_WAIT_AND_CALIB
};
enum tmd2755_feature_state {
TMD2755_FEATURE_OFF = 0,
TMD2755_FEATURE_ON = 1,
};
enum tmd2755_enable_state {
TMD2755_ENABLE_OFF = 0,
TMD2755_ENABLE_ON = 1,
};
enum tmd2755_ctrl_reg {
AGAIN_16 = (5 << 0),
AGAIN_128 = (8 << 0),
AGAIN_1024 = (11 << 0),
PGAIN1_1 = (0 << TMD2755_SHIFT_PGAIN1),
PGAIN1_2 = (1 << TMD2755_SHIFT_PGAIN1),
PGAIN1_4 = (2 << TMD2755_SHIFT_PGAIN1),
PGAIN1_8 = (3 << TMD2755_SHIFT_PGAIN1),
PGAIN2_1 = (0 << TMD2755_SHIFT_PGAIN2),
PGAIN2_2_5 = (1 << TMD2755_SHIFT_PGAIN2),
PGAIN2_5 = (2 << TMD2755_SHIFT_PGAIN2),
PGAIN2_10 = (3 << TMD2755_SHIFT_PGAIN2),
};
enum tmd2755_enable_reg {
TMD2755_PON = (1 << 0),
TMD2755_AEN = (1 << 1),
TMD2755_PEN = (1 << 2),
TMD2755_AWEN = (1 << 3),
TMD2755_PWEN = (1 << 4),
TMD2755_EN_ALL = (TMD2755_AEN |TMD2755_PEN | TMD2755_AWEN | TMD2755_PWEN),
};
enum tmd2755_int_shift {
TMD2755_INT_PRX_SAT_SHIFT = 6,
};
enum tmd2755_int_status {
TMD2755_INT_ST_PSAT_AMBIENT_IRQ = (1 << 0),
TMD2755_INT_ST_PSAT_REFLECT_IRQ = (1 << 1),
TMD2755_INT_ST_ZERODET_IRQ = (1 << 2),
TMD2755_INT_ST_CALIB_IRQ = (1 << 3),
TMD2755_INT_ST_ALS_IRQ = (1 << 4),
TMD2755_INT_ST_PRX_IRQ = (1 << 5),
TMD2755_INT_ST_PRX_SAT_IRQ = (1 << 6),
TMD2755_INT_ST_ALS_SAT_IRQ = (1 << 7),
};
enum tmd2755_intenab_reg {
TMD2755_ZIEN = (1 << 2),
TMD2755_CIEN = (1 << 3),
TMD2755_AIEN = (1 << 4),
TMD2755_PIEN = (1 << 5),
TMD2755_PSIEN = (1 << 6),
TMD2755_ASIEN = (1 << 7),
};
/* Group all the prox interrupts */
#define TMD2755_PROX_INTS (TMD2755_ZIEN | TMD2755_PIEN | TMD2755_PSIEN | TMD2755_CIEN)
// pldrive Ivcsel = (PLDRIVE + 2) mA
#define PDRIVE_MA(p) ({ \
u8 __reg = (((u8)((p) - 2)) & 0x0F); \
__reg = (__reg > 0x0A) ? 0x0A : __reg; \
__reg; \
})
// pulse length (PULSE_LEN + 2) usec - 10 bits
#define PPULSE_LEN_US(p) ({ \
u16 __reg; \
if (p < 2) { \
__reg = 0; \
} else { \
__reg = (((u16)((p) - 2)) & 0x3FF); \
__reg = (__reg > 0x3FF) ? 0x03FF : __reg; \
} \
__reg; \
})
#define P_TIME_US(p) ((((p) / 88) - 1.0) + 0.5)
#define INTEGRATION_CYCLE 2780
/* Used for ALS Wait time and ALS Time */
#define AW_TIME_MS(p) ((((p) * 1000) + (INTEGRATION_CYCLE - 1)) / INTEGRATION_CYCLE)
struct als_prox_pers
{
u8 apers : 4;
u8 ppers : 4;
};
union tmd2755_persist
{
struct als_prox_pers pers;
u8 persistance;
};
#define PROX_PERSIST(p) (((p) & 0x0F) << 4)
#define ALS_PERSIST(p) (((p) & 0x0F) << 0)
struct tmd2755_parameters {
/* Common both als and prox */
union tmd2755_persist persist;
/* Prox */
u16 prox_thresh_min;
u16 prox_thresh_max;
u8 prox_apc;
u8 prox_pulse_cnt;
u16 prox_pulse_len;
u8 prox_gain1;
u8 prox_gain2;
s16 poffset;
u8 prox_drive;
u8 prox_time;
u8 prox_wtime;
/* prox calibration - These registers are set during */
/* prox offset calibration and are currently cannot */
/* be adjusted programatically */
u8 prox_calavg;
u8 prox_calprate;
u8 prox_enable_ore;
u8 prox_ore;
u8 prox_binsrch_tgt;
u8 prox_auto_off_adj;
u8 prox_avg;
/* ALS / Color */
u8 als_gain;
u32 als_auto_gain;
u16 als_deltaP;
u8 als_time;
u8 als_wtime;
u32 dgf;
u32 ch0_coef0;
u32 ch0_coef1;
u32 ch1_coef0;
u32 ch1_coef1;
u32 coef_scale;
s16 poffset_fac;
s16 poffset_limit;
s16 poffset_last;
};
struct tmd2755_als_info {
u32 counts_per_lux;
u32 saturation;
u16 ch0_raw;
u16 ch1_raw;
u16 lux;
};
struct tmd2755_prox_info {
u16 raw;
int detected;
};
// Must match definition in ../arch file
struct tmd2755_i2c_platform_data {
/* The following callback for power events received and handled by
the driver. Currently only for SUSPEND and RESUME */
int (*platform_power)(struct device *dev, enum tmd2755_pwr_state state);
int (*platform_init)(void);
void (*platform_teardown)(struct device *dev);
char const *prox_name;
char const *als_name;
int device_index;
struct tmd2755_parameters parameters;
// TODO: ??? bool proximity_can_wake;
// TODO: ??? bool als_can_wake;
#if defined(CONFIG_OF)
struct device_node *of_node;
#endif
};
struct tmd2755_chip {
struct mutex lock;
struct completion calibration_done;
struct i2c_client *client;
struct gpio_desc *gpiod_interrupt;
struct tmd2755_prox_info prox_info;
struct tmd2755_als_info als_info;
struct tmd2755_parameters params;
struct tmd2755_i2c_platform_data *pdata;
u8 shadow[MAX_REGS];
struct input_dev *prox_idev;
struct input_dev *als_idev;
#ifdef DEBUG_ABI_SET_GET_REGISTERS
struct input_dev *dbg_idev;
#endif // #ifdef DEBUG_ABI_SET_GET_REGISTERS
int in_suspend;
int wake_irq;
int irq_pending;
int in_psat;
bool in_asat;
bool in_calib;
bool unpowered;
bool als_enable;
bool prox_enable;
bool amsCalComplete;
bool cal_en;
u8 device_index;
};
#define TMD2755_PROXIMITY_INF_DEFAULT (0)
#define TMD2755_PROXIMITY_OFFSET_DEFAULT (76)
#define TMD2755_PROXIMITY_THDL_DEFAULT (145)
#define TMD2755_PROXIMITY_THDH_DEFAULT (437)
#define TMD2755_PROXIMITY_AUTOK_MIN (3)
#define TMD2755_PROXIMITY_AUTOK_MAX (300)
#define TMD2755_LIGHT_CALIBRATION_DEFAULT (1440)
#define TMD2755_LIGHT_MAX_THRESHOLD (65534)
#define TMD2755_WAIT_I2C_DELAY 5
#endif // __AMS_TMD2755_H__

View File

@ -0,0 +1,979 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
/*! \file
* \brief Device driver for monitoring ambient light intensity in (lux)
* proximity detection (prox) functionality within the
* AMS TMD2755 family of devices.
*/
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ams_tmd2755.h"
#include "ams_tmd2755_als.h"
#include "ams_i2c.h"
/******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_tmd2755"
#define SENSOR_TYPE_NAME "ALSPS"
#undef dbg
#ifdef ASH_GPIO_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s]"fmt,MODULE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
extern struct tmd2755_chip *g_tmd2755_chip;
/*********************************/
/*****************************************************************
* Local globals for als module *
*****************************************************************/
static u8 const restorable_als_regs[] = {
TMD2755_REG_ATIME,
TMD2755_REG_AWTIME,
TMD2755_REG_PERS,
TMD2755_REG_CFG0,
TMD2755_REG_CFG1,
};
/*****************************************************************
* Local Functions *
*****************************************************************/
static int tmd2755_convert_again(int reg_value)
{
int ret_val = ALS_GAIN_128;
switch (reg_value)
{
case ALS_GAIN_REG_VAL_16:
{
ret_val = ALS_GAIN_16;
break;
}
case ALS_GAIN_REG_VAL_128:
{
ret_val = ALS_GAIN_128;
break;
}
case ALS_GAIN_REG_VAL_1024:
{
ret_val = ALS_GAIN_1024;
break;
}
default:
{
break;
}
}
return(ret_val);
}
static int tmd2755_flush_als_regs(struct tmd2755_chip *chip)
{
unsigned int i;
int rc;
u8 reg;
for (i = 0; i < ARRAY_SIZE(restorable_als_regs); i++) {
reg = restorable_als_regs[i];
rc = ams_i2c_write(chip->client, chip->shadow, reg, chip->shadow[reg]);
if (rc) {
dev_err(&chip->client->dev, "%*.*s():%*d --> err on reg 0x%02X\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, reg);
break;
}
}
return rc;
}
/*
* Refer to Design Notebook 40 for a better understanding of CPL.
*/
static void tmd2755_calc_counts_per_lux(struct tmd2755_chip *chip)
{
u64 cpl;
u32 sat;
u8 atime;
u16 again;
atime = chip->shadow[TMD2755_REG_ATIME];
cpl = (u64) atime + 1; /* add one because atime reg is base 0: 0 = 1 integration time */
cpl *= INTEGRATION_CYCLE; /* using microseconds cancels out the scale factor of the coeffs */
again = tmd2755_convert_again(chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN);
cpl *= again;
/* Optimization if coefficients are scaled by 1000, adjust accordingly */
if (chip->params.coef_scale != ALS_COEFF_SCALE_FACTOR) {
/* Possible overflow if coefficients are scaled > 1000 */
cpl *= chip->params.coef_scale; /* rgb coeff scaling factor */
/* do_div returns the quotient in the divident */
do_div(cpl, (chip->params.dgf * ALS_COEFF_SCALE_FACTOR));
} else {
do_div(cpl, chip->params.dgf);
}
/* min of max_als for max amount based on atime - see datasheet for atime */
/* each 2.78 ms, increase max count by 1024 - left shift of 10 multiplies by */
/* 1024 */
sat = min_t(u32, TMD2755_MAX_ALS_VALUE, (u32) (((atime + 1) << TMD2755_SHIFT_MULT_BY_1024) - 1));
chip->als_info.counts_per_lux = (u32) cpl;
/* Set saturation at 90% of max count*/
chip->als_info.saturation = TENTH_FRACTION_OF_VAL(sat, TMD2755_SATURATION_THRESHOLD);
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Calculating cpl = %llu, count_per_lux=%u, saturation = %d (%d0%% of %d)\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, cpl,
chip->als_info.counts_per_lux, chip->als_info.saturation,
TMD2755_SATURATION_THRESHOLD, sat);
return;
}
static int tmd2755_set_als_gain(struct tmd2755_chip *chip, u8 gain)
{
int rc = 0;
u8 saved_enable;
/* Turn off ALS, so that new ALS gain value will take effect at start of
* new integration cycle.
* New ALS gain value will then be used in next lux calculation.
*/
ams_i2c_read(chip->client, TMD2755_REG_ENABLE, &saved_enable);
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_ENABLE, 0); /* turn off everything */
rc = ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_CFG1, TMD2755_MASK_AGAIN, gain);
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_ENABLE, saved_enable);
if (rc >= 0) {
chip->params.als_gain = chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN;
dev_info(&chip->client->dev, "%*.*s():%*d --> New ALS Gain set %d (%dx)\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, gain,
tmd2755_convert_again(gain));
}
return rc;
}
static void tmd2755_get_rawdata(struct tmd2755_chip *chip)
{
u8 *sh = chip->shadow;
/* extract raw channel data */
chip->als_info.ch0_raw = le16_to_cpup((const __le16 *)&sh[TMD2755_REG_ALSL]);
chip->als_info.ch1_raw = le16_to_cpup((const __le16 *)&sh[TMD2755_REG_IRL]);
return;
}
static void tmd2755_inc_gain(struct tmd2755_chip *chip)
{
int rc;
u8 gain = (chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN);
if (gain == ALS_GAIN_REG_VAL_1024) {
dev_dbg(&chip->client->dev, "%*.*s():%*d -->\tCannot Increment ALS Gain: already at maximum (%d x).\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, ALS_GAIN_1024);
return; /* already at highest gain setting */
}
/* if gain is set to 16x, move it to 128x. If it is 128x, move it to 1024 */
gain = ((gain == ALS_GAIN_REG_VAL_16) ? ALS_GAIN_REG_VAL_128 : ALS_GAIN_REG_VAL_1024);
rc = tmd2755_set_als_gain(chip, gain);
if (rc == 0)
tmd2755_calc_counts_per_lux(chip);
return;
}
static void tmd2755_dec_gain(struct tmd2755_chip *chip)
{
int rc;
u8 gain = (chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN);
if (gain == ALS_GAIN_REG_VAL_16) {
dev_dbg(&chip->client->dev, "%*.*s():%*d --> \tCannot Decrement ALS Gain: already at minimum (%d x).\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, ALS_GAIN_16);
return; /* already at lowest gain */
}
gain = ((gain == ALS_GAIN_REG_VAL_1024) ? ALS_GAIN_REG_VAL_128 : ALS_GAIN_REG_VAL_16);
rc = tmd2755_set_als_gain(chip, gain);
if (rc == 0)
tmd2755_calc_counts_per_lux(chip);
return;
}
static int tmd2755_max_als_value(struct tmd2755_chip *chip)
{
int val;
val = chip->shadow[TMD2755_REG_ATIME];
if (val > ALS_ATIME_FOR_MAX_CNT) /* after a certain atime, the max als count stays the same */
val = ALS_FULL_SCALE_CNT;
else
val = ((val * ALS_ATIME_INCREMENT_CNT) + ALS_ATIME_INCREMENT_CNT-1); /* Initial atime only causes (1024 -1) full scale */
return val;
}
static int tmd2755_update_als_threshold(struct tmd2755_chip *chip, enum tmd2755_enable_state on_enable)
{
s32 ret = 0;
u16 deltaP = chip->params.als_deltaP; /* integer percentage to generate thresholds */
u16 from, to, cur;
u16 saturation = chip->als_info.saturation;
static u16 last_from = 0, last_to = 0;
cur = chip->als_info.ch0_raw;
if (on_enable == TMD2755_ENABLE_ON) {
/* move deltaP far away from current position to force an irq */
from = to = cur > (saturation / 2) ? 0 : saturation;
} else {
deltaP = cur * deltaP / 100;
if (!deltaP)
deltaP = 1;
if (cur > deltaP)
from = cur - deltaP;
else
from = 0;
to = cur + deltaP;
/* prevent high threshold overflow */
if(to > TMD2755_CH0_MAXIMUM){
to = TMD2755_CH0_MAXIMUM;
}
}
*((__le16 *) &chip->shadow[TMD2755_REG_AILTL]) = cpu_to_le16(from);
*((__le16 *) &chip->shadow[TMD2755_REG_AIHTL]) = cpu_to_le16(to);
if(from != last_from || to != last_to || true == g_tmd2755_status_param.log_first_evt){
last_from = from;
last_to = to;
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Low Thresh: %d High Thresh: : %d Current Ch0: %d deltaP: %d Sat Level: %d\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__,
from, to, cur, deltaP, saturation);
g_tmd2755_status_param.log_first_evt = false;
}
ret = ams_i2c_reg_blk_write(chip->client, TMD2755_REG_AILTL, &chip->shadow[TMD2755_REG_AILTL],
(TMD2755_REG_AIHTH - TMD2755_REG_AILTL) + 1);
return (ret < 0) ? ret : 0;
}
int tmd2755_get_lux(struct tmd2755_chip *chip)
{
s64 _lux1, _lux2, _lux3;
s32 __lux1, __lux2, __lux3;
//long lux1, lux2, lux3;
s32 lux = 0;
//s64 sf;
//s32 coefa = chip->params.ch0_coef0;
//s32 coefc = chip->params.ch0_coef1;
//s32 coefb = chip->params.ch1_coef0;
//s32 coefd = chip->params.ch1_coef1;
long ch0 = (long)chip->als_info.ch0_raw;
long ch1 = (long)chip->als_info.ch1_raw;
long coefa = 678; //should / 1000
long coefb = 1050; //should /1000
long coefc = 4;
long DFA = 3850;
long DFB = 18000;
long DFC = 16500;
long div_val = 1000;
long diff1 = 1500; //should /10000
long diff2 = 9900; //should /10000
long ch_temp = 0; // ch0/ch1
int low_thres;
s64 sf = 0;
long ch_data_limit = 0;
static long ch0_last = 0;
// use time in ms get scaling factor
tmd2755_calc_counts_per_lux(chip);
if (!chip->als_info.counts_per_lux) {
dev_info(&chip->client->dev, "%*.*s():%*d --> CPL = 0... Setting to 1\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
chip->als_info.counts_per_lux = 1;
}
dbg("count_per_lux=%u", chip->als_info.counts_per_lux);
sf = (s64)chip->als_info.counts_per_lux; // atime_ms*again/DGF
sf = div64_s64(sf, 1000); // atime_ms*again/DGF
dbg("sf=%lld, count_per_lux=%u", sf, chip->als_info.counts_per_lux);
dbg("DFA=%ld, DFB=%ld, DFC=%ld, coefa=%ld, coefb=%ld, coefc=%ld", DFA, DFB, DFC, coefa, coefb, coefc);
dbg("ch0=%ld, ch1=%ld", ch0, ch1);
dbg("DFA*ch0=%ld, DFA*coefa*ch1=%ld", DFA*ch0, DFA*coefa*ch1);
dbg("DFB*ch0=%ld (/1000, DFB*coefb*ch1=%ld (/1000000", DFB*ch0, DFB*coefb*ch1);
dbg("DFC*ch0=%ld, DFC*coefc*ch1=%ld", DFC*ch0, DFC*coefc*ch1);
_lux1 = (s64)DFA*ch0-(DFA*coefa*ch1)/div_val;
_lux2 = (s64)(DFB*ch0)-(DFB*coefb*ch1)/div_val;
_lux3 = (s64)DFC*ch0-DFC*coefc*ch1;
__lux1 = (s32)div64_s64(_lux1, sf);
__lux2 = (s32)div64_s64(_lux2, sf);
__lux3 = (s32)div64_s64(_lux3, sf);
ch_temp = (ch1*10000)/ch0;
if(diff2 < ch_temp){
lux = __lux1;
}else if((diff2 >= ch_temp) && (diff1 < ch_temp)){
lux = __lux2;
}else{
lux = __lux3;
}
if(ch0 > 1000){
ch_data_limit = ch0_last / 10;
}else{
ch_data_limit = ch0_last * 98 / 100;
}
if(ch0 != ch0_last){
if((ch0_last >= (ch0+ch_data_limit)) || (ch0_last <= (ch0-ch_data_limit)) || g_tmd2755_status_param.log_first_evt == true){
log("lux=%ld, ch0=%u, ch1=%u, ch0_last=%ld, (ch1*10000/ch0)=%ld, sf=%lld",
lux, ch0, ch1, ch0_last, ch_temp, sf);
}
}
ch0_last = ch0;
if (lux < 0) {
dev_info(&chip->client->dev, "%*.*s():%*d --> lux < 0, Use previous value.\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
return chip->als_info.lux; /* use previous value */
} else {
lux = min(ALS_MAX_LUX_VAL, max(0, lux));
}
/* Determine threshold for switching gains */
low_thres = tmd2755_max_als_value(chip) / TMD2755_THRESHOLD_PERCENT;
/* clamp counts to prevent flip-flopping between gains */
low_thres = clamp(low_thres, 0, TMD2755_AUTO_GAIN_CLAMP_CNT);
/* There is a case where one channel can saturate and the other channel can be below the clamping value. */
/* This algorithm does not gracefully handle it. */
if (!chip->params.als_auto_gain) { /* auto gain is off */
if ((chip->als_info.ch0_raw <= TMD2755_MIN_ALS_VALUE) || (chip->als_info.ch1_raw <= TMD2755_MIN_ALS_VALUE)) {
dev_info(&chip->client->dev, "%*.*s():%*d --> Darkness entered: Channel count less than minimum ([%d || %d] <= %d).\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__,
chip->als_info.ch0_raw, chip->als_info.ch1_raw, TMD2755_MIN_ALS_VALUE);
} else if ((chip->als_info.ch0_raw >= chip->als_info.saturation) || (chip->als_info.ch1_raw >= chip->als_info.saturation)) {
dev_info(&chip->client->dev, "%*.*s():%*d --> Saturation occurred: Channel count exceeds maximum ([%d || %d] >= %d).\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__,
chip->als_info.ch0_raw, chip->als_info.ch1_raw, chip->als_info.saturation);
}
} else {
if (chip->als_info.ch0_raw < low_thres || chip->als_info.ch1_raw < low_thres) {
if((chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN) != ALS_GAIN_REG_VAL_1024){
dev_info(&chip->client->dev, "%*.*s():%*d --> Autogain Incrementing, ch0:%d, ch1:%d, low_thres=%d\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN,
__LINE__, chip->als_info.ch0_raw, chip->als_info.ch1_raw, low_thres);
tmd2755_inc_gain(chip);
}
tmd2755_flush_als_regs(chip);
} else if ((chip->als_info.ch0_raw >= chip->als_info.saturation) || (chip->als_info.ch1_raw >= chip->als_info.saturation) || chip->in_asat) {
if ((chip->shadow[TMD2755_REG_CFG1] & TMD2755_MASK_AGAIN) != ALS_GAIN_REG_VAL_16) {
dev_info(&chip->client->dev, "%*.*s():%*d --> Autogain Decrementing, sat=%d, in_asat=%d \n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN,
__LINE__, chip->als_info.saturation, chip->in_asat);
tmd2755_dec_gain(chip);
}
tmd2755_flush_als_regs(chip);
}
}
chip->als_info.lux = lux;
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Lux Calculation: %d, lux=%d\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__,
lux, chip->als_info.lux);
return 0;
}
/*****************************************************************
* Utility Calls *
*****************************************************************/
int tmd2755_configure_als_mode(struct tmd2755_chip *chip, u8 state)
{
struct i2c_client *client = chip->client;
u8 *sh = chip->shadow;
if (state) { /* Enable ALS */
g_tmd2755_status_param.log_first_evt = true;
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Enabling and Configuring ALS\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
chip->shadow[TMD2755_REG_ATIME] = chip->params.als_time;
tmd2755_calc_counts_per_lux(chip);
/* only adjust als peristance */
chip->shadow[TMD2755_REG_PERS] &= (~TMD2755_MASK_ALS_PERS);
chip->shadow[TMD2755_REG_PERS] |= chip->params.persist.pers.apers;
tmd2755_flush_als_regs(chip);
/* AWTIME */
ams_i2c_write(client, sh, TMD2755_REG_AWTIME, chip->params.als_wtime);
/* Enable ALS interrupt */
ams_i2c_modify(client, sh, TMD2755_REG_INTENAB, TMD2755_AIEN, TMD2755_AIEN);
/* When enabling ALS - AEN in Register 0x80, PWEN must be set to 1 if prox is enabled - See datasheet */
/* As of release 1.9, PWEN is active when proximity is turned oa - see ams_tmd2755_prox.c filen */
/* Also Power On */
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_AEN | TMD2755_PON,
TMD2755_AEN | TMD2755_PON);
chip->als_enable = true;
/* Enable PWTIME */
if(chip->prox_enable == true){
log("pon, enable PWEN");
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PWEN, TMD2755_PWEN);
}
} else { /* Disable ALS */
dev_info(&chip->client->dev, "%*.*s():%*d --> Disable ALS\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
ams_i2c_modify(client, sh, TMD2755_REG_INTENAB, TMD2755_AIEN, 0);
/* Cannot turn off PWEN, in case prox feature is still using it */
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_AEN, 0);
chip->als_enable = false;
*((__le16 *) &chip->shadow[TMD2755_REG_AILTL]) = cpu_to_le16(0);
*((__le16 *) &chip->shadow[TMD2755_REG_AIHTL]) = cpu_to_le16(0);
ams_i2c_reg_blk_write(chip->client, TMD2755_REG_AILTL, &chip->shadow[TMD2755_REG_AILTL],
(TMD2755_REG_AIHTH - TMD2755_REG_AILTL) + 1);
log("set hi/low threshold to 0");
/* Close PWTIME */
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PWEN, 0);
/* If Prox is not on, turn off chip */
if (!(sh[TMD2755_REG_ENABLE] & TMD2755_EN_ALL)){
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PON, 0);
}
}
return 0;
}
int tmd2755_read_als(struct tmd2755_chip *chip)
{
int ret;
ret = ams_i2c_blk_read(chip->client, TMD2755_REG_ALSL, &chip->shadow[TMD2755_REG_ALSL], ALS_NUM_CH * ALS_CH_SIZE);
if (ret >= 0) {
tmd2755_get_rawdata(chip);
ret = 0;
}
return ret;
}
extern int light_get_lux(int adc);
void tmd2755_report_als(struct tmd2755_chip *chip)
{
int lux;
int rc;
static int last_lux = 0;
#ifdef REMOVE_INPUT_DEVICE
rc = tmd2755_get_lux(chip); /* always returns 0 */
if (!rc) {
lux = chip->als_info.lux;
lux = light_get_lux(chip->als_info.lux);
lsensor_report_lux(lux);
if(g_tmd2755_status_param.log_first_evt == true){
log("ALS lux First= %d (orig lux=%d)", lux, chip->als_info.lux);
}else if(lux != last_lux){
log("ALS lux = %d (orig lux=%d), last_lux=%d", lux, chip->als_info.lux, last_lux);
}
last_lux = lux;
tmd2755_update_als_threshold(chip, TMD2755_ENABLE_OFF);
} else {
tmd2755_update_als_threshold(chip, TMD2755_ENABLE_ON);
}
#else
if (chip->als_idev) {
rc = tmd2755_get_lux(chip); /* always returns 0 */
if (!rc) {
lux = chip->als_info.lux;
input_report_abs(chip->als_idev, ABS_MISC, lux);
input_sync(chip->als_idev);
dbg("ALS lux = %d", lux);
tmd2755_update_als_threshold(chip, TMD2755_ENABLE_OFF);
} else
tmd2755_update_als_threshold(chip, TMD2755_ENABLE_ON);
}
#endif
}
/*****************************************************************
* sysfs utility functions *
*****************************************************************/
static ssize_t tmd2755_als_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u8 idx, temp;
int val;
ssize_t ret = 0;
if(chip == NULL){
log("chip null");
return ret;
}else{
log("chip on");
}
for (idx = 0; idx < tmd2755_als_attrs_size; idx++) {
if (!strncmp(tmd2755_als_attrs[idx].attr.name, attr->attr.name, strlen(attr->attr.name))) {
if(NULL == chip){
dev_info(&chip->client->dev, "%*.*s():%*d --> lock = NULL\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
return ret;
}else{
AMS_MUTEX_LOCK(&chip->lock);
}
switch (idx) {
case ALS_ATIME_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d (~%d us)\n", chip->shadow[TMD2755_REG_ATIME],
(chip->shadow[TMD2755_REG_ATIME]+1)*INTEGRATION_CYCLE);
break;
case ALS_AWTIME_ATTR:
temp = (chip->shadow[TMD2755_REG_CFG0] & TMD2755_MASK_AWLONG) >> TMD2755_SHIFT_AWLONG;
/* if long bit is set, multiply by 12 */
val = (temp ? AWTIME_LONG_FACTOR : 1);
ret = scnprintf(buf, PAGE_SIZE, "%d (~%d us %s)\n", chip->shadow[TMD2755_REG_AWTIME],
(chip->shadow[TMD2755_REG_AWTIME]+1)*val*INTEGRATION_CYCLE,
val == AWTIME_LONG_FACTOR ? "<awlong bit set:12x>" : "<>");
break;
case ALS_AWLONG_ATTR:
temp = (chip->shadow[TMD2755_REG_CFG0] & TMD2755_MASK_AWLONG) >> TMD2755_SHIFT_AWLONG;
ret = scnprintf(buf, PAGE_SIZE, "%d\n", temp);
break;
case ALS_LUX_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->als_info.lux);
break;
case ALS_GAIN_ATTR:
if(NULL == chip){
log("chip null1");
return ret;
}
log("get als_gain params, 0x%x", chip->params.als_gain);
ret = scnprintf(buf, PAGE_SIZE, "%d (%dx)\n", chip->params.als_gain, tmd2755_convert_again(chip->params.als_gain));
break;
case ALS_CPL_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d (atime_us*again/DGF)\n", chip->als_info.counts_per_lux);
break;
case ALS_CH0_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->als_info.ch0_raw);
break;
case ALS_CH1_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->als_info.ch1_raw);
break;
case ALS_THRESH_DELTAP_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.als_deltaP);
break;
case ALS_AUTO_GAIN_ATTR:
ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->params.als_auto_gain);
break;
case ALS_LUX_COEFF_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "DGF = %d\nSCALE FACTOR = %d\nCOEFF_A = %d/1000\nCOEFF_B = %d\nCOEFF_C = %d/1000\nCOEFF_D = %d\n",
chip->params.dgf, chip->params.coef_scale, chip->params.ch0_coef0, chip->params.ch1_coef0,
chip->params.ch0_coef1, chip->params.ch1_coef1);
break;
case ALS_ENABLE_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->als_enable);
break;
case ALS_PERSIST_ATTR: /* see datasheet for pattern */
if (chip->params.persist.pers.apers >= 4)
val = 10 + ((chip->params.persist.pers.apers - 5) * 5);
else
val = chip->params.persist.pers.apers;
ret = scnprintf(buf, PAGE_SIZE, "%d (%d consecutive OOR)\n", chip->params.persist.pers.apers, val);
break;
case ALS_SATURATION_ATTR:
/* Determine if ALS is in saturation */
ret = scnprintf(buf, PAGE_SIZE, "%s\n", (chip->in_asat ? "ALS_Saturation" : "Normal_Operation"));
break;
case ALS_ADC_ATTR:
tmd2755_get_lux(chip);
ret = scnprintf(buf, PAGE_SIZE, "lux: %d, ch0: %d, ch1:%d\n", chip->als_info.lux,
chip->als_info.ch0_raw, chip->als_info.ch1_raw);
break;
default:
ret = scnprintf(buf, PAGE_SIZE, "not found\n");
break;
}
AMS_MUTEX_UNLOCK(&chip->lock);
break;
}
}
return ret;
}
/*****************************************************************
* sysfs utility functions *
*****************************************************************/
static ssize_t tmd2755_als_atime_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_atime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long atime;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &atime);
if (rc || (atime > ALS_TIME_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
log("atime value = %lu", atime);
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_ATIME, atime);
chip->params.als_time = chip->shadow[TMD2755_REG_ATIME];
tmd2755_calc_counts_per_lux(chip);
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_wtime_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_wtime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long awtime;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &awtime);
if (rc || (awtime > ALS_WTIME_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_AWTIME, awtime);
chip->params.als_wtime = chip->shadow[TMD2755_REG_AWTIME];
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_wlong_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_wlong_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long awlong;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &awlong);
if (rc || (awlong > ALS_WLONG_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_CFG0, TMD2755_MASK_AWLONG, (u8)(awlong << TMD2755_SHIFT_AWLONG));
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_lux_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
AMS_MUTEX_LOCK(&chip->lock);
tmd2755_read_als(chip);
tmd2755_get_lux(chip);
AMS_MUTEX_UNLOCK(&chip->lock);
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long again;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &again);
if (rc || ((again != ALS_GAIN_MIN) && (again != ALS_GAIN_MAX) && (again != ALS_GAIN_DEFAULT)))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_CFG1, TMD2755_MASK_AGAIN, (u8)(again << TMD2755_SHIFT_AGAIN));
chip->params.als_gain = (u8)again;
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_cpl_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_ch0_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_ch1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_deltaP_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_deltaP_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long deltaP;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &deltaP);
if (rc || (deltaP > ALS_DELTA_P_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
chip->params.als_deltaP = deltaP;
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_auto_gain_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_auto_gain_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long auto_gain;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, 10, &auto_gain);
/* if error on conversion, value greater than 1(true) */
if (rc || (auto_gain > 1))
return -EINVAL;
/* if its the same, no need to do any work. */
if (auto_gain == chip->params.als_auto_gain)
return size;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
chip->params.als_auto_gain = auto_gain;
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_lux_coef_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_lux_coef_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u32 dgf, ch0_coeff_0, ch1_coeff_0, ch0_coeff_1, ch1_coeff_1, coeff_scale;
if (sscanf(buf, "%10d,%10d,%10d,%10d,%10d,%10d", &dgf, &coeff_scale, &ch0_coeff_0, &ch1_coeff_0, &ch0_coeff_1, &ch1_coeff_1) != 6)
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
chip->params.dgf = dgf;
chip->params.coef_scale = coeff_scale;
chip->params.ch0_coef0 = ch0_coeff_0;
chip->params.ch0_coef1 = ch0_coeff_1;
chip->params.ch1_coef0 = ch1_coeff_0;
chip->params.ch1_coef1 = ch1_coeff_1;
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long enable;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, 10, &enable);
/* if error on conversion, or value greater than 1(true) */
if (rc || (enable > 1))
return -EINVAL;
/* if its the same, no need to do any work. */
if (enable == chip->als_enable)
return size;
AMS_MUTEX_LOCK(&chip->lock);
if (enable)
tmd2755_configure_als_mode(chip, TMD2755_FEATURE_ON);
else /* disable */
tmd2755_configure_als_mode(chip, TMD2755_FEATURE_OFF);
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_persist_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_persist_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long persist;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &persist);
if (rc || (persist > ALS_PERSIST_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
ams_i2c_modify(chip->client, chip->shadow,
TMD2755_REG_PERS, TMD2755_MASK_ALS_PERS, persist << TMD2755_SHIFT_ALS_PERS);
chip->params.persist.persistance = chip->shadow[TMD2755_REG_PERS];
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_als_sat_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_adc_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_als_show(dev, attr, buf);
}
static ssize_t tmd2755_als_adc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u32 ch0, ch1;
if (sscanf(buf, "%10d,%10d", &ch0, &ch1) != 2)
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
ALS_OFF();
chip->als_info.ch0_raw = ch0;
chip->als_info.ch1_raw = ch1;
ALS_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
struct device_attribute tmd2755_als_attrs[] = {
__ATTR(als_atime, 0664, tmd2755_als_atime_show, tmd2755_als_atime_store),
__ATTR(als_wtime, 0664, tmd2755_als_wtime_show, tmd2755_als_wtime_store),
__ATTR(als_wlong, 0664, tmd2755_als_wlong_show, tmd2755_als_wlong_store),
__ATTR(als_lux, 0444, tmd2755_als_lux_show, NULL),
__ATTR(als_gain, 0664, tmd2755_als_gain_show, tmd2755_als_gain_store),
__ATTR(als_cpl, 0444, tmd2755_als_cpl_show, NULL),
__ATTR(als_ch0, 0444, tmd2755_als_ch0_show, NULL),
__ATTR(als_ch1, 0444, tmd2755_als_ch1_show, NULL),
__ATTR(als_thresh_deltaP, 0664, tmd2755_als_deltaP_show, tmd2755_als_deltaP_store),
__ATTR(als_auto_gain, 0664, tmd2755_auto_gain_enable_show, tmd2755_auto_gain_enable_store),
__ATTR(als_lux_coef, 0664, tmd2755_lux_coef_show, tmd2755_lux_coef_store),
__ATTR(als_enable, 0664, tmd2755_als_enable_show, tmd2755_als_enable_store),
__ATTR(als_persist, 0664, tmd2755_als_persist_show, tmd2755_als_persist_store),
__ATTR(als_sat, 0444, tmd2755_als_sat_show, NULL),
__ATTR(regs, 0644, tmd2755_registers_show, tmd2755_registers_store),
__ATTR(als_adc, 0664, tmd2755_als_adc_show, tmd2755_als_adc_store),
};
int tmd2755_als_attrs_size = ARRAY_SIZE(tmd2755_als_attrs);

View File

@ -0,0 +1,187 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
#ifndef __AMS_TMD2755_ALS_H__
#define __AMS_TMD2755_ALS_H__
/* Debug flags for ALS specific */
// #define DEBUG_LUX
#define ALS_MAX_LUX_VAL (65535) /* (USHRT_MAX) */
#define ALS_FULL_SCALE_CNT (ALS_MAX_LUX_VAL)
#define ALS_ATIME_FOR_MAX_CNT (0x3F) /* this is the first atime value that maxes out the counts - full scale */
#define ALS_ATIME_INCREMENT_CNT (1024) /* each increase in atime, causes, this increase in full scale count */
#define ALS_GAIN_REG_VAL_16 (5) /* Bit value in register */
#define ALS_GAIN_16 (16) /* magnitude of gain */
#define ALS_GAIN_REG_VAL_128 (8) /* Bit value in register */
#define ALS_GAIN_128 (128) /* magnitude of gain */
#define ALS_GAIN_REG_VAL_1024 (11)
#define ALS_GAIN_1024 (1024)
#define ALS_COEFF_SCALE_FACTOR (1000) /* retrieved from DTS */
#define AWTIME_LONG_FACTOR (12)
/* This only works if the channel data is stored in consecutive registers */
#define ALS_NUM_CH (2) /* number of channels performing ALS */
#define ALS_CH_SIZE (sizeof(u8) * 2) /* 16 bit registers */
#define TMD2755_MAX_ALS_VALUE (0xFFFF) /* 16 bit */
#define TMD2755_MIN_ALS_VALUE (10)
#define TMD2755_THRESHOLD_PERCENT (200) /* equates to 0.5% */
#define TMD2755_SATURATION_THRESHOLD (9) /* 90% of max ALS count */
#define TMD2755_CH0_MAXIMUM (65535)
#define TMD2755_AUTO_GAIN_CLAMP_CNT (8)
#define TMD2755_SHIFT_MULT_BY_1024 (10)
/* fraction out of 10 */
#define TENTH_FRACTION_OF_VAL(v, x) ({ \
int __frac = v; \
if (((x) > 0) && ((x) < 10)) \
__frac = (__frac*(x)) / 10 ; \
__frac; \
})
#define ALS_ON() do { \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_ENABLE, TMD2755_AEN, TMD2755_AEN); \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_AIEN, TMD2755_AIEN); \
chip->als_enable = true; \
} while (0)
#define ALS_OFF() do { \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_AIEN, 0); \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_ENABLE, TMD2755_AEN, 0); \
chip->als_enable = false; \
} while (0)
/* Min/Max/Default Values for parameters */
/**********************************************************************************/
#define ALS_PERSIST_MIN (0)
#define ALS_PERSIST_MAX (0x0F)
#define ALS_PERSIST_DEFAULT (2)
#define ALS_GAIN_MIN (5) /* 16x */
#define ALS_GAIN_MAX (11) /* 1024x - only 5, 8 and 11 are acceptable values */
#define ALS_GAIN_DEFAULT (8) /* 128x */
#define ALS_AUTO_GAIN_MIN (0)
#define ALS_AUTO_GAIN_MAX (1)
#define ALS_AUTO_GAIN_DEFAULT (1)
/* Variation allowed in ALS to cause interrupt */
#define ALS_DELTA_P_MIN (0)
#define ALS_DELTA_P_MAX (20)
#define ALS_DELTA_P_DEFAULT (10)
#define ALS_TIME_MIN (0)
#define ALS_TIME_MAX (0xFF)
#define ALS_TIME_DEFAULT (0x3F)
#define ALS_WTIME_MIN (0)
#define ALS_WTIME_MAX (0xFF)
#define ALS_WTIME_DEFAULT (0)
#define ALS_WLONG_MIN (0)
#define ALS_WLONG_MAX (1)
#define ALS_WLONG_DEFAULT (0)
/* coefficient limits are assumed to be scaled */
/* Coefficients vary so placing a limit on them may be difficult */
/* to validate - While these values are here, the actual values */
/* read in from the DT overlay are not boundary checked */
/* Device & Glass Factor */
#define ALS_DGF_MIN (0)
#define ALS_DGF_MAX (200)
#define ALS_DGF_DEFAULT (123)
/* Coeff A */
#define ALS_CH0_COEFF0_MIN (0)
#define ALS_CH0_COEFF0_MAX (1000)
#define ALS_CH0_COEFF0_DEFAULT (1000)
/* Coeff B */
#define ALS_CH1_COEFF0_MIN (0)
#define ALS_CH1_COEFF0_MAX (1000)
#define ALS_CH1_COEFF0_DEFAULT (1427)
/* Coeff C */
#define ALS_CH0_COEFF1_MIN (0)
#define ALS_CH0_COEFF1_MAX (1000)
#define ALS_CH0_COEFF1_DEFAULT (849)
/* Coeff D */
#define ALS_CH1_COEFF1_MIN (0)
#define ALS_CH1_COEFF1_MAX (1000)
#define ALS_CH1_COEFF1_DEFAULT (834)
#define ALS_COEFF_SCALE_MIN (1)
#define ALS_COEFF_SCALE_MAX (1000)
#define ALS_COEFF_SCALE_DEFAULT (1000)
/*
* This must match the order of ATTR defined in
* struct device_attribute tmd2755_als_attrs[]
* in ams_tmd2755_als.c
*/
enum tmd2755_als_attrs {
ALS_ATIME_ATTR,
ALS_AWTIME_ATTR,
ALS_AWLONG_ATTR,
ALS_LUX_ATTR,
ALS_GAIN_ATTR,
ALS_CPL_ATTR,
ALS_CH0_ATTR,
ALS_CH1_ATTR,
ALS_THRESH_DELTAP_ATTR,
ALS_AUTO_GAIN_ATTR,
ALS_LUX_COEFF_ATTR,
ALS_ENABLE_ATTR,
ALS_PERSIST_ATTR,
ALS_SATURATION_ATTR,
ALS_ADC_ATTR,
};
extern struct device_attribute tmd2755_als_attrs[];
extern int tmd2755_als_attrs_size;
int tmd2755_configure_als_mode(struct tmd2755_chip *chip, u8 state);
int tmd2755_read_als(struct tmd2755_chip *chip);
void tmd2755_report_als(struct tmd2755_chip *chip);
extern ssize_t tmd2755_registers_show(struct device *dev, struct device_attribute *attr, char *buf);
extern ssize_t tmd2755_registers_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size);
extern void light_polling_work_assing(void);
#endif // __AMS_TMD2755_ALS_H__

View File

@ -0,0 +1,106 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
/*
* This file is meant to be used as defensive programming to protect invalid
* values passed in via the DTS overlay. Only include this file once in the entire
* project. Include it in the source file that reads the DTS database.
*/
#pragma once
#define CHECK_LIMITS(val, y) ({ \
s32 ret_val = val; \
if ((val < y.min) || (val > y.max)) { \
ret_val = y.def; \
printk(KERN_WARNING "WARNING: Default parameter value being used: %s (attempted val=%d min=%d max=%d def=%d)\n", y.name, val, y.min, y.max, y.def); \
} \
ret_val; \
})
enum dts_parameters {
PROX_PERIST_CFG,
PROX_THRESH_MIN_CFG,
PROX_THRESH_MAX_CFG,
PROX_PULSE_CNT_CFG,
PROX_APC_CFG,
PROX_PULSE_LEN_CFG,
PROX_GAIN_1_CFG,
PROX_GAIN_2_CFG,
PROX_OFFSET_CFG,
PROX_DRIVE_CFG,
PROX_TIME_CFG,
PROX_WTIME_CFG,
/*********************/
ALS_PERSIST_CFG,
ALS_GAIN_CFG,
ALS_AUTO_GAIN_CFG,
ALS_DELTA_P_CFG,
ALS_TIME_CFG,
ALS_WTIME_CFG,
ALS_DGF_CFG,
ALS_CH0_COEFF0_CFG,
ALS_CH1_COEFF0_CFG,
ALS_CH0_COEFF1_CFG,
ALS_CH1_COEFF1_CFG,
ALS_COEFF_SCALE_CFG,
};
static struct {
s32 min;
s32 max;
s32 def;
char *name;
} tmd2755_cfg_limits[] = {
/********************************** PROX *******************************************************/
[PROX_PERIST_CFG] = {PROX_PERSIST_MIN, PROX_PERSIST_MAX, PROX_PERSIST_DEFAULT, "ppersist"},
[PROX_THRESH_MIN_CFG] = {PROX_THRESH_MIN, PROX_THRESH_MAX, PROX_THRESH_DEFAULT, "pmin_thresh"},
[PROX_THRESH_MAX_CFG] = {PROX_THRESH_MIN, PROX_THRESH_MAX, PROX_THRESH_DEFAULT, "pmax_thresh"},
[PROX_PULSE_CNT_CFG] = {PROX_PULSE_CNT_MIN, PROX_PULSE_CNT_MAX, PROX_PULSE_CNT_DEFAULT, "ppulse_cnt"},
[PROX_APC_CFG] = {PROX_APC_MIN, PROX_APC_MAX, PROX_APC_DEFAULT, "papc"},
[PROX_PULSE_LEN_CFG] = {PROX_PULSE_LEN_MIN, PROX_PULSE_LEN_MAX, PROX_PULSE_LEN_DEFAULT, "ppulse_len"},
[PROX_GAIN_1_CFG] = {PROX_GAIN_MIN, PROX_GAIN_MAX, PROX_GAIN_DEFAULT, "pgain_1"},
[PROX_GAIN_2_CFG] = {PROX_GAIN_MIN, PROX_GAIN_MAX, PROX_GAIN_DEFAULT, "pgain_2"}, /* cannot be 2 */
[PROX_OFFSET_CFG] = {PROX_OFFSET_MIN, PROX_OFFSET_MAX, PROX_OFFSET_DEFAULT, "poffset"},
[PROX_DRIVE_CFG] = {PROX_DRIVE_MIN, PROX_DRIVE_MAX, PROX_DRIVE_DEFAULT, "pdrive"},
[PROX_TIME_CFG] = {PROX_TIME_MIN, PROX_TIME_MAX, PROX_TIME_DEFAULT, "ptime"},
[PROX_WTIME_CFG] = {PROX_WTIME_MIN, PROX_WTIME_MAX, PROX_WTIME_DEFAULT, "pwtime"},
/****************************************************************************************************/
/********************************** ALS *******************************************************/
[ALS_PERSIST_CFG] = {ALS_PERSIST_MIN, ALS_PERSIST_MAX, ALS_PERSIST_DEFAULT, "apers"},
[ALS_GAIN_CFG] = {ALS_GAIN_MIN, ALS_GAIN_MAX, ALS_GAIN_DEFAULT, "als_gain"}, /* 5, 8 or 11 */
[ALS_AUTO_GAIN_CFG] = {ALS_AUTO_GAIN_MIN, ALS_AUTO_GAIN_MAX, ALS_AUTO_GAIN_DEFAULT, "als_auto_gain"},
[ALS_DELTA_P_CFG] = {ALS_DELTA_P_MIN, ALS_DELTA_P_MAX, ALS_DELTA_P_DEFAULT, "als_deltap"},
[ALS_TIME_CFG] = {ALS_TIME_MIN, ALS_TIME_MAX, ALS_TIME_DEFAULT, "als_time"},
[ALS_WTIME_CFG] = {ALS_WTIME_MIN, ALS_WTIME_MAX, ALS_WTIME_DEFAULT, "als_wtime"},
[ALS_DGF_CFG] = {ALS_DGF_MIN, ALS_DGF_MAX, ALS_DGF_DEFAULT, "dgf"},
[ALS_CH0_COEFF0_CFG] = {ALS_CH0_COEFF0_MIN, ALS_CH0_COEFF0_MAX, ALS_CH0_COEFF0_DEFAULT, "ch0_coef0"},
[ALS_CH1_COEFF0_CFG] = {ALS_CH1_COEFF0_MIN, ALS_CH1_COEFF0_MAX, ALS_CH1_COEFF0_DEFAULT, "ch1_coef0"},
[ALS_CH0_COEFF1_CFG] = {ALS_CH0_COEFF1_MIN, ALS_CH0_COEFF1_MAX, ALS_CH0_COEFF1_DEFAULT, "ch0_coef1"},
[ALS_CH1_COEFF1_CFG] = {ALS_CH1_COEFF1_MIN, ALS_CH1_COEFF1_MAX, ALS_CH1_COEFF1_DEFAULT, "ch1_coef1"},
[ALS_COEFF_SCALE_CFG] = {ALS_COEFF_SCALE_MIN, ALS_COEFF_SCALE_MAX, ALS_COEFF_SCALE_DEFAULT, "coef_scale"},
/****************************************************************************************************/
};

View File

@ -0,0 +1,863 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
/*! \file
* \brief Device driver for monitoring ambient light intensity in (lux)
* proximity detection (prox) functionality within the
* AMS TMD2755 family of devices.
*/
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ams_tmd2755.h"
#include "ams_tmd2755_prox.h"
#include "ams_i2c.h"
/******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_tmd2755"
#define SENSOR_TYPE_NAME "ALSPS"
#undef dbg
#ifdef ASH_GPIO_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s]"fmt,MODULE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
extern struct tmd2755_chip *g_tmd2755_chip;
/*********************************/
/*****************************************************************
* Local globals for prox module *
*****************************************************************/
/*****************************************************************
* Utility Calls *
*****************************************************************/
void tmd2755_read_poffset(struct tmd2755_chip *chip){
ams_i2c_blk_read(chip->client, TMD2755_REG_POFFSET_L, &chip->shadow[TMD2755_REG_POFFSET_L], 2);
chip->params.poffset = chip->shadow[TMD2755_REG_POFFSET_L];
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Optical Xtalk calib complete(poffsetl=%d, poffseth=%d, ore=%d, ore_en=%d)\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, chip->params.poffset,
chip->shadow[TMD2755_REG_POFFSET_H] & TMD2755_MASK_POFFSET_H, chip->shadow[TMD2755_REG_CALIB_OFF] & TMD2755_MASK_ORE,
(chip->shadow[TMD2755_REG_CALIB_OFF] & TMD2755_MASK_ENABLE_ORE) > TMD2755_SHIFT_ENABLE_ORE);
if (chip->shadow[TMD2755_REG_POFFSET_H] & TMD2755_MASK_POFFSET_H)
chip->params.poffset *= -1;
}
EXPORT_SYMBOL(tmd2755_read_poffset);
static void tmd2755_write_poffset(struct tmd2755_chip *chip){
u8 *sh = chip->shadow;
if(chip->params.poffset >= 0){
ams_i2c_write(chip->client, sh, TMD2755_REG_POFFSET_H, 0);
ams_i2c_write(chip->client, sh, TMD2755_REG_POFFSET_L, chip->params.poffset);
log("wrote offset = %d", chip->params.poffset);
}else{
ams_i2c_write(chip->client, sh, TMD2755_REG_POFFSET_H, 1);
ams_i2c_write(chip->client, sh, TMD2755_REG_POFFSET_L, -chip->params.poffset);
log("wrote -offset = %d", chip->params.poffset);
}
log("set offset = %d", chip->params.poffset);
}
void tmd2755_read_prox(struct tmd2755_chip *chip)
{
/* Read low and high bytes - 14 bits */
ams_i2c_blk_read(chip->client, TMD2755_REG_PDATAL, &chip->shadow[TMD2755_REG_PDATAL], sizeof(chip->prox_info.raw));
if (chip->params.prox_apc == 0) {
chip->prox_info.raw = le16_to_cpu(*((const __le16 *)&chip->shadow[TMD2755_REG_PDATAL]));
}else{
//8bit pdata
chip->prox_info.raw = chip->shadow[TMD2755_REG_PDATAL];
}
tmd2755_read_poffset(chip);
return;
}
static void tmd2755_get_prox(struct tmd2755_chip *chip)
{
u8 *sh = chip->shadow;
//#if defined(DEBUG_PROX_FEATURE)
dev_dbg(&chip->client->dev, "%*.*s():%*d --> \t\tcurrent state: %s Raw: %d Min Thresh: %d Max Thresh:%d, offset =%d\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__,
chip->prox_info.detected ? "<Detect>" : "<Release>", chip->prox_info.raw,
le16_to_cpu(*((const __le16 *)&sh[TMD2755_REG_PILTL])), le16_to_cpu(*((const __le16
*)&sh[TMD2755_REG_PIHTL])), chip->params.poffset);
//#endif
dbg("threshold %d, %d", chip->params.prox_thresh_min, chip->params.prox_thresh_max);
dbg("chip->prox_info.detected=%d, chip->prox_info.raw=%d", chip->prox_info.detected, chip->prox_info.raw);
if (chip->prox_info.raw >= chip->params.prox_thresh_max) {
chip->prox_info.detected = true;
log("new state: <Detect>, New Threshold limits = [%d, %d], offset=%d",
chip->params.prox_thresh_min, PROX_THRESH_MAX, chip->params.poffset);
/*If proximity is detected, set the lower limit to find */
/* proximity release and set the higher limit to avoid */
/* repeated interrupts. */
if (chip->params.prox_apc == 0) {
// apc --> 0 means APC is ENABLED
ams_i2c_write(chip->client, sh, TMD2755_REG_PILTL,
(chip->params.prox_thresh_min & TMD2755_MASK_PILTL));
ams_i2c_write(chip->client, sh, TMD2755_REG_PILTH,
((chip->params.prox_thresh_min >> 8) & TMD2755_MASK_PILTH));
ams_i2c_write(chip->client, sh, TMD2755_REG_PIHTL,
(PROX_THRESH_MAX & TMD2755_MASK_PIHTL));
ams_i2c_write(chip->client, sh, TMD2755_REG_PIHTH,
((PROX_THRESH_MAX >> 8) & TMD2755_MASK_PIHTH));
} else {
// apc --> 1 means APC is DISABLED
// The PIxTH register is ignored and
// and the PIxTL is compared to the upper 8 bits of pdata
ams_i2c_write(chip->client, sh, TMD2755_REG_PILTL,
((chip->params.prox_thresh_min >> 6) & TMD2755_MASK_PIHTL));
ams_i2c_write(chip->client, sh, TMD2755_REG_PILTH, 0);
ams_i2c_write(chip->client, sh, TMD2755_REG_PIHTL,
((PROX_THRESH_MAX >> 6) & 0xFF));
ams_i2c_write(chip->client, sh, TMD2755_REG_PIHTH, 0);
}
} else if (chip->prox_info.raw <= chip->params.prox_thresh_min) {
chip->prox_info.detected = false;
log("new state: <Release>, offset=%d", chip->params.poffset);
/* If proximity is released, set the higher limit to find */
/* proximity and set the lower limit to avoid repeated interrupts */
/* This is same as the init state */
tmd2755_init_prox_mode(chip);
}else{
log("Lose condition, raw=%d, min=%d, max=%d", chip->prox_info.raw,
chip->params.prox_thresh_min, chip->params.prox_thresh_max);
}
//Since chip may send two times INT for near case,
//clear psensor int flag again after set new threshold
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_STATUS,
TMD2755_INT_ST_PRX_IRQ, TMD2755_INT_ST_PRX_IRQ);
return;
}
/*
* Value Meaning
* 0. Prox release event
* 1. Prox detect event
* 2. Prox saturation event
*/
void tmd2755_prox_report_inp_event(struct tmd2755_chip *chip, int value)
{
#ifdef REMOVE_INPUT_DEVICE
proximity_work(value? ALSPS_INT_PS_CLOSE : ALSPS_INT_PS_AWAY);
#else
if (chip->prox_idev) {
input_report_abs(chip->prox_idev, ABS_DISTANCE, value);
input_sync(chip->prox_idev);
}
#endif
return;
}
void tmd2755_process_prox_irq(struct tmd2755_chip *chip)
{
tmd2755_read_prox(chip);
tmd2755_get_prox(chip);
tmd2755_prox_report_inp_event(chip, chip->prox_info.detected ? 1 : 0);
return;
}
void tmd2755_process_saturation_event(struct tmd2755_chip *chip)
{
tmd2755_prox_report_inp_event(chip, PROX_SAT_EVENT);
/* Disable PSAT interrupt otherwise the processor will be over-burdened processing */
/* saturation interrupts */
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_PSIEN, 0);
return;
}
void tmd2755_init_prox_mode(struct tmd2755_chip *chip)
{
/* Init Low threshold to 0 - Only looking for Detect events after init */
log("Setting Initial Thresholds = [%d, %d], (low=%d), offset=%d", MIN_PROX_THRESHOLD,
chip->params.prox_thresh_max, chip->params.prox_thresh_min, chip->params.poffset);
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTL, MIN_PROX_THRESHOLD);
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTH, MIN_PROX_THRESHOLD);
chip->prox_info.raw = 0;
if (chip->params.prox_apc == PROX_APC_ENABLED) {
// apc == 0 means APC is ENABLED
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTL, (chip->params.prox_thresh_max & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTH, ((chip->params.prox_thresh_max >> 8) & TMD2755_MASK_PIHTH));
} else {
// apc == 1 means APC is DISABLED, only 8 MSB of PITH are used - threshold is only 14 bit number (i.e. right shift 6)
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTL, ((chip->params.prox_thresh_max >> 6) & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTH, 0);
}
/* Enable PSAT interrupt during init or after release event */
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_PSIEN, TMD2755_PSIEN);
return;
}
int tmd2755_offset_calibration(struct tmd2755_chip *chip)
{
u8 *sh = chip->shadow;
u8 saveenab, saveint;
int ret;
unsigned long wt;
static int time=1;
/* clean up the sync mechanism between here and ISR */
reinit_completion(&(chip->calibration_done));
/* save PEN state */
ams_i2c_read(chip->client, TMD2755_REG_ENABLE, &saveenab);
/* save prox intr state */
ams_i2c_read(chip->client, TMD2755_REG_INTENAB, &saveint);
/* turn on power, disable prox */
ams_i2c_modify(chip->client, sh, TMD2755_REG_ENABLE, TMD2755_PEN | TMD2755_PON, TMD2755_PON);
/* enable calib intr, disable prox intr */
ams_i2c_modify(chip->client, sh, TMD2755_REG_INTENAB, TMD2755_PIEN | TMD2755_CIEN, TMD2755_CIEN);
/*
** Prox Offset calibration
** binsrch_target (15 counts)
** prox averaging (2 reading window)
** prox_auto_offset_adjust
*/
ams_i2c_modify(chip->client, sh, TMD2755_REG_CALIBCFG,
TMD2755_MASK_BINSRCH_TARGET | TMD2755_MASK_PROX_AUTO_OFFSET_ADJUST | TMD2755_MASK_PROX_DATA_AVG,
(PROX_BINSRCH_TARGET_VALUE << TMD2755_SHIFT_BINSRCH_TARGET) | (PROX_AUTO_OFFSET_ADJ_VAL << TMD2755_SHIFT_PROX_AUTO_OFFSET_ADJUST) |
(PROX_AVG_VAL << TMD2755_SHIFT_PROX_DATA_AVG));
/*
** Calibration Offset
** enable offset range extension
** set ORE to PROX_ORE_VAL
*/
/*
ams_i2c_modify(chip->client, sh, TMD2755_REG_CALIB_OFF,
TMD2755_MASK_ENABLE_ORE | TMD2755_MASK_ORE,
(PROX_ORE_EN << TMD2755_SHIFT_ENABLE_ORE) | (PROX_ORE_VAL << TMD2755_SHIFT_ORE));
*/
/*
* CALAVG: Enable to allow HW averaging
* ELEC_CALIB: perform both electrical and optical - default
* CALPRATE: Enables PRATE during calibration
*/
//ams_i2c_modify(chip->client, sh, TMD2755_REG_CALIB, TMD2755_MASK_CALAVG_CALIB | TMD2755_MASK_CALPRATE_CALIB,
// (PROX_HWAVG_CAL << TMD2755_SHIFT_CALAVG_CALIB) | (PROX_PRATE_CAL << TMD2755_SHIFT_CALPRATE_CALIB));
ams_i2c_modify(chip->client, sh, TMD2755_REG_CALIB, TMD2755_MASK_CALPRATE_CALIB,
(PROX_PRATE_CAL << TMD2755_SHIFT_CALPRATE_CALIB));
/* trigger calibration sequence */
dev_info(&chip->client->dev, "%*.*s():%*d --> offset calibration started (waiting for completion).\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__);
chip->amsCalComplete = false;
chip->in_calib = true;
ams_i2c_modify(chip->client, sh, TMD2755_REG_CALIB, TMD2755_MASK_START_OFFSET_CALIB, (0x01 << TMD2755_SHIFT_START_OFFSET_CALIB));
/* wait for ISR to signal calibration int complete */
AMS_MUTEX_UNLOCK(&chip->lock);
wt = wait_for_completion_interruptible_timeout(&(chip->calibration_done), msecs_to_jiffies(PROX_CALIB_TIMEOUT_MS*(time)));
AMS_MUTEX_LOCK(&chip->lock);
if (wt <= 0) {
dev_info(&chip->client->dev, "%*.*s():%*d --> Proximity Calibration timeout occurred: %lu\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, wt);
ret = -1;
tmd2755_read_poffset(chip);
} else {
ret = 0;
chip->in_calib = false;
chip->amsCalComplete = true;
/* get updated prox offset */
tmd2755_read_poffset(chip);
}
/* Restore register enable and interrupt enable */
ams_i2c_modify(chip->client, sh, TMD2755_REG_ENABLE, TMD2755_PEN, saveenab);
ams_i2c_modify(chip->client, sh, TMD2755_REG_INTENAB, TMD2755_PIEN, saveint);
return ret;
}
int tmd2755_configure_prox_mode(struct tmd2755_chip *chip, u8 state)
{
struct i2c_client *client = chip->client;
u8 *sh = chip->shadow;
dev_dbg(&chip->client->dev, "%*.*s():%*d --> Configuring Prox Mode %s\n",
MIN_KERNEL_LOG_LEN, MAX_KERNEL_LOG_LEN, __func__, LINE_NUM_KERNEL_LOG_LEN, __LINE__, state ? "ON" : "OFF");
/* Turning on prox */
if (state) {
/* Configure default proximity settings - thresholds */
tmd2755_init_prox_mode(chip);
if(chip->cal_en){
tmd2755_offset_calibration(chip);
}else{
log("use previous offset=%d", chip->params.poffset);
if(chip->params.poffset <= 0){
chip->params.poffset = TMD2755_PROXIMITY_OFFSET_DEFAULT;
}
tmd2755_write_poffset(chip);
}
ams_i2c_modify(client, sh, TMD2755_REG_PERS, TMD2755_MASK_PROX_PERS, chip->params.persist.persistance & TMD2755_MASK_PROX_PERS);
ams_i2c_write(client, sh, TMD2755_REG_PCFG2, (chip->params.prox_pulse_len & TMD2755_MASK_PPULSE_LEN_L));
ams_i2c_modify(client, sh, TMD2755_REG_PCFG1, TMD2755_MASK_REG_PPULSE_LEN_H,
(chip->params.prox_pulse_len & TMD2755_MASK_DATA_PPULSE_LEN_H) >> TMD2755_SHIFT_PPULSE_LEN_H);
/* PGAIN2 */
ams_i2c_modify(client, sh, TMD2755_REG_CFG1, TMD2755_MASK_PGAIN2, (chip->params.prox_gain2 << TMD2755_SHIFT_PGAIN2));
/* PGAIN1 */
ams_i2c_modify(client, sh, TMD2755_REG_PCFG0, TMD2755_MASK_PGAIN1, (chip->params.prox_gain1 << TMD2755_SHIFT_PGAIN1));
/* PRATE defaults to 0x1F */
ams_i2c_write(client, sh, TMD2755_REG_PRATE, chip->params.prox_time/* P_TIME_US(INTEGRATION_CYCLE) */);
/* PWTIME */
ams_i2c_write(client, sh, TMD2755_REG_PWTIME, chip->params.prox_wtime);
/* Enable Proximity and Proximity Interrupt */
/* PWEN is required to be enabled if ALS feature is enabled */
/* By default, enable PWTIME with Bit 4 in REG_ENABLE */
//ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PWEN | TMD2755_PEN | TMD2755_PON, TMD2755_PWEN | TMD2755_PEN | TMD2755_PON);
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PWEN | TMD2755_PEN | TMD2755_PON, 0| TMD2755_PEN | TMD2755_PON);
/* Enable Prox interrupt, saturation interrupt and zero detect interrupt */
ams_i2c_modify(client, sh, TMD2755_REG_INTENAB, TMD2755_PIEN | TMD2755_PSIEN | TMD2755_ZIEN,
TMD2755_PIEN | TMD2755_PSIEN | TMD2755_ZIEN);
chip->prox_enable = true;
chip->prox_info.detected = true;
chip->prox_info.raw = 0;
} else {
chip->params.poffset_last = chip->params.poffset;
/* Turning off prox */
/* Disable Proximity feature, and all interrupts associated with prox */
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PEN, 0);
ams_i2c_modify(client, sh, TMD2755_REG_INTENAB, TMD2755_PROX_INTS, 0);
/* If nothing else is enabled set PON = 0 */
if (!(sh[TMD2755_REG_ENABLE] & TMD2755_EN_ALL))
ams_i2c_modify(client, sh, TMD2755_REG_ENABLE, TMD2755_PON, 0x00);
chip->prox_enable = false;
}
return 0;
}
void tmd2755_offset_recalibration(void){
struct tmd2755_chip *chip = g_tmd2755_chip;
AMS_MUTEX_LOCK(&chip->lock);
tmd2755_offset_calibration(chip);
AMS_MUTEX_UNLOCK(&chip->lock);
}
/*****************************************************************
* sysfs utility functions *
*****************************************************************/
static ssize_t tmd2755_prox_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u8 idx;
ssize_t ret = 0;
for (idx = 0; idx < tmd2755_prox_attrs_size; idx++) {
if (!strncmp(tmd2755_prox_attrs[idx].attr.name, attr->attr.name, strlen(attr->attr.name))) {
AMS_MUTEX_LOCK(&chip->lock);
switch (idx) {
case PROX_RAW_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->prox_info.raw);
break;
case PROX_GAIN1_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_gain1);
break;
case PROX_GAIN2_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_gain2);
break;
case PROX_OFFSET_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.poffset);
break;
case PROX_PERSIST_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.persist.pers.ppers);
break;
case PROX_PULSE_LEN_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_pulse_len);
break;
case PROX_ENABLE_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->prox_enable);
break;
case PROX_TIME_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_time);
break;
case PROX_WTIME_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_wtime);
break;
case PROX_LOW_THRESH_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_thresh_min);
break;
case PROX_HIGH_THRESH_ATTR:
ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->params.prox_thresh_max);
break;
case PROX_SATURATION_ATTR:
/* Determine if prox is in saturation */
ret = scnprintf(buf, PAGE_SIZE, "%s\n",
(chip->in_psat == PROX_NO_SAT ? "Normal_Operation" :
(chip->in_psat == PROX_AMBIENT_SAT ? "Ambient_Saturation" : "Reflective_Saturation")));
break;
default:
ret = scnprintf(buf, PAGE_SIZE, "not found\n");
break;
}
AMS_MUTEX_UNLOCK(&chip->lock);
break;
}
}
return ret;
}
/*****************************************************************
* ABI FUNCTIONS - sysfs callbacks *
*****************************************************************/
static ssize_t tmd2755_prox_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
/* populates the prox_info structure */
tmd2755_read_prox(chip);
/* Use scnprintf() */
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_detected_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u8 val;
/* if prox INT is enabled, just grab the data flag that is defined in prox_info */
/* Otherwise read the prox */
ams_i2c_read(chip->client, TMD2755_REG_INTENAB, &val);
if (!(val & TMD2755_PIEN)) {
tmd2755_read_prox(chip);
tmd2755_get_prox(chip);
}
return scnprintf(buf, PAGE_SIZE, "%s\n", chip->prox_info.detected ? "detected" : "released");
}
/* gains */
/* stage 1 - */
static ssize_t tmd2755_prox_gain1_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_gain1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long gain;
struct tmd2755_chip *chip = g_tmd2755_chip;
int rc;
rc = kstrtoul(buf, BASE_10, &gain);
if (rc || (gain > PROX_GAIN_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
rc = ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_PCFG0, TMD2755_MASK_PGAIN1, gain << TMD2755_SHIFT_PGAIN1);
chip->params.prox_gain1 = gain;
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
/* stage 2 - proximity IR sensor */
static ssize_t tmd2755_prox_gain2_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_gain2_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long gain;
struct tmd2755_chip *chip = g_tmd2755_chip;
int rc;
rc = kstrtoul(buf, BASE_10, &gain);
if (rc || (gain > PROX_GAIN_MAX) || (gain == 2)) /* 2 is a reserved value for pgain2 */
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
rc = ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_CFG1, TMD2755_MASK_PGAIN2, gain << TMD2755_SHIFT_PGAIN2);
chip->params.prox_gain2 = gain;
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_offset_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long offset;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &offset);
log("apply offset = %d, input=%s", chip->params.poffset, buf);
chip->params.poffset = offset;
return size;
}
static ssize_t tmd2755_prox_persist_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_persist_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long persist;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &persist);
if (rc || (persist > PROX_PERSIST_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
ams_i2c_modify(chip->client, chip->shadow,
TMD2755_REG_PERS, TMD2755_MASK_PROX_PERS, persist << TMD2755_SHIFT_PROX_PERS);
chip->params.persist.persistance = chip->shadow[TMD2755_REG_PERS];
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_pulse_len_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_pulse_len_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long pulse_len;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &pulse_len);
if (rc || (pulse_len < PROX_PULSE_LEN_MIN) || (pulse_len > PROX_PULSE_LEN_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
/* pulse length is 10 bits: 8 bits in PCFG2 and 2 MSBs in PCFG1 */
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PCFG2, (pulse_len & TMD2755_MASK_PPULSE_LEN_L));
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_PCFG1, TMD2755_MASK_REG_PPULSE_LEN_H,
(pulse_len & TMD2755_MASK_DATA_PPULSE_LEN_H) >> TMD2755_SHIFT_PPULSE_LEN_H);
chip->params.prox_pulse_len = pulse_len;
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_time_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long prate;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &prate);
if (rc || (prate > PROX_TIME_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
ams_i2c_write(chip->client, chip->shadow,
TMD2755_REG_PRATE, prate);
chip->params.prox_time = chip->shadow[TMD2755_REG_PRATE];
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_wtime_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_wtime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long pwtime;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &pwtime);
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
ams_i2c_write(chip->client, chip->shadow,
TMD2755_REG_PWTIME, pwtime);
chip->params.prox_wtime = chip->shadow[TMD2755_REG_PWTIME];
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long enable;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, 10, &enable);
/* if error on conversion, value greater than 1(true) */
if (rc || (enable > 1))
return -EINVAL;
/* if its the same, no need to do any work. */
if (enable == chip->prox_enable)
return size;
AMS_MUTEX_LOCK(&chip->lock);
if (enable)
tmd2755_configure_prox_mode(chip, TMD2755_FEATURE_ON);
else /* disable */
tmd2755_configure_prox_mode(chip, TMD2755_FEATURE_OFF);
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_low_thresh_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_low_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long low_thresh;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &low_thresh);
if (rc || (low_thresh > PROX_THRESH_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
if (chip->params.prox_apc == PROX_APC_ENABLED) {
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTL, (low_thresh & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTH, ((low_thresh >> 8) & TMD2755_MASK_PILTH));
chip->params.prox_thresh_min = low_thresh;
} else {
/* apc == 1 means APC is DISABLED, only 8 MSB of PILT are used - threshold is only 14 bit number (i.e. right shift 6) */
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTL, ((low_thresh >> 6) & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PILTH, 0);
chip->params.prox_thresh_min = low_thresh/64;
}
log("APC disable, thresh_min=%d", chip->params.prox_thresh_min);
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_high_thresh_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
static ssize_t tmd2755_prox_high_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
unsigned long high_thresh;
int rc;
struct tmd2755_chip *chip = g_tmd2755_chip;
rc = kstrtoul(buf, BASE_10, &high_thresh);
if (rc || (high_thresh > PROX_THRESH_MAX))
return -EINVAL;
AMS_MUTEX_LOCK(&chip->lock);
PROX_OFF();
if (chip->params.prox_apc == PROX_APC_ENABLED) {
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTL, (high_thresh & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTH, ((high_thresh >> 8) & TMD2755_MASK_PIHTH));
chip->params.prox_thresh_max = high_thresh;
} else {
/* apc == 1 means APC is DISABLED, only 8 MSB of PIHT are used - threshold is only 14 bit number (i.e. right shift 6) */
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTL, ((high_thresh >> 6) & 0xFF));
ams_i2c_write(chip->client, chip->shadow, TMD2755_REG_PIHTH, 0);
chip->params.prox_thresh_max = high_thresh/64;
}
log("APC disable, thresh_max=%d", chip->params.prox_thresh_max);
PROX_ON();
AMS_MUTEX_UNLOCK(&chip->lock);
return size;
}
static ssize_t tmd2755_prox_regs_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct tmd2755_chip *chip = g_tmd2755_chip;
u8 rEnable = 0, rPrate = 0, rPiltl = 0, rPilth = 0;
u8 rPihtl = 0, rPihth = 0, rPers = 0, rCfg0 = 0;
u8 rPcfg0 = 0, rCfg1 = 0, rStatus = 0, rPcfg1 = 0;
u8 rCfg8 = 0, rCfg3 = 0, rCfg6 = 0, rIntenab = 0;
u8 rPwtime = 0, rCalib = 0, rCalOff = 0, rCalcfg = 0;
u8 rPcfg2 = 0, rCalstat = 0;
ams_i2c_read(chip->client, TMD2755_REG_ENABLE, &rEnable);
ams_i2c_read(chip->client, TMD2755_REG_PRATE, &rPrate);
ams_i2c_read(chip->client, TMD2755_REG_PILTL, &rPiltl);
ams_i2c_read(chip->client, TMD2755_REG_PILTH, &rPilth);
ams_i2c_read(chip->client, TMD2755_REG_PIHTL, &rPihtl);
ams_i2c_read(chip->client, TMD2755_REG_PIHTH, &rPihth);
ams_i2c_read(chip->client, TMD2755_REG_PERS, &rPers);
ams_i2c_read(chip->client, TMD2755_REG_CFG0, &rCfg0);
ams_i2c_read(chip->client, TMD2755_REG_CFG1, &rCfg1);
ams_i2c_read(chip->client, TMD2755_REG_CFG8, &rCfg8);
ams_i2c_read(chip->client, TMD2755_REG_CFG3, &rCfg3);
ams_i2c_read(chip->client, TMD2755_REG_CFG6, &rCfg6);
ams_i2c_read(chip->client, TMD2755_REG_PCFG0, &rPcfg0);
ams_i2c_read(chip->client, TMD2755_REG_PCFG1, &rPcfg1);
ams_i2c_read(chip->client, TMD2755_REG_PCFG2, &rPcfg2);
ams_i2c_read(chip->client, TMD2755_REG_STATUS, &rStatus);
ams_i2c_read(chip->client, TMD2755_REG_PWTIME, &rPwtime);
ams_i2c_read(chip->client, TMD2755_REG_INTENAB, &rIntenab);
/* Calibration Registers */
ams_i2c_read(chip->client, TMD2755_REG_CALIB, &rCalib);
ams_i2c_read(chip->client, TMD2755_REG_CALIB_OFF, &rCalOff);
ams_i2c_read(chip->client, TMD2755_REG_CALIBCFG, &rCalcfg);
ams_i2c_read(chip->client, TMD2755_REG_CALIBSTAT, &rCalstat);
return scnprintf(buf, PAGE_SIZE,
"ENABLE = 0x%02X\nPRATE = 0x%02X\nPILT = 0x%04X\nPIHT = 0x%04X\n"
"PERS = 0x%02X\nPCFG0 = 0x%02X\nPCFG1 = 0x%02X\nPCFG2 = 0x%02X\n"
"CFG0 = 0x%02X\nCFG1 = 0x%02X\nCFG8 = 0x%02X\nCFG3 = 0x%02X\n"
"CFG6 = 0x%02X\nSTATUS = 0x%02X\nPWTIME = 0x%02X\nINTENAB = 0x%02X\n"
"CALIB = 0x%02X\nCAL_OFF = 0x%02X\nCAL_CFG = 0x%02X\nCAL_STAT = 0x%02X\n"
"%s\n",
rEnable, rPrate, (rPilth << 8) | rPiltl, (rPihth << 8) | rPihtl, rPers,
rPcfg0, rPcfg1, rPcfg2,
rCfg0, rCfg1, rCfg8, rCfg3, rCfg6,
rStatus, rPwtime, rIntenab,
rCalib, rCalOff, rCalcfg, rCalstat,
chip->prox_info.detected ? "Prox Detect" : "Prox Release");
}
static ssize_t tmd2755_prox_sat_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return tmd2755_prox_show(dev, attr, buf);
}
/**********************************************************************************************************************
* END OF SYSFS FUNCTIONS *
**********************************************************************************************************************/
/**************************************************************
* Global Sys Fs definitions *
**************************************************************/
extern ssize_t tmd2755_registers_show(struct device *dev, struct device_attribute *attr, char *buf);
extern ssize_t tmd2755_registers_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size);
struct device_attribute tmd2755_prox_attrs[] = {
__ATTR(prox_raw, 0444, tmd2755_prox_raw_show, NULL),
__ATTR(prox_detect, 0444, tmd2755_prox_detected_show, NULL),
__ATTR(prox_gain1, 0644, tmd2755_prox_gain1_show, tmd2755_prox_gain1_store),
__ATTR(prox_gain2, 0644, tmd2755_prox_gain2_show, tmd2755_prox_gain2_store),
__ATTR(prox_offset, 0644, tmd2755_prox_offset_show, tmd2755_prox_offset_store),
__ATTR(prox_persist, 0644, tmd2755_prox_persist_show, tmd2755_prox_persist_store),
__ATTR(prox_pulse_len, 0644, tmd2755_prox_pulse_len_show, tmd2755_prox_pulse_len_store),
__ATTR(prox_enable, 0644, tmd2755_prox_enable_show, tmd2755_prox_enable_store),
__ATTR(prox_time, 0644, tmd2755_prox_time_show, tmd2755_prox_time_store),
__ATTR(prox_wtime, 0644, tmd2755_prox_wtime_show, tmd2755_prox_wtime_store),
__ATTR(prox_low_thresh, 0644, tmd2755_prox_low_thresh_show, tmd2755_prox_low_thresh_store),
__ATTR(prox_high_thresh, 0644, tmd2755_prox_high_thresh_show, tmd2755_prox_high_thresh_store),
__ATTR(prox_regs, 0444, tmd2755_prox_regs_show, NULL),
__ATTR(prox_sat, 0444, tmd2755_prox_sat_show, NULL),
__ATTR(regs, 0644, tmd2755_registers_show, tmd2755_registers_store),
};
int tmd2755_prox_attrs_size = ARRAY_SIZE(tmd2755_prox_attrs);

View File

@ -0,0 +1,158 @@
/*
*****************************************************************************
* Copyright by ams AG *
* All rights are reserved. *
* *
* IMPORTANT - PLEASE READ CAREFULLY BEFORE COPYING, INSTALLING OR USING *
* THE SOFTWARE. *
* *
* THIS SOFTWARE IS PROVIDED FOR USE ONLY IN CONJUNCTION WITH AMS PRODUCTS. *
* USE OF THE SOFTWARE IN CONJUNCTION WITH NON-AMS-PRODUCTS IS EXPLICITLY *
* EXCLUDED. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************
*/
#ifndef __AMS_TMD2755_PROX_H__
#define __AMS_TMD2755_PROX_H__
#define MIN_PROX_THRESHOLD (0)
/* Values used during calibration */
#define PROX_BINSRCH_TARGET_VALUE (4) /* pdata target = 31 */
#define PROX_AUTO_OFFSET_ADJ_VAL (1) /* enabled */
//#define PROX_AVG_VAL (2) /* enabled */
#define PROX_AVG_VAL (0) /* disabled will save 30ms int */
#define PROX_ORE_EN (1) /* enable */
#define PROX_ORE_VAL (0x01) /* nominal + 1 step */
#define PROX_HWAVG_CAL (1) /* Allows hardware averaging during calibration */
#define PROX_PRATE_CAL (0) /* enables PRATE during calibration */
#define PROX_CALIB_TIMEOUT_MS (80)
#define PROX_APC_ENABLED (0)
#define PROX_APC_DISABLED (1)
#define PROX_SAT_EVENT (2)
/* Min/Max/Default Values for parameters */
/**********************************************************************************/
#define PROX_PERSIST_MIN (0)
#define PROX_PERSIST_MAX (15)
#define PROX_PERSIST_DEFAULT (1)
#define PROX_OFFSET_INIT (100)
/* Thresholds limits - up to the user to determine if min < max */
/* Routines adjust value based on APC */
#define PROX_THRESH_MIN (0)
#define PROX_THRESH_MAX (0x3FFF)
#define PROX_THRESH_DEFAULT (55)
#define PROX_PULSE_CNT_MIN (0)
#define PROX_PULSE_CNT_MAX (63)
#define PROX_PULSE_CNT_DEFAULT (15)
#define PROX_APC_MIN PROX_APC_ENABLED
#define PROX_APC_MAX PROX_APC_DISABLED
#define PROX_APC_DEFAULT PROX_APC_ENABLED
#define PROX_PULSE_LEN_MIN (30)
#define PROX_PULSE_LEN_MAX (0x3FF)
#define PROX_PULSE_LEN_DEFAULT (30)
#define PROX_GAIN_MIN (0)
#define PROX_GAIN_MAX (3) /* 2 bits gain_1 and gain_2 */
#define PROX_GAIN_DEFAULT (2)
#define PROX_OFFSET_MIN (-255)
#define PROX_OFFSET_MAX (255)
#define PROX_OFFSET_DEFAULT (6)
#define PROX_DRIVE_MIN (5)
#define PROX_DRIVE_MAX (8)
#define PROX_DRIVE_DEFAULT (5)
#define PROX_TIME_MIN (0)
#define PROX_TIME_MAX (255)
#define PROX_TIME_DEFAULT (31)
#define PROX_WTIME_MIN (0)
#define PROX_WTIME_MAX (255)
#define PROX_WTIME_DEFAULT (0)
/*****************************************************************************/
#define PROX_ON() do { \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_ENABLE, TMD2755_PEN, TMD2755_PEN); \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_PIEN, TMD2755_PIEN); \
} while (0)
#define PROX_OFF() do { \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_INTENAB, TMD2755_PIEN, 0); \
ams_i2c_modify(chip->client, chip->shadow, TMD2755_REG_ENABLE, TMD2755_PEN, 0); \
} while (0)
/*
* This must match the order of ATTR defined in
* struct device_attribute tmd2755_prox_attrs[]
* in ams_tmd2755_prox.c
*/
enum tmd2755_prox_attrs {
PROX_RAW_ATTR,
PROX_DETECT_ATTR,
PROX_GAIN1_ATTR,
PROX_GAIN2_ATTR,
PROX_OFFSET_ATTR,
PROX_PERSIST_ATTR,
PROX_PULSE_LEN_ATTR,
PROX_ENABLE_ATTR,
PROX_TIME_ATTR,
PROX_WTIME_ATTR,
PROX_LOW_THRESH_ATTR,
PROX_HIGH_THRESH_ATTR,
PROX_REGS_ATTR,
PROX_SATURATION_ATTR,
};
enum tmd2755_prox_sat_states {
PROX_NO_SAT,
PROX_SAT, /* general saturation */
PROX_AMBIENT_SAT,
PROX_REFLECTIVE_SAT,
};
extern struct device_attribute tmd2755_prox_attrs[];
extern int tmd2755_prox_attrs_size;
int tmd2755_configure_prox_mode(struct tmd2755_chip *chip, u8 state);
void tmd2755_init_prox_mode(struct tmd2755_chip *chip);
void tmd2755_process_prox_irq(struct tmd2755_chip *chip);
void tmd2755_prox_report_inp_event(struct tmd2755_chip *chip, int value);
void tmd2755_process_saturation_event(struct tmd2755_chip *chip);
extern void proximity_work(int state);
void tmd2755_read_poffset(struct tmd2755_chip *chip);
#endif // __AMS_TMD2755_PROX_H__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,273 @@
/*
* Copyright (C) 2014 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*******************************/
/* IR Sensor Hardware Module */
/******************************/
#ifndef __LINUX_ALSPS_VCNL36866_H
#define __LINUX_ALSPS_VCNL36866_H
#ifdef ONE_PL_CHIP
#define VCNL36866_PROXIMITY_INF_DEFAULT (92)
#define VCNL36866_PROXIMITY_THDL_DEFAULT (139)
#define VCNL36866_PROXIMITY_THDH_DEFAULT (215)
#define VCNL36866_PROXIMITY_AUTOK_MIN (3)
#define VCNL36866_PROXIMITY_AUTOK_MAX (2200)
#define VCNL36866_LIGHT_CALIBRATION_DEFAULT (846)
#else
#define VCNL36866_PROXIMITY_INF_DEFAULT (416)
#define VCNL36866_PROXIMITY_THDL_DEFAULT (520)
#define VCNL36866_PROXIMITY_THDH_DEFAULT (832)
#define VCNL36866_PROXIMITY_AUTOK_MIN (3)
#define VCNL36866_PROXIMITY_AUTOK_MAX (2500)
#define VCNL36866_LIGHT_CALIBRATION_DEFAULT (1658)
#endif
#define VCNL36866_LIGHT_MAX_THRESHOLD (65534)
#define VCNL36866_NUM_REGS (15)
#define VCNL36866_I2C_NAME "vcnl36866"
/* Define Slave Address*/
#define VCNL36866_SLAVE_ADDR 0x60
/* Define Chip ID */
#define VCNL36866_ID 0x62
/*Define Command Code*/
#define CS_CONF1 0x00
#define CS_CONF2 0x00
#define CS_THDH 0x01
#define CS_THDL 0x02
#define PS_CONF1 0x03
#define PS_CONF2 0x03
#define PS_CONF3 0x04
#define PS_CONF4 0x04
#define PS_THDL 0x05
#define PS_THDH 0x06
#define PS_CANC 0x07
#define PS_AC 0x08
#define ALS_DATA 0xF1
#define IR_DATA 0xF3
#define PS_DATA 0xF4
#define INT_FLAG 0xF5
#define ID_REG 0xF6
#define PS_AC_DATA 0xF7
struct vcnl36866_reg {
uint8_t reg;
};
static struct vcnl36866_reg vcnl36866_regs[] = {
{.reg = CS_CONF1, }, // 0x00
{.reg = CS_THDH, }, // 0x01
{.reg = CS_THDL, }, // 0x02
{.reg = PS_CONF1, }, // 0x03
{.reg = PS_CONF3, }, // 0x04
{.reg = PS_THDL, }, // 0x05
{.reg = PS_THDH, }, // 0x06
{.reg = PS_CANC, }, // 0x07
{.reg = PS_AC, }, // 0x08
{.reg = ALS_DATA, }, // 0xF1
{.reg = IR_DATA, }, // 0xF3
{.reg = PS_DATA, }, // 0xF4
{.reg = INT_FLAG, }, // 0xF5
{.reg = ID_REG, }, // 0xF6
{.reg = PS_AC_DATA,}, // 0xF7
};
/**
* for ALS CONF command
**/
/*** CS CONF1 ***/
//PS start
#define VCNL36866_CS_START_MASK 0x7F
#define VCNL36866_CS_START_SHIFT (7)
#define VCNL36866_CS_START (1)
//Integration
#define VCNL36866_CS_IT_MAX (3)
#define VCNL36866_CS_IT_MASK 0xF3
#define VCNL36866_CS_IT_NOT_MASK 0x0C
#define VCNL36866_CS_IT_SHIFT (2)
#define VCNL36866_CS_IT_50MS (0)
#define VCNL36866_CS_IT_100MS (1)
#define VCNL36866_CS_IT_200MS (2)
#define VCNL36866_CS_IT_400MS (3)
#define VCNL36866_CS_STANDBY (1 << 1)
#define VCNL36866_CS_STANDBY_MASK 0xFD
#define VCNL36866_CS_SD (1 << 0) /*enable/disable ALS func, 1:disable , 0: enable*/
#define VCNL36866_CS_SD_MASK 0xFE
/*** CS CONF2 ***/
//Persistence
#define VCNL36866_CS_PERS_MAX (3)
#define VCNL36866_CS_PERS_MASK 0xF3
#define VCNL36866_CS_PERS_SHIFT (2)
#define VCNL36866_CS_PERS_1 (0)
#define VCNL36866_CS_PERS_2 (1)
#define VCNL36866_CS_PERS_4 (2)
#define VCNL36866_CS_PERS_8 (3)
#define VCNL36866_CS_START2_MASK 0xFD
#define VCNL36866_CS_START2_SHIFT (1)
#define VCNL36866_CS_START2 (1)
#define VCNL36866_CS_RSV_MASK 0xDF
#define VCNL36866_CS_RSV_SHIFT (5)
#define VCNL36866_CS_RSV (1)
#define VCNL36866_CS_INT_EN (1 << 0) /*enable/disable Interrupt*/
#define VCNL36866_CS_INT_MASK 0xFE
#define VCNL36866_CS_HD_DISABLE (0)
#define VCNL36866_CS_HD_ENABLE (1)
/**
* for PS CONF command
**/
/*** PS CONF1 ***/
//LED Duty Ratio
#define VCNL36866_PS_DR_MAX (3)
#define VCNL36866_PS_DR_MASK 0x3F
#define VCNL36866_PS_DR_SHIFT (6)
#define VCNL36866_PS_PERIOD_10 (0)
#define VCNL36866_PS_PERIOD_20 (1)
#define VCNL36866_PS_PERIOD_40 (2)
#define VCNL36866_PS_PERIOD_80 (3)
//Persistence
#define VCNL36866_PS_PERS_MAX (3)
#define VCNL36866_PS_PERS_MASK 0xCF
#define VCNL36866_PS_PERS_SHIFT (4)
#define VCNL36866_PS_PERS_1 (0)
#define VCNL36866_PS_PERS_2 (1)
#define VCNL36866_PS_PERS_3 (2)
#define VCNL36866_PS_PERS_4 (3)
#define VCNL36866_PS_INT_IN_AND_OUT (2 << 2) /*enable/disable Interrupt*/
#define VCNL36866_PS_INT_MASK 0xF3 /*enable/disable Interrupt*/
#define VCNL36866_PS_SMART_PERS (1 << 1)
#define VCNL36866_PS_SMART_PERS_MASK 0xFD
#define VCNL36866_PS_SD (1 << 0)/*enable/disable PS func, 1:disable , 0: enable*/
#define VCNL36866_PS_SD_MASK 0xFE
/*** PS CONF2 ***/
//Integration
#define VCNL36866_PS_IT_MAX (3)
#define VCNL36866_PS_IT_MASK 0x3F
#define VCNL36866_PS_IT_SHIFT (6)
#define VCNL36866_PS_IT_1T (0)
#define VCNL36866_PS_IT_2T (1)
#define VCNL36866_PS_IT_4T (2)
#define VCNL36866_PS_IT_8T (3)
//Multi-Pulse setting
#define VCNL36866_PS_MPS_MAX (3)
#define VCNL36866_PS_MPS_MASK 0xCF
#define VCNL36866_PS_MPS_SHIFT (4)
#define VCNL36866_PS_MPS_1 (0)
#define VCNL36866_PS_MPS_2 (1)
#define VCNL36866_PS_MPS_4 (2)
#define VCNL36866_PS_MPS_8 (3)
//PS start
#define VCNL36866_PS_START_MASK 0xF7
#define VCNL36866_PS_START_SHIFT (3)
#define VCNL36866_PS_START (1)
//PS high gain mode enable
#define VCNL36866_PS_HG_ENABLE_MASK 0xFB
#define VCNL36866_PS_HG_ENABLE_SHIFT (2)
#define VCNL36866_PS_HG_ENABLE (1)
#define VCNL36866_PS_INT_SEL (1 << 0)
#define VCNL36866_PS_INT_SEL_MASK 0xFE
/*** PS CONF3 ***/
#define VCNL36866_PS_ACTIVE_FORCE_MODE_MASK 0xBF
#define VCNL36866_PS_ACTIVE_FORCE_MODE_SHIFT (6)
#define VCNL36866_PS_ACTIVE_FORCE_MODE (1)
#define VCNL36866_PS_ACTIVE_FORCE_TRIG_MASK 0xDF
#define VCNL36866_PS_ACTIVE_FORCE_TRIG_SHIFT (5)
#define VCNL36866_PS_ACTIVE_FORCE_TRIG (1)
#define VCNL36866_PS_START2_MASK 0xF7
#define VCNL36866_PS_START2_SHIFT (3)
#define VCNL36866_PS_START2 (1)
/*** PS CONF4 ***/
#define VCNL36866_PS_SUNLIGHT_DEFAULT_MASK 0x1F
#define VCNL36866_LED_I_SHIFT (5)
#define VCNL36866_PS_SUNLIGHT_DEFAULT (7)
//LED Current
#define VCNL36866_VCSEL_I_MAX (4)
#define VCNL36866_VCSEL_I_MASK 0xFC
#define VCNL36866_VCSEL_I_SHIFT (0)
#define VCNL36866_VCSEL_I_7mA (0)
#define VCNL36866_VCSEL_I_11mA (1)
#define VCNL36866_VCSEL_I_14mA (2)
#define VCNL36866_VCSEL_I_17mA (3)
#define VCNL36866_VCSEL_I_20mA (4)
/*** INT FLAG ***/
#define INT_FLAG_PS_ACFLAG (1 << 5) //After PS finishing auto calibration, INT raise.
#define INT_FLAG_PS_SPFLAG (1 << 4) //PS entering protection mode
#define INT_FLAG_CS_IF_L (1 << 3)
#define INT_FLAG_CS_IF_H (1 << 2)
#define INT_FLAG_PS_IF_CLOSE (1 << 1) //PS rises above PS_THDH INT trigger event
#define INT_FLAG_PS_IF_AWAY (1 << 0) //PS drops below PS_THDL INT trigger event
/**
* for ALS Dynamic control array
**/
struct vcnl36866_dynamic {
uint8_t IT_TIME;
int sensitivity;
u64 evt_skip_time_ns;
};
static int ALS_dynamic_status = 0;
#ifdef LONG_LENGTH_LOGN_IT_NON_PERF
static struct vcnl36866_dynamic vcnl36866_dynamic_array[] = {
{.IT_TIME = VCNL36866_CS_IT_400MS, .sensitivity = 1, .evt_skip_time_ns = 0},
{.IT_TIME = VCNL36866_CS_IT_400MS, .sensitivity = 1, .evt_skip_time_ns = 0},
{.IT_TIME = VCNL36866_CS_IT_400MS, .sensitivity = 1, .evt_skip_time_ns = 0},
};
#elif defined LONG_LENGTH_LOGN_IT_PERF
static struct vcnl36866_dynamic vcnl36866_dynamic_array[] = {
{.IT_TIME = VCNL36866_CS_IT_100MS, .sensitivity = 4, .evt_skip_time_ns = 100000000},
{.IT_TIME = VCNL36866_CS_IT_400MS, .sensitivity = 1, .evt_skip_time_ns = 500000000},
{.IT_TIME = VCNL36866_CS_IT_50MS, .sensitivity = 8, .evt_skip_time_ns = 100000000},
};
#else
static struct vcnl36866_dynamic vcnl36866_dynamic_array[] = {
{.IT_TIME = VCNL36866_CS_IT_50MS, .sensitivity=1, .evt_skip_time_ns = 0},
{.IT_TIME = VCNL36866_CS_IT_50MS, .sensitivity=1, .evt_skip_time_ns = 0},
{.IT_TIME = VCNL36866_CS_IT_50MS, .sensitivity=1, .evt_skip_time_ns = 0},
};
#endif
#endif

View File

@ -0,0 +1,230 @@
/*
* Copyright (C) 2014 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*******************************/
/* IR Sensor Hardware Module */
/******************************/
#ifndef __LINUX_ALSPS_VCNL36866_H
#define __LINUX_ALSPS_VCNL36866_H
#define VCNL36866_PROXIMITY_INF_DEFAULT (182)
#define VCNL36866_PROXIMITY_THDL_DEFAULT (426)
#define VCNL36866_PROXIMITY_THDH_DEFAULT (1194)
#define VCNL36866_PROXIMITY_AUTOK_MIN (3)
#define VCNL36866_PROXIMITY_AUTOK_MAX (2500)
#define VCNL36866_LIGHT_CALIBRATION_DEFAULT (4563)
#define VCNL36866_LIGHT_MAX_THRESHOLD (65534)
#define VCNL36866_NUM_REGS (15)
#define VCNL36866_I2C_NAME "vcnl36866"
/* Define Slave Address*/
#define VCNL36866_SLAVE_ADDR 0x60
/* Define Chip ID */
#define VCNL36866_ID 0x62
/*Define Command Code*/
#define CS_CONF1 0x00
#define CS_CONF2 0x00
#define CS_THDH 0x01
#define CS_THDL 0x02
#define PS_CONF1 0x03
#define PS_CONF2 0x03
#define PS_CONF3 0x04
#define PS_CONF4 0x04
#define PS_THDL 0x05
#define PS_THDH 0x06
#define PS_CANC 0x07
#define PS_AC 0x08
#define ALS_DATA 0xF1
#define IR_DATA 0xF3
#define PS_DATA 0xF4
#define INT_FLAG 0xF5
#define ID_REG 0xF6
#define PS_AC_DATA 0xF7
struct vcnl36866_reg {
uint8_t reg;
};
static struct vcnl36866_reg vcnl36866_regs[] = {
{.reg = CS_CONF1, }, // 0x00
{.reg = CS_THDH, }, // 0x01
{.reg = CS_THDL, }, // 0x02
{.reg = PS_CONF1, }, // 0x03
{.reg = PS_CONF3, }, // 0x04
{.reg = PS_THDL, }, // 0x05
{.reg = PS_THDH, }, // 0x06
{.reg = PS_CANC, }, // 0x07
{.reg = PS_AC, }, // 0x08
{.reg = ALS_DATA, }, // 0xF1
{.reg = IR_DATA, }, // 0xF3
{.reg = PS_DATA, }, // 0xF4
{.reg = INT_FLAG, }, // 0xF5
{.reg = ID_REG, }, // 0xF6
{.reg = PS_AC_DATA,}, // 0xF7
};
/**
* for ALS CONF command
**/
/*** CS CONF1 ***/
//PS start
#define VCNL36866_CS_START_MASK 0x7F
#define VCNL36866_CS_START_SHIFT (7)
#define VCNL36866_CS_START (1)
//Integration
#define VCNL36866_CS_IT_MAX (3)
#define VCNL36866_CS_IT_MASK 0xF3
#define VCNL36866_CS_IT_NOT_MASK 0x0C
#define VCNL36866_CS_IT_SHIFT (2)
#define VCNL36866_CS_IT_50MS (0)
#define VCNL36866_CS_IT_100MS (1)
#define VCNL36866_CS_IT_200MS (2)
#define VCNL36866_CS_IT_400MS (3)
#define VCNL36866_CS_STANDBY (1 << 1)
#define VCNL36866_CS_STANDBY_MASK 0xFD
#define VCNL36866_CS_SD (1 << 0) /*enable/disable ALS func, 1:disable , 0: enable*/
#define VCNL36866_CS_SD_MASK 0xFE
/*** CS CONF2 ***/
//Persistence
#define VCNL36866_CS_PERS_MAX (3)
#define VCNL36866_CS_PERS_MASK 0xF3
#define VCNL36866_CS_PERS_SHIFT (2)
#define VCNL36866_CS_PERS_1 (0)
#define VCNL36866_CS_PERS_2 (1)
#define VCNL36866_CS_PERS_4 (2)
#define VCNL36866_CS_PERS_8 (3)
#define VCNL36866_CS_START2_MASK 0xFD
#define VCNL36866_CS_START2_SHIFT (1)
#define VCNL36866_CS_START2 (1)
#define VCNL36866_CS_INT_EN (1 << 0) /*enable/disable Interrupt*/
#define VCNL36866_CS_INT_MASK 0xFE
#define VCNL36866_CS_HD_DISABLE (0)
#define VCNL36866_CS_HD_ENABLE (1)
/**
* for PS CONF command
**/
/*** PS CONF1 ***/
//LED Duty Ratio
#define VCNL36866_PS_DR_MAX (3)
#define VCNL36866_PS_DR_MASK 0x3F
#define VCNL36866_PS_DR_SHIFT (6)
#define VCNL36866_PS_PERIOD_10 (0)
#define VCNL36866_PS_PERIOD_20 (1)
#define VCNL36866_PS_PERIOD_40 (2)
#define VCNL36866_PS_PERIOD_80 (3)
//Persistence
#define VCNL36866_PS_PERS_MAX (3)
#define VCNL36866_PS_PERS_MASK 0xCF
#define VCNL36866_PS_PERS_SHIFT (4)
#define VCNL36866_PS_PERS_1 (0)
#define VCNL36866_PS_PERS_2 (1)
#define VCNL36866_PS_PERS_3 (2)
#define VCNL36866_PS_PERS_4 (3)
#define VCNL36866_PS_INT_IN_AND_OUT (2 << 2) /*enable/disable Interrupt*/
#define VCNL36866_PS_INT_MASK 0xF3 /*enable/disable Interrupt*/
#define VCNL36866_PS_SMART_PERS (1 << 1)
#define VCNL36866_PS_SMART_PERS_MASK 0xFD
#define VCNL36866_PS_SD (1 << 0)/*enable/disable PS func, 1:disable , 0: enable*/
#define VCNL36866_PS_SD_MASK 0xFE
/*** PS CONF2 ***/
//Integration
#define VCNL36866_PS_IT_MAX (3)
#define VCNL36866_PS_IT_MASK 0x3F
#define VCNL36866_PS_IT_SHIFT (6)
#define VCNL36866_PS_IT_1T (0)
#define VCNL36866_PS_IT_2T (1)
#define VCNL36866_PS_IT_4T (2)
#define VCNL36866_PS_IT_8T (3)
//Multi-Pulse setting
#define VCNL36866_PS_MPS_MAX (3)
#define VCNL36866_PS_MPS_MASK 0xCF
#define VCNL36866_PS_MPS_SHIFT (4)
#define VCNL36866_PS_MPS_1 (0)
#define VCNL36866_PS_MPS_2 (1)
#define VCNL36866_PS_MPS_4 (2)
#define VCNL36866_PS_MPS_8 (3)
//PS start
#define VCNL36866_PS_START_MASK 0xF7
#define VCNL36866_PS_START_SHIFT (3)
#define VCNL36866_PS_START (1)
//PS high gain mode enable
#define VCNL36866_PS_HG_ENABLE_MASK 0xFB
#define VCNL36866_PS_HG_ENABLE_SHIFT (2)
#define VCNL36866_PS_HG_ENABLE (1)
#define VCNL36866_PS_INT_SEL (1 << 0)
#define VCNL36866_PS_INT_SEL_MASK 0xFE
/*** PS CONF3 ***/
#define VCNL36866_PS_ACTIVE_FORCE_MODE_MASK 0xBF
#define VCNL36866_PS_ACTIVE_FORCE_MODE_SHIFT (6)
#define VCNL36866_PS_ACTIVE_FORCE_MODE (1)
#define VCNL36866_PS_ACTIVE_FORCE_TRIG_MASK 0xDF
#define VCNL36866_PS_ACTIVE_FORCE_TRIG_SHIFT (5)
#define VCNL36866_PS_ACTIVE_FORCE_TRIG (1)
#define VCNL36866_PS_START2_MASK 0xF7
#define VCNL36866_PS_START2_SHIFT (3)
#define VCNL36866_PS_START2 (1)
/*** PS CONF4 ***/
#define VCNL36866_PS_SUNLIGHT_DEFAULT_MASK 0x1F
#define VCNL36866_LED_I_SHIFT (5)
#define VCNL36866_PS_SUNLIGHT_DEFAULT (7)
//LED Current
#define VCNL36866_VCSEL_I_MAX (4)
#define VCNL36866_VCSEL_I_MASK 0xFC
#define VCNL36866_VCSEL_I_SHIFT (0)
#define VCNL36866_VCSEL_I_7mA (0)
#define VCNL36866_VCSEL_I_11mA (1)
#define VCNL36866_VCSEL_I_14mA (2)
#define VCNL36866_VCSEL_I_17mA (3)
#define VCNL36866_VCSEL_I_20mA (4)
/*** INT FLAG ***/
#define INT_FLAG_PS_ACFLAG (1 << 5) //After PS finishing auto calibration, INT raise.
#define INT_FLAG_PS_SPFLAG (1 << 4) //PS entering protection mode
#define INT_FLAG_CS_IF_L (1 << 3)
#define INT_FLAG_CS_IF_H (1 << 2)
#define INT_FLAG_PS_IF_CLOSE (1 << 1) //PS rises above PS_THDH INT trigger event
#define INT_FLAG_PS_IF_AWAY (1 << 0) //PS drops below PS_THDL INT trigger event
#endif

View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/***********************************/
/* Asus Sensor Hub Hardware */
/**********************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_i2c"
#undef dbg
#ifdef ASH_I2C_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s]"fmt,MODULE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s]"fmt,MODULE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s]"fmt,MODULE_NAME,##args)
/****************************/
/*i2c read/write function*/
/****************************/
uint8_t i2c_read_reg_u8(struct i2c_client* client, u8 reg)
{
uint8_t data =0 ;
if(client == NULL) {
err("%s: i2c client is NULL.\n", __FUNCTION__);
return -1;
}
data = i2c_smbus_read_byte_data(client, reg);
if (data < 0) {
err("%s: i2c_smbus_read_byte_data ERROR(0x%02X). \n", __FUNCTION__, reg);
}
return data;
}
EXPORT_SYMBOL(i2c_read_reg_u8);
int i2c_write_reg_u8(struct i2c_client* client, u8 reg, uint8_t data)
{
int ret = 0;
if(client == NULL) {
err("%s: i2c client is NULL.\n", __FUNCTION__);
return -1;
}
ret = i2c_smbus_write_byte_data(client, reg, data);
if (ret < 0) {
err("%s: i2c_smbus_write_byte_data ERROR(0x%02X). \n", __FUNCTION__, reg);
return ret;
}
return 0;
}
EXPORT_SYMBOL(i2c_write_reg_u8);
int i2c_read_reg_u16(struct i2c_client* client, u8 reg, uint8_t* data)
{
int ret = 0;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0, //write
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD, //read
.len = 2,
.buf = data,
}
};
if(client == NULL) {
err("%s: i2c client is NULL.\n", __FUNCTION__);
return -1;
}
if (!client->adapter) {
return -ENODEV;
}
memset(&data, 0, sizeof(data));
ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
/*return 2 is expected.*/
if (ret != ARRAY_SIZE(msg)) {
err("%s: i2c_transfer ERROR(0x%0X). \n", __FUNCTION__, reg);
return -1;
}
return 0;
}
EXPORT_SYMBOL(i2c_read_reg_u16);
int i2c_write_reg_u16(struct i2c_client* client, u8 reg, uint8_t* data)
{
int ret = 0;
int len = 3;
//uint8_t buf[len];
uint8_t buf[3];
struct i2c_msg msg;
if(client == NULL) {
err("%s: i2c client is NULL.\n", __FUNCTION__);
return -1;
}
if(data == NULL) {
err("%s: data is NULL.\n", __FUNCTION__);
return -1;
}
msg.addr = client->addr;
msg.flags = 0; /*write*/
msg.len = len;
msg.buf = buf;
if (!client->adapter)
return -ENODEV;
buf[0] = reg;
memcpy(buf + 1, &data[0], sizeof(data[0]));
memcpy(buf + 2, &data[1], sizeof(data[1]));
ret = i2c_transfer(client->adapter, &msg, 1);
/*return postive is expected.*/
if(ret < 0){
err("%s: i2c_transfer ERROR. (reg=0x%x, data_l=%d, data_h=%d, err = 0x%x)\n",
__FUNCTION__, reg, data[0], data[1], ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(i2c_write_reg_u16);

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************/
/* IR Sensor Report Module */
/***************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/input/ASH.h>
/*******************************/
/* Debug and Log System */
/*****************************/
#define MODULE_NAME "ASH_Report"
#define SENSOR_TYPE_NAME "light"
#undef dbg
#ifdef ASH_REPORT_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/**********************/
/*Global Variables*/
/********************/
static struct input_dev *input_dev_als = NULL;
static int report_data[5] = {-1};
void lrgbsensor_report_lux(void);
int lsensor_report_register(void)
{
int ret = 0;
/* Light Sensor Input event allocate */
input_dev_als = input_allocate_device();
if (!input_dev_als) {
err("%s: lsensor input_allocate_device is return NULL Pointer. \n", __FUNCTION__);
return -ENOMEM;
}
/* Set Light Sensor input device */
input_dev_als->name = "ASUS Lightsensor";
input_dev_als->id.bustype = BUS_I2C;
input_set_capability(input_dev_als, EV_ABS, ABS_MISC);
__set_bit(EV_ABS, input_dev_als->evbit);
__set_bit(ABS_MISC, input_dev_als->absbit);
input_set_abs_params(input_dev_als, ABS_MISC, 0, 65535, 0, 0);
//input_set_drvdata(input_dev_als, g_als_data);
/* R raw data */
input_set_capability(input_dev_als, EV_ABS, ABS_HAT0X);
__set_bit(ABS_HAT0X, input_dev_als->absbit);
input_set_abs_params(input_dev_als, ABS_HAT0X, 0, 65535, 0, 0);
/* G raw data */
input_set_capability(input_dev_als, EV_ABS, ABS_HAT0Y);
__set_bit(ABS_HAT0Y, input_dev_als->absbit);
input_set_abs_params(input_dev_als, ABS_HAT0Y, 0, 65535, 0, 0);
/* B raw data */
input_set_capability(input_dev_als, EV_ABS, ABS_HAT1X);
__set_bit(ABS_HAT1X, input_dev_als->absbit);
input_set_abs_params(input_dev_als, ABS_HAT1X, 0, 65535, 0, 0);
/* IR raw data */
input_set_capability(input_dev_als, EV_ABS, ABS_HAT1Y);
__set_bit(ABS_HAT1Y, input_dev_als->absbit);
input_set_abs_params(input_dev_als, ABS_HAT1Y, 0, 65535, 0, 0);
/* Register Light Sensor input device */
ret = input_register_device(input_dev_als);
if (ret < 0) {
err("%s: lsensor input_register_device ERROR(%d). \n", __FUNCTION__, ret);
return -1;
}
dbg("Input Event Success Registration\n");
return 0;
}
EXPORT_SYMBOL(lsensor_report_register);
void lsensor_report_unregister(void)
{
input_unregister_device(input_dev_als);
input_free_device(input_dev_als);
}
EXPORT_SYMBOL(lsensor_report_unregister);
void lsensor_report_lux(int lux)
{
report_data[0] = lux;
lrgbsensor_report_lux();
}
EXPORT_SYMBOL(lsensor_report_lux);
void FRGBsensor_report_raw(int *data, int size)
{
report_data[1] = data[0]; /* R */
report_data[2] = data[1]; /* G */
report_data[3] = data[2]; /* B */
report_data[4] = data[3]; /* IR */
lrgbsensor_report_lux();
}
EXPORT_SYMBOL(FRGBsensor_report_raw);
void lrgbsensor_report_lux(void)
{
static int count = 0;
log("report lux=%d, count=%d", report_data[0], count);
input_report_abs(input_dev_als, ABS_MISC, report_data[0]); /* LUX */
input_report_abs(input_dev_als, ABS_HAT0X, count); /* R */
input_report_abs(input_dev_als, ABS_HAT0Y, report_data[2]); /* G */
input_report_abs(input_dev_als, ABS_HAT1X, report_data[3]); /* B */
input_report_abs(input_dev_als, ABS_HAT1Y, report_data[4]); /* IR */
input_event(input_dev_als, EV_SYN, SYN_REPORT, 5);
input_sync(input_dev_als);
count++;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************/
/* Proximity Sensor Report Module */
/***************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_Report"
#define SENSOR_TYPE_NAME "SAR"
#define SAR_SENSOR_INIT -1
#undef dbg
#ifdef ASH_REPORT_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/******************/
/*Global Variables*/
/*****************/
static struct input_dev *input_dev_sar = NULL;
int SAR_sensor_report_register(void)
{
int ret = 0;
/* SAR Input event allocate */
input_dev_sar = input_allocate_device();
if (!input_dev_sar) {
err("%s: SAR sensor input_allocate_device is return NULL Pointer. \n", __FUNCTION__);
return -ENOMEM;
}
/* Set SAR input device */
input_dev_sar->name = "ASUS SARsensor";
input_dev_sar->id.bustype = BUS_I2C;
input_set_capability(input_dev_sar, EV_ABS, ABS_DISTANCE);
__set_bit(EV_ABS, input_dev_sar->evbit);
__set_bit(ABS_DISTANCE, input_dev_sar->absbit);
input_set_abs_params(input_dev_sar, ABS_DISTANCE, 0, 1, 0, 0);
//input_set_drvdata(input_dev_ps, g_ps_data);
/* Register SAR input device */
ret = input_register_device(input_dev_sar);
if (ret < 0) {
err("%s: sar sensor input_register_device ERROR(%d). \n", __FUNCTION__, ret);
return -1;
}
dbg("Input Event Success Registration\n");
return 0;
}
EXPORT_SYMBOL(SAR_sensor_report_register);
void SAR_sensor_report_unregister(void)
{
input_unregister_device(input_dev_sar);
input_free_device(input_dev_sar);
}
EXPORT_SYMBOL(SAR_sensor_report_unregister);
void SAR_sensor_report_abs(int abs)
{
if(abs != SAR_SENSOR_REPORT_AWAY &&
abs != SAR_SENSOR_REPORT_CLOSE) {
if (abs != SAR_SENSOR_INIT) {
err("%s: Sar Detect Object ERROR.\n", __FUNCTION__);
}
}
input_report_abs(input_dev_sar, ABS_DISTANCE, abs);
input_sync(input_dev_sar);
}
EXPORT_SYMBOL(SAR_sensor_report_abs);

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2015 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************/
/* Proximity Sensor Report Module */
/***************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/input/ASH.h>
/**************************/
/* Debug and Log System */
/************************/
#define MODULE_NAME "ASH_Report"
#define SENSOR_TYPE_NAME "proximity"
#define PSENSOR_INIT -1
#undef dbg
#ifdef ASH_REPORT_DEBUG
#define dbg(fmt, args...) printk(KERN_DEBUG "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
#else
#define dbg(fmt, args...)
#endif
#define log(fmt, args...) printk(KERN_INFO "[%s][%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,__func__,##args)
#define err(fmt, args...) printk(KERN_ERR "[%s][%s]"fmt,MODULE_NAME,SENSOR_TYPE_NAME,##args)
/******************/
/*Global Variables*/
/*****************/
static struct input_dev *input_dev_ps = NULL;
static bool g_input_dev_reg_status = false;
int psensor_report_register(void)
{
int ret = 0;
if(true == g_input_dev_reg_status){
err("%s: psensor input_register_device has been registered(%d). \n",
__FUNCTION__);
return 0;
}
/* Proximity Input event allocate */
input_dev_ps = input_allocate_device();
if (!input_dev_ps) {
err("%s: psensor input_allocate_device is return NULL Pointer. \n",
__FUNCTION__);
return -ENOMEM;
}
/* Set Proximity input device */
input_dev_ps->name = "ASUS Proximitysensor";
input_dev_ps->id.bustype = BUS_I2C;
input_set_capability(input_dev_ps, EV_ABS, ABS_DISTANCE);
__set_bit(EV_ABS, input_dev_ps->evbit);
__set_bit(ABS_DISTANCE, input_dev_ps->absbit);
input_set_abs_params(input_dev_ps, ABS_DISTANCE, 0, 1, 0, 0);
//input_set_drvdata(input_dev_ps, g_ps_data);
/* Register Proximity input device */
ret = input_register_device(input_dev_ps);
if (ret < 0) {
err("%s: psensor input_register_device ERROR(%d). \n", __FUNCTION__, ret);
return -1;
}
g_input_dev_reg_status = true;
dbg("Input Event Success Registration\n");
return 0;
}
EXPORT_SYMBOL(psensor_report_register);
void psensor_report_unregister(void)
{
if(true == g_input_dev_reg_status){
input_unregister_device(input_dev_ps);
input_free_device(input_dev_ps);
}
}
EXPORT_SYMBOL(psensor_report_unregister);
void psensor_report_abs(int abs)
{
if(false == g_input_dev_reg_status){
return;
}
#ifndef ONE_PL_CHIP
if(abs != PSENSOR_REPORT_PS_AWAY &&
abs != PSENSOR_REPORT_PS_CLOSE &&
abs != PSENSOR_REPORT_PS_POCKET &&
abs != PSENSOR_2ND_REPORT_PS_AWAY &&
abs != PSENSOR_2ND_REPORT_PS_CLOSE &&
abs != PSENSOR_2ND_REPORT_PS_POCKET) {
if (abs != PSENSOR_INIT) {
err("%s: Proximity Detect Object ERROR.\n", __FUNCTION__);
}
}
#else
if(abs != PSENSOR_REPORT_PS_AWAY &&
abs != PSENSOR_REPORT_PS_CLOSE &&
abs != PSENSOR_REPORT_PS_POCKET) {
if (abs != PSENSOR_INIT) {
err("%s: Proximity Detect Object ERROR.\n", __FUNCTION__);
}
}
#endif
input_report_abs(input_dev_ps, ABS_DISTANCE, abs);
input_sync(input_dev_ps);
}
EXPORT_SYMBOL(psensor_report_abs);

View File

@ -0,0 +1,24 @@
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY
ccflags-y += -DANDROID_GKI_VFS_EXPORT_ONLY=VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver
obj-m := sensors_vcnl36866.o
sensors_vcnl36866-y += ASH_Algo/ALSPSsensor.o
sensors_vcnl36866-y += ASH_ATTR/lsensor_ATTR.o ASH_ATTR/psensor_ATTR.o ASH_ATTR/ASH_ATTR.o
sensors_vcnl36866-y += ASH_Report/psensor_Report.o ASH_Report/LwithRGBsensor_Report.o
sensors_vcnl36866-y += ASH_Factory/psensor_Factory.o ASH_Factory/lsensor_Factory.o
sensors_vcnl36866-y += ASH_GPIO/ALSPSsensor_GPIO.o
sensors_vcnl36866-y += ASH_Hardware/ASH_Hardware.o ASH_Hardware/ALSPSsensor_Hardware/ALSPSsensor_Hardware.o ASH_Hardware/ALSPSsensor_Hardware/vcnl36866/vcnl36866.o
ifeq ($(CONFIG_MACH_ASUS_SAKE),y)
sensors_vcnl36866-y += ASH_Hardware/ALSPSsensor_Hardware/ams_tmd2755/ams_tmd2755.o
sensors_vcnl36866-y += ASH_Hardware/ALSPSsensor_Hardware/ams_tmd2755/ams_tmd2755_prox.o
sensors_vcnl36866-y += ASH_Hardware/ALSPSsensor_Hardware/ams_tmd2755/ams_tmd2755_als.o
sensors_vcnl36866-y += ASH_Hardware/ALSPSsensor_Hardware/ams_tmd2755/ams_i2c.o
endif
ifeq ($(CONFIG_MACH_ASUS_VODKA),y)
sensors_vcnl36866-y += ASH_Algo/ALSPSsensor_2nd.o
sensors_vcnl36866-y += ASH_ATTR/lsensor_2nd_ATTR.o ASH_ATTR/psensor_2nd_ATTR.o
sensors_vcnl36866-y += ASH_GPIO/ALSPSsensor_GPIO_2nd.o
sensors_vcnl36866-y += ASH_Hardware/ALSPSsensor_Hardware/ALSPSsensor_Hardware_2nd.o ASH_Hardware/ALSPSsensor_Hardware/vcnl36866_2nd/vcnl36866_2nd.o
endif

View File

@ -1 +1,14 @@
obj-m += icm206xx.o
obj-y += ASH/
ifeq ($(CONFIG_MACH_ASUS_SAKE),y)
KBUILD_CFLAGS += -DCONFIG_TMD2755_FLAG=1
KBUILD_CFLAGS += -DONE_PL_CHIP
KBUILD_CFLAGS += -DPSENSOR_CAL24
endif
ifeq ($(CONFIG_MACH_ASUS_VODKA),y)
KBUILD_CFLAGS += -DLONG_LENGTH_LOGN_IT_PERF=1
KBUILD_CFLAGS += -DRECOVERY_PSENSOR
KBUILD_CFLAGS += -DPSENSOR_CAL24
endif

1129
include/linux/input/ASH.h Normal file

File diff suppressed because it is too large Load Diff

216
include/linux/input/SAR.h Normal file
View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2019 ASUSTek Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __LINUX_SAR_H
#define __LINUX_SAR_H
#define NAME_SIZE (10)
/**
* Define the SAR report event values.
* @SAR_SENSOR_REPORT_PS_CLOSE : report close event.
* @SAE_SENSOR_REPORT_PS_AWAY : report away event.
*/
#define SAR_SENSOR_REPORT_CLOSE (1)
#define SAR_SENSOR_REPORT_AWAY (0)
#define OBJECT_NEAR (1)
#define OBJECT_FAR (0)
/**
* Define the proxstat bit of SAR sensor,
* which indicates if proximity is currently detected by CSx.
* @PROXSTAT0 : CS0 detect
* @RROXSTAT1 : CS1 detect
* @PROXSTAT2 : CS2 detect
* @PROXSTAT3 : CS3 detect
*/
#define PROXSTAT0 (0x00)
#define PROXSTAT1 (0x02)
#define PROXSTAT2 (0x04)
#define PROXSTAT3 (0x08)
/**
* SAR_sensor_report_register - before report SAR sensor event
* you need to register first. This will create input device for SAR sensor.
*/
extern int SAR_sensor_report_register(void);
/**
* SAR_sensor_report_unregister - Remove the input device for SAR sensor.
*/
extern void SAR_sensor_report_unregister(void);
/**
* SAR_sensor_report_abs - report the SAR abs.
* @ abs=SAR_SENSOR_REPORT_CLOSE : report close event.
* @ abs=SAR_SENSOR_REPORT_AWAY : report away event.
*/
extern void SAR_sensor_report_abs(int abs);
/**
* SAR_sensor_GPIO
*/
typedef struct SAR_sensor_GPIO {
void (*SAR_sensor_isr)(void);
}SAR_sensor_GPIO;
/**
* SAR_sensor_gpio_register - register the GPIO setting and set the IRQ handler.
* Return the IRQ.
*/
#include <linux/i2c.h>
extern int SAR_sensor_gpio_register(struct i2c_client *client, SAR_sensor_GPIO *gpio_ist);
/**
* SAR_sensor_gpio_unregister - unregister the GPIO setting.
*/
extern int SAR_sensor_gpio_unregister(int irq);
/**
* SAR_sensor_gpio_value - return the gpio value.
*/
extern int SAR_sensor_gpio_value(void);
/**
SAR_sensor_I2C - We define functions for i2c driver.
* @SAR_sensor_probe : It will be run when "i2c_add_driver" has been called.
* @SAR_sensor_remove : Remove all Memory.
* @SAR_sensor_shutdown : Turn off all sensors.
* @SAR_sensor_suspend : Do what suspend should do.
* @SAR_sensor_resume : Do what resume should do.
*/
typedef struct SAR_sensor_I2C {
void (*SAR_sensor_probe)(struct i2c_client *client);
void (*SAR_sensor_remove)(void);
void (*SAR_sensor_shutdown)(void);
void (*SAR_sensor_suspend)(void);
void (*SAR_sensor_resume)(void);
}SAR_sensor_I2C;
/**
* SAR_sensor_hw - the i2c control functions for SAR sensor
*/
typedef struct SAR_sensor_hw {
char vendor[NAME_SIZE];
char module_number[NAME_SIZE];
int (*SAR_sensor_hw_check_ID)(void);
int (*SAR_sensor_hw_init)(struct i2c_client* client);
int (*SAR_sensor_hw_read_regStat)(void);
int (*SAR_sensor_hw_get_interrupt)(void);
int (*SAR_sensor_hw_show_allreg)(void);
int (*SAR_sensor_hw_set_register)(uint8_t reg, int value);
int (*SAR_sensor_hw_get_register)(uint8_t reg);
int (*SAR_sensor_hw_turn_onoff)(bool bOn);
int (*SAR_sensor_hw__get_proxuserful)(uint8_t cs);
int (*SAR_sensor_hw_read_rawData)(void);
int (*SAR_sensor_hw_get_manual_offset_cal)(void);
int (*SAR_sensor_hw_manual_offset_cal)(int value);
}SAR_sensor_hw;
/**
* SAR_sensor_ATTR_BMMI - attributes for SAR_sensor BMMI.
*/
typedef struct{
bool (*SAR_sensor_show_atd_test)(void);
int (*SAR_sensor_show_raw_data)(void);
}SAR_sensor_ATTR_BMMI;
/**
* SAR_sensor_info_type - define the SAR_sensor information.
* @vendor : ASUS.
* @version : driver version.
* @module_number : hardware chip serial number.
*/
#define NAME_SIZE (10)
typedef struct{
char vendor[NAME_SIZE];
char module_number[NAME_SIZE];
}SAR_sensor_info_type;
/**
* SAR_sensor_ATTR_HAL - attributes for SAR_sensor HAL function.
*/
typedef struct{
bool (*SAR_sensor_show_switch_onoff)(void);
int (*SAR_sensor_store_switch_onoff)(bool bOn);
int (*SAR_sensor_show_Interrupt_detect_status)(void);
bool (*SAR_sensor_show_sar_status)(void);
}SAR_sensor_ATTR_HAL;
/**
* SAR_sensor_ATTR_Hardware - attributes for SAR_sensor hardware read/write.
*/
typedef struct{
uint8_t show_reg_addr;
int (*SAR_show_reg)(uint8_t addr);
int (*SAR_store_reg)(uint8_t addr, int value);
int (*SAR_sensor_show_manual_offset_cal)(void);
int (*SAR_sensor_store_manual_offset_cal)(int value);
}SAR_sensor_ATTR_Hardware;
/**
* SAR_sensor_ATTR_Extension - attributes for SAR_sensor extensive functions.
*/
typedef struct{
bool (*SAR_sensor_show_allreg)(void);
}SAR_sensor_ATTR_Extension;
/**
* SAR_sensor_ATTR - attributes for lsensor.
*/
typedef struct{
SAR_sensor_info_type *info_type;
SAR_sensor_ATTR_BMMI *ATTR_BMMI;
SAR_sensor_ATTR_HAL *ATTR_HAL;
SAR_sensor_ATTR_Hardware *ATTR_Hardware;
SAR_sensor_ATTR_Extension *ATTR_Extension;
}SAR_sensor_ATTR;
/**
* SAR_sensor_ATTR_register - assign a psensor only file node and create the attributes.
*
* The attributes will be created at /sys/class/sensors/SAR_sensor.
*/
extern int SAR_sensor_ATTR_register(SAR_sensor_ATTR *mATTR);
/**
* SAR_sensor_ATTR_unregister - remove the SAR_sensor attributes.
*/
extern int SAR_sensor_ATTR_unregister(void);
/**
* SAR_sensor_ATTR_create - create SAR_sensor customize attributes.
* @mSAR_sensor_attr : the pointer of device_attribute, which you want to create attribute.
*/
extern int SAR_sensor_ATTR_create(struct device_attribute *mSAR_sensor_attr);
/**
* SAR_sensor_i2c_register - struct SAR_sensor_I2C wrapped by i2c driver.
*/
extern int SAR_sensor_i2c_register(SAR_sensor_I2C *ir_i2c);
/**
* SAR_sensor_hw_getHardware - Before this function, you SHOULD execute SAR_sensor_i2c_register first.
*/
extern SAR_sensor_hw* SAR_sensor_hw_getHardware(void);
/**
* SAR_sensor_i2c_unregister - i2c_del_driver.
*/
extern int SAR_sensor_i2c_unregister(void);
#endif