From 3b918464d062fc4c083993d05c05fe905ae8093f Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 17 Apr 2023 22:51:16 +0200 Subject: [PATCH 1/4] aw8898: import driver --- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw/aw8898.c | 1612 ++++++++++++++++++++++++++++++ sound/soc/codecs/aw/aw8898.h | 72 ++ sound/soc/codecs/aw/aw8898_reg.h | 448 +++++++++ 4 files changed, 2134 insertions(+) create mode 100644 sound/soc/codecs/aw/aw8898.c create mode 100644 sound/soc/codecs/aw/aw8898.h create mode 100644 sound/soc/codecs/aw/aw8898_reg.h diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 69e89e656b1e99..c04515059073cd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -750,3 +750,5 @@ obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO) += snd-soc-lpass-tx-macro.o # Mux obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o + +obj-y += aw/aw8898.o diff --git a/sound/soc/codecs/aw/aw8898.c b/sound/soc/codecs/aw/aw8898.c new file mode 100644 index 00000000000000..dc565ed012cccf --- /dev/null +++ b/sound/soc/codecs/aw/aw8898.c @@ -0,0 +1,1612 @@ +/* + * aw8898.c aw8898 codec module + * + * Version: v1.1.3 + * + * Copyright (c) 2018 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw8898.h" +#include "aw8898_reg.h" + +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW8898_I2C_NAME "aw8898_smartpa" + + +#define AW8898_VERSION "v1.1.3" + +#define AW8898_RATES SNDRV_PCM_RATE_8000_48000 +#define AW8898_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 5 + +static int aw8898_spk_control = 0; +static int aw8898_rcv_control = 0; + +#define AW8898_MAX_FIRMWARE_LOAD_CNT 20 +static char *aw8898_cfg_name = "aw8898_cfg.bin"; + +#ifdef AW8898_VBAT_MONITOR +static int aw8898_vbat_monitor_start(struct aw8898 *aw8898); +static int aw8898_vbat_monitor_stop(struct aw8898 *aw8898); +#endif + /****************************************************** + * + * aw8898 i2c write/read + * + ******************************************************/ +#ifndef AWINIC_I2C_REGMAP +static int i2c_write(struct aw8898 *aw8898, + unsigned char addr, unsigned int reg_data) +{ + int ret = -1; + u8 wbuf[512] = {0}; + + struct i2c_msg msgs[] = { + { + .addr = aw8898->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(aw8898->i2c->adapter, msgs, 1); + if (ret < 0) { + pr_err("%s: i2c write error: %d\n", __func__, ret); + } + + return ret; +} + +static int i2c_read(struct aw8898 *aw8898, + unsigned char addr, unsigned int *reg_data) +{ + int ret = -1; + unsigned char rbuf[512] = {0}; + unsigned int get_data = 0; + + struct i2c_msg msgs[] = { + { + .addr = aw8898->i2c->addr, + .flags = 0, + .len = 1, + .buf = &addr, + }, + { + .addr = aw8898->i2c->addr, + .flags = I2C_M_RD, + .len = 2, + .buf = rbuf, + }, + }; + + ret = i2c_transfer(aw8898->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 aw8898_i2c_write(struct aw8898 *aw8898, + 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(aw8898->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(aw8898, 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 aw8898_i2c_read(struct aw8898 *aw8898, + 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(aw8898->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(aw8898, 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 aw8898_i2c_write_bits(struct aw8898 *aw8898, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + unsigned int reg_val; + + aw8898_i2c_read(aw8898, reg_addr, ®_val); + reg_val &= mask; + reg_val |= reg_data; + aw8898_i2c_write(aw8898, reg_addr, reg_val); + + return 0; +} + +/****************************************************** + * + * aw8898 control + * + ******************************************************/ +static void aw8898_run_mute(struct aw8898 *aw8898, bool mute) +{ + pr_debug("%s enter\n", __func__); + + if(mute) { + aw8898_i2c_write_bits(aw8898, AW8898_REG_PWMCTRL, + AW8898_BIT_PWMCTRL_HMUTE_MASK, AW8898_BIT_PWMCTRL_HMUTE_ENABLE); + } else { + aw8898_i2c_write_bits(aw8898, AW8898_REG_PWMCTRL, + AW8898_BIT_PWMCTRL_HMUTE_MASK, AW8898_BIT_PWMCTRL_HMUTE_DISABLE); + } +} + +static void aw8898_run_pwd(struct aw8898 *aw8898, bool pwd) +{ + pr_debug("%s enter\n", __func__); + + if(pwd) { + aw8898_i2c_write_bits(aw8898, AW8898_REG_SYSCTRL, + AW8898_BIT_SYSCTRL_PW_MASK, AW8898_BIT_SYSCTRL_PW_PDN); + } else { + aw8898_i2c_write_bits(aw8898, AW8898_REG_SYSCTRL, + AW8898_BIT_SYSCTRL_PW_MASK, AW8898_BIT_SYSCTRL_PW_ACTIVE); + } +} + +static void aw8898_spk_rcv_mode(struct aw8898 *aw8898) +{ + pr_debug("%s spk_rcv=%d\n", __func__, aw8898->spk_rcv_mode); + + if(aw8898->spk_rcv_mode == AW8898_SPEAKER_MODE) { + aw8898_i2c_write_bits(aw8898, AW8898_REG_SYSCTRL, + AW8898_BIT_SYSCTRL_MODE_MASK, AW8898_BIT_SYSCTRL_SPK_MODE); + } else if(aw8898->spk_rcv_mode == AW8898_RECEIVER_MODE){ + aw8898_i2c_write_bits(aw8898, AW8898_REG_SYSCTRL, + AW8898_BIT_SYSCTRL_MODE_MASK, AW8898_BIT_SYSCTRL_RCV_MODE); + } else { + } +} + + +static void aw8898_start(struct aw8898 *aw8898) +{ + unsigned int reg_val = 0; + unsigned int iis_check_max = 5; + unsigned int i = 0; + + pr_debug("%s enter\n", __func__); + + aw8898_run_pwd(aw8898, false); + msleep(2); + for(i=0; ilen; i+=4) { + reg_addr = (aw8898_cont->data[i+1]<<8) + aw8898_cont->data[i+0]; + reg_val = (aw8898_cont->data[i+3]<<8) + aw8898_cont->data[i+2]; + pr_info("%s: reg=0x%04x, val = 0x%04x\n", __func__, reg_addr, reg_val); + aw8898_i2c_write(aw8898, (unsigned char)reg_addr, (unsigned int)reg_val); + } + + pr_debug("%s exit\n", __func__); +} + +static void aw8898_cfg_loaded(const struct firmware *cont, void *context) +{ + struct aw8898 *aw8898 = context; + struct aw8898_container *aw8898_cfg; + unsigned int i = 0; + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8898_cfg_name); + release_firmware(cont); + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8898_cfg_name, + cont ? cont->size : 0); + + for(i=0; isize; i++) { + pr_info("%s: addr:0x%04x, data:0x%02x\n", __func__, i, *(cont->data+i)); + } + + aw8898_cfg = kzalloc(cont->size+sizeof(int), GFP_KERNEL); + if (!aw8898_cfg) { + release_firmware(cont); + pr_err("%s: error allocating memory\n", __func__); + return; + } + aw8898_cfg->len = cont->size; + memcpy(aw8898_cfg->data, cont->data, cont->size); + release_firmware(cont); + + aw8898_container_update(aw8898, aw8898_cfg); + + kfree(aw8898_cfg); + + aw8898->init = 1; + pr_info("%s: cfg update complete\n", __func__); + + aw8898_spk_rcv_mode(aw8898); + aw8898_start(aw8898); +} + +static int aw8898_load_cfg(struct aw8898 *aw8898) +{ + pr_info("%s enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8898_cfg_name, aw8898->dev, GFP_KERNEL, + aw8898, aw8898_cfg_loaded); +} + +static void aw8898_cold_start(struct aw8898 *aw8898) +{ + int ret = -1; + + pr_info("%s enter\n", __func__); + + ret = aw8898_load_cfg(aw8898); + if(ret) { + pr_err("%s: cfg loading requested failed: %d\n", __func__, ret); + } +} + +static void aw8898_smartpa_cfg(struct aw8898 *aw8898, bool flag) +{ + pr_info("%s, flag = %d\n", __func__, flag); + + if(flag == true) { + if(aw8898->init == 0) { + pr_info("%s, init = %d\n", __func__, aw8898->init); + aw8898_cold_start(aw8898); + } else { + aw8898_spk_rcv_mode(aw8898); + aw8898_start(aw8898); + } + } else { + aw8898_stop(aw8898); + } +} + +/****************************************************** + * + * kcontrol + * + ******************************************************/ + static const char *const spk_function[] = { "Off", "On" }; + static const char *const rcv_function[] = { "Off", "On" }; + static const DECLARE_TLV_DB_SCALE(digital_gain,0,50,0); + + struct soc_mixer_control aw8898_mixer ={ + .reg = AW8898_REG_HAGCCFG7, + .shift = AW8898_VOL_REG_SHIFT, + .max = AW8898_VOLUME_MAX, + .min = AW8898_VOLUME_MIN, + }; + +static int aw8898_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 aw8898_volume_get(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + unsigned int value = 0; + struct soc_mixer_control *mc = (struct soc_mixer_control*) kcontrol->private_value; + + aw8898_i2c_read(aw8898, AW8898_REG_HAGCCFG7, ®_val); + ucontrol->value.integer.value[0] = (value >> mc->shift)\ + &(AW8898_BIT_HAGCCFG7_VOL_MASK); + return 0; +} + +static int aw8898_volume_put(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control*) kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + unsigned int value = 0; + unsigned int reg_value = 0; + + //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 -1; + } + + //smartpa have clk + aw8898_i2c_read(aw8898, AW8898_REG_SYSST, ®_value); + if(!(reg_value&AW8898_BIT_SYSST_PLLS)){ + pr_err("%s: NO I2S CLK ,cat not write reg \n",__func__); + return 0; + } + //cal real value + value = value << mc->shift&AW8898_BIT_HAGCCFG7_VOL_MASK; + aw8898_i2c_read(aw8898, AW8898_REG_HAGCCFG7, ®_value); + value = value | (reg_value&0x00ff); + + //write value + aw8898_i2c_write(aw8898, AW8898_REG_HAGCCFG7, value); + + return 0; +} + +static struct snd_kcontrol_new aw8898_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "aw8898_rx_volume", + .access= SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_READWRITE, + .tlv.p = (digital_gain), + .info = aw8898_volume_info, + .get = aw8898_volume_get, + .put = aw8898_volume_put, + .private_value = (unsigned long)&aw8898_mixer, +}; + +static int aw8898_spk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: aw8898_spk_control=%d\n", __func__, aw8898_spk_control); + ucontrol->value.integer.value[0] = aw8898_spk_control; + return 0; +} + +static int aw8898_spk_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct aw8898 *aw8898 = 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] == aw8898_spk_control) + return 1; + + aw8898_spk_control = ucontrol->value.integer.value[0]; + + aw8898->spk_rcv_mode = AW8898_SPEAKER_MODE; + + aw8898_spk_rcv_mode(aw8898); + + return 0; +} + +static int aw8898_rcv_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: aw8898_rcv_control=%d\n", __func__, aw8898_rcv_control); + ucontrol->value.integer.value[0] = aw8898_rcv_control; + return 0; +} +static int aw8898_rcv_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct aw8898 *aw8898 = 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] == aw8898_rcv_control) + return 1; + + aw8898_rcv_control = ucontrol->value.integer.value[0]; + + aw8898->spk_rcv_mode = AW8898_RECEIVER_MODE; + + aw8898_spk_rcv_mode(aw8898); + + return 0; +} +static const struct soc_enum aw8898_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rcv_function), rcv_function), +}; + +static struct snd_kcontrol_new aw8898_controls[] = { + SOC_ENUM_EXT("aw8898_speaker_switch", aw8898_snd_enum[0], + aw8898_spk_get, aw8898_spk_set), + SOC_ENUM_EXT("aw8898_receiver_switch", aw8898_snd_enum[1], + aw8898_rcv_get, aw8898_rcv_set), +}; + +static void aw8898_add_codec_controls(struct aw8898 *aw8898) +{ + pr_info("%s enter\n", __func__); + + snd_soc_add_codec_controls(aw8898->codec, aw8898_controls, + ARRAY_SIZE(aw8898_controls)); + + snd_soc_add_codec_controls(aw8898->codec, &aw8898_volume,1); +} + +/****************************************************** + * + * DAPM Widget & Route + * + ******************************************************/ +#if 0 +static struct snd_soc_dapm_widget aw8898_dapm_widgets_common[] = { + /* Stream widgets */ + SND_SOC_DAPM_AIF_IN("AIF_IN", "AW89xx_AIF_Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF_OUT", "AW89xx_AIF_Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_INPUT("AEC_Loopback"), +}; + +static const struct snd_soc_dapm_route aw8898_dapm_routes_common[] = { + { "OUTL", NULL, "AIF_IN" }, + { "AIF_OUT", NULL, "AEC_Loopback" }, +}; + +static void aw8898_add_widgets(struct aw8898 *aw8898) +{ + //struct snd_soc_dapm_context *dapm = &aw8898->codec->dapm; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(aw8898->codec); + struct snd_soc_dapm_widget *widgets; + + pr_info("%s enter\n", __func__); + widgets = devm_kzalloc(&aw8898->i2c->dev, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(aw8898_dapm_widgets_common), + GFP_KERNEL); + if (!widgets) + return; + + memcpy(widgets, aw8898_dapm_widgets_common, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(aw8898_dapm_widgets_common)); + + snd_soc_dapm_new_controls(dapm, widgets, + ARRAY_SIZE(aw8898_dapm_widgets_common)); + snd_soc_dapm_add_routes(dapm, aw8898_dapm_routes_common, + ARRAY_SIZE(aw8898_dapm_routes_common)); +} +#endif +/****************************************************** + * + * Digital Audio Interface + * + ******************************************************/ +static int aw8898_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + + pr_info("%s: enter\n", __func__); + aw8898_run_pwd(aw8898, false); + + return 0; +} + +static int aw8898_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + //struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_codec *codec = dai->codec; + + pr_info("%s: fmt=0x%x\n", __func__, fmt); + + /* Supported mode: regular I2S, slave, or PDM */ + 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 master 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 aw8898_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec_dai->codec); + + pr_info("%s: freq=%d\n", __func__, freq); + + aw8898->sysclk = freq; + return 0; +} + +static int aw8898_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + unsigned int rate = 0; + int reg_value = 0; + int width = 0; + /* Supported */ + + //get rate param + aw8898->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 = AW8898_BIT_I2SCTRL_SR_8K; + break; + case 16000: + reg_value = AW8898_BIT_I2SCTRL_SR_16K; + break; + case 32000: + reg_value = AW8898_BIT_I2SCTRL_SR_32K; + break; + case 44100: + reg_value = AW8898_BIT_I2SCTRL_SR_44P1K; + break; + case 48000: + reg_value = AW8898_BIT_I2SCTRL_SR_48K; + break; + default: + reg_value = AW8898_BIT_I2SCTRL_SR_48K; + pr_err("%s: rate can not support\n", __func__); + break; + } + //set chip rate + if(-1 != reg_value){ + aw8898_i2c_write_bits(aw8898, AW8898_REG_I2SCTRL, + AW8898_BIT_I2SCTRL_SR_MASK, reg_value); + } + + //get bit width + width = params_width(params); + pr_debug("%s: width = %d \n",__func__,width); + switch(width) + { + case 16: + reg_value = AW8898_BIT_I2SCTRL_FMS_16BIT; + break; + case 20: + reg_value = AW8898_BIT_I2SCTRL_FMS_20BIT; + break; + case 24: + reg_value = AW8898_BIT_I2SCTRL_FMS_24BIT; + break; + case 32: + reg_value = AW8898_BIT_I2SCTRL_FMS_32BIT; + break; + default: + reg_value = AW8898_BIT_I2SCTRL_FMS_16BIT; + pr_err("%s: width can not support\n", __func__); + break; + } + //set width + if(-1 != reg_value){ + aw8898_i2c_write_bits(aw8898, AW8898_REG_I2SCTRL, + AW8898_BIT_I2SCTRL_FMS_MASK, reg_value); + } + + return 0; +} + +static int aw8898_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + + pr_info("%s: mute state=%d\n", __func__, mute); + + if (!(aw8898->flags & AW8898_FLAG_START_ON_MUTE)) + return 0; + + if (mute) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + aw8898->pstream = 0; + else + aw8898->cstream = 0; + if (aw8898->pstream != 0 || aw8898->cstream != 0) + return 0; + + mutex_lock(&aw8898->cfg_lock); + aw8898_smartpa_cfg(aw8898, false); + mutex_unlock(&aw8898->cfg_lock); + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + aw8898->pstream = 1; + else + aw8898->cstream = 1; + + mutex_lock(&aw8898->cfg_lock); + aw8898_smartpa_cfg(aw8898, true); + mutex_unlock(&aw8898->cfg_lock); + } + + return 0; +} + +static void aw8898_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + + aw8898->rate = 0; + aw8898_run_pwd(aw8898, true); +} + +static const struct snd_soc_dai_ops aw8898_dai_ops = { + .startup = aw8898_startup, + .set_fmt = aw8898_set_fmt, + .set_sysclk = aw8898_set_dai_sysclk, + .hw_params = aw8898_hw_params, + .mute_stream = aw8898_mute, + .shutdown = aw8898_shutdown, +}; + +static struct snd_soc_dai_driver aw8898_dai[] = { + { + .name = "aw8898-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW8898_RATES, + .formats = AW8898_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW8898_RATES, + .formats = AW8898_FORMATS, + }, + .ops = &aw8898_dai_ops, + .symmetric_rates = 1, + .symmetric_channels = 1, + .symmetric_samplebits = 1, + }, +}; + +/***************************************************** + * + * codec driver + * + *****************************************************/ +static int aw8898_probe(struct snd_soc_codec *codec) +{ + struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + pr_info("%s enter\n", __func__); + + aw8898->codec = codec; + + //aw8898_add_widgets(aw8898); + + aw8898_add_codec_controls(aw8898); + + if (codec->dev->of_node) + dev_set_name(codec->dev, "%s", "aw8898_smartpa"); + + pr_info("%s exit\n", __func__); + + return ret; +} + +static int aw8898_remove(struct snd_soc_codec *codec) +{ + //struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + pr_info("%s enter\n", __func__); + + //aw8898_inputdev_unregister(aw8898); + + return 0; +} + +/* +struct regmap *aw8898_get_regmap(struct device *dev) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + + return aw8898->regmap; +} +*/ + +static unsigned int aw8898_codec_read(struct snd_soc_codec *codec,unsigned int reg) +{ + struct aw8898 *aw8898=snd_soc_codec_get_drvdata(codec); + unsigned int value =0; + int ret; + pr_debug("%s:enter \n",__func__); + + if(aw8898_reg_access[reg]®_RD_ACCESS){ + ret=aw8898_i2c_read(aw8898,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 -1; + } + return value; +} + +static int aw8898_codec_write(struct snd_soc_codec *codec,unsigned int reg,unsigned int value) +{ + int ret ; + struct aw8898 *aw8898=snd_soc_codec_get_drvdata(codec); + pr_debug("%s:enter ,reg is 0x%x value is 0x%x\n",__func__,reg,value); + + if(aw8898_reg_access[reg]®_WR_ACCESS){ + ret=aw8898_i2c_write(aw8898,reg,value); + return ret; + }else{ + pr_debug("%s: Register 0x%x NO write access \n",__func__,reg); + } + + return -1; +} +/* +static int aw8898_codec_readable(struct snd_soc_codec *codec,unsigned int reg) +{ + return aw8898_reg_access[reg]®_RD_ACCESS; +} +*/ +static struct snd_soc_codec_driver soc_codec_dev_aw8898 = { + .probe = aw8898_probe, + .remove = aw8898_remove, + //.get_regmap = aw8898_get_regmap, + .read = aw8898_codec_read, + .write= aw8898_codec_write, + .reg_cache_size= AW8898_REG_MAX, + .reg_word_size=2, +}; + +/***************************************************** + * + * regmap + * + *****************************************************/ +bool aw8898_writeable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +bool aw8898_readable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +bool aw8898_volatile_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static const struct regmap_config aw8898_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = AW8898_MAX_REGISTER, + .writeable_reg = aw8898_writeable_register, + .readable_reg = aw8898_readable_register, + .volatile_reg = aw8898_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +/****************************************************** + * + * irq + * + ******************************************************/ +static void aw8898_interrupt_setup(struct aw8898 *aw8898) +{ + unsigned int reg_val; + + pr_info("%s enter\n", __func__); + + aw8898_i2c_read(aw8898, AW8898_REG_SYSINTM, ®_val); + reg_val &= (~AW8898_BIT_SYSINTM_PLLM); + reg_val &= (~AW8898_BIT_SYSINTM_OTHM); + reg_val &= (~AW8898_BIT_SYSINTM_OCDM); + aw8898_i2c_write(aw8898, AW8898_REG_SYSINTM, reg_val); +} + +static void aw8898_interrupt_clear(struct aw8898 *aw8898) +{ + unsigned int reg_val = 0; + + pr_info("%s enter\n", __func__); + + aw8898_i2c_read(aw8898, AW8898_REG_SYSST, ®_val); + pr_info("%s: reg SYSST=0x%x\n", __func__, reg_val); + + aw8898_i2c_read(aw8898, AW8898_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + + aw8898_i2c_read(aw8898, AW8898_REG_SYSINTM, ®_val); + pr_info("%s: reg SYSINTM=0x%x\n", __func__, reg_val); +} + +static irqreturn_t aw8898_irq(int irq, void *data) +{ + struct aw8898 *aw8898 = data; + + pr_info("%s enter\n", __func__); + + aw8898_interrupt_clear(aw8898); + + pr_info("%s exit\n", __func__); + + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw8898_parse_dt(struct device *dev, struct aw8898 *aw8898, + struct device_node *np) +{ + aw8898->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw8898->reset_gpio < 0) { + dev_err(dev, "%s: no reset gpio provided, will not HW reset device\n", __func__); + return -1; + } else { + dev_info(dev, "%s: reset gpio provided ok\n", __func__); + } + aw8898->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw8898->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 aw8898_hw_reset(struct aw8898 *aw8898) +{ + pr_info("%s enter\n", __func__); + + if (aw8898 && gpio_is_valid(aw8898->reset_gpio)) { + gpio_set_value_cansleep(aw8898->reset_gpio, 0); + msleep(1); + gpio_set_value_cansleep(aw8898->reset_gpio, 1); + msleep(1); + } else { + dev_err(aw8898->dev, "%s: failed\n", __func__); + } + return 0; +} + +/***************************************************** + * + * check chip id + * + *****************************************************/ +int aw8898_read_chipid(struct aw8898 *aw8898) +{ + int ret = -1; + unsigned int cnt = 0; + unsigned int reg = 0; + + while(cnt < AW_READ_CHIPID_RETRIES) { + ret = aw8898_i2c_read(aw8898, AW8898_REG_ID, ®); + if (ret < 0) { + dev_err(aw8898->dev, "%s: failed to read register AW8898_REG_ID: %d\n", __func__, ret); + return -EIO; + } + switch (reg) { + case 0x1702: + pr_info("%s aw8898 detected\n", __func__); + aw8898->flags |= AW8898_FLAG_SKIP_INTERRUPTS; + aw8898->flags |= AW8898_FLAG_START_ON_MUTE; + aw8898->chipid = AW8898_ID; + pr_info("%s aw8898->flags=0x%x\n", __func__, aw8898->flags); + return 0; + default: + pr_info("%s unsupported device revision (0x%x)\n", __func__, reg ); + break; + } + cnt ++; + + msleep(AW_READ_CHIPID_RETRY_DELAY); + } + + return -EINVAL; +} + +/***************************************************** + * + * vbat monitor + * + *****************************************************/ +#ifdef AW8898_VBAT_MONITOR +static int aw8898_vbat_monitor_stop(struct aw8898 *aw8898) +{ + pr_info("%s enter\n", __func__); + + if(hrtimer_active(&aw8898->vbat_monitor_timer)) { + pr_info("%s: cancel vbat monitor\n", __func__); + hrtimer_cancel(&aw8898->vbat_monitor_timer); + } + return 0; +} + +static int aw8898_vbat_monitor_start(struct aw8898 *aw8898) +{ + int ram_timer_val = 30000; + + pr_info("%s enter\n", __func__); + + if(hrtimer_active(&aw8898->vbat_monitor_timer)) { + } else { + pr_info("%s: start vbat monitor\n", __func__); + hrtimer_start(&aw8898->vbat_monitor_timer, + ktime_set(ram_timer_val/1000, (ram_timer_val%1000)*1000000), + HRTIMER_MODE_REL); + } + return 0; +} + +static enum hrtimer_restart aw8898_vbat_monitor_timer_func(struct hrtimer *timer) +{ + struct aw8898 *aw8898 = container_of(timer, struct aw8898, vbat_monitor_timer); + + pr_info("%s enter\n", __func__); + + schedule_work(&aw8898->vbat_monitor_work); + + return HRTIMER_NORESTART; +} + +static int aw8898_get_sys_battery_info(char *dev) +{ + int fd; + int eCheck; + int nReadSize; + char buf[64],*pvalue; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + fd = sys_open(dev, O_RDONLY, 0); + if (fd < 0) { + pr_err("%s: open fail dev:%s fd:%d\n", __func__, dev, fd); + set_fs(oldfs); + return fd; + } + + nReadSize = sys_read(fd, buf, sizeof(buf) - 1); + pr_debug("%s: nReadSize:%d\n", __func__, nReadSize); + + eCheck = simple_strtoul(buf,&pvalue,10); + pr_debug("%s: eCheck = %d\n", __func__, eCheck); + + set_fs(oldfs); + sys_close(fd); + + if (eCheck > 0) + return eCheck; + else + return 0; +} + +static void aw8898_vbat_monitor_work_routine(struct work_struct *work) +{ + struct aw8898 *aw8898 = container_of(work, struct aw8898, vbat_monitor_work); + unsigned int reg_val = 0; + int sys_vbat_vol = 0; + + pr_info("%s enter\n", __func__); + + aw8898_i2c_read(aw8898, AW8898_REG_PWMCTRL, ®_val); + if((reg_val&AW8898_BIT_PWMCTRL_HMUTE_ENABLE) == AW8898_BIT_PWMCTRL_HMUTE_DISABLE) { + sys_vbat_vol = aw8898_get_sys_battery_info(SYS_BAT_DEV); + pr_info("%s: get sys battery = %d\n", __func__, sys_vbat_vol); + if((sys_vbat_vol < AW8898_SYS_VBAT_LIMIT) && (sys_vbat_vol > AW8898_SYS_VBAT_MIN)) { + aw8898_i2c_write_bits(aw8898, AW8898_REG_GENCTRL, + AW8898_BIT_GENCTRL_BST_ILIMIT_MASK, (aw8898->bst_ilimit<<4)); + } + aw8898_vbat_monitor_start(aw8898); + } +} + +static int aw8898_vbat_monitor_init(struct aw8898 *aw8898) +{ + pr_info("%s enter\n", __func__); + + aw8898->bst_ilimit = 0x00; + + hrtimer_init(&aw8898->vbat_monitor_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8898->vbat_monitor_timer.function = aw8898_vbat_monitor_timer_func; + INIT_WORK(&aw8898->vbat_monitor_work, aw8898_vbat_monitor_work_routine); + return 0; +} +#endif +/****************************************************** + * + * sys bin attribute + * + *****************************************************/ +static ssize_t aw8898_reg_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct aw8898 *aw8898 = dev_get_drvdata(dev); + + if (count != 1) { + pr_info("invalid register address"); + return -EINVAL; + } + + aw8898->reg = buf[0]; + + return 1; +} + +static ssize_t aw8898_rw_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct aw8898 *aw8898 = dev_get_drvdata(dev); + u8 *data; + int ret; + int retries = AW_I2C_RETRIES; + + data = kmalloc(count+1, GFP_KERNEL); + if (data == NULL) { + pr_err("can not allocate memory\n"); + return -ENOMEM; + } + + data[0] = aw8898->reg; + memcpy(&data[1], buf, count); + + retry: + ret = i2c_master_send(aw8898->i2c, data, count+1); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(AW_I2C_RETRY_DELAY); + goto retry; + } + } + + kfree(data); + return ret; +} + +static ssize_t aw8898_rw_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct aw8898 *aw8898 = dev_get_drvdata(dev); + struct i2c_msg msgs[] = { + { + .addr = aw8898->i2c->addr, + .flags = 0, + .len = 1, + .buf = &aw8898->reg, + }, + { + .addr = aw8898->i2c->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + int ret; + int retries = AW_I2C_RETRIES; + retry: + ret = i2c_transfer(aw8898->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(AW_I2C_RETRY_DELAY); + goto retry; + } + return ret; + } + /* ret contains the number of i2c messages send */ + return 1 + ((ret > 1) ? count : 0); +} + +static struct bin_attribute dev_attr_rw = { + .attr = { + .name = "rw", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = aw8898_rw_read, + .write = aw8898_rw_write, +}; + +static struct bin_attribute dev_attr_regaddr = { + .attr = { + .name = "regaddr", + .mode = S_IWUSR, + }, + .size = 0, + .read = NULL, + .write = aw8898_reg_write, +}; + +/****************************************************** + * + * sys group attribute: reg + * + ******************************************************/ +static ssize_t aw8898_reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8898_i2c_write(aw8898, databuf[0], databuf[1]); + } + + return count; +} + +static ssize_t aw8898_reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned int reg_val = 0; + for(i = 0; i < AW8898_REG_MAX; i ++) { + if(!(aw8898_reg_access[i]®_RD_ACCESS)) + continue; + aw8898_i2c_read(aw8898, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%04x \n", i, reg_val); + } + return len; +} + +static ssize_t aw8898_spk_rcv_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if(1 == sscanf(buf, "%d", &databuf[0])) { + aw8898->spk_rcv_mode = databuf[0]; + } + + return count; +} + +static ssize_t aw8898_spk_rcv_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + ssize_t len = 0; + if(aw8898->spk_rcv_mode == AW8898_SPEAKER_MODE) { + len += snprintf(buf+len, PAGE_SIZE-len, "aw8898 spk_rcv: %d, speaker mode\n", aw8898->spk_rcv_mode); + } else if (aw8898->spk_rcv_mode == AW8898_RECEIVER_MODE) { + len += snprintf(buf+len, PAGE_SIZE-len, "aw8898 spk_rcv: %d, receiver mode\n", aw8898->spk_rcv_mode); + } else { + len += snprintf(buf+len, PAGE_SIZE-len, "aw8898 spk_rcv: %d, unknown mode\n", aw8898->spk_rcv_mode); + } + + return len; +} + +static ssize_t aw8898_bst_ilimit_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + if(1 == sscanf(buf, "%x", &databuf[0])) { + aw8898->bst_ilimit = databuf[0]; + } + + return count; +} + +static ssize_t aw8898_bst_ilimit_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8898 *aw8898 = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "aw8898 bst_ilimit=0x%02x\n", aw8898->bst_ilimit); + + return len; +} +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8898_reg_show, aw8898_reg_store); +static DEVICE_ATTR(spk_rcv, S_IWUSR | S_IRUGO, aw8898_spk_rcv_show, aw8898_spk_rcv_store); +static DEVICE_ATTR(bst_ilimit, S_IWUSR | S_IRUGO, aw8898_bst_ilimit_show, aw8898_bst_ilimit_store); + +static struct attribute *aw8898_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_spk_rcv.attr, + &dev_attr_bst_ilimit.attr, + NULL +}; + +static struct attribute_group aw8898_attribute_group = { + .attrs = aw8898_attributes +}; + + +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw8898_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai; + struct aw8898 *aw8898; + struct device_node *np = i2c->dev.of_node; + int irq_flags = 0; + int ret = -1; + + pr_info("%s enter\n", __func__); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw8898 = devm_kzalloc(&i2c->dev, sizeof(struct aw8898), GFP_KERNEL); + if (aw8898 == NULL) + return -ENOMEM; + + aw8898->dev = &i2c->dev; + aw8898->i2c = i2c; + + /* aw8898 regmap */ + aw8898->regmap = devm_regmap_init_i2c(i2c, &aw8898_regmap); + if (IS_ERR(aw8898->regmap)) { + ret = PTR_ERR(aw8898->regmap); + dev_err(&i2c->dev, "%s: failed to allocate register map: %d\n", __func__, ret); + goto err_regmap; + } + + i2c_set_clientdata(i2c, aw8898); + mutex_init(&aw8898->cfg_lock); + + /* aw8898 rst & int */ + if (np) { + ret = aw8898_parse_dt(&i2c->dev, aw8898, np); + if (ret) { + dev_err(&i2c->dev, "%s: failed to parse device tree node\n", __func__); + goto err_parse_dt; + } + } else { + aw8898->reset_gpio = -1; + aw8898->irq_gpio = -1; + } + + if (gpio_is_valid(aw8898->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8898->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw8898_rst"); + if (ret){ + dev_err(&i2c->dev, "%s: rst request failed\n", __func__); + goto err_gpio_request; + } + } + + if (gpio_is_valid(aw8898->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8898->irq_gpio, + GPIOF_DIR_IN, "aw8898_int"); + if (ret){ + dev_err(&i2c->dev, "%s: int request failed\n", __func__); + goto err_gpio_request; + } + } + + /* hardware reset */ + aw8898_hw_reset(aw8898); + + /* aw8898 chip id */ + ret = aw8898_read_chipid(aw8898); + if (ret < 0) { + dev_err(&i2c->dev, "%s: aw8898_read_chipid failed ret=%d\n", __func__, ret); + goto err_id; + } + + /* aw8898 device name */ + if (i2c->dev.of_node) { + dev_set_name(&i2c->dev, "%s", "aw8898_smartpa"); + } else { + dev_err(&i2c->dev, "%s failed to set device name: %d\n", __func__, ret); + } + + /* register codec */ + dai = devm_kzalloc(&i2c->dev, sizeof(aw8898_dai), GFP_KERNEL); + if (!dai) { + goto err_dai_kzalloc; + } + memcpy(dai, aw8898_dai, sizeof(aw8898_dai)); + pr_info("%s dai->name(%s)\n", __func__, dai->name); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aw8898, + dai, ARRAY_SIZE(aw8898_dai)); + if (ret < 0) { + dev_err(&i2c->dev, "%s failed to register aw8898: %d\n", __func__, ret); + goto err_register_codec; + } + + /* aw8898 irq */ + if (gpio_is_valid(aw8898->irq_gpio) && + !(aw8898->flags & AW8898_FLAG_SKIP_INTERRUPTS)) { + aw8898_interrupt_setup(aw8898); + /* register irq handler */ + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw8898->irq_gpio), + NULL, aw8898_irq, irq_flags, + "aw8898", aw8898); + if (ret != 0) { + dev_err(&i2c->dev, "failed to request IRQ %d: %d\n", + gpio_to_irq(aw8898->irq_gpio), ret); + goto err_irq; + } + } else { + dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + aw8898->flags |= AW8898_FLAG_SKIP_INTERRUPTS; + } + + /* Register the sysfs files for climax backdoor access */ + ret = device_create_bin_file(&i2c->dev, &dev_attr_rw); + if (ret) + dev_info(&i2c->dev, "%s error creating sysfs files: rw\n", __func__); + ret = device_create_bin_file(&i2c->dev, &dev_attr_regaddr); + if (ret) + dev_info(&i2c->dev, "%s error creating sysfs files: regaddr\n", __func__); + + dev_set_drvdata(&i2c->dev, aw8898); + ret = sysfs_create_group(&i2c->dev.kobj, &aw8898_attribute_group); + if (ret < 0) { + dev_info(&i2c->dev, "%s error creating sysfs attr files\n", __func__); + goto err_sysfs; + } + +#ifdef AW8898_VBAT_MONITOR + aw8898_vbat_monitor_init(aw8898); +#endif + pr_info("%s probe completed successfully!\n", __func__); + + return 0; + +err_sysfs: + device_remove_bin_file(&i2c->dev, &dev_attr_regaddr); + device_remove_bin_file(&i2c->dev, &dev_attr_rw); + devm_free_irq(&i2c->dev, gpio_to_irq(aw8898->irq_gpio), aw8898); +err_irq: + 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(aw8898->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8898->reset_gpio); + if (gpio_is_valid(aw8898->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8898->irq_gpio); +err_gpio_request: +err_parse_dt: +err_regmap: + devm_kfree(&i2c->dev, aw8898); + aw8898 = NULL; + return ret; +} + +static int aw8898_i2c_remove(struct i2c_client *i2c) +{ + struct aw8898 *aw8898 = i2c_get_clientdata(i2c); + + pr_info("%s enter\n", __func__); + + device_remove_bin_file(&i2c->dev, &dev_attr_regaddr); + device_remove_bin_file(&i2c->dev, &dev_attr_rw); + devm_free_irq(&i2c->dev, gpio_to_irq(aw8898->irq_gpio), aw8898); + + snd_soc_unregister_codec(&i2c->dev); + + if (gpio_is_valid(aw8898->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8898->irq_gpio); + if (gpio_is_valid(aw8898->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8898->reset_gpio); + + return 0; +} + +static const struct i2c_device_id aw8898_i2c_id[] = { + { AW8898_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw8898_i2c_id); + +static struct of_device_id aw8898_dt_match[] = { + { .compatible = "awinic,aw8898_smartpa" }, + { }, +}; + +static struct i2c_driver aw8898_i2c_driver = { + .driver = { + .name = AW8898_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw8898_dt_match), + }, + .probe = aw8898_i2c_probe, + .remove = aw8898_i2c_remove, + .id_table = aw8898_i2c_id, +}; + + +static int __init aw8898_i2c_init(void) +{ + int ret = 0; + + pr_info("aw8898 driver version %s\n", AW8898_VERSION); + + ret = i2c_add_driver(&aw8898_i2c_driver); + if(ret){ + pr_err("fail to add aw8898 device into i2c\n"); + return ret; + } + + return 0; +} +module_init(aw8898_i2c_init); + + +static void __exit aw8898_i2c_exit(void) +{ + i2c_del_driver(&aw8898_i2c_driver); +} +module_exit(aw8898_i2c_exit); + + +MODULE_DESCRIPTION("ASoC AW8898 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw/aw8898.h b/sound/soc/codecs/aw/aw8898.h new file mode 100644 index 00000000000000..2042f5ecf57bc2 --- /dev/null +++ b/sound/soc/codecs/aw/aw8898.h @@ -0,0 +1,72 @@ +#ifndef _AW8898_H_ +#define _AW8898_H_ + + +/* + * i2c transaction on Linux limited to 64k + * (See Linux kernel documentation: Documentation/i2c/writing-clients) +*/ +#define MAX_I2C_BUFFER_SIZE 65536 + +#define AW8898_FLAG_START_ON_MUTE (1 << 0) +#define AW8898_FLAG_SKIP_INTERRUPTS (1 << 1) +#define AW8898_FLAG_SAAM_AVAILABLE (1 << 2) +#define AW8898_FLAG_STEREO_DEVICE (1 << 3) +#define AW8898_FLAG_MULTI_MIC_INPUTS (1 << 4) + +#define AW8898_NUM_RATES 9 + +#define AW8898_MAX_REGISTER 0xff + +//#define AW8898_VBAT_MONITOR +#ifdef AW8898_VBAT_MONITOR +#define SYS_BAT_DEV "/sys/class/power_supply/battery/voltage_now" +#define AW8898_SYS_VBAT_LIMIT 3600000 +#define AW8898_SYS_VBAT_MIN 3000000 +#endif +enum aw8898_chipid{ + AW8898_ID, +}; + +enum aw8898_mode_spk_rcv{ + AW8898_SPEAKER_MODE = 0, + AW8898_RECEIVER_MODE = 1, +}; + +struct aw8898 { + struct regmap *regmap; + struct i2c_client *i2c; + struct snd_soc_codec *codec; + struct device *dev; + struct mutex cfg_lock; +#ifdef AW8898_VBAT_MONITOR + struct hrtimer vbat_monitor_timer; + struct work_struct vbat_monitor_work; +#endif + int sysclk; + int rate; + int pstream; + int cstream; + + int reset_gpio; + int irq_gpio; + +#ifdef CONFIG_DEBUG_FS + struct dentry *dbg_dir; +#endif + u8 reg; + + unsigned int flags; + unsigned int chipid; + unsigned int init; + unsigned int spk_rcv_mode; + unsigned int bst_ilimit; +}; + +struct aw8898_container{ + int len; + unsigned char data[]; +}; + + +#endif diff --git a/sound/soc/codecs/aw/aw8898_reg.h b/sound/soc/codecs/aw/aw8898_reg.h new file mode 100644 index 00000000000000..c66927c8277e0b --- /dev/null +++ b/sound/soc/codecs/aw/aw8898_reg.h @@ -0,0 +1,448 @@ +#ifndef _AW8898_REG_H_ +#define _AW8898_REG_H_ + +/******************************************** + * Register List + *******************************************/ +#define AW8898_REG_ID 0x00 +#define AW8898_REG_SYSST 0x01 +#define AW8898_REG_SYSINT 0x02 +#define AW8898_REG_SYSINTM 0x03 +#define AW8898_REG_SYSCTRL 0x04 +#define AW8898_REG_I2SCTRL 0x05 +#define AW8898_REG_I2STXCFG 0x06 +#define AW8898_REG_PWMCTRL 0x08 +#define AW8898_REG_HAGCCFG1 0x09 +#define AW8898_REG_HAGCCFG2 0x0A +#define AW8898_REG_HAGCCFG3 0x0B +#define AW8898_REG_HAGCCFG4 0x0C +#define AW8898_REG_HAGCCFG5 0x0D +#define AW8898_REG_HAGCCFG6 0x0E +#define AW8898_REG_HAGCCFG7 0x0F +#define AW8898_REG_HAGCST 0x10 +#define AW8898_REG_DBGCTRL 0x20 +#define AW8898_REG_I2SCFG 0x21 +#define AW8898_REG_I2SSTAT 0x22 +#define AW8898_REG_I2SCAPCNT 0x23 +#define AW8898_REG_GENCTRL 0x60 +#define AW8898_REG_BSTCTRL1 0x61 +#define AW8898_REG_BSTCTRL2 0x62 +#define AW8898_REG_PLLCTRL1 0x63 +#define AW8898_REG_PLLCTRL2 0x64 +#define AW8898_REG_TESTCTRL 0x65 +#define AW8898_REG_AMPDBG1 0x66 +#define AW8898_REG_AMPDBG2 0x67 +#define AW8898_REG_BSTDBG1 0x68 +#define AW8898_REG_CDACTRL1 0x69 +#define AW8898_REG_CDACTRL2 0x6A +#define AW8898_REG_TESTCTRL2 0x6B + +#define AW8898_REG_MAX 0x6F + +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS 0 +#define REG_RD_ACCESS 1 << 0 +#define REG_WR_ACCESS 1 << 1 + +const unsigned char aw8898_reg_access[AW8898_REG_MAX]={ + [AW8898_REG_ID ]= REG_RD_ACCESS, + [AW8898_REG_SYSST ]= REG_RD_ACCESS, + [AW8898_REG_SYSINT ]= REG_RD_ACCESS, + [AW8898_REG_SYSINTM ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_SYSCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_I2SCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_I2STXCFG ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_PWMCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG2 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG3 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG4 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG5 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG6 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCCFG7 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_HAGCST ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_DBGCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_I2SCFG ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_I2SSTAT ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_I2SCAPCNT ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_GENCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_BSTCTRL1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_BSTCTRL2 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_PLLCTRL1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_PLLCTRL2 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_TESTCTRL ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_AMPDBG1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_AMPDBG2 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_BSTDBG1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_CDACTRL1 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_CDACTRL2 ]= REG_RD_ACCESS|REG_WR_ACCESS, + [AW8898_REG_TESTCTRL2 ]= REG_RD_ACCESS|REG_WR_ACCESS, +}; + +/****************************************************** + * Register Detail + *****************************************************/ +// SYSST +#define AW8898_BIT_SYSST_UVLOS ( 1<<14) +#define AW8898_BIT_SYSST_ADPS ( 1<<13) +#define AW8898_BIT_SYSST_DSPS ( 1<<12) +#define AW8898_BIT_SYSST_BSTOCS ( 1<<11) +#define AW8898_BIT_SYSST_OVPS ( 1<<10) +#define AW8898_BIT_SYSST_BSTS ( 1<< 9) +#define AW8898_BIT_SYSST_SWS ( 1<< 8) +#define AW8898_BIT_SYSST_CLIPS ( 1<< 7) +#define AW8898_BIT_SYSST_WDS ( 1<< 6) +#define AW8898_BIT_SYSST_NOCLKS ( 1<< 5) +#define AW8898_BIT_SYSST_CLKS ( 1<< 4) +#define AW8898_BIT_SYSST_OCDS ( 1<< 3) +#define AW8898_BIT_SYSST_OTLS ( 1<< 2) +#define AW8898_BIT_SYSST_OTHS ( 1<< 1) +#define AW8898_BIT_SYSST_PLLS ( 1<< 0) + +// SYSINT +#define AW8898_BIT_SYSINT_UVLOI ( 1<<14) +#define AW8898_BIT_SYSINT_ADPI ( 1<<13) +#define AW8898_BIT_SYSINT_DSPI ( 1<<12) +#define AW8898_BIT_SYSINT_BSTOCI ( 1<<11) +#define AW8898_BIT_SYSINT_OVPI ( 1<<10) +#define AW8898_BIT_SYSINT_BSTI ( 1<< 9) +#define AW8898_BIT_SYSINT_SWI ( 1<< 8) +#define AW8898_BIT_SYSINT_CLIPI ( 1<< 7) +#define AW8898_BIT_SYSINT_WDI ( 1<< 6) +#define AW8898_BIT_SYSINT_NOCLKI ( 1<< 5) +#define AW8898_BIT_SYSINT_CLKI ( 1<< 4) +#define AW8898_BIT_SYSINT_OCDI ( 1<< 3) +#define AW8898_BIT_SYSINT_OTLI ( 1<< 2) +#define AW8898_BIT_SYSINT_OTHI ( 1<< 1) +#define AW8898_BIT_SYSINT_PLLI ( 1<< 0) + +// SYSINTM +#define AW8898_BIT_SYSINTM_UVLOM ( 1<<14) +#define AW8898_BIT_SYSINTM_ADPM ( 1<<13) +#define AW8898_BIT_SYSINTM_DSPM ( 1<<12) +#define AW8898_BIT_SYSINTM_BSTOCM ( 1<<11) +#define AW8898_BIT_SYSINTM_OVPM ( 1<<10) +#define AW8898_BIT_SYSINTM_BSTM ( 1<< 9) +#define AW8898_BIT_SYSINTM_SWM ( 1<< 8) +#define AW8898_BIT_SYSINTM_CLIPM ( 1<< 7) +#define AW8898_BIT_SYSINTM_WDM ( 1<< 6) +#define AW8898_BIT_SYSINTM_NOCLKM ( 1<< 5) +#define AW8898_BIT_SYSINTM_CLKM ( 1<< 4) +#define AW8898_BIT_SYSINTM_OCDM ( 1<< 3) +#define AW8898_BIT_SYSINTM_OTLM ( 1<< 2) +#define AW8898_BIT_SYSINTM_OTHM ( 1<< 1) +#define AW8898_BIT_SYSINTM_PLLM ( 1<< 0) + +// SYSCTRL +#define AW8898_BIT_SYSCTRL_INTMODE_MASK (~( 3<< 8)) +#define AW8898_BIT_SYSCTRL_INT_HIGH_PP ( 3<< 8) +#define AW8898_BIT_SYSCTRL_INT_LOW_PP ( 2<< 8) +#define AW8898_BIT_SYSCTRL_INT_HIGH_OD ( 1<< 8) +#define AW8898_BIT_SYSCTRL_INT_LOW_OD ( 0<< 8) +#define AW8898_BIT_SYSCTRL_MODE_MASK (~( 1<< 7)) +#define AW8898_BIT_SYSCTRL_RCV_MODE ( 1<< 7) +#define AW8898_BIT_SYSCTRL_SPK_MODE ( 0<< 7) +#define AW8898_BIT_SYSCTRL_I2SEN_MASK (~( 1<< 6)) +#define AW8898_BIT_SYSCTRL_I2S_ENABLE ( 1<< 6) +#define AW8898_BIT_SYSCTRL_I2S_DISABLE ( 0<< 6) +#define AW8898_BIT_SYSCTRL_WSINV_MASK (~( 1<< 5)) +#define AW8898_BIT_SYSCTRL_WS_INVERT ( 1<< 5) +#define AW8898_BIT_SYSCTRL_WS_NO_INVERT ( 0<< 5) +#define AW8898_BIT_SYSCTRL_BCKINV_MASK (~( 1<< 4)) +#define AW8898_BIT_SYSCTRL_BCK_INVERT ( 1<< 4) +#define AW8898_BIT_SYSCTRL_BCK_NO_INVERT ( 0<< 4) +#define AW8898_BIT_SYSCTRL_IPLL_MASK (~( 1<< 3)) +#define AW8898_BIT_SYSCTRL_PLL_WORD ( 1<< 3) +#define AW8898_BIT_SYSCTRL_PLL_BIT ( 0<< 3) +#define AW8898_BIT_SYSCTRL_DSPBY_MASK (~( 1<< 2)) +#define AW8898_BIT_SYSCTRL_DSP_BYPASS ( 1<< 2) +#define AW8898_BIT_SYSCTRL_DSP_WORK ( 0<< 2) +#define AW8898_BIT_SYSCTRL_CP_MASK (~( 1<< 1)) +#define AW8898_BIT_SYSCTRL_CP_PDN ( 1<< 1) +#define AW8898_BIT_SYSCTRL_CP_ACTIVE ( 0<< 1) +#define AW8898_BIT_SYSCTRL_PW_MASK (~( 1<< 0)) +#define AW8898_BIT_SYSCTRL_PW_PDN ( 1<< 0) +#define AW8898_BIT_SYSCTRL_PW_ACTIVE ( 0<< 0) + +// I2SCTRL +#define AW8898_BIT_I2SCTRL_INPLEV_MASK (~( 1<<13)) +#define AW8898_BIT_I2SCTRL_INPLEV_0DB ( 1<<13) +#define AW8898_BIT_I2SCTRL_INPLEV_NEG_6DB ( 0<<13) +#define AW8898_BIT_I2SCTRL_STEREO_MASK (~( 1<<12)) +#define AW8898_BIT_I2SCTRL_STEREO_ENABLE ( 1<<12) +#define AW8898_BIT_I2SCTRL_STEREO_DISABLE ( 0<<12) +#define AW8898_BIT_I2SCTRL_CHS_MASK (~( 3<<10)) +#define AW8898_BIT_I2SCTRL_CHS_MONO ( 3<<10) +#define AW8898_BIT_I2SCTRL_CHS_RIGHT ( 2<<10) +#define AW8898_BIT_I2SCTRL_CHS_LEFT ( 1<<10) +#define AW8898_BIT_I2SCTRL_MD_MASK (~( 3<< 8)) +#define AW8898_BIT_I2SCTRL_MD_LSB ( 2<< 8) +#define AW8898_BIT_I2SCTRL_MD_MSB ( 1<< 8) +#define AW8898_BIT_I2SCTRL_MD_STD ( 0<< 8) +#define AW8898_BIT_I2SCTRL_FMS_MASK (~( 3<< 6)) +#define AW8898_BIT_I2SCTRL_FMS_32BIT ( 3<< 6) +#define AW8898_BIT_I2SCTRL_FMS_24BIT ( 2<< 6) +#define AW8898_BIT_I2SCTRL_FMS_20BIT ( 1<< 6) +#define AW8898_BIT_I2SCTRL_FMS_16BIT ( 0<< 6) +#define AW8898_BIT_I2SCTRL_BCK_MASK (~( 3<< 4)) +#define AW8898_BIT_I2SCTRL_BCK_64FS ( 2<< 4) +#define AW8898_BIT_I2SCTRL_BCK_48FS ( 1<< 4) +#define AW8898_BIT_I2SCTRL_BCK_32FS ( 0<< 4) +#define AW8898_BIT_I2SCTRL_SR_MASK (~(15<< 0)) +#define AW8898_BIT_I2SCTRL_SR_192K (10<< 0) +#define AW8898_BIT_I2SCTRL_SR_96K ( 9<< 0) +#define AW8898_BIT_I2SCTRL_SR_48K ( 8<< 0) +#define AW8898_BIT_I2SCTRL_SR_44P1K ( 7<< 0) +#define AW8898_BIT_I2SCTRL_SR_32K ( 6<< 0) +#define AW8898_BIT_I2SCTRL_SR_24K ( 5<< 0) +#define AW8898_BIT_I2SCTRL_SR_22K ( 4<< 0) +#define AW8898_BIT_I2SCTRL_SR_16K ( 3<< 0) +#define AW8898_BIT_I2SCTRL_SR_12K ( 2<< 0) +#define AW8898_BIT_I2SCTRL_SR_11K ( 1<< 0) +#define AW8898_BIT_I2SCTRL_SR_8K ( 0<< 0) + + +// I2STXCFG +#define AW8898_BIT_I2STXCFG_FSYNC_MASK (~( 1<<15)) +#define AW8898_BIT_I2STXCFG_FSYNC_BCK_CYCLE ( 1<<15) +#define AW8898_BIT_I2STXCFG_FSYNC_ONE_SLOT ( 0<<15) +#define AW8898_BIT_I2STXCFG_SLOT_NUM_MASK (~( 1<<14)) +#define AW8898_BIT_I2STXCFG_SLOT_NUM_4_TIMES ( 1<<14) +#define AW8898_BIT_I2STXCFG_SLOT_NUM_2_TIMES ( 0<<14) +#define AW8898_BIT_I2STXCFG_TX_SLOT_VLD_MASK (~(15<<12)) +#define AW8898_BIT_I2STXCFG_TX_SLOT_VLD_3 ( 3<<12) +#define AW8898_BIT_I2STXCFG_TX_SLOT_VLD_2 ( 2<<12) +#define AW8898_BIT_I2STXCFG_TX_SLOT_VLD_1 ( 1<<12) +#define AW8898_BIT_I2STXCFG_TX_SLOT_VLD_0 ( 0<<12) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_MASK (~(15<< 8)) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_3_2 (12<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_3_1 (10<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_3_0 ( 9<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_2_1 ( 6<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_2_0 ( 5<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_1_0 ( 3<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_3 ( 8<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_2 ( 4<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_1 ( 2<< 8) +#define AW8898_BIT_I2STXCFG_RX_SLOT_VLD_0 ( 1<< 8) +#define AW8898_BIT_I2STXCFG_DRVSTREN_MASK (~( 1<< 5)) +#define AW8898_BIT_I2STXCFG_DRVSTREN_8MA ( 1<< 5) +#define AW8898_BIT_I2STXCFG_DRVSTREN_2MA ( 0<< 5) +#define AW8898_BIT_I2STXCFG_DOHZ_MASK (~( 1<< 4)) +#define AW8898_BIT_I2STXCFG_DOHZ_HIZ ( 1<< 4) +#define AW8898_BIT_I2STXCFG_DOHZ_GND ( 0<< 4) +#define AW8898_BIT_I2STXCFG_DSEL_MASK (~( 3<< 2)) +#define AW8898_BIT_I2STXCFG_DSEL_DSP ( 2<< 2) +#define AW8898_BIT_I2STXCFG_DSEL_GAIN ( 1<< 2) +#define AW8898_BIT_I2STXCFG_DSEL_ZERO ( 0<< 2) +#define AW8898_BIT_I2STXCFG_CHS_MASK (~( 1<< 1)) +#define AW8898_BIT_I2STXCFG_CHS_RIGHT ( 1<< 1) +#define AW8898_BIT_I2STXCFG_CHS_LEFT ( 0<< 1) +#define AW8898_BIT_I2STXCFG_TX_MASK (~( 1<< 0)) +#define AW8898_BIT_I2STXCFG_TX_ENABLE ( 1<< 0) +#define AW8898_BIT_I2STXCFG_TX_DISABLE ( 0<< 0) + +// PWMCTRL +#define AW8898_BIT_PWMCTRL_DSMZTH_MASK (~(15<<12)) +#define AW8898_BIT_PWMCTRL_DSMZTH_UNIT ( 1<<12) +#define AW8898_BIT_PWMCTRL_PWMDELA_MASK (~(15<< 8)) +#define AW8898_BIT_PWMCTRL_PWMDELA_UNIT ( 1<< 8) +#define AW8898_BIT_PWMCTRL_PWMDELB_MASK (~(15<< 4)) +#define AW8898_BIT_PWMCTRL_PWMDELB_UNIT ( 1<< 4) +#define AW8898_BIT_PWMCTRL_PWMSH_MASK (~( 1<< 3)) +#define AW8898_BIT_PWMCTRL_PWMSH_TRIANGLE ( 1<< 3) +#define AW8898_BIT_PWMCTRL_PWMSH_SAWTOOTH ( 0<< 3) +#define AW8898_BIT_PWMCTRL_PWMRES_MASK (~( 1<< 2)) +#define AW8898_BIT_PWMCTRL_PWMRES_8BIT ( 1<< 2) +#define AW8898_BIT_PWMCTRL_PWMRES_7BIT ( 0<< 2) +#define AW8898_BIT_PWMCTRL_HDCCE_MASK (~( 1<< 1)) +#define AW8898_BIT_PWMCTRL_HDCCE_ENABLE ( 1<< 1) +#define AW8898_BIT_PWMCTRL_HDCCE_DISABLE ( 0<< 1) +#define AW8898_BIT_PWMCTRL_HMUTE_MASK (~( 1<< 0)) +#define AW8898_BIT_PWMCTRL_HMUTE_ENABLE ( 1<< 0) +#define AW8898_BIT_PWMCTRL_HMUTE_DISABLE ( 0<< 0) + +// HAGCCFG1 +#define AW8898_BIT_HAGCCFG1_RVTH_MASK (~(255<<8)) +#define AW8898_BIT_HAGCCFG1_RVTH_UNIT ( 1<< 8) +#define AW8898_BIT_HAGCCFG1_AVTH_MASK (~(255<<0)) +#define AW8898_BIT_HAGCCFG1_AVTH_UNIT ( 1<< 0) + +// HAGCCFG2 +#define AW8898_BIT_HAGCCFG2_ATTH_UNIT ( 1<< 0) + +// HAGCCFG3 +#define AW8898_BIT_HAGCCFG3_RTTH_UNIT ( 1<< 0) + +// HAGCCFG4 +#define AW8898_BIT_HAGCCFG4_MPD_MASK (~( 1<<14)) +#define AW8898_BIT_HAGCCFG4_MPD_ENABLE ( 1<<14) +#define AW8898_BIT_HAGCCFG4_MPD_DISABLE ( 0<<14) +#define AW8898_BIT_HAGCCFG4_MPD_TTH_MASK (~( 3<<12)) +#define AW8898_BIT_HAGCCFG4_MPD_TTH_0P047 ( 3<<12) +#define AW8898_BIT_HAGCCFG4_MPD_TTH_0P032 ( 2<<12) +#define AW8898_BIT_HAGCCFG4_MPD_TTH_0P016 ( 1<<12) +#define AW8898_BIT_HAGCCFG4_MPD_TTH_0P008 ( 0<<12) +#define AW8898_BIT_HAGCCFG4_MPD_RTH_MASK (~( 3<<10)) +#define AW8898_BIT_HAGCCFG4_MPD_RTH_0P047 ( 3<<10) +#define AW8898_BIT_HAGCCFG4_MPD_RTH_0P032 ( 2<<10) +#define AW8898_BIT_HAGCCFG4_MPD_RTH_0P016 ( 1<<10) +#define AW8898_BIT_HAGCCFG4_MPD_RTH_0P008 ( 0<<10) +#define AW8898_BIT_HAGCCFG4_MPD_ATH_MASK (~( 3<< 8)) +#define AW8898_BIT_HAGCCFG4_MPD_ATH_0P047 ( 3<< 8) +#define AW8898_BIT_HAGCCFG4_MPD_ATH_0P032 ( 2<< 8) +#define AW8898_BIT_HAGCCFG4_MPD_ATH_0P016 ( 1<< 8) +#define AW8898_BIT_HAGCCFG4_MPD_ATH_0P008 ( 0<< 8) +#define AW8898_BIT_HAGCCFG4_HOLDTH_MASK (~(255<< 0)) + +// HAGCCFG5 + +// HAGCCFG6 + +// HAGCCFG7 +#define AW8898_BIT_HAGCCFG7_VOL_MASK (~(255< 8)) +#define AW8898_VOLUME_MAX (0) +#define AW8898_VOLUME_MIN (-255) +#define AW8898_VOL_REG_SHIFT (8) + +// HAGCST +#define AW8898_BIT_BSTVOUT_ST_10P25V (15<< 0) +#define AW8898_BIT_BSTVOUT_ST_10V (14<< 0) +#define AW8898_BIT_BSTVOUT_ST_9P75V (13<< 0) +#define AW8898_BIT_BSTVOUT_ST_9P5V (12<< 0) +#define AW8898_BIT_BSTVOUT_ST_9P25V (11<< 0) +#define AW8898_BIT_BSTVOUT_ST_9V (10<< 0) +#define AW8898_BIT_BSTVOUT_ST_8P75V ( 9<< 0) +#define AW8898_BIT_BSTVOUT_ST_8P5V ( 8<< 0) +#define AW8898_BIT_BSTVOUT_ST_8P25V ( 7<< 0) +#define AW8898_BIT_BSTVOUT_ST_8V ( 6<< 0) +#define AW8898_BIT_BSTVOUT_ST_7P75V ( 5<< 0) +#define AW8898_BIT_BSTVOUT_ST_7P5V ( 4<< 0) +#define AW8898_BIT_BSTVOUT_ST_7P25V ( 3<< 0) +#define AW8898_BIT_BSTVOUT_ST_7V ( 2<< 0) +#define AW8898_BIT_BSTVOUT_ST_6P75V ( 1<< 0) +#define AW8898_BIT_BSTVOUT_ST_6P5V ( 0<< 0) + +// DBGCTRL +#define AW8898_BIT_DBGCTRL_LPBK_FAR_MASK (~( 1<<15)) +#define AW8898_BIT_DBGCTRL_LPBK_FAR_ENABLE ( 1<<15) +#define AW8898_BIT_DBGCTRL_LPBK_FAR_DISABLE ( 0<<15) +#define AW8898_BIT_DBGCTRL_LPBK_NEAR_MASK (~( 1<<14)) +#define AW8898_BIT_DBGCTRL_LPBK_NEAR_ENABLE ( 1<<14) +#define AW8898_BIT_DBGCTRL_LPBK_NEAR_DISABLE ( 0<<14) +#define AW8898_BIT_DBGCTRL_PDUVL_MASK (~( 1<<13)) +#define AW8898_BIT_DBGCTRL_PDUVL_DISABLE ( 1<<13) +#define AW8898_BIT_DBGCTRL_PDUVL_ENABLE ( 0<<13) +#define AW8898_BIT_DBGCTRL_MUTE_MASK (~( 1<<12)) +#define AW8898_BIT_DBGCTRL_MUTE_NO_AUTO ( 1<<12) +#define AW8898_BIT_DBGCTRL_MUTE_AUTO ( 0<<12) +#define AW8898_BIT_DBGCTRL_NOCLK_RESET_MASK (~( 1<<11)) +#define AW8898_BIT_DBGCTRL_NOCLK_NO_RESET ( 1<<11) +#define AW8898_BIT_DBGCTRL_NOCLK_RESET ( 0<<11) +#define AW8898_BIT_DBGCTRL_PLL_UNLOCK_RESET_MASK (~( 1<<10)) +#define AW8898_BIT_DBGCTRL_PLL_UNLOCK_NO_RESET ( 1<<10) +#define AW8898_BIT_DBGCTRL_PLL_UNLOCK_RESET ( 0<<10) +#define AW8898_BIT_DBGCTRL_CLKMD_MASK (~( 1<< 9)) +#define AW8898_BIT_DBGCTRL_CLKMD_HALF ( 1<< 9) +#define AW8898_BIT_DBGCTRL_CLKMD_NORMAL ( 0<< 9) +#define AW8898_BIT_DBGCTRL_OSCPD_MASK (~( 1<< 8)) +#define AW8898_BIT_DBGCTRL_OSCPD_ENABLE ( 1<< 8) +#define AW8898_BIT_DBGCTRL_OSCPD_DISABLE ( 0<< 8) +#define AW8898_BIT_DBGCTRL_AMPPD_MASK (~( 1<< 7)) +#define AW8898_BIT_DBGCTRL_AMPPD_PDN ( 1<< 7) +#define AW8898_BIT_DBGCTRL_AMPPD_ACTIVE ( 0<< 7) +#define AW8898_BIT_DBGCTRL_PLLPD_MASK (~( 1<< 6)) +#define AW8898_BIT_DBGCTRL_PLLPD_PDN ( 1<< 6) +#define AW8898_BIT_DBGCTRL_PLLPD_ACTIVE ( 0<< 6) +#define AW8898_BIT_DBGCTRL_I2SRST_MASK (~( 1<< 5)) +#define AW8898_BIT_DBGCTRL_I2SRST_RESET ( 1<< 5) +#define AW8898_BIT_DBGCTRL_I2SRST_WORK ( 0<< 5) +#define AW8898_BIT_DBGCTRL_SYSRST_MASK (~( 1<< 4)) +#define AW8898_BIT_DBGCTRL_SYSRST_RESET ( 1<< 4) +#define AW8898_BIT_DBGCTRL_SYSRST_WORK ( 0<< 4) +#define AW8898_BIT_DBGCTRL_SYSCE_MASK (~( 1<< 0)) +#define AW8898_BIT_DBGCTRL_SYSCE_ENABLE ( 1<< 0) +#define AW8898_BIT_DBGCTRL_SYSCE_DISABLE ( 0<< 0) + + +// I2SCFG +#define AW8898_BIT_I2SCFG_I2SRX_MASK (~( 1<< 0)) +#define AW8898_BIT_I2SCFG_I2SRX_ENABLE ( 1<< 0) +#define AW8898_BIT_I2SCFG_I2SRX_DISABLE ( 0<< 0) + +// I2SSAT +#define AW8898_BIT_I2SSAT_DPSTAT ( 1<< 2) +#define AW8898_BIT_I2SSAT_I2SROVS ( 1<< 1) +#define AW8898_BIT_I2SSAT_I2STOVS ( 1<< 0) + +// GENCTRL +#define AW8898_BIT_GENCTRL_BURST_PEAK_MASK (~( 3<<14)) +#define AW8898_BIT_GENCTRL_BURST_PEAK_200MA ( 3<<14) +#define AW8898_BIT_GENCTRL_BURST_PEAK_160MA ( 2<<14) +#define AW8898_BIT_GENCTRL_BURST_PEAK_100MA ( 1<<14) +#define AW8898_BIT_GENCTRL_BURST_PEAK_130MA ( 0<<14) +#define AW8898_BIT_GENCTRL_BST_TDEG2_MASK (~( 7<< 9)) +#define AW8898_BIT_GENCTRL_BST_TDEG2_2P7S ( 7<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_1P3S ( 6<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_672MS ( 5<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_336MS ( 4<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_168MS ( 3<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_84MS ( 2<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_42MS ( 1<< 9) +#define AW8898_BIT_GENCTRL_BST_TDEG2_21MS ( 0<< 9) +#define AW8898_BIT_GENCTRL_BST_OCAP_MASK (~( 1<< 8)) +#define AW8898_BIT_GENCTRL_BST_OCAP_SLOW ( 1<< 8) +#define AW8898_BIT_GENCTRL_BST_OCAP_FAST ( 0<< 8) +#define AW8898_BIT_GENCTRL_BST_EN_MASK (~( 1<< 7)) +#define AW8898_BIT_GENCTRL_BST_ENABLE ( 1<< 7) +#define AW8898_BIT_GENCTRL_BST_DISABLE ( 0<< 7) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_MASK (~( 7<< 4)) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_4P5A ( 7<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_4P25A ( 6<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_4A ( 5<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_3P75A ( 4<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_3P5A ( 3<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_3P25A ( 2<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_3A ( 1<< 4) +#define AW8898_BIT_GENCTRL_BST_ILIMIT_2P75A ( 0<< 4) +#define AW8898_BIT_GENCTRL_BST_VOUT_MASK (~(15<< 0)) +#define AW8898_BIT_GENCTRL_BST_VOUT_10P25V (15<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_10V (14<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_9P75V (13<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_9P5V (12<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_9P25V (11<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_9V (10<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_8P75V ( 9<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_8P5V ( 8<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_8P25V ( 7<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_8V ( 6<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_7P75V ( 5<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_7P5V ( 4<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_7P25V ( 3<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_7V ( 2<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_6P75V ( 1<< 0) +#define AW8898_BIT_GENCTRL_BST_VOUT_6P5V ( 0<< 0) + +// BSTCTRL1 +#define AW8898_BIT_BSTCTRL1_RTH_MASK (~(64<< 8)) +#define AW8898_BIT_BSTCTRL1_ATH_MASK (~(64<< 0)) + +// BSTCTRL2 +#define AW8898_BIT_BST_MODE_MASK (~( 7<< 3)) +#define AW8898_BIT_BST_MODE_SMART_BOOST ( 6<< 3) +#define AW8898_BIT_BST_MODE_ADAPT_BOOST ( 5<< 3) +#define AW8898_BIT_BST_MODE_FORCE_BOOST ( 1<< 3) +#define AW8898_BIT_BST_MODE_TRANSP_BOOST ( 0<< 3) +#define AW8898_BIT_BST_TDEG_MASK (~( 7<< 0)) +#define AW8898_BIT_BST_TDEG_2P7S ( 7<< 0) +#define AW8898_BIT_BST_TDEG_1P3S ( 6<< 0) +#define AW8898_BIT_BST_TDEG_672MS ( 5<< 0) +#define AW8898_BIT_BST_TDEG_336MS ( 4<< 0) +#define AW8898_BIT_BST_TDEG_168MS ( 3<< 0) +#define AW8898_BIT_BST_TDEG_84MS ( 2<< 0) +#define AW8898_BIT_BST_TDEG_42MS ( 1<< 0) +#define AW8898_BIT_BST_TDEG_21MS ( 0<< 0) + +#endif From ae875709997f152b2c992e67947f337481475ea4 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 17 Apr 2023 23:14:32 +0200 Subject: [PATCH 2/4] aw8898: fix up --- sound/soc/codecs/aw/aw8898.c | 97 ++++++++++++++---------------------- sound/soc/codecs/aw/aw8898.h | 2 +- 2 files changed, 39 insertions(+), 60 deletions(-) diff --git a/sound/soc/codecs/aw/aw8898.c b/sound/soc/codecs/aw/aw8898.c index dc565ed012cccf..fbaddad2760df2 100644 --- a/sound/soc/codecs/aw/aw8898.c +++ b/sound/soc/codecs/aw/aw8898.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "aw8898.h" #include "aw8898_reg.h" @@ -352,7 +353,7 @@ static int aw8898_load_cfg(struct aw8898 *aw8898) { pr_info("%s enter\n", __func__); - return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + return request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, aw8898_cfg_name, aw8898->dev, GFP_KERNEL, aw8898, aw8898_cfg_loaded); } @@ -416,8 +417,8 @@ static int aw8898_volume_info(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_ static int aw8898_volume_get(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(component); unsigned int reg_val = 0; unsigned int value = 0; struct soc_mixer_control *mc = (struct soc_mixer_control*) kcontrol->private_value; @@ -431,8 +432,8 @@ static int aw8898_volume_get(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_v static int aw8898_volume_put(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = (struct soc_mixer_control*) kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(component); unsigned int value = 0; unsigned int reg_value = 0; @@ -482,8 +483,8 @@ static int aw8898_spk_get(struct snd_kcontrol *kcontrol, static int aw8898_spk_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(component); pr_debug("%s: ucontrol->value.integer.value[0]=%ld\n ", __func__, ucontrol->value.integer.value[0]); @@ -509,8 +510,8 @@ static int aw8898_rcv_get(struct snd_kcontrol *kcontrol, static int aw8898_rcv_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(component); pr_debug("%s: ucontrol->value.integer.value[0]=%ld\n ", __func__, ucontrol->value.integer.value[0]); if(ucontrol->value.integer.value[0] == aw8898_rcv_control) @@ -540,10 +541,10 @@ static void aw8898_add_codec_controls(struct aw8898 *aw8898) { pr_info("%s enter\n", __func__); - snd_soc_add_codec_controls(aw8898->codec, aw8898_controls, + snd_soc_add_component_controls(aw8898->component, aw8898_controls, ARRAY_SIZE(aw8898_controls)); - snd_soc_add_codec_controls(aw8898->codec, &aw8898_volume,1); + snd_soc_add_component_controls(aw8898->component, &aw8898_volume,1); } /****************************************************** @@ -598,8 +599,7 @@ static void aw8898_add_widgets(struct aw8898 *aw8898) static int aw8898_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(dai->component); pr_info("%s: enter\n", __func__); aw8898_run_pwd(aw8898, false); @@ -609,8 +609,8 @@ static int aw8898_startup(struct snd_pcm_substream *substream, static int aw8898_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - //struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(dai->codec); - struct snd_soc_codec *codec = dai->codec; + //struct aw8898 *aw8898 = snd_soc_component_get_drvdata(dai->codec); + struct snd_soc_component *component = dai->component; pr_info("%s: fmt=0x%x\n", __func__, fmt); @@ -618,12 +618,12 @@ static int aw8898_set_fmt(struct snd_soc_dai *dai, unsigned int 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 master mode\n", __func__); + dev_err(component->dev, "%s: invalid codec master mode\n", __func__); return -EINVAL; } break; default: - dev_err(codec->dev, "%s: unsupported DAI format %d\n", __func__, + dev_err(component->dev, "%s: unsupported DAI format %d\n", __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } @@ -633,7 +633,7 @@ static int aw8898_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int aw8898_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec_dai->codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(codec_dai->component); pr_info("%s: freq=%d\n", __func__, freq); @@ -645,8 +645,7 @@ static int aw8898_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(dai->component); unsigned int rate = 0; int reg_value = 0; int width = 0; @@ -718,8 +717,7 @@ static int aw8898_hw_params(struct snd_pcm_substream *substream, static int aw8898_mute(struct snd_soc_dai *dai, int mute, int stream) { - struct snd_soc_codec *codec = dai->codec; - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(dai->component); pr_info("%s: mute state=%d\n", __func__, mute); @@ -754,8 +752,7 @@ static int aw8898_mute(struct snd_soc_dai *dai, int mute, int stream) static void aw8898_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(dai->component); aw8898->rate = 0; aw8898_run_pwd(aw8898, true); @@ -789,9 +786,9 @@ static struct snd_soc_dai_driver aw8898_dai[] = { .formats = AW8898_FORMATS, }, .ops = &aw8898_dai_ops, - .symmetric_rates = 1, + .symmetric_rate = 1, .symmetric_channels = 1, - .symmetric_samplebits = 1, + .symmetric_sample_bits = 1, }, }; @@ -800,35 +797,33 @@ static struct snd_soc_dai_driver aw8898_dai[] = { * codec driver * *****************************************************/ -static int aw8898_probe(struct snd_soc_codec *codec) +static int aw8898_probe(struct snd_soc_component *component) { - struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898 = snd_soc_component_get_drvdata(component); int ret = 0; pr_info("%s enter\n", __func__); - aw8898->codec = codec; + aw8898->component = component; //aw8898_add_widgets(aw8898); aw8898_add_codec_controls(aw8898); - if (codec->dev->of_node) - dev_set_name(codec->dev, "%s", "aw8898_smartpa"); + if (component->dev->of_node) + dev_set_name(component->dev, "%s", "aw8898_smartpa"); pr_info("%s exit\n", __func__); return ret; } -static int aw8898_remove(struct snd_soc_codec *codec) +static void aw8898_remove(struct snd_soc_component *component) { - //struct aw8898 *aw8898 = snd_soc_codec_get_drvdata(codec); + //struct aw8898 *aw8898 = snd_soc_component_get_drvdata(codec); pr_info("%s enter\n", __func__); //aw8898_inputdev_unregister(aw8898); - - return 0; } /* @@ -840,9 +835,9 @@ struct regmap *aw8898_get_regmap(struct device *dev) } */ -static unsigned int aw8898_codec_read(struct snd_soc_codec *codec,unsigned int reg) +static unsigned int aw8898_codec_read(struct snd_soc_component *component,unsigned int reg) { - struct aw8898 *aw8898=snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898=snd_soc_component_get_drvdata(component); unsigned int value =0; int ret; pr_debug("%s:enter \n",__func__); @@ -860,10 +855,10 @@ static unsigned int aw8898_codec_read(struct snd_soc_codec *codec,unsigned int r return value; } -static int aw8898_codec_write(struct snd_soc_codec *codec,unsigned int reg,unsigned int value) +static int aw8898_codec_write(struct snd_soc_component *component,unsigned int reg,unsigned int value) { int ret ; - struct aw8898 *aw8898=snd_soc_codec_get_drvdata(codec); + struct aw8898 *aw8898=snd_soc_component_get_drvdata(component); pr_debug("%s:enter ,reg is 0x%x value is 0x%x\n",__func__,reg,value); if(aw8898_reg_access[reg]®_WR_ACCESS){ @@ -881,14 +876,12 @@ static int aw8898_codec_readable(struct snd_soc_codec *codec,unsigned int reg) return aw8898_reg_access[reg]®_RD_ACCESS; } */ -static struct snd_soc_codec_driver soc_codec_dev_aw8898 = { +static struct snd_soc_component_driver soc_codec_dev_aw8898 = { .probe = aw8898_probe, .remove = aw8898_remove, //.get_regmap = aw8898_get_regmap, .read = aw8898_codec_read, .write= aw8898_codec_write, - .reg_cache_size= AW8898_REG_MAX, - .reg_word_size=2, }; /***************************************************** @@ -1380,7 +1373,7 @@ static struct attribute_group aw8898_attribute_group = { * i2c driver * ******************************************************/ -static int aw8898_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static int aw8898_i2c_probe(struct i2c_client *i2c) { struct snd_soc_dai_driver *dai; struct aw8898 *aw8898; @@ -1468,7 +1461,7 @@ static int aw8898_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id * memcpy(dai, aw8898_dai, sizeof(aw8898_dai)); pr_info("%s dai->name(%s)\n", __func__, dai->name); - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aw8898, + ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_aw8898, dai, ARRAY_SIZE(aw8898_dai)); if (ret < 0) { dev_err(&i2c->dev, "%s failed to register aw8898: %d\n", __func__, ret); @@ -1523,16 +1516,11 @@ static int aw8898_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id * device_remove_bin_file(&i2c->dev, &dev_attr_rw); devm_free_irq(&i2c->dev, gpio_to_irq(aw8898->irq_gpio), aw8898); err_irq: - 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(aw8898->reset_gpio)) - devm_gpio_free(&i2c->dev, aw8898->reset_gpio); - if (gpio_is_valid(aw8898->irq_gpio)) - devm_gpio_free(&i2c->dev, aw8898->irq_gpio); err_gpio_request: err_parse_dt: err_regmap: @@ -1541,7 +1529,7 @@ static int aw8898_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id * return ret; } -static int aw8898_i2c_remove(struct i2c_client *i2c) +static void aw8898_i2c_remove(struct i2c_client *i2c) { struct aw8898 *aw8898 = i2c_get_clientdata(i2c); @@ -1550,15 +1538,6 @@ static int aw8898_i2c_remove(struct i2c_client *i2c) device_remove_bin_file(&i2c->dev, &dev_attr_regaddr); device_remove_bin_file(&i2c->dev, &dev_attr_rw); devm_free_irq(&i2c->dev, gpio_to_irq(aw8898->irq_gpio), aw8898); - - snd_soc_unregister_codec(&i2c->dev); - - if (gpio_is_valid(aw8898->irq_gpio)) - devm_gpio_free(&i2c->dev, aw8898->irq_gpio); - if (gpio_is_valid(aw8898->reset_gpio)) - devm_gpio_free(&i2c->dev, aw8898->reset_gpio); - - return 0; } static const struct i2c_device_id aw8898_i2c_id[] = { diff --git a/sound/soc/codecs/aw/aw8898.h b/sound/soc/codecs/aw/aw8898.h index 2042f5ecf57bc2..193c72f58344ab 100644 --- a/sound/soc/codecs/aw/aw8898.h +++ b/sound/soc/codecs/aw/aw8898.h @@ -36,7 +36,7 @@ enum aw8898_mode_spk_rcv{ struct aw8898 { struct regmap *regmap; struct i2c_client *i2c; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct device *dev; struct mutex cfg_lock; #ifdef AW8898_VBAT_MONITOR From 012f14b0c263390724439832df39933d4293f12e Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Tue, 18 Apr 2023 19:12:52 +0200 Subject: [PATCH 3/4] fp3: get speaker working (FP3) FP3 doesn't use wcd_codec, remove bits from msm8953.dtsi Commands: echo start | sudo tee /sys/class/remoteproc/remoteproc0/state amixer -c0 cset name='QUIN_MI2S_RX Audio Mixer MultiMedia1' 1 amixer -c0 cset name='aw8898_speaker_switch' 1 aplay -D plughw:0,0 testfiles/03.wav --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 4 + .../boot/dts/qcom/sdm632-fairphone-fp3.dts | 77 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 7be40d16d81b63..a9dfaedf3040d4 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -2868,9 +2868,11 @@ "quin-iomux"; audio-routing = +#if 0 "AMIC1", "MIC BIAS External1", "AMIC2", "MIC BIAS External2", "AMIC3", "MIC BIAS External1", +#endif "MM_DL1", "MultiMedia1 Playback", "MM_DL3", "MultiMedia3 Playback", "MM_DL4", "MultiMedia4 Playback", @@ -2913,6 +2915,7 @@ }; }; +#if 0 primary-mi2s-dai-link { link-name = "Primary MI2S"; cpu { @@ -2942,6 +2945,7 @@ sound-dai = <&lpass_codec 1>, <&wcd_codec 1>; }; }; +#endif }; lpass_codec: codec@c0f0000 { diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts index 5aac0493bfda12..ab0ec8d2782759 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts @@ -119,6 +119,24 @@ }; }; +&i2c_6 { + status = "okay"; + + /* Speaker amp AW8898 @ 34 */ + /* Speaker amp TAS2557 @ 4c */ + // sudo gpioset gpiochip0 21=1 + + aw8898: audio-amplifier@34 { + compatible = "awinic,aw8898_smartpa"; + reg = <0x34>; + + reset-gpio = <&tlmm 21 GPIO_ACTIVE_HIGH>; + irq-gpio = <&tlmm 20 GPIO_ACTIVE_HIGH>; + + #sound-dai-cells = <0>; + }; +}; + &lpass { status = "okay"; }; @@ -288,6 +306,33 @@ * 135-138: fingerprint reader (SPI) */ gpio-reserved-ranges = <0 4>, <135 4>; + + tlmm_pri_act: tlmm_quin_default { + pins = "gpio88", "gpio91", "gpio93"; + function = "pri_mi2s"; + drive-strength = <8>; + /* bias-disable; */ + }; + + tlmm_pri_sus: tlmm_quin_sleep { + pins = "gpio88", "gpio91", "gpio93"; + function = "pri_mi2s"; + drive-strength = <2>; + bias-pull-down; + }; + + tlmm_pri_ws_act: tlmm_pri_ws_default { + pins = "gpio92"; + function = "pri_mi2s_ws"; + drive-strength = <8>; + }; + + tlmm_pri_ws_sus: tlmm_pri_ws_sleep { + pins = "gpio92"; + function = "pri_mi2s_ws"; + drive-strength = <2>; + bias-pull-down; + }; }; &uart_0 { @@ -314,3 +359,35 @@ vddpa-supply = <&pm8953_l9>; vdddig-supply = <&pm8953_l5>; }; + +&sound_card { + model = "fairphone-fp3"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&cdc_pdm_lines_act &cdc_pdm_lines_2_act &cdc_pdm_comp_lines_act &tlmm_pri_act &tlmm_pri_ws_act>; + pinctrl-1 = <&cdc_pdm_lines_sus &cdc_pdm_lines_2_sus &cdc_pdm_comp_lines_act &tlmm_pri_sus &tlmm_pri_ws_sus>; + + status = "okay"; + + quinary-mi2s-dai-link { + link-name = "Quinary MI2S"; + cpu { + sound-dai = <&q6afedai QUINARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&aw8898>; + }; + }; +}; + +&q6afedai { + dai@127 { + reg = ; + qcom,sd-lines = <0 1>; + }; +}; From cc55faff35ba09feef2e75fa988a9d88ecf0dd45 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 14 Nov 2024 08:57:33 +0100 Subject: [PATCH 4/4] defconfig: fp3.config: enable touchscreen driver --- arch/arm64/configs/fp3.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/fp3.config b/arch/arm64/configs/fp3.config index ce4c3c5d69da2b..519c08096a7a6d 100644 --- a/arch/arm64/configs/fp3.config +++ b/arch/arm64/configs/fp3.config @@ -1 +1,2 @@ CONFIG_DRM_PANEL_FAIRPHONE_FP3_HX83112B=m +CONFIG_TOUCHSCREEN_HIMAX_HX83112B=m