# 클록·리셋·레귤레이터: 일부만 켜졌을 때 되돌리는 이유

v6.18.37 / drivers/regulator/core.c

장치 레지스터를 설정하려면 필요한 전압, 클록과 리셋 상태가 먼저 준비되어야 합니다. 전원 공급기인 레귤레이터, 동작 박자를 제공하는 클록, 회로를 초기 상태로 잡는 리셋은 서로 다른 자원입니다. 필요한 순서는 하드웨어 문서에 따라 달라집니다. 아래 regulator_bulk_enable 전체를 통해 여러 전원 중 하나가 실패했을 때 이미 켠 전원을 어떻게 정리하는지 살펴봅니다.

## regulator_bulk_enable

```c

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;
}

```

### 5179행

```c

int regulator_bulk_enable(int num_consumers,

```

함께 켤 공급원의 개수를 받습니다.

### 5180행

```c

			  struct regulator_bulk_data *consumers)

```

공급원 핸들과 개별 결과를 담을 consumers 배열을 받습니다.

### 5182행

```c

	ASYNC_DOMAIN_EXCLUSIVE(async_domain);

```

이번 일괄 작업만 기다릴 수 있도록 전용 비동기 도메인을 만듭니다. CPU 스레드를 직접 하나씩 생성하는 선언은 아닙니다.

### 5183행

```c

	int i;

```

소비자 배열을 순회할 인덱스입니다.

### 5184행

```c

	int ret = 0;

```

전체 결과를 우선 성공값으로 준비합니다.

### 5186행

```c

	for (i = 0; i < num_consumers; i++) {

```

모든 공급원 소비자를 순회합니다.

### 5187행

```c

		async_schedule_domain(regulator_bulk_enable_async,

```

소비자 하나의 enable 작업을 비동기 실행으로 예약합니다.

### 5188행

```c

				      &consumers[i], &async_domain);

```

이번 소비자 객체와 전용 도메인을 넘겨 결과를 각 항목에 기록하고 나중에 함께 기다릴 수 있게 합니다.

### 5191행

```c

	async_synchronize_full_domain(&async_domain);

```

이 도메인에 예약한 enable이 모두 끝날 때까지 기다립니다. 이 뒤에서야 모든 소비자의 결과를 판단합니다.

### 5194행

```c

	for (i = 0; i < num_consumers; i++) {

```

완료한 모든 소비자의 상태를 다시 순회합니다.

### 5195행

```c

		if (consumers[i].ret != 0) {

```

성공값 0이 아닌 결과가 하나라도 있는지 검사합니다.

### 5196행

```c

			ret = consumers[i].ret;

```

발견한 오류를 전체 반환 결과에 보관합니다.

### 5197행

```c

			goto err;

```

부분 성공 상태를 정리하는 경로로 갑니다.

### 5201행

```c

	return 0;

```

모든 enable이 성공한 경우 0을 반환하며 전원 사용 요청을 유지합니다.

### 5203행

```c

err:

```

일괄 enable이 실패했을 때 부분 성공을 되돌리는 위치입니다.

### 5204행

```c

	for (i = 0; i < num_consumers; i++) {

```

먼저 실패한 항목뿐 아니라 모든 항목을 살펴 성공한 enable을 찾아냅니다.

### 5205행

```c

		if (consumers[i].ret < 0)

```

해당 소비자가 음수 오류로 실패했는지 확인합니다.

### 5206행

```c

			pr_err("Failed to enable %s: %pe\n", consumers[i].supply,

```

실패한 공급원 이름과 오류를 진단 메시지로 남깁니다.

### 5207행

```c

			       ERR_PTR(consumers[i].ret));

```

정수 오류를 %pe가 읽을 수 있는 오류 포인터 표현으로 바꿉니다. 이 포인터를 역참조하지 않습니다.

### 5208행

```c

		else

```

이 소비자는 enable에 성공했던 경우입니다.

### 5209행

```c

			regulator_disable(consumers[i].consumer);

```

성공했던 소비자의 사용 요청을 내려놓아 일괄 호출 전 상태로 되돌리려 합니다.

### 5212행

```c

	return ret;

```

일괄 작업을 실패하게 만든 오류를 반환합니다.

