5078 lines
163 KiB
C
Executable file
5078 lines
163 KiB
C
Executable file
/*
|
|
* sound/soc/codec/s5m3700x.c
|
|
*
|
|
* ALSA SoC Audio Layer - Samsung Codec Driver
|
|
*
|
|
* Copyright (C) 2020 Samsung Electronics
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/init.h>
|
|
#include <linux/io.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/slab.h>
|
|
#include <sound/core.h>
|
|
#include <sound/pcm.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/soc.h>
|
|
#include <sound/jack.h>
|
|
#include <sound/initval.h>
|
|
#include <sound/tlv.h>
|
|
#include <sound/samsung/abox.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/input.h>
|
|
#include <linux/completion.h>
|
|
#include <soc/samsung/acpm_mfd.h>
|
|
#include <uapi/linux/input-event-codes.h>
|
|
|
|
#include "s5m3700x.h"
|
|
#include "s5m3700x-jack.h"
|
|
|
|
#define S5M3700X_CODEC_SW_VER 2008
|
|
|
|
static struct s5m3700x_priv *s5m3700x_stat;
|
|
static void codec_regdump(struct snd_soc_component *codec);
|
|
|
|
void s5m3700x_usleep(unsigned int u_sec)
|
|
{
|
|
usleep_range(u_sec, u_sec + 10);
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_usleep);
|
|
|
|
bool s5m3700x_is_probe_done(void)
|
|
{
|
|
if (s5m3700x_stat == NULL)
|
|
return false;
|
|
return s5m3700x_stat->is_probe_done;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_is_probe_done);
|
|
|
|
int s5m3700x_i2c_read_reg(u8 slave, u8 reg, u8 *val)
|
|
{
|
|
struct i2c_msg msg[2];
|
|
struct i2c_client *client;
|
|
u8 buf[2];
|
|
unsigned char retry;
|
|
int ret;
|
|
|
|
client = s5m3700x_stat->i2c_priv[S5M3700D];
|
|
|
|
/* Write Format */
|
|
buf[0] = reg;
|
|
buf[1] = slave;
|
|
msg[0].addr = client->addr;
|
|
msg[0].flags = 0;
|
|
msg[0].len = 2;
|
|
msg[0].buf = buf;
|
|
|
|
/* Read Format */
|
|
msg[1].addr = client->addr;
|
|
msg[1].flags = I2C_M_RD;
|
|
msg[1].len = 1;
|
|
msg[1].buf = val;
|
|
|
|
mutex_lock(&s5m3700x_stat->i2c_mutex);
|
|
for (retry = 0; retry < 5; retry++) {
|
|
ret = i2c_transfer(client->adapter, msg, 2);
|
|
|
|
if (ret == 2)
|
|
break;
|
|
else if (ret < 0)
|
|
pr_err("[%s] i2c read failed! err: %d\n", __func__, ret);
|
|
}
|
|
|
|
mutex_unlock(&s5m3700x_stat->i2c_mutex);
|
|
return ret-2;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_i2c_read_reg);
|
|
|
|
int s5m3700x_i2c_write_reg(u8 slave, u8 reg, u8 val)
|
|
{
|
|
struct i2c_msg msg;
|
|
struct i2c_client *client;
|
|
u8 buf[3];
|
|
unsigned char retry;
|
|
int ret;
|
|
|
|
client = s5m3700x_stat->i2c_priv[S5M3700D];
|
|
|
|
/* Write Format */
|
|
buf[0] = reg;
|
|
buf[1] = slave;
|
|
buf[2] = val;
|
|
msg.addr = client->addr;
|
|
msg.flags = 0;
|
|
msg.len = 3;
|
|
msg.buf = buf;
|
|
|
|
mutex_lock(&s5m3700x_stat->i2c_mutex);
|
|
for (retry = 0; retry < 5; retry++) {
|
|
ret = i2c_transfer(client->adapter, &msg, 1);
|
|
|
|
if (ret == 1)
|
|
break;
|
|
else if (ret < 0)
|
|
pr_err("[%s] i2c write failed! err: %d\n", __func__, ret);
|
|
}
|
|
|
|
mutex_unlock(&s5m3700x_stat->i2c_mutex);
|
|
return ret-1;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_i2c_write_reg);
|
|
|
|
int s5m3700x_i2c_update_reg(u8 slave, u8 reg, u8 mask, u8 val)
|
|
{
|
|
struct i2c_msg msg[2];
|
|
struct i2c_client *client;
|
|
u8 buf[3];
|
|
unsigned char retry;
|
|
int ret;
|
|
u8 old, temp;
|
|
|
|
mutex_lock(&s5m3700x_stat->i2c_mutex);
|
|
|
|
client = s5m3700x_stat->i2c_priv[S5M3700D];
|
|
|
|
/* Write Format */
|
|
buf[0] = reg;
|
|
buf[1] = slave;
|
|
msg[0].addr = client->addr;
|
|
msg[0].flags = 0;
|
|
msg[0].len = 2;
|
|
msg[0].buf = buf;
|
|
|
|
/* Read Format */
|
|
msg[1].addr = client->addr;
|
|
msg[1].flags = I2C_M_RD;
|
|
msg[1].len = 1;
|
|
msg[1].buf = &old;
|
|
|
|
for (retry = 0; retry < 5; retry++) {
|
|
ret = i2c_transfer(client->adapter, msg, 2);
|
|
|
|
if (ret == 2)
|
|
break;
|
|
else if (ret < 0) {
|
|
pr_err("[%s] i2c update failed! err: %d\n", __func__, ret);
|
|
goto i2c_err;
|
|
}
|
|
}
|
|
|
|
temp = old & ~mask;
|
|
temp |= val & mask;
|
|
|
|
if (temp != old) {
|
|
/* Write Format */
|
|
buf[0] = reg;
|
|
buf[1] = slave;
|
|
buf[2] = temp;
|
|
msg[0].addr = client->addr;
|
|
msg[0].flags = 0;
|
|
msg[0].len = 3;
|
|
msg[0].buf = buf;
|
|
|
|
for (retry = 0; retry < 5; retry++) {
|
|
ret = i2c_transfer(client->adapter, &msg[0], 1);
|
|
|
|
if (ret == 1)
|
|
break;
|
|
else if (ret < 0) {
|
|
pr_err("[%s] i2c update failed! err: %d\n", __func__, ret);
|
|
goto i2c_err;
|
|
}
|
|
}
|
|
}
|
|
ret = 0;
|
|
|
|
mutex_unlock(&s5m3700x_stat->i2c_mutex);
|
|
i2c_err:
|
|
mutex_unlock(&s5m3700x_stat->i2c_mutex);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_i2c_update_reg);
|
|
|
|
int s5m3700x_read(struct s5m3700x_priv *s5m3700x,
|
|
unsigned int slave, unsigned int addr, unsigned int *value)
|
|
{
|
|
int ret;
|
|
|
|
switch (slave) {
|
|
case S5M3700X_DIGITAL_ADDR:
|
|
ret = regmap_read(s5m3700x->regmap[S5M3700D], addr, value);
|
|
break;
|
|
case S5M3700X_ANALOG_ADDR:
|
|
ret = regmap_read(s5m3700x->regmap[S5M3700A], addr, value);
|
|
break;
|
|
case S5M3700X_OTP_ADDR:
|
|
ret = regmap_read(s5m3700x->regmap[S5M3700O], addr, value);
|
|
break;
|
|
default:
|
|
dev_err(s5m3700x->dev, "%s: Cannot find slave address. addr: 0x%02X%02X\n",
|
|
__func__, slave, addr);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_read);
|
|
|
|
int s5m3700x_write(struct s5m3700x_priv *s5m3700x,
|
|
unsigned int slave, unsigned int addr, unsigned int value)
|
|
{
|
|
int ret;
|
|
|
|
switch (slave) {
|
|
case S5M3700X_DIGITAL_ADDR:
|
|
ret = regmap_write(s5m3700x->regmap[S5M3700D], addr, value);
|
|
break;
|
|
case S5M3700X_ANALOG_ADDR:
|
|
ret = regmap_write(s5m3700x->regmap[S5M3700A], addr, value);
|
|
break;
|
|
case S5M3700X_OTP_ADDR:
|
|
ret = regmap_write(s5m3700x->regmap[S5M3700O], addr, value);
|
|
break;
|
|
default:
|
|
dev_err(s5m3700x->dev, "%s: Cannot find slave address. addr: 0x%02X%02X\n",
|
|
__func__, slave, addr);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_write);
|
|
|
|
int s5m3700x_update_bits(struct s5m3700x_priv *s5m3700x,
|
|
unsigned int slave, unsigned int addr, unsigned int mask, unsigned int value)
|
|
{
|
|
int ret;
|
|
|
|
switch (slave) {
|
|
case S5M3700X_DIGITAL_ADDR:
|
|
ret = regmap_update_bits(s5m3700x->regmap[S5M3700D], addr, mask, value);
|
|
break;
|
|
case S5M3700X_ANALOG_ADDR:
|
|
ret = regmap_update_bits(s5m3700x->regmap[S5M3700A], addr, mask, value);
|
|
break;
|
|
case S5M3700X_OTP_ADDR:
|
|
ret = regmap_update_bits(s5m3700x->regmap[S5M3700O], addr, mask, value);
|
|
break;
|
|
default:
|
|
dev_err(s5m3700x->dev, "%s: Cannot find slave address. addr: 0x%02X%02X\n",
|
|
__func__, slave, addr);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_update_bits);
|
|
|
|
void regcache_cache_switch(struct s5m3700x_priv *s5m3700x, bool on)
|
|
{
|
|
int p_map;
|
|
|
|
mutex_lock(&s5m3700x->regcache_lock);
|
|
if (!on)
|
|
s5m3700x->regcache_count++;
|
|
else
|
|
s5m3700x->regcache_count--;
|
|
|
|
mutex_unlock(&s5m3700x->regcache_lock);
|
|
|
|
if (!on) {
|
|
if (s5m3700x->regcache_count == 1)
|
|
for (p_map = S5M3700D; p_map <= S5M3700O; p_map++)
|
|
regcache_cache_only(s5m3700x->regmap[p_map], on);
|
|
} else {
|
|
if (s5m3700x->regcache_count == 0)
|
|
for (p_map = S5M3700D; p_map <= S5M3700O; p_map++)
|
|
regcache_cache_only(s5m3700x->regmap[p_map], on);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(regcache_cache_switch);
|
|
|
|
int s5m3700x_regulators_enable(struct snd_soc_component *codec)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int ret;
|
|
|
|
ret = regulator_enable(s5m3700x->vdd);
|
|
ret = regulator_enable(s5m3700x->vdd2);
|
|
|
|
s5m3700x->regulator_count++;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void s5m3700x_regulators_disable(struct snd_soc_component *codec)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
s5m3700x->regulator_count--;
|
|
|
|
if (s5m3700x->regulator_count == 0) {
|
|
regulator_disable(s5m3700x->vdd);
|
|
regulator_disable(s5m3700x->vdd2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return Value
|
|
* True: If the register value cannot be cached, hence we have to read from the
|
|
* hardware directly.
|
|
* False: If the register value can be read from cache.
|
|
*/
|
|
static bool s5m3700x_volatile_register(struct device *dev, unsigned int reg)
|
|
{
|
|
/*
|
|
* For all the registers for which we want to restore the value during
|
|
* regcache_sync operation, we need to return true here. For registers
|
|
* whose value need not be cached and restored should return false here.
|
|
*
|
|
* For the time being, let us cache the value of all registers other
|
|
* than the IRQ pending and IRQ status registers.
|
|
*/
|
|
switch (reg) {
|
|
case 0x01 ... 0x06:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return Value
|
|
* True: If the register value can be read
|
|
* False: If the register cannot be read
|
|
*/
|
|
static bool s5m3700x_readable_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x08 ... 0x0F:
|
|
case 0x10 ... 0x29:
|
|
case 0x2F ... 0x8F:
|
|
case 0x93 ... 0x9E:
|
|
case 0xA0 ... 0xEE:
|
|
case 0xF0 ... 0xFF:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return Value
|
|
* True: If the register value can be write
|
|
* False: If the register cannot be write
|
|
*/
|
|
static bool s5m3700x_writeable_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x08 ... 0x0D:
|
|
case 0x10 ... 0x25:
|
|
case 0x29:
|
|
case 0x2F ... 0x56:
|
|
case 0x58 ... 0x74:
|
|
case 0x77 ... 0x7F:
|
|
case 0x89 ... 0x8E:
|
|
case 0x93 ... 0x9A:
|
|
case 0x9D ... 0x9E:
|
|
case 0xA0 ... 0xBE:
|
|
case 0xC0 ... 0xCD:
|
|
case 0xD0 ... 0xEE:
|
|
case 0xFD ... 0xFF:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int s5m3700x_reg_digital_hw_write(void *context,
|
|
unsigned int reg, unsigned int value)
|
|
{
|
|
return s5m3700x_i2c_write_reg(S5M3700X_DIGITAL_ADDR, (u8)reg, (u8)value);
|
|
}
|
|
|
|
static int s5m3700x_reg_digital_hw_read(void *context,
|
|
unsigned int reg, unsigned int *value)
|
|
{
|
|
return s5m3700x_i2c_read_reg(S5M3700X_DIGITAL_ADDR, (u8)reg, (u8 *)value);
|
|
}
|
|
|
|
static const struct regmap_bus s5m3700x_dbus = {
|
|
.reg_write = s5m3700x_reg_digital_hw_write,
|
|
.reg_read = s5m3700x_reg_digital_hw_read,
|
|
};
|
|
|
|
const struct regmap_config s5m3700x_digital_regmap = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
|
|
/*
|
|
* "i3c" string should be described in the name field
|
|
* this will be used for the i3c inteface,
|
|
* when read/write operations are used in the regmap driver.
|
|
* APM functions will be called instead of the I2C
|
|
* refer to the "drivers/base/regmap/regmap-i2c.c
|
|
*/
|
|
.name = "i2c, S5M3700X",
|
|
.max_register = S5M3700X_REGCACHE_SYNC_END,
|
|
.readable_reg = s5m3700x_readable_register,
|
|
.writeable_reg = s5m3700x_writeable_register,
|
|
.volatile_reg = s5m3700x_volatile_register,
|
|
.use_single_read = true,
|
|
.use_single_write = true,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
};
|
|
|
|
|
|
static bool s5m3700x_volatile_analog_register(struct device *dev, unsigned int reg)
|
|
{
|
|
/*
|
|
* For all the registers for which we want to restore the value during
|
|
* regcache_sync operation, we need to return true here. For registers
|
|
* whose value need not be cached and restored should return false here.
|
|
*
|
|
* For the time being, let us cache the value of all registers other
|
|
* than the IRQ pending and IRQ status registers.
|
|
*/
|
|
switch (reg) {
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool s5m3700x_readable_analog_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x02 ... 0x0D:
|
|
case 0x10 ... 0x23:
|
|
case 0x25:
|
|
case 0x30 ... 0x32:
|
|
case 0x35:
|
|
case 0x38 ... 0x3B:
|
|
case 0x3F ... 0x40:
|
|
case 0x42 ... 0x45:
|
|
case 0x49 ... 0x4A:
|
|
case 0x4C ... 0x4D:
|
|
case 0x50 ... 0x56:
|
|
case 0x80 ... 0x95:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool s5m3700x_writeable_analog_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x02 ... 0x0D:
|
|
case 0x10 ... 0x23:
|
|
case 0x25:
|
|
case 0x30 ... 0x32:
|
|
case 0x35:
|
|
case 0x38 ... 0x3B:
|
|
case 0x3F ... 0x40:
|
|
case 0x42 ... 0x45:
|
|
case 0x49 ... 0x4A:
|
|
case 0x4C ... 0x4D:
|
|
case 0x50 ... 0x56:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int s5m3700x_reg_analog_hw_write(void *context,
|
|
unsigned int reg, unsigned int value)
|
|
{
|
|
return s5m3700x_i2c_write_reg(S5M3700X_ANALOG_ADDR, (u8)reg, (u8)value);
|
|
}
|
|
|
|
static int s5m3700x_reg_analog_hw_read(void *context,
|
|
unsigned int reg, unsigned int *value)
|
|
{
|
|
return s5m3700x_i2c_read_reg(S5M3700X_ANALOG_ADDR, (u8)reg, (u8 *)value);
|
|
}
|
|
|
|
static const struct regmap_bus s5m3700x_abus = {
|
|
.reg_write = s5m3700x_reg_analog_hw_write,
|
|
.reg_read = s5m3700x_reg_analog_hw_read,
|
|
};
|
|
|
|
const struct regmap_config s5m3700x_analog_regmap = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
.name = "i2c, S5M3700X_ANALOG",
|
|
.max_register = S5M3700X_REGCACHE_SYNC_END,
|
|
.readable_reg = s5m3700x_readable_analog_register,
|
|
.writeable_reg = s5m3700x_writeable_analog_register,
|
|
.volatile_reg = s5m3700x_volatile_analog_register,
|
|
.use_single_read = true,
|
|
.use_single_write = true,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
};
|
|
|
|
static bool s5m3700x_volatile_otp_register(struct device *dev, unsigned int reg)
|
|
{
|
|
/*
|
|
* For all the registers for which we want to restore the value during
|
|
* regcache_sync operation, we need to return true here. For registers
|
|
* whose value need not be cached and restored should return false here.
|
|
*
|
|
* For the time being, let us cache the value of all registers other
|
|
* than the IRQ pending and IRQ status registers.
|
|
*/
|
|
switch (reg) {
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool s5m3700x_readable_otp_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x00 ... 0x77:
|
|
case 0x88 ... 0x8A:
|
|
case 0xA6 ... 0xCB:
|
|
case 0xD0 ... 0xF0:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool s5m3700x_writeable_otp_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case 0x00 ... 0x77:
|
|
case 0x88 ... 0x8A:
|
|
case 0xA6 ... 0xCB:
|
|
case 0xD0 ... 0xF0:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static int s5m3700x_reg_otp_hw_write(void *context,
|
|
unsigned int reg, unsigned int value)
|
|
{
|
|
return s5m3700x_i2c_write_reg(S5M3700X_OTP_ADDR, (u8)reg, (u8)value);
|
|
}
|
|
|
|
static int s5m3700x_reg_otp_hw_read(void *context,
|
|
unsigned int reg, unsigned int *value)
|
|
{
|
|
return s5m3700x_i2c_read_reg(S5M3700X_OTP_ADDR, (u8)reg, (u8 *)value);
|
|
}
|
|
|
|
static const struct regmap_bus s5m3700x_obus = {
|
|
.reg_write = s5m3700x_reg_otp_hw_write,
|
|
.reg_read = s5m3700x_reg_otp_hw_read,
|
|
};
|
|
|
|
const struct regmap_config s5m3700x_otp_regmap = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
.name = "i2c, S5M3700X_OTP",
|
|
.max_register = S5M3700X_REGCACHE_SYNC_END,
|
|
.readable_reg = s5m3700x_readable_otp_register,
|
|
.writeable_reg = s5m3700x_writeable_otp_register,
|
|
.volatile_reg = s5m3700x_volatile_otp_register,
|
|
.use_single_read = true,
|
|
.use_single_write = true,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
};
|
|
|
|
bool read_from_cache(struct device *dev, unsigned int reg, int map_type)
|
|
{
|
|
bool result = false;
|
|
|
|
switch (map_type) {
|
|
case S5M3700D:
|
|
result = s5m3700x_readable_register(dev, reg) &&
|
|
(!s5m3700x_volatile_register(dev, reg));
|
|
break;
|
|
case S5M3700A:
|
|
result = s5m3700x_readable_analog_register(dev, reg) &&
|
|
(!s5m3700x_volatile_analog_register(dev, reg));
|
|
break;
|
|
case S5M3700O:
|
|
result = s5m3700x_readable_otp_register(dev, reg) &&
|
|
(!s5m3700x_volatile_otp_register(dev, reg));
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool write_to_hw(struct device *dev, unsigned int reg, int map_type)
|
|
{
|
|
bool result = false;
|
|
|
|
switch (map_type) {
|
|
case S5M3700D:
|
|
result = s5m3700x_writeable_register(dev, reg) &&
|
|
(!s5m3700x_volatile_register(dev, reg));
|
|
break;
|
|
case S5M3700A:
|
|
result = s5m3700x_writeable_analog_register(dev, reg) &&
|
|
(!s5m3700x_volatile_analog_register(dev, reg));
|
|
break;
|
|
case S5M3700O:
|
|
result = s5m3700x_writeable_otp_register(dev, reg) &&
|
|
(!s5m3700x_volatile_otp_register(dev, reg));
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void s5m3700x_regmap_sync(struct device *dev)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(dev);
|
|
int reg[S5M3700X_REGCACHE_SYNC_END] = {0,};
|
|
int p_reg, p_map;
|
|
|
|
for (p_map = S5M3700D; p_map <= S5M3700O; p_map++) {
|
|
|
|
/* Read from Cache */
|
|
for (p_reg = 0; p_reg < S5M3700X_REGCACHE_SYNC_END; p_reg++) {
|
|
if (read_from_cache(dev, p_reg, p_map))
|
|
regmap_read(s5m3700x->regmap[p_map], p_reg, ®[p_reg]);
|
|
}
|
|
|
|
regcache_cache_bypass(s5m3700x->regmap[p_map], true);
|
|
/* Update HW */
|
|
for (p_reg = 0; p_reg < S5M3700X_REGCACHE_SYNC_END; p_reg++)
|
|
if (write_to_hw(dev, p_reg, p_map))
|
|
regmap_write(s5m3700x->regmap[p_map], p_reg, reg[p_reg]);
|
|
regcache_cache_bypass(s5m3700x->regmap[p_map], false);
|
|
}
|
|
}
|
|
|
|
static void s5m3700x_reg_restore(struct snd_soc_component *codec)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
/* For reduce the delay, perform the first time at booting */
|
|
if (!s5m3700x->is_probe_done) {
|
|
|
|
msleep(40);
|
|
|
|
s5m3700x_regmap_sync(codec->dev);
|
|
// s5m3700x_reset_io_selector_bits(codec);
|
|
} else {
|
|
s5m3700x_regmap_sync(codec->dev);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* s5m3700x_adc_digital_mute() - Set ADC digital Mute
|
|
*
|
|
* @codec: SoC audio codec device
|
|
* @channel: Digital mute control for ADC channel
|
|
* @on: mic mute is true, mic unmute is false
|
|
*
|
|
* Desc: When ADC path turn on, analog block noise can be recorded.
|
|
* For remove this, ADC path was muted always except that it was used.
|
|
*/
|
|
void s5m3700x_adc_digital_mute(struct s5m3700x_priv *s5m3700x,
|
|
unsigned int channel, bool on)
|
|
{
|
|
struct device *dev = s5m3700x->dev;
|
|
|
|
mutex_lock(&s5m3700x->adc_mute_lock);
|
|
|
|
if (on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_30_ADC1, channel, channel);
|
|
else
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_30_ADC1, channel, 0);
|
|
|
|
mutex_unlock(&s5m3700x->adc_mute_lock);
|
|
|
|
dev_info(dev, "%s called, %s work done.\n", __func__, on ? "Mute" : "Unmute");
|
|
}
|
|
EXPORT_SYMBOL_GPL(s5m3700x_adc_digital_mute);
|
|
|
|
/*
|
|
* DAC(Rx) functions
|
|
*/
|
|
/*
|
|
* s5m3700x_dac_soft_mute() - Set DAC soft mute
|
|
*
|
|
* @codec: SoC audio codec device
|
|
* @channel: Soft mute control for DAC channel
|
|
* @on: dac mute is true, dac unmute is false
|
|
*
|
|
* Desc: When DAC path turn on, analog block noise can be played.
|
|
* For remove this, DAC path was muted always except that it was used.
|
|
*/
|
|
static void s5m3700x_dac_soft_mute(struct s5m3700x_priv *s5m3700x,
|
|
unsigned int channel, bool on)
|
|
{
|
|
struct device *dev = s5m3700x->dev;
|
|
|
|
if (channel & DA_SMUTEL_MASK)
|
|
mutex_lock(&s5m3700x->dacl_mute_lock);
|
|
if (channel & DA_SMUTER_MASK)
|
|
mutex_lock(&s5m3700x->dacr_mute_lock);
|
|
|
|
if (on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, channel, channel);
|
|
else
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, channel, 0);
|
|
|
|
if (channel & DA_SMUTEL_MASK)
|
|
mutex_unlock(&s5m3700x->dacl_mute_lock);
|
|
if (channel & DA_SMUTER_MASK)
|
|
mutex_unlock(&s5m3700x->dacr_mute_lock);
|
|
|
|
dev_info(dev, "%s called, %s work done.\n", __func__, on ? "Mute" : "Unmute");
|
|
}
|
|
|
|
static void s5m3700x_adc_mute_work(struct work_struct *work)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x =
|
|
container_of(work, struct s5m3700x_priv, adc_mute_work.work);
|
|
unsigned int chop_val;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
dev_info(s5m3700x->dev, "%s called, chop: 0x%02X\n", __func__, chop_val);
|
|
|
|
if (s5m3700x->capture_on)
|
|
s5m3700x_adc_digital_mute(s5m3700x, ADC_MUTE_ALL, false);
|
|
|
|
s5m3700x->tx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->tx_dapm_done && s5m3700x->capture_on)
|
|
codec_regdump(s5m3700x->codec);
|
|
}
|
|
|
|
int check_adc_mode(int chop_val)
|
|
{
|
|
unsigned int mode = 0;
|
|
|
|
if (chop_val & MIC1_ON_MASK)
|
|
mode++;
|
|
if (chop_val & MIC2_ON_MASK)
|
|
mode++;
|
|
if (chop_val & MIC3_ON_MASK)
|
|
mode++;
|
|
if (chop_val & MIC4_ON_MASK)
|
|
mode++;
|
|
return mode;
|
|
}
|
|
|
|
static int vmid_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, dac_on, mic_status, vts_on, hifi_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
vts_on = (s5m3700x->vts1_on | s5m3700x->vts2_on);
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
mic_status = check_adc_mode(chop_val);
|
|
dev_info(codec->dev, "%s called, event = %d, adc mode: %d\n",
|
|
__func__, event, mic_status);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Clock Gate */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK | ADC_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
SEQ_CLK_GATE_MASK | ADC_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
switch (mic_status) {
|
|
case AMIC_MONO:
|
|
case AMIC_STEREO:
|
|
/* Setting Stereo Mode */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
ADC_FSEL_MASK, ADC_MODE_STEREO << ADC_FSEL_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_30_ADC1,
|
|
CH_MODE_MASK, ADC_CH_STEREO << CH_MODE_SHIFT);
|
|
break;
|
|
case AMIC_TRIPLE:
|
|
/* Setting Triple Mode */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK | ADC_CIC_CGC_MASK,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK | ADC_CIC_CGC_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
ADC_FSEL_MASK, ADC_MODE_TRIPLE << ADC_FSEL_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_30_ADC1,
|
|
CH_MODE_MASK, ADC_CH_TRIPLE << CH_MODE_SHIFT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* DMIC OSR Clear */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
DMIC_OSR_MASK, 0);
|
|
|
|
switch (s5m3700x->capture_aifrate) {
|
|
case S5M3700X_SAMPLE_RATE_48KHZ:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
CP_TYPE_SEL_MASK, FILTER_TYPE_NORMAL_AMIC << CP_TYPE_SEL_SHIFT);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_192KHZ:
|
|
case S5M3700X_SAMPLE_RATE_384KHZ:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
CP_TYPE_SEL_MASK, FILTER_TYPE_UHQA_W_LP_AMIC << CP_TYPE_SEL_SHIFT);
|
|
break;
|
|
}
|
|
|
|
/* DSML offset Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11A_DSMC3, 0x00);
|
|
|
|
/* DWA schema change */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_116_DSMC_1, 0x00);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK, 0);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | CORE_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* DSML offset Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11A_DSMC3, 0xE0);
|
|
|
|
/* DWA schema Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_116_DSMC_1, 0x80);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4, 0x00);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
ADC_CIC_CGC_MASK | ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
ADC_CLK_GATE_MASK, 0);
|
|
|
|
if ((!dac_on) && (!vts_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK, 0);
|
|
|
|
if (!hifi_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
COM_CLK_GATE_MASK, 0);
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dvmid_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, dac_on, dmic2_on, vts_on, hifi_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
dmic2_on = chop_val & DMIC2_ON_MASK;
|
|
vts_on = (s5m3700x->vts1_on | s5m3700x->vts2_on);
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
ADC_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
ADC_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
if (!dmic2_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
DMIC_CLK1_GATE_MASK, DMIC_CLK1_GATE_MASK);
|
|
else
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_11_CLKGATE1,
|
|
DMIC_CLK2_GATE_MASK, DMIC_CLK2_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* DMIC CLK ZTIE 0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_32_ADC3,
|
|
DMIC_CLK_ZTIE_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
CP_TYPE_SEL_MASK | DMIC_OSR_MASK,
|
|
FILTER_TYPE_NORMAL_DMIC << CP_TYPE_SEL_SHIFT |
|
|
DMIC_OSR_64 << DMIC_OSR_SHIFT);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
CP_TYPE_SEL_MASK | DMIC_OSR_MASK, 0);
|
|
|
|
/* DMIC CLK ZTIE 1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_32_ADC3,
|
|
DMIC_CLK_ZTIE_MASK, DMIC_CLK_ZTIE_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
ADC_CIC_CGL_MASK | ADC_CIC_CGR_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_11_CLKGATE1,
|
|
DMIC_CLK2_GATE_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
ADC_CLK_GATE_MASK | DMIC_CLK1_GATE_MASK, 0);
|
|
|
|
if ((!dac_on) && (!vts_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
COM_CLK_GATE_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mic1_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* DSML Blocking & Chopping On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_ISIBLKL_MASK | EN_CHOPL_MASK | CAL_SKIP_MASK,
|
|
EN_ISIBLKL_MASK | EN_CHOPL_MASK | CAL_SKIP_MASK);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* MIC1 APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC1L_MASK, APW_MIC1L_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST2_MASK, SEL_BST2_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
/* MIC1 APW Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC1L_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
if ((!s5m3700x->vts1_on) && (!s5m3700x->vts2_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK |
|
|
SEL_BST1_MASK | SEL_BST2_MASK, 0);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* DSML Blocking & Chopping Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPL_MASK | CAL_SKIP_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mic2_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* Boost1 LCP On */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x02);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x80);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* DSML Blocking & Chopping On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPC_MASK | CAL_SKIP_MASK,
|
|
EN_CHOPC_MASK | CAL_SKIP_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* MIC2 APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC2C_MASK, APW_MIC2C_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST2_MASK, SEL_BST2_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
/* MIC2 APW Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC2C_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
if ((!s5m3700x->vts1_on) && (!s5m3700x->vts2_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK | SEL_BST2_MASK, 0);
|
|
|
|
/* Boost1 LCP Off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x00);
|
|
}
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* DSML Blocking & Chopping Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPC_MASK | CAL_SKIP_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mic3_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, mic1_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
mic1_on = chop_val & MIC1_ON_MASK;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* MIC3/4 Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11D_BST_OP, 0x00);
|
|
|
|
/* Boost1 LCP On */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x02);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x80);
|
|
|
|
/* DSML Blocking & Chopping On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK);
|
|
|
|
/* DSMR ISI Blocking */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_119_DSM3, 0x10);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_118_DSMC_2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* MIC3 APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC3R_MASK, APW_MIC3R_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST2_MASK, SEL_BST2_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC3R_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
if ((!s5m3700x->vts1_on) && (!s5m3700x->vts2_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK |
|
|
SEL_BST3_MASK | SEL_BST2_MASK, 0);
|
|
|
|
/* Boost1 LCP Off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x00);
|
|
}
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_118_DSMC_2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* DSMR ISI Blocking */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_119_DSM3, 0x10);
|
|
|
|
/* DSML Blocking & Chopping Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK, 0);
|
|
|
|
/* MIC3/4 Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11D_BST_OP, 0x00);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mic4_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, mic1_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
mic1_on = chop_val & MIC1_ON_MASK;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* MIC3/4 Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11D_BST_OP, 0x04);
|
|
|
|
/* DSML Blocking & Chopping On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK);
|
|
|
|
/* DSMR ISI Blocking */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_119_DSM3, 0x10);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_118_DSMC_2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* MIC4 APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC4R_MASK, APW_MIC4R_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST1_MASK, SEL_BST1_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
/* MIC4 APW Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_MIC4R_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
if ((!s5m3700x->vts1_on) && (!s5m3700x->vts2_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK |
|
|
SEL_BST4_MASK | SEL_BST1_MASK, 0);
|
|
|
|
/* DSML Blocking & Chopping Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_115_DSM1,
|
|
EN_CHOPR_MASK | CAL_SKIP_MASK, 0);
|
|
|
|
/* BST VG Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_118_DSMC_2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* BST BSTR Control */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
/* DSMR ISI Blocking */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_119_DSM3, 0x10);
|
|
|
|
/* MIC3/4 Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11D_BST_OP, 0x00);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dmic1_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, dac_on, hifi_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
DMIC_EN1_MASK, DMIC_EN1_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK, 0);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | CORE_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
DMIC_EN1_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dmic2_pga_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, dac_on, hifi_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
DMIC_EN2_MASK, DMIC_EN2_MASK);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK | CORE_RESETB_MASK);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_ADC_MASK | ADC_RESETB_MASK, 0);
|
|
|
|
if ((!dac_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | CORE_RESETB_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4,
|
|
DMIC_EN2_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int adc_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, dmic_on, amic_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
dmic_on = chop_val & DMIC_ON_MASK;
|
|
amic_on = chop_val & AMIC_ON_MASK;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d, chop: 0x%02X\n",
|
|
__func__, event, chop_val);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
cancel_delayed_work(&s5m3700x->adc_mute_work);
|
|
if (amic_on)
|
|
queue_delayed_work(s5m3700x->adc_mute_wq, &s5m3700x->adc_mute_work,
|
|
msecs_to_jiffies(s5m3700x->amic_delay));
|
|
else if (dmic_on)
|
|
queue_delayed_work(s5m3700x->adc_mute_wq, &s5m3700x->adc_mute_work,
|
|
msecs_to_jiffies(s5m3700x->dmic_delay));
|
|
else
|
|
queue_delayed_work(s5m3700x->adc_mute_wq, &s5m3700x->adc_mute_work,
|
|
msecs_to_jiffies(220));
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_adc_digital_mute(s5m3700x, ADC_MUTE_ALL, true);
|
|
s5m3700x->tx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dac_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int chop_val, hp_on, ep_on, mic_on, vts_on, hifi_on;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
hp_on = chop_val & HP_ON_MASK;
|
|
ep_on = chop_val & EP_ON_MASK;
|
|
mic_on = chop_val & (DMIC_ON_MASK | AMIC_ON_MASK);
|
|
vts_on = (s5m3700x->vts1_on | s5m3700x->vts2_on);
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
dev_info(codec->dev, "%s called, event = %d, chop: 0x%02X\n",
|
|
__func__, event, chop_val);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
if (hp_on) {
|
|
/* CLKGATE 0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
OVP_CLK_GATE_MASK | SEQ_CLK_GATE_MASK | AVC_CLK_GATE_MASK
|
|
| DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
OVP_CLK_GATE_MASK | SEQ_CLK_GATE_MASK | AVC_CLK_GATE_MASK
|
|
| DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
/* CLKGATE 1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_11_CLKGATE1,
|
|
DAC_CIC_TEMP_MASK | DAC_CIC_CGLR_MASK,
|
|
DAC_CIC_TEMP_MASK | DAC_CIC_CGLR_MASK);
|
|
|
|
/* CLKGATE 2 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
CED_CLK_GATE_MASK, CED_CLK_GATE_MASK);
|
|
|
|
/* RESETB */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | RSTB_DAC_DSM_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK,
|
|
AVC_RESETB_MASK | RSTB_DAC_DSM_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK);
|
|
} else {
|
|
/* CLKGATE 0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK | AVC_CLK_GATE_MASK
|
|
| DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
SEQ_CLK_GATE_MASK | AVC_CLK_GATE_MASK
|
|
| DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
/* CLKGATE 1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_11_CLKGATE1,
|
|
DAC_CIC_TEMP_MASK | DAC_CIC_CGC_MASK,
|
|
DAC_CIC_TEMP_MASK | DAC_CIC_CGC_MASK);
|
|
|
|
/* CLKGATE 2 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
CED_CLK_GATE_MASK, CED_CLK_GATE_MASK);
|
|
|
|
/* RESETB */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK);
|
|
}
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_104_CTRL_CP, 0x88);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_104_CTRL_CP, 0xAA);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_106_CTRL_CP2, 0xFF);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_106_CTRL_CP2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_104_CTRL_CP, 0x00);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CLKGATE 2 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
CED_CLK_GATE_MASK, 0);
|
|
|
|
/* CLKGATE 1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_11_CLKGATE1,
|
|
DAC_CIC_TEMP_MASK | DAC_CIC_CGLR_MASK | DAC_CIC_CGC_MASK, 0);
|
|
|
|
/* CLKGATE 0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
OVP_CLK_GATE_MASK, 0);
|
|
|
|
if (!hifi_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
AVC_CLK_GATE_MASK | DAC_CLK_GATE_MASK, 0);
|
|
|
|
if ((!mic_on) && (!vts_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK, 0);
|
|
|
|
if (!hifi_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
COM_CLK_GATE_MASK, 0);
|
|
}
|
|
|
|
/* RESETB */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
RSTB_DAC_DSM_MASK, 0);
|
|
|
|
if (!hifi_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK, 0);
|
|
|
|
if ((!mic_on) && (!hifi_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
CORE_RESETB_MASK, 0);
|
|
|
|
s5m3700x_usleep(5000);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void hp_32ohm(struct snd_soc_component *codec, struct s5m3700x_priv *s5m3700x, int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xEE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x35);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xEE);
|
|
|
|
/* Class-H CP2 Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x7E);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C6_CP2_TH1_16, 0x7C);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C7_CP2_TH2_16, 0x81);
|
|
|
|
/* IDAC Chop Enable */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_131_PD_IDAC2, 0xE0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_17_CLK_MODE_SEL2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BE_IDAC0_OTP, 0X81);
|
|
|
|
/* BIAS & HPZ & CC Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK, 0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13B_OCP_HP, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B3_CTRL_IHP, 0x13);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B5_CTRL_HP1, 0x13);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x1B);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BF_IDAC1_OTP, 0x3A);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C0_IDAC2_OTP, 0x9B);
|
|
|
|
switch (s5m3700x->playback_aifrate) {
|
|
case S5M3700X_SAMPLE_RATE_48KHZ:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x63);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_192KHZ:
|
|
case S5M3700X_SAMPLE_RATE_384KHZ:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x44);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_UHQA_MASK, EN_UHQA_MASK);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x13);
|
|
break;
|
|
default:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x63);
|
|
break;
|
|
}
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x3A);
|
|
/* HP APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_HP_MASK, APW_HP_MASK);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x9A);
|
|
|
|
/* OVP Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_142_REF_SURGE, 0x29);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_143_CTRL_OVP1, 0x12);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
|
|
s5m3700x->rx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
/* HP APW Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_HP_MASK, 0);
|
|
|
|
/* OVP Off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_143_CTRL_OVP1, 0x02);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_142_REF_SURGE, 0x67);
|
|
s5m3700x->rx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x50);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBE);
|
|
|
|
/* IDAC Chop Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_131_PD_IDAC2, 0xC0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_17_CLK_MODE_SEL2, 0x08);
|
|
|
|
/* BIAS & HPZ & CC Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13B_OCP_HP, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x33);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_UHQA_MASK, 0);
|
|
|
|
/* AVC & Playmode Setting Default */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK | AVC_CLK_SEL_MASK, 0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xF7);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x4F);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x2F);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0xE9);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0xC0);
|
|
|
|
/* AVC Default Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x05);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_51_AVC2, 0x6A);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void hp_6ohm(struct snd_soc_component *codec, struct s5m3700x_priv *s5m3700x, int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xEE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x35);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xEE);
|
|
|
|
/* Class-H CP2 Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x7E);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C6_CP2_TH1_16, 0x79);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C7_CP2_TH2_16, 0x80);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CA_CP2_TH2_06, 0x75);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CB_CP2_TH2_06, 0x7B);
|
|
|
|
/* IDAC Chop Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_131_PD_IDAC2, 0xE0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_17_CLK_MODE_SEL2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BE_IDAC0_OTP, 0x81);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x1B);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BF_IDAC1_OTP, 0x3A);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C0_IDAC2_OTP, 0x9B);
|
|
|
|
/* BIAS & HPZ & CC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13B_OCP_HP, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B3_CTRL_IHP, 0x13);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B5_CTRL_HP1, 0x13);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK, 0);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_UHQA_MASK, EN_UHQA_MASK);
|
|
|
|
switch (s5m3700x->playback_aifrate) {
|
|
case S5M3700X_SAMPLE_RATE_48KHZ:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x13);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_192KHZ:
|
|
case S5M3700X_SAMPLE_RATE_384KHZ:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x44);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x12);
|
|
break;
|
|
default:
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B4_CTRL_HP0, 0x13);
|
|
break;
|
|
}
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
/* HP APW On */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_HP_MASK, APW_HP_MASK);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x9A);
|
|
|
|
/* OVP Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_142_REF_SURGE, 0x29);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_143_CTRL_OVP1, 0x12);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
|
|
s5m3700x->rx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
/* HP APW Off */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_HP_MASK, 0);
|
|
|
|
/* OVP Off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_143_CTRL_OVP1, 0x02);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_142_REF_SURGE, 0x67);
|
|
s5m3700x->rx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x50);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBE);
|
|
|
|
/* IDAC Chop Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_131_PD_IDAC2, 0xC0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_17_CLK_MODE_SEL2, 0x08);
|
|
|
|
/* BIAS & HPZ & CC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13B_OCP_HP, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x33);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK,
|
|
EN_HP_BODY_MASK | SEL_RES_SUB_MASK);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_13A_POP_HP,
|
|
EN_UHQA_MASK, 0);
|
|
|
|
/* AVC & Playmode Setting Default */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK | AVC_CLK_SEL_MASK, 0);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xF7);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x4F);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x2F);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0xE9);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0xC0);
|
|
|
|
/* AVC Default Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x05);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_51_AVC2, 0x6A);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int hpdrv_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
switch (s5m3700x->hp_imp) {
|
|
case HP_IMP_32:
|
|
dev_info(codec->dev, "%s called, hp: 32ohm, event = %d\n",
|
|
__func__, event);
|
|
hp_32ohm(codec, s5m3700x, event);
|
|
break;
|
|
case HP_IMP_6:
|
|
dev_info(codec->dev, "%s called, hp: 16ohm, event = %d\n",
|
|
__func__, event);
|
|
hp_6ohm(codec, s5m3700x, event);
|
|
break;
|
|
default:
|
|
dev_info(codec->dev, "%s called, default hp: 32ohm, event = %d\n",
|
|
__func__, event);
|
|
hp_32ohm(codec, s5m3700x, event);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ep_32ohm(struct snd_soc_component *codec, struct s5m3700x_priv *s5m3700x, int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, RSTB_DAC_DSM_C_MASK);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBD);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x07);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBD);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
|
|
/* Class-H */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x7C);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x80);
|
|
|
|
/* IDAC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_288_IDAC3_OTP, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x15);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_28A_IDAC5_OTP, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0x80);
|
|
|
|
/* EP Control Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B7_CTRL_EP0, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B8_CTRL_EP1, 0x13);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B9_CTRL_EP2, 0x63);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, APW_RCV_MASK);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
s5m3700x->rx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, 0);
|
|
s5m3700x->rx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x50);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x33);
|
|
|
|
/* IDAC & EP Control Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0xD0);
|
|
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ep_12ohm(struct snd_soc_component *codec, struct s5m3700x_priv *s5m3700x, int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, RSTB_DAC_DSM_C_MASK);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xCC);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x07);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xCC);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
|
|
/* Class-H */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x7B);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x7F);
|
|
|
|
/* IDAC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_288_IDAC3_OTP, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x15);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_28A_IDAC5_OTP, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0x80);
|
|
|
|
/* EP Control Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B7_CTRL_EP0, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B8_CTRL_EP1, 0x24);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B9_CTRL_EP2, 0x63);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, APW_RCV_MASK);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
s5m3700x->rx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, 0);
|
|
s5m3700x->rx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x50);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x33);
|
|
|
|
/* IDAC & EP Control Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0xD0);
|
|
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ep_6ohm(struct snd_soc_component *codec, struct s5m3700x_priv *s5m3700x, int event)
|
|
{
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, RSTB_DAC_DSM_C_MASK);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xCC);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x07);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xCC);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
|
|
/* Class-H */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x75);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x79);
|
|
|
|
/* IDAC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_288_IDAC3_OTP, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x15);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_28A_IDAC5_OTP, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0x80);
|
|
|
|
/* EP Control Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B7_CTRL_EP0, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B8_CTRL_EP1, 0x24);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2B9_CTRL_EP2, 0x63);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, APW_RCV_MASK);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
s5m3700x->rx_dapm_done = true;
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_RCV_MASK, 0);
|
|
s5m3700x->rx_dapm_done = false;
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x50);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBE);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x33);
|
|
|
|
/* IDAC & EP Control Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_149_PD_EP, 0xD0);
|
|
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, 0);
|
|
break;
|
|
}
|
|
}
|
|
static int epdrv_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
switch (s5m3700x->rcv_imp) {
|
|
case RCV_IMP_32:
|
|
dev_info(codec->dev, "%s called, ep: 32ohm, event = %d\n",
|
|
__func__, event);
|
|
ep_32ohm(codec, s5m3700x, event);
|
|
break;
|
|
case RCV_IMP_12:
|
|
dev_info(codec->dev, "%s called, ep: 12ohm, event = %d\n",
|
|
__func__, event);
|
|
ep_12ohm(codec, s5m3700x, event);
|
|
break;
|
|
case RCV_IMP_6:
|
|
dev_info(codec->dev, "%s called, ep: 6ohm, event = %d\n",
|
|
__func__, event);
|
|
ep_6ohm(codec, s5m3700x, event);
|
|
break;
|
|
default:
|
|
dev_info(codec->dev, "%s called, default ep: 32ohm, event = %d\n",
|
|
__func__, event);
|
|
ep_32ohm(codec, s5m3700x, event);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int linedrv_ev(struct snd_soc_dapm_widget *w,
|
|
struct snd_kcontrol *kcontrol, int event)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(codec->dev, "%s called, event = %d\n", __func__, event);
|
|
|
|
switch (event) {
|
|
case SND_SOC_DAPM_PRE_PMU:
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, RSTB_DAC_DSM_C_MASK);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x05);
|
|
|
|
/* CP Frequency Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBB);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x07);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBB);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
|
|
/* Class-H */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x77);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x7D);
|
|
|
|
/* IDAC Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_288_IDAC3_OTP, 0x32);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_289_IDAC4_OTP, 0x15);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_28A_IDAC5_OTP, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_14A_PD_LO, 0x80);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BA_CTRL_LN1, 0x22);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2BB_CTRL_LN2, 0x63);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMU:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_LINE_MASK, APW_LINE_MASK);
|
|
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, false);
|
|
break;
|
|
case SND_SOC_DAPM_PRE_PMD:
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_19_PWAUTO_DA,
|
|
APW_LINE_MASK, 0);
|
|
break;
|
|
case SND_SOC_DAPM_POST_PMD:
|
|
/* CP Frequency Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x85);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, 0xBB);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_154_DA_CP1, 0x07);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_155_DA_CP2, 0xBB);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_156_DA_CP3, 0x22);
|
|
|
|
/* IDAC & EP Control Setting Default */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_14A_PD_LO, 0xD0);
|
|
|
|
/* RESETB1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
RSTB_DAC_DSM_C_MASK, 0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* s5m3700x_dvol_adc_tlv - Digital volume for ADC
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0x00 ~ 0xE0 : +42dB to -70dB, step 0.5dB
|
|
* 0xE0 ~ 0xE5 : -70dB to -80dB, step 2.0dB
|
|
*
|
|
* When the map is in descending order, we need to set the invert bit
|
|
* and arrange the map in ascending order. The offsets are calculated as
|
|
* (max - offset).
|
|
*
|
|
* offset_in_table = max - offset_actual;
|
|
*
|
|
* DVOL_ADCL : reg(0x34), shift(0), width(8), invert(1), max(0xE5)
|
|
* DVOL_ADCR : reg(0x35), shift(0), width(8), invert(1), max(0xE5)
|
|
* DVOL_ADCC : reg(0x36), shift(0), width(8), invert(1), max(0xE5)
|
|
*/
|
|
static const unsigned int s5m3700x_dvol_adc_tlv[] = {
|
|
TLV_DB_RANGE_HEAD(2),
|
|
0x00, 0x05, TLV_DB_SCALE_ITEM(-8000, 200, 0),
|
|
0x06, 0xE5, TLV_DB_SCALE_ITEM(-6950, 50, 0),
|
|
};
|
|
|
|
|
|
static int mic1_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1, &mic_boost);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int mic1_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
return 0;
|
|
}
|
|
|
|
static int mic2_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_112_BST2, &mic_boost);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int mic2_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_112_BST2,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
return 0;
|
|
}
|
|
|
|
static int mic3_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3, &mic_boost);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int mic3_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
return 0;
|
|
}
|
|
|
|
static int mic4_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4, &mic_boost);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int mic4_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_114_BST4,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* s5m3700x_dmic_gain_tlv - Digital MIC gain
|
|
*
|
|
* Map as per data-sheet:
|
|
* 000 ~ 111 : 1 to 15, step 2 code
|
|
*
|
|
* When the map is in descending order, we need to set the invert bit
|
|
* and arrange the map in ascending order. The offsets are calculated as
|
|
* (max - offset).
|
|
*
|
|
* offset_in_table = max - offset_actual;
|
|
*
|
|
* DMIC_GAIN_PRE : reg(0x32), shift(4), width(3), invert(0), max(7)
|
|
*/
|
|
static const unsigned int s5m3700x_dmic_gain_tlv[] = {
|
|
TLV_DB_RANGE_HEAD(1),
|
|
0x0, 0x7, TLV_DB_SCALE_ITEM(100, 200, 0),
|
|
};
|
|
|
|
/*
|
|
* s5m3700x_dmic_st_tlv - DMIC IO strength selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0x0 ~ 0x3 : 0 to 3, step 1
|
|
*
|
|
* When the map is in descending order, we need to set the invert bit
|
|
* and arrange the map in ascending order. The offsets are calculated as
|
|
* (max - offset).
|
|
*
|
|
* offset_in_table = max - offset_actual;
|
|
*
|
|
* DMIC_ST : reg(0x2F), shift(2), width(2), invert(0), max(0x3)
|
|
*/
|
|
static const unsigned int s5m3700x_dmic_st_tlv[] = {
|
|
TLV_DB_RANGE_HEAD(1),
|
|
0x0, 0x3, TLV_DB_SCALE_ITEM(0, 300, 0),
|
|
};
|
|
|
|
/*
|
|
* s5m3700x_sdout_st_tlv - SDOUT IO strength selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0x0 ~ 0x3 : 0 to 3, step 1
|
|
*
|
|
* When the map is in descending order, we need to set the invert bit
|
|
* and arrange the map in ascending order. The offsets are calculated as
|
|
* (max - offset).
|
|
*
|
|
* offset_in_table = max - offset_actual;
|
|
*
|
|
* SDOUT_ST : reg(0x2F), shift(0), width(2), invert(0), max(0x3)
|
|
*/
|
|
static const unsigned int s5m3700x_sdout_st_tlv[] = {
|
|
TLV_DB_RANGE_HEAD(1),
|
|
0x0, 0x3, TLV_DB_SCALE_ITEM(0, 300, 0),
|
|
};
|
|
|
|
static int micbias1_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int value;
|
|
bool micbias_flag;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM, &value);
|
|
micbias_flag = value & APW_MCB1_MASK;
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = micbias_flag;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int micbias1_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
if (s5m3700x->vts_dmic_on == VTS_DMIC1_ON) {
|
|
dev_info(codec->dev, "%s skip to control micbias1\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
if (value)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB1_MASK, APW_MCB1_MASK);
|
|
else
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB1_MASK, 0);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int micbias2_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int value;
|
|
bool micbias_flag;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM, &value);
|
|
micbias_flag = value & APW_MCB2_MASK;
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = micbias_flag;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int micbias2_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
|
|
if (value) {
|
|
s5m3700x->hp_bias_mix_cnt++;
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB2_MASK, APW_MCB2_MASK);
|
|
} else {
|
|
s5m3700x->hp_bias_mix_cnt--;
|
|
if (s5m3700x->hp_bias_mix_cnt == 0) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB2_MASK, 0);
|
|
} else if (s5m3700x->hp_bias_mix_cnt < 0) {
|
|
dev_info(codec->dev, "%s called, micbias operation is not match\n", __func__);
|
|
s5m3700x->hp_bias_mix_cnt = 0;
|
|
}
|
|
}
|
|
dev_info(codec->dev, "%s called, micbias turn %s, cnt %d\n",
|
|
__func__, value ? "On" : "Off", s5m3700x->hp_bias_mix_cnt);
|
|
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int micbias3_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int value;
|
|
bool micbias_flag;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM, &value);
|
|
micbias_flag = value & APW_MCB3_MASK;
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = micbias_flag;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int micbias3_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
if (s5m3700x->vts_dmic_on == VTS_DMIC2_ON) {
|
|
dev_info(codec->dev, "%s skip to control micbias3\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
if (value)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, APW_MCB3_MASK);
|
|
else
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, 0);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* s5m3700x_adc_dat_src - I2S channel input data selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 00 : ADC Left Channel Data
|
|
* 01 : ADC Right Channel Data
|
|
* 10 : ADC Center Channel Data
|
|
* 11 : Zero data
|
|
*
|
|
* SEL_ADC0 : reg(0x23), shift(0), width(2)
|
|
* SEL_ADC1 : reg(0x23), shift(2), width(2)
|
|
* SEL_ADC2 : reg(0x23), shift(4), width(2)
|
|
* SEL_ADC3 : reg(0x23), shift(6), width(2)
|
|
*/
|
|
static const char * const s5m3700x_adc_dat_src[] = {
|
|
"ADCL", "ADCR", "ADCC", "Zero"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_adc_dat_enum0, S5M3700X_23_IF_FORM4,
|
|
SEL_ADC0_SHIFT, s5m3700x_adc_dat_src);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_adc_dat_enum1, S5M3700X_23_IF_FORM4,
|
|
SEL_ADC1_SHIFT, s5m3700x_adc_dat_src);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_adc_dat_enum2, S5M3700X_23_IF_FORM4,
|
|
SEL_ADC2_SHIFT, s5m3700x_adc_dat_src);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_adc_dat_enum3, S5M3700X_23_IF_FORM4,
|
|
SEL_ADC3_SHIFT, s5m3700x_adc_dat_src);
|
|
|
|
/*
|
|
* s5m3700x_i2s_df_format - I2S Data Format Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 000 : I2S, PCM Long format
|
|
* 001 : Left Justified format
|
|
* 010 : Right Justified format
|
|
* 011 : Not used
|
|
* 100 : I2S, PCM Short format
|
|
* 101 ~ 111 : Not used
|
|
* I2S_DF : reg(0x20), shift(4), width(3)
|
|
*/
|
|
static const char * const s5m3700x_i2s_df_format[] = {
|
|
"PCM-L", "LJ", "RJ", "Zero0", "PCM-S", "Zero1", "Zero2", "Zero3"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_i2s_df_enum, S5M3700X_20_IF_FORM1,
|
|
I2S_DF_SHIFT, s5m3700x_i2s_df_format);
|
|
|
|
/*
|
|
* s5m3700x_i2s_bck_format - I2S BCLK Data Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0 : Normal
|
|
* 1 : Invert
|
|
* I2S_DF : reg(0x20), shift(1)
|
|
*/
|
|
|
|
static const char * const s5m3700x_i2s_bck_format[] = {
|
|
"Normal", "Invert"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_i2s_bck_enum, S5M3700X_20_IF_FORM1,
|
|
BCK_POL_SHIFT, s5m3700x_i2s_bck_format);
|
|
|
|
/*
|
|
* s5m3700x_i2s_lrck_format - I2S LRCLK Data Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0 : 0&2 Low, 1&3 High
|
|
* 1 : 1&3 Low, 0&2 High
|
|
* I2S_DF : reg(0x20), shift(0)
|
|
*/
|
|
|
|
static const char * const s5m3700x_i2s_lrck_format[] = {
|
|
"Normal", "Invert"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_i2s_lrck_enum, S5M3700X_20_IF_FORM1,
|
|
LRCK_POL_SHIFT, s5m3700x_i2s_lrck_format);
|
|
|
|
static int dmic_delay_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->dmic_delay;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dmic_delay_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->dmic_delay = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int amic_delay_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->amic_delay;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int amic_delay_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->amic_delay = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static const char * const s5m3700x_hpf_sel_text[] = {
|
|
"HPF-15Hz", "HPF-33Hz", "HPF-60Hz", "HPF-113Hz"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_hpf_sel_enum, S5M3700X_37_AD_HPF,
|
|
HPF_SEL_SHIFT, s5m3700x_hpf_sel_text);
|
|
|
|
static const char * const s5m3700x_hpf_order_text[] = {
|
|
"HPF-2nd", "HPF-1st"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_hpf_order_enum, S5M3700X_37_AD_HPF,
|
|
HPF_ORDER_SHIFT, s5m3700x_hpf_order_text);
|
|
|
|
static const char * const s5m3700x_hpf_channel_text[] = {
|
|
"Off", "On"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_hpf_channel_enum_l, S5M3700X_37_AD_HPF,
|
|
HPF_ENL_SHIFT, s5m3700x_hpf_channel_text);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_hpf_channel_enum_r, S5M3700X_37_AD_HPF,
|
|
HPF_ENR_SHIFT, s5m3700x_hpf_channel_text);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_hpf_channel_enum_c, S5M3700X_37_AD_HPF,
|
|
HPF_ENC_SHIFT, s5m3700x_hpf_channel_text);
|
|
|
|
/*
|
|
* s5m3700x_dvol_dac_tlv - Maximum headphone gain for EAR/RCV path
|
|
*
|
|
* Map as per data-sheet:
|
|
* 0x00 ~ 0xE0 : +42dB to -70dB, step 0.5dB
|
|
* 0xE1 ~ 0xE5 : -72dB to -80dB, step 2.0dB
|
|
* 0xE6 : -82.4dB
|
|
* 0xE7 ~ 0xE9 : -84.3dB to -96.3dB, step 6dB
|
|
*
|
|
* When the map is in descending order, we need to set the invert bit
|
|
* and arrange the map in ascending order. The offsets are calculated as
|
|
* (max - offset).
|
|
*
|
|
* offset_in_table = max - offset_actual;
|
|
*
|
|
* DVOL_DAL : reg(0x41), shift(0), width(8), invert(1), max(0xE9)
|
|
* DVOL_DAR : reg(0x42), shift(0), width(8), invert(1), max(0xE9)
|
|
*/
|
|
static const unsigned int s5m3700x_dvol_dac_tlv[] = {
|
|
TLV_DB_RANGE_HEAD(4),
|
|
0x01, 0x03, TLV_DB_SCALE_ITEM(-9630, 600, 0),
|
|
0x04, 0x04, TLV_DB_SCALE_ITEM(-8240, 0, 0),
|
|
0x05, 0x09, TLV_DB_SCALE_ITEM(-8000, 200, 0),
|
|
0x0A, 0xE9, TLV_DB_SCALE_ITEM(-7000, 50, 0),
|
|
};
|
|
|
|
static int hp_gain_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->hp_avc_gain;
|
|
|
|
dev_err(s5m3700x->dev, "%s, hp_avc_gain: %d\n",
|
|
__func__, s5m3700x->hp_avc_gain);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int hp_gain_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->hp_avc_gain = value;
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x00);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5F_AVC16,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_61_AVC18,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_63_AVC20,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5F_AVC16,
|
|
AVC_AVOL_MASK, value);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_61_AVC18,
|
|
AVC_AVOL_MASK, value);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_63_AVC20,
|
|
AVC_AVOL_MASK, value);
|
|
return 0;
|
|
}
|
|
|
|
static int rcv_gain_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->rcv_avc_gain;
|
|
|
|
dev_err(s5m3700x->dev, "%s, rcv_avc_gain: %d\n",
|
|
__func__, s5m3700x->rcv_avc_gain);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rcv_gain_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->rcv_avc_gain = value;
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x00);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5F_AVC16,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_61_AVC18,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_63_AVC20,
|
|
SIGN_MASK, 1 << SIGN_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5F_AVC16,
|
|
AVC_AVOL_MASK, value);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_61_AVC18,
|
|
AVC_AVOL_MASK, value);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_63_AVC20,
|
|
AVC_AVOL_MASK, value);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* s5m3700x_dac_dat_src - I2S channel input data selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 00 : DAC I2S Channel 0
|
|
* 01 : DAC I2S Channel 1
|
|
* 10 : DAC I2S Channel 2
|
|
* 11 : DAC I2S Channel 3
|
|
*
|
|
* SEL_DAC0 : reg(0x24), shift(0), width(2)
|
|
* SEL_DAC1 : reg(0x23), shift(4), width(2)
|
|
*/
|
|
static const char * const s5m3700x_dac_dat_src[] = {
|
|
"CH0", "CH1", "CH2", "CH3"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_dac_dat_enum0, S5M3700X_24_IF_FORM5,
|
|
SEL_DAC0_SHIFT, s5m3700x_dac_dat_src);
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_dac_dat_enum1, S5M3700X_24_IF_FORM5,
|
|
SEL_DAC1_SHIFT, s5m3700x_dac_dat_src);
|
|
|
|
/*
|
|
* s5m3700x_dac_mixl_mode_text - DACL Mixer Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 000 : Data L
|
|
* 001 : (L+R)/2 Mono
|
|
* 010 : (L+R) Mono
|
|
* 011 : (L+R)/2 Polarity Changed
|
|
* 100 : (L+R) Polarity Changed
|
|
* 101 : Zero Padding
|
|
* 110 : Data L Polarity Changed
|
|
* 111 : Data R Polarity Changed
|
|
*
|
|
* DAC_MIXL : reg(0x44), shift(4), width(3)
|
|
*/
|
|
static const char * const s5m3700x_dac_mixl_mode_text[] = {
|
|
"Data L", "LR/2 Mono", "LR Mono", "LR/2 PolCh",
|
|
"LR PolCh", "Zero", "Data L PolCh", "Data R PolCh"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_dac_mixl_mode_enum, S5M3700X_44_PLAY_MIX0,
|
|
DAC_MIXL_SHIFT, s5m3700x_dac_mixl_mode_text);
|
|
|
|
/*
|
|
* s5m3700x_dac_mixr_mode_text - DACR Mixer Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 000 : Data R
|
|
* 001 : (L+R)/2 Mono
|
|
* 010 : (L+R) Mono
|
|
* 011 : (L+R)/2 Polarity Changed
|
|
* 100 : (L+R) Polarity Changed
|
|
* 101 : Zero Padding
|
|
* 110 : Data R Polarity Changed
|
|
* 111 : Data L Polarity Changed
|
|
*
|
|
* DAC_MIXR : reg(0x44), shift(0), width(3)
|
|
*/
|
|
static const char * const s5m3700x_dac_mixr_mode_text[] = {
|
|
"Data R", "LR/2 Mono", "LR Mono", "LR/2 PolCh",
|
|
"LR PolCh", "Zero", "Data R PolCh", "Data L PolCh"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_dac_mixr_mode_enum, S5M3700X_44_PLAY_MIX0,
|
|
DAC_MIXR_SHIFT, s5m3700x_dac_mixr_mode_text);
|
|
|
|
/*
|
|
* s5m3700x_lnrcv_mix_mode_text - LINE/RCV Mixer Selection
|
|
*
|
|
* Map as per data-sheet:
|
|
* 00 : Data L
|
|
* 01 : Data R
|
|
* 10 : L/2 + R/2
|
|
* 11 : Zero
|
|
*
|
|
* LINE/RCV MIX : reg(0x45), shift(3), width(2)
|
|
*/
|
|
static const char * const s5m3700x_lnrcv_mix_mode_text[] = {
|
|
"Data L", "Data R", "LR/2", "Zero",
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_lnrcv_mix_mode_enum, S5M3700X_45_PLAY_MIX1,
|
|
LN_RCV_MIX_SHIFT, s5m3700x_lnrcv_mix_mode_text);
|
|
|
|
static int jack_pole_cnt_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->p_jackdet->t_pole_cnt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_pole_cnt_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->p_jackdet->t_pole_cnt = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_pole_delay_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->p_jackdet->t_pole_delay;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_pole_delay_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->p_jackdet->t_pole_delay = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_btn_cnt_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->p_jackdet->t_btn_cnt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_btn_cnt_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->p_jackdet->t_btn_cnt = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_btn_delay_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->p_jackdet->t_btn_delay;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int jack_btn_delay_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
s5m3700x->p_jackdet->t_btn_delay = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ant_mdet1_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int value;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_OTP_ADDR, 0xDD, &value);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = (value & INP_SEL_R_MASK) >> INP_SEL_R_SHIFT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ant_mdet1_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_DD_DCTR_DBNC6,
|
|
INP_SEL_R_MASK, value << INP_SEL_R_SHIFT);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ant_mdet2_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int value;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_OTP_ADDR, 0xDD, &value);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = (value & INP_SEL_L_MASK) >> INP_SEL_L_SHIFT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ant_mdet2_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_DD_DCTR_DBNC6,
|
|
INP_SEL_L_MASK, value << INP_SEL_L_SHIFT);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_S5M3700X_VTS)
|
|
void s5m3700x_vts(struct s5m3700x_priv *s5m3700x, unsigned int type)
|
|
{
|
|
struct snd_soc_component *codec = s5m3700x->codec;
|
|
int chop_val, dac_on, adc_on, mic1_on, mic2_on, mic3_on, mic4_on, hifi_on;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
adc_on = chop_val & (DMIC_ON_MASK | AMIC_ON_MASK);
|
|
mic1_on = chop_val & MIC1_ON_MASK;
|
|
mic2_on = chop_val & MIC2_ON_MASK;
|
|
mic3_on = chop_val & MIC3_ON_MASK;
|
|
mic4_on = chop_val & MIC4_ON_MASK;
|
|
hifi_on = s5m3700x->hifi_on;
|
|
|
|
switch (type) {
|
|
case VTS_OFF:
|
|
dev_info(codec->dev, "%s called. VTS Off.\n", __func__);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x00);
|
|
|
|
/* VTS1 & VTS2 APW OFF */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_VTS1_MASK | APW_VTS2_MASK, 0);
|
|
|
|
/* VTS High-Z Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_2F_DMIC_ST,
|
|
VTS_DATA_ENB_MASK, VTS_DATA_ENB_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
VTS_RESETB_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
VTS_CLK_GATE_MASK, 0);
|
|
|
|
if ((!dac_on) && (!adc_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK, 0);
|
|
|
|
if (!hifi_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
COM_CLK_GATE_MASK, 0);
|
|
}
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_109_CTRL_VTS1,
|
|
CTMI_VTS_INT1_MASK | CTMI_VTS_INT2_MASK,
|
|
CTMI_VTS_2 << CTMI_VTS_INT1_SHIFT |
|
|
CTMI_VTS_2 << CTMI_VTS_INT2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10A_CTRL_VTS2,
|
|
CTMI_VTS_INT3_MASK | CTMI_VTS_INT4_MASK,
|
|
CTMI_VTS_2 << CTMI_VTS_INT3_SHIFT |
|
|
CTMI_VTS_2 << CTMI_VTS_INT4_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11E_CTRL_MIC_I1,
|
|
CTMI_MIC_BST_MASK | CTMI_MIC_INT1_MASK,
|
|
MIC_VAL_0 << CTMI_MIC_BST_SHIFT |
|
|
MIC_VAL_2 << CTMI_MIC_INT1_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10B_CTRL_VTS3,
|
|
CTMF_VTS_LPF_CH1_MASK | CTMF_VTS_LPF_CH2_MASK,
|
|
VTS_LPF_72K << CTMF_VTS_LPF_CH1_SHIFT |
|
|
VTS_LPF_72K << CTMF_VTS_LPF_CH2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
EN_BST1_LPM_MASK | EN_BST2_LPM_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
EN_ISIBLKC_MASK, EN_ISIBLKC_MASK);
|
|
|
|
if ((!mic1_on) && (!mic2_on)) {
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_1 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_1 << CTMR_BSTR2_SHIFT);
|
|
}
|
|
|
|
if ((!mic2_on) && (!mic3_on)) {
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x00);
|
|
}
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST3_MASK, 0);
|
|
|
|
if (!adc_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST_IN_VCM_MASK, 0);
|
|
|
|
/* MCB3 OFF */
|
|
if (!mic3_on) {
|
|
/* MCB3 OFF */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, 0);
|
|
|
|
/* Setting Mic3 Bias Voltage Default Value */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_C9_ACTR_MCB5,
|
|
CTRV_MCB3_MASK, s5m3700x->p_jackdet->mic_bias3_voltage << CTRV_MCB3_SHIFT);
|
|
}
|
|
|
|
if ((!mic1_on) && (!mic2_on) && (!mic3_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST2_MASK, 0);
|
|
|
|
if (!mic4_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_BST1_MASK, 0);
|
|
|
|
break;
|
|
case VTS1_ON:
|
|
dev_info(codec->dev, "%s called. VTS1 On.\n", __func__);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
VTS_CLK_GATE_MASK, VTS_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
VTS_RESETB_MASK, VTS_RESETB_MASK);
|
|
|
|
/* VTS Output Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_2F_DMIC_ST,
|
|
VTS_DATA_ENB_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
EN_BST1_LPM_MASK, EN_BST1_LPM_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_0 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_0 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
EN_ISIBLKC_MASK, EN_ISIBLKC_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_109_CTRL_VTS1,
|
|
CTMI_VTS_INT1_MASK | CTMI_VTS_INT2_MASK,
|
|
CTMI_VTS_2 << CTMI_VTS_INT1_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10A_CTRL_VTS2,
|
|
CTMI_VTS_INT3_MASK | CTMI_VTS_INT4_MASK,
|
|
CTMI_VTS_0 << CTMI_VTS_INT3_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT4_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11E_CTRL_MIC_I1,
|
|
CTMI_MIC_BST_MASK | CTMI_MIC_INT1_MASK,
|
|
MIC_VAL_0 << CTMI_MIC_BST_SHIFT |
|
|
MIC_VAL_2 << CTMI_MIC_INT1_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10B_CTRL_VTS3,
|
|
CTMF_VTS_LPF_CH1_MASK | CTMF_VTS_LPF_CH2_MASK,
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH1_SHIFT |
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH2_SHIFT);
|
|
|
|
/* Setting Mic3 Bias Voltage Default Value */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_C9_ACTR_MCB5,
|
|
CTRV_MCB3_MASK, MICBIAS_VO_1_8V << CTRV_MCB3_SHIFT);
|
|
|
|
/* MCB3 ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, APW_MCB3_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK);
|
|
|
|
/* VTS1 APW ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_VTS1_MASK, APW_VTS1_MASK);
|
|
msleep(60);
|
|
break;
|
|
case VTS2_ON:
|
|
dev_info(codec->dev, "%s called. VTS2 On.\n", __func__);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
VTS_CLK_GATE_MASK, VTS_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
VTS_RESETB_MASK, VTS_RESETB_MASK);
|
|
|
|
/* VTS Output Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_2F_DMIC_ST,
|
|
VTS_DATA_ENB_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
EN_BST2_LPM_MASK, EN_BST2_LPM_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_0 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_0 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
EN_ISIBLKC_MASK, EN_ISIBLKC_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_109_CTRL_VTS1,
|
|
CTMI_VTS_INT1_MASK | CTMI_VTS_INT2_MASK,
|
|
CTMI_VTS_2 << CTMI_VTS_INT1_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10A_CTRL_VTS2,
|
|
CTMI_VTS_INT3_MASK | CTMI_VTS_INT4_MASK,
|
|
CTMI_VTS_0 << CTMI_VTS_INT3_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT4_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11E_CTRL_MIC_I1,
|
|
CTMI_MIC_BST_MASK | CTMI_MIC_INT1_MASK,
|
|
MIC_VAL_0 << CTMI_MIC_BST_SHIFT |
|
|
MIC_VAL_2 << CTMI_MIC_INT1_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10B_CTRL_VTS3,
|
|
CTMF_VTS_LPF_CH1_MASK | CTMF_VTS_LPF_CH2_MASK,
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH1_SHIFT |
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH2_SHIFT);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_BA_ODSEL11, 0x02);
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_122_BST4PN, 0x80);
|
|
|
|
/* Setting Mic3 Bias Voltage Default Value */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_C9_ACTR_MCB5,
|
|
CTRV_MCB3_MASK, MICBIAS_VO_1_8V << CTRV_MCB3_SHIFT);
|
|
|
|
/* MCB3 ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, APW_MCB3_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK);
|
|
|
|
/* VTS2 APW ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_VTS2_MASK, APW_VTS2_MASK);
|
|
msleep(60);
|
|
break;
|
|
case VTS_DUAL:
|
|
dev_info(codec->dev, "%s called. VTS DUAL On.\n", __func__);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
SEQ_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_12_CLKGATE2,
|
|
VTS_CLK_GATE_MASK, VTS_CLK_GATE_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_15_RESETB1,
|
|
VTS_RESETB_MASK, VTS_RESETB_MASK);
|
|
|
|
/* VTS Output Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_2F_DMIC_ST,
|
|
VTS_DATA_ENB_MASK, 0);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
EN_BST1_LPM_MASK | EN_BST2_LPM_MASK,
|
|
EN_BST1_LPM_MASK | EN_BST2_LPM_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_113_BST3,
|
|
CTVOL_BST_MASK, 0x1 << CTVOL_BST_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
CTMR_BSTR1_MASK | CTMR_BSTR2_MASK,
|
|
CTMR_BSTR_3 << CTMR_BSTR1_SHIFT |
|
|
CTMR_BSTR_3 << CTMR_BSTR2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_117_DSM2,
|
|
EN_ISIBLKC_MASK, EN_ISIBLKC_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_109_CTRL_VTS1,
|
|
CTMI_VTS_INT1_MASK | CTMI_VTS_INT2_MASK,
|
|
CTMI_VTS_2 << CTMI_VTS_INT1_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT2_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10A_CTRL_VTS2,
|
|
CTMI_VTS_INT3_MASK | CTMI_VTS_INT4_MASK,
|
|
CTMI_VTS_0 << CTMI_VTS_INT3_SHIFT |
|
|
CTMI_VTS_0 << CTMI_VTS_INT4_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_11E_CTRL_MIC_I1,
|
|
CTMI_MIC_BST_MASK | CTMI_MIC_INT1_MASK,
|
|
MIC_VAL_0 << CTMI_MIC_BST_SHIFT |
|
|
MIC_VAL_2 << CTMI_MIC_INT1_SHIFT);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_10B_CTRL_VTS3,
|
|
CTMF_VTS_LPF_CH1_MASK | CTMF_VTS_LPF_CH2_MASK,
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH1_SHIFT |
|
|
VTS_LPF_12K << CTMF_VTS_LPF_CH2_SHIFT);
|
|
|
|
/* Setting Mic3 Bias Voltage Default Value */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_C9_ACTR_MCB5,
|
|
CTRV_MCB3_MASK, MICBIAS_VO_1_8V << CTRV_MCB3_SHIFT);
|
|
|
|
/* MCB3 ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, APW_MCB3_MASK);
|
|
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_125_RSVD,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK,
|
|
SEL_CLK_LCP_MASK | SEL_BST2_MASK |
|
|
SEL_BST3_MASK | SEL_BST_IN_VCM_MASK);
|
|
|
|
/* VTS1 & VTS2 APW ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_18_PWAUTO_AD,
|
|
APW_VTS1_MASK | APW_VTS2_MASK,
|
|
APW_VTS1_MASK | APW_VTS2_MASK);
|
|
msleep(60);
|
|
break;
|
|
}
|
|
regcache_cache_switch(s5m3700x, true);
|
|
}
|
|
|
|
static int vts_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->vts1_on;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vts_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
switch (value) {
|
|
case VTS_OFF:
|
|
s5m3700x->vts1_on = false;
|
|
s5m3700x->vts2_on = false;
|
|
break;
|
|
case VTS1_ON:
|
|
s5m3700x->vts1_on = true;
|
|
s5m3700x->vts2_on = false;
|
|
break;
|
|
case VTS2_ON:
|
|
s5m3700x->vts1_on = false;
|
|
s5m3700x->vts2_on = true;
|
|
break;
|
|
case VTS_DUAL:
|
|
s5m3700x->vts1_on = true;
|
|
s5m3700x->vts2_on = true;
|
|
break;
|
|
}
|
|
|
|
s5m3700x_vts(s5m3700x, value);
|
|
|
|
dev_info(codec->dev, "%s: VTS: %d\n", __func__, value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void s5m3700x_vts_dmic(struct s5m3700x_priv *s5m3700x, unsigned int type)
|
|
{
|
|
struct snd_soc_component *codec = s5m3700x->codec;
|
|
unsigned int chop_val = 0;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
|
|
switch (type) {
|
|
case VTS_DMIC1_ON:
|
|
if (s5m3700x->vts_dmic_on == VTS_DMIC_OFF) {
|
|
dev_info(codec->dev, "%s called VTS_DMIC1_ON.\n", __func__);
|
|
if (!(chop_val & DMIC1_ON_MASK))
|
|
/* Enable MicBias1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB1_MASK, APW_MCB1_MASK);
|
|
s5m3700x->vts_dmic_on = VTS_DMIC1_ON;
|
|
} else {
|
|
dev_info(codec->dev, "%s prev state should be VTS_DMIC_OFF.\n", __func__);
|
|
}
|
|
break;
|
|
case VTS_DMIC2_ON:
|
|
if (s5m3700x->vts_dmic_on == VTS_DMIC_OFF) {
|
|
dev_info(codec->dev, "%s called VTS_DMIC2_ON.\n", __func__);
|
|
if (!(chop_val & DMIC2_ON_MASK))
|
|
/* Enable MicBias3 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, APW_MCB3_MASK);
|
|
s5m3700x->vts_dmic_on = VTS_DMIC2_ON;
|
|
} else {
|
|
dev_info(codec->dev, "%s prev state should be VTS_DMIC_OFF.\n", __func__);
|
|
}
|
|
break;
|
|
case VTS_DMIC_OFF:
|
|
if (s5m3700x->vts_dmic_on == VTS_DMIC1_ON) {
|
|
dev_info(codec->dev, "%s called VTS_DMIC_OFF. prev %d\n", __func__, s5m3700x->vts_dmic_on);
|
|
if (!(chop_val & DMIC1_ON_MASK))
|
|
/* Disable MicBias1 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB1_MASK, 0);
|
|
s5m3700x->vts_dmic_on = VTS_DMIC_OFF;
|
|
} else if (s5m3700x->vts_dmic_on == VTS_DMIC2_ON) {
|
|
dev_info(codec->dev, "%s called VTS_DMIC_OFF. prev %d\n", __func__, s5m3700x->vts_dmic_on);
|
|
if (!(chop_val & DMIC2_ON_MASK))
|
|
/* Disable MicBias3 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_D0_DCTR_CM,
|
|
APW_MCB3_MASK, 0);
|
|
s5m3700x->vts_dmic_on = VTS_DMIC_OFF;
|
|
}
|
|
break;
|
|
}
|
|
regcache_cache_switch(s5m3700x, true);
|
|
}
|
|
|
|
|
|
static int vts_dmic_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->vts_dmic_on;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vts_dmic_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
if ((value < VTS_DMIC_OFF) || (value > VTS_DMIC2_ON)) {
|
|
dev_err(codec->dev, "%s: unsupported value for dmic vts %d\n", __func__, value);
|
|
return 0;
|
|
}
|
|
|
|
s5m3700x_vts_dmic(s5m3700x, value);
|
|
|
|
dev_info(codec->dev, "%s: DMIC VTS: %d\n", __func__, s5m3700x->vts_dmic_on);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vts1_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1, &mic_boost);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int vts1_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_111_BST1,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vts2_boost_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int mic_boost;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_112_BST2, &mic_boost);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = mic_boost >> CTVOL_BST_SHIFT;
|
|
return 0;
|
|
}
|
|
|
|
static int vts2_boost_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_112_BST2,
|
|
CTVOL_BST_MASK, value << CTVOL_BST_SHIFT);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_S5M3700X_HIFI)
|
|
void s5m3700x_hifi(struct s5m3700x_priv *s5m3700x, int type)
|
|
{
|
|
struct snd_soc_component *codec = s5m3700x->codec;
|
|
int chop_val, dac_on, adc_on, vts_on;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_1E_CHOP1, &chop_val);
|
|
dac_on = chop_val & DAC_ON_MASK;
|
|
adc_on = chop_val & (DMIC_ON_MASK | AMIC_ON_MASK);
|
|
vts_on = (s5m3700x->vts1_on | s5m3700x->vts2_on);
|
|
|
|
switch (type) {
|
|
case HIFI_OFF:
|
|
dev_info(codec->dev, "%s called. HIFI DAC Off.\n", __func__);
|
|
|
|
/* CP1, CP2 CLK Manual Setting OFF */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0,
|
|
SEL_AUTO_CP1_MASK | SEL_AUTO_CP2_MASK,
|
|
SEL_AUTO_CP1_MASK | SEL_AUTO_CP2_MASK);
|
|
|
|
/* CTRL CP1 & CP2 Disable */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_104_CTRL_CP, 0x00);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x7E);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x82);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C7_CP2_TH2_16, 0x79);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C8_CP2_TH3_16, 0x80);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CA_CP2_TH2_06, 0x7E);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CB_CP2_TH2_06, 0x82);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x85);
|
|
|
|
/* RESETB0 */
|
|
if (!dac_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK, 0);
|
|
|
|
if ((!dac_on) && (!adc_on) && (!vts_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
CORE_RESETB_MASK, 0);
|
|
|
|
/* CLKGATE0 */
|
|
if (!dac_on)
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
AVC_CLK_GATE_MASK | DAC_CLK_GATE_MASK, 0);
|
|
|
|
if ((!dac_on) && (!adc_on) && (!vts_on))
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
COM_CLK_GATE_MASK, 0);
|
|
break;
|
|
case HIFI_ON:
|
|
dev_info(codec->dev, "%s called. HIFI DAC On.\n", __func__);
|
|
|
|
/* CLKGATE0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_10_CLKGATE0,
|
|
AVC_CLK_GATE_MASK | DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK,
|
|
AVC_CLK_GATE_MASK | DAC_CLK_GATE_MASK | COM_CLK_GATE_MASK);
|
|
|
|
/* RESETB0 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_14_RESETB0,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK,
|
|
AVC_RESETB_MASK | DAC_RESETB_MASK | CORE_RESETB_MASK);
|
|
|
|
/* Default: 0x99, Don't off it */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5C_AVC13,
|
|
DMUTE_MASKB_MASK, DMUTE_MASKB_MASK);
|
|
|
|
/* CP2 Zero-Cross */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4F_HSYS_CP2_SIGN, 0x05);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C4_CP2_TH2_32, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C5_CP2_TH3_32, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C7_CP2_TH2_16, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2C8_CP2_TH3_16, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CA_CP2_TH2_06, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, S5M3700X_2CB_CP2_TH2_06, 0x00);
|
|
|
|
/* CP1, CP2 CLK Manual Setting ON */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0,
|
|
SEL_AUTO_CP1_MASK | SEL_AUTO_CP2_MASK, 0);
|
|
|
|
/* CTRL CP1 & CP2 Enable */
|
|
s5m3700x_write(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_104_CTRL_CP, 0x2A);
|
|
break;
|
|
}
|
|
|
|
regcache_cache_switch(s5m3700x, true);
|
|
}
|
|
|
|
static int hifi_dac_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->hifi_on;
|
|
return 0;
|
|
}
|
|
|
|
static int hifi_dac_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
switch (value) {
|
|
case HIFI_OFF:
|
|
s5m3700x->hifi_on = false;
|
|
break;
|
|
case HIFI_ON:
|
|
s5m3700x->hifi_on = true;
|
|
break;
|
|
}
|
|
|
|
s5m3700x_hifi(s5m3700x, value);
|
|
|
|
dev_info(codec->dev, "%s: HIFI: %d\n", __func__, value);
|
|
return 0;
|
|
}
|
|
|
|
static int hifi_clk_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int clk_value;
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_read(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0, &clk_value);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
|
|
ucontrol->value.integer.value[0] = clk_value & CTMF_CP_CLK2_MASK;
|
|
return 0;
|
|
}
|
|
|
|
static int hifi_clk_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int clk_value = ucontrol->value.integer.value[0];
|
|
|
|
regcache_cache_switch(s5m3700x, false);
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_153_DA_CP0,
|
|
CTMF_CP_CLK2_MASK, clk_value << CTMF_CP_CLK2_SHIFT);
|
|
regcache_cache_switch(s5m3700x, true);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int codec_enable_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = !(s5m3700x->is_suspend);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int codec_enable_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
if (value)
|
|
s5m3700x_enable(codec->dev);
|
|
else
|
|
s5m3700x_disable(codec->dev);
|
|
|
|
dev_info(codec->dev, "%s: codec enable : %s\n",
|
|
__func__, (value) ? "On" : "Off");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void codec_regdump(struct snd_soc_component *codec)
|
|
{
|
|
u8 reg_d[S5M3700X_REGCACHE_SYNC_END] = {0,};
|
|
u8 reg_a[S5M3700X_REGCACHE_SYNC_END] = {0,};
|
|
u8 reg_o[S5M3700X_REGCACHE_SYNC_END] = {0,};
|
|
u8 reg_p[S5M3700X_REGCACHE_SYNC_END] = {0,};
|
|
u8 p_reg, line, p_line;
|
|
|
|
for (p_reg = 0; p_reg < S5M3700X_REGCACHE_SYNC_END; p_reg++) {
|
|
if (read_from_cache(codec->dev, p_reg, S5M3700D))
|
|
s5m3700x_i2c_read_reg(S5M3700X_DIGITAL_ADDR, p_reg, ®_d[p_reg]);
|
|
|
|
if (read_from_cache(codec->dev, p_reg, S5M3700A))
|
|
s5m3700x_i2c_read_reg(S5M3700X_ANALOG_ADDR, p_reg, ®_a[p_reg]);
|
|
|
|
if (read_from_cache(codec->dev, p_reg, S5M3700O))
|
|
s5m3700x_i2c_read_reg(S5M3700X_OTP_ADDR, p_reg, ®_o[p_reg]);
|
|
|
|
s5m3700x_i2c_read_reg(S5M3700X_MV_ADDR, p_reg, ®_p[p_reg]);
|
|
}
|
|
|
|
dev_info(codec->dev, "========== Codec Digital Block(0x0) Dump ==========\n");
|
|
dev_info(codec->dev, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
|
for (line = 0; line <= 0xf; line++) {
|
|
p_line = line << 4;
|
|
dev_info(codec->dev,
|
|
"%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
p_line, reg_d[p_line + 0], reg_d[p_line + 1], reg_d[p_line + 2],
|
|
reg_d[p_line + 3], reg_d[p_line + 4], reg_d[p_line + 5],
|
|
reg_d[p_line + 6], reg_d[p_line + 7], reg_d[p_line + 8],
|
|
reg_d[p_line + 9], reg_d[p_line + 10], reg_d[p_line + 11],
|
|
reg_d[p_line + 12], reg_d[p_line + 13], reg_d[p_line + 14],
|
|
reg_d[p_line + 15]);
|
|
}
|
|
|
|
dev_info(codec->dev, "========== Codec Analog Block(0x1) Dump ==========\n");
|
|
dev_info(codec->dev, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
|
for (line = 0; line <= 0xf; line++) {
|
|
p_line = line << 4;
|
|
dev_info(codec->dev,
|
|
"%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
p_line, reg_a[p_line + 0], reg_a[p_line + 1], reg_a[p_line + 2],
|
|
reg_a[p_line + 3], reg_a[p_line + 4], reg_a[p_line + 5],
|
|
reg_a[p_line + 6], reg_a[p_line + 7], reg_a[p_line + 8],
|
|
reg_a[p_line + 9], reg_a[p_line + 10], reg_a[p_line + 11],
|
|
reg_a[p_line + 12], reg_a[p_line + 13], reg_a[p_line + 14],
|
|
reg_a[p_line + 15]);
|
|
}
|
|
|
|
dev_info(codec->dev, "========== Codec OTP Block(0x2) Dump ==========\n");
|
|
dev_info(codec->dev, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
|
for (line = 0; line <= 0xf; line++) {
|
|
p_line = line << 4;
|
|
dev_info(codec->dev,
|
|
"%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
p_line, reg_o[p_line + 0], reg_o[p_line + 1], reg_o[p_line + 2],
|
|
reg_o[p_line + 3], reg_o[p_line + 4], reg_o[p_line + 5],
|
|
reg_o[p_line + 6], reg_o[p_line + 7], reg_o[p_line + 8],
|
|
reg_o[p_line + 9], reg_o[p_line + 10], reg_o[p_line + 11],
|
|
reg_o[p_line + 12], reg_o[p_line + 13], reg_o[p_line + 14],
|
|
reg_o[p_line + 15]);
|
|
}
|
|
|
|
dev_info(codec->dev, "========== Codec MV Block(0x3) Dump ==========\n");
|
|
dev_info(codec->dev, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
|
for (line = 0; line <= 0xf; line++) {
|
|
p_line = line << 4;
|
|
dev_info(codec->dev,
|
|
"%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
p_line, reg_p[p_line + 0], reg_p[p_line + 1], reg_p[p_line + 2],
|
|
reg_p[p_line + 3], reg_p[p_line + 4], reg_p[p_line + 5],
|
|
reg_p[p_line + 6], reg_p[p_line + 7], reg_p[p_line + 8],
|
|
reg_p[p_line + 9], reg_p[p_line + 10], reg_p[p_line + 11],
|
|
reg_p[p_line + 12], reg_p[p_line + 13], reg_p[p_line + 14],
|
|
reg_p[p_line + 15]);
|
|
}
|
|
}
|
|
|
|
static int codec_regdump_get(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
ucontrol->value.integer.value[0] = s5m3700x->codec_debug;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int codec_regdump_put(struct snd_kcontrol *kcontrol,
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
{
|
|
struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
int value = ucontrol->value.integer.value[0];
|
|
|
|
if (value) {
|
|
s5m3700x->codec_debug = true;
|
|
codec_regdump(codec);
|
|
} else {
|
|
s5m3700x->codec_debug = false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* struct snd_kcontrol_new s5m3700x_snd_control
|
|
*
|
|
* Every distinct bit-fields within the CODEC SFR range may be considered
|
|
* as a control elements. Such control elements are defined here.
|
|
*
|
|
* Depending on the access mode of these registers, different macros are
|
|
* used to define these control elements.
|
|
*
|
|
* SOC_ENUM: 1-to-1 mapping between bit-field value and provided text
|
|
* SOC_SINGLE: Single register, value is a number
|
|
* SOC_SINGLE_TLV: Single register, value corresponds to a TLV scale
|
|
* SOC_SINGLE_TLV_EXT: Above + custom get/set operation for this value
|
|
* SOC_SINGLE_RANGE_TLV: Register value is an offset from minimum value
|
|
* SOC_DOUBLE: Two bit-fields are updated in a single register
|
|
* SOC_DOUBLE_R: Two bit-fields in 2 different registers are updated
|
|
*/
|
|
|
|
/*
|
|
* All the data goes into s5m3700x_snd_controls.
|
|
* All path inter-connections goes into s5m3700x_dapm_routes
|
|
*/
|
|
static const struct snd_kcontrol_new s5m3700x_snd_controls[] = {
|
|
/*
|
|
* ADC(Tx) path control
|
|
*/
|
|
SOC_SINGLE_TLV("ADC Left Gain", S5M3700X_34_AD_VOLL,
|
|
DVOL_ADC_SHIFT,
|
|
ADC_DVOL_MAXNUM, 1, s5m3700x_dvol_adc_tlv),
|
|
|
|
SOC_SINGLE_TLV("ADC Right Gain", S5M3700X_35_AD_VOLR,
|
|
DVOL_ADC_SHIFT,
|
|
ADC_DVOL_MAXNUM, 1, s5m3700x_dvol_adc_tlv),
|
|
|
|
SOC_SINGLE_TLV("ADC Center Gain", S5M3700X_36_AD_VOLC,
|
|
DVOL_ADC_SHIFT,
|
|
ADC_DVOL_MAXNUM, 1, s5m3700x_dvol_adc_tlv),
|
|
|
|
SOC_SINGLE_EXT("MIC1 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
mic1_boost_get, mic1_boost_put),
|
|
|
|
SOC_SINGLE_EXT("MIC2 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
mic2_boost_get, mic2_boost_put),
|
|
|
|
SOC_SINGLE_EXT("MIC3 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
mic3_boost_get, mic3_boost_put),
|
|
|
|
SOC_SINGLE_EXT("MIC4 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
mic4_boost_get, mic4_boost_put),
|
|
|
|
SOC_SINGLE_TLV("DMIC Gain", S5M3700X_32_ADC3,
|
|
DMIC_GAIN_PRE_SHIFT,
|
|
DMIC_GAIN_15, 0, s5m3700x_dmic_gain_tlv),
|
|
|
|
SOC_SINGLE_TLV("DMIC ST", S5M3700X_2F_DMIC_ST,
|
|
DMIC_ST_SHIFT,
|
|
DMIC_IO_16mA, 0, s5m3700x_dmic_st_tlv),
|
|
|
|
SOC_SINGLE_TLV("SDOUT ST", S5M3700X_2F_DMIC_ST,
|
|
SDOUT_ST_SHIFT,
|
|
SDOUT_IO_16mA, 0, s5m3700x_sdout_st_tlv),
|
|
|
|
SOC_SINGLE_EXT("MIC BIAS1", SND_SOC_NOPM, 0, 1, 0,
|
|
micbias1_get, micbias1_put),
|
|
|
|
SOC_SINGLE_EXT("MIC BIAS2", SND_SOC_NOPM, 0, 1, 0,
|
|
micbias2_get, micbias2_put),
|
|
|
|
SOC_SINGLE_EXT("MIC BIAS3", SND_SOC_NOPM, 0, 1, 0,
|
|
micbias3_get, micbias3_put),
|
|
|
|
SOC_ENUM("ADC DAT Mux0", s5m3700x_adc_dat_enum0),
|
|
|
|
SOC_ENUM("ADC DAT Mux1", s5m3700x_adc_dat_enum1),
|
|
|
|
SOC_ENUM("ADC DAT Mux2", s5m3700x_adc_dat_enum2),
|
|
|
|
SOC_ENUM("ADC DAT Mux3", s5m3700x_adc_dat_enum3),
|
|
|
|
SOC_ENUM("I2S DF", s5m3700x_i2s_df_enum),
|
|
|
|
SOC_ENUM("I2S BCLK POL", s5m3700x_i2s_bck_enum),
|
|
|
|
SOC_ENUM("I2S LRCK POL", s5m3700x_i2s_lrck_enum),
|
|
|
|
SOC_SINGLE_EXT("DMIC delay", SND_SOC_NOPM, 0, 1000, 0,
|
|
dmic_delay_get, dmic_delay_put),
|
|
|
|
SOC_SINGLE_EXT("AMIC delay", SND_SOC_NOPM, 0, 1000, 0,
|
|
amic_delay_get, amic_delay_put),
|
|
|
|
/*
|
|
* HPF Tuning Control
|
|
*/
|
|
SOC_ENUM("HPF Tuning", s5m3700x_hpf_sel_enum),
|
|
|
|
SOC_ENUM("HPF Order", s5m3700x_hpf_order_enum),
|
|
|
|
SOC_ENUM("HPF Left", s5m3700x_hpf_channel_enum_l),
|
|
|
|
SOC_ENUM("HPF Right", s5m3700x_hpf_channel_enum_r),
|
|
|
|
SOC_ENUM("HPF Center", s5m3700x_hpf_channel_enum_c),
|
|
|
|
/*
|
|
* DAC(Rx) path control
|
|
*/
|
|
SOC_DOUBLE_R_TLV("DAC Gain", S5M3700X_41_PLAY_VOLL, S5M3700X_42_PLAY_VOLR,
|
|
DVOL_DA_SHIFT,
|
|
DAC_DVOL_MINNUM, 1, s5m3700x_dvol_dac_tlv),
|
|
|
|
SOC_SINGLE_EXT("HP AVC Gain", SND_SOC_NOPM, 0, 24, 0,
|
|
hp_gain_get, hp_gain_put),
|
|
|
|
SOC_SINGLE_EXT("RCV AVC Gain", SND_SOC_NOPM, 0, 20, 0,
|
|
rcv_gain_get, rcv_gain_put),
|
|
|
|
SOC_ENUM("DAC DAT Mux0", s5m3700x_dac_dat_enum0),
|
|
|
|
SOC_ENUM("DAC DAT Mux1", s5m3700x_dac_dat_enum1),
|
|
|
|
SOC_ENUM("DAC MIXL Mode", s5m3700x_dac_mixl_mode_enum),
|
|
|
|
SOC_ENUM("DAC MIXR Mode", s5m3700x_dac_mixr_mode_enum),
|
|
|
|
SOC_ENUM("LNRCV MIX Mode", s5m3700x_lnrcv_mix_mode_enum),
|
|
|
|
/* Jack control */
|
|
SOC_SINGLE("Jack DBNC In", S5M3700X_D8_DCTR_DBNC1,
|
|
JACK_DBNC_IN_SHIFT, JACK_DBNC_MAX, 0),
|
|
|
|
SOC_SINGLE("Jack DBNC Out", S5M3700X_D8_DCTR_DBNC1,
|
|
JACK_DBNC_OUT_SHIFT, JACK_DBNC_MAX, 0),
|
|
|
|
SOC_SINGLE("Jack DBNC IRQ In", S5M3700X_D9_DCTR_DBNC2,
|
|
JACK_DBNC_INT_IN_SHIFT, JACK_DBNC_INT_MAX, 0),
|
|
|
|
SOC_SINGLE("Jack DBNC IRQ Out", S5M3700X_D9_DCTR_DBNC2,
|
|
JACK_DBNC_INT_OUT_SHIFT, JACK_DBNC_INT_MAX, 0),
|
|
|
|
SOC_SINGLE("MDET Threshold", S5M3700X_C4_ACTR_JD5,
|
|
CTRV_ANT_MDET_SHIFT, 7, 0),
|
|
|
|
SOC_SINGLE("MDET DBNC In", S5M3700X_DB_DCTR_DBNC4,
|
|
ANT_MDET_DBNC_IN_SHIFT, 15, 0),
|
|
|
|
SOC_SINGLE("MDET DBNC Out", S5M3700X_DB_DCTR_DBNC4,
|
|
ANT_MDET_DBNC_OUT_SHIFT, 15, 0),
|
|
|
|
SOC_SINGLE("MDET2 DBNC In", S5M3700X_DC_DCTR_DBNC5,
|
|
ANT_MDET_DBNC_IN_SHIFT, 15, 0),
|
|
|
|
SOC_SINGLE("MDET2 DBNC Out", S5M3700X_DC_DCTR_DBNC5,
|
|
ANT_MDET_DBNC_OUT_SHIFT, 15, 0),
|
|
|
|
SOC_SINGLE("Jack BTN DBNC", S5M3700X_DD_DCTR_DBNC6,
|
|
CTMD_BTN_DBNC_SHIFT, 15, 0),
|
|
|
|
SOC_SINGLE_EXT("Jack Pole Cnt", SND_SOC_NOPM, 0, 5, 0,
|
|
jack_pole_cnt_get, jack_pole_cnt_put),
|
|
|
|
SOC_SINGLE_EXT("Jack Pole Delay", SND_SOC_NOPM, 0, 10, 0,
|
|
jack_pole_delay_get, jack_pole_delay_put),
|
|
|
|
SOC_SINGLE_EXT("Jack Btn Cnt", SND_SOC_NOPM, 0, 5, 0,
|
|
jack_btn_cnt_get, jack_btn_cnt_put),
|
|
|
|
SOC_SINGLE_EXT("Jack Btn Delay", SND_SOC_NOPM, 0, 10, 0,
|
|
jack_btn_delay_get, jack_btn_delay_put),
|
|
|
|
SOC_SINGLE_EXT("ANT MDET1 TRIM", SND_SOC_NOPM, 0, 7, 0,
|
|
ant_mdet1_get, ant_mdet1_put),
|
|
|
|
SOC_SINGLE_EXT("ANT MDET2 TRIM", SND_SOC_NOPM, 0, 7, 0,
|
|
ant_mdet2_get, ant_mdet2_put),
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_S5M3700X_VTS)
|
|
/*
|
|
* VTS Control
|
|
*/
|
|
SOC_SINGLE_EXT("AMIC VTS On", SND_SOC_NOPM, 0, 3, 0,
|
|
vts_get, vts_put),
|
|
|
|
SOC_SINGLE_EXT("DMIC VTS On", SND_SOC_NOPM, 0, 2, 0,
|
|
vts_dmic_get, vts_dmic_put),
|
|
|
|
SOC_SINGLE_EXT("VTS1 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
vts1_boost_get, vts1_boost_put),
|
|
|
|
SOC_SINGLE_EXT("VTS2 Boost Gain", SND_SOC_NOPM, 0, CTVOL_BST_MAXNUM, 0,
|
|
vts2_boost_get, vts2_boost_put),
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_S5M3700X_HIFI)
|
|
/*
|
|
* HIFI DAC Control (CP2 Manual On function)
|
|
*/
|
|
SOC_SINGLE_EXT("HIFI DAC On", SND_SOC_NOPM, 0, 1, 0,
|
|
hifi_dac_get, hifi_dac_put),
|
|
|
|
SOC_SINGLE_EXT("HIFI CP2 CLK", SND_SOC_NOPM, 0, 7, 0,
|
|
hifi_clk_get, hifi_clk_put),
|
|
#endif
|
|
|
|
/*
|
|
* Codec control
|
|
*/
|
|
SOC_SINGLE_EXT("Codec Enable", SND_SOC_NOPM, 0, 1, 0,
|
|
codec_enable_get, codec_enable_put),
|
|
|
|
SOC_SINGLE_EXT("Codec Regdump On", SND_SOC_NOPM, 0, 1, 0,
|
|
codec_regdump_get, codec_regdump_put),
|
|
};
|
|
|
|
/*
|
|
* dapm widget controls set
|
|
*/
|
|
|
|
/* INP SEL */
|
|
static const char * const s5m3700x_inp_sel_src_l[] = {
|
|
"AMIC_L ADC_L", "AMIC_R ADC_L", "AMIC_C ADC_L", "Zero ADC_L",
|
|
"DMIC1L ADC_L", "DMIC1R ADC_L", "DMIC2L ADC_L", "DMIC2R ADC_L"
|
|
};
|
|
static const char * const s5m3700x_inp_sel_src_r[] = {
|
|
"AMIC_R ADC_R", "AMIC_L ADC_R", "AMIC_C ADC_R", "Zero ADC_R",
|
|
"DMIC1L ADC_R", "DMIC1R ADC_R", "DMIC2L ADC_R", "DMIC2R ADC_R"
|
|
};
|
|
static const char * const s5m3700x_inp_sel_src_c[] = {
|
|
"AMIC_C ADC_C", "AMIC_L ADC_C", "AMIC_R ADC_C", "Zero ADC_C",
|
|
"DMIC1L ADC_C", "DMIC1R ADC_C", "DMIC2L ADC_C", "DMIC2R ADC_C"
|
|
};
|
|
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_inp_sel_enum_l, S5M3700X_31_ADC2,
|
|
INP_SEL_L_SHIFT, s5m3700x_inp_sel_src_l);
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_inp_sel_enum_r, S5M3700X_31_ADC2,
|
|
INP_SEL_R_SHIFT, s5m3700x_inp_sel_src_r);
|
|
static SOC_ENUM_SINGLE_DECL(s5m3700x_inp_sel_enum_c, S5M3700X_32_ADC3,
|
|
INP_SEL_C_SHIFT, s5m3700x_inp_sel_src_c);
|
|
|
|
static const struct snd_kcontrol_new s5m3700x_inp_sel_l =
|
|
SOC_DAPM_ENUM("INP_SEL_L", s5m3700x_inp_sel_enum_l);
|
|
static const struct snd_kcontrol_new s5m3700x_inp_sel_r =
|
|
SOC_DAPM_ENUM("INP_SEL_R", s5m3700x_inp_sel_enum_r);
|
|
static const struct snd_kcontrol_new s5m3700x_inp_sel_c =
|
|
SOC_DAPM_ENUM("INP_SEL_C", s5m3700x_inp_sel_enum_c);
|
|
|
|
/* MIC On */
|
|
static const struct snd_kcontrol_new mic1_on[] = {
|
|
SOC_DAPM_SINGLE("MIC1 On", S5M3700X_1E_CHOP1, 0, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new mic2_on[] = {
|
|
SOC_DAPM_SINGLE("MIC2 On", S5M3700X_1E_CHOP1, 1, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new mic3_on[] = {
|
|
SOC_DAPM_SINGLE("MIC3 On", S5M3700X_1E_CHOP1, 2, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new mic4_on[] = {
|
|
SOC_DAPM_SINGLE("MIC4 On", S5M3700X_1E_CHOP1, 3, 1, 0),
|
|
};
|
|
|
|
/* DMIC On */
|
|
static const struct snd_kcontrol_new dmic1_on[] = {
|
|
SOC_DAPM_SINGLE("DMIC1 On", S5M3700X_1E_CHOP1, 4, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new dmic2_on[] = {
|
|
SOC_DAPM_SINGLE("DMIC2 On", S5M3700X_1E_CHOP1, 5, 1, 0),
|
|
};
|
|
|
|
/* Rx Devices */
|
|
static const struct snd_kcontrol_new ep_on[] = {
|
|
SOC_DAPM_SINGLE("EP On", S5M3700X_1E_CHOP1, 6, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new hp_on[] = {
|
|
SOC_DAPM_SINGLE("HP On", S5M3700X_1E_CHOP1, 7, 1, 0),
|
|
};
|
|
static const struct snd_kcontrol_new line_on[] = {
|
|
SOC_DAPM_SINGLE("LN On", S5M3700X_1F_CHOP2, 0, 1, 0),
|
|
};
|
|
static const struct snd_soc_dapm_widget s5m3700x_dapm_widgets[] = {
|
|
/*
|
|
* ADC(Tx) dapm widget
|
|
*/
|
|
SND_SOC_DAPM_INPUT("IN1L"),
|
|
SND_SOC_DAPM_INPUT("IN2L"),
|
|
SND_SOC_DAPM_INPUT("IN3L"),
|
|
SND_SOC_DAPM_INPUT("IN4L"),
|
|
|
|
SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_SUPPLY("DVMID", SND_SOC_NOPM, 0, 0, dvmid_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_PGA_E("MIC1_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, mic1_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_PGA_E("MIC2_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, mic2_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_PGA_E("MIC3_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, mic3_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_PGA_E("MIC4_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, mic4_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_PGA_E("DMIC1_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, dmic1_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_PGA_E("DMIC2_PGA", SND_SOC_NOPM, 0, 0, NULL, 0, dmic2_pga_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_SWITCH("MIC1", SND_SOC_NOPM, 0, 0, mic1_on),
|
|
SND_SOC_DAPM_SWITCH("MIC2", SND_SOC_NOPM, 0, 0, mic2_on),
|
|
SND_SOC_DAPM_SWITCH("MIC3", SND_SOC_NOPM, 0, 0, mic3_on),
|
|
SND_SOC_DAPM_SWITCH("MIC4", SND_SOC_NOPM, 0, 0, mic4_on),
|
|
|
|
SND_SOC_DAPM_SWITCH("DMIC1", SND_SOC_NOPM, 0, 0, dmic1_on),
|
|
SND_SOC_DAPM_SWITCH("DMIC2", SND_SOC_NOPM, 0, 0, dmic2_on),
|
|
|
|
SND_SOC_DAPM_MUX("INP_SEL_L", SND_SOC_NOPM, 0, 0, &s5m3700x_inp_sel_l),
|
|
SND_SOC_DAPM_MUX("INP_SEL_R", SND_SOC_NOPM, 0, 0, &s5m3700x_inp_sel_r),
|
|
SND_SOC_DAPM_MUX("INP_SEL_C", SND_SOC_NOPM, 0, 0, &s5m3700x_inp_sel_c),
|
|
|
|
SND_SOC_DAPM_ADC_E("ADC", "AIF Capture", SND_SOC_NOPM, 0, 0, adc_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_ADC_E("ADC", "AIF2 Capture", SND_SOC_NOPM, 0, 0, adc_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
/*
|
|
* DAC(Rx) dapm widget
|
|
*/
|
|
SND_SOC_DAPM_SWITCH("LINE", SND_SOC_NOPM, 0, 0, line_on),
|
|
SND_SOC_DAPM_SWITCH("EP", SND_SOC_NOPM, 0, 0, ep_on),
|
|
SND_SOC_DAPM_SWITCH("HP", SND_SOC_NOPM, 0, 0, hp_on),
|
|
|
|
SND_SOC_DAPM_OUT_DRV_E("LNDRV", SND_SOC_NOPM, 0, 0, NULL, 0, linedrv_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_OUT_DRV_E("EPDRV", SND_SOC_NOPM, 0, 0, NULL, 0, epdrv_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0, 0, NULL, 0, hpdrv_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_DAC_E("DAC", "AIF Playback", SND_SOC_NOPM, 0, 0, dac_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
SND_SOC_DAPM_DAC_E("DAC", "AIF2 Playback", SND_SOC_NOPM, 0, 0, dac_ev,
|
|
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
|
|
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
|
|
|
|
SND_SOC_DAPM_OUTPUT("LNOUTN"),
|
|
SND_SOC_DAPM_OUTPUT("EPOUTN"),
|
|
SND_SOC_DAPM_OUTPUT("HPOUTLN"),
|
|
};
|
|
|
|
static const struct snd_soc_dapm_route s5m3700x_dapm_routes[] = {
|
|
/*
|
|
* ADC(Tx) dapm route
|
|
*/
|
|
{"MIC1_PGA", NULL, "IN1L"},
|
|
{"MIC1_PGA", NULL, "VMID"},
|
|
{"MIC1", "MIC1 On", "MIC1_PGA"},
|
|
|
|
{"MIC2_PGA", NULL, "IN2L"},
|
|
{"MIC2_PGA", NULL, "VMID"},
|
|
{"MIC2", "MIC2 On", "MIC2_PGA"},
|
|
|
|
{"MIC3_PGA", NULL, "IN3L"},
|
|
{"MIC3_PGA", NULL, "VMID"},
|
|
{"MIC3", "MIC3 On", "MIC3_PGA"},
|
|
|
|
{"MIC4_PGA", NULL, "IN4L"},
|
|
{"MIC4_PGA", NULL, "VMID"},
|
|
{"MIC4", "MIC4 On", "MIC4_PGA"},
|
|
|
|
{"DMIC1_PGA", NULL, "IN1L"},
|
|
{"DMIC1_PGA", NULL, "DVMID"},
|
|
{"DMIC1", "DMIC1 On", "DMIC1_PGA"},
|
|
|
|
{"DMIC2_PGA", NULL, "IN2L"},
|
|
{"DMIC2_PGA", NULL, "DVMID"},
|
|
{"DMIC2", "DMIC2 On", "DMIC2_PGA"},
|
|
|
|
{"INP_SEL_L", "AMIC_L ADC_L", "MIC1"},
|
|
{"INP_SEL_L", "AMIC_C ADC_L", "MIC2"},
|
|
{"INP_SEL_L", "AMIC_R ADC_L", "MIC3"},
|
|
{"INP_SEL_L", "AMIC_R ADC_L", "MIC4"},
|
|
{"INP_SEL_L", "DMIC1L ADC_L", "DMIC1"},
|
|
{"INP_SEL_L", "DMIC1R ADC_L", "DMIC1"},
|
|
{"INP_SEL_L", "DMIC2L ADC_L", "DMIC2"},
|
|
{"INP_SEL_L", "DMIC2R ADC_L", "DMIC2"},
|
|
|
|
{"INP_SEL_R", "AMIC_L ADC_R", "MIC1"},
|
|
{"INP_SEL_R", "AMIC_C ADC_R", "MIC2"},
|
|
{"INP_SEL_R", "AMIC_R ADC_R", "MIC3"},
|
|
{"INP_SEL_R", "AMIC_R ADC_R", "MIC4"},
|
|
{"INP_SEL_R", "DMIC1L ADC_R", "DMIC1"},
|
|
{"INP_SEL_R", "DMIC1R ADC_R", "DMIC1"},
|
|
{"INP_SEL_R", "DMIC2L ADC_R", "DMIC2"},
|
|
{"INP_SEL_R", "DMIC2R ADC_R", "DMIC2"},
|
|
|
|
{"INP_SEL_C", "AMIC_L ADC_C", "MIC1"},
|
|
{"INP_SEL_C", "AMIC_C ADC_C", "MIC2"},
|
|
{"INP_SEL_C", "AMIC_R ADC_C", "MIC3"},
|
|
{"INP_SEL_C", "AMIC_R ADC_C", "MIC4"},
|
|
{"INP_SEL_C", "DMIC1L ADC_C", "DMIC1"},
|
|
{"INP_SEL_C", "DMIC1R ADC_C", "DMIC1"},
|
|
{"INP_SEL_C", "DMIC2L ADC_C", "DMIC2"},
|
|
{"INP_SEL_C", "DMIC2R ADC_C", "DMIC2"},
|
|
|
|
{"ADC", NULL, "INP_SEL_L"},
|
|
{"ADC", NULL, "INP_SEL_R"},
|
|
{"ADC", NULL, "INP_SEL_C"},
|
|
|
|
{"AIF Capture", NULL, "ADC"},
|
|
{"AIF2 Capture", NULL, "ADC"},
|
|
|
|
/*
|
|
* DAC(Rx) dapm route
|
|
*/
|
|
{"DAC", NULL, "AIF Playback"},
|
|
{"DAC", NULL, "AIF2 Playback"},
|
|
|
|
{"LNDRV", NULL, "DAC"},
|
|
{"LINE", "LN On", "LNDRV"},
|
|
{"LNOUTN", NULL, "LINE"},
|
|
|
|
{"EPDRV", NULL, "DAC"},
|
|
{"EP", "EP On", "EPDRV"},
|
|
{"EPOUTN", NULL, "EP"},
|
|
|
|
{"HPDRV", NULL, "DAC"},
|
|
{"HP", "HP On", "HPDRV"},
|
|
{"HPOUTLN", NULL, "HP"},
|
|
};
|
|
|
|
static int s5m3700x_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|
{
|
|
struct snd_soc_component *codec = dai->component;
|
|
|
|
dev_info(codec->dev, "%s called. fmt: %d\n", __func__, fmt);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int s5m3700x_dai_startup(struct snd_pcm_substream *substream,
|
|
struct snd_soc_dai *dai)
|
|
{
|
|
struct snd_soc_component *codec = dai->component;
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(s5m3700x->dev, "(%s) %s completed\n",
|
|
substream->stream ? "C" : "P", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* capture_hw_params() - Register setting for capture
|
|
*
|
|
* @codec: SoC audio codec device
|
|
* @cur_aifrate: current sample rate
|
|
*
|
|
* Desc: Set codec register related sample rate format before capture.
|
|
*/
|
|
static void capture_hw_params(struct snd_soc_component *codec,
|
|
unsigned int cur_aifrate)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(codec->dev, "%s called. priv_aif: %d, cur_aif %d\n",
|
|
__func__, s5m3700x->capture_aifrate, cur_aifrate);
|
|
s5m3700x->capture_on = true;
|
|
s5m3700x_adc_digital_mute(s5m3700x, ADC_MUTE_ALL, true);
|
|
|
|
if (s5m3700x->capture_on) {
|
|
switch (cur_aifrate) {
|
|
case S5M3700X_SAMPLE_RATE_48KHZ:
|
|
/* 48K output format selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR,
|
|
S5M3700X_29_IF_FORM6, ADC_OUT_FORMAT_SEL_MASK, ADC_FM_48K_AT_48K);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_192KHZ:
|
|
/* 192K output format selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR,
|
|
S5M3700X_29_IF_FORM6, ADC_OUT_FORMAT_SEL_MASK, ADC_FM_192K_AT_192K);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_384KHZ:
|
|
/* 192K output format selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR,
|
|
S5M3700X_29_IF_FORM6, ADC_OUT_FORMAT_SEL_MASK, ADC_FM_192K_AT_192K);
|
|
break;
|
|
default:
|
|
dev_err(codec->dev, "%s: sample rate error!\n", __func__);
|
|
/* 48K output format selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR,
|
|
S5M3700X_29_IF_FORM6, ADC_OUT_FORMAT_SEL_MASK, ADC_FM_48K_AT_48K);
|
|
break;
|
|
}
|
|
s5m3700x->capture_aifrate = cur_aifrate;
|
|
}
|
|
if (s5m3700x->codec_debug && s5m3700x->tx_dapm_done && s5m3700x->capture_on)
|
|
codec_regdump(codec);
|
|
}
|
|
|
|
/*
|
|
* playback_hw_params() - Register setting for playback
|
|
*
|
|
* @codec: SoC audio codec device
|
|
* @cur_aifrate: current sample rate
|
|
*
|
|
* Desc: Set codec register related sample rate format before playback.
|
|
*/
|
|
static void playback_hw_params(struct snd_soc_component *codec,
|
|
unsigned int cur_aifrate)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int i = 0;
|
|
|
|
dev_info(codec->dev, "%s called. priv_aif: %d, cur_aif %d\n",
|
|
__func__, s5m3700x->playback_aifrate, cur_aifrate);
|
|
s5m3700x->playback_on = true;
|
|
|
|
if (s5m3700x->playback_on) {
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7A_AVC43, 0x9A);
|
|
|
|
switch (cur_aifrate) {
|
|
case S5M3700X_SAMPLE_RATE_48KHZ:
|
|
/* AVC Var Mode on */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x05);
|
|
|
|
/* AVC Range Default Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_51_AVC2, 0x6A);
|
|
|
|
/* CLK Mode Selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK, 0);
|
|
|
|
/* PlayMode Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x04);
|
|
|
|
/* DAC Gain trim */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_46_PLAY_MIX2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xF7);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x4F);
|
|
/* AVC Delay Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_71_AVC34, 0x18);
|
|
|
|
/* Setting the HP Normal Trim */
|
|
for (i = 0; i < 50; i++)
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, i, s5m3700x->hp_normal_trim[i]);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x2F);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_73_AVC36, 0x17);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0xE9);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_192KHZ:
|
|
/* AVC Var Mode off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x01);
|
|
|
|
/* AVC Range Default Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_51_AVC2, 0x50);
|
|
|
|
/* CLK Mode Selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK, DAC_FSEL_MASK);
|
|
|
|
/* PlayMode Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x44);
|
|
|
|
/* DAC Gain trim */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_46_PLAY_MIX2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xFF);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x1E);
|
|
|
|
/* Setting the HP UHQA Trim */
|
|
for (i = 0; i < 50; i++)
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, i, s5m3700x->hp_uhqa_trim[i]);
|
|
|
|
/* AVC Delay Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_71_AVC34, 0xC6);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x01);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_73_AVC36, 0xC4);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0x39);
|
|
break;
|
|
case S5M3700X_SAMPLE_RATE_384KHZ:
|
|
/* AVC Var Mode off */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x01);
|
|
|
|
/* AVC Range Default Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_51_AVC2, 0x50);
|
|
|
|
/* CLK Mode Selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK | AVC_CLK_SEL_MASK,
|
|
DAC_FSEL_MASK | AVC_CLK_SEL_MASK);
|
|
|
|
/* PlayMode Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x54);
|
|
|
|
/* DAC Gain trim */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_46_PLAY_MIX2, 0x54);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xFD);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x12);
|
|
|
|
/* AVC Delay Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_71_AVC34, 0xC6);
|
|
|
|
/* Setting the HP UHQA Trim */
|
|
for (i = 0; i < 50; i++)
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, i, s5m3700x->hp_uhqa_trim[i]);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x00);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_73_AVC36, 0xC4);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0x3A);
|
|
break;
|
|
default:
|
|
/* CLK Mode Selection */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_16_CLK_MODE_SEL1,
|
|
DAC_FSEL_MASK, 0);
|
|
|
|
/* PlayMode Selection */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x04);
|
|
|
|
/* DAC Gain trim */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_46_PLAY_MIX2, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_47_TRIM_DAC0, 0xF7);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_48_TRIM_DAC1, 0x4F);
|
|
/* AVC Delay Setting */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_71_AVC34, 0x18);
|
|
|
|
/* Setting the HP Normal Trim */
|
|
for (i = 0; i < 50; i++)
|
|
s5m3700x_write(s5m3700x, S5M3700X_OTP_ADDR, i, s5m3700x->hp_normal_trim[i]);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_72_AVC35, 0x2F);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_73_AVC36, 0x17);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_74_AVC37, 0xE9);
|
|
|
|
dev_err(codec->dev, "%s: sample rate error!\n", __func__);
|
|
break;
|
|
}
|
|
s5m3700x->playback_aifrate = cur_aifrate;
|
|
}
|
|
if (s5m3700x->codec_debug && s5m3700x->rx_dapm_done && s5m3700x->playback_on)
|
|
codec_regdump(codec);
|
|
}
|
|
|
|
static int s5m3700x_dai_hw_params(struct snd_pcm_substream *substream,
|
|
struct snd_pcm_hw_params *params,
|
|
struct snd_soc_dai *dai)
|
|
{
|
|
struct snd_soc_component *codec = dai->component;
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
unsigned int cur_aifrate, width, channels;
|
|
|
|
/* Get params */
|
|
cur_aifrate = params_rate(params);
|
|
width = params_width(params);
|
|
channels = params_channels(params);
|
|
|
|
dev_info(codec->dev, "(%s) %s called. aifrate: %d, width: %d, channels: %d\n",
|
|
substream->stream ? "C" : "P", __func__, cur_aifrate, width, channels);
|
|
|
|
switch (width) {
|
|
case BIT_RATE_16:
|
|
/* I2S 16bit Set */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_21_IF_FORM2,
|
|
I2S_DL_MASK, I2S_DL_16);
|
|
|
|
/* I2S Channel Set */
|
|
switch (channels) {
|
|
case CHANNEL_2:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_32);
|
|
break;
|
|
case CHANNEL_4:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_64);
|
|
break;
|
|
default:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_32);
|
|
break;
|
|
}
|
|
break;
|
|
case BIT_RATE_24:
|
|
/* I2S 24bit Set */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_21_IF_FORM2,
|
|
I2S_DL_MASK, I2S_DL_24);
|
|
|
|
/* I2S Channel Set */
|
|
switch (channels) {
|
|
case CHANNEL_2:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_48);
|
|
break;
|
|
case CHANNEL_4:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_96);
|
|
break;
|
|
default:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_48);
|
|
break;
|
|
}
|
|
break;
|
|
case BIT_RATE_32:
|
|
/* I2S 32bit Set */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_21_IF_FORM2,
|
|
I2S_DL_MASK, I2S_DL_32);
|
|
|
|
/* I2S Channel Set */
|
|
switch (channels) {
|
|
case CHANNEL_2:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_64);
|
|
break;
|
|
case CHANNEL_4:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_128);
|
|
break;
|
|
default:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_64);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
dev_err(codec->dev, "%s: bit rate error!\n", __func__);
|
|
/* I2S 16bit Set */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_21_IF_FORM2,
|
|
I2S_DL_MASK, I2S_DL_16);
|
|
|
|
/* I2S Channel Set */
|
|
switch (channels) {
|
|
case CHANNEL_2:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_32);
|
|
break;
|
|
case CHANNEL_4:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_64);
|
|
break;
|
|
default:
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_22_IF_FORM3,
|
|
I2S_XFS_MASK, I2S_XFS_32);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (substream->stream)
|
|
capture_hw_params(codec, cur_aifrate);
|
|
else
|
|
playback_hw_params(codec, cur_aifrate);
|
|
return 0;
|
|
}
|
|
|
|
static void s5m3700x_dai_shutdown(struct snd_pcm_substream *substream,
|
|
struct snd_soc_dai *dai)
|
|
{
|
|
struct snd_soc_component *codec = dai->component;
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(codec->dev, "(%s) %s completed\n",
|
|
substream->stream ? "C" : "P", __func__);
|
|
|
|
if (substream->stream)
|
|
s5m3700x->capture_on = false;
|
|
else
|
|
s5m3700x->playback_on = false;
|
|
}
|
|
|
|
static const struct snd_soc_dai_ops s5m3700x_dai_ops = {
|
|
.set_fmt = s5m3700x_dai_set_fmt,
|
|
.startup = s5m3700x_dai_startup,
|
|
.hw_params = s5m3700x_dai_hw_params,
|
|
.shutdown = s5m3700x_dai_shutdown,
|
|
};
|
|
|
|
#define S5M3700X_RATES SNDRV_PCM_RATE_8000_192000
|
|
#define S5M3700X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
|
SNDRV_PCM_FMTBIT_S20_3LE | \
|
|
SNDRV_PCM_FMTBIT_S24_LE | \
|
|
SNDRV_PCM_FMTBIT_S32_LE)
|
|
|
|
static struct snd_soc_dai_driver s5m3700x_dai[] = {
|
|
{
|
|
.name = "s5m3700x-aif",
|
|
.id = 1,
|
|
.playback = {
|
|
.stream_name = "AIF Playback",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = S5M3700X_RATES,
|
|
.formats = S5M3700X_FORMATS,
|
|
},
|
|
.capture = {
|
|
.stream_name = "AIF Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 8,
|
|
.rates = S5M3700X_RATES,
|
|
.formats = S5M3700X_FORMATS,
|
|
},
|
|
.ops = &s5m3700x_dai_ops,
|
|
.symmetric_rates = 1,
|
|
},
|
|
{
|
|
.name = "s5m3700x-aif2",
|
|
.id = 2,
|
|
.playback = {
|
|
.stream_name = "AIF2 Playback",
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.rates = S5M3700X_RATES,
|
|
.formats = S5M3700X_FORMATS,
|
|
},
|
|
.capture = {
|
|
.stream_name = "AIF2 Capture",
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.rates = S5M3700X_RATES,
|
|
.formats = S5M3700X_FORMATS,
|
|
},
|
|
.ops = &s5m3700x_dai_ops,
|
|
.symmetric_rates = 1,
|
|
},
|
|
};
|
|
|
|
static void s5m3700x_i2c_parse_dt(struct s5m3700x_priv *s5m3700x)
|
|
{
|
|
struct device *dev = s5m3700x->dev;
|
|
struct device_node *np = dev->of_node;
|
|
unsigned int jack_type;
|
|
|
|
/*
|
|
* Setting Jack type
|
|
* 0: 3.5 Pi, 1: USB Type-C
|
|
*/
|
|
if (!of_property_read_u32(dev->of_node, "jack-type", &jack_type))
|
|
s5m3700x->jack_type = jack_type;
|
|
else
|
|
s5m3700x->jack_type = JACK;
|
|
|
|
dev_info(dev, "Jack type: %s\n", s5m3700x->jack_type ? "USB Jack" : "3.5 PI");
|
|
|
|
/* RESETB gpio */
|
|
s5m3700x->resetb_gpio = of_get_named_gpio(np, "s5m3700x-resetb", 0);
|
|
if (s5m3700x->resetb_gpio < 0)
|
|
dev_err(dev, "%s: cannot find resetb gpio in the dt\n", __func__);
|
|
else
|
|
dev_info(dev, "%s: resetb gpio = %d\n",
|
|
__func__, s5m3700x->resetb_gpio);
|
|
|
|
/* external_ldo gpio */
|
|
s5m3700x->external_ldo = of_get_named_gpio(np, "s5m3700x-external-ldo", 0);
|
|
if (s5m3700x->external_ldo < 0)
|
|
dev_err(dev, "%s: cannot find external_ldo gpio in the dt\n", __func__);
|
|
else
|
|
dev_info(dev, "%s: external_ldo gpio = %d\n",
|
|
__func__, s5m3700x->external_ldo);
|
|
|
|
}
|
|
|
|
static void s5m3700x_power_setting(struct s5m3700x_priv *s5m3700x)
|
|
{
|
|
struct device *dev = s5m3700x->dev;
|
|
|
|
/* Setting External LDO gpio */
|
|
if (s5m3700x->external_ldo > 0) {
|
|
if (gpio_request(s5m3700x->external_ldo, "s5m3700x_external_ldo") < 0)
|
|
dev_err(s5m3700x->dev, "%s: Request for %d GPIO failed\n",
|
|
__func__, (int)s5m3700x->external_ldo);
|
|
if (gpio_direction_output(s5m3700x->external_ldo, 1) < 0)
|
|
dev_err(s5m3700x->dev, "%s: GPIO direction to output failed!\n",
|
|
__func__);
|
|
}
|
|
dev_info(dev, "S5M3700X Setting External LDO High.\n");
|
|
|
|
/* HW Delay */
|
|
s5m3700x_usleep(1000);
|
|
|
|
if (!regulator_is_enabled(s5m3700x->vdd)) {
|
|
regulator_enable(s5m3700x->vdd);
|
|
dev_info(dev, "S5M3700X enable vdd regulator.\n");
|
|
}
|
|
|
|
if (!regulator_is_enabled(s5m3700x->vdd2)) {
|
|
regulator_enable(s5m3700x->vdd2);
|
|
dev_info(dev, "S5M3700X enable vdd2 regulator.\n");
|
|
}
|
|
|
|
/* HW Delay */
|
|
s5m3700x_usleep(2000);
|
|
|
|
/* Setting RESETB gpio */
|
|
if (s5m3700x->resetb_gpio > 0) {
|
|
if (gpio_request(s5m3700x->resetb_gpio, "s5m3700x_resetb_gpio") < 0)
|
|
dev_err(s5m3700x->dev, "%s: Request for %d GPIO failed\n",
|
|
__func__, (int)s5m3700x->resetb_gpio);
|
|
if (gpio_direction_output(s5m3700x->resetb_gpio, 1) < 0)
|
|
dev_err(s5m3700x->dev, "%s: GPIO direction to output failed!\n",
|
|
__func__);
|
|
}
|
|
dev_info(dev, "S5M3700X Setting RESETB High.\n");
|
|
}
|
|
|
|
static void s5m3700x_register_initialize(struct s5m3700x_priv *s5m3700x)
|
|
{
|
|
dev_info(s5m3700x->dev, "%s called, setting defaults\n", __func__);
|
|
|
|
/* BGR & IBIAS On */
|
|
s5m3700x_i2c_write_reg(S5M3700X_MV_ADDR, 0x04, 0x03);
|
|
s5m3700x_usleep(5000);
|
|
|
|
/* DLDO On */
|
|
s5m3700x_i2c_write_reg(S5M3700X_MV_ADDR, 0x04, 0x07);
|
|
|
|
/* Audio Codec LV RESETB High */
|
|
s5m3700x_i2c_write_reg(S5M3700X_MV_ADDR, 0x07, 0x42);
|
|
msleep(20);
|
|
|
|
/* Read Codec Chip ID */
|
|
s5m3700x_i2c_read_reg(S5M3700X_MV_ADDR, 0x03, &s5m3700x->codec_ver);
|
|
|
|
#if IS_ENABLED(CONFIG_PM)
|
|
pm_runtime_get_sync(s5m3700x->dev);
|
|
#else
|
|
s5m3700x_enable(s5m3700x->dev);
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_S5M3700X_VTS)
|
|
/* VTS HighZ Setting */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_2F_DMIC_ST,
|
|
VTS_DATA_ENB_MASK, VTS_DATA_ENB_MASK);
|
|
#endif
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_33_ADC4, 0x11);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_38_AD_TRIM1, 0x48);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_39_AD_TRIM2, 0x98);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_40_PLAY_MODE, 0x04);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_50_AVC1, 0x05);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_53_AVC4, 0x80);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_54_AVC5, 0x89);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_58_AVC9, 0x00);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_5C_AVC13, 0x99);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_68_AVC25, 0x08);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_93_DSM_CON1, 0x52);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_9D_AVC_DWA, 0x46);
|
|
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_4B_OFFSET_CTR, 0xFF);
|
|
|
|
/* PD_IDAC4 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_ANALOG_ADDR, S5M3700X_135_PD_IDAC4,
|
|
EN_IDAC1_OUTTIE_MASK|EN_IDAC2_OUTTIE_MASK|EN_OUTTIEL_MASK|EN_OUTTIER_MASK, 0x00);
|
|
/* ODSEL6 */
|
|
s5m3700x_update_bits(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_B5_ODSEL6,
|
|
T_EN_OUTTIEL_MASK|T_EN_OUTTIER_MASK, T_EN_OUTTIEL_MASK|T_EN_OUTTIER_MASK);
|
|
|
|
/* Default Digital Gain */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_41_PLAY_VOLL, 0x54);
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_42_PLAY_VOLR, 0x54);
|
|
|
|
/* RCV gain setting faster to 166usec */
|
|
s5m3700x_write(s5m3700x, S5M3700X_DIGITAL_ADDR, S5M3700X_7E_AVC45, 0x4B);
|
|
|
|
/* ADC/DAC Mute */
|
|
s5m3700x_adc_digital_mute(s5m3700x, ADC_MUTE_ALL, true);
|
|
s5m3700x_dac_soft_mute(s5m3700x, DAC_MUTE_ALL, true);
|
|
|
|
#if IS_ENABLED(CONFIG_PM)
|
|
pm_runtime_put_sync(s5m3700x->dev);
|
|
#else
|
|
s5m3700x_disable(s5m3700x->dev);
|
|
#endif
|
|
}
|
|
|
|
static int s5m3700x_codec_probe(struct snd_soc_component *codec)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
pr_err("Codec Driver Probe: (%s).\n", __func__);
|
|
|
|
s5m3700x->codec = codec;
|
|
|
|
/* register codec power */
|
|
s5m3700x->vdd = devm_regulator_get(s5m3700x->dev, "vdd_hldo");
|
|
if (IS_ERR(s5m3700x->vdd)) {
|
|
dev_warn(s5m3700x->dev, "failed to get regulator vdd\n");
|
|
return PTR_ERR(s5m3700x->vdd);
|
|
}
|
|
|
|
s5m3700x->vdd2 = devm_regulator_get(s5m3700x->dev, "vdd_ldo22s");
|
|
if (IS_ERR(s5m3700x->vdd2)) {
|
|
dev_warn(s5m3700x->dev, "failed to get regulator vdd2\n");
|
|
return PTR_ERR(s5m3700x->vdd2);
|
|
}
|
|
|
|
/* Parsing to dt */
|
|
s5m3700x_i2c_parse_dt(s5m3700x);
|
|
|
|
/* Codec Power GPIO Setting */
|
|
s5m3700x_power_setting(s5m3700x);
|
|
|
|
/* Initialize Codec Register */
|
|
s5m3700x_register_initialize(s5m3700x);
|
|
|
|
/* Ignore suspend status for DAPM endpoint */
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "HPOUTLN");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "EPOUTN");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "LNOUTN");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "IN1L");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "IN2L");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "IN3L");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "IN4L");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "AIF Playback");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "AIF Capture");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "AIF2 Playback");
|
|
snd_soc_dapm_ignore_suspend(snd_soc_component_get_dapm(codec), "AIF2 Capture");
|
|
snd_soc_dapm_sync(snd_soc_component_get_dapm(codec));
|
|
|
|
dev_info(codec->dev, "Codec Probe Done.\n");
|
|
s5m3700x->is_probe_done = true;
|
|
|
|
/* Jack probe */
|
|
if (s5m3700x->jack_type == USB_JACK)
|
|
s5m3700x_usbjack_probe(s5m3700x);
|
|
else
|
|
s5m3700x_jack_probe(s5m3700x);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void s5m3700x_codec_remove(struct snd_soc_component *codec)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = snd_soc_component_get_drvdata(codec);
|
|
|
|
dev_info(s5m3700x->dev, "(*) %s called\n", __func__);
|
|
|
|
destroy_workqueue(s5m3700x->adc_mute_wq);
|
|
|
|
if (s5m3700x->jack_type == USB_JACK)
|
|
s5m3700x_usbjack_remove(codec);
|
|
else
|
|
s5m3700x_jack_remove(codec);
|
|
s5m3700x_regulators_disable(codec);
|
|
}
|
|
|
|
static const struct snd_soc_component_driver soc_codec_dev_s5m3700x = {
|
|
.probe = s5m3700x_codec_probe,
|
|
.remove = s5m3700x_codec_remove,
|
|
.controls = s5m3700x_snd_controls,
|
|
.num_controls = ARRAY_SIZE(s5m3700x_snd_controls),
|
|
.dapm_widgets = s5m3700x_dapm_widgets,
|
|
.num_dapm_widgets = ARRAY_SIZE(s5m3700x_dapm_widgets),
|
|
.dapm_routes = s5m3700x_dapm_routes,
|
|
.num_dapm_routes = ARRAY_SIZE(s5m3700x_dapm_routes),
|
|
.use_pmdown_time = false,
|
|
.idle_bias_on = false,
|
|
};
|
|
|
|
static int s5m3700x_i2c_probe(struct i2c_client *i2c,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x;
|
|
struct device *dev;
|
|
int ret = 0;
|
|
|
|
dev_info(&i2c->dev, "Codec I2C Probe: (%s) name: %s, size: %d, i2c addr: 0x%02x\n",
|
|
__func__, id->name, sizeof(*s5m3700x), (int)i2c->addr);
|
|
|
|
s5m3700x = kzalloc(sizeof(*s5m3700x), GFP_KERNEL);
|
|
if (s5m3700x == NULL)
|
|
return -ENOMEM;
|
|
|
|
i2c->addr = 0x14;
|
|
s5m3700x_stat = s5m3700x;
|
|
s5m3700x->dev = &i2c->dev;
|
|
s5m3700x->is_probe_done = false;
|
|
s5m3700x->regulator_count = 0;
|
|
s5m3700x->regcache_count = 0;
|
|
|
|
/* initialize codec_priv variable */
|
|
s5m3700x->playback_aifrate = 0;
|
|
s5m3700x->capture_aifrate = 0;
|
|
s5m3700x->hp_avc_gain = 0;
|
|
s5m3700x->rcv_avc_gain = 0;
|
|
s5m3700x->playback_on = false;
|
|
s5m3700x->capture_on = false;
|
|
s5m3700x->dmic_delay = 120;
|
|
s5m3700x->amic_delay = 100;
|
|
s5m3700x->vts1_on = false;
|
|
s5m3700x->vts2_on = false;
|
|
s5m3700x->vts_dmic_on = VTS_DMIC_OFF;
|
|
s5m3700x->hifi_on = false;
|
|
s5m3700x->codec_debug = false;
|
|
s5m3700x->tx_dapm_done = false;
|
|
s5m3700x->rx_dapm_done = false;
|
|
s5m3700x->codec_sw_ver = S5M3700X_CODEC_SW_VER;
|
|
s5m3700x->hp_imp = HP_IMP_32;
|
|
s5m3700x->rcv_imp = RCV_IMP_32;
|
|
s5m3700x->hp_bias_cnt = 0;
|
|
s5m3700x->hp_bias_mix_cnt = 0;
|
|
s5m3700x->jack_type = JACK;
|
|
|
|
s5m3700x->i2c_priv[S5M3700D] = i2c;
|
|
s5m3700x->i2c_priv[S5M3700A] = i2c_new_dummy_device(i2c->adapter, S5M3700X_ANALOG_ADDR);
|
|
s5m3700x->i2c_priv[S5M3700O] = i2c_new_dummy_device(i2c->adapter, S5M3700X_OTP_ADDR);
|
|
|
|
i2c_set_clientdata(s5m3700x->i2c_priv[S5M3700D], s5m3700x);
|
|
i2c_set_clientdata(s5m3700x->i2c_priv[S5M3700A], s5m3700x);
|
|
i2c_set_clientdata(s5m3700x->i2c_priv[S5M3700O], s5m3700x);
|
|
|
|
s5m3700x->regmap[S5M3700D] =
|
|
devm_regmap_init(&s5m3700x->i2c_priv[S5M3700D]->dev, &s5m3700x_dbus,
|
|
s5m3700x, &s5m3700x_digital_regmap);
|
|
if (IS_ERR(s5m3700x->regmap[S5M3700D])) {
|
|
dev_err(&i2c->dev, "Failed to allocate digital regmap: %li\n",
|
|
PTR_ERR(s5m3700x->regmap[S5M3700D]));
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
s5m3700x->regmap[S5M3700A] =
|
|
devm_regmap_init(&s5m3700x->i2c_priv[S5M3700A]->dev, &s5m3700x_abus,
|
|
s5m3700x, &s5m3700x_analog_regmap);
|
|
if (IS_ERR(s5m3700x->regmap[S5M3700A])) {
|
|
dev_err(&i2c->dev, "Failed to allocate analog regmap: %li\n",
|
|
PTR_ERR(s5m3700x->regmap[S5M3700A]));
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
s5m3700x->regmap[S5M3700O] =
|
|
devm_regmap_init(&s5m3700x->i2c_priv[S5M3700O]->dev, &s5m3700x_obus,
|
|
s5m3700x, &s5m3700x_otp_regmap);
|
|
if (IS_ERR(s5m3700x->regmap[S5M3700O])) {
|
|
dev_err(&i2c->dev, "Failed to allocate otp regmap: %li\n",
|
|
PTR_ERR(s5m3700x->regmap[S5M3700O]));
|
|
ret = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
dev = &s5m3700x->i2c_priv[S5M3700D]->dev;
|
|
|
|
/* initialize workqueue */
|
|
INIT_DELAYED_WORK(&s5m3700x->adc_mute_work, s5m3700x_adc_mute_work);
|
|
s5m3700x->adc_mute_wq = create_singlethread_workqueue("adc_mute_wq");
|
|
if (s5m3700x->adc_mute_wq == NULL) {
|
|
dev_err(s5m3700x->dev, "Failed to create adc_mute_wq\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* initialize mutex lock */
|
|
mutex_init(&s5m3700x->i2c_mutex);
|
|
mutex_init(&s5m3700x->regcache_lock);
|
|
mutex_init(&s5m3700x->adc_mute_lock);
|
|
mutex_init(&s5m3700x->dacl_mute_lock);
|
|
mutex_init(&s5m3700x->dacr_mute_lock);
|
|
|
|
ret = snd_soc_register_component(dev, &soc_codec_dev_s5m3700x,
|
|
s5m3700x_dai, ARRAY_SIZE(s5m3700x_dai));
|
|
if (ret < 0) {
|
|
dev_err(&i2c->dev, "Failed to register digital codec: %d\n", ret);
|
|
goto err;
|
|
}
|
|
#if IS_ENABLED(CONFIG_PM)
|
|
pm_runtime_enable(s5m3700x->dev);
|
|
#endif
|
|
return ret;
|
|
err:
|
|
kfree(s5m3700x);
|
|
return ret;
|
|
}
|
|
|
|
static int s5m3700x_i2c_remove(struct i2c_client *i2c)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(&i2c->dev);
|
|
|
|
dev_info(s5m3700x->dev, "(*) %s called\n", __func__);
|
|
|
|
snd_soc_unregister_component(&i2c->dev);
|
|
kfree(s5m3700x);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int s5m3700x_enable(struct device *dev)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(dev);
|
|
int p_map;
|
|
|
|
dev_info(dev, "(*) %s. Codec Rev: 0.%d, Ver: %d.\n",
|
|
__func__, s5m3700x->codec_ver, s5m3700x->codec_sw_ver);
|
|
s5m3700x->is_suspend = false;
|
|
s5m3700x->regcache_count++;
|
|
|
|
s5m3700x_regulators_enable(s5m3700x->codec);
|
|
|
|
if (s5m3700x->regcache_count == 1) {
|
|
/* Disable cache_only feature and sync the cache with h/w */
|
|
for (p_map = S5M3700D; p_map <= S5M3700O; p_map++)
|
|
regcache_cache_only(s5m3700x->regmap[p_map], false);
|
|
}
|
|
|
|
s5m3700x_reg_restore(s5m3700x->codec);
|
|
return 0;
|
|
}
|
|
|
|
int s5m3700x_disable(struct device *dev)
|
|
{
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(dev);
|
|
int p_map;
|
|
|
|
dev_info(dev, "(*) %s\n", __func__);
|
|
|
|
s5m3700x->is_suspend = true;
|
|
s5m3700x->regcache_count--;
|
|
|
|
if (s5m3700x->regcache_count == 0) {
|
|
/* As device is going to suspend-state, limit the writes to cache */
|
|
for (p_map = S5M3700D; p_map <= S5M3700O; p_map++)
|
|
regcache_cache_only(s5m3700x->regmap[p_map], true);
|
|
}
|
|
|
|
s5m3700x_regulators_disable(s5m3700x->codec);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int s5m3700x_sys_resume(struct device *dev)
|
|
{
|
|
#if !IS_ENABLED(CONFIG_PM)
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(dev);
|
|
|
|
if (!s5m3700x->is_suspend) {
|
|
dev_info(dev, "(*)s5m3700x not resuming, cp functioning\n");
|
|
return 0;
|
|
}
|
|
dev_info(dev, "(*) %s\n", __func__);
|
|
s5m3700x->pm_suspend = false;
|
|
s5m3700x_enable(dev);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int s5m3700x_sys_suspend(struct device *dev)
|
|
{
|
|
#if !IS_ENABLED(CONFIG_PM)
|
|
struct s5m3700x_priv *s5m3700x = dev_get_drvdata(dev);
|
|
|
|
if (abox_is_on()) {
|
|
dev_info(dev, "(*)Don't suspend s5m3700x, cp functioning\n");
|
|
return 0;
|
|
}
|
|
dev_info(dev, "(*) %s\n", __func__);
|
|
s5m3700x->pm_suspend = true;
|
|
s5m3700x_disable(dev);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_PM)
|
|
static int s5m3700x_runtime_resume(struct device *dev)
|
|
{
|
|
dev_info(dev, "(*) %s\n", __func__);
|
|
s5m3700x_enable(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int s5m3700x_runtime_suspend(struct device *dev)
|
|
{
|
|
dev_info(dev, "(*) %s\n", __func__);
|
|
s5m3700x_disable(dev);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const struct dev_pm_ops s5m3700x_pm = {
|
|
SET_SYSTEM_SLEEP_PM_OPS(
|
|
s5m3700x_sys_suspend,
|
|
s5m3700x_sys_resume)
|
|
#if IS_ENABLED(CONFIG_PM)
|
|
SET_RUNTIME_PM_OPS(
|
|
s5m3700x_runtime_suspend,
|
|
s5m3700x_runtime_resume,
|
|
NULL)
|
|
#endif
|
|
};
|
|
|
|
static const struct i2c_device_id s5m3700x_i2c_id[] = {
|
|
{ "s5m3700x", 0 },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, s5m3700x_i2c_id);
|
|
|
|
const struct of_device_id s5m3700x_of_match[] = {
|
|
{ .compatible = "samsung,s5m3700x", },
|
|
{ },
|
|
};
|
|
|
|
static struct i2c_driver s5m3700x_i2c_driver = {
|
|
.driver = {
|
|
.name = "s5m3700x",
|
|
.owner = THIS_MODULE,
|
|
.pm = &s5m3700x_pm,
|
|
.of_match_table = of_match_ptr(s5m3700x_of_match),
|
|
},
|
|
.probe = s5m3700x_i2c_probe,
|
|
.remove = s5m3700x_i2c_remove,
|
|
.id_table = s5m3700x_i2c_id,
|
|
};
|
|
|
|
module_i2c_driver(s5m3700x_i2c_driver);
|
|
|
|
MODULE_SOFTDEP("pre: snd-soc-samsung-vts");
|
|
MODULE_DESCRIPTION("ASoC S5M3700X driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_ALIAS("platform:S5M3700X-codec");
|