2006-06-26 11:25:03 +04:00
/*
2008-04-16 15:24:42 +04:00
* omap - rng . c - RNG driver for TI OMAP CPU family
2006-06-26 11:25:03 +04:00
*
* Author : Deepak Saxena < dsaxena @ plexity . net >
*
* Copyright 2005 ( c ) MontaVista Software , Inc .
*
* Mostly based on original driver :
*
* Copyright ( C ) 2005 Nokia Corporation
2007-10-20 01:21:04 +04:00
* Author : Juha Yrjölä < juha . yrjola @ nokia . com >
2006-06-26 11:25:03 +04:00
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/random.h>
# include <linux/err.h>
2006-08-05 23:14:04 +04:00
# include <linux/platform_device.h>
2006-06-26 11:25:03 +04:00
# include <linux/hw_random.h>
2007-11-21 07:24:45 +03:00
# include <linux/delay.h>
2020-06-29 11:03:55 +03:00
# include <linux/kernel.h>
2012-09-24 03:28:26 +04:00
# include <linux/slab.h>
2012-09-24 03:28:26 +04:00
# include <linux/pm_runtime.h>
2013-08-05 18:47:21 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_address.h>
2013-08-05 18:47:23 +04:00
# include <linux/interrupt.h>
2016-09-16 13:08:55 +03:00
# include <linux/clk.h>
2021-02-19 14:19:18 +03:00
# include <linux/io.h>
2006-06-26 11:25:03 +04:00
2013-08-05 18:47:23 +04:00
# define RNG_REG_STATUS_RDY (1 << 0)
# define RNG_REG_INTACK_RDY_MASK (1 << 0)
# define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK (1 << 1)
# define RNG_SHUTDOWN_OFLO_MASK (1 << 1)
# define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16
# define RNG_CONTROL_STARTUP_CYCLES_MASK (0xffff << 16)
# define RNG_CONTROL_ENABLE_TRNG_SHIFT 10
# define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
# define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16
# define RNG_CONFIG_MAX_REFIL_CYCLES_MASK (0xffff << 16)
# define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0
# define RNG_CONFIG_MIN_REFIL_CYCLES_MASK (0xff << 0)
# define RNG_CONTROL_STARTUP_CYCLES 0xff
# define RNG_CONFIG_MIN_REFIL_CYCLES 0x21
# define RNG_CONFIG_MAX_REFIL_CYCLES 0x22
# define RNG_ALARMCNT_ALARM_TH_SHIFT 0x0
# define RNG_ALARMCNT_ALARM_TH_MASK (0xff << 0)
# define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16
# define RNG_ALARMCNT_SHUTDOWN_TH_MASK (0x1f << 16)
# define RNG_ALARM_THRESHOLD 0xff
# define RNG_SHUTDOWN_THRESHOLD 0x4
# define RNG_REG_FROENABLE_MASK 0xffffff
# define RNG_REG_FRODETUNE_MASK 0xffffff
# define OMAP2_RNG_OUTPUT_SIZE 0x4
# define OMAP4_RNG_OUTPUT_SIZE 0x8
2016-09-16 13:08:55 +03:00
# define EIP76_RNG_OUTPUT_SIZE 0x10
2013-08-05 18:47:23 +04:00
2019-10-14 15:02:45 +03:00
/*
* EIP76 RNG takes approx . 700u s to produce 16 bytes of output data
* as per testing results . And to account for the lack of udelay ( ) ' s
* reliability , we keep the timeout as 1000u s .
*/
# define RNG_DATA_FILL_TIMEOUT 100
2013-08-05 18:47:23 +04:00
enum {
2016-09-16 13:08:53 +03:00
RNG_OUTPUT_0_REG = 0 ,
RNG_OUTPUT_1_REG ,
RNG_OUTPUT_2_REG ,
RNG_OUTPUT_3_REG ,
2013-08-05 18:47:23 +04:00
RNG_STATUS_REG ,
RNG_INTMASK_REG ,
RNG_INTACK_REG ,
RNG_CONTROL_REG ,
RNG_CONFIG_REG ,
RNG_ALARMCNT_REG ,
RNG_FROENABLE_REG ,
RNG_FRODETUNE_REG ,
RNG_ALARMMASK_REG ,
RNG_ALARMSTOP_REG ,
RNG_REV_REG ,
RNG_SYSCONFIG_REG ,
} ;
static const u16 reg_map_omap2 [ ] = {
2016-09-16 13:08:53 +03:00
[ RNG_OUTPUT_0_REG ] = 0x0 ,
2013-08-05 18:47:23 +04:00
[ RNG_STATUS_REG ] = 0x4 ,
[ RNG_CONFIG_REG ] = 0x28 ,
[ RNG_REV_REG ] = 0x3c ,
[ RNG_SYSCONFIG_REG ] = 0x40 ,
} ;
static const u16 reg_map_omap4 [ ] = {
2016-09-16 13:08:53 +03:00
[ RNG_OUTPUT_0_REG ] = 0x0 ,
[ RNG_OUTPUT_1_REG ] = 0x4 ,
2013-08-05 18:47:23 +04:00
[ RNG_STATUS_REG ] = 0x8 ,
[ RNG_INTMASK_REG ] = 0xc ,
[ RNG_INTACK_REG ] = 0x10 ,
[ RNG_CONTROL_REG ] = 0x14 ,
[ RNG_CONFIG_REG ] = 0x18 ,
[ RNG_ALARMCNT_REG ] = 0x1c ,
[ RNG_FROENABLE_REG ] = 0x20 ,
[ RNG_FRODETUNE_REG ] = 0x24 ,
[ RNG_ALARMMASK_REG ] = 0x28 ,
[ RNG_ALARMSTOP_REG ] = 0x2c ,
[ RNG_REV_REG ] = 0x1FE0 ,
[ RNG_SYSCONFIG_REG ] = 0x1FE4 ,
} ;
2006-06-26 11:25:03 +04:00
2016-09-16 13:08:55 +03:00
static const u16 reg_map_eip76 [ ] = {
[ RNG_OUTPUT_0_REG ] = 0x0 ,
[ RNG_OUTPUT_1_REG ] = 0x4 ,
[ RNG_OUTPUT_2_REG ] = 0x8 ,
[ RNG_OUTPUT_3_REG ] = 0xc ,
[ RNG_STATUS_REG ] = 0x10 ,
[ RNG_INTACK_REG ] = 0x10 ,
[ RNG_CONTROL_REG ] = 0x14 ,
[ RNG_CONFIG_REG ] = 0x18 ,
[ RNG_ALARMCNT_REG ] = 0x1c ,
[ RNG_FROENABLE_REG ] = 0x20 ,
[ RNG_FRODETUNE_REG ] = 0x24 ,
[ RNG_ALARMMASK_REG ] = 0x28 ,
[ RNG_ALARMSTOP_REG ] = 0x2c ,
[ RNG_REV_REG ] = 0x7c ,
} ;
2013-08-05 18:47:23 +04:00
struct omap_rng_dev ;
2012-09-24 03:28:26 +04:00
/**
2013-08-05 18:47:23 +04:00
* struct omap_rng_pdata - RNG IP block - specific data
* @ regs : Pointer to the register offsets structure .
* @ data_size : No . of bytes in RNG output .
* @ data_present : Callback to determine if data is available .
* @ init : Callback for IP specific initialization sequence .
* @ cleanup : Callback for IP specific cleanup sequence .
2012-09-24 03:28:26 +04:00
*/
2013-08-05 18:47:23 +04:00
struct omap_rng_pdata {
u16 * regs ;
u32 data_size ;
u32 ( * data_present ) ( struct omap_rng_dev * priv ) ;
int ( * init ) ( struct omap_rng_dev * priv ) ;
void ( * cleanup ) ( struct omap_rng_dev * priv ) ;
2012-09-24 03:28:26 +04:00
} ;
2006-06-26 11:25:03 +04:00
2013-08-05 18:47:23 +04:00
struct omap_rng_dev {
void __iomem * base ;
struct device * dev ;
const struct omap_rng_pdata * pdata ;
2016-09-16 13:08:52 +03:00
struct hwrng rng ;
2016-09-16 13:08:55 +03:00
struct clk * clk ;
2018-02-28 17:27:23 +03:00
struct clk * clk_reg ;
2013-08-05 18:47:23 +04:00
} ;
static inline u32 omap_rng_read ( struct omap_rng_dev * priv , u16 reg )
{
return __raw_readl ( priv - > base + priv - > pdata - > regs [ reg ] ) ;
}
static inline void omap_rng_write ( struct omap_rng_dev * priv , u16 reg ,
u32 val )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
__raw_writel ( val , priv - > base + priv - > pdata - > regs [ reg ] ) ;
2006-06-26 11:25:03 +04:00
}
2016-09-16 13:08:51 +03:00
static int omap_rng_do_read ( struct hwrng * rng , void * data , size_t max ,
bool wait )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
struct omap_rng_dev * priv ;
2016-09-16 13:08:51 +03:00
int i , present ;
2007-11-21 07:24:45 +03:00
2013-08-05 18:47:23 +04:00
priv = ( struct omap_rng_dev * ) rng - > priv ;
2012-09-24 03:28:26 +04:00
2016-09-16 13:08:51 +03:00
if ( max < priv - > pdata - > data_size )
return 0 ;
2019-10-14 15:02:45 +03:00
for ( i = 0 ; i < RNG_DATA_FILL_TIMEOUT ; i + + ) {
2016-09-16 13:08:51 +03:00
present = priv - > pdata - > data_present ( priv ) ;
if ( present | | ! wait )
2007-11-21 07:24:45 +03:00
break ;
2016-09-16 13:08:51 +03:00
2007-11-21 07:24:45 +03:00
udelay ( 10 ) ;
}
2016-09-16 13:08:51 +03:00
if ( ! present )
return 0 ;
2013-08-05 18:47:23 +04:00
2016-09-16 13:08:53 +03:00
memcpy_fromio ( data , priv - > base + priv - > pdata - > regs [ RNG_OUTPUT_0_REG ] ,
2016-09-16 13:08:51 +03:00
priv - > pdata - > data_size ) ;
2013-08-05 18:47:23 +04:00
if ( priv - > pdata - > regs [ RNG_INTACK_REG ] )
omap_rng_write ( priv , RNG_INTACK_REG , RNG_REG_INTACK_RDY_MASK ) ;
2016-09-16 13:08:51 +03:00
return priv - > pdata - > data_size ;
2013-08-05 18:47:23 +04:00
}
2013-08-20 22:07:53 +04:00
static int omap_rng_init ( struct hwrng * rng )
{
struct omap_rng_dev * priv ;
priv = ( struct omap_rng_dev * ) rng - > priv ;
return priv - > pdata - > init ( priv ) ;
}
static void omap_rng_cleanup ( struct hwrng * rng )
{
struct omap_rng_dev * priv ;
priv = ( struct omap_rng_dev * ) rng - > priv ;
priv - > pdata - > cleanup ( priv ) ;
}
static inline u32 omap2_rng_data_present ( struct omap_rng_dev * priv )
{
return omap_rng_read ( priv , RNG_STATUS_REG ) ? 0 : 1 ;
}
static int omap2_rng_init ( struct omap_rng_dev * priv )
{
omap_rng_write ( priv , RNG_SYSCONFIG_REG , 0x1 ) ;
return 0 ;
}
static void omap2_rng_cleanup ( struct omap_rng_dev * priv )
{
omap_rng_write ( priv , RNG_SYSCONFIG_REG , 0x0 ) ;
}
static struct omap_rng_pdata omap2_rng_pdata = {
. regs = ( u16 * ) reg_map_omap2 ,
. data_size = OMAP2_RNG_OUTPUT_SIZE ,
. data_present = omap2_rng_data_present ,
. init = omap2_rng_init ,
. cleanup = omap2_rng_cleanup ,
} ;
static inline u32 omap4_rng_data_present ( struct omap_rng_dev * priv )
{
return omap_rng_read ( priv , RNG_STATUS_REG ) & RNG_REG_STATUS_RDY ;
}
2016-09-16 13:08:55 +03:00
static int eip76_rng_init ( struct omap_rng_dev * priv )
{
u32 val ;
/* Return if RNG is already running. */
if ( omap_rng_read ( priv , RNG_CONTROL_REG ) & RNG_CONTROL_ENABLE_TRNG_MASK )
return 0 ;
/* Number of 512 bit blocks of raw Noise Source output data that must
* be processed by either the Conditioning Function or the
* SP 800 - 90 DRBG ‘ BC_DF ’ functionality to yield a ‘ full entropy ’
* output value .
*/
val = 0x5 < < RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT ;
/* Number of FRO samples that are XOR-ed together into one bit to be
* shifted into the main shift register
*/
val | = RNG_CONFIG_MAX_REFIL_CYCLES < < RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT ;
omap_rng_write ( priv , RNG_CONFIG_REG , val ) ;
/* Enable all available FROs */
omap_rng_write ( priv , RNG_FRODETUNE_REG , 0x0 ) ;
omap_rng_write ( priv , RNG_FROENABLE_REG , RNG_REG_FROENABLE_MASK ) ;
/* Enable TRNG */
val = RNG_CONTROL_ENABLE_TRNG_MASK ;
omap_rng_write ( priv , RNG_CONTROL_REG , val ) ;
return 0 ;
}
2013-08-05 18:47:23 +04:00
static int omap4_rng_init ( struct omap_rng_dev * priv )
{
u32 val ;
/* Return if RNG is already running. */
2015-03-16 04:54:50 +03:00
if ( omap_rng_read ( priv , RNG_CONTROL_REG ) & RNG_CONTROL_ENABLE_TRNG_MASK )
2013-08-05 18:47:23 +04:00
return 0 ;
val = RNG_CONFIG_MIN_REFIL_CYCLES < < RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT ;
val | = RNG_CONFIG_MAX_REFIL_CYCLES < < RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT ;
omap_rng_write ( priv , RNG_CONFIG_REG , val ) ;
omap_rng_write ( priv , RNG_FRODETUNE_REG , 0x0 ) ;
omap_rng_write ( priv , RNG_FROENABLE_REG , RNG_REG_FROENABLE_MASK ) ;
val = RNG_ALARM_THRESHOLD < < RNG_ALARMCNT_ALARM_TH_SHIFT ;
val | = RNG_SHUTDOWN_THRESHOLD < < RNG_ALARMCNT_SHUTDOWN_TH_SHIFT ;
omap_rng_write ( priv , RNG_ALARMCNT_REG , val ) ;
val = RNG_CONTROL_STARTUP_CYCLES < < RNG_CONTROL_STARTUP_CYCLES_SHIFT ;
val | = RNG_CONTROL_ENABLE_TRNG_MASK ;
omap_rng_write ( priv , RNG_CONTROL_REG , val ) ;
return 0 ;
}
static void omap4_rng_cleanup ( struct omap_rng_dev * priv )
{
int val ;
val = omap_rng_read ( priv , RNG_CONTROL_REG ) ;
val & = ~ RNG_CONTROL_ENABLE_TRNG_MASK ;
2015-03-16 02:19:11 +03:00
omap_rng_write ( priv , RNG_CONTROL_REG , val ) ;
2013-08-05 18:47:23 +04:00
}
static irqreturn_t omap4_rng_irq ( int irq , void * dev_id )
{
struct omap_rng_dev * priv = dev_id ;
u32 fro_detune , fro_enable ;
/*
* Interrupt raised by a fro shutdown threshold , do the following :
* 1. Clear the alarm events .
* 2. De tune the FROs which are shutdown .
* 3. Re enable the shutdown FROs .
*/
omap_rng_write ( priv , RNG_ALARMMASK_REG , 0x0 ) ;
omap_rng_write ( priv , RNG_ALARMSTOP_REG , 0x0 ) ;
fro_enable = omap_rng_read ( priv , RNG_FROENABLE_REG ) ;
fro_detune = ~ fro_enable & RNG_REG_FRODETUNE_MASK ;
fro_detune = fro_detune | omap_rng_read ( priv , RNG_FRODETUNE_REG ) ;
fro_enable = RNG_REG_FROENABLE_MASK ;
2012-09-24 03:28:26 +04:00
2013-08-05 18:47:23 +04:00
omap_rng_write ( priv , RNG_FRODETUNE_REG , fro_detune ) ;
omap_rng_write ( priv , RNG_FROENABLE_REG , fro_enable ) ;
2012-09-24 03:28:26 +04:00
2013-08-05 18:47:23 +04:00
omap_rng_write ( priv , RNG_INTACK_REG , RNG_REG_INTACK_SHUTDOWN_OFLO_MASK ) ;
2006-06-26 11:25:03 +04:00
2013-08-05 18:47:23 +04:00
return IRQ_HANDLED ;
2006-06-26 11:25:03 +04:00
}
2013-08-05 18:47:23 +04:00
static struct omap_rng_pdata omap4_rng_pdata = {
. regs = ( u16 * ) reg_map_omap4 ,
. data_size = OMAP4_RNG_OUTPUT_SIZE ,
. data_present = omap4_rng_data_present ,
. init = omap4_rng_init ,
. cleanup = omap4_rng_cleanup ,
} ;
2016-09-16 13:08:55 +03:00
static struct omap_rng_pdata eip76_rng_pdata = {
. regs = ( u16 * ) reg_map_eip76 ,
. data_size = EIP76_RNG_OUTPUT_SIZE ,
. data_present = omap4_rng_data_present ,
. init = eip76_rng_init ,
. cleanup = omap4_rng_cleanup ,
} ;
2020-06-29 11:03:55 +03:00
static const struct of_device_id omap_rng_of_match [ ] __maybe_unused = {
2013-08-05 18:47:23 +04:00
{
. compatible = " ti,omap2-rng " ,
. data = & omap2_rng_pdata ,
} ,
{
. compatible = " ti,omap4-rng " ,
. data = & omap4_rng_pdata ,
} ,
2016-09-16 13:08:55 +03:00
{
. compatible = " inside-secure,safexcel-eip76 " ,
. data = & eip76_rng_pdata ,
} ,
2013-08-05 18:47:21 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , omap_rng_of_match ) ;
2013-08-05 18:47:23 +04:00
static int of_get_omap_rng_device_details ( struct omap_rng_dev * priv ,
struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
int irq , err ;
2021-03-22 09:51:51 +03:00
priv - > pdata = of_device_get_match_data ( dev ) ;
if ( ! priv - > pdata )
return - ENODEV ;
2013-08-05 18:47:23 +04:00
2016-09-16 13:08:55 +03:00
if ( of_device_is_compatible ( dev - > of_node , " ti,omap4-rng " ) | |
of_device_is_compatible ( dev - > of_node , " inside-secure,safexcel-eip76 " ) ) {
2013-08-05 18:47:23 +04:00
irq = platform_get_irq ( pdev , 0 ) ;
2020-04-04 17:45:57 +03:00
if ( irq < 0 )
2013-08-05 18:47:23 +04:00
return irq ;
err = devm_request_irq ( dev , irq , omap4_rng_irq ,
IRQF_TRIGGER_NONE , dev_name ( dev ) , priv ) ;
if ( err ) {
dev_err ( dev , " unable to request irq %d, err = %d \n " ,
irq , err ) ;
return err ;
}
2016-09-16 13:08:55 +03:00
2017-03-07 17:14:48 +03:00
/*
* On OMAP4 , enabling the shutdown_oflo interrupt is
* done in the interrupt mask register . There is no
* such register on EIP76 , and it ' s enabled by the
* same bit in the control register
*/
if ( priv - > pdata - > regs [ RNG_INTMASK_REG ] )
omap_rng_write ( priv , RNG_INTMASK_REG ,
RNG_SHUTDOWN_OFLO_MASK ) ;
else
omap_rng_write ( priv , RNG_CONTROL_REG ,
RNG_SHUTDOWN_OFLO_MASK ) ;
2013-08-05 18:47:23 +04:00
}
return 0 ;
}
2013-08-05 18:47:21 +04:00
2013-08-05 18:47:23 +04:00
static int get_omap_rng_device_details ( struct omap_rng_dev * omap_rng )
{
/* Only OMAP2/3 can be non-DT */
omap_rng - > pdata = & omap2_rng_pdata ;
return 0 ;
}
2012-12-22 03:12:08 +04:00
static int omap_rng_probe ( struct platform_device * pdev )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
struct omap_rng_dev * priv ;
struct device * dev = & pdev - > dev ;
2006-06-26 11:25:03 +04:00
int ret ;
2013-08-05 18:47:23 +04:00
priv = devm_kzalloc ( dev , sizeof ( struct omap_rng_dev ) , GFP_KERNEL ) ;
2014-04-29 12:15:36 +04:00
if ( ! priv )
2012-09-24 03:28:26 +04:00
return - ENOMEM ;
2016-09-16 13:08:52 +03:00
priv - > rng . read = omap_rng_do_read ;
priv - > rng . init = omap_rng_init ;
priv - > rng . cleanup = omap_rng_cleanup ;
2019-03-11 13:58:57 +03:00
priv - > rng . quality = 900 ;
2016-09-16 13:08:52 +03:00
priv - > rng . priv = ( unsigned long ) priv ;
2013-05-29 04:47:29 +04:00
platform_set_drvdata ( pdev , priv ) ;
2013-08-05 18:47:23 +04:00
priv - > dev = dev ;
2006-06-26 11:25:03 +04:00
2019-10-16 13:46:16 +03:00
priv - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2013-01-21 14:08:59 +04:00
if ( IS_ERR ( priv - > base ) ) {
ret = PTR_ERR ( priv - > base ) ;
2008-09-04 17:07:22 +04:00
goto err_ioremap ;
}
2006-06-26 11:25:03 +04:00
2016-09-16 13:08:52 +03:00
priv - > rng . name = devm_kstrdup ( dev , dev_name ( dev ) , GFP_KERNEL ) ;
if ( ! priv - > rng . name ) {
ret = - ENOMEM ;
goto err_ioremap ;
}
2012-09-24 03:28:26 +04:00
pm_runtime_enable ( & pdev - > dev ) ;
2021-05-24 15:20:57 +03:00
ret = pm_runtime_resume_and_get ( & pdev - > dev ) ;
2016-09-20 18:25:40 +03:00
if ( ret < 0 ) {
2016-06-24 19:50:39 +03:00
dev_err ( & pdev - > dev , " Failed to runtime_get device: %d \n " , ret ) ;
goto err_ioremap ;
}
2012-09-24 03:28:26 +04:00
2017-03-07 17:14:49 +03:00
priv - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2020-02-04 04:37:45 +03:00
if ( PTR_ERR ( priv - > clk ) = = - EPROBE_DEFER )
2017-03-07 17:14:49 +03:00
return - EPROBE_DEFER ;
if ( ! IS_ERR ( priv - > clk ) ) {
ret = clk_prepare_enable ( priv - > clk ) ;
if ( ret ) {
dev_err ( & pdev - > dev ,
" Unable to enable the clk: %d \n " , ret ) ;
goto err_register ;
}
}
2018-02-28 17:27:23 +03:00
priv - > clk_reg = devm_clk_get ( & pdev - > dev , " reg " ) ;
2020-02-04 04:37:45 +03:00
if ( PTR_ERR ( priv - > clk_reg ) = = - EPROBE_DEFER )
2018-02-28 17:27:23 +03:00
return - EPROBE_DEFER ;
if ( ! IS_ERR ( priv - > clk_reg ) ) {
ret = clk_prepare_enable ( priv - > clk_reg ) ;
if ( ret ) {
dev_err ( & pdev - > dev ,
" Unable to enable the register clk: %d \n " ,
ret ) ;
goto err_register ;
}
}
2013-08-05 18:47:23 +04:00
ret = ( dev - > of_node ) ? of_get_omap_rng_device_details ( priv , pdev ) :
get_omap_rng_device_details ( priv ) ;
if ( ret )
2016-09-16 13:08:55 +03:00
goto err_register ;
2013-08-05 18:47:23 +04:00
2019-07-25 11:01:55 +03:00
ret = devm_hwrng_register ( & pdev - > dev , & priv - > rng ) ;
2008-09-04 17:07:22 +04:00
if ( ret )
goto err_register ;
2006-06-26 11:25:03 +04:00
2016-09-16 13:08:54 +03:00
dev_info ( & pdev - > dev , " Random Number Generator ver. %02x \n " ,
2013-08-05 18:47:23 +04:00
omap_rng_read ( priv , RNG_REV_REG ) ) ;
2006-06-26 11:25:03 +04:00
return 0 ;
2008-09-04 17:07:22 +04:00
err_register :
2012-09-24 03:28:26 +04:00
priv - > base = NULL ;
2016-09-16 13:08:55 +03:00
pm_runtime_put_sync ( & pdev - > dev ) ;
2012-09-24 03:28:26 +04:00
pm_runtime_disable ( & pdev - > dev ) ;
2016-09-16 13:08:55 +03:00
2018-02-28 17:27:23 +03:00
clk_disable_unprepare ( priv - > clk_reg ) ;
2018-02-28 17:27:22 +03:00
clk_disable_unprepare ( priv - > clk ) ;
2008-09-04 17:07:22 +04:00
err_ioremap :
2013-08-05 18:47:23 +04:00
dev_err ( dev , " initialization failed. \n " ) ;
2008-09-04 17:07:22 +04:00
return ret ;
2006-06-26 11:25:03 +04:00
}
2015-03-09 20:36:35 +03:00
static int omap_rng_remove ( struct platform_device * pdev )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
struct omap_rng_dev * priv = platform_get_drvdata ( pdev ) ;
2012-09-24 03:28:26 +04:00
2006-06-26 11:25:03 +04:00
2013-08-05 18:47:23 +04:00
priv - > pdata - > cleanup ( priv ) ;
2012-09-24 03:28:26 +04:00
2012-09-24 03:28:26 +04:00
pm_runtime_put_sync ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2006-06-26 11:25:03 +04:00
2018-02-28 17:27:22 +03:00
clk_disable_unprepare ( priv - > clk ) ;
2018-02-28 17:27:23 +03:00
clk_disable_unprepare ( priv - > clk_reg ) ;
2016-09-16 13:08:55 +03:00
2006-06-26 11:25:03 +04:00
return 0 ;
}
2015-03-12 00:08:36 +03:00
static int __maybe_unused omap_rng_suspend ( struct device * dev )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
struct omap_rng_dev * priv = dev_get_drvdata ( dev ) ;
2012-09-24 03:28:26 +04:00
2013-08-05 18:47:23 +04:00
priv - > pdata - > cleanup ( priv ) ;
2012-09-24 03:28:26 +04:00
pm_runtime_put_sync ( dev ) ;
2012-09-24 03:28:26 +04:00
2006-06-26 11:25:03 +04:00
return 0 ;
}
2015-03-12 00:08:36 +03:00
static int __maybe_unused omap_rng_resume ( struct device * dev )
2006-06-26 11:25:03 +04:00
{
2013-08-05 18:47:23 +04:00
struct omap_rng_dev * priv = dev_get_drvdata ( dev ) ;
2016-06-24 19:50:39 +03:00
int ret ;
2021-05-24 15:20:57 +03:00
ret = pm_runtime_resume_and_get ( dev ) ;
2016-09-20 18:25:40 +03:00
if ( ret < 0 ) {
2016-06-24 19:50:39 +03:00
dev_err ( dev , " Failed to runtime_get device: %d \n " , ret ) ;
return ret ;
}
2012-09-24 03:28:26 +04:00
2013-08-05 18:47:23 +04:00
priv - > pdata - > init ( priv ) ;
2012-09-24 03:28:26 +04:00
2006-08-05 23:14:04 +04:00
return 0 ;
2006-06-26 11:25:03 +04:00
}
2012-07-06 21:08:53 +04:00
static SIMPLE_DEV_PM_OPS ( omap_rng_pm , omap_rng_suspend , omap_rng_resume ) ;
2006-06-26 11:25:03 +04:00
2006-08-05 23:14:04 +04:00
static struct platform_driver omap_rng_driver = {
. driver = {
. name = " omap_rng " ,
2015-03-12 00:08:36 +03:00
. pm = & omap_rng_pm ,
2013-08-05 18:47:21 +04:00
. of_match_table = of_match_ptr ( omap_rng_of_match ) ,
2006-08-05 23:14:04 +04:00
} ,
2006-06-26 11:25:03 +04:00
. probe = omap_rng_probe ,
2015-03-09 20:36:35 +03:00
. remove = omap_rng_remove ,
2006-06-26 11:25:03 +04:00
} ;
2013-08-05 18:47:18 +04:00
module_platform_driver ( omap_rng_driver ) ;
MODULE_ALIAS ( " platform:omap_rng " ) ;
2006-06-26 11:25:03 +04:00
MODULE_AUTHOR ( " Deepak Saxena (and others) " ) ;
MODULE_LICENSE ( " GPL " ) ;