xref: /linux/drivers/char/hw_random/exynos-trng.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
16cd225ccSŁukasz Stelmach // SPDX-License-Identifier: GPL-2.0
26cd225ccSŁukasz Stelmach /*
36cd225ccSŁukasz Stelmach  * RNG driver for Exynos TRNGs
46cd225ccSŁukasz Stelmach  *
56cd225ccSŁukasz Stelmach  * Author: Łukasz Stelmach <l.stelmach@samsung.com>
66cd225ccSŁukasz Stelmach  *
76cd225ccSŁukasz Stelmach  * Copyright 2017 (c) Samsung Electronics Software, Inc.
86cd225ccSŁukasz Stelmach  *
96cd225ccSŁukasz Stelmach  * Based on the Exynos PRNG driver drivers/crypto/exynos-rng by
106cd225ccSŁukasz Stelmach  * Krzysztof Kozłowski <krzk@kernel.org>
116cd225ccSŁukasz Stelmach  */
126cd225ccSŁukasz Stelmach 
1310bb6ac8SSam Protsenko #include <linux/arm-smccc.h>
146cd225ccSŁukasz Stelmach #include <linux/clk.h>
156cd225ccSŁukasz Stelmach #include <linux/crypto.h>
166cd225ccSŁukasz Stelmach #include <linux/delay.h>
176cd225ccSŁukasz Stelmach #include <linux/err.h>
186cd225ccSŁukasz Stelmach #include <linux/hw_random.h>
196cd225ccSŁukasz Stelmach #include <linux/io.h>
206cd225ccSŁukasz Stelmach #include <linux/iopoll.h>
216cd225ccSŁukasz Stelmach #include <linux/kernel.h>
226cd225ccSŁukasz Stelmach #include <linux/module.h>
23ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
246cd225ccSŁukasz Stelmach #include <linux/platform_device.h>
256cd225ccSŁukasz Stelmach #include <linux/pm_runtime.h>
2610bb6ac8SSam Protsenko #include <linux/property.h>
276cd225ccSŁukasz Stelmach 
2876536caaSSam Protsenko #define EXYNOS_TRNG_CLKDIV		0x0
296cd225ccSŁukasz Stelmach 
3076536caaSSam Protsenko #define EXYNOS_TRNG_CTRL		0x20
316cd225ccSŁukasz Stelmach #define EXYNOS_TRNG_CTRL_RNGEN		BIT(31)
326cd225ccSŁukasz Stelmach 
3376536caaSSam Protsenko #define EXYNOS_TRNG_POST_CTRL		0x30
3476536caaSSam Protsenko #define EXYNOS_TRNG_ONLINE_CTRL		0x40
3576536caaSSam Protsenko #define EXYNOS_TRNG_ONLINE_STAT		0x44
3676536caaSSam Protsenko #define EXYNOS_TRNG_ONLINE_MAXCHI2	0x48
3776536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_CTRL		0x50
3876536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_0		0x80
3976536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_1		0x84
4076536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_2		0x88
4176536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_3		0x8c
4276536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_4		0x90
4376536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_5		0x94
4476536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_6		0x98
4576536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_7		0x9c
4676536caaSSam Protsenko #define EXYNOS_TRNG_FIFO_LEN		8
4776536caaSSam Protsenko #define EXYNOS_TRNG_CLOCK_RATE		500000
486cd225ccSŁukasz Stelmach 
4910bb6ac8SSam Protsenko /* Driver feature flags */
5010bb6ac8SSam Protsenko #define EXYNOS_SMC			BIT(0)
5110bb6ac8SSam Protsenko 
5210bb6ac8SSam Protsenko #define EXYNOS_SMC_CALL_VAL(func_num)			\
5310bb6ac8SSam Protsenko 	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
5410bb6ac8SSam Protsenko 			   ARM_SMCCC_SMC_32,		\
5510bb6ac8SSam Protsenko 			   ARM_SMCCC_OWNER_SIP,		\
5610bb6ac8SSam Protsenko 			   func_num)
5710bb6ac8SSam Protsenko 
5810bb6ac8SSam Protsenko /* SMC command for DTRNG access */
5910bb6ac8SSam Protsenko #define SMC_CMD_RANDOM			EXYNOS_SMC_CALL_VAL(0x1012)
6010bb6ac8SSam Protsenko 
6110bb6ac8SSam Protsenko /* SMC_CMD_RANDOM: arguments */
6210bb6ac8SSam Protsenko #define HWRNG_INIT			0x0
6310bb6ac8SSam Protsenko #define HWRNG_EXIT			0x1
6410bb6ac8SSam Protsenko #define HWRNG_GET_DATA			0x2
6510bb6ac8SSam Protsenko #define HWRNG_RESUME			0x3
6610bb6ac8SSam Protsenko 
6710bb6ac8SSam Protsenko /* SMC_CMD_RANDOM: return values */
6810bb6ac8SSam Protsenko #define HWRNG_RET_OK			0x0
6910bb6ac8SSam Protsenko #define HWRNG_RET_RETRY_ERROR		0x2
7010bb6ac8SSam Protsenko 
7110bb6ac8SSam Protsenko #define HWRNG_MAX_TRIES			100
7210bb6ac8SSam Protsenko 
736cd225ccSŁukasz Stelmach struct exynos_trng_dev {
746cd225ccSŁukasz Stelmach 	struct device	*dev;
756cd225ccSŁukasz Stelmach 	void __iomem	*mem;
76e003d670SSam Protsenko 	struct clk	*clk;	/* operating clock */
77e003d670SSam Protsenko 	struct clk	*pclk;	/* bus clock */
786cd225ccSŁukasz Stelmach 	struct hwrng	rng;
7910bb6ac8SSam Protsenko 	unsigned long	flags;
806cd225ccSŁukasz Stelmach };
816cd225ccSŁukasz Stelmach 
exynos_trng_do_read_reg(struct hwrng * rng,void * data,size_t max,bool wait)8210bb6ac8SSam Protsenko static int exynos_trng_do_read_reg(struct hwrng *rng, void *data, size_t max,
836cd225ccSŁukasz Stelmach 				   bool wait)
846cd225ccSŁukasz Stelmach {
8576536caaSSam Protsenko 	struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv;
86a8bc71d4SDan Carpenter 	int val;
876cd225ccSŁukasz Stelmach 
886cd225ccSŁukasz Stelmach 	max = min_t(size_t, max, (EXYNOS_TRNG_FIFO_LEN * 4));
896cd225ccSŁukasz Stelmach 	writel_relaxed(max * 8, trng->mem + EXYNOS_TRNG_FIFO_CTRL);
906cd225ccSŁukasz Stelmach 	val = readl_poll_timeout(trng->mem + EXYNOS_TRNG_FIFO_CTRL, val,
916cd225ccSŁukasz Stelmach 				 val == 0, 200, 1000000);
926cd225ccSŁukasz Stelmach 	if (val < 0)
936cd225ccSŁukasz Stelmach 		return val;
946cd225ccSŁukasz Stelmach 
956cd225ccSŁukasz Stelmach 	memcpy_fromio(data, trng->mem + EXYNOS_TRNG_FIFO_0, max);
966cd225ccSŁukasz Stelmach 
976cd225ccSŁukasz Stelmach 	return max;
986cd225ccSŁukasz Stelmach }
996cd225ccSŁukasz Stelmach 
exynos_trng_do_read_smc(struct hwrng * rng,void * data,size_t max,bool wait)10010bb6ac8SSam Protsenko static int exynos_trng_do_read_smc(struct hwrng *rng, void *data, size_t max,
10110bb6ac8SSam Protsenko 				   bool wait)
10210bb6ac8SSam Protsenko {
10310bb6ac8SSam Protsenko 	struct arm_smccc_res res;
10410bb6ac8SSam Protsenko 	unsigned int copied = 0;
10510bb6ac8SSam Protsenko 	u32 *buf = data;
10610bb6ac8SSam Protsenko 	int tries = 0;
10710bb6ac8SSam Protsenko 
10810bb6ac8SSam Protsenko 	while (copied < max) {
10910bb6ac8SSam Protsenko 		arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_GET_DATA, 0, 0, 0, 0, 0, 0,
11010bb6ac8SSam Protsenko 			      &res);
11110bb6ac8SSam Protsenko 		switch (res.a0) {
11210bb6ac8SSam Protsenko 		case HWRNG_RET_OK:
11310bb6ac8SSam Protsenko 			*buf++ = res.a2;
11410bb6ac8SSam Protsenko 			*buf++ = res.a3;
11510bb6ac8SSam Protsenko 			copied += 8;
11610bb6ac8SSam Protsenko 			tries = 0;
11710bb6ac8SSam Protsenko 			break;
11810bb6ac8SSam Protsenko 		case HWRNG_RET_RETRY_ERROR:
11910bb6ac8SSam Protsenko 			if (!wait)
12010bb6ac8SSam Protsenko 				return copied;
12110bb6ac8SSam Protsenko 			if (++tries >= HWRNG_MAX_TRIES)
12210bb6ac8SSam Protsenko 				return copied;
12310bb6ac8SSam Protsenko 			cond_resched();
12410bb6ac8SSam Protsenko 			break;
12510bb6ac8SSam Protsenko 		default:
12610bb6ac8SSam Protsenko 			return -EIO;
12710bb6ac8SSam Protsenko 		}
12810bb6ac8SSam Protsenko 	}
12910bb6ac8SSam Protsenko 
13010bb6ac8SSam Protsenko 	return copied;
13110bb6ac8SSam Protsenko }
13210bb6ac8SSam Protsenko 
exynos_trng_init_reg(struct hwrng * rng)13310bb6ac8SSam Protsenko static int exynos_trng_init_reg(struct hwrng *rng)
1346cd225ccSŁukasz Stelmach {
1356cd225ccSŁukasz Stelmach 	struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv;
1366cd225ccSŁukasz Stelmach 	unsigned long sss_rate;
1376cd225ccSŁukasz Stelmach 	u32 val;
1386cd225ccSŁukasz Stelmach 
1396cd225ccSŁukasz Stelmach 	sss_rate = clk_get_rate(trng->clk);
1406cd225ccSŁukasz Stelmach 
1416cd225ccSŁukasz Stelmach 	/*
1426cd225ccSŁukasz Stelmach 	 * For most TRNG circuits the clock frequency of under 500 kHz
1436cd225ccSŁukasz Stelmach 	 * is safe.
1446cd225ccSŁukasz Stelmach 	 */
1456cd225ccSŁukasz Stelmach 	val = sss_rate / (EXYNOS_TRNG_CLOCK_RATE * 2);
1466cd225ccSŁukasz Stelmach 	if (val > 0x7fff) {
14776536caaSSam Protsenko 		dev_err(trng->dev, "clock divider too large: %d\n", val);
1486cd225ccSŁukasz Stelmach 		return -ERANGE;
1496cd225ccSŁukasz Stelmach 	}
1506cd225ccSŁukasz Stelmach 	val = val << 1;
1516cd225ccSŁukasz Stelmach 	writel_relaxed(val, trng->mem + EXYNOS_TRNG_CLKDIV);
1526cd225ccSŁukasz Stelmach 
1536cd225ccSŁukasz Stelmach 	/* Enable the generator. */
1546cd225ccSŁukasz Stelmach 	val = EXYNOS_TRNG_CTRL_RNGEN;
1556cd225ccSŁukasz Stelmach 	writel_relaxed(val, trng->mem + EXYNOS_TRNG_CTRL);
1566cd225ccSŁukasz Stelmach 
1576cd225ccSŁukasz Stelmach 	/*
1586cd225ccSŁukasz Stelmach 	 * Disable post-processing. /dev/hwrng is supposed to deliver
1596cd225ccSŁukasz Stelmach 	 * unprocessed data.
1606cd225ccSŁukasz Stelmach 	 */
1616cd225ccSŁukasz Stelmach 	writel_relaxed(0, trng->mem + EXYNOS_TRNG_POST_CTRL);
1626cd225ccSŁukasz Stelmach 
1636cd225ccSŁukasz Stelmach 	return 0;
1646cd225ccSŁukasz Stelmach }
1656cd225ccSŁukasz Stelmach 
exynos_trng_init_smc(struct hwrng * rng)16610bb6ac8SSam Protsenko static int exynos_trng_init_smc(struct hwrng *rng)
16710bb6ac8SSam Protsenko {
16810bb6ac8SSam Protsenko 	struct exynos_trng_dev *trng = (struct exynos_trng_dev *)rng->priv;
16910bb6ac8SSam Protsenko 	struct arm_smccc_res res;
17010bb6ac8SSam Protsenko 	int ret = 0;
17110bb6ac8SSam Protsenko 
17210bb6ac8SSam Protsenko 	arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0, 0, 0, 0, 0, &res);
17310bb6ac8SSam Protsenko 	if (res.a0 != HWRNG_RET_OK) {
17410bb6ac8SSam Protsenko 		dev_err(trng->dev, "SMC command for TRNG init failed (%d)\n",
17510bb6ac8SSam Protsenko 			(int)res.a0);
17610bb6ac8SSam Protsenko 		ret = -EIO;
17710bb6ac8SSam Protsenko 	}
17810bb6ac8SSam Protsenko 	if ((int)res.a0 == -1)
17910bb6ac8SSam Protsenko 		dev_info(trng->dev, "Make sure LDFW is loaded by your BL\n");
18010bb6ac8SSam Protsenko 
18110bb6ac8SSam Protsenko 	return ret;
18210bb6ac8SSam Protsenko }
18310bb6ac8SSam Protsenko 
exynos_trng_probe(struct platform_device * pdev)1846cd225ccSŁukasz Stelmach static int exynos_trng_probe(struct platform_device *pdev)
1856cd225ccSŁukasz Stelmach {
1866cd225ccSŁukasz Stelmach 	struct exynos_trng_dev *trng;
1876cd225ccSŁukasz Stelmach 	int ret = -ENOMEM;
1886cd225ccSŁukasz Stelmach 
1896cd225ccSŁukasz Stelmach 	trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
1906cd225ccSŁukasz Stelmach 	if (!trng)
1916cd225ccSŁukasz Stelmach 		return ret;
1926cd225ccSŁukasz Stelmach 
19310bb6ac8SSam Protsenko 	platform_set_drvdata(pdev, trng);
19410bb6ac8SSam Protsenko 	trng->dev = &pdev->dev;
19510bb6ac8SSam Protsenko 
19610bb6ac8SSam Protsenko 	trng->flags = (unsigned long)device_get_match_data(&pdev->dev);
19710bb6ac8SSam Protsenko 
1986cd225ccSŁukasz Stelmach 	trng->rng.name = devm_kstrdup(&pdev->dev, dev_name(&pdev->dev),
1996cd225ccSŁukasz Stelmach 				      GFP_KERNEL);
2006cd225ccSŁukasz Stelmach 	if (!trng->rng.name)
2016cd225ccSŁukasz Stelmach 		return ret;
2026cd225ccSŁukasz Stelmach 
2036cd225ccSŁukasz Stelmach 	trng->rng.priv = (unsigned long)trng;
2046cd225ccSŁukasz Stelmach 
20510bb6ac8SSam Protsenko 	if (trng->flags & EXYNOS_SMC) {
20610bb6ac8SSam Protsenko 		trng->rng.init = exynos_trng_init_smc;
20710bb6ac8SSam Protsenko 		trng->rng.read = exynos_trng_do_read_smc;
20810bb6ac8SSam Protsenko 	} else {
20910bb6ac8SSam Protsenko 		trng->rng.init = exynos_trng_init_reg;
21010bb6ac8SSam Protsenko 		trng->rng.read = exynos_trng_do_read_reg;
2116cd225ccSŁukasz Stelmach 
2123e3c97c6SYueHaibing 		trng->mem = devm_platform_ioremap_resource(pdev, 0);
2132273f42dSweiyongjun \(A\) 		if (IS_ERR(trng->mem))
2146cd225ccSŁukasz Stelmach 			return PTR_ERR(trng->mem);
21510bb6ac8SSam Protsenko 	}
2166cd225ccSŁukasz Stelmach 
2176cd225ccSŁukasz Stelmach 	pm_runtime_enable(&pdev->dev);
2180cdbabf8SŁukasz Stelmach 	ret = pm_runtime_resume_and_get(&pdev->dev);
2196cd225ccSŁukasz Stelmach 	if (ret < 0) {
2206cd225ccSŁukasz Stelmach 		dev_err(&pdev->dev, "Could not get runtime PM.\n");
2216cd225ccSŁukasz Stelmach 		goto err_pm_get;
2226cd225ccSŁukasz Stelmach 	}
2236cd225ccSŁukasz Stelmach 
22481da8056SSam Protsenko 	trng->clk = devm_clk_get_enabled(&pdev->dev, "secss");
2256cd225ccSŁukasz Stelmach 	if (IS_ERR(trng->clk)) {
22681da8056SSam Protsenko 		ret = dev_err_probe(&pdev->dev, PTR_ERR(trng->clk),
22781da8056SSam Protsenko 				    "Could not get clock\n");
2286cd225ccSŁukasz Stelmach 		goto err_clock;
2296cd225ccSŁukasz Stelmach 	}
2306cd225ccSŁukasz Stelmach 
231e003d670SSam Protsenko 	trng->pclk = devm_clk_get_optional_enabled(&pdev->dev, "pclk");
232e003d670SSam Protsenko 	if (IS_ERR(trng->pclk)) {
233e003d670SSam Protsenko 		ret = dev_err_probe(&pdev->dev, PTR_ERR(trng->pclk),
234e003d670SSam Protsenko 				    "Could not get pclk\n");
235e003d670SSam Protsenko 		goto err_clock;
236e003d670SSam Protsenko 	}
237e003d670SSam Protsenko 
2383e75241bSChuhong Yuan 	ret = devm_hwrng_register(&pdev->dev, &trng->rng);
2396cd225ccSŁukasz Stelmach 	if (ret) {
2406cd225ccSŁukasz Stelmach 		dev_err(&pdev->dev, "Could not register hwrng device.\n");
24181da8056SSam Protsenko 		goto err_clock;
2426cd225ccSŁukasz Stelmach 	}
2436cd225ccSŁukasz Stelmach 
2446cd225ccSŁukasz Stelmach 	dev_info(&pdev->dev, "Exynos True Random Number Generator.\n");
2456cd225ccSŁukasz Stelmach 
2466cd225ccSŁukasz Stelmach 	return 0;
2476cd225ccSŁukasz Stelmach 
2486cd225ccSŁukasz Stelmach err_clock:
2490cdbabf8SŁukasz Stelmach 	pm_runtime_put_noidle(&pdev->dev);
2506cd225ccSŁukasz Stelmach 
2516cd225ccSŁukasz Stelmach err_pm_get:
2526cd225ccSŁukasz Stelmach 	pm_runtime_disable(&pdev->dev);
2536cd225ccSŁukasz Stelmach 
2546cd225ccSŁukasz Stelmach 	return ret;
2556cd225ccSŁukasz Stelmach }
2566cd225ccSŁukasz Stelmach 
exynos_trng_remove(struct platform_device * pdev)2579daec3cbSUwe Kleine-König static void exynos_trng_remove(struct platform_device *pdev)
2586cd225ccSŁukasz Stelmach {
25910bb6ac8SSam Protsenko 	struct exynos_trng_dev *trng = platform_get_drvdata(pdev);
26010bb6ac8SSam Protsenko 
26110bb6ac8SSam Protsenko 	if (trng->flags & EXYNOS_SMC) {
26210bb6ac8SSam Protsenko 		struct arm_smccc_res res;
26310bb6ac8SSam Protsenko 
26410bb6ac8SSam Protsenko 		arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0, 0, 0, 0, 0,
26510bb6ac8SSam Protsenko 			      &res);
26610bb6ac8SSam Protsenko 	}
26710bb6ac8SSam Protsenko 
2686cd225ccSŁukasz Stelmach 	pm_runtime_put_sync(&pdev->dev);
2696cd225ccSŁukasz Stelmach 	pm_runtime_disable(&pdev->dev);
2706cd225ccSŁukasz Stelmach }
2716cd225ccSŁukasz Stelmach 
exynos_trng_suspend(struct device * dev)272b4198a9aSMartin Kaiser static int exynos_trng_suspend(struct device *dev)
2736cd225ccSŁukasz Stelmach {
27410bb6ac8SSam Protsenko 	struct exynos_trng_dev *trng = dev_get_drvdata(dev);
27510bb6ac8SSam Protsenko 	struct arm_smccc_res res;
27610bb6ac8SSam Protsenko 
27710bb6ac8SSam Protsenko 	if (trng->flags & EXYNOS_SMC) {
27810bb6ac8SSam Protsenko 		arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_EXIT, 0, 0, 0, 0, 0, 0,
27910bb6ac8SSam Protsenko 			      &res);
28010bb6ac8SSam Protsenko 		if (res.a0 != HWRNG_RET_OK)
28110bb6ac8SSam Protsenko 			return -EIO;
28210bb6ac8SSam Protsenko 	}
28310bb6ac8SSam Protsenko 
2846cd225ccSŁukasz Stelmach 	pm_runtime_put_sync(dev);
2856cd225ccSŁukasz Stelmach 
2866cd225ccSŁukasz Stelmach 	return 0;
2876cd225ccSŁukasz Stelmach }
2886cd225ccSŁukasz Stelmach 
exynos_trng_resume(struct device * dev)289b4198a9aSMartin Kaiser static int exynos_trng_resume(struct device *dev)
2906cd225ccSŁukasz Stelmach {
29110bb6ac8SSam Protsenko 	struct exynos_trng_dev *trng = dev_get_drvdata(dev);
2926cd225ccSŁukasz Stelmach 	int ret;
2936cd225ccSŁukasz Stelmach 
2945d0421d6STian Tao 	ret = pm_runtime_resume_and_get(dev);
2956cd225ccSŁukasz Stelmach 	if (ret < 0) {
2966cd225ccSŁukasz Stelmach 		dev_err(dev, "Could not get runtime PM.\n");
2976cd225ccSŁukasz Stelmach 		return ret;
2986cd225ccSŁukasz Stelmach 	}
2996cd225ccSŁukasz Stelmach 
30010bb6ac8SSam Protsenko 	if (trng->flags & EXYNOS_SMC) {
30110bb6ac8SSam Protsenko 		struct arm_smccc_res res;
30210bb6ac8SSam Protsenko 
30310bb6ac8SSam Protsenko 		arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_RESUME, 0, 0, 0, 0, 0, 0,
30410bb6ac8SSam Protsenko 			      &res);
30510bb6ac8SSam Protsenko 		if (res.a0 != HWRNG_RET_OK)
30610bb6ac8SSam Protsenko 			return -EIO;
30710bb6ac8SSam Protsenko 
30810bb6ac8SSam Protsenko 		arm_smccc_smc(SMC_CMD_RANDOM, HWRNG_INIT, 0, 0, 0, 0, 0, 0,
30910bb6ac8SSam Protsenko 			      &res);
31010bb6ac8SSam Protsenko 		if (res.a0 != HWRNG_RET_OK)
31110bb6ac8SSam Protsenko 			return -EIO;
31210bb6ac8SSam Protsenko 	}
31310bb6ac8SSam Protsenko 
3146cd225ccSŁukasz Stelmach 	return 0;
3156cd225ccSŁukasz Stelmach }
3166cd225ccSŁukasz Stelmach 
317b4198a9aSMartin Kaiser static DEFINE_SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
3186cd225ccSŁukasz Stelmach 				exynos_trng_resume);
3196cd225ccSŁukasz Stelmach 
3206cd225ccSŁukasz Stelmach static const struct of_device_id exynos_trng_dt_match[] = {
3216cd225ccSŁukasz Stelmach 	{
3226cd225ccSŁukasz Stelmach 		.compatible = "samsung,exynos5250-trng",
323*b0c2036dSSam Protsenko 	}, {
324*b0c2036dSSam Protsenko 		.compatible = "samsung,exynos850-trng",
325*b0c2036dSSam Protsenko 		.data = (void *)EXYNOS_SMC,
3266cd225ccSŁukasz Stelmach 	},
3276cd225ccSŁukasz Stelmach 	{ },
3286cd225ccSŁukasz Stelmach };
3296cd225ccSŁukasz Stelmach MODULE_DEVICE_TABLE(of, exynos_trng_dt_match);
3306cd225ccSŁukasz Stelmach 
3316cd225ccSŁukasz Stelmach static struct platform_driver exynos_trng_driver = {
3326cd225ccSŁukasz Stelmach 	.driver = {
3336cd225ccSŁukasz Stelmach 		.name = "exynos-trng",
334b4198a9aSMartin Kaiser 		.pm = pm_sleep_ptr(&exynos_trng_pm_ops),
3356cd225ccSŁukasz Stelmach 		.of_match_table = exynos_trng_dt_match,
3366cd225ccSŁukasz Stelmach 	},
3376cd225ccSŁukasz Stelmach 	.probe = exynos_trng_probe,
3389daec3cbSUwe Kleine-König 	.remove_new = exynos_trng_remove,
3396cd225ccSŁukasz Stelmach };
3406cd225ccSŁukasz Stelmach 
3416cd225ccSŁukasz Stelmach module_platform_driver(exynos_trng_driver);
34276536caaSSam Protsenko 
3436cd225ccSŁukasz Stelmach MODULE_AUTHOR("Łukasz Stelmach");
3446cd225ccSŁukasz Stelmach MODULE_DESCRIPTION("H/W TRNG driver for Exynos chips");
3456cd225ccSŁukasz Stelmach MODULE_LICENSE("GPL v2");
346