2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-01-23 19:08:30 -08:00
/*
* pwrseq_sd8787 . c - power sequence support for Marvell SD8787 BT + Wifi chip
*
* Copyright ( C ) 2016 Matt Ranostay < matt @ ranostay . consulting >
*
* Based on the original work pwrseq_simple . c
* Copyright ( C ) 2014 Linaro Ltd
* Author : Ulf Hansson < ulf . hansson @ linaro . org >
*/
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/module.h>
2021-08-20 12:28:01 +03:00
# include <linux/of.h>
2017-01-23 19:08:30 -08:00
# include <linux/slab.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/gpio/consumer.h>
# include <linux/mmc/host.h>
# include "pwrseq.h"
struct mmc_pwrseq_sd8787 {
struct mmc_pwrseq pwrseq ;
struct gpio_desc * reset_gpio ;
struct gpio_desc * pwrdn_gpio ;
} ;
# define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq)
static void mmc_pwrseq_sd8787_pre_power_on ( struct mmc_host * host )
{
struct mmc_pwrseq_sd8787 * pwrseq = to_pwrseq_sd8787 ( host - > pwrseq ) ;
gpiod_set_value_cansleep ( pwrseq - > reset_gpio , 1 ) ;
2023-05-13 21:23:52 +02:00
msleep ( 300 ) ;
2017-01-23 19:08:30 -08:00
gpiod_set_value_cansleep ( pwrseq - > pwrdn_gpio , 1 ) ;
}
static void mmc_pwrseq_sd8787_power_off ( struct mmc_host * host )
{
struct mmc_pwrseq_sd8787 * pwrseq = to_pwrseq_sd8787 ( host - > pwrseq ) ;
gpiod_set_value_cansleep ( pwrseq - > pwrdn_gpio , 0 ) ;
gpiod_set_value_cansleep ( pwrseq - > reset_gpio , 0 ) ;
}
2023-05-13 21:23:52 +02:00
static void mmc_pwrseq_wilc1000_pre_power_on ( struct mmc_host * host )
{
struct mmc_pwrseq_sd8787 * pwrseq = to_pwrseq_sd8787 ( host - > pwrseq ) ;
/* The pwrdn_gpio is really CHIP_EN, reset_gpio is RESETN */
gpiod_set_value_cansleep ( pwrseq - > pwrdn_gpio , 1 ) ;
msleep ( 5 ) ;
gpiod_set_value_cansleep ( pwrseq - > reset_gpio , 1 ) ;
}
static void mmc_pwrseq_wilc1000_power_off ( struct mmc_host * host )
{
struct mmc_pwrseq_sd8787 * pwrseq = to_pwrseq_sd8787 ( host - > pwrseq ) ;
gpiod_set_value_cansleep ( pwrseq - > reset_gpio , 0 ) ;
gpiod_set_value_cansleep ( pwrseq - > pwrdn_gpio , 0 ) ;
}
2017-01-23 19:08:30 -08:00
static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = {
. pre_power_on = mmc_pwrseq_sd8787_pre_power_on ,
. power_off = mmc_pwrseq_sd8787_power_off ,
} ;
2023-05-13 21:23:52 +02:00
static const struct mmc_pwrseq_ops mmc_pwrseq_wilc1000_ops = {
. pre_power_on = mmc_pwrseq_wilc1000_pre_power_on ,
. power_off = mmc_pwrseq_wilc1000_power_off ,
} ;
2021-08-25 11:19:31 +03:00
2017-01-23 19:08:30 -08:00
static const struct of_device_id mmc_pwrseq_sd8787_of_match [ ] = {
2023-05-13 21:23:52 +02:00
{ . compatible = " mmc-pwrseq-sd8787 " , . data = & mmc_pwrseq_sd8787_ops } ,
{ . compatible = " mmc-pwrseq-wilc1000 " , . data = & mmc_pwrseq_wilc1000_ops } ,
2017-01-23 19:08:30 -08:00
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , mmc_pwrseq_sd8787_of_match ) ;
static int mmc_pwrseq_sd8787_probe ( struct platform_device * pdev )
{
struct mmc_pwrseq_sd8787 * pwrseq ;
struct device * dev = & pdev - > dev ;
2021-08-20 12:28:01 +03:00
const struct of_device_id * match ;
2017-01-23 19:08:30 -08:00
pwrseq = devm_kzalloc ( dev , sizeof ( * pwrseq ) , GFP_KERNEL ) ;
if ( ! pwrseq )
return - ENOMEM ;
2021-08-20 12:28:01 +03:00
match = of_match_node ( mmc_pwrseq_sd8787_of_match , pdev - > dev . of_node ) ;
2017-01-23 19:08:30 -08:00
pwrseq - > pwrdn_gpio = devm_gpiod_get ( dev , " powerdown " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( pwrseq - > pwrdn_gpio ) )
return PTR_ERR ( pwrseq - > pwrdn_gpio ) ;
pwrseq - > reset_gpio = devm_gpiod_get ( dev , " reset " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( pwrseq - > reset_gpio ) )
return PTR_ERR ( pwrseq - > reset_gpio ) ;
pwrseq - > pwrseq . dev = dev ;
2023-05-13 21:23:52 +02:00
pwrseq - > pwrseq . ops = match - > data ;
2017-01-23 19:08:30 -08:00
pwrseq - > pwrseq . owner = THIS_MODULE ;
platform_set_drvdata ( pdev , pwrseq ) ;
return mmc_pwrseq_register ( & pwrseq - > pwrseq ) ;
}
2023-07-27 15:00:43 +08:00
static void mmc_pwrseq_sd8787_remove ( struct platform_device * pdev )
2017-01-23 19:08:30 -08:00
{
struct mmc_pwrseq_sd8787 * pwrseq = platform_get_drvdata ( pdev ) ;
mmc_pwrseq_unregister ( & pwrseq - > pwrseq ) ;
}
static struct platform_driver mmc_pwrseq_sd8787_driver = {
. probe = mmc_pwrseq_sd8787_probe ,
2023-07-27 15:00:43 +08:00
. remove_new = mmc_pwrseq_sd8787_remove ,
2017-01-23 19:08:30 -08:00
. driver = {
. name = " pwrseq_sd8787 " ,
. of_match_table = mmc_pwrseq_sd8787_of_match ,
} ,
} ;
module_platform_driver ( mmc_pwrseq_sd8787_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;