odroid c2 gpio ioctl controll

설명

/dev/gpiomem
/dev/gpioctrl
이라는 녀석이 있습니다

hardkernel이라는 회사에서 만든 드라이버구요
devicetree를 보시면 아시겠지만 0xc8834000 gpio base address부터 4096바이트 만큼 제어를 합니다

gpiomem은 mmap하셔서 직접 컨트롤 하고 싶을 때 사용하시면 되구요
gpioctrl은 ioctl로 레지스터를 r/w를 하시면 됩니다

드라이버 소스는 drivers/hardkernel/odroid-gpioctrl.c, odroid-gpiomem.c 구요
보통 gpioctrl을 많이 쓸 일이 있을 것으로 예상 됩니다
기본 permission이 udev룰에 의해 666(rw_rw_rw)이니 /dev/mem처럼 따로 권한 주는 일은 안 하셔도 됩니다


사용 방법

open 하시고 ioctl 호출하셔서

#define GPIOCTRL_IOCGREG        _IOR('g', 1, struct gpioctrl_iocreg)
#define GPIOCTRL_IOCWREG        _IOW('g', 2, struct gpioctrl_iocreg)

read 할 때는 GPIOCTRL_IOCGREG
write 할 때는 GPIOCTRL_IOCWREG

struct gpioctrl_iocreg {
 __u32 reg_offset;
 __u32 reg_data;
 __u32 bit_mask;
 __u32 bit_data;
};

이 자료형 쓰시면 될꺼 같구요

각 멤버 설명
reg_offset
gpio base로부터 접근하고 싶은 register offset(input/output/pulldown/up 등을 컨트롤)
reg_data
읽거나 쓴 후의 값, register 값이 통째로 들어가 있다
bit_mask
register 중 몇 번째 gpio를 컨트롤 하고 싶은가. 예를 들면 GPIOX 21번은 1<<21
bit_data
bit가 1이나 0이냐

참조 코드 - wiring pi, gpio_status_c2.c


사용 예시

read #1. gpiox_6의 input/output mode 확인
기본 gpiox_6(234) - input, 0, pull down

#define BIT(nr) (1U << (nr))
struct gpioctrl_iocreg ioc_reg;
ioc_reg.reg_offset = 0x118;    //FSEL
ioc_reg.bit_mask = BIT(6);
ioctl(fd, GPIOCTRL_IOCGREG, &ioc_reg);
printf("%s", ioc_reg.bit_data ? "input" : "output");

read #2. gpiox_21의 값 확인
기본 gpiox_21(249) - input, 1, pull up

ioc_reg.reg_offset = 0x11a;  
//input 값 확인하는 register 참고로 output 값 r/w하는 register는 별도로 있다
ioc_reg.bit_mask = BIT(21);
ioctl(fd, GPIOCTRL_IOCGREG, &ioc_reg);
printf("%u", ioc_reg.bit_data);

1 나올 것이다


write #1. gpiox_6을 input -> output으로 변경

ioc_reg.reg_offset = 0x118;
ioc_reg.bit_mask = BIT(6);
ioc_reg.bit_data = 0; //output!!
ioctl(fd, GPIOCTRL_IOCWREG, &ioc_reg);    //GREG가 아니라 WREG다

LED 같은거 연결해두면 불 켜진다


write #2. gpiox_6의 output 값을 0으로 변경

ioc_reg.reg_offset = 0x119;        //output r/w 하는 register
ioc_reg.bit_mask = BIT(6);
ioc_reg.bit_data = 0;
ioctl(fd, GPIOCTRL_IOCWREG, &ioc_reg);

LED 불 꺼진다


write #3. gpiox_6를 input mode, pull up상태로 변경

ioc_reg.reg_offset = 0x13e;        //pull up/down 컨트롤 register
ioc_reg.bit_mask = BIT(6);
ioc_reg.bit_data = 1;            // up
ioctl(fd, GPIOCTRL_IOCWREG, &ioc_reg);

이걸 활용하면 input mode, 기본 상태 pull down으로도 만들 수 있습니다


간단 정리

input mode 세팅
FSEL register 0x118 에서 해당 gpio offset을 1로 세팅

output mode 세팅
FSEL register에서 해당 gpio offset을 0으로 세팅

input mode 값 읽기
input register 0x11a에서

output mode 값 r/w
output register 0x119에서

pull up/down
0x13e 에서 up(1)/down(0) write


상세 정리

S905 amlogic rev 1.1.4 문서 23.4 Register Description
표를 참조해서 계산해보면 driver code와 동일함을 알 수 있다
예시 FSEL(OEN) 0x18
0xc8834400 + 0x18*4 (pdf) == 0xc8834000 + 0x118<<2 (code)


기타

이렇게 설정을 한다고 해서 device driver에서 interrupt handler를 돌릴 수 있는 것은 아닙니다
아마 gpio interrupt edge 설정을 해야할텐데 저는 잘 안되네요
시도하실 분들은 24.3 Register Description을 참조하시기 바랍니다
저의 경우는 ioremap으로 맵하고 readl로 읽으면 panic이 뜨더군요
대부분의 경우 sysfs를 활용해 poll 함수로 값 변화를 사용해 thread로 탐지하든지 하시면 되리라 생각합니다
저 같이 그 이하 레벨에서 뭔가를 하고 싶은 분들은 ㅠㅜ

Posted by 쵸코케키

블로그 이미지
chocokeki
쵸코케키

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.4
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

최근에 올라온 글

최근에 달린 댓글

글 보관함