提交 96ee12b2 编写于 作者: T Thierry Reding

soc/tegra: fuse: Implement nvmem device

The nvmem framework provides a generic infrastructure and API to access
the type of information stored in fuses such as the Tegra FUSE block.

Implement an nvmem device that can be used to access the information in
a more generic way to decouple consumers from the custom Tegra API and
to add a more formal way of creating the dependency between the FUSE
device and the consumers.
Signed-off-by: NThierry Reding <treding@nvidia.com>
上级 9f1022b8
......@@ -8,6 +8,8 @@
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
......@@ -31,50 +33,6 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_A04] = "A04",
};
static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset)
{
u32 val;
val = fuse->read(fuse, round_down(offset, 4));
val >>= (offset % 4) * 8;
val &= 0xff;
return val;
}
static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t pos, size_t size)
{
struct device *dev = kobj_to_dev(kobj);
struct tegra_fuse *fuse = dev_get_drvdata(dev);
int i;
if (pos < 0 || pos >= attr->size)
return 0;
if (size > attr->size - pos)
size = attr->size - pos;
for (i = 0; i < size; i++)
buf[i] = fuse_readb(fuse, pos + i);
return i;
}
static struct bin_attribute fuse_bin_attr = {
.attr = { .name = "fuse", .mode = S_IRUGO, },
.read = fuse_read,
};
static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size,
const struct tegra_fuse_info *info)
{
fuse_bin_attr.size = size;
return device_create_bin_file(dev, &fuse_bin_attr);
}
static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra20-car", },
{ .compatible = "nvidia,tegra30-car", },
......@@ -115,9 +73,23 @@ static const struct of_device_id tegra_fuse_match[] = {
{ /* sentinel */ }
};
static int tegra_fuse_read(void *priv, unsigned int offset, void *value,
size_t bytes)
{
unsigned int count = bytes / 4, i;
struct tegra_fuse *fuse = priv;
u32 *buffer = value;
for (i = 0; i < count; i++)
buffer[i] = fuse->read(fuse, offset + i * 4);
return 0;
}
static int tegra_fuse_probe(struct platform_device *pdev)
{
void __iomem *base = fuse->base;
struct nvmem_config nvmem;
struct resource *res;
int err;
......@@ -150,9 +122,25 @@ static int tegra_fuse_probe(struct platform_device *pdev)
goto restore;
}
if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
fuse->soc->info)) {
err = -ENODEV;
memset(&nvmem, 0, sizeof(nvmem));
nvmem.dev = &pdev->dev;
nvmem.name = "fuse";
nvmem.id = -1;
nvmem.owner = THIS_MODULE;
nvmem.type = NVMEM_TYPE_OTP;
nvmem.read_only = true;
nvmem.root_only = true;
nvmem.reg_read = tegra_fuse_read;
nvmem.size = fuse->soc->info->size;
nvmem.word_size = 4;
nvmem.stride = 4;
nvmem.priv = fuse;
fuse->nvmem = devm_nvmem_register(&pdev->dev, &nvmem);
if (IS_ERR(fuse->nvmem)) {
err = PTR_ERR(fuse->nvmem);
dev_err(&pdev->dev, "failed to register NVMEM device: %d\n",
err);
goto restore;
}
......
......@@ -13,6 +13,7 @@
#include <linux/dmaengine.h>
#include <linux/types.h>
struct nvmem_device;
struct tegra_fuse;
struct tegra_fuse_info {
......@@ -48,6 +49,8 @@ struct tegra_fuse {
dma_addr_t phys;
u32 *virt;
} apbdma;
struct nvmem_device *nvmem;
};
void tegra_init_revision(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册