diff options
author | Terry Lv <r65388@freescale.com> | 2011-01-27 01:52:22 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-07-20 13:10:38 +0800 |
commit | fc95b9b512dcdfab7cf4db3f34573d00121645ae (patch) | |
tree | 5b3b3c84951fbaa52d019a45472a4c0593924190 /drivers/char | |
parent | bdf892704526d3a8ae19c05d4f00de0ed111c580 (diff) |
ENGR00138532: mxc_iim: let mxc_iim work with dd and echo
mxc_iim: let mxc_iim work with dd and echo.
Signed-off-by: Terry Lv <r65388@freescale.com>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/mxc_iim.c | 89 |
1 files changed, 56 insertions, 33 deletions
diff --git a/drivers/char/mxc_iim.c b/drivers/char/mxc_iim.c index 44b1de3d1046..fc42afca2dc4 100644 --- a/drivers/char/mxc_iim.c +++ b/drivers/char/mxc_iim.c @@ -97,12 +97,12 @@ static inline void fuse_op_start(void) dump_reg(); #endif - /* Generate interrupt */ - __raw_writel(0x3, &(iim_reg_base->statm)); - __raw_writel(0xfe, &(iim_reg_base->emask)); /* Clear the status bits and error bits */ __raw_writel(0x3, &(iim_reg_base->stat)); __raw_writel(0xfe, &(iim_reg_base->err)); + /* Generate interrupt */ + __raw_writel(0x3, &(iim_reg_base->statm)); + __raw_writel(0xfe, &(iim_reg_base->emask)); dev_dbg(iim_data->dev, "<= %s\n", __func__); } @@ -211,8 +211,9 @@ static void fuse_blow_row(s32 bank, s32 row, s32 value) for (i = 0; i < 8; i++) { if (((value >> i) & 0x1) == 0) continue; - if (fuse_blow_bit(bank, row, i) != 0) { - dev_dbg(iim_data->dev, "fuse_blow_bit(bank: %d, row: %d, " + if (fuse_blow_bit(bank, row, i) != 0) { + dev_dbg(iim_data->dev, + "fuse_blow_bit(bank: %d, row: %d, " "bit: %d failed\n", bank, row, i); } @@ -259,6 +260,7 @@ static irqreturn_t mxc_iim_irq(int irq, void *dev_id) "at addr=0x%x: 0x%x\n", (u32)&(iim_reg_base->err), error); } + __raw_writel(0x3, &(iim_reg_base->stat)); rtn = 0; goto out; } @@ -373,24 +375,16 @@ static ssize_t mxc_iim_write(struct file *filp, const char __user *buf, ulong fuse_val; s8 row; s8 *tmp_buf = NULL; + loff_t file_pos = *f_pos; ssize_t retval = 0; dev_dbg(iim_data->dev, "=> %s\n", __func__); - dev_dbg(iim_data->dev, "count: %d f_pos: %lld\n", count, *f_pos); - - if (*f_pos & 0x3) - goto invald_arg_out; - if (*f_pos < iim_data->bank_start || - *f_pos > iim_data->bank_end) { - dev_dbg(iim_data->dev, "bank_start: 0x%08x, bank_end: 0x%08x\n", - iim_data->bank_start, iim_data->bank_end); - goto invald_arg_out; - } + dev_dbg(iim_data->dev, "count: %d f_pos: %lld\n", count, file_pos); tmp_buf = kmalloc(count + 1, GFP_KERNEL); if (unlikely(!tmp_buf)) { retval = -ENOMEM; - goto out; + goto out; } memset(tmp_buf, 0, count + 1); if (copy_from_user(tmp_buf, buf, count)) { @@ -398,19 +392,55 @@ static ssize_t mxc_iim_write(struct file *filp, const char __user *buf, goto out; } - bank = (*f_pos - iim_data->bank_start) >> 10; - row = ((*f_pos - iim_data->bank_start) & 0x3ff) >> 2; - if (strict_strtoul(tmp_buf, 16, &fuse_val)) { - dev_dbg(iim_data->dev, "Invalid value parameter: %s\n", - tmp_buf); - goto invald_arg_out; + if (count > 1 && 0 == file_pos) { + /* Check if file_pos and fuse val are in tmp_buf */ + if (sscanf(tmp_buf, "%x %x", + (s32 *)&file_pos, (s32 *)&fuse_val) < 0) { + dev_info(iim_data->dev, + "Invalid input string: %s\n", tmp_buf); + retval = -EINVAL; + goto out; + } + dev_dbg(iim_data->dev, + "file_pos: 0x%08x, fuse_val: 0x%08x\n", + (s32)file_pos, (s32)fuse_val); + } else if (1 == count) + fuse_val = tmp_buf[0]; + else { + dev_info(iim_data->dev, + "Invalid input: %s, count: %d, file pos: %d\n", + tmp_buf, count, (s32)file_pos); + retval = -EINVAL; + goto out; } - if (unlikely(fuse_val > 0xff)) { - dev_dbg(iim_data->dev, "Invalid value for fuse: %d\n", - (unsigned int)fuse_val); - goto invald_arg_out; + + if (fuse_val > 0xff) { + dev_info(iim_data->dev, + "Invalid blow value: 0x%08x\n", (s32)fuse_val); + retval = -EINVAL; + goto out; + } + + if (file_pos & 0x3) { + dev_info(iim_data->dev, "file pos is not 4-byte aligned!\n"); + retval = -EINVAL; + goto out; + } + + if (file_pos < iim_data->bank_start || + file_pos > iim_data->bank_end) { + dev_dbg(iim_data->dev, + "bank_start: 0x%08x, bank_end: 0x%08x\n", + iim_data->bank_start, iim_data->bank_end); + dev_info(iim_data->dev, + "file pos out of range: 0x%08x\n", file_pos); + retval = -EINVAL; + goto out; } + bank = (file_pos - iim_data->bank_start) >> 10; + row = ((file_pos - iim_data->bank_start) & 0x3ff) >> 2; + dev_dbg(iim_data->dev, "Blowing fuse at bank:%d row:%d value:%d\n", bank, row, (int)fuse_val); mutex_lock(&iim_data->mutex); @@ -426,11 +456,6 @@ out: kfree(tmp_buf); dev_dbg(iim_data->dev, "<= %s\n", __func__); return retval; -invald_arg_out: - if (tmp_buf) - kfree(tmp_buf); - retval = -EINVAL; - return retval; } /*! @@ -471,8 +496,6 @@ static int mxc_iim_mmap(struct file *file, struct vm_area_struct *vma) */ static int mxc_iim_open(struct inode *inode, struct file *filp) { - int ret; - dev_dbg(iim_data->dev, "=> %s\n", __func__); dev_dbg(iim_data->dev, "iim_data addr: 0x%08x\n", (u32)iim_data); |