一、概述
SemiDrive X9H 擁有不同的 domain 域,例如 AP,Safety,Secure 等等。對(duì)于 GPIO 資源,不同 domain 之間 gpio 控制器是不同的,本次主要是使用的 AP 使用的是 gpio4 控制器。除了GPIO 控制器在不同 domain 之間不同以外,pin 也是有各自不同的 domain 的,但是當(dāng)它作為 gpio 使用時(shí),可以通過(guò)設(shè)置掛靠到對(duì)應(yīng)域下的 gpio 控制器上來(lái)在對(duì)應(yīng) domain 下使用。具體 pin 的 gpio 控制器的設(shè)置是通過(guò) PC 工具 SDConfigTool 來(lái)進(jìn)行。
本文主要是講述將 pin 作為 GPIO 使用,之后編寫(xiě)字符設(shè)備驅(qū)動(dòng),測(cè)試。
二、適用環(huán)境
硬件:SemiDrive SD003_X9H REF_A03 DEMO Board
軟件:X9 PTG3.9
三、設(shè)備樹(shù)匹配
1、復(fù)用管腳為 GPIO
路徑:
/buildsystem/yocto/source/linux/arch/arm64/boot/dts/semidrive/x9_high_ref_native_serdes_nobt.dts
在上面 dts 文件的 &pinctrl 的 sdx9-evk 中添加管腳復(fù)用,主要是將 GPIO_C1 管腳復(fù)用成 GPIO。
pinctrl_gpio_learning: gpiogrp_learning {
kunlun,pins = <
X9_PINCTRL_GPIO_C1__GPIO_MUX2_IO1_1 0x00
>;
};
2、配置一個(gè)新節(jié)點(diǎn)
路徑:
/buildsystem/yocto/source/linux/arch/arm64/boot/dts/semidrive/x9_high_ref_native_serdes_nobt.dts
在上面 dts 文件里面的根節(jié)點(diǎn) / 下新建一個(gè)節(jié)點(diǎn),添加屬性,獲取 gpio 編號(hào)。
gpio_learning {
#address-cells = <1>;
#size-cells = <1>;
compatible = "gpioled_learning";
pinctrl-0 = <&pinctrl_gpio_learning>;
gpio = <&port4b 17 GPIO_ACTIVE_HIGH>;
status = "okay";
};
四、驅(qū)動(dòng)編寫(xiě)
1、模塊出/入口函數(shù)
其中 module_init 是驅(qū)動(dòng)入口函數(shù),主要進(jìn)行 platform 平臺(tái)驅(qū)動(dòng)注冊(cè),module_exit 是驅(qū)動(dòng)出口函數(shù),主要是進(jìn)行 platform 平臺(tái)驅(qū)動(dòng)注銷(xiāo);
其中 MODULE_LICENSE 主要是聲明模塊許可證,一般為 GPL。
/*設(shè)備入口函數(shù)*/
static int __init gpio_learning_init(void)
{
return platform_driver_register(&gpio_learning_driver);
}
/*設(shè)備出口函數(shù)*/
static void __exit gpio_learning_exit(void)
{
platform_driver_unregister(&gpio_learning_driver);
}
/*指定上面的入口和出口函數(shù)*/
module_init(gpio_learning_init);
module_exit(gpio_learning_exit);
MODULE_LICENSE("GPL"); //LICENSE 采用 GPL 協(xié)議
2、platform 平臺(tái)驅(qū)動(dòng)結(jié)構(gòu)體
主要是通過(guò) match 函數(shù)和對(duì)應(yīng)的設(shè)備樹(shù)里面節(jié)點(diǎn)匹配,只要 compatible 屬性匹配成功即可,匹配成功就執(zhí)行 probe 函數(shù)。
/*匹配列表*/
static const struct of_device_id gpio_learning_of_match[] = {
{ .compatible = "gpioled_learning" },
{ /*sentinel*/}
};
/*
* platform 平臺(tái)驅(qū)動(dòng)結(jié)構(gòu)體
*/
static struct platform_driver gpio_learning_driver ={
.driver = {
.name = "gpio_learning_device",
.of_match_table = gpio_learning_of_match,
},
.probe = gpio_learning_probe,
.remove = gpio_learning_remove,
};
3、probe 函數(shù)
主要是注冊(cè)字符設(shè)備,通過(guò)獲取設(shè)備樹(shù)的節(jié)點(diǎn),獲取 gpio 屬性,從而獲得 gpio編號(hào),之后請(qǐng)求使用該 gpio,設(shè)置 gpio 模式。
/*
* platform 驅(qū)動(dòng)的 probe 函數(shù)
* 驅(qū)動(dòng)與設(shè)備匹配成功以后此函數(shù)就會(huì)執(zhí)行
*/
static int gpio_learning_probe(struct platform_device *dev)
{
printk("led driver and device was matched!\r\n");
/* 1、設(shè)置設(shè)備號(hào) */
if (gpiodev.major) { //如果定義了主設(shè)備號(hào)
gpiodev.devid = MKDEV(gpiodev.major, 0);//次設(shè)備號(hào)號(hào)默認(rèn) 0,構(gòu)建設(shè)備號(hào)
register_chrdev_region(gpiodev.devid, GPIODEV_CNT,GPIODEV_NAME);//注冊(cè)設(shè)備號(hào)
} else {
alloc_chrdev_region(&gpiodev.devid, 0, GPIODEV_CNT,GPIODEV_NAME);//動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)
gpiodev.major = MAJOR(gpiodev.devid);//獲取主設(shè)備號(hào)
}
/* 2、注冊(cè)設(shè)備 */
cdev_init(&gpiodev.cdev,&gpio_learning_fops);
cdev_add(&gpiodev.cdev, gpiodev.devid, GPIODEV_CNT);
/* 3、創(chuàng)建類(lèi) */
gpiodev.class = class_create(THIS_MODULE, GPIODEV_NAME);
if (IS_ERR(gpiodev.class)) {
return PTR_ERR(gpiodev.class);
}
/* 4、創(chuàng)建設(shè)備 */
gpiodev.device = device_create(gpiodev.class, NULL, gpiodev.devid,NULL, GPIODEV_NAME);
if (IS_ERR(gpiodev.device)) {
return PTR_ERR(gpiodev.device);
}
/* 5、初始化 IO */
gpiodev.node = of_find_node_by_path("/gpio_learning");
if (gpiodev.node == NULL){
printk("gpio_learning node nost find!\r\n");
return -EINVAL;
}
gpiodev.led0 = of_get_named_gpio(gpiodev.node, "gpio", 0);/*獲取要使用的 GPIO 編號(hào) */
if (gpiodev.led0 < 0) {
printk("can't get gpio\r\n");
return -EINVAL;
}
printk("led0 = %d\r\n",gpiodev.led0);
int ret = gpio_request(gpiodev.led0, "led0");/*申請(qǐng)gpio管腳 */
if(ret == 0)
{
printk("gpio_request success\r\n");
}
else
{
printk("gpio_request fail\r\n");
return -1;
}
ret = gpio_direction_output(gpiodev.led0, 1); /*設(shè)置為輸出,默認(rèn)高電平 */
if(ret == 0)
{
printk("gpio_direction_output success\r\n");
}
else
{
printk("gpio_direction_output fail\r\n");
return -1;
}
return 0;
}
4、設(shè)備函數(shù)操作結(jié)構(gòu)體
主要是一個(gè) open 和 write 的函數(shù)。
/*
* 設(shè)備操作函數(shù)結(jié)構(gòu)體
*/
static struct file_operations gpio_learning_fops = {
.owner = THIS_MODULE,
.open = gpio_learning_open,
.write = gpio_learning_write,
};
5、設(shè)備操作 open 和 write函數(shù)
主要 open 函數(shù)是將 private_data 指向設(shè)備結(jié)構(gòu)體。
主要 write 函數(shù)是接受用戶(hù)層傳來(lái)的數(shù)據(jù),之后根據(jù)數(shù)據(jù)設(shè)置 gpio 操作。
#define GPIODEV_CNT 1 /* 設(shè)備號(hào)長(zhǎng)度 */
#define GPIODEV_NAME "gpio_learning" /* 設(shè)備名字 */
#define GPIOOFF 0
#define GPIOON 1
//設(shè)備結(jié)構(gòu)體
struct gpiodev_dev{
dev_t devid; /* 設(shè)備號(hào) */
struct cdev cdev; /* cdev */
struct class *class; /* 類(lèi) */
struct device *device; /* 設(shè)備 */
int major; /* 主設(shè)備號(hào) */
struct device_node *node; /* 設(shè)備節(jié)點(diǎn) */
int led0; /* LED 燈 GPIO 標(biāo)號(hào) */
};
struct gpiodev_dev gpiodev;
/*
* @description : LED 打開(kāi)/關(guān)閉
* @param - sta : LEDON(0) 打開(kāi) LED,LEDOFF(1) 關(guān)閉 LED
* @return : 無(wú)
*/
void led0_switch(u8 sta)
{
if (sta == GPIOON )
{
gpio_set_value(gpiodev.led0, 1);
printk("gpio_set_value = 1!\r\n");
}
else if (sta == GPIOOFF)
{
gpio_set_value(gpiodev.led0, 0);
printk("gpio_set_value = 0!\r\n");
}
return 0;
}
/*
* @description : 打開(kāi)設(shè)備
* @param – inode : 傳遞給驅(qū)動(dòng)的 inode
* @param - filp : 設(shè)備文件,file 結(jié)構(gòu)體有個(gè)叫做 private_data 的成員變量
* 一般在 open 的時(shí)候?qū)?private_data 指向設(shè)備結(jié)構(gòu)體。
* @return : 0 成功;其他 失敗
*/
static int gpio_learning_open(struct inode *inode,struct file *filp)
{
filp->private_data = &gpiodev; /* 設(shè)置私有數(shù)據(jù) */
return 0;
}
static ssize_t gpio_learning_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)
{
int retvalue;
unsigned char databuf[2];
unsigned char ledstat;
retvalue = copy_from_user(databuf, buf, cnt);
if(retvalue < 0) {
printk("kernel write failed!\r\n");
return -EFAULT;
}
printk("retvalue = %d\r\n",retvalue);
ledstat = databuf[0];
if (ledstat == GPIOON) {
printk("ledstat = 1\r\n");
led0_switch(GPIOON);
} else if (ledstat == GPIOOFF) {
printk("ledstat = 0\r\n");
led0_switch(GPIOOFF);
}
return 0;
}
五、Kernel 配置
1、Makefile 文件
obj-$(CONFIG_GPIO_LEARNING) += gpio_learning.o
2、Kconfig 文件
config GPIO_LEARNING
tristate "GPIO learning block support"
default m
help
This is enable gpio learning test
3、引用
在自己編寫(xiě)文件的上一級(jí)目錄 Makefile 和 Kconfig 添加對(duì)應(yīng)引用,并在對(duì)應(yīng) deconfig 配置。
Makefile 文件引用
obj-$(CONFIG_GPIO_LEARNING) += gpio_learning/
Kconfig 文件引用
source "drivers/gpio_learning/Kconfig"
deconfig 文件配置
路徑:
/buildsystem/yocto/source/linux/arch/arm64/configs/x9_ref_linux_defconfig
等于 m 表示編譯成 ko 文件,等于 y 表示編譯進(jìn)內(nèi)核。
CONFIG_GPIO_LEARNING=m
六、APP 測(cè)試
主要是傳入三個(gè)參數(shù),一個(gè)是運(yùn)行的 app,一個(gè)是對(duì)應(yīng)的 /dev/xxx,一個(gè)是對(duì) gpio 的操作(1/0),通過(guò) /dev/xxx 打開(kāi)對(duì)應(yīng)驅(qū)動(dòng)文件,通過(guò) write 發(fā)送對(duì)應(yīng)的操作。
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
int main(int argc, char *argv[])
{
int fd, retvalue;
char *filename;
unsigned char databuf[2];
if(argc != 3){ //傳入三個(gè)參數(shù):運(yùn)行的app /dev/xxx 操作
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
/* 打開(kāi) /dev/xxx 驅(qū)動(dòng)文件 */
fd = open(filename, O_RDWR);
if(fd < 0){
printf("file %s open failed!\r\n", argv[1]);
return -1;
}
databuf[0] = atoi(argv[2]); /* 要執(zhí)行的操作:打開(kāi)或關(guān)閉 */
retvalue = write(fd, databuf, sizeof(databuf));
if(retvalue < 0){
printf("LED Control Failed!\r\n");
close(fd);
return -1;
}
retvalue = close(fd); /* 關(guān)閉文件 */
if(retvalue < 0){
printf("file %s close failed!\r\n", argv[1]);
return -1;
}
return 0;
}
以上完成了 SemiDrive X9H GPIO 功能的實(shí)現(xiàn)。
接下來(lái)將會(huì)更新更多關(guān)于 SemiDrive X9H 的開(kāi)發(fā)博文,如有相關(guān)技術(shù)問(wèn)題,可在評(píng)論區(qū)留言。
七、參考文檔
《 SemiDrive_9_Series_GPIO使用手冊(cè)_Rev01.00.pdf 》
《 X9H處理器數(shù)據(jù)手冊(cè)_Rev04.00.pdf 》
《 SD003_X9H_REF_A03_SCH.pdf 》
《 X9_Processor_TRM_Rev00.07.pdf 》
-
控制器
+關(guān)注
關(guān)注
112文章
16133瀏覽量
177137 -
驅(qū)動(dòng)
+關(guān)注
關(guān)注
12文章
1821瀏覽量
85121 -
GPIO
+關(guān)注
關(guān)注
16文章
1189瀏覽量
51847
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論