diff options
Diffstat (limited to 'drivers/char/hw_random/omap-rng.c')
-rw-r--r-- | drivers/char/hw_random/omap-rng.c | 386 |
1 files changed, 315 insertions, 71 deletions
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 6843ec87b98b..9b89ff4881de 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c | |||
@@ -24,57 +24,131 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/of.h> | ||
28 | #include <linux/of_device.h> | ||
29 | #include <linux/of_address.h> | ||
30 | #include <linux/interrupt.h> | ||
27 | 31 | ||
28 | #include <asm/io.h> | 32 | #include <asm/io.h> |
29 | 33 | ||
30 | #define RNG_OUT_REG 0x00 /* Output register */ | 34 | #define RNG_REG_STATUS_RDY (1 << 0) |
31 | #define RNG_STAT_REG 0x04 /* Status register | 35 | |
32 | [0] = STAT_BUSY */ | 36 | #define RNG_REG_INTACK_RDY_MASK (1 << 0) |
33 | #define RNG_ALARM_REG 0x24 /* Alarm register | 37 | #define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK (1 << 1) |
34 | [7:0] = ALARM_COUNTER */ | 38 | #define RNG_SHUTDOWN_OFLO_MASK (1 << 1) |
35 | #define RNG_CONFIG_REG 0x28 /* Configuration register | 39 | |
36 | [11:6] = RESET_COUNT | 40 | #define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16 |
37 | [5:3] = RING2_DELAY | 41 | #define RNG_CONTROL_STARTUP_CYCLES_MASK (0xffff << 16) |
38 | [2:0] = RING1_DELAY */ | 42 | #define RNG_CONTROL_ENABLE_TRNG_SHIFT 10 |
39 | #define RNG_REV_REG 0x3c /* Revision register | 43 | #define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10) |
40 | [7:0] = REV_NB */ | 44 | |
41 | #define RNG_MASK_REG 0x40 /* Mask and reset register | 45 | #define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16 |
42 | [2] = IT_EN | 46 | #define RNG_CONFIG_MAX_REFIL_CYCLES_MASK (0xffff << 16) |
43 | [1] = SOFTRESET | 47 | #define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0 |
44 | [0] = AUTOIDLE */ | 48 | #define RNG_CONFIG_MIN_REFIL_CYCLES_MASK (0xff << 0) |
45 | #define RNG_SYSSTATUS 0x44 /* System status | 49 | |
46 | [0] = RESETDONE */ | 50 | #define RNG_CONTROL_STARTUP_CYCLES 0xff |
51 | #define RNG_CONFIG_MIN_REFIL_CYCLES 0x21 | ||
52 | #define RNG_CONFIG_MAX_REFIL_CYCLES 0x22 | ||
53 | |||
54 | #define RNG_ALARMCNT_ALARM_TH_SHIFT 0x0 | ||
55 | #define RNG_ALARMCNT_ALARM_TH_MASK (0xff << 0) | ||
56 | #define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16 | ||
57 | #define RNG_ALARMCNT_SHUTDOWN_TH_MASK (0x1f << 16) | ||
58 | #define RNG_ALARM_THRESHOLD 0xff | ||
59 | #define RNG_SHUTDOWN_THRESHOLD 0x4 | ||
60 | |||
61 | #define RNG_REG_FROENABLE_MASK 0xffffff | ||
62 | #define RNG_REG_FRODETUNE_MASK 0xffffff | ||
63 | |||
64 | #define OMAP2_RNG_OUTPUT_SIZE 0x4 | ||
65 | #define OMAP4_RNG_OUTPUT_SIZE 0x8 | ||
66 | |||
67 | enum { | ||
68 | RNG_OUTPUT_L_REG = 0, | ||
69 | RNG_OUTPUT_H_REG, | ||
70 | RNG_STATUS_REG, | ||
71 | RNG_INTMASK_REG, | ||
72 | RNG_INTACK_REG, | ||
73 | RNG_CONTROL_REG, | ||
74 | RNG_CONFIG_REG, | ||
75 | RNG_ALARMCNT_REG, | ||
76 | RNG_FROENABLE_REG, | ||
77 | RNG_FRODETUNE_REG, | ||
78 | RNG_ALARMMASK_REG, | ||
79 | RNG_ALARMSTOP_REG, | ||
80 | RNG_REV_REG, | ||
81 | RNG_SYSCONFIG_REG, | ||
82 | }; | ||
83 | |||
84 | static const u16 reg_map_omap2[] = { | ||
85 | [RNG_OUTPUT_L_REG] = 0x0, | ||
86 | [RNG_STATUS_REG] = 0x4, | ||
87 | [RNG_CONFIG_REG] = 0x28, | ||
88 | [RNG_REV_REG] = 0x3c, | ||
89 | [RNG_SYSCONFIG_REG] = 0x40, | ||
90 | }; | ||
47 | 91 | ||
92 | static const u16 reg_map_omap4[] = { | ||
93 | [RNG_OUTPUT_L_REG] = 0x0, | ||
94 | [RNG_OUTPUT_H_REG] = 0x4, | ||
95 | [RNG_STATUS_REG] = 0x8, | ||
96 | [RNG_INTMASK_REG] = 0xc, | ||
97 | [RNG_INTACK_REG] = 0x10, | ||
98 | [RNG_CONTROL_REG] = 0x14, | ||
99 | [RNG_CONFIG_REG] = 0x18, | ||
100 | [RNG_ALARMCNT_REG] = 0x1c, | ||
101 | [RNG_FROENABLE_REG] = 0x20, | ||
102 | [RNG_FRODETUNE_REG] = 0x24, | ||
103 | [RNG_ALARMMASK_REG] = 0x28, | ||
104 | [RNG_ALARMSTOP_REG] = 0x2c, | ||
105 | [RNG_REV_REG] = 0x1FE0, | ||
106 | [RNG_SYSCONFIG_REG] = 0x1FE4, | ||
107 | }; | ||
108 | |||
109 | struct omap_rng_dev; | ||
48 | /** | 110 | /** |
49 | * struct omap_rng_private_data - RNG IP block-specific data | 111 | * struct omap_rng_pdata - RNG IP block-specific data |
50 | * @base: virtual address of the beginning of the RNG IP block registers | 112 | * @regs: Pointer to the register offsets structure. |
51 | * @mem_res: struct resource * for the IP block registers physical memory | 113 | * @data_size: No. of bytes in RNG output. |
114 | * @data_present: Callback to determine if data is available. | ||
115 | * @init: Callback for IP specific initialization sequence. | ||
116 | * @cleanup: Callback for IP specific cleanup sequence. | ||
52 | */ | 117 | */ |
53 | struct omap_rng_private_data { | 118 | struct omap_rng_pdata { |
54 | void __iomem *base; | 119 | u16 *regs; |
55 | struct resource *mem_res; | 120 | u32 data_size; |
121 | u32 (*data_present)(struct omap_rng_dev *priv); | ||
122 | int (*init)(struct omap_rng_dev *priv); | ||
123 | void (*cleanup)(struct omap_rng_dev *priv); | ||
56 | }; | 124 | }; |
57 | 125 | ||
58 | static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg) | 126 | struct omap_rng_dev { |
127 | void __iomem *base; | ||
128 | struct device *dev; | ||
129 | const struct omap_rng_pdata *pdata; | ||
130 | }; | ||
131 | |||
132 | static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg) | ||
59 | { | 133 | { |
60 | return __raw_readl(priv->base + reg); | 134 | return __raw_readl(priv->base + priv->pdata->regs[reg]); |
61 | } | 135 | } |
62 | 136 | ||
63 | static inline void omap_rng_write_reg(struct omap_rng_private_data *priv, | 137 | static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg, |
64 | int reg, u32 val) | 138 | u32 val) |
65 | { | 139 | { |
66 | __raw_writel(val, priv->base + reg); | 140 | __raw_writel(val, priv->base + priv->pdata->regs[reg]); |
67 | } | 141 | } |
68 | 142 | ||
69 | static int omap_rng_data_present(struct hwrng *rng, int wait) | 143 | static int omap_rng_data_present(struct hwrng *rng, int wait) |
70 | { | 144 | { |
71 | struct omap_rng_private_data *priv; | 145 | struct omap_rng_dev *priv; |
72 | int data, i; | 146 | int data, i; |
73 | 147 | ||
74 | priv = (struct omap_rng_private_data *)rng->priv; | 148 | priv = (struct omap_rng_dev *)rng->priv; |
75 | 149 | ||
76 | for (i = 0; i < 20; i++) { | 150 | for (i = 0; i < 20; i++) { |
77 | data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1; | 151 | data = priv->pdata->data_present(priv); |
78 | if (data || !wait) | 152 | if (data || !wait) |
79 | break; | 153 | break; |
80 | /* RNG produces data fast enough (2+ MBit/sec, even | 154 | /* RNG produces data fast enough (2+ MBit/sec, even |
@@ -89,27 +163,212 @@ static int omap_rng_data_present(struct hwrng *rng, int wait) | |||
89 | 163 | ||
90 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) | 164 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) |
91 | { | 165 | { |
92 | struct omap_rng_private_data *priv; | 166 | struct omap_rng_dev *priv; |
167 | u32 data_size, i; | ||
168 | |||
169 | priv = (struct omap_rng_dev *)rng->priv; | ||
170 | data_size = priv->pdata->data_size; | ||
171 | |||
172 | for (i = 0; i < data_size / sizeof(u32); i++) | ||
173 | data[i] = omap_rng_read(priv, RNG_OUTPUT_L_REG + i); | ||
174 | |||
175 | if (priv->pdata->regs[RNG_INTACK_REG]) | ||
176 | omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK); | ||
177 | return data_size; | ||
178 | } | ||
179 | |||
180 | static int omap_rng_init(struct hwrng *rng) | ||
181 | { | ||
182 | struct omap_rng_dev *priv; | ||
93 | 183 | ||
94 | priv = (struct omap_rng_private_data *)rng->priv; | 184 | priv = (struct omap_rng_dev *)rng->priv; |
185 | return priv->pdata->init(priv); | ||
186 | } | ||
95 | 187 | ||
96 | *data = omap_rng_read_reg(priv, RNG_OUT_REG); | 188 | static void omap_rng_cleanup(struct hwrng *rng) |
189 | { | ||
190 | struct omap_rng_dev *priv; | ||
97 | 191 | ||
98 | return sizeof(u32); | 192 | priv = (struct omap_rng_dev *)rng->priv; |
193 | priv->pdata->cleanup(priv); | ||
99 | } | 194 | } |
100 | 195 | ||
101 | static struct hwrng omap_rng_ops = { | 196 | static struct hwrng omap_rng_ops = { |
102 | .name = "omap", | 197 | .name = "omap", |
103 | .data_present = omap_rng_data_present, | 198 | .data_present = omap_rng_data_present, |
104 | .data_read = omap_rng_data_read, | 199 | .data_read = omap_rng_data_read, |
200 | .init = omap_rng_init, | ||
201 | .cleanup = omap_rng_cleanup, | ||
202 | }; | ||
203 | |||
204 | static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv) | ||
205 | { | ||
206 | return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1; | ||
207 | } | ||
208 | |||
209 | static int omap2_rng_init(struct omap_rng_dev *priv) | ||
210 | { | ||
211 | omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static void omap2_rng_cleanup(struct omap_rng_dev *priv) | ||
216 | { | ||
217 | omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0); | ||
218 | } | ||
219 | |||
220 | static struct omap_rng_pdata omap2_rng_pdata = { | ||
221 | .regs = (u16 *)reg_map_omap2, | ||
222 | .data_size = OMAP2_RNG_OUTPUT_SIZE, | ||
223 | .data_present = omap2_rng_data_present, | ||
224 | .init = omap2_rng_init, | ||
225 | .cleanup = omap2_rng_cleanup, | ||
105 | }; | 226 | }; |
106 | 227 | ||
228 | #if defined(CONFIG_OF) | ||
229 | static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv) | ||
230 | { | ||
231 | return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY; | ||
232 | } | ||
233 | |||
234 | static int omap4_rng_init(struct omap_rng_dev *priv) | ||
235 | { | ||
236 | u32 val; | ||
237 | |||
238 | /* Return if RNG is already running. */ | ||
239 | if (omap_rng_read(priv, RNG_CONFIG_REG) & RNG_CONTROL_ENABLE_TRNG_MASK) | ||
240 | return 0; | ||
241 | |||
242 | val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; | ||
243 | val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; | ||
244 | omap_rng_write(priv, RNG_CONFIG_REG, val); | ||
245 | |||
246 | omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0); | ||
247 | omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK); | ||
248 | val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT; | ||
249 | val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT; | ||
250 | omap_rng_write(priv, RNG_ALARMCNT_REG, val); | ||
251 | |||
252 | val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT; | ||
253 | val |= RNG_CONTROL_ENABLE_TRNG_MASK; | ||
254 | omap_rng_write(priv, RNG_CONTROL_REG, val); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static void omap4_rng_cleanup(struct omap_rng_dev *priv) | ||
260 | { | ||
261 | int val; | ||
262 | |||
263 | val = omap_rng_read(priv, RNG_CONTROL_REG); | ||
264 | val &= ~RNG_CONTROL_ENABLE_TRNG_MASK; | ||
265 | omap_rng_write(priv, RNG_CONFIG_REG, val); | ||
266 | } | ||
267 | |||
268 | static irqreturn_t omap4_rng_irq(int irq, void *dev_id) | ||
269 | { | ||
270 | struct omap_rng_dev *priv = dev_id; | ||
271 | u32 fro_detune, fro_enable; | ||
272 | |||
273 | /* | ||
274 | * Interrupt raised by a fro shutdown threshold, do the following: | ||
275 | * 1. Clear the alarm events. | ||
276 | * 2. De tune the FROs which are shutdown. | ||
277 | * 3. Re enable the shutdown FROs. | ||
278 | */ | ||
279 | omap_rng_write(priv, RNG_ALARMMASK_REG, 0x0); | ||
280 | omap_rng_write(priv, RNG_ALARMSTOP_REG, 0x0); | ||
281 | |||
282 | fro_enable = omap_rng_read(priv, RNG_FROENABLE_REG); | ||
283 | fro_detune = ~fro_enable & RNG_REG_FRODETUNE_MASK; | ||
284 | fro_detune = fro_detune | omap_rng_read(priv, RNG_FRODETUNE_REG); | ||
285 | fro_enable = RNG_REG_FROENABLE_MASK; | ||
286 | |||
287 | omap_rng_write(priv, RNG_FRODETUNE_REG, fro_detune); | ||
288 | omap_rng_write(priv, RNG_FROENABLE_REG, fro_enable); | ||
289 | |||
290 | omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_SHUTDOWN_OFLO_MASK); | ||
291 | |||
292 | return IRQ_HANDLED; | ||
293 | } | ||
294 | |||
295 | static struct omap_rng_pdata omap4_rng_pdata = { | ||
296 | .regs = (u16 *)reg_map_omap4, | ||
297 | .data_size = OMAP4_RNG_OUTPUT_SIZE, | ||
298 | .data_present = omap4_rng_data_present, | ||
299 | .init = omap4_rng_init, | ||
300 | .cleanup = omap4_rng_cleanup, | ||
301 | }; | ||
302 | |||
303 | static const struct of_device_id omap_rng_of_match[] = { | ||
304 | { | ||
305 | .compatible = "ti,omap2-rng", | ||
306 | .data = &omap2_rng_pdata, | ||
307 | }, | ||
308 | { | ||
309 | .compatible = "ti,omap4-rng", | ||
310 | .data = &omap4_rng_pdata, | ||
311 | }, | ||
312 | {}, | ||
313 | }; | ||
314 | MODULE_DEVICE_TABLE(of, omap_rng_of_match); | ||
315 | |||
316 | static int of_get_omap_rng_device_details(struct omap_rng_dev *priv, | ||
317 | struct platform_device *pdev) | ||
318 | { | ||
319 | const struct of_device_id *match; | ||
320 | struct device *dev = &pdev->dev; | ||
321 | int irq, err; | ||
322 | |||
323 | match = of_match_device(of_match_ptr(omap_rng_of_match), dev); | ||
324 | if (!match) { | ||
325 | dev_err(dev, "no compatible OF match\n"); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | priv->pdata = match->data; | ||
329 | |||
330 | if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) { | ||
331 | irq = platform_get_irq(pdev, 0); | ||
332 | if (irq < 0) { | ||
333 | dev_err(dev, "%s: error getting IRQ resource - %d\n", | ||
334 | __func__, irq); | ||
335 | return irq; | ||
336 | } | ||
337 | |||
338 | err = devm_request_irq(dev, irq, omap4_rng_irq, | ||
339 | IRQF_TRIGGER_NONE, dev_name(dev), priv); | ||
340 | if (err) { | ||
341 | dev_err(dev, "unable to request irq %d, err = %d\n", | ||
342 | irq, err); | ||
343 | return err; | ||
344 | } | ||
345 | omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK); | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | #else | ||
350 | static int of_get_omap_rng_device_details(struct omap_rng_dev *omap_rng, | ||
351 | struct platform_device *pdev) | ||
352 | { | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | #endif | ||
356 | |||
357 | static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng) | ||
358 | { | ||
359 | /* Only OMAP2/3 can be non-DT */ | ||
360 | omap_rng->pdata = &omap2_rng_pdata; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
107 | static int omap_rng_probe(struct platform_device *pdev) | 364 | static int omap_rng_probe(struct platform_device *pdev) |
108 | { | 365 | { |
109 | struct omap_rng_private_data *priv; | 366 | struct omap_rng_dev *priv; |
367 | struct resource *res; | ||
368 | struct device *dev = &pdev->dev; | ||
110 | int ret; | 369 | int ret; |
111 | 370 | ||
112 | priv = kzalloc(sizeof(struct omap_rng_private_data), GFP_KERNEL); | 371 | priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL); |
113 | if (!priv) { | 372 | if (!priv) { |
114 | dev_err(&pdev->dev, "could not allocate memory\n"); | 373 | dev_err(&pdev->dev, "could not allocate memory\n"); |
115 | return -ENOMEM; | 374 | return -ENOMEM; |
@@ -117,26 +376,29 @@ static int omap_rng_probe(struct platform_device *pdev) | |||
117 | 376 | ||
118 | omap_rng_ops.priv = (unsigned long)priv; | 377 | omap_rng_ops.priv = (unsigned long)priv; |
119 | platform_set_drvdata(pdev, priv); | 378 | platform_set_drvdata(pdev, priv); |
379 | priv->dev = dev; | ||
120 | 380 | ||
121 | priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 381 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
122 | priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res); | 382 | priv->base = devm_ioremap_resource(dev, res); |
123 | if (IS_ERR(priv->base)) { | 383 | if (IS_ERR(priv->base)) { |
124 | ret = PTR_ERR(priv->base); | 384 | ret = PTR_ERR(priv->base); |
125 | goto err_ioremap; | 385 | goto err_ioremap; |
126 | } | 386 | } |
127 | platform_set_drvdata(pdev, priv); | ||
128 | 387 | ||
129 | pm_runtime_enable(&pdev->dev); | 388 | pm_runtime_enable(&pdev->dev); |
130 | pm_runtime_get_sync(&pdev->dev); | 389 | pm_runtime_get_sync(&pdev->dev); |
131 | 390 | ||
391 | ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) : | ||
392 | get_omap_rng_device_details(priv); | ||
393 | if (ret) | ||
394 | goto err_ioremap; | ||
395 | |||
132 | ret = hwrng_register(&omap_rng_ops); | 396 | ret = hwrng_register(&omap_rng_ops); |
133 | if (ret) | 397 | if (ret) |
134 | goto err_register; | 398 | goto err_register; |
135 | 399 | ||
136 | dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", | 400 | dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", |
137 | omap_rng_read_reg(priv, RNG_REV_REG)); | 401 | omap_rng_read(priv, RNG_REV_REG)); |
138 | |||
139 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); | ||
140 | 402 | ||
141 | return 0; | 403 | return 0; |
142 | 404 | ||
@@ -144,26 +406,21 @@ err_register: | |||
144 | priv->base = NULL; | 406 | priv->base = NULL; |
145 | pm_runtime_disable(&pdev->dev); | 407 | pm_runtime_disable(&pdev->dev); |
146 | err_ioremap: | 408 | err_ioremap: |
147 | kfree(priv); | 409 | dev_err(dev, "initialization failed.\n"); |
148 | |||
149 | return ret; | 410 | return ret; |
150 | } | 411 | } |
151 | 412 | ||
152 | static int __exit omap_rng_remove(struct platform_device *pdev) | 413 | static int __exit omap_rng_remove(struct platform_device *pdev) |
153 | { | 414 | { |
154 | struct omap_rng_private_data *priv = platform_get_drvdata(pdev); | 415 | struct omap_rng_dev *priv = platform_get_drvdata(pdev); |
155 | 416 | ||
156 | hwrng_unregister(&omap_rng_ops); | 417 | hwrng_unregister(&omap_rng_ops); |
157 | 418 | ||
158 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); | 419 | priv->pdata->cleanup(priv); |
159 | 420 | ||
160 | pm_runtime_put_sync(&pdev->dev); | 421 | pm_runtime_put_sync(&pdev->dev); |
161 | pm_runtime_disable(&pdev->dev); | 422 | pm_runtime_disable(&pdev->dev); |
162 | 423 | ||
163 | release_mem_region(priv->mem_res->start, resource_size(priv->mem_res)); | ||
164 | |||
165 | kfree(priv); | ||
166 | |||
167 | return 0; | 424 | return 0; |
168 | } | 425 | } |
169 | 426 | ||
@@ -171,9 +428,9 @@ static int __exit omap_rng_remove(struct platform_device *pdev) | |||
171 | 428 | ||
172 | static int omap_rng_suspend(struct device *dev) | 429 | static int omap_rng_suspend(struct device *dev) |
173 | { | 430 | { |
174 | struct omap_rng_private_data *priv = dev_get_drvdata(dev); | 431 | struct omap_rng_dev *priv = dev_get_drvdata(dev); |
175 | 432 | ||
176 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); | 433 | priv->pdata->cleanup(priv); |
177 | pm_runtime_put_sync(dev); | 434 | pm_runtime_put_sync(dev); |
178 | 435 | ||
179 | return 0; | 436 | return 0; |
@@ -181,10 +438,10 @@ static int omap_rng_suspend(struct device *dev) | |||
181 | 438 | ||
182 | static int omap_rng_resume(struct device *dev) | 439 | static int omap_rng_resume(struct device *dev) |
183 | { | 440 | { |
184 | struct omap_rng_private_data *priv = dev_get_drvdata(dev); | 441 | struct omap_rng_dev *priv = dev_get_drvdata(dev); |
185 | 442 | ||
186 | pm_runtime_get_sync(dev); | 443 | pm_runtime_get_sync(dev); |
187 | omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); | 444 | priv->pdata->init(priv); |
188 | 445 | ||
189 | return 0; | 446 | return 0; |
190 | } | 447 | } |
@@ -198,31 +455,18 @@ static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume); | |||
198 | 455 | ||
199 | #endif | 456 | #endif |
200 | 457 | ||
201 | /* work with hotplug and coldplug */ | ||
202 | MODULE_ALIAS("platform:omap_rng"); | ||
203 | |||
204 | static struct platform_driver omap_rng_driver = { | 458 | static struct platform_driver omap_rng_driver = { |
205 | .driver = { | 459 | .driver = { |
206 | .name = "omap_rng", | 460 | .name = "omap_rng", |
207 | .owner = THIS_MODULE, | 461 | .owner = THIS_MODULE, |
208 | .pm = OMAP_RNG_PM, | 462 | .pm = OMAP_RNG_PM, |
463 | .of_match_table = of_match_ptr(omap_rng_of_match), | ||
209 | }, | 464 | }, |
210 | .probe = omap_rng_probe, | 465 | .probe = omap_rng_probe, |
211 | .remove = __exit_p(omap_rng_remove), | 466 | .remove = __exit_p(omap_rng_remove), |
212 | }; | 467 | }; |
213 | 468 | ||
214 | static int __init omap_rng_init(void) | 469 | module_platform_driver(omap_rng_driver); |
215 | { | 470 | MODULE_ALIAS("platform:omap_rng"); |
216 | return platform_driver_register(&omap_rng_driver); | ||
217 | } | ||
218 | |||
219 | static void __exit omap_rng_exit(void) | ||
220 | { | ||
221 | platform_driver_unregister(&omap_rng_driver); | ||
222 | } | ||
223 | |||
224 | module_init(omap_rng_init); | ||
225 | module_exit(omap_rng_exit); | ||
226 | |||
227 | MODULE_AUTHOR("Deepak Saxena (and others)"); | 471 | MODULE_AUTHOR("Deepak Saxena (and others)"); |
228 | MODULE_LICENSE("GPL"); | 472 | MODULE_LICENSE("GPL"); |