kernel_samsung_a34x-permissive/sound/soc/codecs/aw8896.c
2024-04-28 15:51:13 +02:00

1978 lines
48 KiB
C

/*
* aw8896.c aw8896 codec module
*
* Version: v1.0.16
*
* Copyright (c) 2017 AWINIC Technology CO., LTD
*
* Author: Nick Li <liweilei@awinic.com.cn>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#define DEBUG
#include <linux/module.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/debugfs.h>
#include <linux/version.h>
#include <linux/input.h>
#include <sound/tlv.h>
#include <linux/version.h>
#include <sound/control.h>
#include "aw8896.h"
#include "aw8896_reg.h"
/******************************************************
*
* Marco
*
******************************************************/
#define AW8896_I2C_NAME "aw889x_smartpa"
#define AW8896_VERSION "v1.0.16"
#define AW8896_RATES SNDRV_PCM_RATE_8000_48000
#define AW8896_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define AWINIC_I2C_REGMAP
#define AW_I2C_RETRIES 5
#define AW_I2C_RETRY_DELAY 5 /* 5ms */
#define AW_READ_CHIPID_RETRIES 5
#define AW_READ_CHIPID_RETRY_DELAY_US 5000
#define AW8896_MAX_DSP_START_TRY_COUNT 20
static int aw8896_spk_control;
static int aw8896_rcv_control;
#define AW8896_FW_NAME_MAX 64
#define AW8896_MAX_FIRMWARE_LOAD_CNT 20
static char *aw8896_reg_name = "aw8896_reg.bin";
static char *aw8896_fw_name = "aw8896_fw_e.bin";
/******************************************************
*
* aw882xx distinguish between codecs and components by version
*
******************************************************/
#ifdef AW_KERNEL_VER_OVER_4_19_1
static const struct aw_componet_codec_ops aw_componet_codec_ops = {
.aw_snd_soc_kcontrol_codec = snd_soc_kcontrol_component,
.aw_snd_soc_codec_get_drvdata = snd_soc_component_get_drvdata,
.aw_snd_soc_add_codec_controls = snd_soc_add_component_controls,
.aw_snd_soc_unregister_codec = snd_soc_unregister_component,
.aw_snd_soc_register_codec = snd_soc_register_component,
};
#else
static const struct aw_componet_codec_ops aw_componet_codec_ops = {
.aw_snd_soc_kcontrol_codec = snd_soc_kcontrol_codec,
.aw_snd_soc_codec_get_drvdata = snd_soc_codec_get_drvdata,
.aw_snd_soc_add_codec_controls = snd_soc_add_codec_controls,
.aw_snd_soc_unregister_codec = snd_soc_unregister_codec,
.aw_snd_soc_register_codec = snd_soc_register_codec,
};
#endif
static aw_snd_soc_codec_t *aw_get_codec(struct snd_soc_dai *dai)
{
#ifdef AW_KERNEL_VER_OVER_4_19_1
return dai->component;
#else
return dai->codec;
#endif
}
static unsigned char aw8896_dsp_fw_data[AW8896_DSP_FW_SIZE] = {0};
static int aw8896_i2c_write(struct aw8896 *aw8896,
unsigned char reg_addr, unsigned int reg_data);
static int aw8896_i2c_read(struct aw8896 *aw8896,
unsigned char reg_addr, unsigned int *reg_data);
static void aw8896_interrupt_setup(struct aw8896 *aw8896);
static void aw8896_interrupt_clear(struct aw8896 *aw8896);
/******************************************************
*
* aw8896 i2c write/read
*
******************************************************/
#ifndef AWINIC_I2C_REGMAP
static int i2c_write(struct aw8896 *aw8896,
unsigned char addr, unsigned int reg_data)
{
int ret;
u8 wbuf[512] = {0};
struct i2c_msg msgs[] = {
{
.addr = aw8896->i2c->addr,
.flags = 0,
.len = 3,
.buf = wbuf,
},
};
wbuf[0] = addr;
wbuf[1] = (unsigned char)((reg_data & 0xff00)>>8);
wbuf[2] = (unsigned char)(reg_data & 0x00ff);
ret = i2c_transfer(aw8896->i2c->adapter, msgs, 1);
if (ret < 0)
pr_err("%s: i2c write error: %d\n", __func__, ret);
return ret;
}
static int i2c_read(struct aw8896 *aw8896,
unsigned char addr, unsigned int *reg_data)
{
int ret;
unsigned char rbuf[512] = {0};
unsigned int get_data;
struct i2c_msg msgs[] = {
{
.addr = aw8896->i2c->addr,
.flags = 0,
.len = 1,
.buf = &addr,
},
{
.addr = aw8896->i2c->addr,
.flags = I2C_M_RD,
.len = 2,
.buf = rbuf,
},
};
ret = i2c_transfer(aw8896->i2c->adapter, msgs, 2);
if (ret < 0) {
pr_err("%s: i2c read error: %d\n", __func__, ret);
return ret;
}
get_data = (unsigned int)(rbuf[0] & 0x00ff);
get_data <<= 8;
get_data |= (unsigned int)rbuf[1];
*reg_data = get_data;
return ret;
}
#endif
static int aw8896_i2c_write(struct aw8896 *aw8896,
unsigned char reg_addr, unsigned int reg_data)
{
int ret = -1;
unsigned char cnt = 0;
while (cnt < AW_I2C_RETRIES) {
#ifdef AWINIC_I2C_REGMAP
ret = regmap_write(aw8896->regmap, reg_addr, reg_data);
if (ret < 0) {
pr_err("%s: regmap_write cnt=%d error=%d\n",
__func__, cnt, ret);
} else {
break;
}
#else
ret = i2c_write(aw8896, reg_addr, reg_data);
if (ret < 0) {
pr_err("%s: i2c_write cnt=%d error=%d\n",
__func__, cnt, ret);
} else {
break;
}
#endif
cnt++;
}
return ret;
}
static int aw8896_i2c_read(struct aw8896 *aw8896,
unsigned char reg_addr, unsigned int *reg_data)
{
int ret = -1;
unsigned char cnt = 0;
while (cnt < AW_I2C_RETRIES) {
#ifdef AWINIC_I2C_REGMAP
ret = regmap_read(aw8896->regmap, reg_addr, reg_data);
if (ret < 0) {
pr_err("%s: regmap_read cnt=%d error=%d\n",
__func__, cnt, ret);
} else {
break;
}
#else
ret = i2c_read(aw8896, reg_addr, reg_data);
if (ret < 0) {
pr_err("%s: i2c_read cnt=%d error=%d\n",
__func__, cnt, ret);
} else {
break;
}
#endif
cnt++;
}
return ret;
}
static int aw8896_i2c_writes(struct aw8896 *aw8896,
unsigned char reg_addr,
unsigned char *buf,
unsigned int len)
{
int ret = -1;
unsigned char *data;
data = kmalloc(len+1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data[0] = reg_addr;
memcpy(&data[1], buf, len);
ret = i2c_master_send(aw8896->i2c, data, len+1);
if (ret < 0)
pr_err("%s: i2c send error\n", __func__);
kfree(data);
return ret;
}
/******************************************************
*
* aw8896 control
*
******************************************************/
static bool aw8896_is_hmute(struct aw8896 *aw8896)
{
unsigned int reg_val = 0;
aw8896_i2c_read(aw8896, AW8896_REG_PWMCTRL, &reg_val);
return (reg_val & (AW8896_BIT_PWMCTRL_HMUTE)) ? true : false;
}
static void aw8896_run_mute(struct aw8896 *aw8896, bool mute)
{
unsigned int reg_val = 0;
unsigned int status_reg_val = 0;
pr_debug("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_PWMCTRL, &reg_val);
if (mute)
reg_val |= AW8896_BIT_PWMCTRL_HMUTE;
else
reg_val &= (~AW8896_BIT_PWMCTRL_HMUTE);
aw8896_i2c_write(aw8896, AW8896_REG_PWMCTRL, reg_val);
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &status_reg_val);
pr_debug("%s System Status Register[%x] = 0x%x\n",
__func__, AW8896_REG_SYSST, status_reg_val);
}
static void aw8896_run_pwd(struct aw8896 *aw8896, bool pwd)
{
unsigned int reg_val = 0;
pr_debug("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
if (pwd)
reg_val |= AW8896_BIT_SYSCTRL_PWDN;
else
reg_val &= (~AW8896_BIT_SYSCTRL_PWDN);
aw8896_i2c_write(aw8896, AW8896_REG_SYSCTRL, reg_val);
}
static void aw8896_run_amp_off(struct aw8896 *aw8896, bool apm_off)
{
unsigned int reg_val = 0;
pr_debug("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
if (apm_off)
reg_val |= AW8896_BIT_SYSCTRL_BSTPD;
else
reg_val &= (~AW8896_BIT_SYSCTRL_BSTPD);
aw8896_i2c_write(aw8896, AW8896_REG_SYSCTRL, reg_val);
}
static void aw8896_dsp_enable(struct aw8896 *aw8896, bool dsp)
{
unsigned int reg_val = 0;
pr_debug("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
if (dsp)
reg_val &= (~AW8896_BIT_SYSCTRL_DSPBY);
else
reg_val |= AW8896_BIT_SYSCTRL_DSPBY;
aw8896_i2c_write(aw8896, AW8896_REG_SYSCTRL, reg_val);
}
static int aw8896_get_iis_status(struct aw8896 *aw8896)
{
int ret = -1;
unsigned int reg_val = 0;
pr_debug("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &reg_val);
if (reg_val & AW8896_BIT_SYSST_PLLS)
ret = 0;
return ret;
}
static int aw8896_get_dsp_status(struct aw8896 *aw8896)
{
int ret = -1;
int retry = 50;
unsigned int reg_val = 0;
pr_debug("%s enter\n", __func__);
while (retry-- > 0) {
aw8896_i2c_read(aw8896, AW8896_REG_WDT, &reg_val);
if (reg_val)
return 0;
usleep_range(1000, 2000);
}
return ret;
}
static void aw8896_spk_rcv_mode(struct aw8896 *aw8896)
{
unsigned int reg_val = 0;
pr_debug("%s spk_rcv=%d\n", __func__, aw8896->spk_rcv_mode);
if (aw8896->spk_rcv_mode == AW8896_SPEAKER_MODE) {
/* RFB IDAC = 6V */
aw8896_i2c_read(aw8896, AW8896_REG_AMPDBG1, &reg_val);
reg_val |= AW8896_BIT_AMPDBG1_OPD;
reg_val &= (~AW8896_BIT_AMPDBG1_IPWM_20UA);
reg_val &= (~AW8896_BIT_AMPDBG1_RFB_MASK);
reg_val |= 0x0002;
aw8896_i2c_write(aw8896, AW8896_REG_AMPDBG1, reg_val);
/* Speaker Mode */
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
reg_val &= (~AW8896_BIT_SYSCTRL_RCV_MODE);
aw8896_i2c_write(aw8896, AW8896_REG_SYSCTRL, reg_val);
} else if (aw8896->spk_rcv_mode == AW8896_RECEIVER_MODE) {
/* RFB IDAC = 4V */
aw8896_i2c_read(aw8896, AW8896_REG_AMPDBG1, &reg_val);
reg_val |= AW8896_BIT_AMPDBG1_OPD;
reg_val |= (AW8896_BIT_AMPDBG1_IPWM_20UA);
reg_val &= (~AW8896_BIT_AMPDBG1_RFB_MASK);
reg_val |= 0x000B;
aw8896_i2c_write(aw8896, AW8896_REG_AMPDBG1, reg_val);
/* Receiver Mode */
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
reg_val |= AW8896_BIT_SYSCTRL_RCV_MODE;
aw8896_i2c_write(aw8896, AW8896_REG_SYSCTRL, reg_val);
} else {
}
}
static int aw8896_get_sysint(struct aw8896 *aw8896, uint16_t *sysint)
{
int ret = -1;
unsigned int reg_val = 0;
ret = aw8896_i2c_read(aw8896, AW8896_REG_SYSINT, &reg_val);
if (ret < 0)
pr_info("%s: read sysint fail, ret=%d\n",
__func__, ret);
else
*sysint = reg_val;
return ret;
}
static int aw8896_set_intmask(struct aw8896 *aw8896, bool flag)
{
if (flag)
aw8896_interrupt_setup(aw8896);
else
aw8896_i2c_write(aw8896, AW8896_REG_SYSINTM,
AW8896_BIT_SYSINTM_MASK);
return 0;
}
static void aw8896_start(struct aw8896 *aw8896)
{
int ret = -1;
uint16_t sysint = 0;
int i;
pr_debug("%s enter\n", __func__);
aw8896_run_pwd(aw8896, false);
for (i = 0; i < AW8896_MAX_DSP_START_TRY_COUNT; i++) {
ret = aw8896_get_iis_status(aw8896);
if (ret < 0) {
pr_err("%s: get no iis signal, ret=%d\n",
__func__, ret);
usleep_range(2000, 2000 + 20);
if (i == AW8896_MAX_DSP_START_TRY_COUNT - 1)
break;
} else {
aw8896_dsp_enable(aw8896, true);
break;
}
}
aw8896_run_mute(aw8896, false);
ret = aw8896_get_sysint(aw8896, &sysint);
if (ret < 0)
pr_err("%s: get_sysint fail, ret=%d\n",
__func__, ret);
else
pr_info("%s: get_sysint=0x%04x\n",
__func__, sysint);
ret = aw8896_get_sysint(aw8896, &sysint);
if (ret < 0)
pr_err("%s: get_sysint fail, ret=%d\n",
__func__, ret);
else
pr_info("%s: get_sysint=0x%04x\n",
__func__, sysint);
aw8896_set_intmask(aw8896, true);
}
static void aw8896_stop(struct aw8896 *aw8896)
{
int ret = -1;
uint16_t sysint = 0;
pr_info("%s enter\n", __func__);
aw8896_run_mute(aw8896, true);
aw8896_set_intmask(aw8896, false);
ret = aw8896_get_sysint(aw8896, &sysint);
if (ret < 0)
pr_err("%s: get_sysint fail, ret=%d\n",
__func__, ret);
else
pr_info("%s: get_sysint=0x%04x\n",
__func__, sysint);
aw8896_dsp_enable(aw8896, false);
usleep_range(1000, 2000);
aw8896_run_pwd(aw8896, true);
}
static void aw8896_dsp_container_update(struct aw8896 *aw8896,
struct aw8896_container *aw8896_cont,
int base)
{
int i = 0;
#ifdef AWINIC_DSP_I2C_WRITES
unsigned char tmp_val = 0;
unsigned int tmp_len = 0;
#else
int tmp_val = 0;
int addr = 0;
#endif
pr_debug("%s enter\n", __func__);
#ifdef AWINIC_DSP_I2C_WRITES
/* i2c writes */
aw8896_i2c_write(aw8896, AW8896_REG_DSPMADD, base);
for (i = 0; i < aw8896_cont->len; i += 2) {
tmp_val = aw8896_cont->data[i+0];
aw8896_cont->data[i+0] = aw8896_cont->data[i+1];
aw8896_cont->data[i+1] = tmp_val;
}
for (i = 0; i < aw8896_cont->len; i += MAX_RAM_WRITE_BYTE_SIZE) {
if ((aw8896_cont->len - i) < MAX_RAM_WRITE_BYTE_SIZE)
tmp_len = aw8896_cont->len - i;
else
tmp_len = MAX_RAM_WRITE_BYTE_SIZE;
aw8896_i2c_writes(aw8896, AW8896_REG_DSPMDAT,
&aw8896_cont->data[i], tmp_len);
}
#else
/* i2c write */
for (i = 0; i < aw8896_cont->len; i += 2) {
tmp_val = (aw8896_cont->data[i+1]<<8) + aw8896_cont->data[i+0];
aw8896_i2c_write(aw8896, AW8896_REG_DSPMADD, base+addr);
aw8896_i2c_write(aw8896, AW8896_REG_DSPMDAT, tmp_val);
addr++;
}
#endif
pr_debug("%s exit\n", __func__);
}
static int aw8896_fw_loaded(const struct firmware *cont, struct aw8896 *aw8896)
{
struct aw8896_container *aw8896_fw;
/* int i; */
int ret = -1;
pr_debug("%s enter\n", __func__);
aw8896->dsp_fw_state = AW8896_DSP_FW_FAIL;
if (!cont) {
pr_err("%s: failed to read %s\n", __func__, aw8896_fw_name);
release_firmware(cont);
return -EINVAL;
}
pr_info("%s: loaded %s - size: %zu\n", __func__, aw8896_fw_name,
cont ? cont->size : 0);
if (cont->size > AW8896_DSP_FW_SIZE) {
pr_err("%s: Errof:Size exceeds the limit of 512\n", __func__);
release_firmware(cont);
return -ENOMEM;
}
aw8896_fw = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
if (!aw8896_fw) {
release_firmware(cont);
pr_err("%s: Error allocating memory\n", __func__);
return -ENOMEM;
}
aw8896_fw->len = cont->size;
memcpy(aw8896_fw->data, cont->data, cont->size);
aw8896_dsp_container_update(aw8896, aw8896_fw,
AW8896_DSP_FW_BASE);
memcpy(aw8896_fw->data, cont->data, cont->size);
aw8896_dsp_container_update(aw8896, aw8896_fw,
AW8896_DSP_FW_BACKUP_BASE);
memcpy(aw8896_dsp_fw_data, cont->data, cont->size);
release_firmware(cont);
aw8896->dsp_fw_len = aw8896_fw->len;
kfree(aw8896_fw);
pr_info("%s: fw update complete\n", __func__);
aw8896_dsp_enable(aw8896, true);
usleep_range(1000, 2000);
ret = aw8896_get_dsp_status(aw8896);
if (ret) {
aw8896->init = 0;
aw8896_dsp_enable(aw8896, false);
aw8896_run_mute(aw8896, true);
pr_info("%s: dsp working wdt, dsp fw update failed\n",
__func__);
} else {
if (aw8896->call_in_kctl == 0) {
aw8896_spk_rcv_mode(aw8896);
aw8896_start(aw8896);
}
if (!(aw8896->flags & AW8896_FLAG_SKIP_INTERRUPTS)) {
aw8896_interrupt_clear(aw8896);
aw8896_interrupt_setup(aw8896);
}
aw8896->init = 1;
aw8896->dsp_fw_state = AW8896_DSP_FW_OK;
pr_info("%s: init ok\n", __func__);
}
return 0;
}
static int aw8896_load_fw(struct aw8896 *aw8896)
{
const struct firmware *cont = NULL;
int ret;
pr_info("%s enter\n", __func__);
if (aw8896->dsp_fw_state == AW8896_DSP_FW_OK) {
pr_info("%s: dsp fw ok\n", __func__);
return 0;
}
aw8896->dsp_fw_state = AW8896_DSP_FW_PENDING;
aw8896_run_mute(aw8896, true);
aw8896_dsp_enable(aw8896, false);
ret = request_firmware(&cont, aw8896_fw_name, aw8896->dev);
if (ret < 0) {
pr_err("%s: failed to read %s\n", __func__, aw8896_fw_name);
release_firmware(cont);
return ret;
}
return aw8896_fw_loaded(cont, aw8896);
}
static void aw8896_reg_container_update(struct aw8896 *aw8896,
struct aw8896_container *aw8896_cont)
{
int i = 0;
int reg_addr = 0;
int reg_val = 0;
pr_debug("%s enter\n", __func__);
for (i = 0; i < aw8896_cont->len; i += 4) {
reg_addr = (aw8896_cont->data[i+1]<<8) + aw8896_cont->data[i+0];
reg_val = (aw8896_cont->data[i+3]<<8) + aw8896_cont->data[i+2];
pr_debug("%s: reg=0x%04x, val = 0x%04x\n",
__func__, reg_addr, reg_val);
aw8896_i2c_write(aw8896, (unsigned char)reg_addr,
(unsigned int)reg_val);
}
pr_debug("%s exit\n", __func__);
}
static int aw8896_reg_loaded(const struct firmware *cont, struct aw8896 *aw8896)
{
struct aw8896_container *aw8896_reg = NULL;
int ret = -1;
int i = 0;
int iis_check_max = 5;
unsigned int reg_val = 0;
if (!cont) {
pr_err("%s: failed to read %s\n", __func__, aw8896_reg_name);
release_firmware(cont);
return -EINVAL;
}
pr_info("%s: loaded %s - size: %zu\n", __func__, aw8896_reg_name,
cont ? cont->size : 0);
aw8896_reg = kzalloc(cont->size+sizeof(int), GFP_KERNEL);
if (!aw8896_reg) {
release_firmware(cont);
pr_err("%s: error allocating memory\n", __func__);
return -ENOMEM;
}
aw8896_reg->len = cont->size;
memcpy(aw8896_reg->data, cont->data, cont->size);
release_firmware(cont);
aw8896_reg_container_update(aw8896, aw8896_reg);
aw8896_i2c_read(aw8896, AW8896_REG_DBGCTRL, &reg_val);
aw8896_i2c_write(aw8896, AW8896_REG_DBGCTRL,
reg_val | AW8896_BIT_DBGCTRL_DISNCKRST);
aw8896_i2c_read(aw8896, AW8896_REG_I2SCTRL, &reg_val);
aw8896_i2c_write(aw8896, AW8896_REG_I2SCTRL,
reg_val & (~AW8896_BIT_I2SCTRL_INPLEV));
kfree(aw8896_reg);
for (i = 0; i < iis_check_max; i++) {
ret = aw8896_get_iis_status(aw8896);
if (ret < 0) {
pr_err("%s: get no iis signal, ret=%d\n",
__func__, ret);
} else {
usleep_range(5000, 6000);
ret = aw8896_load_fw(aw8896);
if (ret) {
pr_err("%s: fw loading requested failed: %d\n",
__func__, ret);
}
break;
}
usleep_range(2000, 3000);
}
return ret;
}
static int aw8896_load_reg(struct aw8896 *aw8896)
{
const struct firmware *cont = NULL;
int ret;
pr_info("%s enter\n", __func__);
ret = request_firmware(&cont, aw8896_reg_name, aw8896->dev);
if (ret < 0) {
pr_err("%s: failed to read %s\n", __func__, aw8896_reg_name);
release_firmware(cont);
return ret;
}
return aw8896_reg_loaded(cont, aw8896);
}
static void aw8896_cold_start(struct aw8896 *aw8896)
{
int ret = -1;
pr_info("%s enter\n", __func__);
ret = aw8896_load_reg(aw8896);
if (ret)
pr_err("%s: reg/fw loading requested failed: %d\n",
__func__, ret);
}
static void aw8896_smartpa_cfg(struct aw8896 *aw8896, bool flag)
{
pr_info("%s, flag = %d\n", __func__, flag);
if (flag == true) {
if (aw8896->init == 0) {
pr_info("%s, init = %d\n", __func__, aw8896->init);
aw8896_cold_start(aw8896);
} else {
aw8896_spk_rcv_mode(aw8896);
aw8896_start(aw8896);
}
} else {
aw8896_stop(aw8896);
}
}
/******************************************************
*
* kcontrol
*
******************************************************/
static const char *const spk_function[] = { "Off", "On" };
static const char *const rcv_function[] = { "Off", "On" };
static const char *const hmute_function[] = { "Off", "On" };
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 50, 0);
struct soc_mixer_control aw8896_mixer = {
.reg = AW8896_REG_DSPCFG,
.shift = AW8896_VOL_REG_SHIFT,
.max = AW8896_VOLUME_MAX,
.min = AW8896_VOLUME_MIN,
};
static int aw8896_volume_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *) kcontrol->private_value;
/* set kcontrol info */
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = mc->max - mc->min;
return 0;
}
static int aw8896_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
int value;
struct soc_mixer_control *mc =
(struct soc_mixer_control *) kcontrol->private_value;
aw8896_i2c_read(aw8896, AW8896_REG_DSPCFG, &value);
ucontrol->value.integer.value[0] = (value >> mc->shift)
&(~AW8896_BIT_DSPCFG_VOL_MASK);
return 0;
}
static int aw8896_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *) kcontrol->private_value;
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
unsigned int value, reg_value;
/* value is right */
value = ucontrol->value.integer.value[0];
if (value > (mc->max-mc->min) || value < 0) {
pr_err("%s:value over range\n", __func__);
return -EPERM;
}
/* smartpa have clk */
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &reg_value);
if (!(reg_value&AW8896_BIT_SYSST_PLLS)) {
pr_err("%s: NO I2S CLK ,cat not write reg\n", __func__);
return 0;
}
/* cal real value */
value = value << mc->shift&AW8896_BIT_DSPCFG_VOL_MASK;
aw8896_i2c_read(aw8896, AW8896_REG_DSPCFG, &reg_value);
value = value | (reg_value&0x00ff);
/* write value */
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_value);
if (reg_value&AW8896_BIT_SYSCTRL_DSPBY) {
aw8896_i2c_write(aw8896, AW8896_REG_DSPCFG, value);
} else {
aw8896_dsp_enable(aw8896, false);
aw8896_i2c_write(aw8896, AW8896_REG_DSPCFG, value);
aw8896_dsp_enable(aw8896, true);
}
return 0;
}
static struct snd_kcontrol_new aw8896_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "aw8896_rx_volume",
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_READWRITE,
.tlv.p = (digital_gain),
.info = aw8896_volume_info,
.get = aw8896_volume_get,
.put = aw8896_volume_put,
.private_value = (unsigned long)&aw8896_mixer,
};
static int aw8896_spk_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s: aw8896_spk_control=%d\n", __func__, aw8896_spk_control);
ucontrol->value.integer.value[0] = aw8896_spk_control;
return 0;
}
static int aw8896_spk_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
pr_debug("%s: ucontrol->value.integer.value[0]=%ld\n",
__func__, ucontrol->value.integer.value[0]);
if (ucontrol->value.integer.value[0] == aw8896_spk_control)
return 1;
aw8896_spk_control = ucontrol->value.integer.value[0];
aw8896->spk_rcv_mode = AW8896_SPEAKER_MODE;
return 0;
}
static int aw8896_rcv_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
pr_debug("%s: aw8896_rcv_control=%d\n", __func__, aw8896_rcv_control);
ucontrol->value.integer.value[0] = aw8896_rcv_control;
return 0;
}
static int aw8896_rcv_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
pr_debug("%s: ucontrol->value.integer.value[0]=%ld\n",
__func__, ucontrol->value.integer.value[0]);
if (ucontrol->value.integer.value[0] == aw8896_rcv_control)
return 1;
aw8896_rcv_control = ucontrol->value.integer.value[0];
aw8896->spk_rcv_mode = AW8896_RECEIVER_MODE;
return 0;
}
static int aw8896_hmute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
bool is_mute = true;
is_mute = aw8896_is_hmute(aw8896);
ucontrol->value.integer.value[0] = is_mute ? 1 : 0;
return 0;
}
static int aw8896_hmute_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
aw_snd_soc_codec_t *codec =
aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
bool is_mute = true;
int cur_state = 0;
pr_debug("%s: ucontrol->value.integer.value[0]=%ld\n",
__func__, ucontrol->value.integer.value[0]);
is_mute = aw8896_is_hmute(aw8896);
cur_state = is_mute ? 1 : 0;
if (ucontrol->value.integer.value[0] == cur_state)
return 1;
if (is_mute) {
if (aw8896->init == 0) {
aw8896->call_in_kctl = 1;
aw8896_cold_start(aw8896);
aw8896->call_in_kctl = 0;
}
aw8896_run_amp_off(aw8896, false);
aw8896_run_mute(aw8896, false);
} else {
aw8896_run_mute(aw8896, true);
usleep_range(1000, 2000);
aw8896_run_amp_off(aw8896, true);
}
return 0;
}
static const struct soc_enum aw8896_snd_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rcv_function), rcv_function),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hmute_function), hmute_function),
};
static struct snd_kcontrol_new aw8896_controls[] = {
SOC_ENUM_EXT("aw8896_speaker_switch", aw8896_snd_enum[0],
aw8896_spk_get, aw8896_spk_set),
SOC_ENUM_EXT("aw8896_receiver_switch", aw8896_snd_enum[1],
aw8896_rcv_get, aw8896_rcv_set),
SOC_ENUM_EXT("aw8896_playback_spk_mute", aw8896_snd_enum[2],
aw8896_hmute_get, aw8896_hmute_set),
};
static void aw8896_add_codec_controls(struct aw8896 *aw8896)
{
pr_info("%s enter\n", __func__);
aw_componet_codec_ops.aw_snd_soc_add_codec_controls(aw8896->codec,
aw8896_controls,
ARRAY_SIZE(aw8896_controls));
aw_componet_codec_ops.aw_snd_soc_add_codec_controls(aw8896->codec,
&aw8896_volume, 1);
}
/******************************************************
*
* Digital Audio Interface
*
******************************************************/
static int aw8896_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
aw_snd_soc_codec_t *codec = aw_get_codec(dai);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_info("%s: playback enter\n", __func__);
mutex_lock(&aw8896->lock);
aw8896_run_pwd(aw8896, false);
mutex_unlock(&aw8896->lock);
} else {
pr_info("%s: capture enter\n", __func__);
}
return 0;
}
static int aw8896_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
aw_snd_soc_codec_t *codec = aw_get_codec(dai);
pr_info("%s: fmt=0x%x\n", __func__, fmt);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) !=
SND_SOC_DAIFMT_CBS_CFS) {
dev_err(codec->dev,
"%s: invalid codec mode\n", __func__);
return -EINVAL;
}
break;
default:
dev_err(codec->dev, "%s: unsupported DAI format %d\n", __func__,
(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
return -EINVAL;
}
return 0;
}
static int aw8896_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
aw_snd_soc_codec_t *codec = aw_get_codec(codec_dai);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
pr_info("%s: freq=%d\n", __func__, freq);
aw8896->sysclk = freq;
return 0;
}
static int aw8896_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
aw_snd_soc_codec_t *codec = aw_get_codec(dai);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
unsigned int rate;
int reg_value, tmp_value;
int width;
/* Supported */
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: requested rate: %d, sample size: %d\n",
__func__, rate,
snd_pcm_format_width(params_format(params)));
return 0;
}
mutex_lock(&aw8896->lock);
/* get rate param */
aw8896->rate = rate = params_rate(params);
pr_debug("%s: requested rate: %d, sample size: %d\n", __func__, rate,
snd_pcm_format_width(params_format(params)));
/* match rate */
switch (rate) {
case 8000:
reg_value = AW8896_BIT_I2SCTRL_SR_8K;
break;
case 16000:
reg_value = AW8896_BIT_I2SCTRL_SR_16K;
break;
case 32000:
reg_value = AW8896_BIT_I2SCTRL_SR_32K;
break;
case 44100:
reg_value = AW8896_BIT_I2SCTRL_SR_44K;
break;
case 48000:
reg_value = AW8896_BIT_I2SCTRL_SR_48K;
break;
default:
reg_value = AW8896_BIT_I2SCTRL_SR_48K;
pr_err("%s: rate can not support\n", __func__);
break;
}
/* set chip rate */
if (-1 != reg_value) {
aw8896_i2c_read(aw8896, AW8896_REG_I2SCTRL, &tmp_value);
reg_value = reg_value |
(tmp_value & (~AW8896_BIT_I2SCTRL_SR_MASK));
aw8896_i2c_write(aw8896, AW8896_REG_I2SCTRL, reg_value);
}
/* get bit width */
width = params_width(params);
pr_debug("%s: width = %d\n", __func__, width);
switch (width) {
case 16:
reg_value = AW8896_BIT_I2SCTRL_FMS_16BIT;
break;
case 20:
reg_value = AW8896_BIT_I2SCTRL_FMS_20BIT;
break;
case 24:
reg_value = AW8896_BIT_I2SCTRL_FMS_24BIT;
break;
case 32:
reg_value = AW8896_BIT_I2SCTRL_FMS_32BIT;
break;
default:
reg_value = AW8896_BIT_I2SCTRL_FMS_16BIT;
pr_err("%s: width can not support\n", __func__);
break;
}
/* set width */
if (-1 != reg_value) {
aw8896_i2c_read(aw8896, AW8896_REG_I2SCTRL, &tmp_value);
reg_value = reg_value |
(tmp_value&(~AW8896_BIT_I2SCTRL_FMS_MASK));
aw8896_i2c_write(aw8896, AW8896_REG_I2SCTRL, reg_value);
}
mutex_unlock(&aw8896->lock);
return 0;
}
static int aw8896_mute(struct snd_soc_dai *dai, int mute, int stream)
{
aw_snd_soc_codec_t *codec = aw_get_codec(dai);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
pr_info("%s: mute state=%d\n", __func__, mute);
if (!(aw8896->flags & AW8896_FLAG_DSP_START_ON_MUTE))
return 0;
if (stream != SNDRV_PCM_STREAM_PLAYBACK) {
pr_info("%s: not playback\n", __func__);
return 0;
}
if (mute) {
/* Stop DSP */
mutex_lock(&aw8896->lock);
aw8896_smartpa_cfg(aw8896, false);
mutex_unlock(&aw8896->lock);
} else {
/* Start DSP */
mutex_lock(&aw8896->lock);
aw8896_smartpa_cfg(aw8896, true);
mutex_unlock(&aw8896->lock);
}
return 0;
}
static void aw8896_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
aw_snd_soc_codec_t *codec = aw_get_codec(dai);
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_info("%s: playback shutdown\n", __func__);
mutex_lock(&aw8896->lock);
aw8896->rate = 0;
aw8896_run_pwd(aw8896, true);
mutex_unlock(&aw8896->lock);
}
}
static const struct snd_soc_dai_ops aw8896_dai_ops = {
.startup = aw8896_startup,
.set_fmt = aw8896_set_fmt,
.set_sysclk = aw8896_set_dai_sysclk,
.hw_params = aw8896_hw_params,
.mute_stream = aw8896_mute,
.shutdown = aw8896_shutdown,
};
static struct snd_soc_dai_driver aw8896_dai[] = {
{
.name = "aw8896-aif",
.id = 1,
.playback = {
.stream_name = "Speaker_Playback",
.channels_min = 1,
.channels_max = 2,
.rates = AW8896_RATES,
.formats = AW8896_FORMATS,
},
.capture = {
.stream_name = "Speaker_Capture",
.channels_min = 1,
.channels_max = 2,
.rates = AW8896_RATES,
.formats = AW8896_FORMATS,
},
.ops = &aw8896_dai_ops,
.symmetric_rates = 1,
.symmetric_channels = 1,
.symmetric_samplebits = 1,
},
};
/*****************************************************
*
* codec driver
*
*****************************************************/
static int aw8896_probe(aw_snd_soc_codec_t *codec)
{
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
int ret = 0;
pr_info("%s enter\n", __func__);
aw8896->codec = codec;
aw8896_add_codec_controls(aw8896);
if (codec->dev->of_node)
dev_set_name(codec->dev, "%s", "aw8896_smartpa");
pr_info("%s exit\n", __func__);
return ret;
}
#ifdef AW_KERNEL_VER_OVER_4_19_1
static void aw8896_remove(struct snd_soc_component *component)
{
pr_info("%s enter\n", __func__);
}
#else
static int aw8896_remove(aw_snd_soc_codec_t *codec)
{
pr_info("%s enter\n", __func__);
return 0;
}
#endif
struct regmap *aw8896_get_regmap(struct device *dev)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
return aw8896->regmap;
}
static unsigned int aw8896_codec_read(aw_snd_soc_codec_t *codec,
unsigned int reg)
{
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
unsigned int value = 0;
int ret;
pr_debug("%s:enter\n", __func__);
if (aw8896_reg_access[reg]&REG_RD_ACCESS) {
ret = aw8896_i2c_read(aw8896, reg, &value);
if (ret < 0) {
pr_debug("%s: read register failed\n", __func__);
return ret;
}
} else {
pr_debug("%s:Register 0x%x NO read access\n", __func__, reg);
return -EPERM;
}
return value;
}
static int aw8896_codec_write(aw_snd_soc_codec_t *codec,
unsigned int reg, unsigned int value)
{
int ret;
struct aw8896 *aw8896 =
aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);
pr_debug("%s:enter ,reg is 0x%x value is 0x%x\n", __func__, reg, value);
if (aw8896_reg_access[reg]&REG_WR_ACCESS) {
ret = aw8896_i2c_write(aw8896, reg, value);
return ret;
}
pr_debug("%s: Register 0x%x NO write access\n", __func__, reg);
return -EPERM;
}
static const struct snd_soc_dapm_widget aw8896_dapm_widgets[] = {
SND_SOC_DAPM_DAC_E("DAC", "Speaker_Playback", SND_SOC_NOPM, 0, 0, NULL,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUTPUT("SPK"),
};
static const struct snd_soc_dapm_route aw8896_audio_map[] = {
/* sink, control, source */
{"SPK", NULL, "DAC"},
};
#ifdef AW_KERNEL_VER_OVER_4_19_1
static const struct snd_soc_component_driver soc_codec_dev_aw8896 = {
.probe = aw8896_probe,
.remove = aw8896_remove,
.read = aw8896_codec_read,
.write = aw8896_codec_write,
.dapm_widgets = aw8896_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(aw8896_dapm_widgets),
.dapm_routes = aw8896_audio_map,
.num_dapm_routes = ARRAY_SIZE(aw8896_audio_map),
};
#else
static const struct snd_soc_codec_driver soc_codec_dev_aw8896 = {
.probe = aw8896_probe,
.remove = aw8896_remove,
.read = aw8896_codec_read,
.write = aw8896_codec_write,
.component_driver = {
.dapm_widgets = aw8896_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(aw8896_dapm_widgets),
.dapm_routes = aw8896_audio_map,
.num_dapm_routes = ARRAY_SIZE(aw8896_audio_map),
},
.reg_cache_size = AW8896_REG_MAX,
.reg_word_size = 2,
};
#endif
/*****************************************************
*
* regmap
*
*****************************************************/
bool aw8896_writeable_register(struct device *dev, unsigned int reg)
{
/* enable read access for all registers */
return 1;
}
bool aw8896_readable_register(struct device *dev, unsigned int reg)
{
/* enable read access for all registers */
return 1;
}
bool aw8896_volatile_register(struct device *dev, unsigned int reg)
{
/* enable read access for all registers */
return 1;
}
static const struct regmap_config aw8896_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = AW8896_MAX_REGISTER,
.writeable_reg = aw8896_writeable_register,
.readable_reg = aw8896_readable_register,
.volatile_reg = aw8896_volatile_register,
.cache_type = REGCACHE_RBTREE,
};
/******************************************************
*
* irq
*
******************************************************/
static void aw8896_interrupt_setup(struct aw8896 *aw8896)
{
unsigned int reg_val;
pr_info("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSINTM, &reg_val);
/* i2s status interrupt unmask */
reg_val &= (~AW8896_BIT_SYSINTM_PLLM);
reg_val &= (~AW8896_BIT_SYSINTM_CLKM);
reg_val &= (~AW8896_BIT_SYSINTM_NOCLKM);
/* uvlo interrupt unmask */
reg_val &= (~AW8896_BIT_SYSINTM_UVLOM);
/* over temperature interrupt unmask */
reg_val &= (~AW8896_BIT_SYSINTM_OTHM);
/* dsp watchdog status interrupt unmask */
reg_val &= (~AW8896_BIT_SYSINTM_WDM);
aw8896_i2c_write(aw8896, AW8896_REG_SYSINTM, reg_val);
}
static void aw8896_interrupt_clear(struct aw8896 *aw8896)
{
unsigned int reg_val;
pr_info("%s enter\n", __func__);
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &reg_val);
pr_info("%s: reg SYSST=0x%x\n", __func__, reg_val);
aw8896_i2c_read(aw8896, AW8896_REG_SYSINT, &reg_val);
pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val);
aw8896_i2c_read(aw8896, AW8896_REG_SYSINTM, &reg_val);
pr_info("%s: reg SYSINTM=0x%x\n", __func__, reg_val);
}
static irqreturn_t aw8896_irq(int irq, void *data)
{
struct aw8896 *aw8896 = data;
pr_info("%s enter\n", __func__);
aw8896_interrupt_clear(aw8896);
pr_info("%s exit\n", __func__);
return IRQ_HANDLED;
}
/*****************************************************
*
* device tree
*
*****************************************************/
static int aw8896_parse_dt(struct device *dev, struct aw8896 *aw8896,
struct device_node *np)
{
aw8896->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
if (aw8896->reset_gpio < 0) {
dev_err(dev,
"%s: no reset gpio provided, will not HW reset device\n",
__func__);
return -EPERM;
}
dev_info(dev, "%s: reset gpio provided ok\n", __func__);
aw8896->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0);
if (aw8896->irq_gpio < 0)
dev_info(dev, "%s: no irq gpio provided.\n", __func__);
else
dev_info(dev, "%s: irq gpio provided ok.\n", __func__);
return 0;
}
int aw8896_hw_reset(struct aw8896 *aw8896)
{
pr_info("%s enter\n", __func__);
if (aw8896 && gpio_is_valid(aw8896->reset_gpio)) {
gpio_set_value_cansleep(aw8896->reset_gpio, 1);
usleep_range(1000, 2000);
gpio_set_value_cansleep(aw8896->reset_gpio, 0);
usleep_range(1000, 2000);
} else {
dev_err(aw8896->dev, "%s: failed\n", __func__);
}
return 0;
}
/*****************************************************
*
* check chip id
*
*****************************************************/
int aw8896_read_chipid(struct aw8896 *aw8896)
{
int ret = -1;
unsigned int cnt = 0;
unsigned int reg = 0;
while (cnt < AW_READ_CHIPID_RETRIES) {
ret = aw8896_i2c_read(aw8896, AW8896_REG_ID, &reg);
if (ret < 0) {
dev_err(aw8896->dev,
"%s: failed to read register AW8896_REG_ID: %d\n",
__func__, ret);
return -EIO;
}
switch (reg) {
case 0x0310:
pr_info("%s aw8896 detected\n", __func__);
aw8896->flags |= AW8896_FLAG_SKIP_INTERRUPTS;
aw8896->flags |= AW8896_FLAG_DSP_START_ON_MUTE;
aw8896->flags |= AW8896_FLAG_DSP_START_ON;
aw8896->chipid = AW8990_ID;
pr_info("%s aw8896->flags=0x%x\n",
__func__, aw8896->flags);
return 0;
default:
pr_info("%s unsupported device revision (0x%x)\n",
__func__, reg);
break;
}
cnt++;
usleep_range(AW_READ_CHIPID_RETRY_DELAY_US,
AW_READ_CHIPID_RETRY_DELAY_US + 1000);
}
return -EINVAL;
}
/******************************************************
*
* sys group attribute: reg
*
******************************************************/
static ssize_t aw8896_reg_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
unsigned int databuf[2] = {0};
if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2)
aw8896_i2c_write(aw8896, databuf[0], databuf[1]);
return count;
}
static ssize_t aw8896_reg_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
ssize_t len = 0;
unsigned char i = 0;
unsigned int reg_val = 0;
for (i = 0; i < AW8896_REG_MAX; i++) {
if (!(aw8896_reg_access[i]&REG_RD_ACCESS))
continue;
aw8896_i2c_read(aw8896, i, &reg_val);
len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%04x\n",
i, reg_val);
}
return len;
}
static ssize_t aw8896_dsp_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
unsigned int databuf[16] = {0};
unsigned int reg_val = 0;
int ret;
ret = kstrtoint(buf, 0, &databuf[0]);
if (ret < 0) {
dev_err(dev, "%s, read buf %s failed\n",
__func__, buf);
return ret;
}
if (databuf[0] == 1) {
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &reg_val);
if (reg_val & AW8896_BIT_SYSST_PLLS) {
aw8896->init = 0;
aw8896->dsp_fw_state = AW8896_DSP_FW_FAIL;
aw8896_smartpa_cfg(aw8896, false);
aw8896_smartpa_cfg(aw8896, true);
} else {
count += snprintf((char *)(buf+count),
PAGE_SIZE-count,
"aw8896 plls=%d, no iis signal\n",
reg_val&AW8896_BIT_SYSST_PLLS);
}
} else {
aw8896_dsp_enable(aw8896, false);
}
return count;
}
static ssize_t aw8896_dsp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
ssize_t len = 0;
unsigned int i = 0;
unsigned int addr = 0;
unsigned int reg_val = 0;
aw8896_i2c_read(aw8896, AW8896_REG_SYSCTRL, &reg_val);
if (reg_val & AW8896_BIT_SYSCTRL_DSPBY) {
len += snprintf(buf+len, PAGE_SIZE-len, "aw8896 dsp bypass\n");
} else {
aw8896_i2c_read(aw8896, AW8896_REG_SYSST, &reg_val);
if (reg_val & AW8896_BIT_SYSST_PLLS) {
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 dsp working\n");
aw8896_dsp_enable(aw8896, false);
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 dsp firmware:\n");
addr = 0;
for (i = 0; i < aw8896->dsp_fw_len; i += 2) {
aw8896_i2c_write(aw8896, AW8896_REG_DSPMADD,
AW8896_DSP_FW_BASE+addr);
aw8896_i2c_read(aw8896, AW8896_REG_DSPMDAT,
&reg_val);
len += snprintf(buf+len, PAGE_SIZE-len,
"0x%02x,0x%02x,",
reg_val&0x00FF, (reg_val>>8));
if ((i/2+1)%4 == 0)
len += snprintf(buf+len,
PAGE_SIZE-len, "\n");
addr++;
}
len += snprintf(buf+len, PAGE_SIZE-len, "\n");
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 dsp firmware backup:\n");
addr = 0;
for (i = 0; i < aw8896->dsp_fw_len; i += 2) {
aw8896_i2c_write(aw8896, AW8896_REG_DSPMADD,
AW8896_DSP_FW_BACKUP_BASE+addr);
aw8896_i2c_read(aw8896, AW8896_REG_DSPMDAT,
&reg_val);
len += snprintf(buf+len, PAGE_SIZE-len,
"0x%02x,0x%02x,",
reg_val&0x00FF, (reg_val>>8));
if ((i/2+1)%4 == 0)
len += snprintf(buf+len,
PAGE_SIZE-len, "\n");
addr++;
}
len += snprintf(buf+len, PAGE_SIZE-len, "\n");
aw8896_dsp_enable(aw8896, true);
} else {
len += snprintf((char *)(buf+len), PAGE_SIZE-len,
"aw8896 plls=%d, no iis signal\n",
reg_val&AW8896_BIT_SYSST_PLLS);
}
}
return len;
}
static ssize_t aw8896_spk_rcv_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
int ret;
unsigned int databuf[2] = {0};
ret = kstrtoint(buf, 0, &databuf[0]);
if (ret < 0) {
dev_err(dev, "%s, read buf %s failed\n",
__func__, buf);
return ret;
}
aw8896->spk_rcv_mode = databuf[0];
return count;
}
static ssize_t aw8896_spk_rcv_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct aw8896 *aw8896 = dev_get_drvdata(dev);
ssize_t len = 0;
if (aw8896->spk_rcv_mode == AW8896_SPEAKER_MODE) {
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 spk_rcv: %d, speaker mode\n",
aw8896->spk_rcv_mode);
} else if (aw8896->spk_rcv_mode == AW8896_RECEIVER_MODE) {
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 spk_rcv: %d, receiver mode\n",
aw8896->spk_rcv_mode);
} else {
len += snprintf(buf+len, PAGE_SIZE-len,
"aw8896 spk_rcv: %d, unknown mode\n",
aw8896->spk_rcv_mode);
}
return len;
}
static DEVICE_ATTR(reg, 0644, aw8896_reg_show, aw8896_reg_store);
static DEVICE_ATTR(dsp, 0644, aw8896_dsp_show, aw8896_dsp_store);
static DEVICE_ATTR(spk_rcv, 0644,
aw8896_spk_rcv_show, aw8896_spk_rcv_store);
static struct attribute *aw8896_attributes[] = {
&dev_attr_reg.attr,
&dev_attr_dsp.attr,
&dev_attr_spk_rcv.attr,
NULL
};
static struct attribute_group aw8896_attribute_group = {
.attrs = aw8896_attributes
};
/******************************************************
*
* i2c driver
*
******************************************************/
int aw8896_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
struct snd_soc_dai_driver *dai;
struct aw8896 *aw8896;
struct device_node *np = i2c->dev.of_node;
int irq_flags = 0;
int ret = -1;
pr_info("%s enter\n", __func__);
pr_info("%s: driver version %s\n", __func__, AW8896_VERSION);
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
dev_err(&i2c->dev, "check_functionality failed\n");
return -EIO;
}
aw8896 = devm_kzalloc(&i2c->dev, sizeof(struct aw8896), GFP_KERNEL);
if (aw8896 == NULL)
return -ENOMEM;
aw8896->dev = &i2c->dev;
aw8896->i2c = i2c;
/* aw8896 regmap */
aw8896->regmap = devm_regmap_init_i2c(i2c, &aw8896_regmap);
if (IS_ERR(aw8896->regmap)) {
ret = PTR_ERR(aw8896->regmap);
dev_err(&i2c->dev,
"%s: failed to allocate register map: %d\n",
__func__, ret);
goto err_regmap;
}
i2c_set_clientdata(i2c, aw8896);
mutex_init(&aw8896->lock);
/* aw8896 rst & int */
if (np) {
ret = aw8896_parse_dt(&i2c->dev, aw8896, np);
if (ret) {
dev_err(&i2c->dev,
"%s: failed to parse device tree node\n",
__func__);
goto err_parse_dt;
}
} else {
aw8896->reset_gpio = -1;
aw8896->irq_gpio = -1;
}
if (gpio_is_valid(aw8896->reset_gpio)) {
ret = devm_gpio_request_one(&i2c->dev, aw8896->reset_gpio,
GPIOF_OUT_INIT_LOW, "aw8896_rst");
if (ret) {
dev_err(&i2c->dev,
"%s: rst request failed\n", __func__);
goto err_reset_gpio_request;
}
}
if (gpio_is_valid(aw8896->irq_gpio)) {
ret = devm_gpio_request_one(&i2c->dev, aw8896->irq_gpio,
GPIOF_DIR_IN, "aw8896_int");
if (ret) {
dev_err(&i2c->dev,
"%s: int request failed\n", __func__);
goto err_irq_gpio_request;
}
}
/* hardware reset */
aw8896_hw_reset(aw8896);
/* aw8896 chip id */
ret = aw8896_read_chipid(aw8896);
if (ret < 0) {
dev_err(&i2c->dev,
"%s: aw8896_read_chipid failed ret=%d\n",
__func__, ret);
goto err_id;
}
/* aw8896 device name */
if (i2c->dev.of_node) {
dev_set_name(&i2c->dev, "%s", "aw8896_smartpa");
} else {
dev_err(&i2c->dev,
"%s failed to set device name: %d\n",
__func__, ret);
}
/* register codec */
dai = devm_kzalloc(&i2c->dev, sizeof(aw8896_dai), GFP_KERNEL);
if (!dai)
goto err_dai_kzalloc;
memcpy(dai, aw8896_dai, sizeof(aw8896_dai));
pr_info("%s dai->name(%s)\n", __func__, dai->name);
ret = aw_componet_codec_ops.aw_snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aw8896,
dai, ARRAY_SIZE(aw8896_dai));
if (ret < 0) {
dev_err(&i2c->dev,
"%s failed to register aw8896: %d\n",
__func__, ret);
goto err_register_codec;
}
/* aw8896 irq */
if (gpio_is_valid(aw8896->irq_gpio) &&
!(aw8896->flags & AW8896_FLAG_SKIP_INTERRUPTS)) {
/* register irq handler */
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
ret = devm_request_threaded_irq(&i2c->dev,
gpio_to_irq(aw8896->irq_gpio),
NULL, aw8896_irq, irq_flags,
"aw8896", aw8896);
if (ret != 0) {
dev_err(&i2c->dev, "failed to request IRQ %d: %d\n",
gpio_to_irq(aw8896->irq_gpio), ret);
goto err_irq;
}
} else {
dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__);
/* disable feature support if gpio was invalid */
aw8896->flags |= AW8896_FLAG_SKIP_INTERRUPTS;
}
dev_set_drvdata(&i2c->dev, aw8896);
ret = sysfs_create_group(&i2c->dev.kobj, &aw8896_attribute_group);
if (ret < 0) {
dev_info(&i2c->dev,
"%s error creating sysfs attr files\n", __func__);
goto err_sysfs;
}
aw8896->call_in_kctl = 0;
pr_info("%s probe completed successfully!\n", __func__);
return 0;
err_sysfs:
devm_free_irq(&i2c->dev, gpio_to_irq(aw8896->irq_gpio), aw8896);
err_irq:
aw_componet_codec_ops.aw_snd_soc_unregister_codec(&i2c->dev);
err_register_codec:
devm_kfree(&i2c->dev, dai);
dai = NULL;
err_dai_kzalloc:
err_id:
if (gpio_is_valid(aw8896->irq_gpio))
devm_gpio_free(&i2c->dev, aw8896->irq_gpio);
err_irq_gpio_request:
if (gpio_is_valid(aw8896->reset_gpio))
devm_gpio_free(&i2c->dev, aw8896->reset_gpio);
err_reset_gpio_request:
err_parse_dt:
err_regmap:
devm_kfree(&i2c->dev, aw8896);
aw8896 = NULL;
return ret;
}
EXPORT_SYMBOL(aw8896_i2c_probe);
int aw8896_i2c_remove(struct i2c_client *i2c)
{
struct aw8896 *aw8896 = i2c_get_clientdata(i2c);
pr_info("%s enter\n", __func__);
if (gpio_to_irq(aw8896->irq_gpio))
devm_free_irq(&i2c->dev, gpio_to_irq(aw8896->irq_gpio), aw8896);
aw_componet_codec_ops.aw_snd_soc_unregister_codec(&i2c->dev);
if (gpio_is_valid(aw8896->irq_gpio))
devm_gpio_free(&i2c->dev, aw8896->irq_gpio);
if (gpio_is_valid(aw8896->reset_gpio))
devm_gpio_free(&i2c->dev, aw8896->reset_gpio);
devm_kfree(&i2c->dev, aw8896);
aw8896 = NULL;
return 0;
}
EXPORT_SYMBOL(aw8896_i2c_remove);
#if 0
static const struct i2c_device_id aw8896_i2c_id[] = {
{ AW8896_I2C_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw8896_i2c_id);
static const struct of_device_id aw8896_dt_match[] = {
{ .compatible = "awinic,aw8896_smartpa" },
{ },
};
static struct i2c_driver aw8896_i2c_driver = {
.driver = {
.name = AW8896_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(aw8896_dt_match),
},
.probe = aw8896_i2c_probe,
.remove = aw8896_i2c_remove,
.id_table = aw8896_i2c_id,
};
static int __init aw8896_i2c_init(void)
{
int ret = 0;
pr_info("aw8896 driver version %s\n", AW8896_VERSION);
ret = i2c_add_driver(&aw8896_i2c_driver);
if (ret) {
pr_err("fail to add aw8896 device into i2c\n");
return ret;
}
return 0;
}
module_init(aw8896_i2c_init);
static void __exit aw8896_i2c_exit(void)
{
i2c_del_driver(&aw8896_i2c_driver);
}
module_exit(aw8896_i2c_exit);
#endif
MODULE_DESCRIPTION("ASoC AW8896 Smart PA Driver");
MODULE_LICENSE("GPL v2");