From 579dce92c8bcd13a6424f80ed554b7621784297b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:13:55 +0200 Subject: [PATCH 01/12] ARM: i.MX: iim: Check result of dev_request_mem_region Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index dccaaa9e9..8e37cd713 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -277,6 +277,8 @@ static int imx_iim_probe(struct device_d *dev) void __iomem *base; base = dev_request_mem_region(dev, 0); + if (!base) + return -EBUSY; for (i = 0; i < 8; i++) { imx_iim_add_bank(dev, base, i); From c50bdcf71e9002b31e45c13973c3db477823387e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:36:53 +0200 Subject: [PATCH 02/12] ARM: i.MX: iim: introduce private data struct Instead of duplicating data shared between the banks in a bank specific struct, use a iim struct and a bank struct. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 74 ++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 8e37cd713..16d664907 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -30,16 +30,25 @@ #include #define DRIVERNAME "imx_iim" +#define IIM_NUM_BANKS 8 static int iim_write_enable; static int iim_sense_enable; +struct iim_priv; + +struct iim_bank { + struct cdev cdev; + void __iomem *bankbase; + int bank; + struct iim_priv *iim; +}; + struct iim_priv { struct cdev cdev; void __iomem *base; void __iomem *bankbase; - int bank; - int banksize; + struct iim_bank *bank[IIM_NUM_BANKS]; }; static int do_fuse_sense(void __iomem *reg_base, unsigned int bank, @@ -88,22 +97,23 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags) { ulong size, i; - struct iim_priv *priv = cdev->priv; + struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); + struct iim_priv *iim = bank->iim; - size = min((loff_t)count, priv->banksize - offset); + size = min((loff_t)count, 32 - offset); if (iim_sense_enable) { for (i = 0; i < size; i++) { int row_val; - row_val = do_fuse_sense(priv->base, - priv->bank, offset + i); + row_val = do_fuse_sense(iim->base, + bank->bank, offset + i); if (row_val < 0) return row_val; ((u8 *)buf)[i] = (u8)row_val; } } else { for (i = 0; i < size; i++) - ((u8 *)buf)[i] = ((u8 *)priv->bankbase)[(offset+i)*4]; + ((u8 *)buf)[i] = ((u8 *)bank->bankbase)[(offset+i)*4]; } return size; @@ -173,22 +183,23 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou loff_t offset, ulong flags) { ulong size, i; - struct iim_priv *priv = cdev->priv; + struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); + struct iim_priv *iim = bank->iim; - size = min((loff_t)count, priv->banksize - offset); + size = min((loff_t)count, 32 - offset); if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && iim_write_enable) { for (i = 0; i < size; i++) { int ret; - ret = do_fuse_blow(priv->base, priv->bank, + ret = do_fuse_blow(iim->base, bank->bank, offset + i, ((u8 *)buf)[i]); if (ret < 0) return ret; } } else { for (i = 0; i < size; i++) - ((u8 *)priv->bankbase)[(offset+i)*4] = ((u8 *)buf)[i]; + ((u8 *)bank->bankbase)[(offset+i)*4] = ((u8 *)buf)[i]; } return size; @@ -200,26 +211,25 @@ static struct file_operations imx_iim_ops = { .lseek = dev_lseek_default, }; -static int imx_iim_add_bank(struct device_d *dev, void __iomem *base, int num) +static int imx_iim_add_bank(struct iim_priv *iim, int num) { - struct iim_priv *priv; + struct iim_bank *bank; struct cdev *cdev; - priv = xzalloc(sizeof (*priv)); + bank = xzalloc(sizeof (*bank)); - priv->base = base; - priv->bankbase = priv->base + 0x800 + 0x400 * num; - priv->bank = num; - priv->banksize = 32; - cdev = &priv->cdev; - cdev->dev = dev; + bank->bankbase = iim->base + 0x800 + 0x400 * num; + bank->bank = num; + bank->iim = iim; + cdev = &bank->cdev; cdev->ops = &imx_iim_ops; - cdev->priv = priv; cdev->size = 32; cdev->name = asprintf(DRIVERNAME "_bank%d", num); if (cdev->name == NULL) return -ENOMEM; + iim->bank[num] = bank; + return devfs_create(cdev); } @@ -231,7 +241,7 @@ static int imx_iim_add_bank(struct device_d *dev, void __iomem *base, int num) */ #define MAC_ADDRESS_PROPLEN (3 * sizeof(__be32)) -static void imx_iim_init_dt(struct device_d *dev) +static void imx_iim_init_dt(struct device_d *dev, struct iim_priv *iim) { char mac[6]; const __be32 *prop; @@ -266,25 +276,29 @@ static void imx_iim_init_dt(struct device_d *dev) } } #else -static inline void imx_iim_init_dt(struct device_d *dev) +static inline void imx_iim_init_dt(struct device_d *dev, struct iim_priv *iim) { } #endif static int imx_iim_probe(struct device_d *dev) { - int i; - void __iomem *base; + struct iim_priv *iim; + int i, ret; - base = dev_request_mem_region(dev, 0); - if (!base) + iim = xzalloc(sizeof(*iim)); + + iim->base = dev_request_mem_region(dev, 0); + if (!iim->base) return -EBUSY; - for (i = 0; i < 8; i++) { - imx_iim_add_bank(dev, base, i); + for (i = 0; i < IIM_NUM_BANKS; i++) { + ret = imx_iim_add_bank(iim, i); + if (ret) + return ret; } - imx_iim_init_dt(dev); + imx_iim_init_dt(dev, iim); if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW)) dev_add_param_bool(dev, "permanent_write_enable", From fd56e95b1872eb4a40d86710f1bbf0498330262d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:38:56 +0200 Subject: [PATCH 03/12] ARM: i.MX: iim: Add namespace to functions Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 16d664907..98fd0311c 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -51,7 +51,7 @@ struct iim_priv { struct iim_bank *bank[IIM_NUM_BANKS]; }; -static int do_fuse_sense(void __iomem *reg_base, unsigned int bank, +static int imx_iim_fuse_sense(void __iomem *reg_base, unsigned int bank, unsigned int row) { u8 err, stat; @@ -105,7 +105,7 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, for (i = 0; i < size; i++) { int row_val; - row_val = do_fuse_sense(iim->base, + row_val = imx_iim_fuse_sense(iim->base, bank->bank, offset + i); if (row_val < 0) return row_val; @@ -119,7 +119,7 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, return size; } -static int do_fuse_blow(void __iomem *reg_base, unsigned int bank, +static int imx_iim_fuse_blow(void __iomem *reg_base, unsigned int bank, unsigned int row, u8 value) { int bit, ret = 0; @@ -192,7 +192,7 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou for (i = 0; i < size; i++) { int ret; - ret = do_fuse_blow(iim->base, bank->bank, + ret = imx_iim_fuse_blow(iim->base, bank->bank, offset + i, ((u8 *)buf)[i]); if (ret < 0) return ret; From eec34f2a0820c8e478a357c018a45297f30b702e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:39:35 +0200 Subject: [PATCH 04/12] ARM: i.MX: iim: register iim device With devicetree devicenames start with numbers. Parameters on these devices are not accessible since variables can't start with numbers. Register a logical 'iim' device which makes the permanent_write_enable and explicit_sense_enable parameters accessible again. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 98fd0311c..01cb97e40 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -46,6 +46,7 @@ struct iim_bank { struct iim_priv { struct cdev cdev; + struct device_d dev; void __iomem *base; void __iomem *bankbase; struct iim_bank *bank[IIM_NUM_BANKS]; @@ -288,6 +289,13 @@ static int imx_iim_probe(struct device_d *dev) iim = xzalloc(sizeof(*iim)); + strcpy(iim->dev.name, "iim"); + iim->dev.parent = dev; + iim->dev.id = DEVICE_ID_SINGLE; + ret = register_device(&iim->dev); + if (ret) + return ret; + iim->base = dev_request_mem_region(dev, 0); if (!iim->base) return -EBUSY; @@ -301,10 +309,10 @@ static int imx_iim_probe(struct device_d *dev) imx_iim_init_dt(dev, iim); if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW)) - dev_add_param_bool(dev, "permanent_write_enable", + dev_add_param_bool(&iim->dev, "permanent_write_enable", NULL, NULL, &iim_write_enable, NULL); - dev_add_param_bool(dev, "explicit_sense_enable", + dev_add_param_bool(&iim->dev, "explicit_sense_enable", NULL, NULL, &iim_sense_enable, NULL); return 0; From bb9e3842b2a64a5d1d4e7ca90d6a633b42535ee3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:48:06 +0200 Subject: [PATCH 05/12] ARM: i.MX: iim: pass private data struct to imx_iim_fuse_blow To make all struct members available and to reduce the argument count. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 01cb97e40..0208a38f6 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -120,17 +120,13 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, return size; } -static int imx_iim_fuse_blow(void __iomem *reg_base, unsigned int bank, - unsigned int row, u8 value) +static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned int row, u8 value) { + struct iim_priv *iim = bank->iim; + void __iomem *reg_base = iim->base; int bit, ret = 0; u8 err, stat; - if (bank > 7) { - printf("%s: invalid bank number\n", __func__); - return -EINVAL; - } - if (row > 255) { printf("%s: invalid row index\n", __func__); return -EINVAL; @@ -144,7 +140,7 @@ static int imx_iim_fuse_blow(void __iomem *reg_base, unsigned int bank, writeb(0xaa, reg_base + IIM_PREG_P); /* upper half address register */ - writeb((bank << 3) | (row >> 5), reg_base + IIM_UA); + writeb((bank->bank << 3) | (row >> 5), reg_base + IIM_UA); for (bit = 0; bit < 8; bit++) { if (((value >> bit) & 1) == 0) @@ -167,7 +163,7 @@ static int imx_iim_fuse_blow(void __iomem *reg_base, unsigned int bank, err = readb(reg_base + IIM_ERR); if (err) { printf("%s: bank %u, row %u, bit %d program error " - "(0x%02x)\n", __func__, bank, row, bit, + "(0x%02x)\n", __func__, bank->bank, row, bit, err); ret = -EIO; goto out; @@ -185,7 +181,6 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou { ulong size, i; struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); - struct iim_priv *iim = bank->iim; size = min((loff_t)count, 32 - offset); @@ -193,8 +188,7 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou for (i = 0; i < size; i++) { int ret; - ret = imx_iim_fuse_blow(iim->base, bank->bank, - offset + i, ((u8 *)buf)[i]); + ret = imx_iim_fuse_blow(bank, offset + i, ((u8 *)buf)[i]); if (ret < 0) return ret; } From d3feff68e2f036ccf4d365eb3b6ff4a278d8b7c2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:48:06 +0200 Subject: [PATCH 06/12] ARM: i.MX: iim: pass private data struct to imx_iim_fuse_sense To make all struct members available and to reduce the argument count. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 0208a38f6..f2076eec3 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -52,16 +52,12 @@ struct iim_priv { struct iim_bank *bank[IIM_NUM_BANKS]; }; -static int imx_iim_fuse_sense(void __iomem *reg_base, unsigned int bank, - unsigned int row) +static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) { + struct iim_priv *iim = bank->iim; + void __iomem *reg_base = iim->base; u8 err, stat; - if (bank > 7) { - printf("%s: invalid bank number\n", __func__); - return -EINVAL; - } - if (row > 255) { printf("%s: invalid row index\n", __func__); return -EINVAL; @@ -72,7 +68,7 @@ static int imx_iim_fuse_sense(void __iomem *reg_base, unsigned int bank, writeb(0xfe, reg_base + IIM_ERR); /* upper and lower address halves */ - writeb((bank << 3) | (row >> 5), reg_base + IIM_UA); + writeb((bank->bank << 3) | (row >> 5), reg_base + IIM_UA); writeb((row << 3) & 0xf8, reg_base + IIM_LA); /* start fuse sensing */ @@ -99,15 +95,13 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, { ulong size, i; struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); - struct iim_priv *iim = bank->iim; size = min((loff_t)count, 32 - offset); if (iim_sense_enable) { for (i = 0; i < size; i++) { int row_val; - row_val = imx_iim_fuse_sense(iim->base, - bank->bank, offset + i); + row_val = imx_iim_fuse_sense(bank, offset + i); if (row_val < 0) return row_val; ((u8 *)buf)[i] = (u8)row_val; From c9f2e96c61f850cbc0496986dd34dfe21441b55f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 09:52:41 +0200 Subject: [PATCH 07/12] ARM: i.MX: iim: use dev_* for messages Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index f2076eec3..e1a9f3bfe 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -59,7 +59,7 @@ static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) u8 err, stat; if (row > 255) { - printf("%s: invalid row index\n", __func__); + dev_err(&iim->dev, "%s: invalid row index\n", __func__); return -EINVAL; } @@ -83,7 +83,7 @@ static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) err = readb(reg_base + IIM_ERR); if (err) { - printf("%s: sense error (0x%02x)\n", __func__, err); + dev_err(&iim->dev, "sense error (0x%02x)\n", err); return -EIO; } @@ -122,7 +122,7 @@ static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned int row, u8 value) u8 err, stat; if (row > 255) { - printf("%s: invalid row index\n", __func__); + dev_err(&iim->dev, "%s: invalid row index\n", __func__); return -EINVAL; } @@ -156,8 +156,8 @@ static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned int row, u8 value) err = readb(reg_base + IIM_ERR); if (err) { - printf("%s: bank %u, row %u, bit %d program error " - "(0x%02x)\n", __func__, bank->bank, row, bit, + dev_err(&iim->dev, "bank %u, row %u, bit %d program error " + "(0x%02x)\n", bank->bank, row, bit, err); ret = -EIO; goto out; From 310c20d927142abe90e5857032ae5edfa3a025bb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 10:08:39 +0200 Subject: [PATCH 08/12] ARM: i.MX: iim: move static variables into driver struct Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index e1a9f3bfe..081b9b108 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -32,9 +32,6 @@ #define DRIVERNAME "imx_iim" #define IIM_NUM_BANKS 8 -static int iim_write_enable; -static int iim_sense_enable; - struct iim_priv; struct iim_bank { @@ -50,6 +47,8 @@ struct iim_priv { void __iomem *base; void __iomem *bankbase; struct iim_bank *bank[IIM_NUM_BANKS]; + int write_enable; + int sense_enable; }; static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) @@ -97,7 +96,7 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); size = min((loff_t)count, 32 - offset); - if (iim_sense_enable) { + if (bank->iim->sense_enable) { for (i = 0; i < size; i++) { int row_val; @@ -178,7 +177,7 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou size = min((loff_t)count, 32 - offset); - if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && iim_write_enable) { + if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && bank->iim->write_enable) { for (i = 0; i < size; i++) { int ret; @@ -298,10 +297,10 @@ static int imx_iim_probe(struct device_d *dev) if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW)) dev_add_param_bool(&iim->dev, "permanent_write_enable", - NULL, NULL, &iim_write_enable, NULL); + NULL, NULL, &iim->write_enable, NULL); dev_add_param_bool(&iim->dev, "explicit_sense_enable", - NULL, NULL, &iim_sense_enable, NULL); + NULL, NULL, &iim->sense_enable, NULL); return 0; } From e315ea6f7d1af687066506c01b8928d488f3ae98 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 10:17:14 +0200 Subject: [PATCH 09/12] ARM: i.MX: iim: don't make detour over cdev API imx_iim_read is a iim internal function, so access the internal functions rather than using the cdev API. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 081b9b108..4a2c0ed40 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -51,6 +51,8 @@ struct iim_priv { int sense_enable; }; +static struct iim_priv *imx_iim; + static int imx_iim_fuse_sense(struct iim_bank *bank, unsigned int row) { struct iim_priv *iim = bank->iim; @@ -113,6 +115,22 @@ static ssize_t imx_iim_cdev_read(struct cdev *cdev, void *buf, size_t count, return size; } +int imx_iim_read(unsigned int banknum, int offset, void *buf, int count) +{ + struct iim_priv *iim = imx_iim; + struct iim_bank *bank; + + if (!imx_iim) + return -ENODEV; + + if (banknum > IIM_NUM_BANKS) + return -EINVAL; + + bank = iim->bank[banknum]; + + return imx_iim_cdev_read(&bank->cdev, buf, count, offset, 0); +} + static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned int row, u8 value) { struct iim_priv *iim = bank->iim; @@ -274,8 +292,13 @@ static int imx_iim_probe(struct device_d *dev) struct iim_priv *iim; int i, ret; + if (imx_iim) + return -EBUSY; + iim = xzalloc(sizeof(*iim)); + imx_iim = iim; + strcpy(iim->dev.name, "iim"); iim->dev.parent = dev; iim->dev.id = DEVICE_ID_SINGLE; @@ -326,21 +349,3 @@ static int imx_iim_init(void) return 0; } coredevice_initcall(imx_iim_init); - -int imx_iim_read(unsigned int bank, int offset, void *buf, int count) -{ - struct cdev *cdev; - char *name = asprintf(DRIVERNAME "_bank%d", bank); - int ret; - - cdev = cdev_open(name, O_RDONLY); - if (!cdev) - return -ENODEV; - - ret = cdev_read(cdev, buf, count, offset, 0); - - cdev_close(cdev); - free(name); - - return ret; -} From f321ec1699d7b0cdc145bae69cd6ccfabec95e2c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 12:23:41 +0200 Subject: [PATCH 10/12] ARM: i.MX: iim: make fuse blowing work on i.MX5 The i.MX5 iim has an additional bit in the CCM module which enables the supply. Add support for it. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 4a2c0ed40..f2c8c44be 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -28,6 +28,9 @@ #include #include +#include +#include +#include #define DRIVERNAME "imx_iim" #define IIM_NUM_BANKS 8 @@ -49,6 +52,11 @@ struct iim_priv { struct iim_bank *bank[IIM_NUM_BANKS]; int write_enable; int sense_enable; + void (*supply)(int enable); +}; + +struct imx_iim_drvdata { + void (*supply)(int enable); }; static struct iim_priv *imx_iim; @@ -192,10 +200,14 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou { ulong size, i; struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); + struct iim_priv *iim = bank->iim; size = min((loff_t)count, 32 - offset); if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && bank->iim->write_enable) { + if (iim->supply) + iim->supply(1); + for (i = 0; i < size; i++) { int ret; @@ -203,6 +215,10 @@ static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t cou if (ret < 0) return ret; } + + if (iim->supply) + iim->supply(0); + } else { for (i = 0; i < size; i++) ((u8 *)bank->bankbase)[(offset+i)*4] = ((u8 *)buf)[i]; @@ -291,12 +307,18 @@ static int imx_iim_probe(struct device_d *dev) { struct iim_priv *iim; int i, ret; + struct imx_iim_drvdata *drvdata = NULL; if (imx_iim) return -EBUSY; iim = xzalloc(sizeof(*iim)); + dev_get_drvdata(dev, (unsigned long *)&drvdata); + + if (drvdata && drvdata->supply) + iim->supply = drvdata->supply; + imx_iim = iim; strcpy(iim->dev.name, "iim"); @@ -328,9 +350,51 @@ static int imx_iim_probe(struct device_d *dev) return 0; } +static void imx5_iim_supply(void __iomem *ccm_base, int enable) +{ + uint32_t val; + + val = readl(ccm_base + MX5_CCM_CGPR); + + if (enable) + val |= 1 << 4; + else + val &= ~(1 << 4); + + writel(val, ccm_base + MX5_CCM_CGPR); +} + +static void imx51_iim_supply(int enable) +{ + imx5_iim_supply((void __iomem *)MX51_CCM_BASE_ADDR, enable); +} + +static void imx53_iim_supply(int enable) +{ + imx5_iim_supply((void __iomem *)MX53_CCM_BASE_ADDR, enable); +} + +static struct imx_iim_drvdata imx27_drvdata = { +}; + +static struct imx_iim_drvdata imx51_drvdata = { + .supply = imx51_iim_supply, +}; + +static struct imx_iim_drvdata imx53_drvdata = { + .supply = imx53_iim_supply, +}; + static __maybe_unused struct of_device_id imx_iim_dt_ids[] = { { + .compatible = "fsl,imx53-iim", + .data = (unsigned long)&imx53_drvdata, + }, { + .compatible = "fsl,imx51-iim", + .data = (unsigned long)&imx51_drvdata, + }, { .compatible = "fsl,imx27-iim", + .data = (unsigned long)&imx27_drvdata, }, { /* sentinel */ } From cf32bf77debf3c32ef3a38a9cc4f49b1424571e7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 12:27:18 +0200 Subject: [PATCH 11/12] ARM: i.MX: iim: provide a MAC address convenience variable Allow to read/write the registered MAC addresses in the iim module directly via a device parameter. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 56 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index f2c8c44be..294f41c12 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -257,6 +257,57 @@ static int imx_iim_add_bank(struct iim_priv *iim, int num) #if IS_ENABLED(CONFIG_OFDEVICE) +#define MAC_BYTES 6 + +struct imx_iim_mac { + struct iim_bank *bank; + int offset; + u8 ethaddr[MAC_BYTES]; +}; + +static int imx_iim_get_mac(struct param_d *param, void *priv) +{ + struct imx_iim_mac *iimmac = priv; + struct iim_bank *bank = iimmac->bank; + int ret; + + ret = imx_iim_cdev_read(&bank->cdev, iimmac->ethaddr, MAC_BYTES, iimmac->offset, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int imx_iim_set_mac(struct param_d *param, void *priv) +{ + struct imx_iim_mac *iimmac = priv; + struct iim_bank *bank = iimmac->bank; + int ret; + + ret = imx_iim_cdev_write(&bank->cdev, iimmac->ethaddr, MAC_BYTES, iimmac->offset, 0); + if (ret < 0) + return ret; + + return 0; +} + +static void imx_iim_add_mac_param(struct iim_priv *iim, int macnum, int bank, int offset) +{ + struct imx_iim_mac *iimmac; + char *name; + + iimmac = xzalloc(sizeof(*iimmac)); + iimmac->offset = offset; + iimmac->bank = iim->bank[bank]; + + name = asprintf("ethaddr%d", macnum); + + dev_add_param_mac(&iim->dev, name, imx_iim_set_mac, + imx_iim_get_mac, iimmac->ethaddr, iimmac); + + free(name); +} + /* * a single MAC address reference has the form * <&phandle iim-bank-no offset>, so three cells @@ -268,7 +319,7 @@ static void imx_iim_init_dt(struct device_d *dev, struct iim_priv *iim) char mac[6]; const __be32 *prop; struct device_node *node = dev->device_node; - int len, ret; + int len, ret, macnum = 0; if (!node) return; @@ -294,6 +345,9 @@ static void imx_iim_init_dt(struct device_d *dev, struct iim_priv *iim) dev_err(dev, "cannot read: %s\n", strerror(-ret)); } + imx_iim_add_mac_param(iim, macnum, bank, offset); + macnum++; + len -= MAC_ADDRESS_PROPLEN; } } From bb662e2474cbc41419c1cc2c024a07ea265e59f7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 16 May 2014 13:36:27 +0200 Subject: [PATCH 12/12] ARM: i.MX: iim: Add regulator support The voltage for programming the fuses is external to the SoC and on some boards this is controllable with a regulator, so add regulator support to the iim driver. Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/iim.c | 60 ++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c index 294f41c12..16ba67884 100644 --- a/arch/arm/mach-imx/iim.c +++ b/arch/arm/mach-imx/iim.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -53,6 +55,7 @@ struct iim_priv { int write_enable; int sense_enable; void (*supply)(int enable); + struct regulator *fuse_supply; }; struct imx_iim_drvdata { @@ -139,7 +142,7 @@ int imx_iim_read(unsigned int banknum, int offset, void *buf, int count) return imx_iim_cdev_read(&bank->cdev, buf, count, offset, 0); } -static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned int row, u8 value) +static int imx_iim_fuse_blow_one(struct iim_bank *bank, unsigned int row, u8 value) { struct iim_priv *iim = bank->iim; void __iomem *reg_base = iim->base; @@ -195,30 +198,53 @@ out: return ret; } +static int imx_iim_fuse_blow(struct iim_bank *bank, unsigned offset, const void *buf, + unsigned size) +{ + struct iim_priv *iim = bank->iim; + int ret, i; + + if (IS_ERR(iim->fuse_supply)) { + iim->fuse_supply = regulator_get(iim->dev.parent, "vdd-fuse"); + dev_info(iim->dev.parent, "regul: %p\n", iim->fuse_supply); + if (IS_ERR(iim->fuse_supply)) + return PTR_ERR(iim->fuse_supply); + } + + ret = regulator_enable(iim->fuse_supply); + if (ret < 0) + return ret; + + 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; + } + + if (iim->supply) + iim->supply(0); + + ret = 0; + +err_out: + regulator_disable(iim->fuse_supply); + + return ret; +} + static ssize_t imx_iim_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags) { ulong size, i; struct iim_bank *bank = container_of(cdev, struct iim_bank, cdev); - struct iim_priv *iim = bank->iim; size = min((loff_t)count, 32 - offset); if (IS_ENABLED(CONFIG_IMX_IIM_FUSE_BLOW) && bank->iim->write_enable) { - if (iim->supply) - iim->supply(1); - - for (i = 0; i < size; i++) { - int ret; - - ret = imx_iim_fuse_blow(bank, offset + i, ((u8 *)buf)[i]); - if (ret < 0) - return ret; - } - - if (iim->supply) - iim->supply(0); - + 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]; @@ -382,6 +408,8 @@ static int imx_iim_probe(struct device_d *dev) if (ret) return ret; + iim->fuse_supply = ERR_PTR(-ENODEV); + iim->base = dev_request_mem_region(dev, 0); if (!iim->base) return -EBUSY;