diff options
-rw-r--r-- | drivers/char/hw_random/mxc-rnga.c | 108 |
1 files changed, 51 insertions, 57 deletions
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index 62c7efe375ab..f05d85713fd3 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c | |||
@@ -59,16 +59,21 @@ | |||
59 | #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 | 59 | #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 |
60 | #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 | 60 | #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 |
61 | 61 | ||
62 | static struct platform_device *rng_dev; | 62 | struct mxc_rng { |
63 | struct device *dev; | ||
64 | struct hwrng rng; | ||
65 | void __iomem *mem; | ||
66 | struct clk *clk; | ||
67 | }; | ||
63 | 68 | ||
64 | static int mxc_rnga_data_present(struct hwrng *rng, int wait) | 69 | static int mxc_rnga_data_present(struct hwrng *rng, int wait) |
65 | { | 70 | { |
66 | void __iomem *rng_base = (void __iomem *)rng->priv; | ||
67 | int i; | 71 | int i; |
72 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); | ||
68 | 73 | ||
69 | for (i = 0; i < 20; i++) { | 74 | for (i = 0; i < 20; i++) { |
70 | /* how many random numbers are in FIFO? [0-16] */ | 75 | /* how many random numbers are in FIFO? [0-16] */ |
71 | int level = (__raw_readl(rng_base + RNGA_STATUS) & | 76 | int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) & |
72 | RNGA_STATUS_LEVEL_MASK) >> 8; | 77 | RNGA_STATUS_LEVEL_MASK) >> 8; |
73 | if (level || !wait) | 78 | if (level || !wait) |
74 | return !!level; | 79 | return !!level; |
@@ -81,20 +86,20 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) | |||
81 | { | 86 | { |
82 | int err; | 87 | int err; |
83 | u32 ctrl; | 88 | u32 ctrl; |
84 | void __iomem *rng_base = (void __iomem *)rng->priv; | 89 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
85 | 90 | ||
86 | /* retrieve a random number from FIFO */ | 91 | /* retrieve a random number from FIFO */ |
87 | *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO); | 92 | *data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO); |
88 | 93 | ||
89 | /* some error while reading this random number? */ | 94 | /* some error while reading this random number? */ |
90 | err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; | 95 | err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; |
91 | 96 | ||
92 | /* if error: clear error interrupt, but doesn't return random number */ | 97 | /* if error: clear error interrupt, but doesn't return random number */ |
93 | if (err) { | 98 | if (err) { |
94 | dev_dbg(&rng_dev->dev, "Error while reading random number!\n"); | 99 | dev_dbg(mxc_rng->dev, "Error while reading random number!\n"); |
95 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 100 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
96 | __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, | 101 | __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, |
97 | rng_base + RNGA_CONTROL); | 102 | mxc_rng->mem + RNGA_CONTROL); |
98 | return 0; | 103 | return 0; |
99 | } else | 104 | } else |
100 | return 4; | 105 | return 4; |
@@ -103,22 +108,22 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) | |||
103 | static int mxc_rnga_init(struct hwrng *rng) | 108 | static int mxc_rnga_init(struct hwrng *rng) |
104 | { | 109 | { |
105 | u32 ctrl, osc; | 110 | u32 ctrl, osc; |
106 | void __iomem *rng_base = (void __iomem *)rng->priv; | 111 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
107 | 112 | ||
108 | /* wake up */ | 113 | /* wake up */ |
109 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 114 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
110 | __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL); | 115 | __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL); |
111 | 116 | ||
112 | /* verify if oscillator is working */ | 117 | /* verify if oscillator is working */ |
113 | osc = __raw_readl(rng_base + RNGA_STATUS); | 118 | osc = __raw_readl(mxc_rng->mem + RNGA_STATUS); |
114 | if (osc & RNGA_STATUS_OSC_DEAD) { | 119 | if (osc & RNGA_STATUS_OSC_DEAD) { |
115 | dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n"); | 120 | dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n"); |
116 | return -ENODEV; | 121 | return -ENODEV; |
117 | } | 122 | } |
118 | 123 | ||
119 | /* go running */ | 124 | /* go running */ |
120 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 125 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
121 | __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); | 126 | __raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); |
122 | 127 | ||
123 | return 0; | 128 | return 0; |
124 | } | 129 | } |
@@ -126,40 +131,40 @@ static int mxc_rnga_init(struct hwrng *rng) | |||
126 | static void mxc_rnga_cleanup(struct hwrng *rng) | 131 | static void mxc_rnga_cleanup(struct hwrng *rng) |
127 | { | 132 | { |
128 | u32 ctrl; | 133 | u32 ctrl; |
129 | void __iomem *rng_base = (void __iomem *)rng->priv; | 134 | struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); |
130 | 135 | ||
131 | ctrl = __raw_readl(rng_base + RNGA_CONTROL); | 136 | ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); |
132 | 137 | ||
133 | /* stop rnga */ | 138 | /* stop rnga */ |
134 | __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); | 139 | __raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); |
135 | } | 140 | } |
136 | 141 | ||
137 | static struct hwrng mxc_rnga = { | ||
138 | .name = "mxc-rnga", | ||
139 | .init = mxc_rnga_init, | ||
140 | .cleanup = mxc_rnga_cleanup, | ||
141 | .data_present = mxc_rnga_data_present, | ||
142 | .data_read = mxc_rnga_data_read | ||
143 | }; | ||
144 | |||
145 | static int __init mxc_rnga_probe(struct platform_device *pdev) | 142 | static int __init mxc_rnga_probe(struct platform_device *pdev) |
146 | { | 143 | { |
147 | int err = -ENODEV; | 144 | int err = -ENODEV; |
148 | struct clk *clk; | ||
149 | struct resource *res, *mem; | 145 | struct resource *res, *mem; |
150 | void __iomem *rng_base = NULL; | 146 | struct mxc_rng *mxc_rng; |
151 | 147 | ||
152 | if (rng_dev) | 148 | mxc_rng = devm_kzalloc(&pdev->dev, sizeof(struct mxc_rng), |
153 | return -EBUSY; | 149 | GFP_KERNEL); |
154 | 150 | if (!mxc_rng) | |
155 | clk = clk_get(&pdev->dev, NULL); | 151 | return -ENOMEM; |
156 | if (IS_ERR(clk)) { | 152 | |
153 | mxc_rng->dev = &pdev->dev; | ||
154 | mxc_rng->rng.name = "mxc-rnga"; | ||
155 | mxc_rng->rng.init = mxc_rnga_init; | ||
156 | mxc_rng->rng.cleanup = mxc_rnga_cleanup, | ||
157 | mxc_rng->rng.data_present = mxc_rnga_data_present, | ||
158 | mxc_rng->rng.data_read = mxc_rnga_data_read, | ||
159 | |||
160 | mxc_rng->clk = devm_clk_get(&pdev->dev, NULL); | ||
161 | if (IS_ERR(mxc_rng->clk)) { | ||
157 | dev_err(&pdev->dev, "Could not get rng_clk!\n"); | 162 | dev_err(&pdev->dev, "Could not get rng_clk!\n"); |
158 | err = PTR_ERR(clk); | 163 | err = PTR_ERR(mxc_rng->clk); |
159 | goto out; | 164 | goto out; |
160 | } | 165 | } |
161 | 166 | ||
162 | clk_prepare_enable(clk); | 167 | clk_prepare_enable(mxc_rng->clk); |
163 | 168 | ||
164 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
165 | if (!res) { | 170 | if (!res) { |
@@ -173,36 +178,27 @@ static int __init mxc_rnga_probe(struct platform_device *pdev) | |||
173 | goto err_region; | 178 | goto err_region; |
174 | } | 179 | } |
175 | 180 | ||
176 | rng_base = ioremap(res->start, resource_size(res)); | 181 | mxc_rng->mem = ioremap(res->start, resource_size(res)); |
177 | if (!rng_base) { | 182 | if (!mxc_rng->mem) { |
178 | err = -ENOMEM; | 183 | err = -ENOMEM; |
179 | goto err_ioremap; | 184 | goto err_ioremap; |
180 | } | 185 | } |
181 | 186 | ||
182 | mxc_rnga.priv = (unsigned long)rng_base; | 187 | err = hwrng_register(&mxc_rng->rng); |
183 | |||
184 | err = hwrng_register(&mxc_rnga); | ||
185 | if (err) { | 188 | if (err) { |
186 | dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); | 189 | dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); |
187 | goto err_register; | 190 | goto err_ioremap; |
188 | } | 191 | } |
189 | 192 | ||
190 | rng_dev = pdev; | ||
191 | |||
192 | dev_info(&pdev->dev, "MXC RNGA Registered.\n"); | 193 | dev_info(&pdev->dev, "MXC RNGA Registered.\n"); |
193 | 194 | ||
194 | return 0; | 195 | return 0; |
195 | 196 | ||
196 | err_register: | ||
197 | iounmap(rng_base); | ||
198 | rng_base = NULL; | ||
199 | |||
200 | err_ioremap: | 197 | err_ioremap: |
201 | release_mem_region(res->start, resource_size(res)); | 198 | release_mem_region(res->start, resource_size(res)); |
202 | 199 | ||
203 | err_region: | 200 | err_region: |
204 | clk_disable_unprepare(clk); | 201 | clk_disable_unprepare(mxc_rng->clk); |
205 | clk_put(clk); | ||
206 | 202 | ||
207 | out: | 203 | out: |
208 | return err; | 204 | return err; |
@@ -211,17 +207,15 @@ out: | |||
211 | static int __exit mxc_rnga_remove(struct platform_device *pdev) | 207 | static int __exit mxc_rnga_remove(struct platform_device *pdev) |
212 | { | 208 | { |
213 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 209 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
214 | void __iomem *rng_base = (void __iomem *)mxc_rnga.priv; | 210 | struct mxc_rng *mxc_rng = platform_get_drvdata(pdev); |
215 | struct clk *clk = clk_get(&pdev->dev, NULL); | ||
216 | 211 | ||
217 | hwrng_unregister(&mxc_rnga); | 212 | hwrng_unregister(&mxc_rng->rng); |
218 | 213 | ||
219 | iounmap(rng_base); | 214 | iounmap(mxc_rng->mem); |
220 | 215 | ||
221 | release_mem_region(res->start, resource_size(res)); | 216 | release_mem_region(res->start, resource_size(res)); |
222 | 217 | ||
223 | clk_disable_unprepare(clk); | 218 | clk_disable_unprepare(mxc_rng->clk); |
224 | clk_put(clk); | ||
225 | 219 | ||
226 | return 0; | 220 | return 0; |
227 | } | 221 | } |