2019-05-20 15:59:19 +02:00
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2016-06-10 10:21:53 +02:00
/*
* Copyright ( c ) 2016 BayLibre , SAS .
* Author : Neil Armstrong < narmstrong @ baylibre . com >
* Copyright ( C ) 2014 Amlogic , Inc .
*/
# include <linux/err.h>
# include <linux/module.h>
# include <linux/io.h>
# include <linux/platform_device.h>
# include <linux/hw_random.h>
# include <linux/slab.h>
# include <linux/types.h>
# include <linux/of.h>
2017-02-22 08:02:31 +01:00
# include <linux/clk.h>
2016-06-10 10:21:53 +02:00
# define RNG_DATA 0x00
struct meson_rng_data {
void __iomem * base ;
struct platform_device * pdev ;
struct hwrng rng ;
2017-02-22 08:02:31 +01:00
struct clk * core_clk ;
2016-06-10 10:21:53 +02:00
} ;
static int meson_rng_read ( struct hwrng * rng , void * buf , size_t max , bool wait )
{
struct meson_rng_data * data =
container_of ( rng , struct meson_rng_data , rng ) ;
* ( u32 * ) buf = readl_relaxed ( data - > base + RNG_DATA ) ;
return sizeof ( u32 ) ;
}
2017-02-22 08:02:31 +01:00
static void meson_rng_clk_disable ( void * data )
{
clk_disable_unprepare ( data ) ;
}
2016-06-10 10:21:53 +02:00
static int meson_rng_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct meson_rng_data * data ;
2017-02-22 08:02:31 +01:00
int ret ;
2016-06-10 10:21:53 +02:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > pdev = pdev ;
2019-10-16 18:46:14 +08:00
data - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2016-06-10 10:21:53 +02:00
if ( IS_ERR ( data - > base ) )
return PTR_ERR ( data - > base ) ;
2017-02-22 08:02:31 +01:00
data - > core_clk = devm_clk_get ( dev , " core " ) ;
if ( IS_ERR ( data - > core_clk ) )
data - > core_clk = NULL ;
if ( data - > core_clk ) {
ret = clk_prepare_enable ( data - > core_clk ) ;
if ( ret )
return ret ;
ret = devm_add_action_or_reset ( dev , meson_rng_clk_disable ,
data - > core_clk ) ;
if ( ret )
return ret ;
}
2016-06-10 10:21:53 +02:00
data - > rng . name = pdev - > name ;
data - > rng . read = meson_rng_read ;
platform_set_drvdata ( pdev , data ) ;
return devm_hwrng_register ( dev , & data - > rng ) ;
}
static const struct of_device_id meson_rng_of_match [ ] = {
{ . compatible = " amlogic,meson-rng " , } ,
{ } ,
} ;
2016-10-17 16:51:17 -03:00
MODULE_DEVICE_TABLE ( of , meson_rng_of_match ) ;
2016-06-10 10:21:53 +02:00
static struct platform_driver meson_rng_driver = {
. probe = meson_rng_probe ,
. driver = {
. name = " meson-rng " ,
. of_match_table = meson_rng_of_match ,
} ,
} ;
module_platform_driver ( meson_rng_driver ) ;
MODULE_DESCRIPTION ( " Meson H/W Random Number Generator driver " ) ;
MODULE_AUTHOR ( " Lawrence Mok <lawrence.mok@amlogic.com> " ) ;
MODULE_AUTHOR ( " Neil Armstrong <narmstrong@baylibre.com> " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;