Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/freezer.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/sensor-dev.h>
#include <linux/types.h>


#define DRIVER_VERSION		        "1.0"

#define PWR_MODE_DOWN_MASK     		0x80
#define PWR_MODE_OPERATE_MASK     0x7F


/*us5152 Slave Addr*/
#define LIGHT_ADDR      0x72

/*Interrupt PIN for S3C6410*/
#define IRQ_LIGHT_INT IRQ_EINT(6)

/*Register Set*/
#define REGS_CR0          	0x00
#define REGS_CR1          	0x01
#define REGS_CR2          	0x02
#define REGS_CR3          	0x03
//ALS
#define REGS_INT_LSB_TH_LO      0x04
#define REGS_INT_MSB_TH_LO      0x05
#define REGS_INT_LSB_TH_HI      0x06
#define REGS_INT_MSB_TH_HI      0x07
//ALS data
#define REGS_LBS_SENSOR         0x0C
#define REGS_MBS_SENSOR         0x0D

#define REGS_CR10          	0x10
#define REGS_CR11          	0x11
#define REGS_VERSION_ID      	0x1F
#define REGS_CHIP_ID      	0xB2

/*ShutDown_EN*/
#define CR0_OPERATION		0x0
#define CR0_SHUTDOWN_EN		0x1

#define CR0_SHUTDOWN_SHIFT   	(7)
#define CR0_SHUTDOWN_MASK    	(0x1 << CR0_SHUTDOWN_SHIFT)

/*OneShot_EN*/
#define CR0_ONESHOT_EN		0x01

#define CR0_ONESHOT_SHIFT   	(6)
#define CR0_ONESHOT_MASK    	(0x1 << CR0_ONESHOT_SHIFT)

/*Operation Mode*/
#define CR0_OPMODE_ALSANDPS	0x0
#define CR0_OPMODE_ALSONLY	0x1
#define CR0_OPMODE_IRONLY		0x2

#define CR0_OPMODE_SHIFT       	(4)
#define CR0_OPMODE_MASK        	(0x3 << CR0_OPMODE_SHIFT)

/*all int flag (PROX, INT_A, INT_P)*/
#define CR0_ALL_INT_CLEAR	0x0

#define CR0_ALL_INT_SHIFT       (1)
#define CR0_ALL_INT_MASK        (0x7 << CR0_ALL_INT_SHIFT)


/*indicator of object proximity detection*/
#define CR0_PROX_CLEAR		0x0

#define CR0_PROX_SHIFT       	(3)
#define CR0_PROX_MASK        	(0x1 << CR0_PROX_SHIFT)

/*interrupt status of proximity sensor*/
#define CR0_INTP_CLEAR		0x0

#define CR0_INTP_SHIFT       	(2)
#define CR0_INTP_MASK        	(0x1 << CR0_INTP_SHIFT)

/*interrupt status of ambient sensor*/
#define CR0_INTA_CLEAR		0x0

#define CR0_INTA_SHIFT       	(1)
#define CR0_INTA_MASK        	(0x1 << CR0_INTA_SHIFT)

/*Word mode enable*/
#define CR0_WORD_EN		0x1

#define CR0_WORD_SHIFT       	(0)
#define CR0_WORD_MASK        	(0x1 << CR0_WORD_SHIFT)


/*ALS fault queue depth for interrupt enent output*/
#define CR1_ALS_FQ_1		0x0
#define CR1_ALS_FQ_4		0x1
#define CR1_ALS_FQ_8		0x2
#define CR1_ALS_FQ_16		0x3
#define CR1_ALS_FQ_24		0x4
#define CR1_ALS_FQ_32		0x5
#define CR1_ALS_FQ_48		0x6
#define CR1_ALS_FQ_63		0x7

#define CR1_ALS_FQ_SHIFT       	(5)
#define CR1_ALS_FQ_MASK        	(0x7 << CR1_ALS_FQ_SHIFT)

/*resolution for ALS*/
#define CR1_ALS_RES_12BIT	0x0
#define CR1_ALS_RES_14BIT	0x1
#define CR1_ALS_RES_16BIT	0x2
#define CR1_ALS_RES_16BIT_2	0x3

#define CR1_ALS_RES_SHIFT      	(3)
#define CR1_ALS_RES_MASK       	(0x3 << CR1_ALS_RES_SHIFT)

/*sensing amplifier selection for ALS*/
#define CR1_ALS_GAIN_X1		0x0
#define CR1_ALS_GAIN_X2		0x1
#define CR1_ALS_GAIN_X4		0x2
#define CR1_ALS_GAIN_X8		0x3
#define CR1_ALS_GAIN_X16	0x4
#define CR1_ALS_GAIN_X32	0x5
#define CR1_ALS_GAIN_X64	0x6
#define CR1_ALS_GAIN_X128	0x7

#define CR1_ALS_GAIN_SHIFT      (0)
#define CR1_ALS_GAIN_MASK       (0x7 << CR1_ALS_GAIN_SHIFT)


/*PS fault queue depth for interrupt event output*/
#define CR2_PS_FQ_1		0x0
#define CR2_PS_FQ_4		0x1
#define CR2_PS_FQ_8		0x2
#define CR2_PS_FQ_15		0x3

#define CR2_PS_FQ_SHIFT      	(6)
#define CR2_PS_FQ_MASK       	(0x3 << CR2_PS_FQ_SHIFT)

/*interrupt type setting */
/*low active*/
#define CR2_INT_LEVEL		0x0
/*low pulse*/
#define CR2_INT_PULSE		0x1

#define CR2_INT_SHIFT      	(5)
#define CR2_INT_MASK       	(0x1 << CR2_INT_SHIFT)

/*resolution for PS*/
#define CR2_PS_RES_12		0x0
#define CR2_PS_RES_14		0x1
#define CR2_PS_RES_16		0x2
#define CR2_PS_RES_16_2		0x3

#define CR2_PS_RES_SHIFT      	(3)
#define CR2_PS_RES_MASK       	(0x3 << CR2_PS_RES_SHIFT)

/*sensing amplifier selection for PS*/
#define CR2_PS_GAIN_1		0x0
#define CR2_PS_GAIN_2		0x1
#define CR2_PS_GAIN_4		0x2
#define CR2_PS_GAIN_8		0x3
#define CR2_PS_GAIN_16		0x4
#define CR2_PS_GAIN_32		0x5
#define CR2_PS_GAIN_64		0x6
#define CR2_PS_GAIN_128		0x7

#define CR2_PS_GAIN_SHIFT      	(0)
#define CR2_PS_GAIN_MASK       	(0x7 << CR2_PS_GAIN_SHIFT)

/*wait-time slot selection*/
#define CR3_WAIT_SEL_0		0x0
#define CR3_WAIT_SEL_4		0x1
#define CR3_WAIT_SEL_8		0x2
#define CR3_WAIT_SEL_16		0x3

#define CR3_WAIT_SEL_SHIFT      (6)
#define CR3_WAIT_SEL_MASK       (0x3 << CR3_WAIT_SEL_SHIFT)

/*IR-LED drive peak current setting*/
#define CR3_LEDDR_12_5		0x0
#define CR3_LEDDR_25		0x1
#define CR3_LEDDR_50		0x2
#define CR3_LEDDR_100		0x3

#define CR3_LEDDR_SHIFT      	(4)
#define CR3_LEDDR_MASK       	(0x3 << CR3_LEDDR_SHIFT)

/*INT pin source selection*/
#define CR3_INT_SEL_BATH	0x0
#define CR3_INT_SEL_ALS		0x1
#define CR3_INT_SEL_PS		0x2
#define CR3_INT_SEL_PSAPP	0x3

#define CR3_INT_SEL_SHIFT      	(2)
#define CR3_INT_SEL_MASK       	(0x3 << CR3_INT_SEL_SHIFT)

/*software reset for register and core*/
#define CR3_SOFTRST_EN		0x1

#define CR3_SOFTRST_SHIFT      	(0)
#define CR3_SOFTRST_MASK       	(0x1 << CR3_SOFTRST_SHIFT)

/*modulation frequency of LED driver*/
#define CR10_FREQ_DIV2		0x0
#define CR10_FREQ_DIV4		0x1
#define CR10_FREQ_DIV8		0x2
#define CR10_FREQ_DIV16		0x3

#define CR10_FREQ_SHIFT      	(1)
#define CR10_FREQ_MASK       	(0x3 << CR10_FREQ_SHIFT)

/*50/60 Rejection enable*/
#define CR10_REJ_5060_DIS	0x00
#define CR10_REJ_5060_EN	0x01

#define CR10_REJ_5060_SHIFT     (0)
#define CR10_REJ_5060_MASK      (0x1 << CR10_REJ_5060_SHIFT)

#define us5152_NUM_CACHABLE_REGS 0x12


static int sensor_active(struct i2c_client *client, int enable, int rate)
{
	//struct sensor_private_data *sensor =
	   // (struct sensor_private_data *) i2c_get_clientdata(client);
	int result = 0;
	char value = 0;
	int i = 0;

	for(i=0; i<3; i++)
		{
			if(!enable)
			{
				value = sensor_read_reg(client, REGS_CR0);
				value |= PWR_MODE_DOWN_MASK;	//ShutDown_EN=1
				result = sensor_write_reg(client, REGS_CR0, value);
				if(result)
					return result;
			}
			else
			{
				value = sensor_read_reg(client, REGS_CR0);
				value &= PWR_MODE_OPERATE_MASK ; //Operation_EN=0
				result = sensor_write_reg(client, REGS_CR0, value);
				if(result)
					return result;
			}

			if(!result)
			break;
		}

		if(i>1)
		printk("%s:set %d times",__func__,i);


	//TODO:? function to be added here

	return result;

}


static int sensor_init(struct i2c_client *client)
{
	struct sensor_private_data *sensor =
	    (struct sensor_private_data *) i2c_get_clientdata(client);
	int result = 0;
	char value = 0;

	result = sensor->ops->active(client,0,0);
	if(result)
	{
		printk("%s:line=%d,error\n",__func__,__LINE__);
		return result;
	}

	sensor->status_cur = SENSOR_OFF;

	value = sensor_read_reg(client, REGS_CHIP_ID); //read chip ids
	printk("us5152 chip id is %x!\n", value);

	value = 0x01;//word accessing

	result = sensor_write_reg(client, REGS_CR0, value);
	if(result)
	{
		printk("%s:line=%d,error\n",__func__,__LINE__);
		return result;
	}

	return result;
}


static int us5152_value_report(struct input_dev *input, int data)
{
	unsigned char index = 0;
	if(data <= 10){
		index = 0;goto report;
	}
	else if(data <= 160){
		index = 1;goto report;
	}
	else if(data <= 225){
		index = 2;goto report;
	}
	else if(data <= 320){
		index = 3;goto report;
	}
	else if(data <= 640){
		index = 4;goto report;
	}
	else if(data <= 1280){
		index = 5;goto report;
	}
	else if(data <= 2600){
		index = 6;goto report;
	}
	else{
		index = 7;goto report;
	}

report:
	input_report_abs(input, ABS_MISC, index);
	input_sync(input);
	return index;
}

static int sensor_report_value(struct i2c_client *client)
{
	struct sensor_private_data *sensor =
	    (struct sensor_private_data *) i2c_get_clientdata(client);
	int result = 0;
	int value = 0;
	char index = 0;
	char buffer[2]= { 0 } ;
	int ret=0;

	if(sensor->pdata->irq_enable)
	{
		if(sensor->ops->int_status_reg >= 0)
		{
			value = sensor_read_reg(client, sensor->ops->int_status_reg);
		}

	}

	//value = sensor_read_reg(client, sensor->ops->read_reg);  //TODO:? to be changed
	if(sensor->ops->read_len< 2) //12bit
	{
		printk("us5152 data read para num error ; len = %d\n ",sensor->ops->read_len);
		return -1;
	}
	memset(buffer , 0 , 2);
	do
	{
		*buffer = sensor->ops->read_reg;
		ret=sensor_rx_data(client,buffer,sensor->ops->read_len);
		if(ret<0)
			return ret;
	}
	while(0);
	value=buffer[1];
	value =((value << 8) | buffer[0]) & 0xffff;
	index = us5152_value_report(sensor->input_dev, value);  //now is 12bit

	//printk("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, value,index);
	DBG("%s:%s result=%d,index=%d buffer[1]=0x%x , buffer[0]=0x%x \n",__func__,sensor->ops->name, value,index,buffer[1],buffer[0]);

	return result;
}


static struct sensor_operate light_us5152_ops = {
	.name				= "ls_us5152",
	.type				= SENSOR_TYPE_LIGHT,	//sensor type and it should be correct
	.id_i2c				= LIGHT_ID_US5152,	//i2c id number
	.read_reg			= REGS_LBS_SENSOR,	//read data
	.read_len			= 2,			//data length
	.id_reg				= REGS_CHIP_ID,		//read device id from this register
	.id_data 			= 0x26,			//device id
	.precision			= 12,			//12 bits
	.ctrl_reg 			= REGS_CR0,		//enable or disable
	.int_status_reg 		= SENSOR_UNKNOW_DATA,	//intterupt status register
	.range				= {0,10},		//range
	.brightness                     = {10,4095},                          // brightness
	.trig				= IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
	.active				= sensor_active,
	.init				= sensor_init,
	.report				= sensor_report_value,
};
/****************operate according to sensor chip:end************/
static int light_us5152_probe(struct i2c_client *client,
			      const struct i2c_device_id *devid)
{
	return sensor_register_device(client, NULL, devid, &light_us5152_ops);
}

static int light_us5152_remove(struct i2c_client *client)
{
	return sensor_unregister_device(client, NULL, &light_us5152_ops);
}

static const struct i2c_device_id light_us5152_id[] = {
	{"ls_us5152", LIGHT_ID_US5152},
	{}
};

static struct i2c_driver light_us5152_driver = {
	.probe = light_us5152_probe,
	.remove = light_us5152_remove,
	.shutdown = sensor_shutdown,
	.id_table = light_us5152_id,
	.driver = {
		.name = "light_us5152",
	#ifdef CONFIG_PM
		.pm = &sensor_pm_ops,
	#endif
	},
};


module_i2c_driver(light_us5152_driver);

MODULE_AUTHOR("Finley Huang finley_huang@upi-semi.com");
MODULE_DESCRIPTION("us5152 ambient light sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);