blob: 98e28d644f67d19e3a4981640a8a2f19d25b1dac [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Amlogic, Inc. All rights reserved.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include "pdm_hw.h"
#include "regs.h"
#include "iomap.h"
#include "pdm_hw_coeff.h"
#include "pdm.h"
static DEFINE_SPINLOCK(pdm_lock);
static unsigned long pdm_enable_cnt;
void pdm_enable(int is_enable, int id)
{
unsigned long flags;
spin_lock_irqsave(&pdm_lock, flags);
if (is_enable) {
if (pdm_enable_cnt == 0)
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 31,
is_enable << 31);
pdm_enable_cnt++;
} else {
if (WARN_ON(pdm_enable_cnt == 0))
goto exit;
if (--pdm_enable_cnt == 0)
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 31 | 0x1 << 16,
0 << 31 | 0 << 16);
}
exit:
spin_unlock_irqrestore(&pdm_lock, flags);
}
void pdm_fifo_reset(int id)
{
/* PDM Asynchronous FIFO soft reset.
* write 1 to soft reset AFIFO
*/
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 16,
0 << 16);
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 16,
0x1 << 16);
}
void pdm_force_sysclk_to_oscin(bool force, int id)
{
if (id == 0)
audiobus_update_bits(EE_AUDIO_CLK_PDMIN_CTRL1, 0x1 << 30, force << 30);
else if (id == 1)
audiobus_update_bits(EE_AUDIO_CLK_PDMIN_CTRL3, 0x1 << 30, force << 30);
}
void pdm_set_channel_ctrl(int sample_count, int id)
{
int left_sample_count = sample_count, right_sample_count = sample_count;
int train_version = pdm_get_train_version();
/* only for sc2, left and right sample count are different */
/* sysclk / dclk / 2 */
/* 133 / 3.072 / 2 = 22 */
if (train_version == PDM_TRAIN_VERSION_V2)
right_sample_count += 22;
aml_pdm_write(id, PDM_CHAN_CTRL, ((right_sample_count << 24) |
(left_sample_count << 16) |
(right_sample_count << 8) |
(left_sample_count << 0)
));
aml_pdm_write(id, PDM_CHAN_CTRL1, ((right_sample_count << 24) |
(left_sample_count << 16) |
(right_sample_count << 8) |
(left_sample_count << 0)
));
}
void aml_pdm_ctrl(struct pdm_info *info, int id)
{
int mode, i, ch_mask = 0;
int pdm_chs, lane_chs = 0;
if (!info)
return;
if (info->bitdepth == 32)
mode = 0;
else
mode = 1;
/* update pdm channels for loopback */
pdm_chs = info->channels;
if (info->channels > PDM_CHANNELS_MAX)
pdm_chs = PDM_CHANNELS_MAX;
if (pdm_chs > info->lane_masks * 2)
pr_warn("capturing channels more than lanes carried\n");
/* each lanes carries two channels */
for (i = 0; i < PDM_LANE_MAX; i++)
if ((1 << i) & info->lane_masks) {
ch_mask |= (1 << (2 * i));
lane_chs += 1;
if (lane_chs >= info->channels)
break;
ch_mask |= (1 << (2 * i + 1));
lane_chs += 1;
if (lane_chs >= info->channels)
break;
}
pr_info("%s, lane mask:0x%x, channels:%d, channels mask:0x%x, bypass:%d\n",
__func__,
info->lane_masks,
info->channels,
ch_mask,
info->bypass);
aml_pdm_write(id, PDM_CLKG_CTRL, 1);
/* must be sure that clk and pdm is enable */
aml_pdm_update_bits(id, PDM_CTRL,
(0x7 << 28 | 0xff << 8 | 0xff << 0),
/* invert the PDM_DCLK or not */
(0 << 30) |
/* output mode: 1: 24bits. 0: 32 bits */
(mode << 29) |
/* bypass mode.
* 1: bypass all filter. 0: normal mode.
*/
(info->bypass << 28) |
/* PDM channel reset. */
(ch_mask << 8) |
/* PDM channel enable */
(ch_mask << 0)
);
pdm_set_channel_ctrl(info->sample_count, id);
}
void aml_pdm_arb_config(struct aml_audio_controller *actrl)
{
/* config ddr arb */
aml_audiobus_write(actrl, EE_AUDIO_ARB_CTRL, 1 << 31 | 0xff << 0);
}
/* config for hcic, lpf1,2,3, hpf */
static void aml_pdm_filters_config(int pdm_gain_index, int osr,
int lpf1_len, int lpf2_len, int lpf3_len, int id)
{
s32 hcic_dn_rate;
s32 hcic_tap_num;
s32 hcic_gain;
s32 f1_tap_num;
s32 f2_tap_num;
s32 f3_tap_num;
s32 f1_rnd_mode;
s32 f2_rnd_mode;
s32 f3_rnd_mode;
s32 f1_ds_rate;
s32 f2_ds_rate;
s32 f3_ds_rate;
s32 hpf_en;
s32 hpf_shift_step;
s32 hpf_out_factor;
s32 pdm_out_mode;
switch (osr) {
case 32:
hcic_dn_rate = 0x4;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_32];
break;
case 40:
hcic_dn_rate = 0x5;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_40];
break;
case 48:
hcic_dn_rate = 0x6;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_48];
break;
case 56:
hcic_dn_rate = 0x7;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_56];
break;
case 64:
hcic_dn_rate = 0x0008;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_64];
break;
case 96:
hcic_dn_rate = 0x000c;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_96];
break;
case 128:
hcic_dn_rate = 0x0010;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_128];
break;
case 192:
hcic_dn_rate = 0x0018;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_192];
break;
case 384:
hcic_dn_rate = 0x0030;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_384];
break;
default:
pr_info("Not support osr:%d, translate to :192\n", osr);
hcic_dn_rate = 0x0018;
hcic_gain = pdm_gain_table[pdm_gain_index][PDM_OSR_192];
break;
}
hcic_tap_num = 0x0007;
f1_tap_num = lpf1_len;
f2_tap_num = lpf2_len;
f3_tap_num = lpf3_len;
hpf_shift_step = 0xd;
hpf_en = 1;
pdm_out_mode = 0;
hpf_out_factor = 0x8000;
f1_rnd_mode = 1;
f2_rnd_mode = 0;
f3_rnd_mode = 1;
f1_ds_rate = 2;
f2_ds_rate = 2;
f3_ds_rate = 2;
/* hcic */
aml_pdm_write(id, PDM_HCIC_CTRL1,
(0x80000000 |
hcic_tap_num |
(hcic_dn_rate << 4) |
(hcic_gain << 16))
);
/* lpf */
aml_pdm_write(id, PDM_F1_CTRL,
(0x80000000 |
f1_tap_num |
(2 << 12) |
(f1_rnd_mode << 16))
);
aml_pdm_write(id, PDM_F2_CTRL,
(0x80000000 |
f2_tap_num |
(2 << 12) |
(f2_rnd_mode << 16))
);
aml_pdm_write(id, PDM_F3_CTRL,
(0x80000000 |
f3_tap_num |
(2 << 12) |
(f3_rnd_mode << 16))
);
/* hpf */
aml_pdm_write(id, PDM_HPF_CTRL,
(hpf_out_factor |
(hpf_shift_step << 16) |
(hpf_en << 31))
);
}
/* coefficent for LPF1,2,3 */
static void aml_pdm_LPF_coeff(int lpf1_len, const int *lpf1_coeff,
int lpf2_len, const int *lpf2_coeff,
int lpf3_len, const int *lpf3_coeff, int id)
{
int i;
s32 data;
s32 data_tmp;
aml_pdm_write(id, PDM_COEFF_ADDR, 0);
for (i = 0;
i < lpf1_len;
i++)
aml_pdm_write(id, PDM_COEFF_DATA, lpf1_coeff[i]);
for (i = 0;
i < lpf2_len;
i++)
aml_pdm_write(id, PDM_COEFF_DATA, lpf2_coeff[i]);
for (i = 0;
i < lpf3_len;
i++)
aml_pdm_write(id, PDM_COEFF_DATA, lpf3_coeff[i]);
aml_pdm_write(id, PDM_COEFF_ADDR, 0);
for (i = 0; i < lpf1_len; i++) {
data = aml_pdm_read(id, PDM_COEFF_DATA);
data_tmp = lpf1_coeff[i];
if (data != data_tmp) {
pr_info("FAILED coeff data verified wrong!\n");
pr_info("Coeff = %x\n", data);
pr_info("DDR COEFF = %x\n", data_tmp);
}
}
for (i = 0; i < lpf2_len; i++) {
data = aml_pdm_read(id, PDM_COEFF_DATA);
data_tmp = lpf2_coeff[i];
if (data != data_tmp) {
pr_info("FAILED coeff data verified wrong!\n");
pr_info("Coeff = %x\n", data);
pr_info("DDR COEFF = %x\n", data_tmp);
}
}
for (i = 0; i < lpf3_len; i++) {
data = aml_pdm_read(id, PDM_COEFF_DATA);
data_tmp = lpf3_coeff[i];
if (data != data_tmp) {
pr_info("FAILED coeff data verified wrong!\n");
pr_info("Coeff = %x\n", data);
pr_info("DDR COEFF = %x\n", data_tmp);
}
}
}
void aml_pdm_filter_ctrl(int pdm_gain_index, int osr, int mode, int id)
{
int lpf1_len, lpf2_len, lpf3_len;
const int *lpf1_coeff, *lpf2_coeff, *lpf3_coeff;
/* select LPF coefficent
* For filter 1 and filter 3,
* it's only relative with coefficent mode
* For filter 2,
* it's only relative with osr and hcic stage number
*/
/* mode and its latency
* mode | latency
* 0 | 47.7
* 1 | 38.7
* 2 | 26
* 3 | 20.4
* 4 | 15
*/
switch (osr) {
case 32:
case 64:
lpf2_coeff = lpf2_osr64;
break;
case 96:
lpf2_coeff = lpf2_osr96;
break;
case 128:
lpf2_coeff = lpf2_osr128;
break;
case 192:
lpf2_coeff = lpf2_osr192;
break;
case 256:
lpf2_coeff = lpf2_osr256;
break;
case 384:
lpf2_coeff = lpf2_osr384;
break;
default:
pr_info("osr :%d , lpf2 uses default parameters with osr64\n",
osr);
lpf2_coeff = lpf2_osr64;
break;
}
switch (mode) {
case 0:
lpf1_len = 110;
lpf2_len = 33;
lpf3_len = 147;
lpf1_coeff = lpf1_mode0;
lpf3_coeff = lpf3_mode0;
break;
case 1:
lpf1_len = 87;
lpf2_len = 33;
lpf3_len = 117;
lpf1_coeff = lpf1_mode1;
lpf3_coeff = lpf3_mode1;
break;
case 2:
lpf1_len = 87;
lpf2_len = 33;
lpf3_len = 66;
lpf1_coeff = lpf1_mode2;
lpf3_coeff = lpf3_mode2;
break;
case 3:
lpf1_len = 65;
lpf2_len = 33;
lpf3_len = 49;
lpf1_coeff = lpf1_mode3;
lpf3_coeff = lpf3_mode3;
break;
case 4:
lpf1_len = 43;
lpf2_len = 33;
lpf3_len = 32;
lpf1_coeff = lpf1_mode4;
lpf3_coeff = lpf3_mode4;
break;
default:
pr_info("default mode 1, osr 64\n");
lpf1_len = 87;
lpf2_len = 33;
lpf3_len = 117;
lpf1_coeff = lpf1_mode1;
lpf3_coeff = lpf3_mode1;
break;
}
/* config filter */
aml_pdm_filters_config(pdm_gain_index,
osr,
lpf1_len,
lpf2_len,
lpf3_len, id);
aml_pdm_LPF_coeff(lpf1_len, lpf1_coeff,
lpf2_len, lpf2_coeff,
lpf3_len, lpf3_coeff,
id);
}
int pdm_get_mute_value(int id)
{
return aml_pdm_read(id, PDM_MUTE_VALUE);
}
void pdm_set_mute_value(int val, int id)
{
aml_pdm_write(id, PDM_MUTE_VALUE, val);
}
int pdm_get_mute_channel(int id)
{
int val = aml_pdm_read(id, PDM_CTRL);
return (val & (0xff << 20));
}
void pdm_set_mute_channel(int mute_chmask, int id)
{
int mute_en = 0;
if (mute_chmask)
mute_en = 1;
aml_pdm_update_bits(id, PDM_CTRL,
(0xff << 20 | 0x1 << 17),
(mute_chmask << 20 | mute_en << 17));
}
void pdm_set_bypass_data(bool bypass, int id)
{
aml_pdm_update_bits(id, PDM_CTRL, 0x1 << 28, bypass << 28);
}
void pdm_init_truncate_data(int freq, int id)
{
int mask_val;
/* assume mask 1.05ms */
mask_val = ((freq / 1000) * 1050 * 8) / 1000 - 1;
aml_pdm_write(id, PDM_MASK_NUM, mask_val);
}
void pdm_train_en(bool en, int id)
{
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 19,
en << 19);
}
void pdm_train_clr(int id)
{
aml_pdm_update_bits(id, PDM_CTRL,
0x1 << 18,
0x1 << 18);
}
int pdm_train_sts(int id)
{
int val = aml_pdm_read(id, PDM_STS);
return ((val >> 4) & 0xff);
}
int pdm_dclkidx2rate(int idx)
{
int rate;
if (idx == 2)
rate = 768000;
else if (idx == 1)
rate = 1024000;
else
rate = 3072000;
return rate;
}
int pdm_get_sample_count(int islowpower, int dclk_idx)
{
int count = 0;
if (islowpower) {
count = 0;
} else if (dclk_idx == 1) {
count = 38;
} else if (dclk_idx == 2) {
count = 48;
} else {
count = pdm_get_train_sample_count_from_dts();
if (count < 0)
count = 18;
}
return count;
}
int pdm_get_ors(int dclk_idx, int sample_rate)
{
int osr = 0;
if (dclk_idx == 1) {
if (sample_rate == 16000)
osr = 64;
else if (sample_rate == 8000)
osr = 128;
else
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
} else if (dclk_idx == 2) {
if (sample_rate == 16000)
osr = 48;
else if (sample_rate == 8000)
osr = 96;
else
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
} else {
if (sample_rate == 96000)
osr = 32;
else if (sample_rate == 48000)
osr = 64;
else if (sample_rate == 32000)
osr = 96;
else if (sample_rate == 24000)
osr = 128;
else if (sample_rate == 16000)
osr = 192;
else if (sample_rate == 8000)
osr = 384;
else
pr_err("%s, Not support rate:%d\n",
__func__, sample_rate);
}
return osr;
}
int pdm_auto_train_algorithm(int pdm_id, int enable)
{
int sample_count = 0;
int find = 0;
int val;
int count = 0;
int sample_count1, sample_count2;
aml_pdm_update_bits(pdm_id, PDM_CTRL, 1 << 19, enable << 19);
if (enable == 0)
return 0;
pdm_set_channel_ctrl(sample_count, pdm_id);
while (1) {
aml_pdm_update_bits(pdm_id, PDM_CTRL, 1 << 18, 1 << 18);
aml_pdm_update_bits(pdm_id, PDM_CTRL, 1 << 18, 0 << 18);
usleep_range(8, 10);
val = (aml_pdm_read(pdm_id, PDM_STS) >> 4) & 0xff;
if (val == 0) {
count++;
/*try to 10*/
if (count < 10)
continue;
else
count = 0;
} else {
/*must be find two sample count for max and min range*/
if (find == 1) {
sample_count2 = sample_count;
if (abs(sample_count2 - sample_count1) > 10) {
pr_info("sample range:%d~:%d\n",
(sample_count1 < sample_count2 ?
sample_count1 : sample_count2),
(sample_count1 < sample_count2 ?
sample_count2 : sample_count1));
break;
}
} else {
sample_count1 = sample_count;
find = 1;
}
}
pdm_set_channel_ctrl(sample_count++, 0);
if (sample_count > 100) {
pr_info("not find the sample range\n");
break;
}
}
return (sample_count1 + sample_count2) / 2;
}