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;
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;
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;
ioctl(fd, GPIOCTRL_IOCWREG, &ioc_reg);
LED 같은거 연결해두면 불 켜진다
write #2. gpiox_6의 output 값을 0으로 변경
ioc_reg.reg_offset = 0x119;
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;
ioc_reg.bit_mask = BIT(6);
ioc_reg.bit_data = 1;
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로 탐지하든지 하시면 되리라 생각합니다
저 같이 그 이하 레벨에서 뭔가를 하고 싶은 분들은 ㅠㅜ