2018-12-07 13:01:44 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 ROHM Semiconductors
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
2020-01-20 16:44:19 +03:00
# include <linux/mfd/rohm-generic.h>
2018-12-07 13:01:44 +03:00
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
# include <linux/regmap.h>
2020-01-20 16:44:19 +03:00
/* clk control registers */
/* BD70528 */
# define BD70528_REG_OUT32K 0x2c
/* BD71828 */
# define BD71828_REG_OUT32K 0x4B
/* BD71837 and BD71847 */
# define BD718XX_REG_OUT32K 0x2E
/*
* BD71837 , BD71847 , BD70528 and BD71828 all use bit [ 0 ] to clk output control
*/
# define CLK_OUT_EN_MASK BIT(0)
2018-12-07 13:01:44 +03:00
struct bd718xx_clk {
struct clk_hw hw ;
u8 reg ;
u8 mask ;
struct platform_device * pdev ;
2019-06-03 10:24:32 +03:00
struct rohm_regmap_dev * mfd ;
2018-12-07 13:01:44 +03:00
} ;
2020-01-20 16:44:19 +03:00
static int bd71837_clk_set ( struct bd718xx_clk * c , unsigned int status )
2018-12-07 13:01:44 +03:00
{
return regmap_update_bits ( c - > mfd - > regmap , c - > reg , c - > mask , status ) ;
}
static void bd71837_clk_disable ( struct clk_hw * hw )
{
int rv ;
struct bd718xx_clk * c = container_of ( hw , struct bd718xx_clk , hw ) ;
2020-01-20 16:44:19 +03:00
rv = bd71837_clk_set ( c , 0 ) ;
2018-12-07 13:01:44 +03:00
if ( rv )
dev_dbg ( & c - > pdev - > dev , " Failed to disable 32K clk (%d) \n " , rv ) ;
}
static int bd71837_clk_enable ( struct clk_hw * hw )
{
2020-01-20 16:44:19 +03:00
struct bd718xx_clk * c = container_of ( hw , struct bd718xx_clk , hw ) ;
return bd71837_clk_set ( c , 0xffffffff ) ;
2018-12-07 13:01:44 +03:00
}
static int bd71837_clk_is_enabled ( struct clk_hw * hw )
{
int enabled ;
int rval ;
struct bd718xx_clk * c = container_of ( hw , struct bd718xx_clk , hw ) ;
rval = regmap_read ( c - > mfd - > regmap , c - > reg , & enabled ) ;
if ( rval )
return rval ;
return enabled & c - > mask ;
}
static const struct clk_ops bd71837_clk_ops = {
. prepare = & bd71837_clk_enable ,
. unprepare = & bd71837_clk_disable ,
. is_prepared = & bd71837_clk_is_enabled ,
} ;
static int bd71837_clk_probe ( struct platform_device * pdev )
{
struct bd718xx_clk * c ;
int rval = - ENOMEM ;
const char * parent_clk ;
struct device * parent = pdev - > dev . parent ;
2019-06-03 10:24:32 +03:00
struct rohm_regmap_dev * mfd = dev_get_drvdata ( parent ) ;
2018-12-07 13:01:44 +03:00
struct clk_init_data init = {
. name = " bd718xx-32k-out " ,
. ops = & bd71837_clk_ops ,
} ;
2020-01-20 16:42:38 +03:00
enum rohm_chip_type chip = platform_get_device_id ( pdev ) - > driver_data ;
2018-12-07 13:01:44 +03:00
c = devm_kzalloc ( & pdev - > dev , sizeof ( * c ) , GFP_KERNEL ) ;
if ( ! c )
return - ENOMEM ;
init . num_parents = 1 ;
parent_clk = of_clk_get_parent_name ( parent - > of_node , 0 ) ;
init . parent_names = & parent_clk ;
if ( ! parent_clk ) {
dev_err ( & pdev - > dev , " No parent clk found \n " ) ;
return - EINVAL ;
}
2020-01-20 16:42:38 +03:00
switch ( chip ) {
2019-06-03 10:25:39 +03:00
case ROHM_CHIP_TYPE_BD71837 :
case ROHM_CHIP_TYPE_BD71847 :
c - > reg = BD718XX_REG_OUT32K ;
2020-01-20 16:44:19 +03:00
c - > mask = CLK_OUT_EN_MASK ;
break ;
case ROHM_CHIP_TYPE_BD71828 :
c - > reg = BD71828_REG_OUT32K ;
c - > mask = CLK_OUT_EN_MASK ;
2019-06-03 10:25:39 +03:00
break ;
case ROHM_CHIP_TYPE_BD70528 :
2020-01-20 16:44:19 +03:00
c - > reg = BD70528_REG_OUT32K ;
c - > mask = CLK_OUT_EN_MASK ;
2019-06-03 10:25:39 +03:00
break ;
default :
dev_err ( & pdev - > dev , " Unknown clk chip \n " ) ;
return - EINVAL ;
}
2018-12-07 13:01:44 +03:00
c - > mfd = mfd ;
c - > pdev = pdev ;
c - > hw . init = & init ;
of_property_read_string_index ( parent - > of_node ,
" clock-output-names " , 0 , & init . name ) ;
rval = devm_clk_hw_register ( & pdev - > dev , & c - > hw ) ;
if ( rval ) {
dev_err ( & pdev - > dev , " failed to register 32K clk " ) ;
return rval ;
}
rval = devm_of_clk_add_hw_provider ( & pdev - > dev , of_clk_hw_simple_get ,
& c - > hw ) ;
if ( rval )
dev_err ( & pdev - > dev , " adding clk provider failed \n " ) ;
return rval ;
}
2020-01-20 16:42:38 +03:00
static const struct platform_device_id bd718x7_clk_id [ ] = {
{ " bd71837-clk " , ROHM_CHIP_TYPE_BD71837 } ,
{ " bd71847-clk " , ROHM_CHIP_TYPE_BD71847 } ,
{ " bd70528-clk " , ROHM_CHIP_TYPE_BD70528 } ,
2020-01-20 16:44:19 +03:00
{ " bd71828-clk " , ROHM_CHIP_TYPE_BD71828 } ,
2020-01-20 16:42:38 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( platform , bd718x7_clk_id ) ;
2018-12-07 13:01:44 +03:00
static struct platform_driver bd71837_clk = {
. driver = {
. name = " bd718xx-clk " ,
} ,
. probe = bd71837_clk_probe ,
2020-01-20 16:42:38 +03:00
. id_table = bd718x7_clk_id ,
2018-12-07 13:01:44 +03:00
} ;
module_platform_driver ( bd71837_clk ) ;
MODULE_AUTHOR ( " Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> " ) ;
2019-06-03 10:25:39 +03:00
MODULE_DESCRIPTION ( " BD71837/BD71847/BD70528 chip clk driver " ) ;
2018-12-07 13:01:44 +03:00
MODULE_LICENSE ( " GPL " ) ;
2019-09-30 23:26:01 +03:00
MODULE_ALIAS ( " platform:bd718xx-clk " ) ;