145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/*
245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * RNG driver for Freescale RNGA
345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis *
445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * Author: Alan Carvalho de Assis <acassis@gmail.com>
645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis */
745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/*
945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * The code contained herein is licensed under the GNU General Public
1045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * License. You may obtain a copy of the GNU General Public License
1145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * Version 2 or later at the following locations:
1245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis *
1345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * http://www.opensource.org/licenses/gpl-license.html
1445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * http://www.gnu.org/copyleft/gpl.html
1545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis *
1645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis * This driver is based on other RNG drivers.
1745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis */
1845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
1945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/module.h>
2045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/init.h>
2145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/kernel.h>
2245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/clk.h>
2345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/err.h>
2445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/ioport.h>
2545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/platform_device.h>
2645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/hw_random.h>
2745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#include <linux/io.h>
2845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
2945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/* RNGA Registers */
3045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL			0x00
3145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS			0x04
3245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_ENTROPY			0x08
3345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_OUTPUT_FIFO		0x0c
3445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_MODE			0x10
3545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_VERIFICATION_CONTROL	0x14
3645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_OSC_CONTROL_COUNTER	0x18
3745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_OSC1_COUNTER		0x1c
3845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_OSC2_COUNTER		0x20
3945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_OSC_COUNTER_STATUS		0x24
4045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
4145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/* RNGA Registers Range */
4245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNG_ADDR_RANGE			0x28
4345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
4445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/* RNGA Control Register */
4545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL_SLEEP		0x00000010
4645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL_CLEAR_INT		0x00000008
4745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL_MASK_INTS		0x00000004
4845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL_HIGH_ASSURANCE	0x00000002
4945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_CONTROL_GO			0x00000001
5045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
5145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_LEVEL_MASK		0x0000ff00
5245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
5345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis/* RNGA Status Register */
5445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_OSC_DEAD		0x80000000
5545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_SLEEP		0x00000010
5645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_ERROR_INT		0x00000008
5745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_FIFO_UNDERFLOW	0x00000004
5845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_LAST_READ_STATUS	0x00000002
5945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis#define RNGA_STATUS_SECURITY_VIOLATION	0x00000001
6045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
6145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic struct platform_device *rng_dev;
6245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
6345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int mxc_rnga_data_present(struct hwrng *rng)
6445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
6545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	int level;
6645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = (void __iomem *)rng->priv;
6745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
6845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* how many random numbers is in FIFO? [0-16] */
6945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	level = ((__raw_readl(rng_base + RNGA_STATUS) &
7045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis			RNGA_STATUS_LEVEL_MASK) >> 8);
7145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
7245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return level > 0 ? 1 : 0;
7345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
7445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
7545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int mxc_rnga_data_read(struct hwrng *rng, u32 * data)
7645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
7745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	int err;
7845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	u32 ctrl;
7945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = (void __iomem *)rng->priv;
8045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
8145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* retrieve a random number from FIFO */
8245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	*data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO);
8345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
8445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* some error while reading this random number? */
8545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT;
8645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
8745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* if error: clear error interrupt, but doesn't return random number */
8845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (err) {
8945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		dev_dbg(&rng_dev->dev, "Error while reading random number!\n");
9045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		ctrl = __raw_readl(rng_base + RNGA_CONTROL);
9145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		__raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT,
9245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis					rng_base + RNGA_CONTROL);
9345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		return 0;
9445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	} else
9545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		return 4;
9645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
9745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
9845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int mxc_rnga_init(struct hwrng *rng)
9945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
10045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	u32 ctrl, osc;
10145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = (void __iomem *)rng->priv;
10245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
10345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* wake up */
10445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
10545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	__raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL);
10645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
10745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* verify if oscillator is working */
10845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	osc = __raw_readl(rng_base + RNGA_STATUS);
10945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (osc & RNGA_STATUS_OSC_DEAD) {
11045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n");
11145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		return -ENODEV;
11245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
11345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
11445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* go running */
11545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
11645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	__raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
11745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
11845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return 0;
11945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
12045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
12145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic void mxc_rnga_cleanup(struct hwrng *rng)
12245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
12345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	u32 ctrl;
12445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = (void __iomem *)rng->priv;
12545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
12645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	ctrl = __raw_readl(rng_base + RNGA_CONTROL);
12745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
12845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	/* stop rnga */
12945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	__raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL);
13045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
13145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
13245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic struct hwrng mxc_rnga = {
13345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.name = "mxc-rnga",
13445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.init = mxc_rnga_init,
13545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.cleanup = mxc_rnga_cleanup,
13645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.data_present = mxc_rnga_data_present,
13745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.data_read = mxc_rnga_data_read
13845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis};
13945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
14045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int __init mxc_rnga_probe(struct platform_device *pdev)
14145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
14245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	int err = -ENODEV;
14345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	struct clk *clk;
14445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	struct resource *res, *mem;
14545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = NULL;
14645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
14745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (rng_dev)
14845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		return -EBUSY;
14945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
15045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk = clk_get(&pdev->dev, "rng");
15145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (IS_ERR(clk)) {
15245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		dev_err(&pdev->dev, "Could not get rng_clk!\n");
15345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		err = PTR_ERR(clk);
15445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		goto out;
15545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
15645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
15745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk_enable(clk);
15845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
15945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
16045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (!res) {
16145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		err = -ENOENT;
16245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		goto err_region;
16345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
16445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
16545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	mem = request_mem_region(res->start, resource_size(res), pdev->name);
16645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (mem == NULL) {
16745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		err = -EBUSY;
16845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		goto err_region;
16945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
17045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
17145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	rng_base = ioremap(res->start, resource_size(res));
17245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (!rng_base) {
17345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		err = -ENOMEM;
17445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		goto err_ioremap;
17545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
17645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
17745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	mxc_rnga.priv = (unsigned long)rng_base;
17845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
17945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	err = hwrng_register(&mxc_rnga);
18045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	if (err) {
18145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err);
18245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		goto err_register;
18345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	}
18445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
18545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	rng_dev = pdev;
18645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
18745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	dev_info(&pdev->dev, "MXC RNGA Registered.\n");
18845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
18945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return 0;
19045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
19145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assiserr_register:
19245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	iounmap(rng_base);
19345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	rng_base = NULL;
19445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
19545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assiserr_ioremap:
19645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	release_mem_region(res->start, resource_size(res));
19745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
19845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assiserr_region:
19945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk_disable(clk);
20045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk_put(clk);
20145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
20245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisout:
20345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return err;
20445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
20545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
20645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int __exit mxc_rnga_remove(struct platform_device *pdev)
20745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
20845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
20945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	void __iomem *rng_base = (void __iomem *)mxc_rnga.priv;
21045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	struct clk *clk = clk_get(&pdev->dev, "rng");
21145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
21245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	hwrng_unregister(&mxc_rnga);
21345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
21445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	iounmap(rng_base);
21545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
21645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	release_mem_region(res->start, resource_size(res));
21745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
21845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk_disable(clk);
21945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	clk_put(clk);
22045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
22145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return 0;
22245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
22345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
22445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic struct platform_driver mxc_rnga_driver = {
22545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.driver = {
22645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		   .name = "mxc_rnga",
22745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		   .owner = THIS_MODULE,
22845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis		   },
22945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	.remove = __exit_p(mxc_rnga_remove),
23045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis};
23145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
23245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic int __init mod_init(void)
23345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
23445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
23545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
23645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
23745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assisstatic void __exit mod_exit(void)
23845001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis{
23945001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis	platform_driver_unregister(&mxc_rnga_driver);
24045001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis}
24145001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
24245001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assismodule_init(mod_init);
24345001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assismodule_exit(mod_exit);
24445001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de Assis
24545001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de AssisMODULE_AUTHOR("Freescale Semiconductor, Inc.");
24645001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de AssisMODULE_DESCRIPTION("H/W RNGA driver for i.MX");
24745001e92d0249a8c4b9f6c3695215652e8e8493dAlan Carvalho de AssisMODULE_LICENSE("GPL");
248