2019-04-17 17:16:29 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// arizona-micsupp.c -- Microphone supply for Arizona devices
//
// Copyright 2012 Wolfson Microelectronics PLC.
//
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
2012-06-14 21:14:00 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/bitops.h>
# include <linux/err.h>
2014-05-08 20:17:38 +04:00
# include <linux/of.h>
2012-06-14 21:14:00 +04:00
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
2014-04-16 13:01:41 +04:00
# include <linux/regulator/of_regulator.h>
2012-06-14 21:14:00 +04:00
# include <linux/gpio.h>
# include <linux/slab.h>
2013-01-10 23:14:11 +04:00
# include <linux/workqueue.h>
# include <sound/soc.h>
2012-06-14 21:14:00 +04:00
# include <linux/mfd/arizona/core.h>
# include <linux/mfd/arizona/pdata.h>
# include <linux/mfd/arizona/registers.h>
2017-04-18 13:43:49 +03:00
# include <linux/regulator/arizona-micsupp.h>
2012-06-14 21:14:00 +04:00
struct arizona_micsupp {
struct regulator_dev * regulator ;
2017-04-18 13:43:50 +03:00
struct regmap * regmap ;
struct snd_soc_dapm_context * * dapm ;
unsigned int enable_reg ;
struct device * dev ;
2012-06-14 21:14:00 +04:00
struct regulator_consumer_supply supply ;
struct regulator_init_data init_data ;
2013-01-10 23:14:11 +04:00
struct work_struct check_cp_work ;
2012-06-14 21:14:00 +04:00
} ;
2013-01-10 23:14:11 +04:00
static void arizona_micsupp_check_cp ( struct work_struct * work )
{
struct arizona_micsupp * micsupp =
container_of ( work , struct arizona_micsupp , check_cp_work ) ;
2017-04-18 13:43:50 +03:00
struct snd_soc_dapm_context * dapm = * micsupp - > dapm ;
struct snd_soc_component * component ;
unsigned int val ;
2013-01-10 23:14:11 +04:00
int ret ;
2017-04-18 13:43:50 +03:00
ret = regmap_read ( micsupp - > regmap , micsupp - > enable_reg , & val ) ;
2013-01-10 23:14:11 +04:00
if ( ret ! = 0 ) {
2017-04-18 13:43:50 +03:00
dev_err ( micsupp - > dev ,
" Failed to read CP state: %d \n " , ret ) ;
2013-01-10 23:14:11 +04:00
return ;
}
if ( dapm ) {
2017-04-18 13:43:50 +03:00
component = snd_soc_dapm_to_component ( dapm ) ;
if ( ( val & ( ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS ) ) = =
2013-01-10 23:14:11 +04:00
ARIZONA_CPMIC_ENA )
2016-12-15 17:43:49 +03:00
snd_soc_component_force_enable_pin ( component ,
" MICSUPP " ) ;
2013-01-10 23:14:11 +04:00
else
2016-12-15 17:43:49 +03:00
snd_soc_component_disable_pin ( component , " MICSUPP " ) ;
2013-01-10 23:14:11 +04:00
snd_soc_dapm_sync ( dapm ) ;
}
}
static int arizona_micsupp_enable ( struct regulator_dev * rdev )
{
struct arizona_micsupp * micsupp = rdev_get_drvdata ( rdev ) ;
int ret ;
ret = regulator_enable_regmap ( rdev ) ;
if ( ret = = 0 )
schedule_work ( & micsupp - > check_cp_work ) ;
return ret ;
}
static int arizona_micsupp_disable ( struct regulator_dev * rdev )
{
struct arizona_micsupp * micsupp = rdev_get_drvdata ( rdev ) ;
int ret ;
ret = regulator_disable_regmap ( rdev ) ;
if ( ret = = 0 )
schedule_work ( & micsupp - > check_cp_work ) ;
return ret ;
}
static int arizona_micsupp_set_bypass ( struct regulator_dev * rdev , bool ena )
{
struct arizona_micsupp * micsupp = rdev_get_drvdata ( rdev ) ;
int ret ;
ret = regulator_set_bypass_regmap ( rdev , ena ) ;
if ( ret = = 0 )
schedule_work ( & micsupp - > check_cp_work ) ;
return ret ;
}
2017-01-28 16:40:00 +03:00
static const struct regulator_ops arizona_micsupp_ops = {
2013-01-10 23:14:11 +04:00
. enable = arizona_micsupp_enable ,
. disable = arizona_micsupp_disable ,
2012-06-14 21:14:00 +04:00
. is_enabled = regulator_is_enabled_regmap ,
2013-11-15 17:13:32 +04:00
. list_voltage = regulator_list_voltage_linear_range ,
. map_voltage = regulator_map_voltage_linear_range ,
2012-06-14 21:14:00 +04:00
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
2012-08-28 03:04:47 +04:00
. get_bypass = regulator_get_bypass_regmap ,
2013-01-10 23:14:11 +04:00
. set_bypass = arizona_micsupp_set_bypass ,
2012-06-14 21:14:00 +04:00
} ;
2013-11-15 17:13:32 +04:00
static const struct regulator_linear_range arizona_micsupp_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 1700000 , 0 , 0x1e , 50000 ) ,
REGULATOR_LINEAR_RANGE ( 3300000 , 0x1f , 0x1f , 0 ) ,
} ;
2012-06-14 21:14:00 +04:00
static const struct regulator_desc arizona_micsupp = {
. name = " MICVDD " ,
. supply_name = " CPVDD " ,
. type = REGULATOR_VOLTAGE ,
2013-11-15 17:13:32 +04:00
. n_voltages = 32 ,
2012-06-14 21:14:00 +04:00
. ops = & arizona_micsupp_ops ,
. vsel_reg = ARIZONA_LDO2_CONTROL_1 ,
. vsel_mask = ARIZONA_LDO2_VSEL_MASK ,
. enable_reg = ARIZONA_MIC_CHARGE_PUMP_1 ,
. enable_mask = ARIZONA_CPMIC_ENA ,
2012-08-28 03:04:47 +04:00
. bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1 ,
. bypass_mask = ARIZONA_CPMIC_BYPASS ,
2012-06-14 21:14:00 +04:00
2013-11-15 17:13:32 +04:00
. linear_ranges = arizona_micsupp_ranges ,
. n_linear_ranges = ARRAY_SIZE ( arizona_micsupp_ranges ) ,
2012-11-27 18:55:49 +04:00
. enable_time = 3000 ,
2012-06-14 21:14:00 +04:00
. owner = THIS_MODULE ,
} ;
2013-11-15 17:48:23 +04:00
static const struct regulator_linear_range arizona_micsupp_ext_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 900000 , 0 , 0x14 , 25000 ) ,
REGULATOR_LINEAR_RANGE ( 1500000 , 0x15 , 0x27 , 100000 ) ,
} ;
static const struct regulator_desc arizona_micsupp_ext = {
. name = " MICVDD " ,
. supply_name = " CPVDD " ,
. type = REGULATOR_VOLTAGE ,
. n_voltages = 40 ,
. ops = & arizona_micsupp_ops ,
. vsel_reg = ARIZONA_LDO2_CONTROL_1 ,
. vsel_mask = ARIZONA_LDO2_VSEL_MASK ,
. enable_reg = ARIZONA_MIC_CHARGE_PUMP_1 ,
. enable_mask = ARIZONA_CPMIC_ENA ,
. bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1 ,
. bypass_mask = ARIZONA_CPMIC_BYPASS ,
. linear_ranges = arizona_micsupp_ext_ranges ,
. n_linear_ranges = ARRAY_SIZE ( arizona_micsupp_ext_ranges ) ,
. enable_time = 3000 ,
. owner = THIS_MODULE ,
} ;
2012-06-14 21:14:00 +04:00
static const struct regulator_init_data arizona_micsupp_default = {
. constraints = {
. valid_ops_mask = REGULATOR_CHANGE_STATUS |
2013-01-10 23:31:47 +04:00
REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_BYPASS ,
2012-06-14 21:14:00 +04:00
. min_uV = 1700000 ,
. max_uV = 3300000 ,
} ,
. num_consumer_supplies = 1 ,
} ;
2013-11-15 17:48:23 +04:00
static const struct regulator_init_data arizona_micsupp_ext_default = {
. constraints = {
. valid_ops_mask = REGULATOR_CHANGE_STATUS |
REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_BYPASS ,
. min_uV = 900000 ,
. max_uV = 3300000 ,
} ,
. num_consumer_supplies = 1 ,
} ;
2017-04-18 13:43:49 +03:00
static int arizona_micsupp_of_get_pdata ( struct arizona_micsupp_pdata * pdata ,
2014-11-10 16:43:53 +03:00
struct regulator_config * config ,
const struct regulator_desc * desc )
2014-04-16 13:01:41 +04:00
{
struct arizona_micsupp * micsupp = config - > driver_data ;
struct device_node * np ;
struct regulator_init_data * init_data ;
2017-04-18 13:43:49 +03:00
np = of_get_child_by_name ( config - > dev - > of_node , " micvdd " ) ;
2014-04-16 13:01:41 +04:00
if ( np ) {
config - > of_node = np ;
2017-04-18 13:43:49 +03:00
init_data = of_get_regulator_init_data ( config - > dev , np , desc ) ;
2014-04-16 13:01:41 +04:00
if ( init_data ) {
init_data - > consumer_supplies = & micsupp - > supply ;
init_data - > num_consumer_supplies = 1 ;
2017-04-18 13:43:49 +03:00
pdata - > init_data = init_data ;
2014-04-16 13:01:41 +04:00
}
}
return 0 ;
}
2017-04-18 13:43:51 +03:00
static int arizona_micsupp_common_init ( struct platform_device * pdev ,
struct arizona_micsupp * micsupp ,
const struct regulator_desc * desc ,
struct arizona_micsupp_pdata * pdata )
2012-06-14 21:14:00 +04:00
{
struct regulator_config config = { } ;
int ret ;
2013-01-10 23:14:11 +04:00
INIT_WORK ( & micsupp - > check_cp_work , arizona_micsupp_check_cp ) ;
2012-06-14 21:14:00 +04:00
micsupp - > init_data . consumer_supplies = & micsupp - > supply ;
micsupp - > supply . supply = " MICVDD " ;
2017-04-18 13:43:51 +03:00
micsupp - > supply . dev_name = dev_name ( micsupp - > dev ) ;
2017-04-18 13:43:50 +03:00
micsupp - > enable_reg = desc - > enable_reg ;
2012-06-14 21:14:00 +04:00
2017-04-18 13:43:51 +03:00
config . dev = micsupp - > dev ;
2012-06-14 21:14:00 +04:00
config . driver_data = micsupp ;
2017-04-18 13:43:51 +03:00
config . regmap = micsupp - > regmap ;
2012-06-14 21:14:00 +04:00
2014-04-16 13:01:41 +04:00
if ( IS_ENABLED ( CONFIG_OF ) ) {
2017-04-18 13:43:51 +03:00
if ( ! dev_get_platdata ( micsupp - > dev ) ) {
2017-04-18 13:43:49 +03:00
ret = arizona_micsupp_of_get_pdata ( pdata , & config ,
desc ) ;
2014-04-16 13:01:41 +04:00
if ( ret < 0 )
return ret ;
}
}
2017-04-18 13:43:49 +03:00
if ( pdata - > init_data )
config . init_data = pdata - > init_data ;
2012-06-14 21:14:00 +04:00
else
config . init_data = & micsupp - > init_data ;
2017-04-18 13:43:51 +03:00
/* Default to regulated mode */
regmap_update_bits ( micsupp - > regmap , micsupp - > enable_reg ,
2012-07-04 15:50:02 +04:00
ARIZONA_CPMIC_BYPASS , 0 ) ;
2013-08-31 14:57:00 +04:00
micsupp - > regulator = devm_regulator_register ( & pdev - > dev ,
2013-11-15 17:48:23 +04:00
desc ,
2013-08-31 14:57:00 +04:00
& config ) ;
2015-02-20 19:08:44 +03:00
of_node_put ( config . of_node ) ;
2012-06-14 21:14:00 +04:00
if ( IS_ERR ( micsupp - > regulator ) ) {
ret = PTR_ERR ( micsupp - > regulator ) ;
2017-04-18 13:43:51 +03:00
dev_err ( micsupp - > dev , " Failed to register mic supply: %d \n " ,
2012-06-14 21:14:00 +04:00
ret ) ;
return ret ;
}
platform_set_drvdata ( pdev , micsupp ) ;
return 0 ;
}
2017-04-18 13:43:51 +03:00
static int arizona_micsupp_probe ( struct platform_device * pdev )
{
struct arizona * arizona = dev_get_drvdata ( pdev - > dev . parent ) ;
const struct regulator_desc * desc ;
struct arizona_micsupp * micsupp ;
micsupp = devm_kzalloc ( & pdev - > dev , sizeof ( * micsupp ) , GFP_KERNEL ) ;
if ( ! micsupp )
return - ENOMEM ;
micsupp - > regmap = arizona - > regmap ;
micsupp - > dapm = & arizona - > dapm ;
micsupp - > dev = arizona - > dev ;
/*
* Since the chip usually supplies itself we provide some
* default init_data for it . This will be overridden with
* platform data if provided .
*/
switch ( arizona - > type ) {
case WM5110 :
case WM8280 :
desc = & arizona_micsupp_ext ;
micsupp - > init_data = arizona_micsupp_ext_default ;
break ;
default :
desc = & arizona_micsupp ;
micsupp - > init_data = arizona_micsupp_default ;
break ;
}
return arizona_micsupp_common_init ( pdev , micsupp , desc ,
& arizona - > pdata . micvdd ) ;
}
2012-06-14 21:14:00 +04:00
static struct platform_driver arizona_micsupp_driver = {
. probe = arizona_micsupp_probe ,
. driver = {
. name = " arizona-micsupp " ,
} ,
} ;
module_platform_driver ( arizona_micsupp_driver ) ;
/* Module information */
MODULE_AUTHOR ( " Mark Brown <broonie@opensource.wolfsonmicro.com> " ) ;
MODULE_DESCRIPTION ( " Arizona microphone supply driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:arizona-micsupp " ) ;