#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
/*********************************************
Register
**********************************************/
#define TMD26353_ENABLE_PROXIMITY 0x80
#define TMD26353_PRATE 0x82 //采样时间PRATE
#define TMD26353_PCFG0 0x8E //增益
#define TMD26353_PCFG1 0x8F
#define TMD26353_DEVICE_ID 0x92
#define TMD26353_PDATAL 0x9C //ADC
#define TMD26353_PDATAH 0x9D
#define TMD26353_CFG6_APC 0xAE //使能APC
#define TMD26353_POFFSETL 0xC0 自动校准
#define TMD26353_POFFSETH 0xC1
#define TMD26353_CALIBCFG 0xD9 //样本数量CALIBCFG
struct tmd26353_data {
struct i2c_client *client;
struct mutex lock;
int irq_pin;
unsigned int irq_111 ;
unsigned int irq_num;
u32 read_adc;
u32 read_enable;
struct work_struct pen_event_work;
struct workqueue_struct *tmd26353_workqueue;
};
static struct tmd26353_data tmd26353;
static struct task_struct *p_data_task;
enum tmd26353_register_name {
REG_PDATA = 0,
REG_DEVICE_ID = 1,
REG_ENABLE = 2,
REG_POFFSET = 3,
REG_PRATE = 4,
REG_CALIBCFG = 5,
REG_CFG6_APC = 6,
REG_PCFG0 = 7,
REG_PCFG1 = 8,
};
struct tmd26353_register_desc {
u8 msb;
u8 lsb;
};
static const struct tmd26353_register_desc tmd26353_registers[] = {
[REG_PDATA] = {
.msb = TMD26353_PDATAH,
.lsb = TMD26353_PDATAL,
},
[REG_DEVICE_ID] = {
.lsb = TMD26353_DEVICE_ID,
},
[REG_ENABLE] = {
.lsb = TMD26353_ENABLE_PROXIMITY,
},
[REG_POFFSET] = {
.msb = TMD26353_POFFSETH,
.lsb = TMD26353_POFFSETL,
},
[REG_PRATE] = {
.lsb = TMD26353_PRATE,
},
[REG_CALIBCFG] = {
.lsb = TMD26353_CALIBCFG,
},
[REG_CFG6_APC] = {
.lsb = TMD26353_CFG6_APC,
},
[REG_PCFG0] = {
.lsb = TMD26353_PCFG0,
},
[REG_PCFG1] = {
.lsb = TMD26353_PCFG1,
},
};
static int tmd26353_register_read_single(struct tmd26353_data *data,
enum tmd26353_register_name name,u32 *val)
{
const struct tmd26353_register_desc *reg = &tmd26353_registers[name];
u8 msb = 0,lsb = 0;
s32 ret;
mutex_lock(&data->lock);
if(reg->msb){
ret = i2c_smbus_read_byte_data(data->client,reg->msb);
if(ret < 0){
printk("read msb failed %d \n",ret);
goto error;
}
msb = ret;
}
if(reg->lsb){
ret = i2c_smbus_read_byte_data(data->client,reg->lsb);
if(ret < 0){
printk("read lsb failed %d \n",ret);
goto error;
}
lsb = ret;
}
mutex_unlock(&data->lock);
*val = (msb << 8) + lsb;
return 0;
error:
mutex_unlock(&data->lock);
return ret;
}
static u32 tmd26353_register_write_single(struct tmd26353_data *data,
enum tmd26353_register_name name,u32 value)
{
const struct tmd26353_register_desc *reg = &tmd26353_registers[name];
u8 msb,lsb;
int ret;
if(!reg->msb && value > U8_MAX){
printk("value > U8_MAX \n");
return -EINVAL;
}
if(value > U16_MAX){
printk("value > U16_MAX \n");
return -EINVAL;
}
if(!reg->msb){
lsb = value & 0xff;
}else{
msb = (value >> 8) & 0xff;
lsb = value & 0xff;
}
mutex_lock(&data->lock);
if(reg->msb){
ret = i2c_smbus_write_byte_data(data->client, reg->msb,msb);
if(ret < 0){
printk("write msb failed %d \n",ret);
goto error;
}
}
if(reg->lsb){
ret = i2c_smbus_write_byte_data(data->client, reg->lsb,lsb);
if(ret < 0){
printk("write lsb failed %d \n",ret);
goto error;
}
}
mutex_unlock(&data->lock);
return 0;
error:
mutex_unlock(&data->lock);
return ret;
}
//read adc
static ssize_t control_show_read_adc(struct device *dev, struct device_attribute *attr, char *buf)
{
//tmd26353.read_adc = reg_value;
return sprintf(buf, "%d\n", tmd26353.read_adc);
}
static ssize_t control_store_read_adc(struct device* dev, struct device_attribute *attr, const char *buf, size_t count)
{
printk("read_adc =%d \n",tmd26353.read_adc);
return count;
}
static DEVICE_ATTR(read_adc,0664, control_show_read_adc,control_store_read_adc);
static struct attribute *tmd26353_attributes[] = {
&dev_attr_read_adc.attr,
//&dev_attr_set_state.attr,
NULL
};
static const struct attribute_group tmd26353_attr_group = {
.attrs = tmd26353_attributes,
};
//Funcktion/
static int tmd26353_verify_chip_id(struct tmd26353_data *data)//struct i2c_client *client
{
u32 reg_value;
int ret;
ret = tmd26353_register_read_single(data,REG_DEVICE_ID,®_value);
if(ret){
return ret;
}
printk("DEVICE_ID = %x \n",reg_value);
return 0;
}
static int tmd26353_init(struct tmd26353_data *data)
{
u32 reg_value[] = {0x15,0x1F,0x54,0x3F,0x3F,0x8F,0x60};
int ret,length,i;
unsigned int name[] = {REG_ENABLE,REG_PRATE,REG_CALIBCFG,REG_POFFSET,
REG_CFG6_APC,REG_PCFG0,REG_PCFG1};
length = sizeof(reg_value)/sizeof(reg_value[0]);
for(i=0;i<length;++i){
ret = tmd26353_register_write_single(data,name[i],reg_value[i]);//使能
if(ret){
continue;
}
printk("name[%d]= %d,reg_value=%x\n",i,name[i],reg_value[i]);
}
return 0;
}
static void tmd26353_pen_irq_work(struct work_struct *work)
{
int ret = -1;
u32 reg_value;
ret = tmd26353_register_read_single(&tmd26353,REG_PDATA,®_value); //ADC
if(ret){
printk("tmd26353_pen_irq_work\n");
}
//printk("REG_PDATA ADC= %d\n",reg_value);
tmd26353.read_adc = reg_value;
msleep(20);
}
static irqreturn_t tmd26353_handler(int irq, void *dev_id)
{/*
int ret;
u32 reg_value;
ret = tmd26353_register_read_single(&tmd26353,REG_PDATA,®_value); //ADC
if(ret){
return ret;
}
printk("REG_PDATA ADC= %d\n",reg_value);*/
struct tmd26353_data *data = dev_id;
msleep(500);
printk("---------------enter tmd26353_handler----------------- \n");
if(!work_pending(&data->pen_event_work)){
queue_work(data->tmd26353_workqueue,&data->pen_event_work);
}
return IRQ_HANDLED;
}
static int tmd26353_irq_init(struct i2c_client *client,struct tmd26353_data *dev)
{
int ret;
dev->irq_pin = of_get_named_gpio_flags(client->dev.of_node, "anan-gpios", 0, NULL);
tmd26353.irq_pin = dev->irq_pin;
if(gpio_is_valid(dev->irq_pin)){
ret = devm_gpio_request_one(&client->dev,dev->irq_pin,GPIOF_IN,"tmd26353_irq");
if(ret){
dev_err(&client->dev,"Failed to request GPIO %d, error %d\n",dev->irq_pin, ret);
return ret;
}
}
//gpio_direction_input(dev->irq_pin);
tmd26353.irq_num = gpio_to_irq(dev->irq_pin);
ret = devm_request_threaded_irq(&client->dev,tmd26353.irq_num,tmd26353_handler,NULL,
IRQ_TYPE_LEVEL_LOW,client->name,dev);
if(ret){
dev_err(&client->dev, "Unable to request p-sensor IRQ.\n");
return ret;
}
return 0;
}
/*
static int pdata_thread(void *data)
{
int ret;
u32 reg_value;
while(!kthread_should_stop()){
ret = tmd26353_register_read_single(&tmd26353,REG_PDATA,®_value); //ADC
if(ret){
continue;
}
//printk("REG_PDATA ADC= %d\n",reg_value);
tmd26353.read_adc = reg_value;
msleep(200);
//printk("---------------enter pdata_thread----------------- \n");
}
return 0;
}*/
static int tmd26353_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct tmd26353_data *data;
printk("----------tmd26353_probe------------ \n");
if(!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
| I2C_FUNC_SMBUS_READ_BYTE_DATA)){
ret = -EIO;
dev_err(&client->dev,"i2c_check_functionality failed \n");
goto exit;
}
data = kzalloc(sizeof(struct tmd26353_data), GFP_KERNEL);
if(!data){
ret = -EIO;
dev_err(&client->dev,"kzalloc failed \n");
goto exit;
}
data->client = client;
tmd26353.client = client;
i2c_set_clientdata(client,data);
mutex_init(&data->lock);
ret = tmd26353_verify_chip_id(data);//client
if(ret){
dev_err(&client->dev,"tmd26353_verify_chip_id failed %d \n",ret);
goto exit_kfree;
}
ret = tmd26353_init(data);
if(ret){
dev_err(&client->dev,"tmd26353_init failed %d \n",ret);
goto exit_kfree;
}
///
INIT_WORK(&data->pen_event_work,tmd26353_pen_irq_work);
data->tmd26353_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
if(!data->tmd26353_workqueue){
dev_err(&client->dev,"tmd26353_workqueue failed %d \n",ret);
goto exit_kfree;
}
//irq
ret = tmd26353_irq_init(client,data);
if(ret){
dev_err(&client->dev,"tmd26353_irq_init failed %d \n",ret);
goto irq_failed;
}
/*
//thread
p_data_task = kthread_create(pdata_thread,NULL,"pdata_thread");
if(IS_ERR(p_data_task)){
dev_err(&client->dev,"kthread_create failed \n");
ret = PTR_ERR(p_data_task);
p_data_task = NULL;
goto exit_kfree;
}
wake_up_process(p_data_task);*/
/* Register sysfs hooks */
ret = sysfs_create_group(&client->dev.kobj, &tmd26353_attr_group);
if (ret)
goto sysfs_create_group_failed;
return 0;
irq_failed:
sysfs_create_group_failed:
cancel_work_sync(&data->pen_event_work);
destroy_workqueue(data->tmd26353_workqueue);
exit_kfree:
i2c_set_clientdata(client, NULL);
kfree(data);
exit:
return ret;
}
static int tmd26353_remove(struct i2c_client *client)
{
//struct iio_dev *indio_dev = i2c_get_clientdata(client);
//struct tmd26353_data *data = iio_priv(indio_dev);
//iio_device_unregister(indio_dev);
//iio_device_free(indio_dev);
//free_irq(tmd26353.irq_num,&tmd26353);
//kthread_stop(p_data_task);
//p_data_task = NULL;
struct tmd26353_data *data = i2c_get_clientdata(client);
sysfs_remove_group(&client->dev.kobj, &tmd26353_attr_group);
cancel_work_sync(&data->pen_event_work);
destroy_workqueue(data->tmd26353_workqueue);
kfree(data);
return 0;
};
static const struct i2c_device_id tmd26353_id[] = {
{"tmd26353",0},
{}
};
MODULE_DEVICE_TABLE(i2c,tmd26353_id);
static const struct of_device_id tmd26353_of_match[] = {
{.compatible = "p-sensor,tmd26353",},
{}
};
MODULE_DEVICE_TABLE(of,tmd26353_of_match);
static struct i2c_driver tmd26353_driver = {
.driver = {
.name = "tmd26353",
.of_match_table = of_match_ptr(tmd26353_of_match),
},
.probe = tmd26353_probe,
.remove = tmd26353_remove,
.id_table = tmd26353_id,
};
module_i2c_driver(tmd26353_driver);
MODULE_AUTHOR("A_NAN");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TMD26353 Proximity driver");
在学习中进步,如有错误,请多多批评指正