diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-08 08:27:03 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-08 08:27:03 +0100 |
commit | 7482ab4de107d6fe3136f741ad6a3d423661f125 (patch) | |
tree | 06bf853ab81348f0a4028fb3c41978b61dfb03f6 /arch | |
parent | c0735348802c29cc46db3758b5e477f2bc8ff058 (diff) | |
parent | 2ee6bb35043de0bc994da4bf3f0139280229c3bd (diff) | |
download | barebox-7482ab4de107d6fe3136f741ad6a3d423661f125.tar.gz barebox-7482ab4de107d6fe3136f741ad6a3d423661f125.tar.xz |
Merge branch 'for-next/regmap'
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-imx/iim.c | 121 | ||||
-rw-r--r-- | arch/arm/mach-imx/ocotp.c | 227 |
2 files changed, 169 insertions, 179 deletions
diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index c5751fe111..c16a6c6879 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <of.h> #include <io.h> +#include <regmap.h> #include <regulator.h> #include <linux/err.h> @@ -40,14 +41,14 @@ struct iim_priv; struct iim_bank { - struct cdev cdev; + struct regmap *map; void __iomem *bankbase; int bank; struct iim_priv *iim; + struct regmap_config map_config; }; struct iim_priv { - struct cdev cdev; struct device_d dev; void __iomem *base; void __iomem *bankbase; @@ -102,34 +103,28 @@ static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) return readb(reg_base + IIM_SDAT); } -static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, - loff_t offset, ulong flags) +static int imx_iim_reg_read(void *ctx, unsigned int reg, unsigned int *val) { - ulong size, i; - struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); + struct iim_bank *bank = ctx; - size = min((loff_t)count, 32 - offset); if (bank->iim->sense_enable) { - for (i = 0; i < size; i++) { - int row_val; - - row_val = imx_iim_fuse_sense(bank, offset + i); - if (row_val < 0) - return row_val; - ((u8 *)buf)[i] = (u8)row_val; - } + int row_val; + row_val = imx_iim_fuse_sense(bank, reg); + if (row_val < 0) + return row_val; + *val = (u8)row_val; } else { - for (i = 0; i < size; i++) - ((u8 *)buf)[i] = ((u8 *)bank->bankbase)[(offset+i)*4]; + *val = readl(bank->bankbase + reg * 4); } - return size; + return 0; } int imx_iim_read(unsigned int banknum, int offset, void *buf, int count) { struct iim_priv *iim = imx_iim; struct iim_bank *bank; + int ret; if (!imx_iim) return -ENODEV; @@ -139,7 +134,11 @@ int imx_iim_read(unsigned int banknum, int offset, void *buf, int count) bank = iim->bank[banknum]; - return imx_iim_cdev_read(&bank->cdev, buf, count, offset, 0); + ret = regmap_bulk_read(bank->map, offset, buf, count); + if (ret) + return ret; + + return count; } static int imx_iim_fuse_blow_one(struct iim_bank *bank, unsigned int row, u8 value) @@ -198,11 +197,10 @@ out: return ret; } -static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned offset, const void *buf, - unsigned size) +static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned offset, unsigned val) { struct iim_priv *iim = bank->iim; - int ret, i; + int ret; if (IS_ERR(iim->fuse_supply)) { iim->fuse_supply = regulator_get(iim->dev.parent, "vdd-fuse"); @@ -218,11 +216,9 @@ static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned offset, const void if (iim->supply) iim->supply(1); - for (i = 0; i < size; i++) { - ret = imx_iim_fuse_blow_one(bank, offset + i, ((u8 *)buf)[i]); - if (ret < 0) - goto err_out; - } + ret = imx_iim_fuse_blow_one(bank, offset, val); + if (ret < 0) + goto err_out; if (iim->supply) iim->supply(0); @@ -235,52 +231,60 @@ err_out: return ret; } -static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t count, - loff_t offset, ulong flags) +static ssize_t imx_iim_reg_write(void *ctx, unsigned int reg, unsigned int val) { - ulong size, i; - struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); + struct iim_bank *bank = ctx; - size = min((loff_t)count, 32 - offset); - - if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && bank->iim->write_enable) { - return imx_iim_fuse_blow(bank, offset, buf, size); - } else { - for (i = 0; i < size; i++) - ((u8 *)bank->bankbase)[(offset+i)*4] = ((u8 *)buf)[i]; - } + if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && bank->iim->write_enable) + return imx_iim_fuse_blow(bank, reg, val); + else + writel(val, bank->bankbase + reg * 4); - return size; + return 0; } -static struct file_operations imx_iim_ops = { - .read = imx_iim_cdev_read, - .write = imx_iim_cdev_write, - .lseek = dev_lseek_default, +static struct regmap_bus imx_iim_regmap_bus = { + .reg_write = imx_iim_reg_write, + .reg_read = imx_iim_reg_read, }; static int imx_iim_add_bank(struct iim_priv *iim, int num) { struct iim_bank *bank; - struct cdev *cdev; + char *name; + int ret; bank = xzalloc(sizeof (*bank)); bank->bankbase = iim->base + 0x800 + 0x400 * num; bank->bank = num; bank->iim = iim; - cdev = &bank->cdev; - cdev->ops = &imx_iim_ops; - cdev->size = 32; - cdev->name = asprintf(DRIVERNAME "_bank%d", num); - if (cdev->name == NULL) - return -ENOMEM; iim->bank[num] = bank; - return devfs_create(cdev); + bank->map_config.reg_bits = 8, + bank->map_config.val_bits = 8, + bank->map_config.reg_stride = 1, + bank->map_config.max_register = 31, + bank->map_config.name = xasprintf("bank%d", num); + + bank->map = regmap_init(&iim->dev, &imx_iim_regmap_bus, bank, &bank->map_config); + if (IS_ERR(bank->map)) + return PTR_ERR(bank->map); + + name = xasprintf(DRIVERNAME "_bank%d", num); + + ret = regmap_register_cdev(bank->map, name); + + free(name); + + if (ret) + return ret; + + return 0; } + #if IS_ENABLED(CONFIG_OFDEVICE) #define MAC_BYTES 6 @@ -297,7 +301,7 @@ static int imx_iim_get_mac(struct param_d *param, void *priv) struct iim_bank *bank = iimmac->bank; int ret; - ret = imx_iim_cdev_read(&bank->cdev, iimmac->ethaddr, MAC_BYTES, iimmac->offset, 0); + ret = regmap_bulk_read(bank->map, iimmac->offset, iimmac->ethaddr, MAC_BYTES); if (ret < 0) return ret; @@ -310,7 +314,7 @@ static int imx_iim_set_mac(struct param_d *param, void *priv) struct iim_bank *bank = iimmac->bank; int ret; - ret = imx_iim_cdev_write(&bank->cdev, iimmac->ethaddr, MAC_BYTES, iimmac->offset, 0); + ret = regmap_bulk_write(bank->map, iimmac->offset, iimmac->ethaddr, MAC_BYTES); if (ret < 0) return ret; @@ -364,12 +368,11 @@ static void imx_iim_init_dt(struct device_d *dev, struct iim_priv *iim) bank = be32_to_cpup(prop++); offset = be32_to_cpup(prop++); - ret = imx_iim_read(bank, offset, mac, 6); - if (ret == 6) { - of_eth_register_ethaddr(rnode, mac); - } else { + ret = regmap_bulk_read(iim->bank[bank]->map, offset, mac, MAC_BYTES); + if (ret) dev_err(dev, "cannot read: %s\n", strerror(-ret)); - } + else + of_eth_register_ethaddr(rnode, mac); if (IS_ENABLED(CONFIG_NET)) imx_iim_add_mac_param(iim, macnum, bank, offset); diff --git a/arch/arm/mach-imx/ocotp.c b/arch/arm/mach-imx/ocotp.c index c99a003bb0..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> /* @@ -35,6 +36,7 @@ #define MAC_ADDRESS_PROPLEN (2 * sizeof(__be32)) /* OCOTP Registers offsets */ +#define OCOTP_CTRL 0x00 #define OCOTP_CTRL_SET 0x04 #define OCOTP_CTRL_CLR 0x08 #define OCOTP_TIMING 0x10 @@ -70,14 +72,19 @@ #define MAC_OFFSET (0x22 * 4) #define MAC_BYTES 8 +struct imx_ocotp_data { + int num_regs; +}; + 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) @@ -101,18 +108,13 @@ static int imx6_ocotp_set_timing(struct ocotp_priv *priv) return 0; } -static int imx6_ocotp_wait_busy(u32 flags, struct ocotp_priv *priv) +static int imx6_ocotp_wait_busy(struct ocotp_priv *priv, u32 flags) { uint64_t start = get_time_ns(); - while ((OCOTP_CTRL_BUSY | OCOTP_CTRL_ERROR | flags) & - readl(priv->base)) { - if (is_timeout(start, MSECOND)) { - /* Clear ERROR bit */ - writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR); + while (readl(priv->base + OCOTP_CTRL) & (OCOTP_CTRL_BUSY | flags)) + if (is_timeout(start, MSECOND)) return -ETIMEDOUT; - } - } return 0; } @@ -125,103 +127,94 @@ static int imx6_ocotp_prepare(struct ocotp_priv *priv) if (ret) return ret; - ret = imx6_ocotp_wait_busy(0, priv); + ret = imx6_ocotp_wait_busy(priv, 0); if (ret) return ret; return 0; } -static int fuse_read_addr(u32 addr, u32 *pdata, struct ocotp_priv *priv) +static int fuse_read_addr(struct ocotp_priv *priv, u32 addr, u32 *pdata) { u32 ctrl_reg; int ret; - ctrl_reg = readl(priv->base); + writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR); + + ctrl_reg = readl(priv->base + OCOTP_CTRL); ctrl_reg &= ~OCOTP_CTRL_ADDR_MASK; ctrl_reg &= ~OCOTP_CTRL_WR_UNLOCK_MASK; ctrl_reg |= BF(addr, OCOTP_CTRL_ADDR); - writel(ctrl_reg, priv->base); + writel(ctrl_reg, priv->base + OCOTP_CTRL); writel(OCOTP_READ_CTRL_READ_FUSE, priv->base + OCOTP_READ_CTRL); - ret = imx6_ocotp_wait_busy(0, priv); + ret = imx6_ocotp_wait_busy(priv, 0); if (ret) return ret; - *pdata = readl(priv->base + OCOTP_READ_FUSE_DATA); + if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR) + *pdata = 0xbadabada; + else + *pdata = readl(priv->base + OCOTP_READ_FUSE_DATA); return 0; } -int imx6_ocotp_read_one_u32(u32 index, u32 *pdata, struct ocotp_priv *priv) +int imx6_ocotp_read_one_u32(struct ocotp_priv *priv, u32 index, u32 *pdata) { int ret; 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(index, pdata, priv); + 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; } - if (readl(priv->base) & OCOTP_CTRL_ERROR) { - dev_err(priv->cdev.dev, "bad read status at fuse 0x%08x\n", index); - return -EFAULT; - } - 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(i, buf, priv); - 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(u32 addr, u32 value, struct ocotp_priv *priv) +static int fuse_blow_addr(struct ocotp_priv *priv, u32 addr, u32 value) { u32 ctrl_reg; int ret; + writel(OCOTP_CTRL_ERROR, priv->base + OCOTP_CTRL_CLR); + /* Control register */ - ctrl_reg = readl(priv->base); + ctrl_reg = readl(priv->base + OCOTP_CTRL); ctrl_reg &= ~OCOTP_CTRL_ADDR_MASK; ctrl_reg |= BF(addr, OCOTP_CTRL_ADDR); ctrl_reg |= BF(OCOTP_CTRL_WR_UNLOCK_KEY, OCOTP_CTRL_WR_UNLOCK); - writel(ctrl_reg, priv->base); + writel(ctrl_reg, priv->base + OCOTP_CTRL); writel(value, priv->base + OCOTP_DATA); - ret = imx6_ocotp_wait_busy(0, priv); + ret = imx6_ocotp_wait_busy(priv, 0); if (ret) return ret; @@ -232,94 +225,63 @@ static int fuse_blow_addr(u32 addr, u32 value, struct ocotp_priv *priv) 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); - return imx6_ocotp_wait_busy(OCOTP_CTRL_RELOAD_SHADOWS, priv); + return imx6_ocotp_wait_busy(priv, OCOTP_CTRL_RELOAD_SHADOWS); } -int imx6_ocotp_blow_one_u32(u32 index, u32 data, u32 *pfused_value, - struct ocotp_priv *priv) +int imx6_ocotp_blow_one_u32(struct ocotp_priv *priv, u32 index, u32 data, + u32 *pfused_value) { int ret; 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(index, data, priv); + 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_ERROR) { - dev_err(priv->cdev.dev, "bad write status\n"); + if (readl(priv->base + OCOTP_CTRL) & OCOTP_CTRL_ERROR) { + dev_err(&priv->dev, "bad write status\n"); return -EFAULT; } - ret = imx6_ocotp_read_one_u32(index, pfused_value, priv); + ret = imx6_ocotp_read_one_u32(priv, index, pfused_value); 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; - - data = buf; - - for (i = index; i < (index + count); i++) { - if (priv->permanent_write_enable) { - ret = imx6_ocotp_blow_one_u32(i, *data, - &pfuse, priv); - if (ret < 0) { - goto out; - } - } else { - writel(*data, priv->base + 0x400 + i * 0x10); - } + index = reg >> 2; - 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) @@ -373,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]; @@ -393,19 +357,28 @@ 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; + + ret = dev_get_drvdata(dev, (const void **)&data); + if (ret) + return ret; base = dev_request_mem_region(dev, 0); if (IS_ERR(base)) @@ -420,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 = 192; - 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); @@ -450,11 +424,24 @@ static int imx_ocotp_probe(struct device_d *dev) return 0; } +static struct imx_ocotp_data imx6q_ocotp_data = { + .num_regs = 512, +}; + +static struct imx_ocotp_data imx6sl_ocotp_data = { + .num_regs = 256, +}; + static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = { { .compatible = "fsl,imx6q-ocotp", + .data = &imx6q_ocotp_data, }, { .compatible = "fsl,imx6sx-ocotp", + .data = &imx6q_ocotp_data, + }, { + .compatible = "fsl,imx6sl-ocotp", + .data = &imx6sl_ocotp_data, }, { /* sentinel */ } |