mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 18:09:57 +00:00
![Douglas Anderson](/assets/img/avatar_default.png)
Sometimes the clients of nvmem just want to get a number out of nvmem. They don't want to think about exactly how many bytes the nvmem cell took up. They just want the number. Let's make it easy. In general this concept is useful because nvmem space is precious and usually the fewest bits are allocated that will hold a given value on a given system. However, even though small numbers might be fine on one system that doesn't mean that logically the number couldn't be bigger. Imagine nvmem containing a max frequency for a component. On one system perhaps that fits in 16 bits. On another system it might fit in 32 bits. The code reading this number doesn't care--it just wants the number. We'll provide two functions: nvmem_cell_read_variable_le_u32() and nvmem_cell_read_variable_le_u64(). Comparing these to the existing functions like nvmem_cell_read_u32(): * These new functions have no problems if the value was stored in nvmem in fewer bytes. It's OK to use these function as long as the value stored will fit in 32-bits (or 64-bits). * These functions avoid problems that the earlier APIs had with bit offsets. For instance, you can't use nvmem_cell_read_u32() to read a value has nbits=32 and bit_offset=4 because the nvmem cell must be at least 5 bytes big to hold this value. The new API accounts for this and works fine. * These functions make it very explicit that they assume that the number was stored in little endian format. The old functions made this assumption whenever bit_offset was non-zero (see nvmem_shift_read_buffer_in_place()) but didn't whenever the bit_offset was zero. NOTE: it's assumed that we don't need an 8-bit or 16-bit version of this function. The 32-bit version of the function can be used to read 8-bit or 16-bit data. At the moment, I'm only adding the "unsigned" versions of these functions, but if it ends up being useful someone could add a "signed" version that did 2's complement sign extension. At the moment, I'm only adding the "little endian" versions of these functions. Adding the "big endian" version would require adding "big endian" support to nvmem_shift_read_buffer_in_place(). Signed-off-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Link: https://lore.kernel.org/r/20210330111241.19401-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
249 lines
6.5 KiB
C
249 lines
6.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* nvmem framework consumer.
|
|
*
|
|
* Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
|
* Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
*/
|
|
|
|
#ifndef _LINUX_NVMEM_CONSUMER_H
|
|
#define _LINUX_NVMEM_CONSUMER_H
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/notifier.h>
|
|
|
|
struct device;
|
|
struct device_node;
|
|
/* consumer cookie */
|
|
struct nvmem_cell;
|
|
struct nvmem_device;
|
|
|
|
struct nvmem_cell_info {
|
|
const char *name;
|
|
unsigned int offset;
|
|
unsigned int bytes;
|
|
unsigned int bit_offset;
|
|
unsigned int nbits;
|
|
};
|
|
|
|
/**
|
|
* struct nvmem_cell_lookup - cell lookup entry
|
|
*
|
|
* @nvmem_name: Name of the provider.
|
|
* @cell_name: Name of the nvmem cell as defined in the name field of
|
|
* struct nvmem_cell_info.
|
|
* @dev_id: Name of the consumer device that will be associated with
|
|
* this cell.
|
|
* @con_id: Connector id for this cell lookup.
|
|
*/
|
|
struct nvmem_cell_lookup {
|
|
const char *nvmem_name;
|
|
const char *cell_name;
|
|
const char *dev_id;
|
|
const char *con_id;
|
|
struct list_head node;
|
|
};
|
|
|
|
enum {
|
|
NVMEM_ADD = 1,
|
|
NVMEM_REMOVE,
|
|
NVMEM_CELL_ADD,
|
|
NVMEM_CELL_REMOVE,
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_NVMEM)
|
|
|
|
/* Cell based interface */
|
|
struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id);
|
|
struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id);
|
|
void nvmem_cell_put(struct nvmem_cell *cell);
|
|
void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
|
|
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
|
|
int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
|
|
int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val);
|
|
int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
|
|
int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
|
|
int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val);
|
|
int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
|
|
u32 *val);
|
|
int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
|
|
u64 *val);
|
|
|
|
/* direct nvmem device read/write interface */
|
|
struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
|
|
struct nvmem_device *devm_nvmem_device_get(struct device *dev,
|
|
const char *name);
|
|
void nvmem_device_put(struct nvmem_device *nvmem);
|
|
void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
|
|
int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
|
|
size_t bytes, void *buf);
|
|
int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
|
|
size_t bytes, void *buf);
|
|
ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
|
|
struct nvmem_cell_info *info, void *buf);
|
|
int nvmem_device_cell_write(struct nvmem_device *nvmem,
|
|
struct nvmem_cell_info *info, void *buf);
|
|
|
|
const char *nvmem_dev_name(struct nvmem_device *nvmem);
|
|
|
|
void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries,
|
|
size_t nentries);
|
|
void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries,
|
|
size_t nentries);
|
|
|
|
int nvmem_register_notifier(struct notifier_block *nb);
|
|
int nvmem_unregister_notifier(struct notifier_block *nb);
|
|
|
|
struct nvmem_device *nvmem_device_find(void *data,
|
|
int (*match)(struct device *dev, const void *data));
|
|
|
|
#else
|
|
|
|
static inline struct nvmem_cell *nvmem_cell_get(struct device *dev,
|
|
const char *id)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev,
|
|
const char *id)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline void devm_nvmem_cell_put(struct device *dev,
|
|
struct nvmem_cell *cell)
|
|
{
|
|
|
|
}
|
|
static inline void nvmem_cell_put(struct nvmem_cell *cell)
|
|
{
|
|
}
|
|
|
|
static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline int nvmem_cell_write(struct nvmem_cell *cell,
|
|
void *buf, size_t len)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_cell_read_u16(struct device *dev,
|
|
const char *cell_id, u16 *val)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_cell_read_u32(struct device *dev,
|
|
const char *cell_id, u32 *val)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_cell_read_u64(struct device *dev,
|
|
const char *cell_id, u64 *val)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline struct nvmem_device *nvmem_device_get(struct device *dev,
|
|
const char *name)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev,
|
|
const char *name)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline void nvmem_device_put(struct nvmem_device *nvmem)
|
|
{
|
|
}
|
|
|
|
static inline void devm_nvmem_device_put(struct device *dev,
|
|
struct nvmem_device *nvmem)
|
|
{
|
|
}
|
|
|
|
static inline ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
|
|
struct nvmem_cell_info *info,
|
|
void *buf)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_device_cell_write(struct nvmem_device *nvmem,
|
|
struct nvmem_cell_info *info,
|
|
void *buf)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_device_read(struct nvmem_device *nvmem,
|
|
unsigned int offset, size_t bytes,
|
|
void *buf)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_device_write(struct nvmem_device *nvmem,
|
|
unsigned int offset, size_t bytes,
|
|
void *buf)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline const char *nvmem_dev_name(struct nvmem_device *nvmem)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline void
|
|
nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {}
|
|
static inline void
|
|
nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) {}
|
|
|
|
static inline int nvmem_register_notifier(struct notifier_block *nb)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline int nvmem_unregister_notifier(struct notifier_block *nb)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline struct nvmem_device *nvmem_device_find(void *data,
|
|
int (*match)(struct device *dev, const void *data))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#endif /* CONFIG_NVMEM */
|
|
|
|
#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
|
|
struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
|
|
const char *id);
|
|
struct nvmem_device *of_nvmem_device_get(struct device_node *np,
|
|
const char *name);
|
|
#else
|
|
static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
|
|
const char *id)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
|
|
static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np,
|
|
const char *name)
|
|
{
|
|
return ERR_PTR(-EOPNOTSUPP);
|
|
}
|
|
#endif /* CONFIG_NVMEM && CONFIG_OF */
|
|
|
|
#endif /* ifndef _LINUX_NVMEM_CONSUMER_H */
|