본문 바로가기
임베디드

regmap_update_bits 함수

by I!i어★떤☆날★에Ι!i 2022. 10. 28.
반응형

regmap의 특정 비트를 업데이트하기 위해서  regmap_update_bits 함수를 사용한다.

 

 

linux_regmap
linux regmap

 

/include/linux/regmap.h

static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
				     unsigned int mask, unsigned int val)
{
	return regmap_update_bits_base(map, reg, mask, val, NULL, false, false);
}

 

regmap_update_bits 함수를 살펴보면, 파라미터로 받는 reg 변수의 mask에 해당하는 영역에 val 변수값을 업데이트한다.

 

val 변수값은 FIELD_PREP 매크로를 통해서 비트 영역에 맞는 값을 할당할 수 있다.

 

include/linux/bitfield.h

/**
 * FIELD_PREP() - prepare a bitfield element
 * @_mask: shifted mask defining the field's length and position
 * @_val:  value to put in the field
 *
 * FIELD_PREP() masks and shifts up the value.  The result should
 * be combined with other fields of the bitfield using logical OR.
 */
#define FIELD_PREP(_mask, _val)						\
	({								\
		__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: ");	\
		((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask);	\
	})

 

 

예를 들어 값이 3인데 4~5번 비트에 할당되는 값이면, 다음과 같은 형식을 통해서 val 변수에 값을 할당할 수 있다.

이렇게 하면 regmap_update_bits 함수에 값을 더 쉽게 입력할 수 있다.

 

val = FIELD_PREP( GENMASK(4,5), 3 );

 

 

FIELD_PREP 매크로를 통해서 할당한 값을 regmap_update_bits 함수에 설정하면 된다.

regmap_update_bits 함수를 좀더 상세히 살펴보자.

 

 

drivers/base/regmap/regmap.c

/**
 * regmap_update_bits_base() - Perform a read/modify/write cycle on a register
 *
 * @map: Register map to update
 * @reg: Register to update
 * @mask: Bitmask to change
 * @val: New value for bitmask
 * @change: Boolean indicating if a write was done
 * @async: Boolean indicating asynchronously
 * @force: Boolean indicating use force update
 *
 * Perform a read/modify/write cycle on a register map with change, async, force
 * options.
 *
 * If async is true:
 *
 * With most buses the read must be done synchronously so this is most useful
 * for devices with a cache which do not need to interact with the hardware to
 * determine the current register value.
 *
 * Returns zero for success, a negative number on error.
 */
int regmap_update_bits_base(struct regmap *map, unsigned int reg,
			    unsigned int mask, unsigned int val,
			    bool *change, bool async, bool force)
{
	int ret;

	map->lock(map->lock_arg);

	map->async = async;

	ret = _regmap_update_bits(map, reg, mask, val, change, force);

	map->async = false;

	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_update_bits_base);

 

함수는 regmap_read로 값을 읽은 후, 값을 OR 연산하고 regmap_write로 다시 쓴다. 이때 뮤텍스 처리를 해서 값이 서로 충돌하는 것을 막는다.

 

static int _regmap_update_bits(struct regmap *map, unsigned int reg,
			       unsigned int mask, unsigned int val,
			       bool *change, bool force_write)
{
	int ret;
	unsigned int tmp, orig;

	if (change)
		*change = false;

	if (regmap_volatile(map, reg) && map->reg_update_bits) {
		ret = map->reg_update_bits(map->bus_context, reg, mask, val);
		if (ret == 0 && change)
			*change = true;
	} else {
		ret = _regmap_read(map, reg, &orig);
		if (ret != 0)
			return ret;

		tmp = orig & ~mask;
		tmp |= val & mask;

		if (force_write || (tmp != orig)) {
			ret = _regmap_write(map, reg, tmp);
			if (ret == 0 && change)
				*change = true;
		}
	}

	return ret;
}

 

 

regmap의 특정 비트를 업데이트 할때  regmap_update_bits 함수를 사용해 보자.

반응형

댓글