MoroSound v2.1.1: Sound driver for Galaxy S9 (Madera CS47L92)
- Headphone Gain control - 5 Bands Equalizer Based on the Boeffla Sound 1.6 for Galaxy S3 Credits: andip71, author of Boeffla Sound Supercurio, Yank555 and Gokhanmoral. AndreiLux, for his Arizona control sound mod Flar2, for his speaker gain mod Signed-off-by: djb77 <dwayne.bakewell@gmail.com>
This commit is contained in:
parent
374f4688f0
commit
f810ad12f6
7 changed files with 1091 additions and 0 deletions
|
@ -5958,3 +5958,4 @@ CONFIG_OID_REGISTRY=y
|
|||
CONFIG_SG_POOL=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
CONFIG_SBITMAP=y
|
||||
CONFIG_MORO_SOUND=y
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
*/
|
||||
#undef LOG_DEVICE
|
||||
|
||||
int moro_sound_write_hook(unsigned int reg, unsigned int val);
|
||||
|
||||
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val,
|
||||
bool *change, bool force_write);
|
||||
|
@ -1635,6 +1637,8 @@ int _regmap_write(struct regmap *map, unsigned int reg,
|
|||
if (!regmap_writeable(map, reg))
|
||||
return -EIO;
|
||||
|
||||
val = moro_sound_write_hook(reg, val);
|
||||
|
||||
if (!map->cache_bypass && !map->defer_caching) {
|
||||
ret = regcache_write(map, reg, val);
|
||||
if (ret != 0)
|
||||
|
@ -1655,6 +1659,37 @@ int _regmap_write(struct regmap *map, unsigned int reg,
|
|||
return map->reg_write(context, reg, val);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MORO_SOUND
|
||||
int _regmap_write_nohook(struct regmap *map, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
void *context = _regmap_map_get_context(map);
|
||||
|
||||
if (!regmap_writeable(map, reg))
|
||||
return -EIO;
|
||||
|
||||
if (!map->cache_bypass && !map->defer_caching) {
|
||||
ret = regcache_write(map, reg, val);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (map->cache_only) {
|
||||
map->cache_dirty = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LOG_DEVICE
|
||||
if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
|
||||
dev_info(map->dev, "%x <= %x\n", reg, val);
|
||||
#endif
|
||||
|
||||
trace_regmap_reg_write(map, reg, val);
|
||||
|
||||
return map->reg_write(context, reg, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* regmap_write(): Write a value to a single register
|
||||
*
|
||||
|
|
|
@ -1145,4 +1145,8 @@ config SND_SOC_TPA6130A2
|
|||
tristate "Texas Instruments TPA6130A2 headphone amplifier"
|
||||
depends on I2C
|
||||
|
||||
config MORO_SOUND
|
||||
bool "Sound control for S9 madera driver"
|
||||
default y
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -453,6 +453,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
|
|||
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
|
||||
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
|
||||
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
|
||||
obj-$(CONFIG_MORO_SOUND) += moro_sound.o
|
||||
|
||||
# Amp
|
||||
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include "madera.h"
|
||||
#include "wm_adsp.h"
|
||||
|
||||
#ifdef CONFIG_MORO_SOUND
|
||||
#include "moro_sound.h"
|
||||
#endif
|
||||
|
||||
#define CS47L92_NUM_ADSP 1
|
||||
#define CS47L92_MONO_OUTPUTS 3
|
||||
|
||||
|
@ -1981,6 +1985,10 @@ static int cs47l92_codec_probe(struct snd_soc_codec *codec)
|
|||
MADERA_AUXPDM1_TXEDGE_MASK |
|
||||
MADERA_AUXPDM1_MSTR_MASK, val);
|
||||
|
||||
#ifdef CONFIG_MORO_SOUND
|
||||
moro_sound_hook_madera_pcm_probe(madera->regmap);
|
||||
#endif
|
||||
|
||||
ret = madera_init_outputs(codec, CS47L92_MONO_OUTPUTS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
980
sound/soc/codecs/moro_sound.c
Normal file
980
sound/soc/codecs/moro_sound.c
Normal file
|
@ -0,0 +1,980 @@
|
|||
/*
|
||||
* moro_sound.c -- Sound mod for Madera/CS47L92, S9 sound driver
|
||||
*
|
||||
* Author : @morogoku https://github.com/morogoku
|
||||
*
|
||||
* Date : March 2019 - v2.0
|
||||
*
|
||||
*
|
||||
* Based on the Boeffla Sound 1.6 for Galaxy S3
|
||||
*
|
||||
* Credits: andip71, author of Boeffla Sound
|
||||
* Supercurio, Yank555 and Gokhanmoral.
|
||||
*
|
||||
* AndreiLux, for his Arizona control sound mod
|
||||
*
|
||||
* Flar2, for his speaker gain mod
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "moro_sound.h"
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Variables
|
||||
/*****************************************/
|
||||
|
||||
// pointer to regmap
|
||||
static struct regmap *map;
|
||||
|
||||
// internal moro sound variables
|
||||
static int first = 1; // first access
|
||||
|
||||
static int moro_sound; // moro sound master switch
|
||||
static int debug; // debug switch
|
||||
|
||||
static int headphone_gain_l; // headphone volume left
|
||||
static int headphone_gain_r; // headphone volume right
|
||||
|
||||
static int out2l_mix_source; // out2 mix source left
|
||||
static int out2r_mix_source; // out2 mix source right
|
||||
static int eq1_mix_source; // eq1 mix source left
|
||||
static int eq2_mix_source; // eq2 mix soirce right
|
||||
|
||||
static int eq; // eq master switch
|
||||
static int eq_gains[5] = {EQ_GAIN_DEFAULT}; // eq 5 bands gains
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Internal function declarations
|
||||
/*****************************************/
|
||||
|
||||
static unsigned int get_headphone_gain_l(void);
|
||||
static unsigned int get_headphone_gain_r(void);
|
||||
static void set_headphone_gain_l(int gain);
|
||||
static void set_headphone_gain_r(int gain);
|
||||
|
||||
static void set_out2l_mix_source(int value);
|
||||
static void set_out2r_mix_source(int value);
|
||||
|
||||
static void set_eq1_mix_source(int value);
|
||||
static void set_eq2_mix_source(int value);
|
||||
|
||||
static void set_eq(void);
|
||||
static void set_eq_gains(void);
|
||||
|
||||
static void reset_moro_sound(void);
|
||||
static void reset_audio_hub(void);
|
||||
static void update_audio_hub(void);
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Internal helper functions
|
||||
/*****************************************/
|
||||
|
||||
#define _write(reg, val) _regmap_write_nohook(map, reg, val)
|
||||
|
||||
#define _read(reg, val) regmap_read(map, reg, val)
|
||||
|
||||
static unsigned int get_headphone_gain_l(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_DAC_DIGITAL_VOLUME_2L, &val);
|
||||
val &= MADERA_OUT2L_VOL_MASK;
|
||||
val >>= MADERA_OUT2L_VOL_SHIFT;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void set_headphone_gain_l(int gain)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_DAC_DIGITAL_VOLUME_2L, &val);
|
||||
val &= ~MADERA_OUT2L_VOL_MASK;
|
||||
val |= (gain << MADERA_OUT2L_VOL_SHIFT);
|
||||
_write(MADERA_DAC_DIGITAL_VOLUME_2L, val);
|
||||
}
|
||||
|
||||
static unsigned int get_headphone_gain_r(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_DAC_DIGITAL_VOLUME_2R, &val);
|
||||
val &= MADERA_OUT2R_VOL_MASK;
|
||||
val >>= MADERA_OUT2R_VOL_SHIFT;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void set_headphone_gain_r(int gain)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_DAC_DIGITAL_VOLUME_2R, &val);
|
||||
val &= ~MADERA_OUT2R_VOL_MASK;
|
||||
val |= (gain << MADERA_OUT2R_VOL_SHIFT);
|
||||
_write(MADERA_DAC_DIGITAL_VOLUME_2R, val);
|
||||
}
|
||||
|
||||
static void set_out2l_mix_source(int value)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_OUT2LMIX_INPUT_1_SOURCE, &val);
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (value << MADERA_MIXER_SOURCE_SHIFT);
|
||||
_write(MADERA_OUT2LMIX_INPUT_1_SOURCE, val);
|
||||
}
|
||||
|
||||
static void set_out2r_mix_source(int value)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_OUT2RMIX_INPUT_1_SOURCE, &val);
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (value << MADERA_MIXER_SOURCE_SHIFT);
|
||||
_write(MADERA_OUT2RMIX_INPUT_1_SOURCE, val);
|
||||
}
|
||||
|
||||
static void set_eq1_mix_source(int value)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_EQ1MIX_INPUT_1_SOURCE, &val);
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (value << MADERA_MIXER_SOURCE_SHIFT);
|
||||
_write(MADERA_EQ1MIX_INPUT_1_SOURCE, val);
|
||||
}
|
||||
|
||||
|
||||
static void set_eq2_mix_source(int value)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
_read(MADERA_EQ2MIX_INPUT_1_SOURCE, &val);
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (value << MADERA_MIXER_SOURCE_SHIFT);
|
||||
_write(MADERA_EQ2MIX_INPUT_1_SOURCE, val);
|
||||
}
|
||||
|
||||
static void set_eq(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
// If EQ is enabled
|
||||
if (eq & moro_sound)
|
||||
{
|
||||
// Enable EQ1 for left channel
|
||||
_read(MADERA_EQ1_1, &val);
|
||||
val &= ~MADERA_EQ1_ENA_MASK;
|
||||
val |= 1 << MADERA_EQ1_ENA_SHIFT;
|
||||
_write(MADERA_EQ1_1, val);
|
||||
|
||||
// Enable EQ2 for right channel
|
||||
_read(MADERA_EQ2_1, &val);
|
||||
val &= ~MADERA_EQ2_ENA_MASK;
|
||||
val |= 1 << MADERA_EQ2_ENA_SHIFT;
|
||||
_write(MADERA_EQ2_1, val);
|
||||
|
||||
// Set mixers
|
||||
eq1_mix_source = 32; // EQ1 -> AIF1 RX1 left
|
||||
eq2_mix_source = 33; // EQ2 -> AIF1 RX2 right
|
||||
set_eq1_mix_source(eq1_mix_source);
|
||||
set_eq2_mix_source(eq2_mix_source);
|
||||
|
||||
out2l_mix_source = 80; // OUT2L -> EQ1 left
|
||||
out2r_mix_source = 81; // OUT2R -> EQ2 right
|
||||
set_out2l_mix_source(out2l_mix_source);
|
||||
set_out2r_mix_source(out2r_mix_source);
|
||||
}
|
||||
// If EQ is disabled
|
||||
else
|
||||
{
|
||||
// Disable EQ1
|
||||
_read(MADERA_EQ1_1, &val);
|
||||
val &= ~MADERA_EQ1_ENA_MASK;
|
||||
val |= 0 << MADERA_EQ1_ENA_SHIFT;
|
||||
_write(MADERA_EQ1_1, val);
|
||||
|
||||
// Disable EQ2
|
||||
_read(MADERA_EQ2_1, &val);
|
||||
val &= ~MADERA_EQ2_ENA_MASK;
|
||||
val |= 0 << MADERA_EQ2_ENA_SHIFT;
|
||||
_write(MADERA_EQ2_1, val);
|
||||
|
||||
// Set mixers to default
|
||||
eq1_mix_source = EQ1_MIX_DEFAULT;
|
||||
eq2_mix_source = EQ2_MIX_DEFAULT;
|
||||
set_eq1_mix_source(eq1_mix_source);
|
||||
set_eq2_mix_source(eq2_mix_source);
|
||||
|
||||
out2l_mix_source = OUT2L_MIX_DEFAULT;
|
||||
out2r_mix_source = OUT2R_MIX_DEFAULT;
|
||||
set_out2l_mix_source(out2l_mix_source);
|
||||
set_out2r_mix_source(out2r_mix_source);
|
||||
}
|
||||
|
||||
set_eq_gains();
|
||||
}
|
||||
|
||||
static void set_eq_gains(void)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int gain1, gain2, gain3, gain4, gain5;
|
||||
|
||||
gain1 = eq_gains[0];
|
||||
gain2 = eq_gains[1];
|
||||
gain3 = eq_gains[2];
|
||||
gain4 = eq_gains[3];
|
||||
gain5 = eq_gains[4];
|
||||
|
||||
// First register
|
||||
// read current value from audio hub and mask all bits apart from equalizer enabled bit,
|
||||
// add individual gains and write back to audio hub
|
||||
_read(MADERA_EQ1_1, &val);
|
||||
val &= MADERA_EQ1_ENA_MASK;
|
||||
val |= ((gain1 + EQ_GAIN_OFFSET) << MADERA_EQ1_B1_GAIN_SHIFT);
|
||||
val |= ((gain2 + EQ_GAIN_OFFSET) << MADERA_EQ1_B2_GAIN_SHIFT);
|
||||
val |= ((gain3 + EQ_GAIN_OFFSET) << MADERA_EQ1_B3_GAIN_SHIFT);
|
||||
_write(MADERA_EQ1_1, val);
|
||||
_write(MADERA_EQ2_1, val);
|
||||
|
||||
// second register
|
||||
// read current value from audio hub and mask all bits apart from band1 mode bit,
|
||||
// set individual gains and write back to audio hub
|
||||
_read(MADERA_EQ1_2, &val);
|
||||
val &= MADERA_EQ1_B1_MODE_MASK;
|
||||
val |= ((gain4 + EQ_GAIN_OFFSET) << MADERA_EQ1_B4_GAIN_SHIFT);
|
||||
val |= ((gain5 + EQ_GAIN_OFFSET) << MADERA_EQ1_B5_GAIN_SHIFT);
|
||||
_write(MADERA_EQ1_2, val);
|
||||
_write(MADERA_EQ2_2, val);
|
||||
|
||||
if (debug)
|
||||
printk("Moro-sound: written the new EQ gain values\n");
|
||||
}
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Sound hook functions
|
||||
/*****************************************/
|
||||
|
||||
void moro_sound_hook_madera_pcm_probe(struct regmap *pmap)
|
||||
{
|
||||
// store a copy of the pointer to the regmap, we need
|
||||
// that for internal calls to the audio hub
|
||||
map = pmap;
|
||||
|
||||
// Print debug info
|
||||
printk("Moro-sound: regmap pointer received\n");
|
||||
|
||||
// Initialize moro sound master switch finally
|
||||
moro_sound = MORO_SOUND_DEFAULT;
|
||||
eq = EQ_DEFAULT;
|
||||
set_eq();
|
||||
|
||||
// If moro sound is enabled during driver start, reset to default configuration
|
||||
if (moro_sound)
|
||||
{
|
||||
reset_moro_sound();
|
||||
printk("Moro-sound: moro sound enabled during startup\n");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int moro_sound_write_hook(unsigned int reg, unsigned int val)
|
||||
{
|
||||
// if moro sound is off, return original value
|
||||
if (!moro_sound)
|
||||
return val;
|
||||
|
||||
// based on the register, do the appropriate processing
|
||||
switch (reg)
|
||||
{
|
||||
// headphone l
|
||||
case MADERA_DAC_DIGITAL_VOLUME_2L:
|
||||
{
|
||||
val &= ~MADERA_OUT2L_VOL_MASK;
|
||||
val |= (headphone_gain_l << MADERA_OUT2L_VOL_SHIFT);
|
||||
break;
|
||||
}
|
||||
|
||||
// headphone r
|
||||
case MADERA_DAC_DIGITAL_VOLUME_2R:
|
||||
{
|
||||
val &= ~MADERA_OUT2R_VOL_MASK;
|
||||
val |= (headphone_gain_r << MADERA_OUT2R_VOL_SHIFT);
|
||||
break;
|
||||
}
|
||||
|
||||
if (eq){
|
||||
// hpout2 l
|
||||
case MADERA_OUT2LMIX_INPUT_1_SOURCE:
|
||||
{
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (out2l_mix_source << MADERA_MIXER_SOURCE_SHIFT);
|
||||
break;
|
||||
}
|
||||
// hpout2 r
|
||||
case MADERA_OUT2RMIX_INPUT_1_SOURCE:
|
||||
{
|
||||
val &= ~MADERA_MIXER_SOURCE_MASK;
|
||||
val |= (out2r_mix_source << MADERA_MIXER_SOURCE_SHIFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Initialization functions
|
||||
/*****************************************/
|
||||
|
||||
static void reset_moro_sound(void)
|
||||
{
|
||||
// set all moro sound config settings to defaults
|
||||
|
||||
headphone_gain_l = HEADPHONE_DEFAULT;
|
||||
headphone_gain_r = HEADPHONE_DEFAULT;
|
||||
|
||||
out2l_mix_source = OUT2L_MIX_DEFAULT;
|
||||
out2r_mix_source = OUT2R_MIX_DEFAULT;
|
||||
|
||||
eq1_mix_source = EQ1_MIX_DEFAULT;
|
||||
eq2_mix_source = EQ2_MIX_DEFAULT;
|
||||
|
||||
debug = DEBUG_DEFAULT;
|
||||
|
||||
if (debug)
|
||||
printk("Moro-sound: moro sound reset done\n");
|
||||
}
|
||||
|
||||
|
||||
static void reset_audio_hub(void)
|
||||
{
|
||||
// reset all audio hub registers back to defaults
|
||||
|
||||
set_headphone_gain_l(HEADPHONE_DEFAULT);
|
||||
set_headphone_gain_r(HEADPHONE_DEFAULT);
|
||||
|
||||
set_out2l_mix_source(OUT2L_MIX_DEFAULT);
|
||||
set_out2r_mix_source(OUT2R_MIX_DEFAULT);
|
||||
|
||||
set_eq1_mix_source(EQ1_MIX_DEFAULT);
|
||||
set_eq2_mix_source(EQ2_MIX_DEFAULT);
|
||||
|
||||
set_eq();
|
||||
|
||||
if (debug)
|
||||
printk("Moro-sound: moon audio hub reset done\n");
|
||||
}
|
||||
|
||||
|
||||
static void update_audio_hub(void)
|
||||
{
|
||||
// reset all audio hub registers back to defaults
|
||||
|
||||
set_headphone_gain_l(headphone_gain_l);
|
||||
set_headphone_gain_r(headphone_gain_r);
|
||||
|
||||
set_out2l_mix_source(out2l_mix_source);
|
||||
set_out2r_mix_source(out2r_mix_source);
|
||||
|
||||
set_eq1_mix_source(eq1_mix_source);
|
||||
set_eq2_mix_source(eq2_mix_source);
|
||||
|
||||
set_eq();
|
||||
|
||||
if (debug)
|
||||
printk("Moro-sound: moon audio hub updated done\n");
|
||||
}
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// sysfs interface functions
|
||||
/*****************************************/
|
||||
|
||||
// Moro sound master switch
|
||||
|
||||
static ssize_t moro_sound_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// print current value
|
||||
return sprintf(buf, "%d\n", moro_sound);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t moro_sound_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// read values from input buffer
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
// store if valid data
|
||||
if (((val == 0) || (val == 1)))
|
||||
{
|
||||
// check if there was a change
|
||||
if (moro_sound != val)
|
||||
{
|
||||
// set new status
|
||||
moro_sound = val;
|
||||
|
||||
// re-initialize settings and audio hub (in any case for both on and off !)
|
||||
// if is the first enable, reset variables
|
||||
if(first) {
|
||||
reset_moro_sound();
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if(val == 1) {
|
||||
update_audio_hub();
|
||||
} else {
|
||||
reset_audio_hub();
|
||||
}
|
||||
}
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: status %d\n", moro_sound);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Headphone volume
|
||||
|
||||
static ssize_t headphone_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// print current values
|
||||
return sprintf(buf, "%d %d\n", headphone_gain_l, headphone_gain_r);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t headphone_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val_l;
|
||||
int val_r;
|
||||
|
||||
// Terminate if moro sound is not enabled
|
||||
if (!moro_sound)
|
||||
return count;
|
||||
|
||||
// read values from input buffer
|
||||
ret = sscanf(buf, "%d %d", &val_l, &val_r);
|
||||
|
||||
if (ret != 2)
|
||||
return -EINVAL;
|
||||
|
||||
// store new values
|
||||
headphone_gain_l = val_l;
|
||||
headphone_gain_r = val_r;
|
||||
|
||||
// set new values
|
||||
set_headphone_gain_l(headphone_gain_l);
|
||||
set_headphone_gain_r(headphone_gain_r);
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: headphone volume L=%d R=%d\n", headphone_gain_l, headphone_gain_r);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// EQ
|
||||
|
||||
static ssize_t eq_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
// print current value
|
||||
return sprintf(buf, "%d\n", eq);
|
||||
}
|
||||
|
||||
static ssize_t eq_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// Terminate if moro sound is not enabled
|
||||
if (!moro_sound)
|
||||
return count;
|
||||
|
||||
// read values from input buffer
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
// store if valid data
|
||||
if (((val == 0) || (val == 1)))
|
||||
{
|
||||
// check if there was a change
|
||||
if (eq != val)
|
||||
{
|
||||
// store new value
|
||||
eq = val;
|
||||
|
||||
set_eq();
|
||||
}
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ status: %d\n", eq);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// EQ GAIN
|
||||
|
||||
static ssize_t eq_gains_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// print current values
|
||||
return sprintf(buf, "%d %d %d %d %d\n", eq_gains[0], eq_gains[1], eq_gains[2], eq_gains[3], eq_gains[4]);
|
||||
}
|
||||
|
||||
static ssize_t eq_gains_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int gains[5];
|
||||
int i;
|
||||
|
||||
// Terminate if moro sound is not enabled
|
||||
if (!moro_sound)
|
||||
return count;
|
||||
|
||||
// read values from input buffer
|
||||
ret = sscanf(buf, "%d %d %d %d %d", &gains[0], &gains[1], &gains[2], &gains[3], &gains[4]);
|
||||
|
||||
if (ret != 5)
|
||||
return -EINVAL;
|
||||
|
||||
// check validity of gain values and adjust
|
||||
for (i = 0; i <= 4; i++)
|
||||
{
|
||||
if (gains[i] < EQ_GAIN_MIN)
|
||||
gains[i] = EQ_GAIN_MIN;
|
||||
|
||||
if (gains[i] > EQ_GAIN_MAX)
|
||||
gains[i] = EQ_GAIN_MAX;
|
||||
|
||||
eq_gains[i] = gains[i];
|
||||
}
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ gains: %d %d %d %d %d\n", eq_gains[0], eq_gains[1], eq_gains[2], eq_gains[3], eq_gains[4]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t eq_b1_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", eq_gains[0]);
|
||||
}
|
||||
|
||||
static ssize_t eq_b1_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < EQ_GAIN_MIN)
|
||||
val = EQ_GAIN_MIN;
|
||||
|
||||
if (val > EQ_GAIN_MAX)
|
||||
val = EQ_GAIN_MAX;
|
||||
|
||||
// store new value
|
||||
eq_gains[0] = val;
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ Band1 gain: %d\n", eq_gains[0]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t eq_b2_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", eq_gains[1]);
|
||||
}
|
||||
|
||||
static ssize_t eq_b2_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < EQ_GAIN_MIN)
|
||||
val = EQ_GAIN_MIN;
|
||||
|
||||
if (val > EQ_GAIN_MAX)
|
||||
val = EQ_GAIN_MAX;
|
||||
|
||||
// store new value
|
||||
eq_gains[1] = val;
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ Band2 gain: %d\n", eq_gains[1]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t eq_b3_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", eq_gains[2]);
|
||||
}
|
||||
|
||||
static ssize_t eq_b3_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < EQ_GAIN_MIN)
|
||||
val = EQ_GAIN_MIN;
|
||||
|
||||
if (val > EQ_GAIN_MAX)
|
||||
val = EQ_GAIN_MAX;
|
||||
|
||||
// store new value
|
||||
eq_gains[2] = val;
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ Band3 gain: %d\n", eq_gains[2]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t eq_b4_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", eq_gains[3]);
|
||||
}
|
||||
|
||||
static ssize_t eq_b4_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < EQ_GAIN_MIN)
|
||||
val = EQ_GAIN_MIN;
|
||||
|
||||
if (val > EQ_GAIN_MAX)
|
||||
val = EQ_GAIN_MAX;
|
||||
|
||||
// store new value
|
||||
eq_gains[3] = val;
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ Band4 gain: %d\n", eq_gains[3]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t eq_b5_gain_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", eq_gains[4]);
|
||||
}
|
||||
|
||||
static ssize_t eq_b5_gain_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < EQ_GAIN_MIN)
|
||||
val = EQ_GAIN_MIN;
|
||||
|
||||
if (val > EQ_GAIN_MAX)
|
||||
val = EQ_GAIN_MAX;
|
||||
|
||||
// store new value
|
||||
eq_gains[4] = val;
|
||||
|
||||
// set new values
|
||||
set_eq_gains();
|
||||
|
||||
// print debug info
|
||||
if (debug)
|
||||
printk("Moro-sound: EQ Band5 gain: %d\n", eq_gains[4]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Debug status
|
||||
|
||||
static ssize_t debug_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return current debug status
|
||||
return sprintf(buf, "%d\n", debug);
|
||||
}
|
||||
|
||||
static ssize_t debug_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int ret = -EINVAL;
|
||||
unsigned int val;
|
||||
|
||||
// check data and store if valid
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if ((val == 0) || (val == 1))
|
||||
debug = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Register dump
|
||||
|
||||
static ssize_t reg_dump_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned int out2_ena, out2l_mix, out2r_mix, eq1_ena, eq2_ena, eq1_mix, eq2_mix, eq_b1,
|
||||
eq_b2, eq_b3, eq_b4, eq_b5;
|
||||
|
||||
_read(MADERA_OUTPUT_ENABLES_1, &out2_ena);
|
||||
out2_ena = (out2_ena & MADERA_OUT2L_ENA_MASK) >> MADERA_OUT2L_ENA_SHIFT;
|
||||
|
||||
_read(MADERA_OUT2LMIX_INPUT_1_SOURCE, &out2l_mix);
|
||||
|
||||
_read(MADERA_OUT2RMIX_INPUT_1_SOURCE, &out2r_mix);
|
||||
|
||||
_read(MADERA_EQ1_1, &eq1_ena);
|
||||
eq1_ena = (eq1_ena & MADERA_EQ1_ENA_MASK) >> MADERA_EQ1_ENA_SHIFT;
|
||||
|
||||
_read(MADERA_EQ2_1, &eq2_ena);
|
||||
eq2_ena = (eq2_ena & MADERA_EQ2_ENA_MASK) >> MADERA_EQ2_ENA_SHIFT;
|
||||
|
||||
_read(MADERA_EQ1MIX_INPUT_1_SOURCE, &eq1_mix);
|
||||
|
||||
_read(MADERA_EQ2MIX_INPUT_1_SOURCE, &eq2_mix);
|
||||
|
||||
_read(MADERA_EQ1_1, &eq_b1);
|
||||
eq_b1 = ((eq_b1 & MADERA_EQ1_B1_GAIN_MASK) >> MADERA_EQ1_B1_GAIN_SHIFT) - EQ_GAIN_OFFSET;
|
||||
_read(MADERA_EQ1_1, &eq_b2);
|
||||
eq_b2 = ((eq_b2 & MADERA_EQ1_B2_GAIN_MASK) >> MADERA_EQ1_B2_GAIN_SHIFT) - EQ_GAIN_OFFSET;
|
||||
_read(MADERA_EQ1_1, &eq_b3);
|
||||
eq_b3 = ((eq_b3 & MADERA_EQ1_B3_GAIN_MASK) >> MADERA_EQ1_B3_GAIN_SHIFT) - EQ_GAIN_OFFSET;
|
||||
_read(MADERA_EQ1_2, &eq_b4);
|
||||
eq_b4 = ((eq_b4 & MADERA_EQ1_B4_GAIN_MASK) >> MADERA_EQ1_B4_GAIN_SHIFT) - EQ_GAIN_OFFSET;
|
||||
_read(MADERA_EQ1_2, &eq_b5);
|
||||
eq_b5 = ((eq_b5 & MADERA_EQ1_B5_GAIN_MASK) >> MADERA_EQ1_B5_GAIN_SHIFT) - EQ_GAIN_OFFSET;
|
||||
|
||||
|
||||
|
||||
|
||||
// return register dump information
|
||||
return sprintf(buf, "\
|
||||
headphone_gain_l: reg: %d, variable: %d\n\
|
||||
headphone_gain_r: reg: %d, variable: %d\n\
|
||||
first enable: %d\n\
|
||||
HPOUT2 Enabled: %d\n\
|
||||
HPOUT2L Source: %d\n\
|
||||
HPOUT2R Source: %d\n\
|
||||
EQ1 Enabled: %d\n\
|
||||
EQ2 Enabled: %d\n\
|
||||
EQ1MIX source: %d\n\
|
||||
EQ2MIX source: %d\n\
|
||||
EQ b1 gain: %d\n\
|
||||
EQ b2 gain: %d\n\
|
||||
EQ b3 gain: %d\n\
|
||||
EQ b4 gain: %d\n\
|
||||
EQ b5 gain: %d\n\
|
||||
",
|
||||
get_headphone_gain_l(),
|
||||
headphone_gain_l,
|
||||
get_headphone_gain_r(),
|
||||
headphone_gain_r,
|
||||
first,
|
||||
out2_ena,
|
||||
out2l_mix,
|
||||
out2r_mix,
|
||||
eq1_ena,
|
||||
eq2_ena,
|
||||
eq1_mix,
|
||||
eq2_mix,
|
||||
eq_b1,
|
||||
eq_b2,
|
||||
eq_b3,
|
||||
eq_b4,
|
||||
eq_b5);
|
||||
}
|
||||
|
||||
|
||||
// Version information
|
||||
|
||||
static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
// return version information
|
||||
return sprintf(buf, "%s\n", MORO_SOUND_VERSION);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Initialize moro sound sysfs folder
|
||||
/*****************************************/
|
||||
|
||||
// define objects
|
||||
static DEVICE_ATTR(moro_sound, 0664, moro_sound_show, moro_sound_store);
|
||||
static DEVICE_ATTR(headphone_gain, 0664, headphone_gain_show, headphone_gain_store);
|
||||
static DEVICE_ATTR(eq, 0664, eq_show, eq_store);
|
||||
static DEVICE_ATTR(eq_gains, 0664, eq_gains_show, eq_gains_store);
|
||||
static DEVICE_ATTR(eq_b1_gain, 0664, eq_b1_gain_show, eq_b1_gain_store);
|
||||
static DEVICE_ATTR(eq_b2_gain, 0664, eq_b2_gain_show, eq_b2_gain_store);
|
||||
static DEVICE_ATTR(eq_b3_gain, 0664, eq_b3_gain_show, eq_b3_gain_store);
|
||||
static DEVICE_ATTR(eq_b4_gain, 0664, eq_b4_gain_show, eq_b4_gain_store);
|
||||
static DEVICE_ATTR(eq_b5_gain, 0664, eq_b5_gain_show, eq_b5_gain_store);
|
||||
static DEVICE_ATTR(debug, 0664, debug_show, debug_store);
|
||||
static DEVICE_ATTR(version, 0664, version_show, NULL);
|
||||
static DEVICE_ATTR(reg_dump, 0664, reg_dump_show, NULL);
|
||||
|
||||
// define attributes
|
||||
static struct attribute *moro_sound_attributes[] = {
|
||||
&dev_attr_moro_sound.attr,
|
||||
&dev_attr_headphone_gain.attr,
|
||||
&dev_attr_eq.attr,
|
||||
&dev_attr_eq_gains.attr,
|
||||
&dev_attr_eq_b1_gain.attr,
|
||||
&dev_attr_eq_b2_gain.attr,
|
||||
&dev_attr_eq_b3_gain.attr,
|
||||
&dev_attr_eq_b4_gain.attr,
|
||||
&dev_attr_eq_b5_gain.attr,
|
||||
&dev_attr_debug.attr,
|
||||
&dev_attr_version.attr,
|
||||
&dev_attr_reg_dump.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
// define attribute group
|
||||
static struct attribute_group moro_sound_control_group = {
|
||||
.attrs = moro_sound_attributes,
|
||||
};
|
||||
|
||||
|
||||
// define control device
|
||||
static struct miscdevice moro_sound_control_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "moro_sound",
|
||||
};
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Driver init and exit functions
|
||||
/*****************************************/
|
||||
|
||||
static int moro_sound_init(void)
|
||||
{
|
||||
// register moro sound control device
|
||||
misc_register(&moro_sound_control_device);
|
||||
if (sysfs_create_group(&moro_sound_control_device.this_device->kobj,
|
||||
&moro_sound_control_group) < 0) {
|
||||
printk("Moro-sound: failed to create sys fs object.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize moro sound master switch with OFF per default (will be set to correct
|
||||
// default value when we receive the codec pointer later - avoids startup boot loop)
|
||||
moro_sound = 0;
|
||||
eq = 0;
|
||||
|
||||
// Initialize variables
|
||||
reset_moro_sound();
|
||||
|
||||
// Print debug info
|
||||
printk("Moro-sound: engine version %s started\n", MORO_SOUND_VERSION);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void moro_sound_exit(void)
|
||||
{
|
||||
// remove moro sound control device
|
||||
sysfs_remove_group(&moro_sound_control_device.this_device->kobj,
|
||||
&moro_sound_control_group);
|
||||
|
||||
// Print debug info
|
||||
printk("Moro-sound: engine stopped\n");
|
||||
}
|
||||
|
||||
|
||||
/* define driver entry points */
|
||||
|
||||
module_init(moro_sound_init);
|
||||
module_exit(moro_sound_exit);
|
||||
|
||||
|
62
sound/soc/codecs/moro_sound.h
Normal file
62
sound/soc/codecs/moro_sound.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* moro_sound.h -- Sound mod for Moon, S7 sound driver
|
||||
*
|
||||
* Author : @morogoku https://github.com/morogoku
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/printk.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/mfd/madera/registers.h>
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// External function declarations
|
||||
/*****************************************/
|
||||
|
||||
void moro_sound_hook_madera_pcm_probe(struct regmap *pmap);
|
||||
int _regmap_write_nohook(struct regmap *map, unsigned int reg, unsigned int val);
|
||||
|
||||
|
||||
/*****************************************/
|
||||
// Definitions
|
||||
/*****************************************/
|
||||
|
||||
// Moro sound general
|
||||
#define MORO_SOUND_DEFAULT 0
|
||||
#define MORO_SOUND_VERSION "2.1.1"
|
||||
#define DEBUG_DEFAULT 0
|
||||
|
||||
// headphone levels
|
||||
#define HEADPHONE_DEFAULT 128
|
||||
#define HEADPHONE_MIN 60
|
||||
#define HEADPHONE_MAX 190
|
||||
|
||||
// Mixers sources
|
||||
#define OUT2L_MIX_DEFAULT 32
|
||||
#define OUT2R_MIX_DEFAULT 33
|
||||
#define EQ1_MIX_DEFAULT 0
|
||||
#define EQ2_MIX_DEFAULT 0
|
||||
|
||||
// EQ gain
|
||||
#define EQ_DEFAULT 0
|
||||
#define EQ_GAIN_DEFAULT 0
|
||||
#define EQ_GAIN_OFFSET 12
|
||||
#define EQ_GAIN_MIN -12
|
||||
#define EQ_GAIN_MAX 12
|
||||
|
||||
// Mixers
|
||||
#define MADERA_MIXER_SOURCE_MASK 0xff
|
||||
#define MADERA_MIXER_SOURCE_SHIFT 0
|
||||
#define MADERA_MIXER_VOLUME_MASK 0xfe
|
||||
#define MADERA_MIXER_VOLUME_SHIFT 1
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue