#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <linux/miscdevice.h>
#include <linux/of_device.h>
static char *KEYS_NAME = "KEY";
/* interrupt handler */
static irqreturn_t keys_isq(int irq, void *data)
{
struct device *dev = data;
dev_info(dev, "interrupt received. key: %s\n", KEYS_NAME);
return IRQ_HANDLED;
}
static struct miscdevice mydev_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mydev",
};
static int my_probe(struct platform_device *pdev)
{
int ret_val, irq;
struct gpio_desc *gpio;
struct device *dev = &pdev->dev;
dev_info(dev, "my_probe() is enter.\n");
/* Linux IRQ number를 알아내는 방법 1
* devm_gpiod_get - Resource-managed gpiod_get()
devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags)
@dev: device
@con_id: device tree에서 gpio를 찾을때 사용
ex)
compatible = "vendor,mydevice";
...
gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
--->gpio-names = "my_gpio";
...
};
@flags: gpio 초기 상태를 설정
enum gpiod_flags {
GPIOD_ASIS = 설정을 변경하지 않음
GPIOD_IN = 입력모드
GPIOD_OUT_LOW = low 로 출력모드
GPIOD_OUT_HIGH = high 로 출력모드
GPIOD_OUT_LOW_OPEN_DRAIN = 저전력 오픈드레인 출력모드
GPIOD_OUT_HIGH_OPEN_DRAIN = 고전력 오픈드레인 출력모드
*/
gpio = devm_gpiod_get(dev, NULL, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "failed to get gpio\n");
return PTR_ERR(gpio);
}
/*
gpio 디스크립터를 사용하여 IRQ number를 알아낸다.
*/
irq = gpiod_to_irq(gpio);
if (irq < 0)
return irq;
dev_info(dev, "gpiod_to_irq IRQ number : %d\n", irq);
/* Linux IRQ number를 알아내는 방법 2 */
irq = platform_get_irq(pdev, 0);
if (irq < 0){
dev_err(dev, "failed to get irq number\n");
return -EINVAL;
}
dev_info(dev, "platform_get_irq irq number : %d\n", irq);
/*
인터럽터를 할당
devm_request_irq(struct device *dev, irq number , irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
handler : 인터럽터 발생시 수행할 함수 등록
irqflags 리스트
#define IRQF_TRIGGER_NONE : 설정하지 않음
#define IRQF_TRIGGER_RISING : 상승에지에서 트리거
#define IRQF_TRIGGER_FALLING : 하강에지에서 트리거
#define IRQF_TRIGGER_HIGH : 상승일때 트리거
#define IRQF_TRIGGER_LOW : 하강일때 트리거
#define IRQF_TRIGGER_MASK : 모튼 인터럽트 타입의 비트마스크
#define IRQF_TRIGGER_PROBE : 인터럽트 트리거 타입을 자동으로 감지
*/
ret_val = devm_request_irq(dev, irq, keys_isq,
IRQF_TRIGGER_FALLING,
KEYS_NAME, dev);
if (ret_val) {
dev_err(dev, "Failed to request interrupt \n");
return ret_val;
}
ret_val = misc_register(&mydev_misc);
if (ret_val != 0)
{
dev_err(dev, "failed to register misc\n");
return ret_val;
}
dev_info(dev, "mydev: got minor %i\n",mydev_misc.minor);
dev_info(dev, "my_probe() is exited.\n");
return 0;
}
static int my_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "my_remove() function \n");
misc_deregister(&mydev_misc);
return 0;
}
static const struct of_device_id my_of_ids[] = {
{ .compatible = "arrow,key"},
{},
};
MODULE_DEVICE_TABLE(of, my_of_ids);
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "intkey_driver_name",
.of_match_table = my_of_ids,
.owner = THIS_MODULE,
}
};
module_platform_driver(my_platform_driver);
MODULE_LICENSE("GPL");
&gpio {
...
...
key_pin: key_pin {
brcm,pins = <23>;
brcm,function = <0>; /* Input */
brcm,pull = <1>; /* Pull down */
};
---
&soc {
...
...
irq_key {
compatible = "arrow,key";
pinctrl-names = "default";
pinctrl-0 = <&key_pin>;
gpios = <&gpio 23 0>;
interrupts = <23 1>;
interrupt-parent = <&gpio>;
};
dev_info(error 등등) log 출력 의미
[platform driver name] [device name(device tree node name)] : message
1.[platform driver name]
static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
------> .name = "intkey_driver_name",
.of_match_table = my_of_ids,
.owner = THIS_MODULE,
}
};
2. [device name(device tree node name)]
---> irq_key {
compatible = "arrow,key";
pinctrl-names = "default";
pinctrl-0 = <&key_pin>;
gpios = <&gpio 23 0>;
interrupts = <23 1>;
interrupt-parent = <&gpio>;
};
insmod
[ 229.282086] intkey_driver_name soc:irq_key: my_probe() is enter.
[ 229.282290] intkey_driver_name soc:irq_key: gpiod_to_irq IRQ number : 166
[ 229.282353] intkey_driver_name soc:irq_key: platform_get_irq irq number : 166
[ 229.282718] intkey_driver_name soc:irq_key: mydev: got minor 60
[ 229.282733] intkey_driver_name soc:irq_key: my_probe() is exited.
dmesg 출력시 -w 옵션을 사용하면 실시간으로 dmesg 출력을 확인 할 수 있다
dmesg -w
인터럽트 정보 확인하기
cat /proc/interrupt
root@raspberrypi:/home/board# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
17: 776 0 0 0 ARMCTRL-level 1 Edge 3f00b880.mailbox
18: 978 0 0 0 ARMCTRL-level 2 Edge VCHIQ doorbell
34: 0 0 0 0 ARMCTRL-level 42 Edge vc4
35: 0 0 0 0 ARMCTRL-level 43 Edge 3f004000.txp
42: 247 0 0 0 ARMCTRL-level 50 Edge DMA IRQ
44: 8823 0 0 0 ARMCTRL-level 52 Edge DMA IRQ
45: 0 0 0 0 ARMCTRL-level 53 Edge DMA IRQ
48: 0 0 0 0 ARMCTRL-level 56 Edge DMA IRQ
49: 0 0 0 0 ARMCTRL-level 57 Edge DMA IRQ
56: 144660 0 0 0 ARMCTRL-level 64 Edge dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
57: 1 0 0 0 ARMCTRL-level 65 Edge vc4 hvs
64: 0 0 0 0 ARMCTRL-level 72 Edge vc4 hdmi cec
66: 5 0 0 0 ARMCTRL-level 74 Edge vc4 crtc
69: 0 0 0 0 ARMCTRL-level 77 Edge vc4 crtc
70: 0 0 0 0 ARMCTRL-level 78 Edge vc4 crtc
77: 0 0 0 0 ARMCTRL-level 85 Edge 3f804000.i2c, 3f805000.i2c
78: 0 0 0 0 ARMCTRL-level 86 Edge 3f204000.spi
80: 1004 0 0 0 ARMCTRL-level 88 Edge mmc0
81: 4337 0 0 0 ARMCTRL-level 89 Edge uart-pl011
86: 10901 0 0 0 ARMCTRL-level 94 Edge mmc1
161: 0 0 0 0 bcm2836-timer 0 Edge arch_timer
162: 5150 7474 5737 4333 bcm2836-timer 1 Edge arch_timer
165: 0 0 0 0 bcm2836-pmu 9 Edge arm-pmu
166: 1 0 0 0 pinctrl-bcm2835 23 Edge KEY <<<<<<<<-----------------------------------
FIQ: usb_fiq
IPI0: 0 0 0 0 CPU wakeup interrupts
IPI1: 0 0 0 0 Timer broadcast interrupts
IPI2: 5735 10509 10759 8110 Rescheduling interrupts
IPI3: 573 1368 1024 1685 Function call interrupts
IPI4: 0 0 0 0 CPU stop interrupts
IPI5: 477 2070 570 87 IRQ work interrupts
IPI6: 0 0 0 0 completion interrupts
Err: 0
인터럽트 발생시
[ 237.898983] intkey_driver_name soc:irq_key: interrupt received. key: KEY
'device driver' 카테고리의 다른 글
kernel linked list api 사용법 (0) | 2023.06.01 |
---|---|
Waiting queues (0) | 2023.06.01 |
charter device driver - 7. i2c platform driver 만들기 (0) | 2023.05.28 |
charter device driver - 6. led_class_platform 만들기 (0) | 2023.05.26 |
charter device driver - 5. platform_driver로 led control 해보자 (0) | 2023.05.22 |
댓글