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

Commit 821873ab authored by Fabio Estevam's avatar Fabio Estevam Committed by Herbert Xu
Browse files

hwrng: mxc-rnga - Access data via structure



In current driver, everytime we need to access the rng clock
,ie to enable or disable it, a call to clk_get is done.

This is not correct and the preferred way is to provide a rng data structure
that could be used for accessing rng resources.

Acked-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarFabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent a9ccb7bd
Loading
Loading
Loading
Loading
+51 −57
Original line number Diff line number Diff line
@@ -59,16 +59,21 @@
#define RNGA_STATUS_LAST_READ_STATUS	0x00000002
#define RNGA_STATUS_SECURITY_VIOLATION	0x00000001

static struct platform_device *rng_dev;
struct mxc_rng {
	struct device *dev;
	struct hwrng rng;
	void __iomem *mem;
	struct clk *clk;
};

static int mxc_rnga_data_present(struct hwrng *rng, int wait)
{
	void __iomem *rng_base = (void __iomem *)rng->priv;
	int i;
	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);

	for (i = 0; i < 20; i++) {
		/* how many random numbers are in FIFO? [0-16] */
		int level = (__raw_readl(rng_base + RNGA_STATUS) &
		int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) &
				RNGA_STATUS_LEVEL_MASK) >> 8;
		if (level || !wait)
			return !!level;
@@ -81,20 +86,20 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
{
	int err;
	u32 ctrl;
	void __iomem *rng_base = (void __iomem *)rng->priv;
	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);

	/* retrieve a random number from FIFO */
	*data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO);
	*data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO);

	/* some error while reading this random number? */
	err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
	err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;

	/* if error: clear error interrupt, but doesn't return random number */
	if (err) {
		dev_dbg(&rng_dev->dev, "Error while reading random number!\n");
		ctrl = __raw_readl(rng_base + RNGA_CONTROL);
		dev_dbg(mxc_rng->dev, "Error while reading random number!\n");
		ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
		__raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
					rng_base + RNGA_CONTROL);
					mxc_rng->mem + RNGA_CONTROL);
		return 0;
	} else
		return 4;
@@ -103,22 +108,22 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
static int mxc_rnga_init(struct hwrng *rng)
{
	u32 ctrl, osc;
	void __iomem *rng_base = (void __iomem *)rng->priv;
	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);

	/* wake up */
	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
	__raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL);
	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
	__raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL);

	/* verify if oscillator is working */
	osc = __raw_readl(rng_base + RNGA_STATUS);
	osc = __raw_readl(mxc_rng->mem + RNGA_STATUS);
	if (osc & RNGA_STATUS_OSC_DEAD) {
		dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n");
		dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n");
		return -ENODEV;
	}

	/* go running */
	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
	__raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);
	__raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);

	return 0;
}
@@ -126,40 +131,40 @@ static int mxc_rnga_init(struct hwrng *rng)
static void mxc_rnga_cleanup(struct hwrng *rng)
{
	u32 ctrl;
	void __iomem *rng_base = (void __iomem *)rng->priv;
	struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng);

	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
	ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL);

	/* stop rnga */
	__raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
	__raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL);
}

static struct hwrng mxc_rnga = {
	.name = "mxc-rnga",
	.init = mxc_rnga_init,
	.cleanup = mxc_rnga_cleanup,
	.data_present = mxc_rnga_data_present,
	.data_read = mxc_rnga_data_read
};

static int __init mxc_rnga_probe(struct platform_device *pdev)
{
	int err = -ENODEV;
	struct clk *clk;
	struct resource *res, *mem;
	void __iomem *rng_base = NULL;

	if (rng_dev)
		return -EBUSY;

	clk = clk_get(&pdev->dev, NULL);
	if (IS_ERR(clk)) {
	struct mxc_rng *mxc_rng;

	mxc_rng = devm_kzalloc(&pdev->dev, sizeof(struct mxc_rng),
					GFP_KERNEL);
	if (!mxc_rng)
		return -ENOMEM;

	mxc_rng->dev = &pdev->dev;
	mxc_rng->rng.name = "mxc-rnga";
	mxc_rng->rng.init = mxc_rnga_init;
	mxc_rng->rng.cleanup = mxc_rnga_cleanup,
	mxc_rng->rng.data_present = mxc_rnga_data_present,
	mxc_rng->rng.data_read = mxc_rnga_data_read,

	mxc_rng->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(mxc_rng->clk)) {
		dev_err(&pdev->dev, "Could not get rng_clk!\n");
		err = PTR_ERR(clk);
		err = PTR_ERR(mxc_rng->clk);
		goto out;
	}

	clk_prepare_enable(clk);
	clk_prepare_enable(mxc_rng->clk);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
@@ -173,36 +178,27 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
		goto err_region;
	}

	rng_base = ioremap(res->start, resource_size(res));
	if (!rng_base) {
	mxc_rng->mem = ioremap(res->start, resource_size(res));
	if (!mxc_rng->mem) {
		err = -ENOMEM;
		goto err_ioremap;
	}

	mxc_rnga.priv = (unsigned long)rng_base;

	err = hwrng_register(&mxc_rnga);
	err = hwrng_register(&mxc_rng->rng);
	if (err) {
		dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
		goto err_register;
		goto err_ioremap;
	}

	rng_dev = pdev;

	dev_info(&pdev->dev, "MXC RNGA Registered.\n");

	return 0;

err_register:
	iounmap(rng_base);
	rng_base = NULL;

err_ioremap:
	release_mem_region(res->start, resource_size(res));

err_region:
	clk_disable_unprepare(clk);
	clk_put(clk);
	clk_disable_unprepare(mxc_rng->clk);

out:
	return err;
@@ -211,17 +207,15 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
static int __exit mxc_rnga_remove(struct platform_device *pdev)
{
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	void __iomem *rng_base = (void __iomem *)mxc_rnga.priv;
	struct clk *clk = clk_get(&pdev->dev, NULL);
	struct mxc_rng *mxc_rng = platform_get_drvdata(pdev);

	hwrng_unregister(&mxc_rnga);
	hwrng_unregister(&mxc_rng->rng);

	iounmap(rng_base);
	iounmap(mxc_rng->mem);

	release_mem_region(res->start, resource_size(res));

	clk_disable_unprepare(clk);
	clk_put(clk);
	clk_disable_unprepare(mxc_rng->clk);

	return 0;
}