一、概述
SemiDrive X9H 擁有不同的 domain 域,例如 AP,Safety,Secure 等等。對于 GPIO 資源,不同 domain 之間 gpio 控制器是不同的,本次主要是使用的 AP 使用的是 gpio4 控制器。除了GPIO 控制器在不同 domain 之間不同以外,pin 也是有各自不同的 domain 的,但是當它作為 gpio 使用時,可以通過設(shè)置掛靠到對應(yīng)域下的 gpio 控制器上來在對應(yīng) domain 下使用。具體 pin 的 gpio 控制器的設(shè)置是通過 PC 工具 SDConfigTool 來進行。
本文主要是講述將 pin 作為 GPIO 使用,之后編寫字符設(shè)備驅(qū)動,測試。
二、適用環(huán)境
硬件:SemiDrive SD003_X9H REF_A03 DEMO Board
軟件:X9 PTG3.9
三、設(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、配置一個新節(jié)點
路徑:
/buildsystem/yocto/source/linux/arch/arm64/boot/dts/semidrive/x9_high_ref_native_serdes_nobt.dts
在上面 dts 文件里面的根節(jié)點 / 下新建一個節(jié)點,添加屬性,獲取 gpio 編號。
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ū)動編寫
1、模塊出/入口函數(shù)
其中 module_init 是驅(qū)動入口函數(shù),主要進行 platform 平臺驅(qū)動注冊,module_exit 是驅(qū)動出口函數(shù),主要是進行 platform 平臺驅(qū)動注銷;
其中 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 平臺驅(qū)動結(jié)構(gòu)體
主要是通過 match 函數(shù)和對應(yīng)的設(shè)備樹里面節(jié)點匹配,只要 compatible 屬性匹配成功即可,匹配成功就執(zhí)行 probe 函數(shù)。
/*匹配列表*/
static const struct of_device_id gpio_learning_of_match[] = {
{ .compatible = "gpioled_learning" },
{ /*sentinel*/}
};
/*
* platform 平臺驅(qū)動結(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ù)
主要是注冊字符設(shè)備,通過獲取設(shè)備樹的節(jié)點,獲取 gpio 屬性,從而獲得 gpio編號,之后請求使用該 gpio,設(shè)置 gpio 模式。
/*
* platform 驅(qū)動的 probe 函數(shù)
* 驅(qū)動與設(shè)備匹配成功以后此函數(shù)就會執(zhí)行
*/
static int gpio_learning_probe(struct platform_device *dev)
{
printk("led driver and device was matched!\r\n");
/* 1、設(shè)置設(shè)備號 */
if (gpiodev.major) { //如果定義了主設(shè)備號
gpiodev.devid = MKDEV(gpiodev.major, 0);//次設(shè)備號號默認 0,構(gòu)建設(shè)備號
register_chrdev_region(gpiodev.devid, GPIODEV_CNT,GPIODEV_NAME);//注冊設(shè)備號
} else {
alloc_chrdev_region(&gpiodev.devid, 0, GPIODEV_CNT,GPIODEV_NAME);//動態(tài)申請設(shè)備號
gpiodev.major = MAJOR(gpiodev.devid);//獲取主設(shè)備號
}
/* 2、注冊設(shè)備 */
cdev_init(&gpiodev.cdev,&gpio_learning_fops);
cdev_add(&gpiodev.cdev, gpiodev.devid, GPIODEV_CNT);
/* 3、創(chuàng)建類 */
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 編號 */
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");/*申請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è)置為輸出,默認高電平 */
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)體
主要是一個 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ù)是接受用戶層傳來的數(shù)據(jù),之后根據(jù)數(shù)據(jù)設(shè)置 gpio 操作。
#define GPIODEV_CNT 1 /* 設(shè)備號長度 */
#define GPIODEV_NAME "gpio_learning" /* 設(shè)備名字 */
#define GPIOOFF 0
#define GPIOON 1
//設(shè)備結(jié)構(gòu)體
struct gpiodev_dev{
dev_t devid; /* 設(shè)備號 */
struct cdev cdev; /* cdev */
struct class *class; /* 類 */
struct device *device; /* 設(shè)備 */
int major; /* 主設(shè)備號 */
struct device_node *node; /* 設(shè)備節(jié)點 */
int led0; /* LED 燈 GPIO 標號 */
};
struct gpiodev_dev gpiodev;
/*
* @description : LED 打開/關(guān)閉
* @param - sta : LEDON(0) 打開 LED,LEDOFF(1) 關(guān)閉 LED
* @return : 無
*/
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 : 打開設(shè)備
* @param – inode : 傳遞給驅(qū)動的 inode
* @param - filp : 設(shè)備文件,file 結(jié)構(gòu)體有個叫做 private_data 的成員變量
* 一般在 open 的時候?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、引用
在自己編寫文件的上一級目錄 Makefile 和 Kconfig 添加對應(yīng)引用,并在對應(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 表示編譯進內(nèi)核。
CONFIG_GPIO_LEARNING=m
六、APP 測試
主要是傳入三個參數(shù),一個是運行的 app,一個是對應(yīng)的 /dev/xxx,一個是對 gpio 的操作(1/0),通過 /dev/xxx 打開對應(yīng)驅(qū)動文件,通過 write 發(fā)送對應(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){ //傳入三個參數(shù):運行的app /dev/xxx 操作
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
/* 打開 /dev/xxx 驅(qū)動文件 */
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í)行的操作:打開或關(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 功能的實現(xiàn)。
接下來將會更新更多關(guān)于 SemiDrive X9H 的開發(fā)博文,如有相關(guān)技術(shù)問題,可在評論區(qū)留言。
七、參考文檔
《 SemiDrive_9_Series_GPIO使用手冊_Rev01.00.pdf 》
《 X9H處理器數(shù)據(jù)手冊_Rev04.00.pdf 》
《 SD003_X9H_REF_A03_SCH.pdf 》
《 X9_Processor_TRM_Rev00.07.pdf 》
-
控制器
+關(guān)注
關(guān)注
112文章
16473瀏覽量
179663 -
驅(qū)動
+關(guān)注
關(guān)注
12文章
1853瀏覽量
85697 -
GPIO
+關(guān)注
關(guān)注
16文章
1217瀏覽量
52447
發(fā)布評論請先 登錄
相關(guān)推薦
MDMF304L1H9M-MINAS A6BU 系列 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MDMF304L1<b class='flag-5'>H9</b>M-MINAS A6BU 系列 <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304L1H9M-MINAS A6BL (EtherCAT) 系列 技術(shù)資料 -EtherCAT 通信規(guī)格篇- 松下
![MDMF304L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技術(shù)</b>資料 -EtherCAT 通信規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304L1H9M-MINAS A6B 系列 (EtherCAT) 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MDMF304L1<b class='flag-5'>H9</b>M-MINAS A6B 系列 (EtherCAT) <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304L1H9M-MINAS A6NL系列 (RTEX) 技術(shù)資料 -RTEX通信規(guī)格篇- 松下
![MDMF304L1<b class='flag-5'>H9</b>M-MINAS A6NL系列 (RTEX) <b class='flag-5'>技術(shù)</b>資料 -RTEX通信規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304L1H9M-MINAS A6N系列 (RTEX) 技術(shù)資料 -RTEX通信規(guī)格篇- 松下
![MDMF304L1<b class='flag-5'>H9</b>M-MINAS A6N系列 (RTEX) <b class='flag-5'>技術(shù)</b>資料 -RTEX通信規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304A1H9M-MINAS A6BN 系列 技術(shù)資料 -EtherCAT 通信規(guī)格篇- 松下
![MDMF304A1<b class='flag-5'>H9</b>M-MINAS A6BN 系列 <b class='flag-5'>技術(shù)</b>資料 -EtherCAT 通信規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304A1H9M-MINAS A6BL (EtherCAT) 系列 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MDMF304A1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MDMF304A1H9M-MINAS A6S 系列 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MDMF304A1<b class='flag-5'>H9</b>M-MINAS A6S 系列 <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
SOC GPIO操作
使用LP875230C-Q1 和 LP87565V-Q1 的 Semidrive X9H 電源設(shè)計
![使用LP875230C-Q1 和 LP87565V-Q1 的 <b class='flag-5'>Semidrive</b> <b class='flag-5'>X9H</b> 電源設(shè)計](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
Semidrive X9P/X9U 電源設(shè)計
![<b class='flag-5'>Semidrive</b> <b class='flag-5'>X9</b>P/<b class='flag-5'>X9</b>U 電源設(shè)計](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
SemiDrive X9 AI 開發(fā)環(huán)境搭建
![<b class='flag-5'>SemiDrive</b> <b class='flag-5'>X9</b> AI 開發(fā)環(huán)境搭建](https://file1.elecfans.com/web2/M00/01/83/wKgaomawbryAFxYLAAA7ZOQUd5o541.png)
MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技術(shù)資料 -EtherCAT 通信規(guī)格篇- 松下
![MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技術(shù)</b>資料 -EtherCAT 通信規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
MGMF444L1H9M-MINAS A6NL系列 (RTEX) 技術(shù)資料 -基本功能規(guī)格篇- 松下
![MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6NL系列 (RTEX) <b class='flag-5'>技術(shù)</b>資料 -基本功能規(guī)格<b class='flag-5'>篇</b>- 松下](https://file1.elecfans.com/web2/M00/A9/42/wKgaomUwmYKAXjWEAAAsCdY_muE289.png)
評論