이 코드는 어떤 문제를 푸나요?
장치 레지스터를 설정하려면 필요한 전압, 클록과 리셋 상태가 먼저 준비되어야 합니다. 전원 공급기인 레귤레이터, 동작 박자를 제공하는 클록, 회로를 초기 상태로 잡는 리셋은 서로 다른 자원입니다. 필요한 순서는 하드웨어 문서에 따라 달라집니다. 아래 regulator_bulk_enable 전체를 통해 여러 전원 중 하나가 실패했을 때 이미 켠 전원을 어떻게 정리하는지 살펴봅니다.
읽을 범위: v6.6 · drivers/regulator/core.c · regulator_bulk_enable 4934–4968행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
레귤레이터
장치가 요구하는 공급 전압을 제공하거나 조절하는 자원입니다. 공유 공급원의 사용 계수를 관리하므로 enable 호출 한 번을 물리 스위치 변경 한 번과 동일시하지 않습니다.
클록과 리셋
클록은 회로 동작에 필요한 신호이고 리셋은 회로를 초기 상태에 두거나 해제합니다. 전원만 켜졌다고 장치가 정상 동작하는 것은 아닙니다.
공급자와 소비자
장치 드라이버는 소비자이며 클록·전원 등을 제공하는 드라이버는 공급자입니다. 공급자가 아직 등록되지 않으면 probe를 미뤄야 할 수 있습니다.
일괄 enable
여러 공급원을 켜는 작업의 성공과 실패를 묶어 관리합니다. 여기서는 비동기 작업을 모두 마친 뒤 실패를 검사하므로 일부 항목만 봐서는 최종 상태를 알 수 없습니다.
처음 읽을 때
설명용으로 공급원 A와 B 중 B의 enable이 실패했다고 가정하십시오. A를 켠 상태로 방치하면 실패한 장치가 계속 전력을 쓰거나 재시도 때 계수가 어긋날 수 있습니다. 두 공급원의 숫자와 이름은 예시이며 실제 보드 구성을 뜻하지 않습니다.
더 깊이 살펴볼 때
비동기 작업 완료를 모두 기다린 뒤 소비자별 결과를 읽는 순서와 성공한 소비자만 disable하는 롤백을 보십시오. bulk 함수는 전원만 다루므로 클록 enable 및 reset deassert 순서까지 보장하지 않습니다.
그림으로 보는 변화

1. 여러 전원을 요청합니다
각 소비자의 enable 작업을 같은 비동기 도메인에 예약합니다.
갈라지는 화살표는 병렬로 진행할 수 있는 enable 요청입니다.
2. 모든 결과를 기다립니다
한 작업의 성공만 보고 끝내지 않고 도메인의 모든 작업 완료를 기다립니다.
합쳐지는 화살표는 완료 동기화입니다. 공급 전압이 합산된다는 뜻이 아닙니다.
3. 성공을 유지하거나 되돌립니다
모두 성공하면 유지하고 하나라도 실패하면 성공했던 소비자의 enable을 취소합니다.
되돌아가는 화살표는 사용 요청 해제입니다. 공유 전원이 반드시 물리적으로 꺼진다는 뜻은 아닙니다.
regulator_bulk_enable를 한 줄씩 읽기
줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
int regulator_bulk_enable(int num_consumers,
struct regulator_bulk_data *consumers)
{
ASYNC_DOMAIN_EXCLUSIVE(async_domain);
int i;
int ret = 0;
for (i = 0; i < num_consumers; i++) {
async_schedule_domain(regulator_bulk_enable_async,
&consumers[i], &async_domain);
}
async_synchronize_full_domain(&async_domain);
/* If any consumer failed we need to unwind any that succeeded */
for (i = 0; i < num_consumers; i++) {
if (consumers[i].ret != 0) {
ret = consumers[i].ret;
goto err;
}
}
return 0;
err:
for (i = 0; i < num_consumers; i++) {
if (consumers[i].ret < 0)
pr_err("Failed to enable %s: %pe\n", consumers[i].supply,
ERR_PTR(consumers[i].ret));
else
regulator_disable(consumers[i].consumer);
}
return ret;
}int regulator_bulk_enable(int num_consumers,함께 켤 공급원의 개수를 받습니다.
struct regulator_bulk_data *consumers)공급원 핸들과 개별 결과를 담을 consumers 배열을 받습니다.
ASYNC_DOMAIN_EXCLUSIVE(async_domain);이번 일괄 작업만 기다릴 수 있도록 전용 비동기 도메인을 만듭니다. CPU 스레드를 직접 하나씩 생성하는 선언은 아닙니다.
int i;소비자 배열을 순회할 인덱스입니다.
int ret = 0;전체 결과를 우선 성공값으로 준비합니다.
for (i = 0; i < num_consumers; i++) {모든 공급원 소비자를 순회합니다.
async_schedule_domain(regulator_bulk_enable_async,소비자 하나의 enable 작업을 비동기 실행으로 예약합니다.
&consumers[i], &async_domain);이번 소비자 객체와 전용 도메인을 넘겨 결과를 각 항목에 기록하고 나중에 함께 기다릴 수 있게 합니다.
async_synchronize_full_domain(&async_domain);이 도메인에 예약한 enable이 모두 끝날 때까지 기다립니다. 이 뒤에서야 모든 소비자의 결과를 판단합니다.
for (i = 0; i < num_consumers; i++) {완료한 모든 소비자의 상태를 다시 순회합니다.
if (consumers[i].ret != 0) {성공값 0이 아닌 결과가 하나라도 있는지 검사합니다.
ret = consumers[i].ret;발견한 오류를 전체 반환 결과에 보관합니다.
goto err;부분 성공 상태를 정리하는 경로로 갑니다.
return 0;모든 enable이 성공한 경우 0을 반환하며 전원 사용 요청을 유지합니다.
err:일괄 enable이 실패했을 때 부분 성공을 되돌리는 위치입니다.
for (i = 0; i < num_consumers; i++) {먼저 실패한 항목뿐 아니라 모든 항목을 살펴 성공한 enable을 찾아냅니다.
if (consumers[i].ret < 0)해당 소비자가 음수 오류로 실패했는지 확인합니다.
pr_err("Failed to enable %s: %pe\n", consumers[i].supply,실패한 공급원 이름과 오류를 진단 메시지로 남깁니다.
ERR_PTR(consumers[i].ret));정수 오류를 %pe가 읽을 수 있는 오류 포인터 표현으로 바꿉니다. 이 포인터를 역참조하지 않습니다.
else이 소비자는 enable에 성공했던 경우입니다.
regulator_disable(consumers[i].consumer);성공했던 소비자의 사용 요청을 내려놓아 일괄 호출 전 상태로 되돌리려 합니다.
return ret;일괄 작업을 실패하게 만든 오류를 반환합니다.
함께 생각해 볼 질문
레귤레이터가 켜졌으면 클록도 자동으로 켜지나요?
아닙니다. 별도의 자원이며 드라이버가 하드웨어에 맞는 순서로 관리해야 합니다.
한 공급원이 실패해도 다른 성공한 작업은 계속 남기나요?
이 함수는 실패를 발견하면 성공한 소비자에 대해 regulator_disable을 호출해 앞서 한 enable을 되돌립니다.
disable 한 번이면 전압이 반드시 0이 되나요?
공유 사용자나 항상 켜야 하는 정책이 있을 수 있습니다. 우선 이 소비자의 사용 요청을 내려놓는 동작으로 이해해야 합니다.
출처와 읽은 범위
Linux stable v6.6 · drivers/regulator/core.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
