2023-03-07 18:02:02 +00:00
// SPDX-License-Identifier: GPL-2.0
2015-02-05 11:11:28 +01:00
/*
* Simple Power - Managed Bus Driver
*
* Copyright ( C ) 2014 - 2015 Glider bvba
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
2022-12-26 11:14:17 +08:00
# include <linux/clk.h>
2015-02-05 11:11:28 +01:00
# include <linux/module.h>
2023-08-03 16:42:56 -06:00
# include <linux/of.h>
# include <linux/of_device.h>
2015-02-05 11:11:28 +01:00
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
2022-12-26 11:14:17 +08:00
struct simple_pm_bus {
struct clk_bulk_data * clks ;
int num_clks ;
} ;
2015-02-05 11:11:28 +01:00
static int simple_pm_bus_probe ( struct platform_device * pdev )
{
2021-09-28 17:07:33 -07:00
const struct device * dev = & pdev - > dev ;
const struct of_dev_auxdata * lookup = dev_get_platdata ( dev ) ;
struct device_node * np = dev - > of_node ;
const struct of_device_id * match ;
2022-12-26 11:14:17 +08:00
struct simple_pm_bus * bus ;
2021-09-28 17:07:33 -07:00
/*
* Allow user to use driver_override to bind this driver to a
* transparent bus device which has a different compatible string
* that ' s not listed in simple_pm_bus_of_match . We don ' t want to do any
* of the simple - pm - bus tasks for these devices , so return early .
*/
if ( pdev - > driver_override )
return 0 ;
match = of_match_device ( dev - > driver - > of_match_table , dev ) ;
/*
* These are transparent bus devices ( not simple - pm - bus matches ) that
* have their child nodes populated automatically . So , don ' t need to
* do anything more . We only match with the device if this driver is
* the most specific match because we don ' t want to incorrectly bind to
* a device that has a more specific driver .
*/
if ( match & & match - > data ) {
if ( of_property_match_string ( np , " compatible " , match - > compatible ) = = 0 )
return 0 ;
else
return - ENODEV ;
}
2015-02-05 11:11:28 +01:00
2022-12-26 11:14:17 +08:00
bus = devm_kzalloc ( & pdev - > dev , sizeof ( * bus ) , GFP_KERNEL ) ;
if ( ! bus )
return - ENOMEM ;
bus - > num_clks = devm_clk_bulk_get_all ( & pdev - > dev , & bus - > clks ) ;
if ( bus - > num_clks < 0 )
return dev_err_probe ( & pdev - > dev , bus - > num_clks , " failed to get clocks \n " ) ;
dev_set_drvdata ( & pdev - > dev , bus ) ;
2015-02-05 11:11:28 +01:00
dev_dbg ( & pdev - > dev , " %s \n " , __func__ ) ;
pm_runtime_enable ( & pdev - > dev ) ;
if ( np )
2021-01-15 10:47:17 +02:00
of_platform_populate ( np , NULL , lookup , & pdev - > dev ) ;
2015-02-05 11:11:28 +01:00
return 0 ;
}
static int simple_pm_bus_remove ( struct platform_device * pdev )
{
2021-09-28 17:07:33 -07:00
const void * data = of_device_get_match_data ( & pdev - > dev ) ;
if ( pdev - > driver_override | | data )
return 0 ;
2015-02-05 11:11:28 +01:00
dev_dbg ( & pdev - > dev , " %s \n " , __func__ ) ;
pm_runtime_disable ( & pdev - > dev ) ;
return 0 ;
}
2022-12-26 11:14:17 +08:00
static int simple_pm_bus_runtime_suspend ( struct device * dev )
{
struct simple_pm_bus * bus = dev_get_drvdata ( dev ) ;
clk_bulk_disable_unprepare ( bus - > num_clks , bus - > clks ) ;
return 0 ;
}
static int simple_pm_bus_runtime_resume ( struct device * dev )
{
struct simple_pm_bus * bus = dev_get_drvdata ( dev ) ;
int ret ;
ret = clk_bulk_prepare_enable ( bus - > num_clks , bus - > clks ) ;
if ( ret ) {
dev_err ( dev , " failed to enable clocks: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static const struct dev_pm_ops simple_pm_bus_pm_ops = {
RUNTIME_PM_OPS ( simple_pm_bus_runtime_suspend , simple_pm_bus_runtime_resume , NULL )
NOIRQ_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend , pm_runtime_force_resume )
} ;
2021-09-28 17:07:33 -07:00
# define ONLY_BUS ((void *) 1) /* Match if the device is only a bus. */
2015-02-05 11:11:28 +01:00
static const struct of_device_id simple_pm_bus_of_match [ ] = {
{ . compatible = " simple-pm-bus " , } ,
2021-09-28 17:07:33 -07:00
{ . compatible = " simple-bus " , . data = ONLY_BUS } ,
{ . compatible = " simple-mfd " , . data = ONLY_BUS } ,
{ . compatible = " isa " , . data = ONLY_BUS } ,
{ . compatible = " arm,amba-bus " , . data = ONLY_BUS } ,
2015-02-05 11:11:28 +01:00
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , simple_pm_bus_of_match ) ;
static struct platform_driver simple_pm_bus_driver = {
. probe = simple_pm_bus_probe ,
. remove = simple_pm_bus_remove ,
. driver = {
. name = " simple-pm-bus " ,
. of_match_table = simple_pm_bus_of_match ,
2022-12-26 11:14:17 +08:00
. pm = pm_ptr ( & simple_pm_bus_pm_ops ) ,
2015-02-05 11:11:28 +01:00
} ,
} ;
module_platform_driver ( simple_pm_bus_driver ) ;
MODULE_DESCRIPTION ( " Simple Power-Managed Bus Driver " ) ;
MODULE_AUTHOR ( " Geert Uytterhoeven <geert+renesas@glider.be> " ) ;