AM2320 linux驱动程序

AM2320 linux驱动程序

采集,上报input 子系统

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>

#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/err.h>
#include <linux/i2c.h>

#include <linux/leds.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/input.h>


#include <linux/amlogic/jtag.h>
#include <linux/pwm.h>
#include <linux/amlogic/pwm_meson.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/device.h>
#include <linux/amlogic/i2c-amlogic.h>

#include "am2320.h"

static int i2c_read(struct i2c_adapter *i2c_adap,
			   unsigned char address, unsigned char *wdata,
			   unsigned int wlen, unsigned char *rdata,unsigned int rlen)
{
	struct i2c_msg msgs[2];
	int res;

	if (!rdata || !i2c_adap) {
		am2320_error("%s:line=%d,error\n",__func__,__LINE__);
		return -EINVAL;
	}

	msgs[0].addr = address;
	msgs[0].flags = 0;	/* write */
	msgs[0].buf = wdata;
	msgs[0].len = wlen;

	msgs[1].addr = address;
	msgs[1].flags = I2C_M_RD;
	msgs[1].buf = rdata;
	msgs[1].len = rlen;

	res = i2c_transfer(i2c_adap, &msgs[0], 1);
	udelay(2* 1000);
	res = i2c_transfer(i2c_adap, &msgs[1], 1);
	
	if (res == 1)
		return 0;
	else if(res == 0)
		return -EBUSY;
	else
		return res;

	return res;
}

static int i2c_rx_data(struct i2c_client *client, char * txData,int tlen,char *rxData, int rlen)
{
	int ret = 0;
	int i = 0;

	for (i = 0; i < 2; i++) {

		ret = i2c_read(client->adapter, client->addr, txData,tlen,rxData,rlen);
		if (ret < 0){
			am2320_error("haier_i2c_rx_data error\n");
		}else{
			break;
		}
	}
	return ret;
}

static int i2c_write(struct i2c_adapter *i2c_adap,
			    unsigned char address,
			    unsigned int len, unsigned char const *data)
{
	struct i2c_msg msgs[1];
	int res;

	if (!i2c_adap) {
		am2320_error("%s:line=%d,error\n",__func__,__LINE__);
		return -EINVAL;
	}

	msgs[0].addr = address;
	msgs[0].flags = 0;
	msgs[0].buf = (unsigned char *)data;
	msgs[0].len = len;

	res = i2c_transfer(i2c_adap, msgs, 1);
	if (res == 1)
		return 0;
	else if(res == 0)
		return -EBUSY;
	else
		return res;

}

static int i2c_tx_data(struct i2c_client *client, char *txData, int length)
{
	int ret = 0;
	int i = 0;

	for (i = 0; i < 3; i++) {
		ret = i2c_write(client->adapter, client->addr, length, txData);
		if (!ret)
			break;

	}
	return ret;
}

static int am2320_read_data(struct am2320_driver *am2320_driver,
				char *w_data,int w_len,char *r_data,int r_len)
{
	int ret = 0;
	ret = i2c_tx_data(am2320_driver->client,NULL,0); // wake up device
	if (ret < 0){
		am2320_error("am2320_wake_up error\n");
		return ret;
	}
	ret = i2c_rx_data(am2320_driver->client,w_data,w_len,r_data,r_len);//get data 
	if (ret < 0){
		am2320_error("am2320_read_data error\n");
		return ret;
	}
	return ret;
}

static void am2320_schedele_work(struct work_struct *work)
{
	int m_temp = 0;
	int m_humidity = 0;
	struct am2320_driver *am2320_driver = container_of((struct delayed_work *)work,
							struct am2320_driver, work);
	unsigned long delay = msecs_to_jiffies(am2320_driver->delay);
	char w_temp_data[AM2320_TEMP_RETURN_LENGTH] = {0};
	char r_temp_data[AM2320_TEMP_RETURN_LENGTH] = {0};

	w_temp_data[0] = AM2320_FUNCTION_CODE;
	w_temp_data[1] = AM2320_TEMP_HUMIDITY_ADDR;
	w_temp_data[2] = AM2320_TEMP_HUMIDITY_LENGTH;
	
	am2320_read_data(am2320_driver,w_temp_data,AM2320_CMD_LEMGTH,
			r_temp_data,AM2320_TEMP_RETURN_LENGTH);

	m_temp = ((r_temp_data[4] << 8) | r_temp_data[5]);
	m_humidity = ((r_temp_data[2] << 8) | r_temp_data[3]);
	
	input_report_abs(am2320_driver->input_dev, ABS_MISC, m_temp);
	input_sync(am2320_driver->input_dev);  //reprot temp value
	input_report_abs(am2320_driver->input_dev, ABS_X, m_humidity);
	input_sync(am2320_driver->input_dev);  //report thumidity value

	am2320_info("m_temp===%d\n",m_temp);
	am2320_info("m_humidity===%d\n",m_humidity);
	schedule_delayed_work(&am2320_driver->work, delay);
}


static int am2320_probe(struct i2c_client *client,
		     	 const struct i2c_device_id *id)
{
	int ret = 0;

	struct am2320_driver *am2320_driver = NULL;
	///static struct class *memc_class;

	am2320_driver = kzalloc(sizeof(struct am2320_driver), GFP_KERNEL);
	if (am2320_driver == NULL) {
		printk("failed to create our am2320_driver\n");
		return -ENOMEM;
	}

	am2320_driver->client = client;
	i2c_set_clientdata(client, am2320_driver);

	INIT_DELAYED_WORK(&am2320_driver->work, am2320_schedele_work);
	schedule_delayed_work(&am2320_driver->work, AM2320_SCHE_DELAY);
	am2320_driver->delay = AM2320_SCHE_DELAY;

	am2320_driver->input_dev= input_allocate_device();	
	if (!am2320_driver->input_dev) {

		am2320_error("input_allocate_device error\n");
		goto kfree_exit;	
	}
	am2320_driver->input_dev->name = DEVICE_NAME;
	am2320_driver->input_dev->id.bustype = BUS_I2C;
	input_set_capability(am2320_driver->input_dev, EV_ABS, ABS_MISC);
	input_set_abs_params(am2320_driver->input_dev, ABS_MISC, 0, 8192, 0, 0);
	input_set_abs_params(am2320_driver->input_dev, ABS_X, 0, 8192, 0, 0);
	input_set_drvdata(am2320_driver->input_dev, am2320_driver);
	
	ret = input_register_device(am2320_driver->input_dev);
	if (ret < 0) {
		input_free_device(am2320_driver->input_dev);
		goto kfree_exit;
	}
	
	mutex_init(&am2320_driver->mutex);

	
	return 0;

kfree_exit:
	kfree(am2320_driver);
	return -ENODEV;

}

static int am2320_remove(struct i2c_client *client)
{
	struct am2320_driver *am2320_driver = i2c_get_clientdata(client);
	i2c_unregister_device(am2320_driver->client);
	kfree(am2320_driver);
	return 0;
}



static const struct of_device_id i2c_am2320_of_match[] = {
	{ .compatible = "max,am2320" },
	{ }
};

static const struct i2c_device_id am2320_device_id[] = {
	{DEVICE_NAME, 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, am2320_device_id);


static struct i2c_driver am2320_driver = {
	.driver = {
		.name	= DRIVER_NAME,
		.owner  = THIS_MODULE,
		.of_match_table = of_match_ptr(i2c_am2320_of_match),
	},
	.probe = am2320_probe,
	.remove = am2320_remove,
	.id_table	= am2320_device_id,
};


static int __init am2320_init(void)
{

	i2c_add_driver(&am2320_driver);
	return 0;
}

static void __exit am2320_exit(void)
{
	i2c_del_driver(&am2320_driver);
}

module_init(am2320_init);
module_exit(am2320_exit);

MODULE_DESCRIPTION("Am2320 Temp and Humidity Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("738270732@qq.com");

#ifndef __AM2320_H_
#define __AM2320_H_

#define DEVICE_NAME 	"am2320"
#define DRIVER_NAME     "am2320"

struct am2320_driver {
	
	int  debug_level;
	int  delay;	
	int  enable;	
	struct mutex mutex;
	struct i2c_client	*client;
	struct device		*dev;
	struct delayed_work work;
	struct input_dev    *input_dev;
};
#define AM2320_FUNCTION_CODE 		0x03
#define AM2320_TEMP_HUMIDITY_ADDR   0x00
#define AM2320_HUMIDITY_ADDR        0x00
#define AM2320_TEMP_ADDR  			0x02
#define AM2320_DEVICE_ID_ADDR       0x08
#define AM2320_TEMP_HUMIDITY_LENGTH 0x04
#define AM2320_DEVICE_ID_LENGTH		0x07
#define AM2320_CMD_LEMGTH           0x03
#define AM2320_TEMP_RETURN_LENGTH  	0x08 
#define AM2320_DEVICE_RETURN_LENGTH 0x0B
#define AM2320_SCHE_DELAY			5000
#define LOG_LEVEL_NONE 		0
#define LOG_LEVEL_ERROR 	1
#define LOG_LEVEL_NOTICE	2
#define LOG_LEVEL_WARNING 	3
#define LOG_LEVEL_INFO 		4
#define LOG_LEVEL_VERBOSE 	5
#define AM2320_DEBUG_LEVEL 	5

#define AM2320_LOG_DYNAMIC_CONTROL
#ifdef 	AM2320_LOG_DYNAMIC_CONTROL

	#define am2320_error(...){ \
		if(AM2320_DEBUG_LEVEL >= LOG_LEVEL_ERROR) { \
			printk(KERN_ERR "AM2320 Error: "  __VA_ARGS__); \
		}\
	}

	#define am2320_notice(...){ \
		if(AM2320_DEBUG_LEVEL >= LOG_LEVEL_NOTICE) { \
			printk(KERN_NOTICE "AM2320 Notice: "  __VA_ARGS__); \
		}\
	}

	#define am2320_warning(...){ \
		if(AM2320_DEBUG_LEVEL >= LOG_LEVEL_WARNING) { \
			printk(KERN_WARNING "AM2320 Warning: "  __VA_ARGS__); \
		}\
	}

	#define am2320_info(...){ \
		if(AM2320_DEBUG_LEVEL >= LOG_LEVEL_INFO) { \
			printk(KERN_INFO "AM2320 Info: "  __VA_ARGS__); \
		}\
	}

#endif
#endif

&i2c1 {
	status = "okay";
	clock-frequency = <300000>;
	pinctrl-names="default";
	pinctrl-0=<&i2c1_h_pins>;
	am2320@5c{
		compatible = "max,am2320";
		reg = <0x5c>;
		status = "okay";
	};
};

App端测试

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include "android/log.h"
#include <cutils/properties.h>
#include <stdbool.h>
#include <linux/input.h>

int main()
{
	struct input_event inputevent;
	int fd;
	int err;

	fd = open("/dev/input/event2", O_RDWR);
 	if (fd < 0) {

		printf("Can't open file %s\r\n", "/dev/input/event2");
 		return -1;
 	}
	while (1) {

		err = read(fd, &inputevent, sizeof(inputevent));
		if (err > 0) {

			switch (inputevent.type) {

				case EV_ABS:

					printf("input_code==%d\n",inputevent.code);
					printf("input_type==%d\n",inputevent.type);
					printf("input_value==%d\n",inputevent.value);
					break;
				default:
					break;
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值