2020-02-19 13:28:57 +03:00
// SPDX-License-Identifier: GPL-2.0-only
//
// rt5682-sdw.c -- RT5682 ALSA SoC audio component driver
//
// Copyright 2019 Realtek Semiconductor Corp.
// Author: Oder Chiou <oder_chiou@realtek.com>
//
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/pm.h>
# include <linux/acpi.h>
2020-05-28 12:17:17 +03:00
# include <linux/pm_runtime.h>
2020-02-19 13:28:57 +03:00
# include <linux/regulator/consumer.h>
# include <linux/mutex.h>
# include <linux/soundwire/sdw.h>
# include <linux/soundwire/sdw_type.h>
2020-09-08 16:45:15 +03:00
# include <linux/soundwire/sdw_registers.h>
2020-02-19 13:28:57 +03:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/jack.h>
2022-11-23 19:54:28 +03:00
# include <sound/sdw.h>
2020-02-19 13:28:57 +03:00
# include <sound/soc.h>
# include <sound/soc-dapm.h>
# include <sound/initval.h>
# include <sound/tlv.h>
# include "rt5682.h"
2020-05-28 12:17:17 +03:00
# define RT5682_SDW_ADDR_L 0x3000
# define RT5682_SDW_ADDR_H 0x3001
# define RT5682_SDW_DATA_L 0x3004
# define RT5682_SDW_DATA_H 0x3005
# define RT5682_SDW_CMD 0x3008
static int rt5682_sdw_read ( void * context , unsigned int reg , unsigned int * val )
{
struct device * dev = context ;
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
unsigned int data_l , data_h ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_CMD , 0 ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_ADDR_H , ( reg > > 8 ) & 0xff ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_ADDR_L , ( reg & 0xff ) ) ;
regmap_read ( rt5682 - > sdw_regmap , RT5682_SDW_DATA_H , & data_h ) ;
regmap_read ( rt5682 - > sdw_regmap , RT5682_SDW_DATA_L , & data_l ) ;
* val = ( data_h < < 8 ) | data_l ;
dev_vdbg ( dev , " [%s] %04x => %04x \n " , __func__ , reg , * val ) ;
return 0 ;
}
static int rt5682_sdw_write ( void * context , unsigned int reg , unsigned int val )
{
struct device * dev = context ;
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_CMD , 1 ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_ADDR_H , ( reg > > 8 ) & 0xff ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_ADDR_L , ( reg & 0xff ) ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_DATA_H , ( val > > 8 ) & 0xff ) ;
regmap_write ( rt5682 - > sdw_regmap , RT5682_SDW_DATA_L , ( val & 0xff ) ) ;
dev_vdbg ( dev , " [%s] %04x <= %04x \n " , __func__ , reg , val ) ;
return 0 ;
}
static const struct regmap_config rt5682_sdw_indirect_regmap = {
. reg_bits = 16 ,
. val_bits = 16 ,
. max_register = RT5682_I2C_MODE ,
. volatile_reg = rt5682_volatile_register ,
. readable_reg = rt5682_readable_register ,
2023-04-25 20:22:46 +03:00
. cache_type = REGCACHE_MAPLE ,
2020-05-28 12:17:17 +03:00
. reg_defaults = rt5682_reg ,
. num_reg_defaults = RT5682_REG_NUM ,
. use_single_read = true ,
. use_single_write = true ,
. reg_read = rt5682_sdw_read ,
. reg_write = rt5682_sdw_write ,
} ;
static int rt5682_set_sdw_stream ( struct snd_soc_dai * dai , void * sdw_stream ,
int direction )
{
2023-03-24 04:44:08 +03:00
snd_soc_dai_dma_data_set ( dai , direction , sdw_stream ) ;
2020-05-28 12:17:17 +03:00
return 0 ;
}
static void rt5682_sdw_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
snd_soc_dai_set_dma_data ( dai , substream , NULL ) ;
}
static int rt5682_sdw_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
struct snd_soc_component * component = dai - > component ;
struct rt5682_priv * rt5682 = snd_soc_component_get_drvdata ( component ) ;
2022-11-23 19:54:28 +03:00
struct sdw_stream_config stream_config = { 0 } ;
struct sdw_port_config port_config = { 0 } ;
2023-03-24 04:44:08 +03:00
struct sdw_stream_runtime * sdw_stream ;
2022-11-23 19:54:28 +03:00
int retval ;
2020-05-28 12:17:17 +03:00
unsigned int val_p = 0 , val_c = 0 , osr_p = 0 , osr_c = 0 ;
dev_dbg ( dai - > dev , " %s %s " , __func__ , dai - > name ) ;
2023-03-24 04:44:08 +03:00
sdw_stream = snd_soc_dai_get_dma_data ( dai , substream ) ;
if ( ! sdw_stream )
2020-05-28 12:17:17 +03:00
return - ENOMEM ;
if ( ! rt5682 - > slave )
return - EINVAL ;
/* SoundWire specific configuration */
2022-11-23 19:54:28 +03:00
snd_sdw_params_to_config ( substream , params , & stream_config , & port_config ) ;
2020-05-28 12:17:17 +03:00
2022-11-23 19:54:28 +03:00
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
port_config . num = 1 ;
else
port_config . num = 2 ;
2020-05-28 12:17:17 +03:00
retval = sdw_stream_add_slave ( rt5682 - > slave , & stream_config ,
2023-03-24 04:44:08 +03:00
& port_config , 1 , sdw_stream ) ;
2020-05-28 12:17:17 +03:00
if ( retval ) {
2024-03-26 01:18:17 +03:00
dev_err ( dai - > dev , " %s: Unable to configure port \n " , __func__ ) ;
2020-05-28 12:17:17 +03:00
return retval ;
}
switch ( params_rate ( params ) ) {
case 48000 :
val_p = RT5682_SDW_REF_1_48K ;
val_c = RT5682_SDW_REF_2_48K ;
break ;
case 96000 :
val_p = RT5682_SDW_REF_1_96K ;
val_c = RT5682_SDW_REF_2_96K ;
break ;
case 192000 :
val_p = RT5682_SDW_REF_1_192K ;
val_c = RT5682_SDW_REF_2_192K ;
break ;
case 32000 :
val_p = RT5682_SDW_REF_1_32K ;
val_c = RT5682_SDW_REF_2_32K ;
break ;
case 24000 :
val_p = RT5682_SDW_REF_1_24K ;
val_c = RT5682_SDW_REF_2_24K ;
break ;
case 16000 :
val_p = RT5682_SDW_REF_1_16K ;
val_c = RT5682_SDW_REF_2_16K ;
break ;
case 12000 :
val_p = RT5682_SDW_REF_1_12K ;
val_c = RT5682_SDW_REF_2_12K ;
break ;
case 8000 :
val_p = RT5682_SDW_REF_1_8K ;
val_c = RT5682_SDW_REF_2_8K ;
break ;
case 44100 :
val_p = RT5682_SDW_REF_1_44K ;
val_c = RT5682_SDW_REF_2_44K ;
break ;
case 88200 :
val_p = RT5682_SDW_REF_1_88K ;
val_c = RT5682_SDW_REF_2_88K ;
break ;
case 176400 :
val_p = RT5682_SDW_REF_1_176K ;
val_c = RT5682_SDW_REF_2_176K ;
break ;
case 22050 :
val_p = RT5682_SDW_REF_1_22K ;
val_c = RT5682_SDW_REF_2_22K ;
break ;
case 11025 :
val_p = RT5682_SDW_REF_1_11K ;
val_c = RT5682_SDW_REF_2_11K ;
break ;
default :
return - EINVAL ;
}
if ( params_rate ( params ) < = 48000 ) {
osr_p = RT5682_DAC_OSR_D_8 ;
osr_c = RT5682_ADC_OSR_D_8 ;
} else if ( params_rate ( params ) < = 96000 ) {
osr_p = RT5682_DAC_OSR_D_4 ;
osr_c = RT5682_ADC_OSR_D_4 ;
} else {
osr_p = RT5682_DAC_OSR_D_2 ;
osr_c = RT5682_ADC_OSR_D_2 ;
}
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
regmap_update_bits ( rt5682 - > regmap , RT5682_SDW_REF_CLK ,
RT5682_SDW_REF_1_MASK , val_p ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_ADDA_CLK_1 ,
RT5682_DAC_OSR_MASK , osr_p ) ;
} else {
regmap_update_bits ( rt5682 - > regmap , RT5682_SDW_REF_CLK ,
RT5682_SDW_REF_2_MASK , val_c ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_ADDA_CLK_1 ,
RT5682_ADC_OSR_MASK , osr_c ) ;
}
return retval ;
}
static int rt5682_sdw_hw_free ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct snd_soc_component * component = dai - > component ;
struct rt5682_priv * rt5682 = snd_soc_component_get_drvdata ( component ) ;
2023-03-24 04:44:08 +03:00
struct sdw_stream_runtime * sdw_stream =
2020-05-28 12:17:17 +03:00
snd_soc_dai_get_dma_data ( dai , substream ) ;
if ( ! rt5682 - > slave )
return - EINVAL ;
2023-03-24 04:44:08 +03:00
sdw_stream_remove_slave ( rt5682 - > slave , sdw_stream ) ;
2020-05-28 12:17:17 +03:00
return 0 ;
}
2021-02-25 00:19:16 +03:00
static const struct snd_soc_dai_ops rt5682_sdw_ops = {
2020-05-28 12:17:17 +03:00
. hw_params = rt5682_sdw_hw_params ,
. hw_free = rt5682_sdw_hw_free ,
2021-12-24 05:10:31 +03:00
. set_stream = rt5682_set_sdw_stream ,
2020-05-28 12:17:17 +03:00
. shutdown = rt5682_sdw_shutdown ,
} ;
static struct snd_soc_dai_driver rt5682_dai [ ] = {
{
. name = " rt5682-aif1 " ,
. id = RT5682_AIF1 ,
. playback = {
. stream_name = " AIF1 Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = RT5682_STEREO_RATES ,
. formats = RT5682_FORMATS ,
} ,
. capture = {
. stream_name = " AIF1 Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = RT5682_STEREO_RATES ,
. formats = RT5682_FORMATS ,
} ,
. ops = & rt5682_aif1_dai_ops ,
} ,
{
. name = " rt5682-aif2 " ,
. id = RT5682_AIF2 ,
. capture = {
. stream_name = " AIF2 Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = RT5682_STEREO_RATES ,
. formats = RT5682_FORMATS ,
} ,
. ops = & rt5682_aif2_dai_ops ,
} ,
{
. name = " rt5682-sdw " ,
. id = RT5682_SDW ,
. playback = {
. stream_name = " SDW Playback " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = RT5682_STEREO_RATES ,
. formats = RT5682_FORMATS ,
} ,
. capture = {
. stream_name = " SDW Capture " ,
. channels_min = 1 ,
. channels_max = 2 ,
. rates = RT5682_STEREO_RATES ,
. formats = RT5682_FORMATS ,
} ,
. ops = & rt5682_sdw_ops ,
} ,
} ;
static int rt5682_sdw_init ( struct device * dev , struct regmap * regmap ,
struct sdw_slave * slave )
{
struct rt5682_priv * rt5682 ;
int ret ;
rt5682 = devm_kzalloc ( dev , sizeof ( * rt5682 ) , GFP_KERNEL ) ;
if ( ! rt5682 )
return - ENOMEM ;
dev_set_drvdata ( dev , rt5682 ) ;
rt5682 - > slave = slave ;
rt5682 - > sdw_regmap = regmap ;
rt5682 - > is_sdw = true ;
2021-06-14 21:08:14 +03:00
mutex_init ( & rt5682 - > disable_irq_lock ) ;
2020-05-28 12:17:17 +03:00
rt5682 - > regmap = devm_regmap_init ( dev , NULL , dev ,
& rt5682_sdw_indirect_regmap ) ;
if ( IS_ERR ( rt5682 - > regmap ) ) {
ret = PTR_ERR ( rt5682 - > regmap ) ;
2024-03-26 01:18:17 +03:00
dev_err ( dev , " %s: Failed to allocate register map: %d \n " ,
__func__ , ret ) ;
2020-05-28 12:17:17 +03:00
return ret ;
}
2023-08-17 17:03:20 +03:00
ret = rt5682_get_ldo1 ( rt5682 , dev ) ;
if ( ret )
return ret ;
2023-08-02 18:36:16 +03:00
regcache_cache_only ( rt5682 - > sdw_regmap , true ) ;
regcache_cache_only ( rt5682 - > regmap , true ) ;
2020-05-28 12:17:17 +03:00
/*
* Mark hw_init to false
* HW init will be performed when device reports present
*/
rt5682 - > hw_init = false ;
rt5682 - > first_hw_init = false ;
mutex_init ( & rt5682 - > calibrate_mutex ) ;
INIT_DELAYED_WORK ( & rt5682 - > jack_detect_work ,
rt5682_jack_detect_handler ) ;
ret = devm_snd_soc_register_component ( dev ,
& rt5682_soc_component_dev ,
rt5682_dai , ARRAY_SIZE ( rt5682_dai ) ) ;
2023-08-02 18:36:27 +03:00
if ( ret < 0 )
return ret ;
/* set autosuspend parameters */
pm_runtime_set_autosuspend_delay ( dev , 3000 ) ;
pm_runtime_use_autosuspend ( dev ) ;
/* make sure the device does not suspend immediately */
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_enable ( dev ) ;
/* important note: the device is NOT tagged as 'active' and will remain
* ' suspended ' until the hardware is enumerated / initialized . This is required
* to make sure the ASoC framework use of pm_runtime_get_sync ( ) does not silently
* fail with - EACCESS because of race conditions between card creation and enumeration
*/
dev_dbg ( dev , " %s \n " , __func__ ) ;
2020-05-28 12:17:17 +03:00
return ret ;
}
static int rt5682_io_init ( struct device * dev , struct sdw_slave * slave )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
2021-01-11 12:27:40 +03:00
int ret = 0 , loop = 10 ;
2020-05-28 12:17:17 +03:00
unsigned int val ;
2021-06-14 21:08:14 +03:00
rt5682 - > disable_irq = false ;
2020-05-28 12:17:17 +03:00
if ( rt5682 - > hw_init )
return 0 ;
2023-08-02 18:36:16 +03:00
regcache_cache_only ( rt5682 - > sdw_regmap , false ) ;
regcache_cache_only ( rt5682 - > regmap , false ) ;
if ( rt5682 - > first_hw_init )
regcache_cache_bypass ( rt5682 - > regmap , true ) ;
2020-05-28 12:17:17 +03:00
/*
2023-08-02 18:36:27 +03:00
* PM runtime status is marked as ' active ' only when a Slave reports as Attached
2020-05-28 12:17:17 +03:00
*/
2023-08-02 18:36:27 +03:00
if ( ! rt5682 - > first_hw_init )
2020-05-28 12:17:17 +03:00
/* update count of parent 'active' children */
pm_runtime_set_active ( & slave - > dev ) ;
pm_runtime_get_noresume ( & slave - > dev ) ;
2021-01-11 12:27:40 +03:00
while ( loop > 0 ) {
regmap_read ( rt5682 - > regmap , RT5682_DEVICE_ID , & val ) ;
if ( val = = DEVICE_ID )
break ;
dev_warn ( dev , " Device with ID register %x is not rt5682 \n " , val ) ;
usleep_range ( 30000 , 30005 ) ;
loop - - ;
}
2021-06-08 01:22:36 +03:00
2021-01-11 12:27:40 +03:00
if ( val ! = DEVICE_ID ) {
2024-03-26 01:18:17 +03:00
dev_err ( dev , " %s: Device with ID register %x is not rt5682 \n " , __func__ , val ) ;
2021-06-08 01:22:36 +03:00
ret = - ENODEV ;
goto err_nodev ;
2021-01-11 12:27:40 +03:00
}
2020-05-28 12:17:17 +03:00
rt5682_calibrate ( rt5682 ) ;
if ( rt5682 - > first_hw_init ) {
regcache_cache_bypass ( rt5682 - > regmap , false ) ;
regcache_mark_dirty ( rt5682 - > regmap ) ;
regcache_sync ( rt5682 - > regmap ) ;
/* volatile registers */
regmap_update_bits ( rt5682 - > regmap , RT5682_CBJ_CTRL_2 ,
RT5682_EXT_JD_SRC , RT5682_EXT_JD_SRC_MANUAL ) ;
goto reinit ;
}
rt5682_apply_patch_list ( rt5682 , dev ) ;
regmap_write ( rt5682 - > regmap , RT5682_DEPOP_1 , 0x0000 ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_PWR_ANLG_1 ,
RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK ,
RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X ) ;
2020-07-17 10:02:28 +03:00
regmap_write ( rt5682 - > regmap , RT5682_MICBIAS_2 , 0x0080 ) ;
2020-05-28 12:17:17 +03:00
regmap_write ( rt5682 - > regmap , RT5682_TEST_MODE_CTRL_1 , 0x0000 ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_BIAS_CUR_CTRL_8 ,
RT5682_HPA_CP_BIAS_CTRL_MASK , RT5682_HPA_CP_BIAS_3UA ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_CHARGE_PUMP_1 ,
RT5682_CP_CLK_HP_MASK , RT5682_CP_CLK_HP_300KHZ ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_HP_CHARGE_PUMP_1 ,
RT5682_PM_HP_MASK , RT5682_PM_HP_HV ) ;
/* Soundwire */
regmap_write ( rt5682 - > regmap , RT5682_PLL2_INTERNAL , 0xa266 ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL2_CTRL_1 , 0x1700 ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL2_CTRL_2 , 0x0006 ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL2_CTRL_3 , 0x2600 ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL2_CTRL_4 , 0x0c8f ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL_TRACK_2 , 0x3000 ) ;
regmap_write ( rt5682 - > regmap , RT5682_PLL_TRACK_3 , 0x4000 ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_GLB_CLK ,
RT5682_SCLK_SRC_MASK | RT5682_PLL2_SRC_MASK ,
RT5682_SCLK_SRC_PLL2 | RT5682_PLL2_SRC_SDW ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_CBJ_CTRL_2 ,
RT5682_EXT_JD_SRC , RT5682_EXT_JD_SRC_MANUAL ) ;
2021-06-04 09:31:50 +03:00
regmap_write ( rt5682 - > regmap , RT5682_CBJ_CTRL_1 , 0xd142 ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_CBJ_CTRL_5 , 0x0700 , 0x0600 ) ;
2020-05-28 12:17:17 +03:00
regmap_update_bits ( rt5682 - > regmap , RT5682_CBJ_CTRL_3 ,
RT5682_CBJ_IN_BUF_EN , RT5682_CBJ_IN_BUF_EN ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_SAR_IL_CMD_1 ,
RT5682_SAR_POW_MASK , RT5682_SAR_POW_EN ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_RC_CLK_CTRL ,
RT5682_POW_IRQ | RT5682_POW_JDH |
RT5682_POW_ANA , RT5682_POW_IRQ |
RT5682_POW_JDH | RT5682_POW_ANA ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_PWR_ANLG_2 ,
RT5682_PWR_JDH , RT5682_PWR_JDH ) ;
regmap_update_bits ( rt5682 - > regmap , RT5682_IRQ_CTRL_2 ,
RT5682_JD1_EN_MASK | RT5682_JD1_IRQ_MASK ,
RT5682_JD1_EN | RT5682_JD1_IRQ_PUL ) ;
reinit :
mod_delayed_work ( system_power_efficient_wq ,
& rt5682 - > jack_detect_work , msecs_to_jiffies ( 250 ) ) ;
/* Mark Slave initialization complete */
rt5682 - > hw_init = true ;
rt5682 - > first_hw_init = true ;
2021-06-08 01:22:36 +03:00
err_nodev :
2020-05-28 12:17:17 +03:00
pm_runtime_mark_last_busy ( & slave - > dev ) ;
pm_runtime_put_autosuspend ( & slave - > dev ) ;
2021-06-08 01:22:36 +03:00
dev_dbg ( & slave - > dev , " %s hw_init complete: %d \n " , __func__ , ret ) ;
2020-05-28 12:17:17 +03:00
return ret ;
}
2020-02-19 13:28:57 +03:00
static bool rt5682_sdw_readable_register ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case 0x00e0 :
case 0x00f0 :
case 0x3000 :
case 0x3001 :
case 0x3004 :
case 0x3005 :
case 0x3008 :
return true ;
default :
return false ;
}
}
2020-05-28 12:17:17 +03:00
static const struct regmap_config rt5682_sdw_regmap = {
2020-02-19 13:28:57 +03:00
. name = " sdw " ,
. reg_bits = 32 ,
. val_bits = 8 ,
. max_register = RT5682_I2C_MODE ,
. readable_reg = rt5682_sdw_readable_register ,
. cache_type = REGCACHE_NONE ,
. use_single_read = true ,
. use_single_write = true ,
} ;
static int rt5682_update_status ( struct sdw_slave * slave ,
enum sdw_slave_status status )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( & slave - > dev ) ;
if ( status = = SDW_SLAVE_UNATTACHED )
rt5682 - > hw_init = false ;
/*
* Perform initialization only if slave status is present and
* hw_init flag is false
*/
2023-05-18 10:27:45 +03:00
if ( rt5682 - > hw_init | | status ! = SDW_SLAVE_ATTACHED )
2020-02-19 13:28:57 +03:00
return 0 ;
/* perform I/O transfers required for Slave initialization */
return rt5682_io_init ( & slave - > dev , slave ) ;
}
static int rt5682_read_prop ( struct sdw_slave * slave )
{
struct sdw_slave_prop * prop = & slave - > prop ;
2020-08-31 16:43:16 +03:00
int nval , i ;
2020-02-19 13:28:57 +03:00
u32 bit ;
unsigned long addr ;
struct sdw_dpn_prop * dpn ;
2020-09-08 16:45:15 +03:00
prop - > scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
SDW_SCP_INT1_PARITY ;
2020-09-08 16:45:19 +03:00
prop - > quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY ;
2020-09-08 16:45:15 +03:00
2020-02-19 13:28:57 +03:00
prop - > paging_support = false ;
/* first we need to allocate memory for set bits in port lists */
prop - > source_ports = 0x4 ; /* BITMAP: 00000100 */
prop - > sink_ports = 0x2 ; /* BITMAP: 00000010 */
nval = hweight32 ( prop - > source_ports ) ;
prop - > src_dpn_prop = devm_kcalloc ( & slave - > dev , nval ,
sizeof ( * prop - > src_dpn_prop ) ,
GFP_KERNEL ) ;
if ( ! prop - > src_dpn_prop )
return - ENOMEM ;
i = 0 ;
dpn = prop - > src_dpn_prop ;
addr = prop - > source_ports ;
for_each_set_bit ( bit , & addr , 32 ) {
dpn [ i ] . num = bit ;
dpn [ i ] . type = SDW_DPN_FULL ;
dpn [ i ] . simple_ch_prep_sm = true ;
dpn [ i ] . ch_prep_timeout = 10 ;
i + + ;
}
/* do this again for sink now */
nval = hweight32 ( prop - > sink_ports ) ;
prop - > sink_dpn_prop = devm_kcalloc ( & slave - > dev , nval ,
sizeof ( * prop - > sink_dpn_prop ) ,
GFP_KERNEL ) ;
if ( ! prop - > sink_dpn_prop )
return - ENOMEM ;
i = 0 ;
dpn = prop - > sink_dpn_prop ;
addr = prop - > sink_ports ;
for_each_set_bit ( bit , & addr , 32 ) {
dpn [ i ] . num = bit ;
dpn [ i ] . type = SDW_DPN_FULL ;
dpn [ i ] . simple_ch_prep_sm = true ;
dpn [ i ] . ch_prep_timeout = 10 ;
i + + ;
}
/* set the timeout values */
prop - > clk_stop_timeout = 20 ;
/* wake-up event */
prop - > wake_capable = 1 ;
return 0 ;
}
/* Bus clock frequency */
# define RT5682_CLK_FREQ_9600000HZ 9600000
# define RT5682_CLK_FREQ_12000000HZ 12000000
# define RT5682_CLK_FREQ_6000000HZ 6000000
# define RT5682_CLK_FREQ_4800000HZ 4800000
# define RT5682_CLK_FREQ_2400000HZ 2400000
# define RT5682_CLK_FREQ_12288000HZ 12288000
2020-02-28 10:56:09 +03:00
static int rt5682_clock_config ( struct device * dev )
2020-02-19 13:28:57 +03:00
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
unsigned int clk_freq , value ;
clk_freq = ( rt5682 - > params . curr_dr_freq > > 1 ) ;
switch ( clk_freq ) {
case RT5682_CLK_FREQ_12000000HZ :
value = 0x0 ;
break ;
case RT5682_CLK_FREQ_6000000HZ :
value = 0x1 ;
break ;
case RT5682_CLK_FREQ_9600000HZ :
value = 0x2 ;
break ;
case RT5682_CLK_FREQ_4800000HZ :
value = 0x3 ;
break ;
case RT5682_CLK_FREQ_2400000HZ :
value = 0x4 ;
break ;
case RT5682_CLK_FREQ_12288000HZ :
value = 0x5 ;
break ;
default :
return - EINVAL ;
}
regmap_write ( rt5682 - > sdw_regmap , 0xe0 , value ) ;
regmap_write ( rt5682 - > sdw_regmap , 0xf0 , value ) ;
dev_dbg ( dev , " %s complete, clk_freq=%d \n " , __func__ , clk_freq ) ;
return 0 ;
}
static int rt5682_bus_config ( struct sdw_slave * slave ,
struct sdw_bus_params * params )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( & slave - > dev ) ;
int ret ;
memcpy ( & rt5682 - > params , params , sizeof ( * params ) ) ;
ret = rt5682_clock_config ( & slave - > dev ) ;
if ( ret < 0 )
2024-03-26 01:18:17 +03:00
dev_err ( & slave - > dev , " %s: Invalid clk config " , __func__ ) ;
2020-02-19 13:28:57 +03:00
return ret ;
}
static int rt5682_interrupt_callback ( struct sdw_slave * slave ,
struct sdw_slave_intr_status * status )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( & slave - > dev ) ;
dev_dbg ( & slave - > dev ,
" %s control_port_stat=%x " , __func__ , status - > control_port ) ;
2021-06-14 21:08:14 +03:00
mutex_lock ( & rt5682 - > disable_irq_lock ) ;
if ( status - > control_port & 0x4 & & ! rt5682 - > disable_irq ) {
2020-02-19 13:28:57 +03:00
mod_delayed_work ( system_power_efficient_wq ,
2021-03-09 11:58:27 +03:00
& rt5682 - > jack_detect_work , msecs_to_jiffies ( rt5682 - > irq_work_delay_time ) ) ;
2020-02-19 13:28:57 +03:00
}
2021-06-14 21:08:14 +03:00
mutex_unlock ( & rt5682 - > disable_irq_lock ) ;
2020-02-19 13:28:57 +03:00
return 0 ;
}
2021-02-25 00:19:15 +03:00
static const struct sdw_slave_ops rt5682_slave_ops = {
2020-02-19 13:28:57 +03:00
. read_prop = rt5682_read_prop ,
. interrupt_callback = rt5682_interrupt_callback ,
. update_status = rt5682_update_status ,
. bus_config = rt5682_bus_config ,
} ;
static int rt5682_sdw_probe ( struct sdw_slave * slave ,
const struct sdw_device_id * id )
{
struct regmap * regmap ;
/* Regmap Initialization */
regmap = devm_regmap_init_sdw ( slave , & rt5682_sdw_regmap ) ;
if ( IS_ERR ( regmap ) )
return - EINVAL ;
2023-08-02 18:36:14 +03:00
return rt5682_sdw_init ( & slave - > dev , regmap , slave ) ;
2020-02-19 13:28:57 +03:00
}
static int rt5682_sdw_remove ( struct sdw_slave * slave )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( & slave - > dev ) ;
2022-06-06 23:37:46 +03:00
if ( rt5682 - > hw_init )
2021-02-04 23:17:38 +03:00
cancel_delayed_work_sync ( & rt5682 - > jack_detect_work ) ;
2020-02-19 13:28:57 +03:00
2023-08-02 18:36:27 +03:00
pm_runtime_disable ( & slave - > dev ) ;
2022-06-06 23:37:46 +03:00
2020-02-19 13:28:57 +03:00
return 0 ;
}
static const struct sdw_device_id rt5682_id [ ] = {
2020-08-18 17:14:35 +03:00
SDW_SLAVE_ENTRY_EXT ( 0x025d , 0x5682 , 0x2 , 0 , 0 ) ,
2020-02-19 13:28:57 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( sdw , rt5682_id ) ;
2020-03-10 19:35:09 +03:00
static int __maybe_unused rt5682_dev_suspend ( struct device * dev )
2020-02-19 13:28:57 +03:00
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
if ( ! rt5682 - > hw_init )
return 0 ;
2021-02-04 23:17:38 +03:00
cancel_delayed_work_sync ( & rt5682 - > jack_detect_work ) ;
2023-08-02 18:36:16 +03:00
regcache_cache_only ( rt5682 - > sdw_regmap , true ) ;
2020-02-19 13:28:57 +03:00
regcache_cache_only ( rt5682 - > regmap , true ) ;
regcache_mark_dirty ( rt5682 - > regmap ) ;
return 0 ;
}
2021-06-14 21:08:14 +03:00
static int __maybe_unused rt5682_dev_system_suspend ( struct device * dev )
{
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
struct sdw_slave * slave = dev_to_sdw_dev ( dev ) ;
int ret ;
if ( ! rt5682 - > hw_init )
return 0 ;
/*
* prevent new interrupts from being handled after the
* deferred work completes and before the parent disables
* interrupts on the link
*/
mutex_lock ( & rt5682 - > disable_irq_lock ) ;
rt5682 - > disable_irq = true ;
ret = sdw_update_no_pm ( slave , SDW_SCP_INTMASK1 ,
SDW_SCP_INT1_IMPL_DEF , 0 ) ;
mutex_unlock ( & rt5682 - > disable_irq_lock ) ;
if ( ret < 0 ) {
/* log but don't prevent suspend from happening */
dev_dbg ( & slave - > dev , " %s: could not disable imp-def interrupts \n : " , __func__ ) ;
}
return rt5682_dev_suspend ( dev ) ;
}
2020-03-10 19:35:09 +03:00
static int __maybe_unused rt5682_dev_resume ( struct device * dev )
2020-02-19 13:28:57 +03:00
{
struct sdw_slave * slave = dev_to_sdw_dev ( dev ) ;
struct rt5682_priv * rt5682 = dev_get_drvdata ( dev ) ;
unsigned long time ;
2021-06-08 01:22:29 +03:00
if ( ! rt5682 - > first_hw_init )
2020-02-19 13:28:57 +03:00
return 0 ;
2023-07-21 12:06:43 +03:00
if ( ! slave - > unattach_request ) {
2024-03-26 01:18:12 +03:00
mutex_lock ( & rt5682 - > disable_irq_lock ) ;
2023-07-21 12:06:43 +03:00
if ( rt5682 - > disable_irq = = true ) {
sdw_write_no_pm ( slave , SDW_SCP_INTMASK1 , SDW_SCP_INT1_IMPL_DEF ) ;
rt5682 - > disable_irq = false ;
}
2024-03-26 01:18:12 +03:00
mutex_unlock ( & rt5682 - > disable_irq_lock ) ;
2020-02-19 13:28:57 +03:00
goto regmap_sync ;
2023-07-21 12:06:43 +03:00
}
2020-02-19 13:28:57 +03:00
time = wait_for_completion_timeout ( & slave - > initialization_complete ,
msecs_to_jiffies ( RT5682_PROBE_TIMEOUT ) ) ;
if ( ! time ) {
2024-03-26 01:18:17 +03:00
dev_err ( & slave - > dev , " %s: Initialization not complete, timed out \n " , __func__ ) ;
2022-07-14 04:10:43 +03:00
sdw_show_ping_status ( slave - > bus , true ) ;
2020-02-19 13:28:57 +03:00
return - ETIMEDOUT ;
}
regmap_sync :
slave - > unattach_request = 0 ;
2023-08-02 18:36:16 +03:00
regcache_cache_only ( rt5682 - > sdw_regmap , false ) ;
2020-02-19 13:28:57 +03:00
regcache_cache_only ( rt5682 - > regmap , false ) ;
regcache_sync ( rt5682 - > regmap ) ;
return 0 ;
}
static const struct dev_pm_ops rt5682_pm = {
2021-06-14 21:08:14 +03:00
SET_SYSTEM_SLEEP_PM_OPS ( rt5682_dev_system_suspend , rt5682_dev_resume )
2020-02-19 13:28:57 +03:00
SET_RUNTIME_PM_OPS ( rt5682_dev_suspend , rt5682_dev_resume , NULL )
} ;
static struct sdw_driver rt5682_sdw_driver = {
. driver = {
. name = " rt5682 " ,
. owner = THIS_MODULE ,
. pm = & rt5682_pm ,
} ,
. probe = rt5682_sdw_probe ,
. remove = rt5682_sdw_remove ,
. ops = & rt5682_slave_ops ,
. id_table = rt5682_id ,
} ;
module_sdw_driver ( rt5682_sdw_driver ) ;
MODULE_DESCRIPTION ( " ASoC RT5682 driver SDW " ) ;
MODULE_AUTHOR ( " Oder Chiou <oder_chiou@realtek.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;