Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (c) 2015, Daniel Thompson
  3 *
  4 * This file is free software; you can redistribute it and/or
  5 * modify it under the terms of the GNU General Public License
  6 * as published by the Free Software Foundation; either version 2
  7 * of the License, or (at your option) any later version.
  8 *
  9 * This file is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 */
 14
 15#include <linux/clk.h>
 16#include <linux/delay.h>
 17#include <linux/hw_random.h>
 18#include <linux/io.h>
 19#include <linux/iopoll.h>
 20#include <linux/kernel.h>
 21#include <linux/module.h>
 22#include <linux/of_address.h>
 23#include <linux/of_platform.h>
 24#include <linux/pm_runtime.h>
 25#include <linux/reset.h>
 26#include <linux/slab.h>
 27
 28#define RNG_CR 0x00
 29#define RNG_CR_RNGEN BIT(2)
 30#define RNG_CR_CED BIT(5)
 31
 32#define RNG_SR 0x04
 33#define RNG_SR_SEIS BIT(6)
 34#define RNG_SR_CEIS BIT(5)
 35#define RNG_SR_DRDY BIT(0)
 36
 37#define RNG_DR 0x08
 38
 39struct stm32_rng_private {
 40	struct hwrng rng;
 41	void __iomem *base;
 42	struct clk *clk;
 43	struct reset_control *rst;
 44	bool ced;
 45};
 46
 47static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 48{
 49	struct stm32_rng_private *priv =
 50	    container_of(rng, struct stm32_rng_private, rng);
 51	u32 sr;
 52	int retval = 0;
 53
 54	pm_runtime_get_sync((struct device *) priv->rng.priv);
 55
 56	while (max > sizeof(u32)) {
 57		sr = readl_relaxed(priv->base + RNG_SR);
 58		/* Manage timeout which is based on timer and take */
 59		/* care of initial delay time when enabling rng	*/
 60		if (!sr && wait) {
 61			retval = readl_relaxed_poll_timeout_atomic(priv->base
 62								   + RNG_SR,
 63								   sr, sr,
 64								   10, 50000);
 65			if (retval)
 66				dev_err((struct device *)priv->rng.priv,
 67					"%s: timeout %x!\n", __func__, sr);
 68		}
 69
 70		/* If error detected or data not ready... */
 71		if (sr != RNG_SR_DRDY) {
 72			if (WARN_ONCE(sr & (RNG_SR_SEIS | RNG_SR_CEIS),
 73					"bad RNG status - %x\n", sr))
 74				writel_relaxed(0, priv->base + RNG_SR);
 75			break;
 76		}
 77
 78		*(u32 *)data = readl_relaxed(priv->base + RNG_DR);
 79
 80		retval += sizeof(u32);
 81		data += sizeof(u32);
 82		max -= sizeof(u32);
 83	}
 84
 85	pm_runtime_mark_last_busy((struct device *) priv->rng.priv);
 86	pm_runtime_put_sync_autosuspend((struct device *) priv->rng.priv);
 87
 88	return retval || !wait ? retval : -EIO;
 89}
 90
 91static int stm32_rng_init(struct hwrng *rng)
 92{
 93	struct stm32_rng_private *priv =
 94	    container_of(rng, struct stm32_rng_private, rng);
 95	int err;
 96
 97	err = clk_prepare_enable(priv->clk);
 98	if (err)
 99		return err;
100
101	if (priv->ced)
102		writel_relaxed(RNG_CR_RNGEN, priv->base + RNG_CR);
103	else
104		writel_relaxed(RNG_CR_RNGEN | RNG_CR_CED,
105			       priv->base + RNG_CR);
106
107	/* clear error indicators */
108	writel_relaxed(0, priv->base + RNG_SR);
109
110	return 0;
111}
112
113static void stm32_rng_cleanup(struct hwrng *rng)
114{
115	struct stm32_rng_private *priv =
116	    container_of(rng, struct stm32_rng_private, rng);
117
118	writel_relaxed(0, priv->base + RNG_CR);
119	clk_disable_unprepare(priv->clk);
120}
121
122static int stm32_rng_probe(struct platform_device *ofdev)
123{
124	struct device *dev = &ofdev->dev;
125	struct device_node *np = ofdev->dev.of_node;
126	struct stm32_rng_private *priv;
127	struct resource res;
128	int err;
129
130	priv = devm_kzalloc(dev, sizeof(struct stm32_rng_private), GFP_KERNEL);
131	if (!priv)
132		return -ENOMEM;
133
134	err = of_address_to_resource(np, 0, &res);
135	if (err)
136		return err;
137
138	priv->base = devm_ioremap_resource(dev, &res);
139	if (IS_ERR(priv->base))
140		return PTR_ERR(priv->base);
141
142	priv->clk = devm_clk_get(&ofdev->dev, NULL);
143	if (IS_ERR(priv->clk))
144		return PTR_ERR(priv->clk);
145
146	priv->rst = devm_reset_control_get(&ofdev->dev, NULL);
147	if (!IS_ERR(priv->rst)) {
148		reset_control_assert(priv->rst);
149		udelay(2);
150		reset_control_deassert(priv->rst);
151	}
152
153	priv->ced = of_property_read_bool(np, "clock-error-detect");
154
155	dev_set_drvdata(dev, priv);
156
157	priv->rng.name = dev_driver_string(dev),
158#ifndef CONFIG_PM
159	priv->rng.init = stm32_rng_init,
160	priv->rng.cleanup = stm32_rng_cleanup,
161#endif
162	priv->rng.read = stm32_rng_read,
163	priv->rng.priv = (unsigned long) dev;
164
165	pm_runtime_set_autosuspend_delay(dev, 100);
166	pm_runtime_use_autosuspend(dev);
167	pm_runtime_enable(dev);
168
169	return devm_hwrng_register(dev, &priv->rng);
170}
171
172#ifdef CONFIG_PM
173static int stm32_rng_runtime_suspend(struct device *dev)
174{
175	struct stm32_rng_private *priv = dev_get_drvdata(dev);
176
177	stm32_rng_cleanup(&priv->rng);
178
179	return 0;
180}
181
182static int stm32_rng_runtime_resume(struct device *dev)
183{
184	struct stm32_rng_private *priv = dev_get_drvdata(dev);
185
186	return stm32_rng_init(&priv->rng);
187}
188#endif
189
190static UNIVERSAL_DEV_PM_OPS(stm32_rng_pm_ops, stm32_rng_runtime_suspend,
191			    stm32_rng_runtime_resume, NULL);
192
193static const struct of_device_id stm32_rng_match[] = {
194	{
195		.compatible = "st,stm32-rng",
196	},
197	{},
198};
199MODULE_DEVICE_TABLE(of, stm32_rng_match);
200
201static struct platform_driver stm32_rng_driver = {
202	.driver = {
203		.name = "stm32-rng",
204		.pm = &stm32_rng_pm_ops,
205		.of_match_table = stm32_rng_match,
206	},
207	.probe = stm32_rng_probe,
208};
209
210module_platform_driver(stm32_rng_driver);
211
212MODULE_LICENSE("GPL");
213MODULE_AUTHOR("Daniel Thompson <daniel.thompson@linaro.org>");
214MODULE_DESCRIPTION("STMicroelectronics STM32 RNG device driver");