AM3353平台上的Linux 3.2.0 IIO子文件系统框架的驱动
在Linux kernel 3.2已经引入了IIO子文件系统,但是驱动不多,毕竟刚开始的一个新的子文件系统 。在kernel 3.x版本中目录在drivers/staging/iio目录下,到了kernel 4.x版本下被移到了drivers/iio,显然大家认可了这个子文件系统的框架。由于我所使用的平台是 kernel 3.2版本,在对DHT11的驱动上这一版本并没支持,需要自己的移植。虽然
在Linux kernel 3.2已经引入了IIO子文件系统,但是驱动不多,毕竟刚开始的一个新的子文件系统 。在kernel 3.x版本中目录在drivers/staging/iio目录下,到了kernel 4.x版本下被移到了drivers/iio,显然大家认可了这个子文件系统的框架。
由于我所使用的平台是 kernel 3.2版本,在对DHT11的驱动上这一版本并没支持,需要自己的移植。虽然kernel 4.x有了支持,但是对整体版本升级,有所得不偿失。我就自己移植了。
下面的记录就是对移植过程的记录:
1、修改kernel-3.2/drivers/staging/iio目录下的industrialio-core.c文件:
static const char * const iio_chan_type_name_spec[] = {
[IIO_VOLTAGE] = "voltage",
[IIO_CURRENT] = "current",
[IIO_POWER] = "power",
[IIO_ACCEL] = "accel",
[IIO_ANGL_VEL] = "anglvel",
[IIO_MAGN] = "magn",
[IIO_LIGHT] = "illuminance",
[IIO_INTENSITY] = "intensity",
[IIO_PROXIMITY] = "proximity",
[IIO_TEMP] = "temp",
[IIO_HUMIDITYRELATIVE] = "humidityrelative", //增加湿度
[IIO_INCLI] = "incli",
[IIO_ROT] = "rot",
[IIO_ANGL] = "angl",
[IIO_TIMESTAMP] = "timestamp",
[IIO_CAPACITANCE] = "capacitance",
};
蓝色的文集是增加的,这个版本已经支持了温度,但是没有支持湿度,因此需要增加。
2、修改kernel-3.2/drivers/staging/iio目录下的iio.h文件:
enum iio_chan_type {
/* real channel types */
IIO_VOLTAGE,
IIO_CURRENT,
IIO_POWER,
IIO_ACCEL,
IIO_ANGL_VEL,
IIO_MAGN,
IIO_LIGHT,
IIO_INTENSITY,
IIO_PROXIMITY,
IIO_TEMP,
IIO_HUMIDITYRELATIVE, //增加湿度
IIO_INCLI,
IIO_ROT,
IIO_ANGL,
IIO_TIMESTAMP,
IIO_CAPACITANCE,
};
3、复制网上找到kernel 4.4.1版本中的/drivers/iio/humidity目录到kernel-3.2/drivers/staging/iio目录下,并修改Kconfig
source "drivers/staging/iio/humidity/Kconfig"
4、修改Makefile
obj-y += humidity/
x -> Device Drivers x
x -> Staging drivers (STAGING [=y]) x
x -> Industrial I/O support (IIO [=y]) x
x -> Humidity sensors x
5、因为kernel 4.4 相对 kernel 3.2 增加很对新函数所以不能直接使用原先的dht11.c驱动文件,需要自己重新编写,废话不多少。
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/ktime.h>
//#include <linux/timekeeping.h>
//#include "/home/zuoyi/works/kernel-3.2/drivers/staging/iio/iio.h"
#include "../iio.h"
#define DRIVER_NAME "dht11"
/* Convert GPIO signal to GPIO pin number */
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
#define DHT11_GPIO GPIO_TO_PIN(1, 26)
#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */
#define DHT11_EDGES_PREAMBLE 2
#define DHT11_BITS_PER_READ 40
/*
* Note that when reading the sensor actually 84 edges are detected, but
* since the last edge is not significant, we only store 83:
*/
#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
DHT11_EDGES_PREAMBLE + 1)
/* Data transmission timing (nano seconds) */
#define DHT11_START_TRANSMISSION 18 /* ms */
#define DHT11_SENSOR_RESPONSE 80000
#define DHT11_START_BIT 50000
#define DHT11_DATA_BIT_LOW 27000
#define DHT11_DATA_BIT_HIGH 70000
struct dht11 {
struct device *dev;
int gpio;
int irq;
struct completion completion;
/* The iio sysfs interface doesn't prevent concurrent reads: */
struct mutex lock;
s64 timestamp;
int temperature;
int humidity;
/* num_edges: -1 means "no transmission in progress" */
int num_edges;
struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ];
};
/* 读取单字节(8 bit)数据 */
static char DHT11_read_byte ( void )
{
char DHT11_byte ;
unsigned char i ;
unsigned char temp ;
DHT11_byte = 0 ;
for ( i = 0 ; i < 8 ; i ++ )
{
temp = 0 ;
while ( ! (gpio_get_value(DHT11_GPIO) ) )
{
temp ++ ;
if ( temp > 12 )
return 1 ;
udelay ( 5 ) ;
}
temp = 0 ;
while ( gpio_get_value(DHT11_GPIO) )
{
temp ++ ;
if ( temp > 20 )
return 1 ;
udelay ( 5 ) ;
}
if ( temp > 6 )
{
DHT11_byte <<= 1 ;
DHT11_byte |= 1 ;
}
else
{
DHT11_byte <<= 1 ;
DHT11_byte |= 0 ;
}
}
return DHT11_byte ;
}
static int dht11_read_raw(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long m)
{
struct dht11 *dht11 = iio_priv(iio_dev);
int ret;//, timeres;
unsigned char DataTemp;
unsigned char i;
unsigned char err;
char tempBuf[5]={0};
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
mutex_lock(&dht11->lock);
err = 0 ;
/* 管脚设置为输出并拉低电平 */
gpio_direction_output(DHT11_GPIO, 0);
msleep ( 18 );
//mdelay ( 18 );
gpio_set_value(DHT11_GPIO, 1);
udelay ( 40 );
gpio_direction_input(DHT11_GPIO);
if ( !err )
{
DataTemp = 10 ;
while ( !( gpio_get_value(DHT11_GPIO) ) && DataTemp )
{
DataTemp --;
udelay ( 10 );
}
if ( !DataTemp )
{
err = 1;
ret = -EFAULT;
goto err;
}
}
if ( !err )
{
DataTemp = 10 ;
while ( gpio_get_value(DHT11_GPIO) && DataTemp )
{
DataTemp --;
udelay ( 10 );
}
if ( !DataTemp )
{
err = 1;
ret = -EFAULT;
goto err;
}
}
if ( !err )
{
for ( i = 0; i < 5; i ++ )
{
tempBuf[i] = DHT11_read_byte () ;
}
DataTemp = 0 ;
for ( i = 0; i < 4; i ++ )
{
DataTemp += tempBuf[i] ;
}
if ( DataTemp != tempBuf[4] )
{
ret = -EFAULT;
goto err;
}
}
hum_int = tempBuf[0];
hum_dec = tempBuf[1];
temp_int = tempBuf[2];
temp_dec = tempBuf[3];
checksum = tempBuf[4];
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
return -EIO;
//printk( "Humidity:%d.%d %%RH Temperature:%d.%d C sum is:%d\n", tempBuf[0], tempBuf[1], tempBuf[2], tempBuf[3],tempBuf[4] ) ;
dht11->temperature = (((temp_int & 0x7f)* 100) + temp_dec) * ((temp_int & 0x80) ? -1 : 1);
dht11->humidity = ((hum_int * 100) + hum_dec);
ret = IIO_VAL_INT;
if (chan->type == IIO_TEMP)
*val = dht11->temperature;
else if (chan->type == IIO_HUMIDITYRELATIVE)
*val = dht11->humidity;
else
ret = -EINVAL;
err:
dht11->num_edges = -1;
mutex_unlock(&dht11->lock);
/* 管脚设置为输出并拉高 */
gpio_direction_output(DHT11_GPIO, 1);
return ret;
}
static const struct iio_info dht11_iio_info = {
.driver_module = THIS_MODULE,
.read_raw = dht11_read_raw,
};
//static const struct iio_chan_spec dht11_chan_spec[] = {
// { .type = IIO_TEMP,
// //.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
// { .type = IIO_HUMIDITYRELATIVE,
// //.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }
//};
static const struct iio_chan_spec dht11_chan_spec[] = {
{
.type = IIO_TEMP,
//.indexed = 2,
.channel = 1,
}, {
.type = IIO_HUMIDITYRELATIVE,
//.indexed = 1,
.channel = 0,
}
};
static const struct of_device_id dht11_dt_ids[] = {
{ .compatible = "dht11", },
{ }
};
MODULE_DEVICE_TABLE(of, dht11_dt_ids);
/* 探测函数 */
static int dht11_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
//struct device_node *node = dev->of_node;
struct dht11 *dht11;
struct iio_dev *iio;
int ret;
/* 1、分配一个IIO设备 */
// iio = devm_iio_device_alloc(dev, sizeof(*dht11));
// if (!iio) {
// dev_err(dev, "Failed to allocate IIO device\n");
// return -ENOMEM;
// }
iio = iio_allocate_device(sizeof(struct dht11));
if (!iio) {
dev_err(dev, "Failed to allocate IIO device\n");
return -ENOMEM;
}
/* 2、设置IIO设备 */
dht11 = iio_priv(iio);
dht11->dev = dev;
/* 1、申请管脚 */
ret = gpio_request(DHT11_GPIO, "dht11_gpio");
if (ret)
goto free_master;
/* 2、管脚设置为输出并拉高 */
gpio_direction_output(DHT11_GPIO, 1);
platform_set_drvdata(pdev, iio);
init_completion(&dht11->completion);
mutex_init(&dht11->lock);
iio->name = pdev->name;
iio->dev.parent = &pdev->dev;
iio->info = &dht11_iio_info;
iio->modes = INDIO_DIRECT_MODE;
iio->channels = dht11_chan_spec;
iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
/* 3、注册一个IIO设备 */
return iio_device_register(iio);
free_master:
return ret;
}
static struct platform_driver dht11_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = dht11_dt_ids,
},
.probe = dht11_probe,
};
module_platform_driver(dht11_driver);
MODULE_AUTHOR("zue ");
MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
MODULE_LICENSE("GPL v2");
6、修改arch/arm/mach-omap2/board-am335xevm.c增加一个device驱动
/* add a dht11 */
static struct platform_device dht11_device = {
.name = "dht11",
.id = -1,
};
static void dht11_init(int evm_id, int profile )
{
int err;
err = platform_device_register(&dht11_device);
if (err)
pr_err("failed to register dht11 device\n");
else
pr_info("register dht11 device ok\n");
}
static struct evm_dev_cfg ok335x_dev_cfg[] = {
......
{dht11_init, DEV_ON_BASEBOARD, PROFILE_ALL},
重新编译并烧写新内核。
[ 0.091666] register dht11 device ok
在/sys/bus/iio/devices可以看到一个新的iio设备
/sys/bus/iio/devices # ls
iio:device0 iio:device1
/sys/devices/platform/dht11/iio:device1 # ls -l
total 0
-r--r--r-- 1 0 0 4096 Jun 28 15:36 dev
-r--r--r-- 1 0 0 4096 Jun 28 15:36 in_humidityrelative_raw
-r--r--r-- 1 0 0 4096 Jun 28 15:36 in_temp_raw
-r--r--r-- 1 0 0 4096 Jun 28 15:36 name
drwxr-xr-x 2 0 0 0 Jun 28 15:36 power
lrwxrwxrwx 1 0 0 0 Jun 28 15:36 subsystem -> ../../../../bus/iio
-rw-r--r-- 1 0 0 4096 Jun 28 15:36 uevent
/sys/devices/platform/dht11/iio:device1 # cat name
dht11
/sys/devices/platform/dht11/iio:device1 # cat in_temp_raw
2800
/sys/devices/platform/dht11/iio:device1 # cat in_humidityrelative_raw
3100
获取的温度和湿度数据。注意获取真实数字需要除以100,例如2800/100=28摄氏度,3100/100=31%PH
也可以在下面的路径读取。其实是一样的。
/sys/devices/platform/dht11/iio:device1 # ls -l
total 0
-r--r--r-- 1 0 0 4096 Jun 28 15:36 dev
-r--r--r-- 1 0 0 4096 Jun 28 15:36 in_humidityrelative_raw
-r--r--r-- 1 0 0 4096 Jun 28 15:36 in_temp_raw
-r--r--r-- 1 0 0 4096 Jun 28 15:36 name
drwxr-xr-x 2 0 0 0 Jun 28 15:36 power
lrwxrwxrwx 1 0 0 0 Jun 28 15:36 subsystem -> ../../../../bus/iio
-rw-r--r-- 1 0 0 4096 Jun 28 15:36 uevent
更多推荐
所有评论(0)