2018-02-26 05:23:14 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2018 Spreadtrum Communications Inc .
* Copyright ( C ) 2018 Linaro Ltd .
*/
# include <linux/cpu.h>
# include <linux/kernel.h>
2020-03-09 11:18:46 +03:00
# include <linux/module.h>
2018-02-26 05:23:14 +03:00
# include <linux/platform_device.h>
# include <linux/pm.h>
# include <linux/regmap.h>
# include <linux/syscore_ops.h>
# define SC27XX_PWR_PD_HW 0xc2c
# define SC27XX_PWR_OFF_EN BIT(0)
2020-03-09 11:18:44 +03:00
# define SC27XX_SLP_CTRL 0xdf0
# define SC27XX_LDO_XTL_EN BIT(3)
2018-02-26 05:23:14 +03:00
static struct regmap * regmap ;
/*
* On Spreadtrum platform , we need power off system through external SC27xx
* series PMICs , and it is one similar SPI bus mapped by regmap to access PMIC ,
* which is not fast io access .
*
* So before stopping other cores , we need release other cores ' resource by
* taking cpus down to avoid racing regmap or spi mutex lock when poweroff
* system through PMIC .
*/
2018-03-13 13:54:06 +03:00
static void sc27xx_poweroff_shutdown ( void )
2018-02-26 05:23:14 +03:00
{
2020-03-09 11:18:45 +03:00
# ifdef CONFIG_HOTPLUG_CPU
int cpu ;
2018-02-26 05:23:14 +03:00
2020-03-09 11:18:45 +03:00
for_each_online_cpu ( cpu ) {
if ( cpu ! = smp_processor_id ( ) )
2020-04-05 23:47:57 +03:00
remove_cpu ( cpu ) ;
2020-03-09 11:18:45 +03:00
}
2018-02-26 05:23:14 +03:00
# endif
}
static struct syscore_ops poweroff_syscore_ops = {
. shutdown = sc27xx_poweroff_shutdown ,
} ;
static void sc27xx_poweroff_do_poweroff ( void )
{
2020-03-09 11:18:44 +03:00
/* Disable the external subsys connection's power firstly */
regmap_write ( regmap , SC27XX_SLP_CTRL , SC27XX_LDO_XTL_EN ) ;
2018-02-26 05:23:14 +03:00
regmap_write ( regmap , SC27XX_PWR_PD_HW , SC27XX_PWR_OFF_EN ) ;
}
static int sc27xx_poweroff_probe ( struct platform_device * pdev )
{
if ( regmap )
return - EINVAL ;
regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
if ( ! regmap )
return - ENODEV ;
pm_power_off = sc27xx_poweroff_do_poweroff ;
register_syscore_ops ( & poweroff_syscore_ops ) ;
return 0 ;
}
static struct platform_driver sc27xx_poweroff_driver = {
. probe = sc27xx_poweroff_probe ,
. driver = {
. name = " sc27xx-poweroff " ,
} ,
} ;
2020-03-09 11:18:46 +03:00
module_platform_driver ( sc27xx_poweroff_driver ) ;
MODULE_DESCRIPTION ( " Power off driver for SC27XX PMIC Device " ) ;
MODULE_AUTHOR ( " Baolin Wang <baolin.wang@unisoc.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;