static ssize_t qfprom_read_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	u32 *p_buf = NULL;
	int ret = 0;

	if(!qfprom_address){
		printk("%s: qfprom address is NULL\n", __func__);
		return -EINVAL;
	}

	p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
	if(!p_buf){
		printk("%s : buffer memory alloc fail\n", __func__);
		ret = -ENOMEM;
	}
	ret = qfuse_read_single_row(qfprom_address, 0, p_buf);
	qfprom_address = 0;
	if(ret == 0){
		qfprom_lsb_value = p_buf[0];
		qfprom_msb_value = p_buf[1];
		kfree(p_buf);
		return count;
	}
	else if(ret < 0)
		printk("%s: scm call fail\n", __func__);
	else
		printk("%s: qfprom write status error = %x\n", __func__, ret);

	kfree(p_buf);

	return -EINVAL;
}
/* this api handle diag command(fusing check command) from ATD 
 * if fusing value 0 ==> is not fused
 * if fusing value 1 ==> fused (secure boot enable, jtag disable, oem config, hw secondary key, RW permission)
 */
static ssize_t qfusing_show(struct device* dev, struct device_attribute* attr, char* buf)
{
	int fusing=0;
	int i,ret;
	u32 key_status=0;
	u32* p_buf=NULL;

	if(fusing_flag==0) {
		key_status = qfprom_secondary_hwkey_status();
		if((key_status&SEC_HW_KEY_BLOWN)!=SEC_HW_KEY_BLOWN) {
			printk("%s: hw key is not blown\n",__func__);
			goto err_mem;
		} else {
			msleep(10);
			printk("%s:secondary HW key check complete!!!!!\n",__func__);
			p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
			if(!p_buf) {
				printk("%s: memory alloc fail\n",__func__);
				goto err_mem;
			}
			for(i=0;i<ARRAY_SIZE(blow_data);i++) {
				if(blow_data[i].qfprom_addr==QFPROM_CHECK_HW_KEY) 
					continue;
			
				ret = qfuse_read_single_row(blow_data[i].qfprom_addr,0,p_buf);
				if(ret!=0) {
					printk("%s: qfprom 0x%x read fail\n",__func__,blow_data[i].qfprom_addr);
					goto err;
				}
				else {
					if(((p_buf[0]&blow_data[i].lsb_data)==blow_data[i].lsb_data) &&
						((p_buf[1]&blow_data[i].msb_data)==blow_data[i].msb_data)) {
						printk("%s: 0x%x chekc complete\n",__func__,blow_data[i].qfprom_addr);
						continue;
					}
					else {
						printk("%s: fusing value is not match\n",__func__);
						goto err;
					}
					msleep(10);
				}
			}
			fusing=1;
		}
	} 
	else {
		if(fusing_flag==FUSING_COMPLETED_STATE)
			fusing=1;
	}
err:
	kfree(p_buf);
err_mem:
	return sprintf(buf,"%x\n",fusing);
}
u32 qfprom_verification_blow_data(void)
{
	int i, ret;
	u32 key_status = 0;
	u32 *p_buf = NULL;
	u32 fusing_verification=0;

	
	p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
	if(!p_buf) {
		printk("%s: memory alloc fail\n", __func__);
		goto err_mem;
	}
	for(i=0;i<ARRAY_SIZE(blow_data);i++) {
		if(blow_data[i].qfprom_addr == QFPROM_CHECK_HW_KEY)
		{
			key_status = qfprom_secondary_hwkey_status();
			if((key_status&SEC_KEY_DERIVATION_BLOWN)  == SEC_KEY_DERIVATION_BLOWN)
			{
				fusing_verification |= (0x1<<i);
				printk("%s: hw key is blown\n", __func__);
			}
			printk("%s:secondary HW key check complete!!!!!\n", __func__);
			continue;
		}
		msleep(10);
		ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf);
		if(ret != 0) {
			printk("%s: qfprom 0x%x read fail\n", __func__, blow_data[i].qfprom_addr);
			continue;
		} else {
			if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) &&
				((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) {
				printk("%s: 0x%x check complete\n", __func__, blow_data[i].qfprom_addr);
				fusing_verification |= (0x1<<i);
				printk("%s: %d fusing_verification\n",__func__,fusing_verification);
			} else {
				printk("%s: 0x%x fusing value is not match\n", __func__,blow_data[i].qfprom_addr);
			}
			msleep(10);
		}
	}
err_mem:
	kfree(p_buf);
	
	return fusing_verification;
}
int qfprom_read_one_row(u32 address, u32 *buf)
{
	int ret = 0;
	printk(KERN_INFO "%s : address %x\n", __func__, address);

	switch (qfprom_read_kind) {
	case 0:
		ret = qfuse_read_single_row(address, 0, buf);
		break;
	case 1:
		ret = 0;
		buf[0] = qfprom_read(address);
		buf[1] = qfprom_read(address + 4);
		break;
	case 2:
		/* ret = qfprom_read_from_misc(address, &buf[0], &buf[1]); */
		break;
	}
	printk(KERN_INFO "%s : return %x\n", __func__, ret);

	return ret;
}
static ssize_t qfprom_sdp_enum_show(struct device* dev, struct device_attribute* attr, char* buf)
{
	int ret;
	struct qfprom_blow_data sdp_data = { QFPROM_DEBUG_DISABLE, 0x200, 0x0 };
	unsigned int mask = 0x00000200;
	u32* p_buf=NULL;

	p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
	if(!p_buf) {
		printk("%s: memory alloc fail\n",__func__);
		ret=-EINVAL;
		return -EINVAL;
	}
	ret = qfuse_read_single_row(sdp_data.qfprom_addr,0,p_buf);
	if(ret!=0) {
		printk("%s: qfprom 0x%x read fail\n", __func__, sdp_data.qfprom_addr);
		kfree(p_buf);
		return -EINVAL;
	}
	printk("%s: sdp_enum is lsb : %x, msb : %x\n", __func__, p_buf[0]&sdp_data.lsb_data, p_buf[1]&sdp_data.msb_data);
	ret = (p_buf[0]&sdp_data.lsb_data & mask) >> 9;
	kfree(p_buf);
	return sprintf(buf,"%d", ret);
}
int qfprom_blow_secondary_hwkey_region(void)
{
	int ret;
	u32 addr, lsb, msb;
	int i;
	u32 *p_buf = NULL;

	p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
	if(!p_buf){
		printk("%s : buffer memory alloc fail\n", __func__);
		return -ENOMEM;
	}

	/* we check read permission
	 * if read permission region is blown, we can see all hw secondary key is blown
	 * because permission fuse is follow to secondary hw key
	 */
	
	ret = qfuse_read_single_row(QFPROM_RD_WR_PERMISSION, 0, p_buf);
	if(ret != 0){
		printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, QFPROM_RD_WR_PERMISSION, ret);
		ret = -EINVAL;
		goto err;
	}
	if((p_buf[0]&0x0C000000) == 0x0C000000) {
		printk("%s: All hw key was written already\n", __func__);
		ret = 0;
		goto err;
	}

	addr = QFPROM_SECONDARY_HW_KEY;
	for(i=0;i<7;i++){
		/* we can read hw secondary key region because before read permission is set */
		/*
		ret = qfuse_read_single_row(addr, 0, p_buf);
		if(ret != 0){
			printk("%s: qfuse addr %x read fail, ret=%d\n", __func__, addr,ret);
			ret = -EINVAL;
			goto err;
		}
		printk("%s:Currently, secondary key addr=0x%x, lsb=0x%x, msb=0x%x\n", __func__, addr,p_buf[0], p_buf[1]);
		*/
		msleep(10);

		/* if you have not written ever hw key before, value to read will be zero
		 * so create random using tzbsp
		 * LSB region */
		if(!p_buf[0]){
			lsb = qfprom_create_random();
			if(!lsb) {
				ret = -EINVAL;
				goto err;
			}
			msleep(5);
		} else {
			/* dont create random value and rewrite value to read */
			printk("hw lsb key was blow already in 0x%x addr\n", addr);
			lsb = p_buf[0];
		}
		/* if you have not written ever hw key before, value to read will be zero
		 * so create random using tzbsp
		 * MSB region */
		if(!p_buf[1]) {
			msb = qfprom_create_random();
			if(!msb) {
				ret = -EINVAL;
				goto err;
			}
			msleep(5);
		} else {

			printk("hw msb key was blow already in 0x%x addr\n", addr+4);
			msb = p_buf[1];
		}
		/* must mask FEC bit */
		lsb = lsb&HW_KEY_LSB_FEC_MASK;
		msb = msb&HW_KEY_MSB_FEC_MASK;
		printk("We start to writing secondary key !!!\n");
		printk("addr=0x%x, lsb=0x%x, msb=0x%x\n", addr, lsb, msb);
		msleep(10);
		ret = qfuse_write_single_row(addr, lsb, msb);
		if(ret != 0) {
			printk("%s:qfus addr 0x%x write error, ret=%d\n", __func__, addr, ret);
			ret = -EINVAL;
			goto err;
		} else {
			/* write double check routine */
			printk("hw secondary key write successful\n");
			msleep(10);
			/*
			ret = qfuse_read_single_row(addr, 0, p_buf);
			if(ret != 0) {
				printk("%s:read fail when double check routine, ret=%d\n", __func__, ret);
				goto err;
			}
			if((p_buf[0]==lsb)&&(p_buf[1]==msb))
				printk("%s: hw key write double check successful!!!!!!!\n",__func__);
			else {
				printk("%s: hw key double check error, read_lsb=0x%x,read_msb=0x%x\n",__func__,p_buf[0],p_buf[1]);
				ret = -EINVAL;
				goto err;
			}
			*/
		}
		addr = addr+8;
		msleep(10);
	}

err:
	kfree(p_buf);
	return ret;
}
/* this api handle diag command(fusing command) from ATD
 * this api fuse secure boot, jtag disable, oem config, secondary hw key, R/W permission
 * this api check secondary hw key status before fusing R/W permission
 */
static ssize_t qfusing_store(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	int ret;
	int i = 0;
	u32 *p_buf = NULL;
	u32 fusing_flag=0;

	if(!sysfs_streq(buf, "fusing")){
		printk("%s:argument fault\n", __func__);
		ret = -EINVAL;
		goto err;
	}

	p_buf = kmalloc(sizeof(u32)*2, GFP_KERNEL);
	if(!p_buf) {
		printk("%s: memory alloc fail\n", __func__);
		ret = -EINVAL;
		goto err;;

	}

	for(i=0;i<ARRAY_SIZE(blow_data);i++){
		if(blow_data[i].qfprom_addr==QFPROM_CHECK_HW_KEY) {
			/* We dont check secondary hw key status
			 * But qfprom_blow secondary_hwkey_region api does not create random if qfprom block was written
			 * The api create random if was not written only
			 * So HW key region to be written is not written by new random key
			 * The reason to not check hw key status reg is to check 7 hw key block to be written
			 */
			ret = qfprom_blow_secondary_hwkey_region();
			if(ret < 0) {
				printk("%s: hw key region blow error\n", __func__);
				goto err_fuse;
			}
			fusing_flag |= (0x1<<i);
			printk("%s: HW secondary key region is blown successfully\n", __func__);
			continue;
		}

		msleep(10);
		ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf);
		if(ret != 0) {
			printk("%s: qfprom addr %x read fail, ret=%d\n", __func__, blow_data[i].qfprom_addr, ret);
			goto err_fuse;
		}
		printk("%s:read addr 0x%x, lsb 0x%x, msb 0x%x\n", __func__, blow_data[i].qfprom_addr, p_buf[0], p_buf[1]);
		/* Don't rewrite if value to read is same value to write */
		if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) &&
			((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) {
			printk("%s: 0x%x was blown already\n", __func__, blow_data[i].qfprom_addr);
		} else {
			msleep(10);
			ret = qfuse_write_single_row(blow_data[i].qfprom_addr, blow_data[i].lsb_data, blow_data[i].msb_data);
			if(ret != 0) {
				printk("%s: qfuse addr %x blow write error!!!\n", __func__, blow_data[i].qfprom_addr);
				ret = -EINVAL;
				goto err_fuse;
			} else {
				/* double check routine*/
				msleep(10);
				printk("%s: qfprom 0x%x addr write double check routine\n", __func__, blow_data[i].qfprom_addr);
				ret = qfuse_read_single_row(blow_data[i].qfprom_addr, 0, p_buf);
				if(ret != 0) {
					printk("%s: read fail when double check, ret=%d\n", __func__, ret);
					ret = -EINVAL;
					goto err_fuse;
				}
				if(((p_buf[0]&blow_data[i].lsb_data) == blow_data[i].lsb_data) &&
					((p_buf[1]&blow_data[i].msb_data) == blow_data[i].msb_data)) {
					printk("%s:write double check successfully", __func__);
				} else {
					printk("%s:qfprom write successful but error when double check\n", __func__);
					ret = -EINVAL;
					goto err_fuse;
				}

			}

		}
		fusing_flag |= (0x1<<i);
	}
	printk("%s: fusing flag = 0x%x\n", __func__, fusing_flag);
	printk("%s: fusing complete!!!!!!!!!!!!!!!!!!!!\n", __func__);
	kfree(p_buf);
	return count;

err_fuse:
	kfree(p_buf);
err:
	return ret;
}
/* this api handle diag command(fusing check command) from ATD 
 * if fusing value 0 ==> is not fused
 * if fusing value 1 ==> fused (secure boot enable, jtag disable,
 * oem config, hw secondary key, RW permission)
 */
static ssize_t qfusing_show(struct device *dev, struct device_attribute *attr,
			    char *buf)
{
	int fusing = 0;
	int i, ret;
	u32 key_status = 0;
	u32 *p_buf = NULL;

	if(fusing_flag==0) {
////////////////////////////////////////
// workaround for apq8064 //
// hardcoding to understand easily.//

			p_buf = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
			if (!p_buf) {
				printk("%s: memory alloc fail\n", __func__);
				goto err_mem;
			}

			memset(p_buf, 0x00, sizeof(u32) * 2);
			msleep(10);
			ret =
			    qfuse_read_single_row(QFPROM_DEBUG_ENABLE, 0,
						  p_buf);
			printk("%s: addr = 0x%x LSB = 0x%x MSB = 0x%x\n",
			       __func__, QFPROM_DEBUG_ENABLE, p_buf[0],
			       p_buf[1]);
			if (ret != 0) {
				printk("%s: qfprom read fail error=%d\n", __func__,ret);
				kfree(p_buf);
				goto err_mem;

			}

			if ((p_buf[0] == 0xC1000000) && (p_buf[1] == 0x0000006F)) {

					printk("old versionwill be passed unquestioningly for factory process");
					goto workaround_for_old_apq8064;

			} else if  ((p_buf[0] == 0xC1300000) && (p_buf[1]== 0x0000006F)) {

					printk("new version will be passed unquestioningly for factory process");
					goto workaround_for_new_apq8064;

			} else {

					printk("empty or strange will be passed unquestioningly for factory process");
					goto workaround_for_new_apq8064;

			}


////////////////////////////////////////

workaround_for_new_apq8064:

	key_status = qfprom_secondary_hwkey_status();
	if ((key_status & SEC_HW_KEY_BLOWN) != SEC_HW_KEY_BLOWN) {
			printk("%s: hw key is not blown\n",__func__);
		goto err;
	} else {
			msleep(10);
			printk("%s:secondary HW key check complete!!!!!\n",__func__);

workaround_for_old_apq8064:

		for (i = 0; i < ARRAY_SIZE(blow_data); i++) {
			if (blow_data[i].qfprom_addr == QFPROM_CHECK_HW_KEY)
				continue;

			memset(p_buf, 0x00, sizeof(u32) * 2);
			msleep(10);
			ret =
			    qfuse_read_single_row(blow_data[i].qfprom_addr, 0,
						  p_buf);
			printk("%s: addr = 0x%x LSB = 0x%x MSB = 0x%x\n",
			       __func__, blow_data[i].qfprom_addr, p_buf[0],
			       p_buf[1]);
			if (ret != 0) {
				printk("%s: qfprom read fail error=%d\n", __func__,ret);
				goto err;
			} else {

////////////////////////////////////////
// workaround for apq8064 //
// hardcoding to understand easily.//
if (blow_data[i].qfprom_addr == QFPROM_DEBUG_ENABLE) {
	if ((p_buf[0] == 0xC1000000) && (p_buf[1] == 0x0000006F)) {

		printk("old version will be passed unquestioningly for factory process");
		continue;
	}
}
///////////////////////////////////////



					if(((p_buf[0]&blow_data[i].lsb_data)==blow_data[i].lsb_data) &&
						((p_buf[1]&blow_data[i].msb_data)==blow_data[i].msb_data)) {
						printk("%s: 0x%x chekc complete\n",__func__,blow_data[i].qfprom_addr);
						continue;
					}
				else {
					printk
					    ("%s: fusing value is not match\n",
					     __func__);
					goto err;
				}
					msleep(10);
			}
		}
		fusing = 1;
	}
	} 
	else {
		if(fusing_flag==FUSING_COMPLETED_STATE)
			fusing=1;
	}
err:
	kfree(p_buf);
err_mem:
	return sprintf(buf, "%x\n", fusing);
}