Skip to content

Commit

Permalink
soc/tegra: fuse: Implement nvmem device
Browse files Browse the repository at this point in the history
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: Thierry Reding <treding@nvidia.com>
  • Loading branch information
Thierry Reding committed Oct 16, 2019
1 parent 9f1022b commit 96ee12b
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 47 deletions.
82 changes: 35 additions & 47 deletions drivers/soc/tegra/fuse/fuse-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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", },
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/soc/tegra/fuse/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/dmaengine.h>
#include <linux/types.h>

struct nvmem_device;
struct tegra_fuse;

struct tegra_fuse_info {
Expand Down Expand Up @@ -48,6 +49,8 @@ struct tegra_fuse {
dma_addr_t phys;
u32 *virt;
} apbdma;

struct nvmem_device *nvmem;
};

void tegra_init_revision(void);
Expand Down

0 comments on commit 96ee12b

Please sign in to comment.