高通MSM8909下Android 7.1.2的GPIO驱动配置记录

需要修改的文件:

1. 修改设备树文件 kernel/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi

在&soc下添加

test_gpio {
            compatible = "test_gpio";
            test_gpio,gpio0 = <&msm_gpio 0 0>;
            qcom,num-grp-pins = <1>;
            qcom,pin-func = <0>;
            pinctrl-names = "test_gpio";
            pinctrl-0 = <&sim8905_act>;
            label = "test_gpio";
            sim8905_act: active {
                drive-strength = <2>;
                bias-disable = <0>;
            };
        };

2. 在 kernel/drivers/misc 下添加 test_gpio.c文件

#include <linux/types.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <asm/setup.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>

int test_gpio0 = -1;

static struct class * test_gpios_class = NULL;
static struct device * test_gpio0_dev = NULL;

#define CTL_POWER_ON "1"
#define CTL_POWER_OFF "0"

//此函数会在使用 cat命令时候自动调用
static ssize_t test_gpio0_show(struct device *dev,struct device_attribute *attr, char *buf)
{
	int gpio_state = gpio_get_value(test_gpio0);
	sprintf(buf, "%d\n", gpio_state);
	return strlen(buf);
}

//此函数会在使用 echo 命令时候自动调用
static ssize_t test_gpio0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	if(!strncmp(buf, CTL_POWER_ON, strlen(CTL_POWER_ON))) {
		gpio_set_value(test_gpio0, 1);
	} else if(!strncmp(buf, CTL_POWER_OFF, strlen(CTL_POWER_OFF))) {
		gpio_set_value(test_gpio0, 0);
	}
	return count;
}

static struct device_attribute test_gpio0_dev_attr = {
	.attr = {
		.name = "state",
		.mode = S_IRWXU|S_IRWXG|S_IRWXO,
	},
	.show = test_gpio0_show,
	.store = test_gpio0_store,
};


static int test_gpio_probe(struct platform_device *pdev)
{
	int ret = 0;
	printk("zc enter test_gpio_probe \n");
	//寻找设备树dts下的 "test_gpio,gpio0" 名称对应的GPIO口
	test_gpio0 = of_get_named_gpio(pdev->dev.of_node, "test_gpio,gpio0", 0);
	if (test_gpio0 < 0)
		printk("test_gpio0 is not available \n");
	//对应修改的dts的 label
	ret = gpio_request(test_gpio0, "test_gpio");
	if(0 != ret) {
		printk("gpio request %d failed.", test_gpio0);
		goto fail1;
	}
	
	//设置gpio为输出
	gpio_direction_output(test_gpio0, 0);
	
	//创建test_gpios节点
	test_gpios_class = class_create(THIS_MODULE, "test_gpios");
	if(IS_ERR(test_gpios_class))
	{
		ret = PTR_ERR(test_gpios_class);
		printk("Failed to create class.\n");
		return ret;
	}
	
	//创建test_gpio0 的驱动设备
	test_gpio0_dev=device_create(test_gpios_class, NULL, 0, NULL, "test_gpio0");
	if (IS_ERR(test_gpio0_dev))
	{
		ret = PTR_ERR(test_gpios_class);
		printk("Failed to create device(test_gpio0_dev)!\n");
		return ret;
	}
	
	//根据 test_gpio0_dev_attr 配置,生成相应的文件
	ret = device_create_file(test_gpio0_dev, & test_gpio0_dev_attr);
	if(ret)
	{
		pr_err("%s: test_gpio0 creat sysfs failed\n",__func__);
		return ret;
	}
	printk("enter test_gpio_probe, ok \n");
fail1:
	return ret;
}


static int test_gpio_remove(struct platform_device *pdev)
{
	device_destroy(test_gpios_class, 0);
	class_destroy(test_gpios_class);
	device_remove_file(test_gpio0_dev, & test_gpio0_dev_attr);
	return 0;
}
static int test_gpio_suspend(struct platform_device *pdev,pm_message_t state)
{
	return 0;
}

static int test_gpio_resume(struct platform_device *pdev)
{
	return 0;
}


static struct of_device_id test_gpio_dt_match[] = {
	{ .compatible = "test_gpio",},
	{ },
};


MODULE_DEVICE_TABLE(of, test_gpio_dt_match);

//驱动的方法与函数对应
static struct platform_driver gpio_power_driver = {
	.driver = {
		.name = "test_gpio",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(test_gpio_dt_match),
	},
	.probe = test_gpio_probe,
	.remove = test_gpio_remove,
	.suspend = test_gpio_suspend,
	.resume = test_gpio_resume,
};


static __init int gpio_power_init(void)
{
	return platform_driver_register(&gpio_power_driver);
}
static void __exit gpio_power_exit(void)
{
	platform_driver_unregister(&gpio_power_driver);
}


module_init(gpio_power_init);
module_exit(gpio_power_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("test_gpio Driver");

3.修改 kernel/drivers/misc 下 Makefile 和 Kconfig 文件

在Kconfig文件最后endmenu前面添加

config TEST_GPIO
	tristate "test_gpio"


在Makefile文件最后添加

obj-$(CONFIG_TEST_GPIO) 	+= test_gpio.o

4. 修改 kernel/arch/arm/configs 下的 msm8909-1gb_defconfig 文件

msm8909-1gb_defconfig这个文件是根据芯片型号和编译的版本来的,我的是在/device/qcom/msm8909/AndroidBoard.mk中定义。如下

ifeq ($(KERNEL_DEFCONFIG),)
    ifeq ($(TARGET_BUILD_VARIANT),user)
      KERNEL_DEFCONFIG := msm8909-1gb-perf_defconfig
    else
      KERNEL_DEFCONFIG := msm8909-1gb_defconfig
    endif
endif

user版本是选择msm8909-1gb-perf_defconfig,其余版本是msm8909-1gb_defconfig。

 修改msm8909-1gb_defconfig如下

在文件最后添加

CONFIG_TEST_GPIO=y

添加这个,才能把写的驱动编译进系统。

5. 执行编译、烧录

6. 测试驱动

系统启动后,用adb命令进入系统

可以看到在 /sys/devices/virtual/ 目录下生成了 test_gpios 文件夹,里面有个test_gpio0 文件夹。

下面我们就可以控制state文件夹,去给 gpio0 高低电平。

输出低电平使用
echo 0 > state           

输出高电平使用
echo 1 > state  


查看当前输出的状态(1是高电平)
cat state

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值