您的位置:首页 > 运维架构 > Linux

AM3353平台上的Linux 3.2.0 IIO子文件系统框架的驱动

2017-06-28 16:18 1086 查看
在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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐