linux 按键轮询驱动(gpio_keys_polled.c)

本文详细介绍如何在不修改设备树的前提下,定制Linux系统中的GPIO按键驱动gpio_keys_polled.c。通过直接在驱动文件中对按键结构体进行赋值,实现对IO按钮的定义,并修改驱动的probe函数和平台数据获取函数,最后注册platform device完成驱动定制。

系统自带了gpio_keys_polled.c驱动文件,硬件资源是通过设备树获取,在不修改设备树的情况下,可以直接在驱动文件中对相关的结构体进行赋值。

1、定义当前使用的IO按钮数组

static struct gpio_keys_button buttons[]={
    {
        .gpio = 41,//IO引脚号,根据实际情况修改
        .code = KEY_1,
        .desc = "KEY1",
        .active_low = 1,
    },
    {
        .gpio = 120,
        .code = KEY_2,
        .desc = "KEY2",
        .active_low = 1,
    },
    {
        .gpio = 121,
        .code = KEY_3,
        .desc = "KEY3",
        .active_low = 1,
    },
    {
        .gpio = 5,
        .code = KEY_4,
        .desc = "KEY4",
        .active_low = 1,
    },
    {
        .gpio = 226,
        .code = KEY_5,
        .desc = "KEY5",
        .active_low = 1,
    },
};

2、修改gpio_keys_polled_probe()函数

具体硬件资源与驱动匹配的函数为 gpio_keys_polled_get_devtree_pdata(),需要注释掉“if(!pdata)这行,否则会出现pdata->poll_interval未赋值的情况。

3、修改gpio_keys_polled_get_devtree_pdata()函数

static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
	struct device_node *node, *pp;
	struct gpio_keys_platform_data *pdata;
	struct gpio_keys_button *button;
	int error;
	int nbuttons;
	int i;

	//不使用设备树,与之相关的代码均可注释掉
	//node = dev->of_node;
	//if (!node)
	//	return NULL;
    
    //按键数
	nbuttons = ARRAY_SIZE(buttons);//nbuttons = of_get_child_count(node);
	//if (nbuttons == 0)
	//	return NULL;

	pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
			GFP_KERNEL);
	if (!pdata) {
		error = -ENOMEM;
		goto err_out;
	}

	pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
	pdata->nbuttons = nbuttons;

    //扫描间隔手动赋值,注释掉从设备树获取代码
	//pdata->rep = !!of_get_property(node, "autorepeat", NULL);
	//of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
	pdata->poll_interval = 50;//50ms

	i = 0;
	#if 0 //注释掉从设备树获取相关按键代码
	for_each_child_of_node(node, pp) {
		int gpio;
		enum of_gpio_flags flags;

		if (!of_find_property(pp, "gpios", NULL)) {
			pdata->nbuttons--;
			dev_warn(dev, "Found button without gpios\n");
			continue;
		}

		gpio = of_get_gpio_flags(pp, 0, &flags);
		if (gpio < 0) {
			error = gpio;
			if (error != -EPROBE_DEFER)
				dev_err(dev,
					"Failed to get gpio flags, error: %d\n",
					error);
			goto err_free_pdata;
		}

		button = &pdata->buttons[i++];

		button->gpio = gpio;
		button->active_low = flags & OF_GPIO_ACTIVE_LOW;

		if (of_property_read_u32(pp, "linux,code", &button->code)) {
			dev_err(dev, "Button without keycode: 0x%x\n",
				button->gpio);
			error = -EINVAL;
			goto err_free_pdata;
		}

		button->desc = of_get_property(pp, "label", NULL);

		if (of_property_read_u32(pp, "linux,input-type", &button->type))
			button->type = EV_KEY;

		button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);

		if (of_property_read_u32(pp, "debounce-interval",
					 &button->debounce_interval))
			button->debounce_interval = 5;
	}
	#else //使用我们定义的按键填充相关结构体
	for(i=0; i<nbuttons; i++)
	{
		button = &pdata->buttons[i];	
		button->gpio = buttons[i].gpio;
		button->active_low = buttons[i].active_low;
		button->type = EV_KEY;
		button->code = buttons[i].code;	
	}

	#endif

	if (pdata->nbuttons == 0) {
		error = -EINVAL;
		goto err_free_pdata;
	}

	return pdata;

err_free_pdata:
	kfree(pdata);
err_out:
	return ERR_PTR(error);
}

static struct of_device_id gpio_keys_polled_of_match[] = {
	{ .compatible = "gpio-keys-polled", },
	{ },
};

4、添加platform device 注册相关代码

static struct gpio_keys_platform_data button_data={
	.buttons = buttons,
	.nbuttons = ARRAY_SIZE(buttons),
};

static struct platform_device button_device={
	.name = "gpio-keys-polled",//此名字需与platform driver名字一致
	.id = -1,
	.dev = {
		.platform_data = &button_data,
	},
};
static int keys_dev_init(void)
{
	platform_device_register(&button_device);
	return 0;
}

static void keys_dev_exit(void)
{
	platform_device_unregister(&button_device);
}
module_init(keys_dev_init);
module_exit(keys_dev_exit);

到此修改完毕,编译下载运行。

5、终端输入cat /proc/bus/input/devices

6、终端输入 hexdump /dev/input/event1  查看运行情况

void lcd_hw_init(void) { gpio_init_type gpio_init_struct; dma_init_type dma_init_struct; spi_init_type spi_init_struct; gpio_pin_remap_config(SWJTAG_GMUX_010, TRUE); gpio_default_para_init(&gpio_init_struct); gpio_init_struct.gpio_pins = LCD_BLK_PIN; //LCD_BLK gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init(LCD_BLK_PORT, &gpio_init_struct); gpio_init_struct.gpio_pins = LCD_RST_PIN; //LCD_RST gpio_init(LCD_RST_PORT, &gpio_init_struct); gpio_init_struct.gpio_pins = LCD_DC_PIN; //LCD_DC gpio_init(LCD_DC_PORT, &gpio_init_struct); gpio_init_struct.gpio_pins = LCD_CS1_PIN; //LCD_CS1 gpio_init(LCD_CS1_PORT, &gpio_init_struct); gpio_init_struct.gpio_pins = LCD_CS2_PIN; //LCD_CS2 gpio_init(LCD_CS2_PORT, &gpio_init_struct); LCD_BLK_CLR; LCD_RST_SET; LCD_CS1_SET; LCD_CS2_SET; // gpio_init_struct.gpio_pins = LCD_PEN_PIN; //LCD_PEN // gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; // gpio_init_struct.gpio_pull = GPIO_PULL_UP; // gpio_init(LCD_PEN_PORT, &gpio_init_struct); /* configure spi_master pins: sck, mosi and miso */ /* configure miso pin as alternate function push pull */ gpio_default_para_init(&gpio_init_struct); gpio_init_struct.gpio_pins = LCD_SPI_SCK_PIN; //LCD_SPI_SCK gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init(LCD_SPI_SCK_PORT, &gpio_init_struct); gpio_init_struct.gpio_pins = LCD_SPI_MOSI_PIN; //LCD_SPI_MOSI gpio_init(LCD_SPI_MOSI_PORT, &gpio_init_struct); // gpio_init_struct.gpio_pins = LCD_SPI_MOSI_PIN; //LCD_SPI_MOSI // gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; // gpio_init_struct.gpio_pull = GPIO_PULL_DOWN; // gpio_init(LCD_SPI_MISO_PORT, &gpio_init_struct); /* configureand mosi pins as alternate function push pull */ gpio_init_struct.gpio_pins = LCD_SPI_MISO_PIN; //LCD_SPI_MISO gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; gpio_init_struct.gpio_pull = GPIO_PULL_DOWN; gpio_init(LCD_SPI_MISO_PORT, &gpio_init_struct); /* spi_master configuration */ spi_default_para_init(&spi_init_struct); spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX; spi_init_struct.master_slave_mode = SPI_MODE_MASTER; spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_4; spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB; spi_init_struct.frame_bit_num = SPI_FRAME_8BIT; spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH; spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE; spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; spi_init(LCD_SPI_SELECTED, &spi_init_struct); /* enable spi_maser tx request */ spi_i2s_dma_transmitter_enable(LCD_SPI_SELECTED, TRUE); /* enable spi_maser */ spi_enable(LCD_SPI_SELECTED, TRUE); /* lcd_spi_master_tx_dma_channel configuration */ dma_reset(LCD_SPI_MASTER_Tx_DMA_Channel); dma_init_struct.buffer_size = 0xFFFE; dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_base_addr = (uint32_t)lcd_data_buf; dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD; dma_init_struct.memory_inc_enable = TRUE; dma_init_struct.peripheral_base_addr = (uint32_t)LCD_SPI_MASTER_DR_Base; dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD; dma_init_struct.peripheral_inc_enable = FALSE; dma_init_struct.priority = DMA_PRIORITY_HIGH; dma_init_struct.loop_mode_enable = FALSE; dma_init(LCD_SPI_MASTER_Tx_DMA_Channel, &dma_init_struct); }如果不想用dma传输数据,怎么处理这段代码
03-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值