在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/


在make menuconfig
 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



Logo

更多推荐