天天看點

[RK3399][Android7.1]編寫一個安卓的GPIO驅動

1、在kernel/drivers目錄下建立ioctrl檔案夾

# cd kernel/drivers

# mkdir ioctrl

在/driver/ioctrl目錄下,建立ioctrl.c ,ioctrl.h , Kconfig, Makefile 等4個檔案。

2、在Kconfig下添加代碼:

config IOCTRL
        tristate "io Control"
        default y
        help
          when system setup,change the io state
           

在Makefile下添加代碼:

obj-$(CONFIG_IOCTRL)                    += ioctrl.o
           

在ioctrl.c中添加代碼:

/*
 * Driver for pwm demo on Firefly board ioctrl.
 *
 * Copyright (C) 2022, Zhongshan T-chip Intelligent Technology Co.,ltd.
 * Copyright 2006  Sam Chan
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/**********************************************************************
 * version control
 *
 * version: v1.0.0_20191022
 * creater: dulc
 * creat date: 2019.10.22
 * changer: 
 * chang date:
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/delay.h>


#define IOCTRL_MAJOR	97


struct firefly_ioctrl_info {
    int gpio_wireless_en;        // 3g/4g power control
    int gpio_we_value;
};



static int firefly_ioctrl_probe(struct platform_device *pdev);

// ioctrl operation 
ssize_t ioctrl_read( struct file * file, char * buf, size_t count, loff_t * f_ops );
ssize_t ioctrl_write( struct file * file, const char * buf, size_t count, loff_t *f_ops );
long ioctrl_ioctl( struct file *file, unsigned int cmd, unsigned long arg);
int ioctrl_open( struct inode * inode, struct file *file );
int ioctrl_release(struct inode *inode, struct file *file );
int ioctrl_led_control( char cmd, char subcmd );



/*********************************GPIO*************************************/
static struct of_device_id firefly_ioctrl_match_table[] = {
	{ .compatible = "firefly,rk3399-gpio1",},
	{},
};

static struct platform_driver firefly_ioctrl_driver = {
	.driver = {
		.name = "firefly-ioctrl",
		.owner = THIS_MODULE,
		.of_match_table = firefly_ioctrl_match_table,
	},
	.probe = firefly_ioctrl_probe,
};
/*********************************GPIO*************************************/





// the ioctrl operations device
static const struct file_operations io_ctrl_ops = {
	.owner		= THIS_MODULE,
	.open		= ioctrl_open,
	.read		= ioctrl_read,
	.write		= ioctrl_write,
	.unlocked_ioctl	= ioctrl_ioctl,
	.release	= ioctrl_release,
};



// gpio device
struct firefly_ioctrl_info *ioctrl_device_ctrl = NULL;




ssize_t ioctrl_read( struct file * file, char * buf, size_t count, loff_t * f_ops )
{
	ssize_t size = 0;

	return size;
}


ssize_t ioctrl_write(struct file * file, const char * buf, size_t count, loff_t *f_ops )
{
	ssize_t size = 0;

	return size;
}



long ioctrl_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
	long ret = 0;
	
	if ( cmd == 0 )
        {
            gpio_direction_output(ioctrl_device_ctrl->gpio_wireless_en, false);
        }
	else
	{
            gpio_direction_output(ioctrl_device_ctrl->gpio_wireless_en, true);
	}

	return ret;
}



int ioctrl_open( struct inode * inode, struct file *file )
{
	return 0;
}



int ioctrl_release(struct inode *inode, struct file *file )
{
	return 0;
}



static int firefly_ioctrl_probe(struct platform_device *pdev)
{
    int gpio;
    enum of_gpio_flags flag;
    struct firefly_ioctrl_info *gpio_info;
    struct device_node *firefly_ioctrl_node = pdev->dev.of_node;

	gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct firefly_ioctrl_info *), GFP_KERNEL);
	if (!gpio_info) {
        dev_err(&pdev->dev, "devm_kzalloc failed!\n");
		return -ENOMEM;
	}
	
    // 3g/4g power control
     gpio = of_get_named_gpio_flags(firefly_ioctrl_node, "firefly-gpio-wireless", 0, &flag);
    if (!gpio_is_valid(gpio)) {
        dev_err(&pdev->dev, "firefly-gpio-wireless: %d is invalid\n", gpio);
        return -ENODEV;
    }
    if (gpio_request(gpio, "firefly-gpio-wireless")) {
        dev_err(&pdev->dev, "firefly-gpio-wireless: %d request failed!\n", gpio);
        gpio_free(gpio);
        return -ENODEV;
    }
    
    printk("ioctrl driver register success!\n");

    gpio_info->gpio_wireless_en = gpio;
   // gpio_info->gpio_pe_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
    gpio_direction_output(gpio_info->gpio_wireless_en, false);

    ioctrl_device_ctrl = gpio_info;


    return 0;
}




// init the ioctrl driver
static int ioctrl_init(void)
{
	int ret = -ENODEV;
	int ret_val = 0xFFFFFFFF;
	struct class *ioctrl_dev_class;


	// register GPIO driver
	platform_driver_register(&firefly_ioctrl_driver);
	
	// register driver
	ret = register_chrdev( IOCTRL_MAJOR, "ioctrldrive", &io_ctrl_ops );
	if ( ret < 0 )
	{
		printk("register ioctrl driver error! \n");
		return ret;
	}
	// creat class
	ioctrl_dev_class = class_create( THIS_MODULE, "ioctrldrive" );
	if ( IS_ERR(ioctrl_dev_class) )
	{
		unregister_chrdev( IOCTRL_MAJOR, "capi20");
		return PTR_ERR(ioctrl_dev_class);
	}
	// creat node
	device_create( ioctrl_dev_class, NULL, MKDEV(IOCTRL_MAJOR,0),NULL, "ioctrl");

	
	return ret_val;
}
module_init(ioctrl_init);


static void ioctrl_exit(void)
{
	platform_driver_unregister(&firefly_ioctrl_driver);

}
module_exit(ioctrl_exit);


MODULE_AUTHOR("dulc <[email protected]>");
MODULE_DESCRIPTION("Firefly ioctrl demo driver");
MODULE_ALIAS("platform:firefly-ioctrl");
MODULE_LICENSE("GPL");
           

在kernel/drivers目錄下的Makefile檔案下,添加以下代碼:

obj-$(CONFIG_IOCTRL)            += ioctrl/
           

在kernel/drivers目錄下的Kconfig檔案下,添加以下代碼:

source "drivers/ioctrl/Kconfig"
           

這時代碼預設就編譯到了kernel中,在kernel檔案夾下,執行指令

# make menuconfig

選擇Device Drivers,可看到編譯進去的驅動

[RK3399][Android7.1]編寫一個安卓的GPIO驅動

(預設為選中狀态(*),是由于ioctrl檔案夾下的Kconfig配置為 tristate  "io Control"   default y,  io Control是名稱,default y是預設開啟,預設關閉用default n)

3、編寫C語言測試程式。

在 your_android_src/external目錄下,建立檔案夾

# mkdir ioctrltest

在該檔案夾下添加兩個檔案:Android.mk 、ioctrltest.c

在Android.mk檔案中添加代碼:

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= ioctrltest.c
LOCAL_MODULE:=ioctrlapp
include $(BUILD_EXECUTABLE)
           

其中 LOCAL_SRC_FILES為測試程式的源檔案,LOCAL_MODULE為生成的可執行檔案。

在ioctrltest.c中添加代碼:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_NAME "/dev/ioctrl"


int main( int argc, char ** argv )
{
	int fd;
	char cmd, subcmd;
	int i;

	printf("\n -----turn on the 3g power ----- \n");
	fd = open(DEVICE_NAME, O_RDWR );
	printf("fd = %d \n", fd );

	if ( fd == -1 )
	{
		printf("open device %s error \n", DEVICE_NAME );
	}
	else
	{
		// turn on the 3g power
		ioctl(fd, 1, 0);
	}
}
           

在安卓目錄下,執行

# make ioctrlapp

會在  out/target/product/rk3399_firefly_box/system/bin/ioctrlapp  生成相應的ioctrlapp (目錄可能不同,根據自己實際情況操作)

把ioctrlapp拷貝到優盤中,啟動rk3399,将優盤插入3399,然後在調試模式下,執行如下操作,可運作該程式

$su
#cp mnt/medea_rw/(upan_name)/ioctrlapp /mnt/ioctrlapp
#cd mnt
./ioctrlapp
           

注:在dev下生成的ioctrl驅動,要擷取權限才可打開,臨時擷取權限,使用以下指令:

# chmod 777 /dev/ioctrl

永久擷取權限,參照以下連結執行即可:

https://blog.csdn.net/d4l6c8/article/details/101345756

4、開啟啟動該程式ioctrlapp。

在device/rockchip/rk3399/device.mk中添加以下語句:

PRODUCT_COPY_FILES += \
        out/target/product/rk3399_firefly_aiojd4_mipi_box/system/bin/ioctrlapp:system/bin/ioctrlapp
           

在/device/rockchip/rk3399/rk3399_firefly_aiojd4_mipi_box目錄下的init.rc 下添加以下語句:

#dlc add
service service_ioctrl /system/bin/ioctrlapp
    user root
    group root
    disabled
    oneshot

on property:sys.boot_completed=1
           

注意 service_ioctrl這個服務名稱不能超過16個位元組,否則認為該服務有問題,不會啟動該服務。

在/device/rockchip/common/sepolicy目錄下新增檔案service_ioctrl.te,添加如下代碼:

type service_ioctrl, domain;
type service_ioctrl_exec, exec_type, file_type;
permissive service_ioctrl;
init_daemon_domain(service_ioctrl)
           

在/device/rockchip/common/sepolicy目錄下新增檔案ioctrl_device.te,添加如下代碼:

type ioctrl_device,file_type,dev_type;
           

在file_contexts檔案中添加如下代碼:

#service_ioctrl
/system/bin/ioctrlapp           u:object_r:service_ioctrl_exec:s0
/dev/ioctrl                     u:object_r:ioctrl_device:s0
           

到這裡基本完成,路徑根據自己的工程修改。