【BeagleBone Black Rev. C試用體驗】+裝置樹驅動
阿新 • • 發佈:2019-01-04
感覺裝置樹寫驅動是未來的潮流。。。下面我們來講講裝置樹驅動開發。。
裝置樹語法我們這就不說了,去下面連結自己參考吧:
http://www.cnblogs.com/xiaojiang1025/p/6131381.html
一、修改裝置樹:
裝置樹檔案在arch/arm/boot/dts目錄下am335x-boneblack.dts檔案
先貼程式碼:
修改的地方我都有標註。。。
compatible是用來匹配的。。。
pinctrl-names用來匹配pinctrl設定資訊。。。
source_gpios用來獲取io資訊。。。
我們用的是gpio1_12,設定mode7,且為輸出模式。。。
二、匯流排驅動
platform匯流排驅動這裡就不介紹了。我也講不明白。感興趣的可以去 瞭解,以前學習的時候都是自己寫個device再寫個driver然後匹配。
現在有裝置樹了devcie省去了,減少了很大的程式碼冗餘。。。。
寫驅動編譯有錯誤不要緊,一條條出解決,查問題。這個驅動剛寫好時,一編譯刷刷的一排error下來,看到額眼睛都花了,但是一個個看過去還是能解決的。無非就是標頭檔案沒包含
語法有問題。。呼叫的變數型別有問題。。
下面貼個簡單的框架:
接下來就是填充程式碼了,先填充probe函式,再填充remove函式,接下來註冊init和exit函式。。
最後把file_operations結構體填充完。。
完整程式碼:
printk函式的列印資訊是通過串列埠打印出來的。
還要改下列印級別:
用原始碼的除錯吧。。
測試程式碼:
裝置樹語法我們這就不說了,去下面連結自己參考吧:
http://www.cnblogs.com/xiaojiang1025/p/6131381.html
一、修改裝置樹:
裝置樹檔案在arch/arm/boot/dts目錄下am335x-boneblack.dts檔案
先貼程式碼:
/* add by Sourcelink */
/ {
model = "TI AM335x BeagleBoneBlack";
compatible = "ti,am335x-bone", "ti,am33xx";
cpus {
[email protected]{
cpu0-supply = <&dcdc2_reg>;
};
};
/* add by Sourcelink */
source_gpio {
compatible = "sourcelink_gpio";
pinctrl-names = "sourcelink_gpio";
pinctrl-0 = <&sourcelink_pin>;
source_gpios = <&gpio2 12 0>;
};
};
&am33xx_pinmux {
rstctl_pins: pinmux_rstctl_pins {
pinctrl-single,pins = <
/* eMMC_RSTn */
0x50 0x17 /* gpmc_a4.gpio1_20, OUTPUT | MODE7 | PULLUP */
>;
};
/* add by Sourcelink */
sourcelink_pin: pinmux_source_pins {
pinctrl-single,pins = <
0x30 0x7 /* gpmc_ad12.gpio1_12, OUTPUT | MODE7 */
>;
};
};
compatible是用來匹配的。。。
pinctrl-names用來匹配pinctrl設定資訊。。。
source_gpios用來獲取io資訊。。。
我們用的是gpio1_12,設定mode7,且為輸出模式。。。
切記gpio的地址標號是從1開始的。。。gpio1對應的是GPIO0_x的地址,我就是這出了問題一直沒有調出來。。。
引腳的複用都是從800h地址開始:
對應管腳從gpio0_0開始四個位元組開始增加,所以gpio1_12偏移對應:4*12 = 48 = 0x30
二、匯流排驅動
platform匯流排驅動這裡就不介紹了。我也講不明白。感興趣的可以去 瞭解,以前學習的時候都是自己寫個device再寫個driver然後匹配。
現在有裝置樹了devcie省去了,減少了很大的程式碼冗餘。。。。
寫驅動編譯有錯誤不要緊,一條條出解決,查問題。這個驅動剛寫好時,一編譯刷刷的一排error下來,看到額眼睛都花了,但是一個個看過去還是能解決的。無非就是標頭檔案沒包含
語法有問題。。呼叫的變數型別有問題。。
下面貼個簡單的框架:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>
static int gpio_drv_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
int ret;
return ret;
}
struct file_operations gpio_drv_fops = {
.owner = THIS_MODULE,
.open = gpio_drv_open,
.write = gpio_drv_write,
};
static const struct of_device_id of_gpio_fortree_match[] = {
{ .compatible = "sourcelink_gpio", },
{},
};
static int gpio_fortree_probe(struct platform_device *pdev)
{
return 0;
}
static int gpio_fortree_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver gpio_fortree_driver = {
.probe = gpio_fortree_probe,
.remove = gpio_fortree_remove,
.driver = {
.name = "sourcelink_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_fortree_match),
},
};
static int gpio_fortree_init(void)
{
int ret;
return ret;
}
static void gpio_fortree_exit(void)
{
}
module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);
MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");
接下來就是填充程式碼了,先填充probe函式,再填充remove函式,接下來註冊init和exit函式。。
最後把file_operations結構體填充完。。
完整程式碼:
#include <linux/module.h>驅動我寫了很多列印函式。。很方便除錯。。
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>
static int source_gpio;
static struct cdev gpio_drv_cdev; //核心中用cdev描述一個字元裝置
static struct class *gpio_drv_class;
static int minor;
static int gpio_drv_open(struct inode *inode, struct file *file)
{
minor = iminor(inode); /* 獲取檔案的次裝置號 */
printk("gpio_drv_open\n");
printk("minor:%d \n", minor);
return 0;
}
static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
int ret = 0;
int val = 0;
// 返回錯誤個數,正確返回0
if (copy_from_user((int *)&val, user_buf, count)) {
ret = -EFAULT;
} else {
*ppos += count;
ret = count;
}
printk("val:%d \n", val);
if (val == 1) {
switch(minor){
case 0:
gpio_set_value(source_gpio, 1);
printk("gpio_on\n");
break;
}
} else {
switch(minor){
case 0:
gpio_set_value(source_gpio, 0);
printk("gpio_off\n");
break;
}
}
return ret;
}
struct file_operations gpio_drv_fops = {
.owner = THIS_MODULE,
.open = gpio_drv_open,
.write = gpio_drv_write,
};
static const struct of_device_id of_gpio_fortree_match[] = {
{ .compatible = "sourcelink_gpio", },
{},
};
static int major;
static int gpio_fortree_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
dev_t devid;
struct pinctrl *pctrl;
struct pinctrl_state *pstate;
printk("enter %s\n",__func__);
pctrl = devm_pinctrl_get(dev);
if(pctrl == NULL)
{
printk("devm_pinctrl_get error\n");
}
pstate = pinctrl_lookup_state(pctrl, "sourcelink_gpio");
if(pstate == NULL)
{
printk("pinctrl_lookup_state error\n");
}
pinctrl_select_state(pctrl, pstate); /* gpmc_a12.gpio1_12, OUTPUT | MODE7 */
source_gpio = of_get_named_gpio(dev->of_node, "source_gpios", 0);
if (source_gpio <= 0) {
printk("of_get_named_gpio error!!!\n");
return -EINVAL;
} else {
printk("sourcelink_gpio is %d\n", source_gpio);
if (devm_gpio_request_one(dev, source_gpio, GPIOF_OUT_INIT_LOW, "source_gpio44") != 0) {
printk("devm_gpio_request_one error!!!\n");
}
}
if(alloc_chrdev_region(&devid, 0, 1, "sourcelink") < 0)/* (major,0~1) 對應 hello_fops, (major, 2~255)都不對應hello_fops */
{
printk("%s ERROR\n",__func__);
goto error;
}
major = MAJOR(devid);
cdev_init(&gpio_drv_cdev, &gpio_drv_fops); //繫結檔案操作函式
cdev_add(&gpio_drv_cdev, devid, 1); //註冊到核心
gpio_drv_class = class_create(THIS_MODULE, "sourcelink"); //建立sourcelink類,向類中新增裝置,mdev會幫我們建立裝置節點
device_create(gpio_drv_class, NULL, MKDEV(major, 0), NULL, "source_gpio44");
return 0;
error:
unregister_chrdev_region(MKDEV(major, 0), 1);
return -EINVAL;
}
static int gpio_fortree_remove(struct platform_device *pdev)
{
printk("enter %s\n",__func__);
device_destroy(gpio_drv_class, MKDEV(major, 0));
class_destroy(gpio_drv_class);
cdev_del(&gpio_drv_cdev);
unregister_chrdev_region(MKDEV(major, 0), 1);
return 0;
}
static struct platform_driver gpio_fortree_driver = {
.probe = gpio_fortree_probe,
.remove = gpio_fortree_remove,
.driver = {
.name = "sourcelink_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_fortree_match),
},
};
static int gpio_fortree_init(void)
{
int ret;
printk("enter %s\n",__func__);
ret = platform_driver_register(&gpio_fortree_driver);
if (ret)
printk(KERN_ERR "gpio_fortree_probe: probe failed: %d\n", ret);
return ret;
}
static void gpio_fortree_exit(void)
{
printk("enter %s\n",__func__);
platform_driver_unregister(&gpio_fortree_driver);
}
module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);
MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");
printk函式的列印資訊是通過串列埠打印出來的。
還要改下列印級別:
echo 5 > /proc/sys/kernel/printk
用原始碼的除錯吧。。
測試程式碼:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int fd;
int led_state = 0;
int i;
fd = open("/dev/source_gpio44", O_RDWR);
if (fd < 0)
printf("can't open!\n");
#if 0
if (argc != 2) {
printf("Usage: \n");
printf("%s <on|off>\n", argv[0]);
return -1;
}
if (strcmp(argv[1], "on") == 0)
led_state = 1;
else
led_state = 0;
if (write (fd, &led_state, 1)) {
printf("write successful!\n");
}
#else
for (i = 0; i < 10; i++) {
switch (led_state) {
case 0:
write (fd, &led_state, 1);
printf("led off!\n");
led_state = 1;
break;
case 1:
write (fd, &led_state, 1);
printf("led on!\n");
led_state = 0;
break;
}
sleep(1);
}
#endif
close(fd);
return 0;
}