ARM: i.MX: ocotp: Switch to regmap support
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
09db5f43f9
commit
2ee6bb3504
|
@ -26,6 +26,7 @@
|
|||
#include <io.h>
|
||||
#include <of.h>
|
||||
#include <clock.h>
|
||||
#include <regmap.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
/*
|
||||
|
@ -76,13 +77,14 @@ struct imx_ocotp_data {
|
|||
};
|
||||
|
||||
struct ocotp_priv {
|
||||
struct cdev cdev;
|
||||
struct regmap *map;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct device_d dev;
|
||||
int permanent_write_enable;
|
||||
int sense_enable;
|
||||
char ethaddr[6];
|
||||
struct regmap_config map_config;
|
||||
};
|
||||
|
||||
static int imx6_ocotp_set_timing(struct ocotp_priv *priv)
|
||||
|
@ -164,48 +166,37 @@ int imx6_ocotp_read_one_u32(struct ocotp_priv *priv, u32 index, u32 *pdata)
|
|||
|
||||
ret = imx6_ocotp_prepare(priv);
|
||||
if (ret) {
|
||||
dev_err(priv->cdev.dev, "failed to prepare read fuse 0x%08x\n",
|
||||
dev_err(&priv->dev, "failed to prepare read fuse 0x%08x\n",
|
||||
index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fuse_read_addr(priv, index, pdata);
|
||||
if (ret) {
|
||||
dev_err(priv->cdev.dev, "failed to read fuse 0x%08x\n", index);
|
||||
dev_err(&priv->dev, "failed to read fuse 0x%08x\n", index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t imx6_ocotp_cdev_read(struct cdev *cdev, void *buf,
|
||||
size_t count, loff_t offset, unsigned long flags)
|
||||
static int imx_ocotp_reg_read(void *ctx, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct ocotp_priv *priv = ctx;
|
||||
u32 index;
|
||||
ssize_t read_count = 0;
|
||||
int ret, i;
|
||||
struct ocotp_priv *priv = container_of(cdev, struct ocotp_priv, cdev);
|
||||
int ret;
|
||||
|
||||
index = offset >> 2;
|
||||
count >>= 2;
|
||||
index = reg >> 2;
|
||||
|
||||
if (count > (FUSE_REGS_COUNT - index))
|
||||
count = FUSE_REGS_COUNT - index - 1;
|
||||
|
||||
for (i = index; i < (index + count); i++) {
|
||||
if (priv->sense_enable) {
|
||||
ret = imx6_ocotp_read_one_u32(priv, i, buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
*(u32 *)buf = readl(priv->base + 0x400 + i * 0x10);
|
||||
}
|
||||
|
||||
buf += 4;
|
||||
read_count++;
|
||||
if (priv->sense_enable) {
|
||||
ret = imx6_ocotp_read_one_u32(priv, index, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
*(u32 *)val = readl(priv->base + 0x400 + index * 0x10);
|
||||
}
|
||||
|
||||
return read_count << 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_blow_addr(struct ocotp_priv *priv, u32 addr, u32 value)
|
||||
|
@ -234,7 +225,7 @@ static int fuse_blow_addr(struct ocotp_priv *priv, u32 addr, u32 value)
|
|||
|
||||
static int imx6_ocotp_reload_shadow(struct ocotp_priv *priv)
|
||||
{
|
||||
dev_info(priv->cdev.dev, "reloading shadow registers...\n");
|
||||
dev_info(&priv->dev, "reloading shadow registers...\n");
|
||||
writel(OCOTP_CTRL_RELOAD_SHADOWS, priv->base + OCOTP_CTRL_SET);
|
||||
udelay(1);
|
||||
|
||||
|
@ -248,18 +239,18 @@ int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data,
|
|||
|
||||
ret = imx6_ocotp_prepare(priv);
|
||||
if (ret) {
|
||||
dev_err(priv->cdev.dev, "prepare to write failed\n");
|
||||
dev_err(&priv->dev, "prepare to write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fuse_blow_addr(priv, index, data);
|
||||
if (ret) {
|
||||
dev_err(priv->cdev.dev, "fuse blow failed\n");
|
||||
dev_err(&priv->dev, "fuse blow failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR) {
|
||||
dev_err(priv->cdev.dev, "bad write status\n");
|
||||
dev_err(&priv->dev, "bad write status\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
@ -268,60 +259,29 @@ int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t imx6_ocotp_cdev_write(struct cdev *cdev, const void *buf,
|
||||
size_t count, loff_t offset, unsigned long flags)
|
||||
static int imx_ocotp_reg_write(void *ctx, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct ocotp_priv *priv = cdev->priv;
|
||||
int index, i;
|
||||
ssize_t write_count = 0;
|
||||
const u32 *data;
|
||||
struct ocotp_priv *priv = ctx;
|
||||
int index;
|
||||
u32 pfuse;
|
||||
int ret;
|
||||
|
||||
/* We could do better, but currently this is what's implemented */
|
||||
if (offset & 0x3 || count & 0x3) {
|
||||
dev_err(cdev->dev, "only u32 aligned writes allowed\n");
|
||||
return -EINVAL;
|
||||
index = reg >> 2;
|
||||
|
||||
if (priv->permanent_write_enable) {
|
||||
ret = imx6_ocotp_blow_one_u32(priv, index, val, &pfuse);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
writel(val, priv->base + 0x400 + index * 0x10);
|
||||
}
|
||||
|
||||
index = offset >> 2;
|
||||
count >>= 2;
|
||||
|
||||
if (count > (FUSE_REGS_COUNT - index))
|
||||
count = FUSE_REGS_COUNT - index - 1;
|
||||
|
||||
data = buf;
|
||||
|
||||
for (i = index; i < (index + count); i++) {
|
||||
if (priv->permanent_write_enable) {
|
||||
ret = imx6_ocotp_blow_one_u32(priv, i, *data,
|
||||
&pfuse);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
writel(*data, priv->base + 0x400 + i * 0x10);
|
||||
}
|
||||
|
||||
data++;
|
||||
write_count++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (priv->permanent_write_enable)
|
||||
imx6_ocotp_reload_shadow(priv);
|
||||
|
||||
return ret < 0 ? ret : (write_count << 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations imx6_ocotp_ops = {
|
||||
.read = imx6_ocotp_cdev_read,
|
||||
.write = imx6_ocotp_cdev_write,
|
||||
.lseek = dev_lseek_default,
|
||||
};
|
||||
|
||||
static uint32_t inc_offset(uint32_t offset)
|
||||
{
|
||||
if ((offset & 0x3) == 0x3)
|
||||
|
@ -375,9 +335,11 @@ static int imx_ocotp_get_mac(struct param_d *param, void *priv)
|
|||
{
|
||||
struct ocotp_priv *ocotp_priv = priv;
|
||||
char buf[8];
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
imx6_ocotp_cdev_read(&ocotp_priv->cdev, buf, MAC_BYTES, MAC_OFFSET, 0);
|
||||
ret = regmap_bulk_read(ocotp_priv->map, MAC_OFFSET, buf, MAC_BYTES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
ocotp_priv->ethaddr[i] = buf[5 - i];
|
||||
|
@ -395,18 +357,22 @@ static int imx_ocotp_set_mac(struct param_d *param, void *priv)
|
|||
buf[5 - i] = ocotp_priv->ethaddr[i];
|
||||
buf[6] = 0; buf[7] = 0;
|
||||
|
||||
ret = imx6_ocotp_cdev_write(&ocotp_priv->cdev, buf, MAC_BYTES, MAC_OFFSET, 0);
|
||||
ret = regmap_bulk_write(ocotp_priv->map, MAC_OFFSET, buf, MAC_BYTES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_bus imx_ocotp_regmap_bus = {
|
||||
.reg_write = imx_ocotp_reg_write,
|
||||
.reg_read = imx_ocotp_reg_read,
|
||||
};
|
||||
|
||||
static int imx_ocotp_probe(struct device_d *dev)
|
||||
{
|
||||
void __iomem *base;
|
||||
struct ocotp_priv *priv;
|
||||
struct cdev *cdev;
|
||||
int ret = 0;
|
||||
struct imx_ocotp_data *data;
|
||||
|
||||
|
@ -427,22 +393,23 @@ static int imx_ocotp_probe(struct device_d *dev)
|
|||
if (IS_ERR(priv->clk))
|
||||
return PTR_ERR(priv->clk);
|
||||
|
||||
cdev = &priv->cdev;
|
||||
cdev->dev = dev;
|
||||
cdev->ops = &imx6_ocotp_ops;
|
||||
cdev->priv = priv;
|
||||
cdev->size = data->num_regs;
|
||||
cdev->name = "imx-ocotp";
|
||||
|
||||
ret = devfs_create(cdev);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
strcpy(priv->dev.name, "ocotp");
|
||||
priv->dev.parent = dev;
|
||||
register_device(&priv->dev);
|
||||
|
||||
priv->map_config.reg_bits = 32;
|
||||
priv->map_config.val_bits = 32;
|
||||
priv->map_config.reg_stride = 4;
|
||||
priv->map_config.max_register = data->num_regs - 1;
|
||||
|
||||
priv->map = regmap_init(&priv->dev, &imx_ocotp_regmap_bus, priv, &priv->map_config);
|
||||
if (IS_ERR(priv->map))
|
||||
return PTR_ERR(priv->map);
|
||||
|
||||
ret = regmap_register_cdev(priv->map, "imx-ocotp");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_IMX_OCOTP_WRITE)) {
|
||||
dev_add_param_bool(&(priv->dev), "permanent_write_enable",
|
||||
NULL, NULL, &priv->permanent_write_enable, NULL);
|
||||
|
|
Loading…
Reference in New Issue