diff options
Diffstat (limited to 'drivers/nvmem/core.c')
| -rw-r--r-- | drivers/nvmem/core.c | 95 | 
1 files changed, 95 insertions, 0 deletions
| diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index a5ab1e0c74cf..bca671ff4e54 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1606,6 +1606,101 @@ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)  }  EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); +static void *nvmem_cell_read_variable_common(struct device *dev, +					     const char *cell_id, +					     size_t max_len, size_t *len) +{ +	struct nvmem_cell *cell; +	int nbits; +	void *buf; + +	cell = nvmem_cell_get(dev, cell_id); +	if (IS_ERR(cell)) +		return cell; + +	nbits = cell->nbits; +	buf = nvmem_cell_read(cell, len); +	nvmem_cell_put(cell); +	if (IS_ERR(buf)) +		return buf; + +	/* +	 * If nbits is set then nvmem_cell_read() can significantly exaggerate +	 * the length of the real data. Throw away the extra junk. +	 */ +	if (nbits) +		*len = DIV_ROUND_UP(nbits, 8); + +	if (*len > max_len) { +		kfree(buf); +		return ERR_PTR(-ERANGE); +	} + +	return buf; +} + +/** + * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, +				    u32 *val) +{ +	size_t len; +	u8 *buf; +	int i; + +	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); +	if (IS_ERR(buf)) +		return PTR_ERR(buf); + +	/* Copy w/ implicit endian conversion */ +	*val = 0; +	for (i = 0; i < len; i++) +		*val |= buf[i] << (8 * i); + +	kfree(buf); + +	return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); + +/** + * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, +				    u64 *val) +{ +	size_t len; +	u8 *buf; +	int i; + +	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); +	if (IS_ERR(buf)) +		return PTR_ERR(buf); + +	/* Copy w/ implicit endian conversion */ +	*val = 0; +	for (i = 0; i < len; i++) +		*val |= (uint64_t)buf[i] << (8 * i); + +	kfree(buf); + +	return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); +  /**   * nvmem_device_cell_read() - Read a given nvmem device and cell   * | 
