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;elsereturn 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;elsereturn 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 deviceif (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 valueinput_report_abs(am2320_driver->input_dev, ABS_X, m_humidity);input_sync(am2320_driver->input_dev); //report thumidity valueam2320_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;
}