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;
}