Driver / Device · Linux v6.6 · source + diagram note

clock/reset/regulator

clock, reset, regulator의 독립된 handle·활성 상태와 driver별 오류 정리를 v6.6 원문으로 읽습니다.

세 공급 자원은 한 묶음의 상태가 아니다

하나의 IP driver가 clock, reset, regulator를 모두 사용할 수 있지만, 세 handle의 획득·활성화·반납 계약은 별개다. DT/ACPI 속성은 provider를 찾는 단서이고 실제 provider 준비 여부·deferred probe는 각 API 결과로 판단한다. 전압 공급·clock·reset의 하드웨어 순서는 선택한 IP의 데이터시트와 driver 구현에 따른다.

그림 1. consumer가 얻는 세 handle과 세 독립 상태
Clock
clk_getconsumer handle 획득. 아직 enabled로 가정하지 않음
clk_prepare_enableprepare + enable 요청; 반환값 확인
정리clk_disable_unprepare → clk_put
Reset
exclusive/shared 선택reset_control_get_exclusive / reset_control_get_shared
line 조작driver 정책에 따라 deassert/assert; shared는 균형 필요
정리필요한 상태 복구 → reset_control_put
Regulator
regulator_getsupply handle 획득. rail 상태와 별개
제약·enable필요시 set_voltage; regulator_enable 반환 확인
정리regulator_disable → regulator_put

세 줄 사이에는 프레임워크가 정한 전역 순서 화살표가 없다. 특정 driver의 probe()가 선택한 순서만 역순 정리의 기준이 된다.

clock balance · reset get variants · regulator enable balance

소스 코드 위치

기존 발췌는 drivers/clk/clk.c의 이름·HW helper와 drivers/reset/core.c의 exclusive acquire 부분이다. 실제 consumer clk_get() 구현은 drivers/clk/clkdev.c에 있고, reset get 변형은 include/linux/reset.h에 선언된다. regulator consumer 계약도 별도 파일에서 읽는다.

관심사v6.6 고정 원문이 글에서 읽는 부분
Clockdrivers/clk/clk.c · drivers/clk/clkdev.c · include/linux/clk.h기존 helper 발췌와 별개인 clk_get·prepare/enable 계약
Resetdrivers/reset/core.c · include/linux/reset.hexclusive acquire 발췌와 get variant·assert/deassert 계약
Regulatordrivers/regulator/core.c · include/linux/regulator/consumer.hconsumer handle, voltage 제약, enable/disable

대표 코드

Clock 이름·HW helper 구간

고정 원본: drivers/clk/clk.c:263-302 · 실제 clk_get() 구현은 clkdev.c:100–118
	return ret;
}

/***    helper functions   ***/

const char *__clk_get_name(const struct clk *clk)
{
	return !clk ? NULL : clk->core->name;
}
EXPORT_SYMBOL_GPL(__clk_get_name);

const char *clk_hw_get_name(const struct clk_hw *hw)
{
	return hw->core->name;
}
EXPORT_SYMBOL_GPL(clk_hw_get_name);

struct clk_hw *__clk_get_hw(struct clk *clk)
{
	return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);

unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
{
	return hw->core->num_parents;
}
EXPORT_SYMBOL_GPL(clk_hw_get_num_parents);

struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
{
	return hw->core->parent ? hw->core->parent->hw : NULL;
}
EXPORT_SYMBOL_GPL(clk_hw_get_parent);

static struct clk_core *__clk_lookup_subtree(const char *name,
					     struct clk_core *core)
{
	struct clk_core *child;
	struct clk_core *ret;

읽기 기준: 이 조각은 보유한 clock/HW의 이름·포인터를 읽는 helper 범위다. clk_get()도 provider 등록도 수행하지 않는다. 반환값은 해당 helper의 값이며 clock enable 상태를 뜻하지 않는다.

reset_control_acquire() 설명과 함수 앞부분

고정 원본: drivers/reset/core.c:623-662 · reset get variant는 reset.h
 *
 * This is used to explicitly acquire a reset control for exclusive use. Note
 * that exclusive resets are requested as acquired by default. In order for a
 * second consumer to be able to control the reset, the first consumer has to
 * release it first. Typically the easiest way to achieve this is to call the
 * reset_control_get_exclusive_released() to obtain an instance of the reset
 * control. Such reset controls are not acquired by default.
 *
 * Consumers implementing shared access to an exclusive reset need to follow
 * a specific protocol in order to work together. Before consumers can change
 * a reset they must acquire exclusive access using reset_control_acquire().
 * After they are done operating the reset, they must release exclusive access
 * with a call to reset_control_release(). Consumers are not granted exclusive
 * access to the reset as long as another consumer hasn't released a reset.
 *
 * See also: reset_control_release()
 */
int reset_control_acquire(struct reset_control *rstc)
{
	struct reset_control *rc;

	if (!rstc)
		return 0;

	if (WARN_ON(IS_ERR(rstc)))
		return -EINVAL;

	if (reset_control_is_array(rstc))
		return reset_control_array_acquire(rstc_to_array(rstc));

	mutex_lock(&reset_list_mutex);

	if (rstc->acquired) {
		mutex_unlock(&reset_list_mutex);
		return 0;
	}

	list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
		if (rstc != rc && rstc->id == rc->id) {
			if (rc->acquired) {

읽기 기준: 이 조각은 이미 얻은 reset control의 exclusive 접근권을 acquire하는 설명과 함수 앞부분이다. handle을 새로 얻는 reset get API가 아니다. NULL·error pointer·array·acquired 조건을 구분하고 나머지 분기는 원문 뒤를 읽는다.

발췌의 실제 함수와 consumer API를 나눠 읽기

위 대표 코드 첫 조각은 clk_get()이 아니라 clock 이름·HW 정보 helper들의 연속 구간이다. 두 번째는 reset_control_get() 구현이 아니라 reset_control_acquire()의 설명과 함수 앞부분이다. v6.6 발췌의 끝은 __clk_lookup_subtree 함수 시작이다.

그림 2. 기존 발췌 두 개가 가리키는 범위와 실제 consumer 진입점

발췌 A · clock helper

__clk_get_name, clk_hw_get_name 등은 이미 가진 clock/HW의 정보를 읽는다. provider 등록이나 consumer get을 실행하지 않는다.

실제 clk_get(dev,id)는 clkdev.c에서 OF lookup 결과를 시도하고 필요 시 clkdev lookup을 사용한다.

발췌 B · reset acquire

reset_control_acquire(rstc)는 released exclusive handle에 접근권을 얻는 함수다. NULL이면 0, error pointer는 -EINVAL, 경쟁 acquired handle이면 -EBUSY 경로가 있다.

handle 생성은 reset_control_get_exclusive / reset_control_get_shared 등 별도 API에서 한다.

handle 획득clk_get / reset get variant / regulator_get
선택적 동작clock prepare+enable, reset deassert/assert, regulator voltage+enable
driver별 unwind실제로 성공한 동작만 균형 정리; handle도 별도로 반납
API 층반환/상태짝이 되는 작업주의
clk_getstruct clk * 또는 ERR_PTR; source는 clkdev.cclk_put획득만으로 enabled 아님
clk_prepare_enable성공하면 사용 count 증가clk_disable_unprepareget/put과 다른 균형
reset get / acquireexclusive 또는 shared handle; released exclusive는 별도 acquirereset_control_release(해당 variant), reset_control_putshared assert/deassert는 균형 조건
regulator_get / enablehandle과 rail enable 요청은 별개regulator_disable, regulator_put전압 제약·다른 consumer·bootloader 상태와 구분

clk_get 구현 · clock helper 발췌 · reset acquire 발췌 · regulator_get 구현

handle 수명과 활성 상태는 서로 다르다

devm_* get은 보통 detach 때 handle을 반납하지만, 일반 get으로 켠 자원을 반드시 꺼 준다는 뜻은 아니다. 결합 helper를 사용했는지 실제 driver 코드를 봐야 한다.

그림 3. 각 자원에서 별도로 맞춰야 하는 두 장부
Clock 장부clk_get → clk_put는 참조 수명. clk_prepare_enable → clk_disable_unprepare는 사용 상태. 이름/HW helper는 어느 장부도 증가시키지 않는다.
Reset 장부get/put은 handle 수명. exclusive/shared 및 released-exclusive acquire/release는 접근 권한. assert/deassert는 line 상태 또는 shared 사용 count에 영향을 준다.
Regulator 장부get/put은 consumer handle. regulator_enable → regulator_disable는 사용 count. set_voltage는 별도 제약 요청이며 단순 enable의 대체가 아니다.

하드웨어의 실제 전기적 상태는 bootloader 초기 상태, 다른 consumer, provider의 구현에 좌우될 수 있으므로 소프트웨어 count와 동일시하지 않는다.

객체획득활성/제어해제 시 확인
clock consumer handleclk_get 또는 devm_clk_getclk_prepare_enable 성공 여부활성 균형 후 put 또는 devres
reset control handleexclusive/shared/optional variantacquire 필요 variant, assert/deassert 정책access release·line 상태·put을 분리
regulator consumer handleregulator_get 또는 devm전압 제약과 enable 성공 여부성공한 enable을 disable한 뒤 put

probe 오류가 난 위치에 따라 정리가 달라진다

다음 그림은 특정 하드웨어에 강제하는 순서가 아니라, driver가 세 자원을 모두 요청했을 때 정리 장부를 작성하는 방법이다. 실제 요청 순서는 해당 IP의 데이터시트와 probe 구현으로 채운다.

그림 4. 성공한 동작만 기록해 driver가 되돌리는 예시
획득 기록어떤 clock/reset/regulator handle을 얻었는지, devm인지 수동인지 기록
활성 기록prepare+enable / deassert / regulator enable 중 실제 성공한 동작만 표시
오류 지점각 반환값과 -EPROBE_DEFER 여부 확인; 이미 성공한 동작을 driver 순서에 맞춰 정리

성공 전

handle만 얻은 자원은 활성 해제가 필요하지 않다. 첫 enable 전에 실패했다면 해당 enable의 역함수를 무조건 호출하지 않는다.

일부 성공 후

성공한 clock/regulator 사용 count, reset line 조작을 대응시킨다. devm handle 반납과 하드웨어 상태 복구는 다른 책임이다.

이 세 framework를 하나의 원자적 트랜잭션으로 취급하지 않는다. 별도 bulk·managed helper의 보장 범위도 호출한 API 구현마다 확인한다.

실패 시점이미 남을 수 있는 상태driver가 확인할 정리원인 분리
clock get앞서 획득한 다른 handle그 handle의 put/devreslookup error와 -EPROBE_DEFER
reset get/acquireclock handle 또는 이미 활성화한 clock활성화했다면 disable/unprepare 후 handle 정리exclusive 충돌, optional 없음, provider 지연
regulator enablehandle·앞선 성공 동작regulator enable 실패를 성공으로 세지 않고 앞선 활성 동작 정리전압 제약/공급자 결과
IP 초기화 후속 단계세 자원의 일부 또는 전부 활성그 driver에서 성공시킨 상태의 역순 정리자원 획득과 IP 오류를 구분

세 자원에서 지켜야 할 균형

clock

clk_get 성공과 clk_prepare_enable 성공을 별도로 기록한다. enable을 못 했는데 disable하거나, 활성 상태를 남긴 채 put하지 않는다.

reset

exclusive·shared·optional 중 실제 variant를 기록한다. released-exclusive는 acquire/release 접근권이 필요하고 shared deassert/assert에는 균형 조건이 있다.

regulator

regulator_get과 regulator_enable은 다른 단계다. 필요하다면 전압 제약 요청 결과도 따로 기록하고 성공한 enable을 disable한다.

driver 순서

세 framework가 공통 순서나 전체 rollback을 제공한다고 가정하지 않는다. MMIO 접근 조건과 teardown 순서는 선택한 IP의 driver·datasheet에서 확인한다.

읽기 전용으로 provider와 consumer 상태를 확인

아래 debugfs 파일은 해당 framework와 debugfs 설정이 있을 때만 보인다. 값은 순간 관측치이며 대상 driver의 성공 경로를 대체하지 않는다. 전역 tracer/filter를 바꾸지 않는다.

가설읽기 전용 관찰해석 한계
clock provider/consumer있으면 cat /sys/kernel/debug/clk/clk_summaryprepare/enable count와 실제 IP 동작을 구분
regulator rail있으면 cat /sys/kernel/debug/regulator/regulator_summary다른 consumer·bootloader 초기 상태 고려
provider 지연있으면 cat /sys/kernel/debug/devices_deferreddeferred 목록이 빈 것만으로 probe 성공 아님
reset line선택한 reset provider/driver 로그와 reset_control_status 지원 여부status callback 미구현이면 -ENOTSUPP 가능

trace가 꼭 필요할 때는 테스트 보드에서 사용 가능한 event를 먼저 조회하고 특정 driver·함수 범위로 제한한다. 공용 시스템의 current_tracer나 set_ftrace_filter를 예제로 덮어쓰지 않는다.

선택한 IP driver에서 확인할 질문

  • 각 get의 실제 variant와 반환값은 무엇이며 -EPROBE_DEFER는 어디서 전달되는가?
  • clk_prepare_enable·regulator_enable·reset deassert 가운데 어느 동작까지 성공했는가?
  • driver가 선택한 전원·clock·reset 순서는 데이터시트의 MMIO 접근 전제와 일치하는가?
  • 오류 label, remove, suspend 경로가 성공한 동작을 각각 균형 있게 되돌리는가?
  • devm get을 썼다면 handle release 외의 활성 상태 정리를 누가 맡는가?