Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17227f66 authored by Rohit Vaswani's avatar Rohit Vaswani
Browse files

misc: qfp_fuse: Add the open firmware support



Added the open firmware support in the driver. Base physical address
is passed instead of remapped address to the driver. The probe
function is modified to ioremap the address.

Change-Id: I167e3a158f970d7578a18638b197b28490727b71
Acked-by: default avatarKaushik Sikdar <ksikdar@qti.qualcomm.com>
Signed-off-by: default avatarRohit Vaswani <rvaswani@codeaurora.org>
parent aaa958ef
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
* QFP-FUSE

The qfp-fuse entry specifies the memory mapped addresses for the QFPROM fuse
registers. The qfpfuse driver uses these to provide api(s) that can be used
to read and write the fuse values. The write operation can be done one time
only.

Required Properties:
compatible: component name used for driver matching, should be "qcom,qfp-fuse"
reg: physical base address and length of the register set
qcom,blow-status-offset: offset of the blow status registers.
vdd-blow-supply: regulator used to blow fuses. For backward compatibility, the
regulator name must contain the string vdd-blow.

Example:
	qcom,qfpfuse@fc4b8000 {
		compatible = "qcom,qfp-fuse";
		reg = <0xfc4b8000 0x7000>;
		qcom,blow-status-offset = 0x204c;
		vdd-blow-supply: <&vdd_blow>;
	};
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -386,8 +386,8 @@ char fuse_regulator_name[] = "8058_lvs0";

struct resource qfp_fuse_resources[] = {
	{
		.start = (uint32_t) MSM_QFP_FUSE_BASE,
		.end   = (uint32_t) MSM_QFP_FUSE_BASE + MSM_QFP_FUSE_SIZE,
		.start = MSM_QFP_FUSE_PHYS,
		.end   = MSM_QFP_FUSE_PHYS + MSM_QFP_FUSE_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
};
+73 −12
Original line number Diff line number Diff line
/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>

/*
 * Time QFPROM requires to reliably burn a fuse.
@@ -41,15 +42,24 @@

#define QFP_FUSE_READY              0x01
#define QFP_FUSE_OFF                0x00
static const char *blow_supply = "vdd-blow";

struct qfp_priv_t {
	uint32_t base;
	uint32_t end;
	uint32_t blow_status_offset;
	struct mutex lock;
	struct regulator *fuse_vdd;
	u8 state;
};

struct qfp_resource {
	resource_size_t	start;
	resource_size_t	size;
	uint32_t	blow_status_offset;
	const char	*regulator_name;
};

/* We need only one instance of this for the driver */
static struct qfp_priv_t *qfp_priv;

@@ -79,7 +89,7 @@ static inline int qfp_fuse_wait_for_fuse_blow(u32 *status)
	udelay(400);
	do {
		*status = readl_relaxed(
			qfp_priv->base + QFPROM_BLOW_STATUS_OFFSET);
			qfp_priv->base + qfp_priv->blow_status_offset);

		if (!(*status & QFPROM_BLOW_STATUS_BUSY))
			return 0;
@@ -313,21 +323,61 @@ static struct miscdevice qfp_fuse_dev = {
	.fops = &qfp_fuse_fops
};


static int qfp_fuse_probe(struct platform_device *pdev)
static int qfp_get_resource(struct platform_device *pdev,
			    struct qfp_resource *qfp_res)
{
	int ret = 0;
	struct resource *res;
	const char *regulator_name = pdev->dev.platform_data;

	const char *regulator_name = NULL;
	uint32_t blow_status_offset = QFPROM_BLOW_STATUS_OFFSET;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENODEV;

	if (pdev->dev.of_node) {
		struct device_node *np = pdev->dev.of_node;

		if (of_property_read_u32(np, "qcom,blow-status-offset",
					 &blow_status_offset) == 0) {
			if ((res->start + blow_status_offset) > res->end) {
				pr_err("Invalid blow-status-offset\n");
				return -EINVAL;
			}
		}

		if (of_property_read_bool(np, "vdd-blow-supply")) {
			/* For backward compatibility, use the name
			 * from blow_supply */
			regulator_name = blow_supply;
		} else {
			pr_err("Failed to find regulator-name property\n");
			return -EINVAL;
		}

	} else {
		regulator_name = pdev->dev.platform_data;
	}

	if (!regulator_name)
		return -EINVAL;

	qfp_res->start = res->start;
	qfp_res->size = resource_size(res);
	qfp_res->blow_status_offset = blow_status_offset;
	qfp_res->regulator_name = regulator_name;

	return 0;
}

static int qfp_fuse_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct qfp_resource res;

	ret = qfp_get_resource(pdev, &res);
	if (ret)
		return ret;

	/* Initialize */
	qfp_priv = kzalloc(sizeof(struct qfp_priv_t), GFP_KERNEL);

@@ -336,15 +386,19 @@ static int qfp_fuse_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	/* The driver is passed ioremapped address */
	qfp_priv->base = res->start;
	qfp_priv->end = res->end;
	qfp_priv->base = (uint32_t)ioremap(res.start, res.size);
	if (!qfp_priv->base) {
		pr_warn("ioremap failed\n");
		goto err;
	}
	qfp_priv->end = qfp_priv->base + res.size;
	qfp_priv->blow_status_offset = res.blow_status_offset;

	/* Get regulator for QFPROM writes */
	qfp_priv->fuse_vdd = regulator_get(NULL, regulator_name);
	qfp_priv->fuse_vdd = regulator_get(&pdev->dev, res.regulator_name);
	if (IS_ERR(qfp_priv->fuse_vdd)) {
		ret = PTR_ERR(qfp_priv->fuse_vdd);
		pr_err("Err (%d) getting %s\n", ret, regulator_name);
		pr_err("Err (%d) getting %s\n", ret, res.regulator_name);
		qfp_priv->fuse_vdd = NULL;
		goto err;
	}
@@ -374,6 +428,7 @@ static int qfp_fuse_remove(struct platform_device *plat)
	if (qfp_priv && qfp_priv->fuse_vdd)
		regulator_put(qfp_priv->fuse_vdd);

	iounmap((void __iomem *)qfp_priv->base);
	kfree(qfp_priv);
	qfp_priv = NULL;

@@ -382,12 +437,18 @@ static int qfp_fuse_remove(struct platform_device *plat)
	return 0;
}

static struct of_device_id __attribute__ ((unused)) qfp_fuse_of_match[] = {
	{ .compatible = "qcom,qfp-fuse", },
	{}
};

static struct platform_driver qfp_fuse_driver = {
	.probe = qfp_fuse_probe,
	.remove = qfp_fuse_remove,
	.driver = {
		.name = "qfp_fuse_driver",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(qfp_fuse_of_match),
	},
};