diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-03 16:03:54 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-05 15:13:29 +0100 |
commit | 2ee6bb35043de0bc994da4bf3f0139280229c3bd (patch) | |
tree | 8fc49476b13ed0e31812453b2ef81bed90144e35 /arch | |
parent | 09db5f43f9f36440fcdcf6fbc21257338053bd1c (diff) | |
download | barebox-2ee6bb35043de0bc994da4bf3f0139280229c3bd.tar.gz barebox-2ee6bb35043de0bc994da4bf3f0139280229c3bd.tar.xz |
ARM: i.MX: ocotp: Switch to regmap support
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-imx/ocotp.c | 145 |
1 files changed, 56 insertions, 89 deletions
diff --git a/arch/arm/mach-imx/ocotp.c b/arch/arm/mach-imx/ocotp.c index a9df08c1b2..e2f10e12a0 100644 --- a/arch/arm/mach-imx/ocotp.c +++ b/arch/arm/mach-imx/ocotp.c @@ -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); - - index = offset >> 2; - count >>= 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++; + int ret; + + index = reg >> 2; + + 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 = offset >> 2; - count >>= 2; - - if (count > (FUSE_REGS_COUNT - index)) - count = FUSE_REGS_COUNT - index - 1; + index = reg >> 2; - 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++; + 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); } - 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); |