1bc85b25eSAlessandro Rubini /* 2bc85b25eSAlessandro Rubini * Nomadik RNG support 3bc85b25eSAlessandro Rubini * Copyright 2009 Alessandro Rubini 4bc85b25eSAlessandro Rubini * 5bc85b25eSAlessandro Rubini * This program is free software; you can redistribute it and/or modify 6bc85b25eSAlessandro Rubini * it under the terms of the GNU General Public License as published by 7bc85b25eSAlessandro Rubini * the Free Software Foundation; either version 2 of the License, or 8bc85b25eSAlessandro Rubini * (at your option) any later version. 9bc85b25eSAlessandro Rubini */ 10bc85b25eSAlessandro Rubini 11bc85b25eSAlessandro Rubini #include <linux/kernel.h> 12bc85b25eSAlessandro Rubini #include <linux/module.h> 13bc85b25eSAlessandro Rubini #include <linux/init.h> 14bc85b25eSAlessandro Rubini #include <linux/device.h> 15bc85b25eSAlessandro Rubini #include <linux/amba/bus.h> 16bc85b25eSAlessandro Rubini #include <linux/hw_random.h> 17bc85b25eSAlessandro Rubini #include <linux/io.h> 181944cc89SSrinidhi Kasagar #include <linux/clk.h> 191944cc89SSrinidhi Kasagar #include <linux/err.h> 201944cc89SSrinidhi Kasagar 211944cc89SSrinidhi Kasagar static struct clk *rng_clk; 22bc85b25eSAlessandro Rubini 23bc85b25eSAlessandro Rubini static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) 24bc85b25eSAlessandro Rubini { 25bc85b25eSAlessandro Rubini void __iomem *base = (void __iomem *)rng->priv; 26bc85b25eSAlessandro Rubini 27bc85b25eSAlessandro Rubini /* 28bc85b25eSAlessandro Rubini * The register is 32 bits and gives 16 random bits (low half). 29bc85b25eSAlessandro Rubini * A subsequent read will delay the core for 400ns, so we just read 30bc85b25eSAlessandro Rubini * once and accept the very unlikely very small delay, even if wait==0. 31bc85b25eSAlessandro Rubini */ 32bc85b25eSAlessandro Rubini *(u16 *)data = __raw_readl(base + 8) & 0xffff; 33bc85b25eSAlessandro Rubini return 2; 34bc85b25eSAlessandro Rubini } 35bc85b25eSAlessandro Rubini 36bc85b25eSAlessandro Rubini /* we have at most one RNG per machine, granted */ 37bc85b25eSAlessandro Rubini static struct hwrng nmk_rng = { 38bc85b25eSAlessandro Rubini .name = "nomadik", 39bc85b25eSAlessandro Rubini .read = nmk_rng_read, 40bc85b25eSAlessandro Rubini }; 41bc85b25eSAlessandro Rubini 42aa25afadSRussell King static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) 43bc85b25eSAlessandro Rubini { 44bc85b25eSAlessandro Rubini void __iomem *base; 45bc85b25eSAlessandro Rubini int ret; 46bc85b25eSAlessandro Rubini 471655c240SJingoo Han rng_clk = devm_clk_get(&dev->dev, NULL); 481944cc89SSrinidhi Kasagar if (IS_ERR(rng_clk)) { 491944cc89SSrinidhi Kasagar dev_err(&dev->dev, "could not get rng clock\n"); 501944cc89SSrinidhi Kasagar ret = PTR_ERR(rng_clk); 511944cc89SSrinidhi Kasagar return ret; 521944cc89SSrinidhi Kasagar } 531944cc89SSrinidhi Kasagar 54beca35d0SLinus Walleij clk_prepare_enable(rng_clk); 551944cc89SSrinidhi Kasagar 56bc85b25eSAlessandro Rubini ret = amba_request_regions(dev, dev->dev.init_name); 57bc85b25eSAlessandro Rubini if (ret) 582725ae17SJulia Lawall goto out_clk; 59bc85b25eSAlessandro Rubini ret = -ENOMEM; 601655c240SJingoo Han base = devm_ioremap(&dev->dev, dev->res.start, 611655c240SJingoo Han resource_size(&dev->res)); 62bc85b25eSAlessandro Rubini if (!base) 63bc85b25eSAlessandro Rubini goto out_release; 64bc85b25eSAlessandro Rubini nmk_rng.priv = (unsigned long)base; 65bc85b25eSAlessandro Rubini ret = hwrng_register(&nmk_rng); 66bc85b25eSAlessandro Rubini if (ret) 671655c240SJingoo Han goto out_release; 68bc85b25eSAlessandro Rubini return 0; 69bc85b25eSAlessandro Rubini 70bc85b25eSAlessandro Rubini out_release: 71bc85b25eSAlessandro Rubini amba_release_regions(dev); 722725ae17SJulia Lawall out_clk: 731944cc89SSrinidhi Kasagar clk_disable(rng_clk); 74bc85b25eSAlessandro Rubini return ret; 75bc85b25eSAlessandro Rubini } 76bc85b25eSAlessandro Rubini 77bc85b25eSAlessandro Rubini static int nmk_rng_remove(struct amba_device *dev) 78bc85b25eSAlessandro Rubini { 79bc85b25eSAlessandro Rubini hwrng_unregister(&nmk_rng); 80bc85b25eSAlessandro Rubini amba_release_regions(dev); 811944cc89SSrinidhi Kasagar clk_disable(rng_clk); 82bc85b25eSAlessandro Rubini return 0; 83bc85b25eSAlessandro Rubini } 84bc85b25eSAlessandro Rubini 85bc85b25eSAlessandro Rubini static struct amba_id nmk_rng_ids[] = { 86bc85b25eSAlessandro Rubini { 87bc85b25eSAlessandro Rubini .id = 0x000805e1, 88bc85b25eSAlessandro Rubini .mask = 0x000fffff, /* top bits are rev and cfg: accept all */ 89bc85b25eSAlessandro Rubini }, 90bc85b25eSAlessandro Rubini {0, 0}, 91bc85b25eSAlessandro Rubini }; 92bc85b25eSAlessandro Rubini 934e3f3d53SDave Martin MODULE_DEVICE_TABLE(amba, nmk_rng_ids); 944e3f3d53SDave Martin 95bc85b25eSAlessandro Rubini static struct amba_driver nmk_rng_driver = { 96bc85b25eSAlessandro Rubini .drv = { 97bc85b25eSAlessandro Rubini .owner = THIS_MODULE, 98bc85b25eSAlessandro Rubini .name = "rng", 99bc85b25eSAlessandro Rubini }, 100bc85b25eSAlessandro Rubini .probe = nmk_rng_probe, 101bc85b25eSAlessandro Rubini .remove = nmk_rng_remove, 102bc85b25eSAlessandro Rubini .id_table = nmk_rng_ids, 103bc85b25eSAlessandro Rubini }; 104bc85b25eSAlessandro Rubini 1059e5ed094Sviresh kumar module_amba_driver(nmk_rng_driver); 106bc85b25eSAlessandro Rubini 107bc85b25eSAlessandro Rubini MODULE_LICENSE("GPL"); 108