2009-12-19 14:45:43 +03:00
/*
* Nomadik RNG support
* Copyright 2009 Alessandro Rubini
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/amba/bus.h>
# include <linux/hw_random.h>
# include <linux/io.h>
2010-05-19 09:49:13 +04:00
# include <linux/clk.h>
# include <linux/err.h>
static struct clk * rng_clk ;
2009-12-19 14:45:43 +03:00
static int nmk_rng_read ( struct hwrng * rng , void * data , size_t max , bool wait )
{
void __iomem * base = ( void __iomem * ) rng - > priv ;
/*
* The register is 32 bits and gives 16 random bits ( low half ) .
* A subsequent read will delay the core for 400 ns , so we just read
* once and accept the very unlikely very small delay , even if wait = = 0.
*/
* ( u16 * ) data = __raw_readl ( base + 8 ) & 0xffff ;
return 2 ;
}
/* we have at most one RNG per machine, granted */
static struct hwrng nmk_rng = {
. name = " nomadik " ,
. read = nmk_rng_read ,
} ;
2011-02-19 18:55:00 +03:00
static int nmk_rng_probe ( struct amba_device * dev , const struct amba_id * id )
2009-12-19 14:45:43 +03:00
{
void __iomem * base ;
int ret ;
2014-02-27 09:06:31 +04:00
rng_clk = devm_clk_get ( & dev - > dev , NULL ) ;
2010-05-19 09:49:13 +04:00
if ( IS_ERR ( rng_clk ) ) {
dev_err ( & dev - > dev , " could not get rng clock \n " ) ;
ret = PTR_ERR ( rng_clk ) ;
return ret ;
}
2013-06-03 04:02:09 +04:00
clk_prepare_enable ( rng_clk ) ;
2010-05-19 09:49:13 +04:00
2009-12-19 14:45:43 +03:00
ret = amba_request_regions ( dev , dev - > dev . init_name ) ;
if ( ret )
2011-06-08 17:00:55 +04:00
goto out_clk ;
2009-12-19 14:45:43 +03:00
ret = - ENOMEM ;
2014-02-27 09:06:31 +04:00
base = devm_ioremap ( & dev - > dev , dev - > res . start ,
resource_size ( & dev - > res ) ) ;
2009-12-19 14:45:43 +03:00
if ( ! base )
goto out_release ;
nmk_rng . priv = ( unsigned long ) base ;
ret = hwrng_register ( & nmk_rng ) ;
if ( ret )
2014-02-27 09:06:31 +04:00
goto out_release ;
2009-12-19 14:45:43 +03:00
return 0 ;
out_release :
amba_release_regions ( dev ) ;
2011-06-08 17:00:55 +04:00
out_clk :
2010-05-19 09:49:13 +04:00
clk_disable ( rng_clk ) ;
2009-12-19 14:45:43 +03:00
return ret ;
}
static int nmk_rng_remove ( struct amba_device * dev )
{
hwrng_unregister ( & nmk_rng ) ;
amba_release_regions ( dev ) ;
2010-05-19 09:49:13 +04:00
clk_disable ( rng_clk ) ;
2009-12-19 14:45:43 +03:00
return 0 ;
}
static struct amba_id nmk_rng_ids [ ] = {
{
. id = 0x000805e1 ,
. mask = 0x000fffff , /* top bits are rev and cfg: accept all */
} ,
{ 0 , 0 } ,
} ;
2011-10-05 18:15:20 +04:00
MODULE_DEVICE_TABLE ( amba , nmk_rng_ids ) ;
2009-12-19 14:45:43 +03:00
static struct amba_driver nmk_rng_driver = {
. drv = {
. owner = THIS_MODULE ,
. name = " rng " ,
} ,
. probe = nmk_rng_probe ,
. remove = nmk_rng_remove ,
. id_table = nmk_rng_ids ,
} ;
2012-03-15 13:40:38 +04:00
module_amba_driver ( nmk_rng_driver ) ;
2009-12-19 14:45:43 +03:00
MODULE_LICENSE ( " GPL " ) ;