// SPDX-License-Identifier: GPL-2.0 /** * Copyright (C) Fourier Semiconductor Inc. 2016-2020. All rights reserved. * 2019-01-29 File created. */ #if defined(CONFIG_FSM_FS1801) #include "fsm_public.h" #include "fs1801_reg_bf.h" #define FS1801_PRESET_EQ_LEN (0x0069) #define FS1801_RS2RL_RATIO (2300) #define FS1801_OTP_COUNT_MAX (15) #define FS1801_EXCER_RAM_ADDR (0xD2) const static fsm_pll_config_t g_fs1801_pll_tbl[] = { /* bclk, 0xC1, 0xC2, 0xC3 */ { 256000, 0x01A0, 0x0180, 0x0001 }, // 8000*16*2 { 512000, 0x01A0, 0x0180, 0x0002 }, // 16000*16*2 & 8000*32*2 { 1024000, 0x0260, 0x0120, 0x0003 }, // & 16000*32*2 { 1024032, 0x0260, 0x0120, 0x0003 }, // 32000*16*2+32 { 1411200, 0x01A0, 0x0100, 0x0004 }, // 44100*16*2 { 1536000, 0x0260, 0x0100, 0x0004 }, // 48000*16*2 { 2048032, 0x0260, 0x0120, 0x0006 }, // & 32000*32*2+32 { 2822400, 0x01A0, 0x0100, 0x0008 }, // & 44100*32*2 { 3072000, 0x0260, 0x0100, 0x0008 }, // & 48000*32*2 }; const static struct fsm_bpcoef g_fs1801_bpcoef_table[] = { { 200, { 0x00181B7B, 0x001801DA, 0xffe7e485, 0x0007C629, 0xFFE8349E} }, { 250, { 0x001817ED, 0x001801DA, 0xffe7e813, 0x0007CEEF, 0xFFE82DB5} }, { 300, { 0x001815DA, 0x001801DA, 0xffe7edda, 0x0007D06F, 0xFFE829D8} }, { 350, { 0x0018168A, 0x001801DA, 0xffe7e96a, 0x0007C908, 0xFFE82F78} }, { 400, { 0x00181489, 0x001801DA, 0xffe7eb77, 0x0007CBF4, 0xFFE82B7D} }, { 450, { 0x00181225, 0x001801DA, 0xffe7eddb, 0x0007C804, 0xFFE82625} }, { 500, { 0x001817EE, 0x001801DA, 0xffe7e816, 0x0007C3FC, 0xFFE82DB3} }, { 550, { 0x0018152A, 0x001801DA, 0xffe7eaca, 0x0007C0D8, 0xFFE8283B} }, { 600, { 0x00181226, 0x001801DA, 0xffe7edde, 0x0007BF3F, 0xFFE82620} }, { 650, { 0x00181479, 0x001801DA, 0xffe7eb87, 0x0007B6E7, 0xFFE82A92} }, { 700, { 0x0018156D, 0x001801DA, 0xffe7ea93, 0x0007B585, 0xFFE828B5} }, { 750, { 0x00181223, 0x001801DA, 0xffe7eddd, 0x0007B111, 0xFFE8262E} }, { 800, { 0x00181491, 0x001801DA, 0xffe7eb6f, 0x0007A919, 0xFFE82B42} }, { 850, { 0x0018154B, 0x001801DA, 0xffe7eab5, 0x0007A5AC, 0xFFE828FE} }, { 900, { 0x0018122C, 0x001801DA, 0xffe7edd0, 0x00079E4B, 0xFFE82637} }, { 950, { 0x001814D5, 0x001801DA, 0xffe7eb2b, 0x00079728, 0xFFE82BC5} }, { 1000, { 0x001815AF, 0x001801DA, 0xffe7ea51, 0x00079082, 0xFFE82936} }, { 1050, { 0x00181228, 0x001801DA, 0xffe7edd4, 0x00078AE0, 0xFFE8263F} }, { 1100, { 0x00181538, 0x001801DA, 0xffe7eac4, 0x00078039, 0xFFE8281F} }, { 1150, { 0x00181585, 0x001801DA, 0xffe7ea7b, 0x00077AC8, 0xFFE8291A} }, { 1200, { 0x00181237, 0x001801DA, 0xffe7edc9, 0x0007721D, 0xFFE82601} }, { 1250, { 0x00181564, 0x001801DA, 0xffe7ea98, 0x0007687F, 0xFFE828A4} }, { 1300, { 0x00181596, 0x001801DA, 0xffe7ea6e, 0x00076073, 0xFFE82940} }, { 1350, { 0x0018123D, 0x001801DA, 0xffe7edc3, 0x000758E1, 0xFFE8260A} }, { 1400, { 0x0018157B, 0x001801DA, 0xffe7ea85, 0x00074F9B, 0xFFE82899} }, { 1450, { 0x001815E6, 0x001801DA, 0xffe7ea1e, 0x000744F8, 0xFFE829A3} }, { 1500, { 0x0018123B, 0x001801DA, 0xffe7edc5, 0x00073A42, 0xFFE82619} }, { 1550, { 0x0018155D, 0x001801DA, 0xffe7eaa3, 0x00072E67, 0xFFE828CA} }, { 1600, { 0x001815F7, 0x001801DA, 0xffe7ea09, 0x00072459, 0xFFE82981} }, { 1650, { 0x00181200, 0x001801DA, 0xffe7edfc, 0x00071B3B, 0xFFE8266C} }, { 1700, { 0x001815AB, 0x001801DA, 0xffe7ea55, 0x00070FFA, 0xFFE82939} }, { 1750, { 0x001815C4, 0x001801DA, 0xffe7ea38, 0x00070315, 0xFFE829E4} }, { 1800, { 0x00181209, 0x001801DA, 0xffe7edf7, 0x0006F6C3, 0xFFE8267D} }, { 1850, { 0x00181586, 0x001801DA, 0xffe7ea7e, 0x0006E8B4, 0xFFE82960} }, { 1900, { 0x001815CA, 0x001801DA, 0xffe7ea2a, 0x0006DCD0, 0xFFE829F8} }, { 1950, { 0x00181210, 0x001801DA, 0xffe7edec, 0x0006D19E, 0xFFE8264C} }, { 2000, { 0x00181593, 0x001801DA, 0xffe7ea6d, 0x0006C076, 0xFFE82949} }, }; static int fs1801_i2c_reset(fsm_dev_t *fsm_dev) { uint16_t val; int ret; int i; fsm_dev->acc_count = 0; for (i = 0; i < FSM_I2C_RETRY; i++) { fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0002); fsm_reg_read(fsm_dev, REG(FSM_SYSCTRL), NULL); // dummy read fsm_delay_ms(15); // 15ms ret = fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0001); // check init finish flag ret |= fsm_reg_multiread(fsm_dev, REG(FSM_CHIPINI), &val); if ((val == 0x0003) || (val == 0x0300)) { break; } } if (i == FSM_I2C_RETRY) { pr_addr(err, "retry timeout"); ret = -ETIMEDOUT; } return ret; } static int fs1801_config_pll(fsm_dev_t *fsm_dev, bool on) { fsm_config_t *cfg = fsm_get_config(); int idx; int ret; if (!fsm_dev || !cfg) { return -EINVAL; } // config pll need disable pll firstly ret = fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), 0); fsm_delay_ms(1); if (!on) { // disable pll return ret; } for (idx = 0; idx < ARRAY_SIZE(g_fs1801_pll_tbl); idx++) { if (g_fs1801_pll_tbl[idx].bclk == cfg->i2s_bclk) { break; } } pr_addr(debug, "bclk[%d]: %d", idx, cfg->i2s_bclk); if (idx >= ARRAY_SIZE(g_fs1801_pll_tbl)) { pr_addr(err, "Not found bclk: %d, rate: %d", cfg->i2s_bclk, cfg->i2s_srate); return -EINVAL; } ret |= fsm_access_key(fsm_dev, 1); if (cfg->i2s_srate == 32000) { ret |= fsm_reg_write(fsm_dev, REG(FSM_ANACTRL), 0x0101); } else { ret |= fsm_reg_write(fsm_dev, REG(FSM_ANACTRL), 0x0100); } ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL1), g_fs1801_pll_tbl[idx].c1); ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL2), g_fs1801_pll_tbl[idx].c2); ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL3), g_fs1801_pll_tbl[idx].c3); ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), 0x000F); ret |= fsm_access_key(fsm_dev, 0); FSM_FUNC_EXIT(ret); return ret; } static int fs1801_config_i2s(fsm_dev_t *fsm_dev) { fsm_config_t *cfg = fsm_get_config(); uint16_t i2sctrl; uint16_t i2ssr; int ret; if (!fsm_dev || !cfg) { return -EINVAL; } i2ssr = fsm_get_srate_bits(fsm_dev, cfg->i2s_srate); if (i2ssr < 0) { pr_addr(err, "unsupport srate:%d", cfg->i2s_srate); return -EINVAL; } ret = fsm_reg_read(fsm_dev, REG(FSM_I2SCTRL), &i2sctrl); set_bf_val(&i2sctrl, FSM_I2SSR, i2ssr); set_bf_val(&i2sctrl, FSM_I2SF, FSM_FMT_I2S); pr_addr(debug, "srate:%d, val:%04X", cfg->i2s_srate, i2sctrl); ret |= fsm_reg_write(fsm_dev, REG(FSM_I2SCTRL), i2sctrl); ret |= fsm_swap_channel(fsm_dev, cfg->next_angle); FSM_FUNC_EXIT(ret); return ret; } static int fs1801_store_otp(fsm_dev_t *fsm_dev, uint8_t valOTP) { uint16_t sysctrl; uint16_t pllctrl4; uint16_t bstctrl; uint16_t otprdata; int count; int delta; int re25_otp; int ret; if (fsm_dev == NULL) { return -EINVAL; } ret = fsm_access_key(fsm_dev, 1); // power on device and ClassD off ret |= fsm_reg_read(fsm_dev, REG(FSM_SYSCTRL), &sysctrl); ret |= fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0000); ret |= fsm_reg_read(fsm_dev, REG(FSM_PLLCTRL4), &pllctrl4); ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), 0x000F); ret |= fsm_reg_multiread(fsm_dev, REG(FSM_BSTCTRL), &bstctrl); ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0x0000); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPADDR), 0x0010); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0000); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0001); do { ret |= fsm_wait_stable(fsm_dev, FSM_WAIT_OTP_READY); if (ret) { pr_addr(err, "wait OTP ready fail:%d", ret); break; } ret = fsm_reg_multiread(fsm_dev, REG(FSM_OTPRDATA), &otprdata); fsm_parse_otp(fsm_dev, otprdata, &re25_otp, &count); pr_addr(info, "re25 old:%d, new:%d", re25_otp, fsm_dev->re25); delta = abs(re25_otp - fsm_dev->re25); if (delta < (FSM_MAGNIF(fsm_dev->spkr) / 20)) { pr_addr(info, "not need to update otp, delta:%d", delta); break; } if (count >= fsm_dev->compat.otp_max_count) { pr_addr(err, "count exceeds max:%d", count); ret = -EINVAL; break; } ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), 0x000B); // enable boost and follow mode ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0x0008); fsm_wait_stable(fsm_dev, FSM_WAIT_BOOST_SSEND); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPADDR), 0x0010); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPWDATA), (uint16_t)valOTP); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0000); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x2000); ret |= fsm_wait_stable(fsm_dev, FSM_WAIT_BOOST_SSEND); if (ret) { pr_addr(err, "wait boost ready failed"); break; } ret = fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x2002); ret |= fsm_wait_stable(fsm_dev, FSM_WAIT_OTP_READY); if (ret) { pr_addr(err, "wait OTP ready failed"); break; } ret = fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0000); fsm_delay_ms(1); // disable boost and discharge ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0x0001); fsm_delay_ms(5); ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0x0000); // read back otp info ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), 0x000A); ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0x0000); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPADDR), 0x0010); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0000); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTPCMD), 0x0001); ret |= fsm_wait_stable(fsm_dev, FSM_WAIT_OTP_READY); if (ret) { pr_addr(err, "wait OTP ready failed"); break; } ret = fsm_reg_multiread(fsm_dev, REG(FSM_OTPRDATA), &otprdata); if (HIGH8(otprdata) != valOTP) { pr_addr(err, "read back failed:%04X(expect:%04X)", otprdata, valOTP); ret = -EINVAL; break; } fsm_parse_otp(fsm_dev, otprdata, &re25_otp, &count); fsm_dev->cal_count = count; pr_addr(info, "read back count:%d", count); } while (0); ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), bstctrl); ret |= fsm_reg_write(fsm_dev, REG(FSM_PLLCTRL4), pllctrl4); ret |= fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), sysctrl); ret |= fsm_access_key(fsm_dev, 0); FSM_FUNC_EXIT(ret); return ret; } static int fs1801_update_otctrl(fsm_dev_t *fsm_dev) { uint16_t otppg1w0; uint16_t otctrl; int new_val; int offset; int ret; ret = fsm_access_key(fsm_dev, 1); ret |= fsm_reg_read(fsm_dev, REG(FSM_OTPPG1W0), &otppg1w0); ret |= fsm_reg_read(fsm_dev, REG(FSM_OTCTRL), &otctrl); offset = (otppg1w0 & 0x007F); if ((otppg1w0 & 0x0080) != 0) { offset = (-1 * offset); } do { new_val = offset + LOW8(otctrl); if (new_val < 0 || new_val > 0xFF) break; otctrl = ((otctrl & 0xFF00) | new_val); new_val = offset + HIGH8(otctrl); if (new_val < 0 || new_val > 0xFF) break; otctrl = ((otctrl & 0x00FF) | (new_val << 8)); ret |= fsm_reg_write(fsm_dev, REG(FSM_OTCTRL), otctrl); } while (0); ret |= fsm_access_key(fsm_dev, 0); return ret; } int fs1801_reg_init(fsm_dev_t *fsm_dev) { int ret; if (!fsm_dev) { return -EINVAL; } ret = fs1801_i2c_reset(fsm_dev); ret |= fsm_reg_write(fsm_dev, 0xC4, 0x000A); fsm_delay_ms(5); // 5ms ret |= fsm_reg_write(fsm_dev, 0x06, 0x0000); ret |= fsm_access_key(fsm_dev, 1); ret |= fsm_reg_write(fsm_dev, 0xD3, 0x0100); ret |= fsm_reg_write(fsm_dev, 0xC0, 0x15C0); ret |= fsm_reg_write(fsm_dev, 0xC4, 0x000F); ret |= fsm_reg_write(fsm_dev, 0xAE, 0x0210); ret |= fsm_reg_write(fsm_dev, 0xB9, 0xFFFF); ret |= fsm_reg_write(fsm_dev, 0x09, 0x0000); ret |= fsm_reg_write(fsm_dev, 0xCD, 0x2004); ret |= fsm_reg_write(fsm_dev, 0xA1, 0x1C92); ret |= fs1801_update_otctrl(fsm_dev); ret |= fsm_access_key(fsm_dev, 0); fsm_dev->errcode = ret; return ret; } static int fs1801_f0_reg_init(fsm_dev_t *fsm_dev) { int ret; if (fsm_dev == NULL) { return -EINVAL; } ret = fs1801_i2c_reset(fsm_dev); ret |= fsm_access_key(fsm_dev, 1); ret |= fsm_reg_write(fsm_dev, REG(FSM_AUDIOCTRL), 0xFF00); ret |= fsm_reg_write(fsm_dev, REG(FSM_DACCTRL), 0x0210); fs1801_config_i2s(fsm_dev); fs1801_config_pll(fsm_dev, true); // Make sure 0xC4 is 0x000F ret |= fsm_set_bf(fsm_dev, FSM_CHS12, 3); // ValD0 Bypass OT ret |= fsm_reg_write(fsm_dev, REG(FSM_ANACTRL), 0x0120); //DCR Bypass ret |= fsm_reg_write(fsm_dev, REG(FSM_AUXCFG), 0x1020); // Power up ret |= fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0000); // Boost control ret |= fsm_reg_write(fsm_dev, REG(FSM_BSTCTRL), 0xBF0E); // ret |= fsm_reg_read(fsm_dev, REG(FSM_STATUS), NULL); // DSP control ret |= fsm_reg_write(fsm_dev, REG(FSM_DSPCTRL), 0x1012); // ret |= fsm_reg_write(fsm_dev, REG(FSM_ACSCTRL), 0x9880); // ADC control, adc env, adc time ret |= fsm_reg_write(fsm_dev, REG(FSM_ADCCTRL), 0x0300); ret |= fsm_reg_write(fsm_dev, REG(FSM_ADCENV), 0x9FFF); ret |= fsm_reg_write(fsm_dev, REG(FSM_ADCTIME), 0x0038); // BFL, AGC ret |= fsm_reg_write(fsm_dev, REG(FSM_BFLCTRL), 0x0006); ret |= fsm_reg_write(fsm_dev, REG(FSM_BFLSET), 0x009F); ret |= fsm_reg_write(fsm_dev, REG(FSM_AGC), 0x00B7); ret |= fsm_reg_write(fsm_dev, REG(FSM_DRPARA), 0x0001); ret |= fsm_access_key(fsm_dev, 0); // TS control ret |= fsm_reg_write(fsm_dev, REG(FSM_TSCTRL), 0x162F); // wait stable: DACRUN=0 ret |= fsm_wait_stable(fsm_dev, FSM_WAIT_AMP_OFF); if (ret) { pr_addr(err, "wait timeout"); return ret; } return ret; } static int fs1801_f0_ram_init(fsm_dev_t *fsm_dev) { int32_t coef_ad[COEF_LEN] = {0x00674612, 0x0098B9EC, 0x001801AD, 0x002794B3, 0x001801AD}; uint8_t buf[sizeof(uint32_t)]; int ret; int i; if (fsm_dev == NULL) { return -EINVAL; } ret = fsm_access_key(fsm_dev, 1); // Set ADC coef(B0, B1) ret |= fsm_reg_write(fsm_dev, REG(FSM_ADCEQA), 0x0000); for (i = 0; i < COEF_LEN; i++) { convert_data_to_bytes(coef_ad[i], buf); ret |= fsm_burst_write(fsm_dev, REG(FSM_ADCEQWL), buf, sizeof(uint32_t)); } for (i = 0; i < COEF_LEN; i++) { convert_data_to_bytes(coef_ad[i], buf); ret |= fsm_burst_write(fsm_dev, REG(FSM_ADCEQWL), buf, sizeof(uint32_t)); } ret |= fsm_access_key(fsm_dev, 0); return ret; } int fs1801_pre_f0_test(fsm_dev_t *fsm_dev) { int ret; if (fsm_dev == NULL) { return -EINVAL; } fsm_dev->f0 = 0; fsm_dev->state.f0_runing = true; if (fsm_dev->tdata) { fsm_dev->tdata->test_f0 = 0; memset(&fsm_dev->tdata->f0, 0, sizeof(struct f0_data)); } ret = fs1801_f0_reg_init(fsm_dev); // make sure amp off here // ret |= fsm_reg_read(fsm_dev, REG(FSM_SYSCTRL), NULL); ret = fsm_access_key(fsm_dev, 1); ret |= fs1801_f0_ram_init(fsm_dev); // ADC on ret |= fsm_reg_write(fsm_dev, REG(FSM_ADCCTRL), 0x1300); ret |= fsm_access_key(fsm_dev, 0); fsm_dev->errcode = ret; FSM_ADDR_EXIT(ret); return ret; } int fs1801_f0_test(fsm_dev_t *fsm_dev) { fsm_config_t *cfg = fsm_get_config(); const uint32_t *coef_acsbp = NULL; uint8_t buf[sizeof(uint32_t)]; int freq; int ret; int i; if (fsm_dev == NULL || !cfg) { return -EINVAL; } if (!fsm_dev->state.f0_runing) { pr_addr(info, "invalid running state"); return 0; } // CalculateBPCoef freq = cfg->test_freq; for (i = 0; i < ARRAY_SIZE(g_fs1801_bpcoef_table); i++) { if (freq == g_fs1801_bpcoef_table[i].freq) { coef_acsbp = g_fs1801_bpcoef_table[i].coef; break; } } if (!coef_acsbp) { pr_addr(err, "freq no matched: %d", freq); return -EINVAL; } // Keep amp off here. ret = fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0000); // wait stable ret = fsm_wait_stable(fsm_dev, FSM_WAIT_AMP_OFF); if (ret) { return ret; } // ACS EQ band 0 and band 1 ret |= fsm_access_key(fsm_dev, 1); ret |= fsm_reg_write(fsm_dev, fsm_dev->compat.ACSEQA, 0x0000); // 0xA6 for (i = 0; i < COEF_LEN; i++) { convert_data_to_bytes(coef_acsbp[i], buf); ret |= fsm_burst_write(fsm_dev, fsm_dev->compat.ACSEQWL, buf, sizeof(uint32_t)); } for (i = 0; i < COEF_LEN; i++) { convert_data_to_bytes(coef_acsbp[i], buf); ret |= fsm_burst_write(fsm_dev, fsm_dev->compat.ACSEQWL, buf, sizeof(uint32_t)); } ret |= fsm_access_key(fsm_dev, 0); // Amp on ret |= fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0008); // now need sleep 350ms, first time need 700ms FSM_ADDR_EXIT(ret); return ret; } int fs1801_post_f0_test(fsm_dev_t *fsm_dev) { int ret; if (fsm_dev == NULL) { return -EINVAL; } if (!fsm_dev->state.f0_runing) { pr_addr(info, "invalid running state"); return 0; } fsm_dev->state.f0_runing = false; ret = fsm_reg_write(fsm_dev, REG(FSM_SYSCTRL), 0x0001); return ret; } void fs1801_ops(fsm_dev_t *fsm_dev) { if (!fsm_dev) { return; } fsm_dev->dev_ops.reg_init = fs1801_reg_init; fsm_dev->dev_ops.i2s_config = fs1801_config_i2s; fsm_dev->dev_ops.pll_config = fs1801_config_pll; fsm_dev->dev_ops.store_otp = fs1801_store_otp; fsm_dev->dev_ops.pre_f0_test = fs1801_pre_f0_test; fsm_dev->dev_ops.f0_test = fs1801_f0_test; fsm_dev->dev_ops.post_f0_test = fs1801_post_f0_test; fsm_dev->compat.preset_unit_len = FS1801_PRESET_EQ_LEN; fsm_dev->compat.addr_excer_ram = FS1801_EXCER_RAM_ADDR; fsm_dev->compat.otp_max_count = FS1801_OTP_COUNT_MAX; fsm_dev->compat.ACSEQA = REG(FS1801_DACEQA); fsm_dev->compat.ACSEQWL = REG(FS1801_DACEQWL); fsm_dev->compat.DACEQA = REG(FS1801_DACEQA); fsm_dev->compat.DACEQWL = REG(FS1801_DACEQWL); fsm_dev->compat.RS2RL_RATIO = FS1801_RS2RL_RATIO; } #endif