1. GPIO
일반적으로 하나의 gpio 핀은 여러 기능을 수행할 수 있다. 예를 들면 UART, I2C, SPI 등, 설정 가능한 여러 기능이 있으며 현재의 configuration에 맞게 동작한다.
설정할 수 있는 값은 일반적으로 아래와 같다.
(1) 기능(인터페이스) 설정 : i2c, i2s, spi, uart등
(2) 핀 설정 : pull up/down, value 설정등
(3) 그룹 설정, 핀들을 모아 특정 인터페이스를 세팅
2. GPIO configuration
GPIO 설정은 당연히 kernel pinctrl driver를 통하여 하나씩 설정할 수 있다. 일반적으로 enable이나 interrupt 핀의 경우, driver에서 gpio를 컨트롤하는 방식을 많이 사용한다.
하지만 여러개의 핀을 한번에 설정하는 동작이나 suspend, resume과 같이 특정 기능에 콜백으로 처리하는 경우도 생각한다면, driver에서 하나씩 하나씩 설정하는 것은 썩 좋지 못한 방법이다.
3. pinctrl-names
다수의 configruation을 일괄로 처리하기 위한 방법으로 pinctrl-names를 고려해볼 수 있다. device tree를 통하여 여러개의 configuration을 생성해두고, 각 configuration마다 name을 부여한 다음, driver에서는 단순히 name을 호출하는 방식으로 처리하는 것이다.
예를 들어 아래와 같이 default와 sleep 이라는 이름을 정의하면, 각각의 이름은 pinctrl-0과 pinctrl-1에 대응된다.
&uart1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&uart1_pins_default>;
pinctrl-1 = <&uart1_pins_sleep>;
};
그리고 device driver에서는 아래와 같이 pinctrl 정보를 얻어, name으로 일괄 설정을 할 수 있게 된다.
struct device *dev = 어딘가
struct pinctrl *pinctrl;
struct pinctrl_state *default_state;
pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pinctrl)) {
dev_err(dev, "Failed to get pinctrl\n");
return PTR_ERR(pinctrl);
}
default_state = pinctrl_lookup_state(pinctrl, "default");
if (IS_ERR(default_state)) {
dev_err(dev, "Failed to look up 'default' state\n");
return PTR_ERR(default_state);
}
pinctrl_select_state(pinctrl, default_state);
4. 별개로 알아두면 좋은 것들
핀컨트롤 커널 링크: https://www.kernel.org/doc/Documentation/pinctrl.txt
핀컨트롤 커널 레포: https://github.com/torvalds/linux/blob/master/drivers/pinctrl/core.c#L1048
pinctrl은 create_pinctrl이 호출될 때 device 정보를 같이 받으며, 해당 device의 np으로 pinctrl-names와 pinctrl-0,..를 파싱해서 pinctrl_list에 저장해둔다.
따라서 장치의 pinctrl을 찾으려면, devm_pinctrl_get을 이용할 수 있다. 이 함수는 pinctrl_list에 저장되어 있는 항목 중 device가 동일한 pinctrl을 리턴한다.
struct pinctrl *devm_pinctrl_get(struct device *dev)
그리고 create_pinctrl시에 device의 pinctrl은 pinctrl-0, ... , N의 property로 길이를 측정한다. 정확히는 0부터 계속해서 찾아나가는 형태이며, 이에 대응되는 names가 없는 경우, 해당 숫자가 이름으로 설정된다.
예를 들어 아래와 같이 pinctrl-0~4번까지 있지만, names는 2개밖에 없는 경우는 "default", "sleep", "2" ,"3" 과 동일하다.
그리고 pinctrl-3과 같이 아무것도 없는 경우 dummy state로 생성되어 매핑된다.
물론 3번에 해당되는 names를 안부르면 그만이지만, 정말 삭제하고자 한다면 delete property를 이용해야 한다.
&uart1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&uart1_pins_default>;
pinctrl-1 = <&uart1_pins_sleep>;
pinctrl-2 = <&uart1_pins_idle>;
pinctrl-3;
};
create_pinctrl https://github.com/torvalds/linux/blob/master/drivers/pinctrl/core.c#L1048C24-L1048C38
pinctrl_dt_to_map https://github.com/torvalds/linux/blob/master/drivers/pinctrl/devicetree.c#L182
'프로그래밍 > 리눅스 커널' 카테고리의 다른 글
s906b sound card probe 살펴보기 (1) | 2022.05.26 |
---|---|
s906b alsa sound card 코드 따라가기 (0) | 2022.05.19 |
삼성 S906B (S22+) 리눅스 커널 다운 및 vim, cscope, ctags 준비 (0) | 2022.05.19 |