linux input子系统实例分析 -- 2 als&ps 数据上报

项目中要用到光感传感器,选型SFH7779,als&ps功能

其中als包括可见光和红外,项目中因为不需要距离和红外,所以只使用了可将光功能

SFH7779接口如下,看到其实是有中断脚的,但是项目中实际只有i2c和power,中断脚没有接

所以在写程序的时候,打算使用input的poll功能进行数据上报。

直接贴代码

/*
 * Driver for SFH7779 als&ps sensor
 */


#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input-polldev.h>

int sfh_debug;
module_param_named(debug, sfh_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");

#define sfh_dbg(level, debug, dev, fmt, arg...)			\
	do {								\
		if (debug >= (level))					\
			printk(KERN_CRIT "%s: " fmt, (dev)->name, ## arg);  \
	} while (0)


#define SFH7779_NAME "sfh7779"

#define SFH7779_CHIP_ID			0x09
#define SFH7779_CHIP_ID_MASK 	0x3f

#define SFH7779_SYS_CTL_REG		0x40
#define SFH7779_MODE_CTL_REG	0x41
#define SFH7779_ALSPS_CTL_REG	0x42
#define SFH7779_ALS_VIS_DL_REG	0x46
#define SFH7779_ALS_VIS_DH_REG	0x47

struct sfh7779_dev {
	struct i2c_client *client;
	struct input_polled_dev *poll_dev;
	struct mutex sfh_lock;
};

static void alsps_poll(struct input_polled_dev *poll_dev)
{
	struct sfh7779_dev *sfh_dev = poll_dev->private;
	struct i2c_client *client = sfh_dev->client;
	struct input_dev *input=  sfh_dev->poll_dev->input;
	int als_l, als_h, als_value;
	static u8 cnt = 0;

	sfh_dbg(1, sfh_debug, client, "%s\n", __func__);
	
	if (cnt % 2) {
		i2c_smbus_write_byte_data(client, SFH7779_ALSPS_CTL_REG, 0x7f);
		i2c_smbus_write_byte_data(client, SFH7779_MODE_CTL_REG, 0x0a);
	} else {
		als_l = i2c_smbus_read_byte_data(client, SFH7779_ALS_VIS_DL_REG) & 0xff;
		als_h = i2c_smbus_read_byte_data(client, SFH7779_ALS_VIS_DH_REG) & 0xff;

		als_value = (als_h << 8 ) | als_l;

		sfh_dbg(1, sfh_debug, client, "als_value = 0x%04x\n", als_value);
		input_report_abs(input, ABS_MISC, als_value);
		input_sync(input);	
	}
	cnt++;
}

int sfh7779_check_id(struct i2c_client *client)
{
	int data;
	data = i2c_smbus_read_byte_data(client, SFH7779_SYS_CTL_REG);
	if (data < 0) {
		printk(KERN_CRIT "id read error\n");
		return -1;
	}

	if ((data & SFH7779_CHIP_ID_MASK) != SFH7779_CHIP_ID) {
		printk(KERN_CRIT "id wrong!\n");
		return -1;
	}

	return 0;
}

static int sfh7779_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct sfh7779_dev *sfh_dev;
	struct input_polled_dev *poll_dev;
	struct input_dev *input;
	int value;
	int ret;

	if (sfh7779_check_id(client) != 0) {
		 dev_err(dev,"sfh7779 not exist, please check!\n");
		 return -1;
	}

	sfh_dev = devm_kzalloc(dev, sizeof(*sfh_dev), GFP_KERNEL);
	if (!sfh_dev)
		return -ENOMEM;

	sfh_dev->client = client;

	poll_dev = devm_input_allocate_polled_device(dev);
	if (!poll_dev) {
		dev_err(dev, "failed to allocate input device\n");
		return -ENOMEM;
	}

	mutex_init(&sfh_dev->sfh_lock);

	if (!device_property_read_u32(dev, "poll-interval", &value)) {
		poll_dev->poll_interval = value;
	} else {
		poll_dev->poll_interval = 500;
	}

	poll_dev->poll = alsps_poll;
	poll_dev->private = sfh_dev;

	sfh_dev->poll_dev = poll_dev;
	input = poll_dev->input;

	input->name = client->name;
	input->dev.parent = dev;

	input->id.bustype = BUS_HOST;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0001;

	input_set_abs_params(input, ABS_MISC, 0, 0xffff, 0, 0);

	input_set_drvdata(input, sfh_dev);

	i2c_set_clientdata(client, sfh_dev);

	ret = input_register_polled_device(poll_dev);
	if (ret) {
		dev_err(dev, "Unable to register input device, error: %d\n",
				ret);
		return ret;
	}

	printk(KERN_CRIT "%s\n", __func__);
	return 0;
}

static int sfh7779_remove(struct i2c_client *client)
{
	struct sfh7779_dev *sfh_dev = i2c_get_clientdata(client);
	mutex_destroy(&sfh_dev->sfh_lock);
	return 0;
}

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id sfh7779_of_match[] = {
	{ .compatible = "sfh7779" },
	{},
};
MODULE_DEVICE_TABLE(of, sfh7779_of_match);
#endif

static const struct i2c_device_id sfh7779_match_id[] = {
	{"sfh7779", 0 },
	{ },
};

static struct i2c_driver sfh7779_i2c_driver = {
	.driver = {
		.name = SFH7779_NAME,
		.of_match_table = of_match_ptr(sfh7779_of_match),
	},
	.probe		= &sfh7779_probe,
	.remove		= &sfh7779_remove,
	.id_table	= sfh7779_match_id,
};

static int __init sfh7779_mod_init(void)
{
	return i2c_add_driver(&sfh7779_i2c_driver);
}

static void __exit sfh7779_mod_exit(void)
{
	i2c_del_driver(&sfh7779_i2c_driver);
}

device_initcall_sync(sfh7779_mod_init);
module_exit(sfh7779_mod_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dianlong Li <dianlong_lee@163.com>");
MODULE_DESCRIPTION("Driver for als&ps sensor SFH7779");

代码中input上报事件选择的是EV_ABS,绝对坐标的方式上报,这里不能以为EV_ABS就是用于触摸屏这种,如果有一天我们使用了温度传感器,那么温度的值也完全可以使用EV_ABS事件,只要和应用协商好事件以及事件使用的编码,通信完全没有问题

下面再说一下代码的部分细节,在poll函数中,默认是500ms轮询一次,但是在poll中发现,其实先进行启动als检测,再次poll的时候才进行数据上报,这样的原因是,当前配置的als增益比较高,导致每次转换都需要大约400ms的事件,所以这里才会这样操作。

ok,这个就到这里了。

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值