18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD1843 low level driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> 68c2ecf20Sopenharmony_ci * Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * inspired from vwsnd.c (SGI VW audio driver) 98c2ecf20Sopenharmony_ci * Copyright 1999 Silicon Graphics, Inc. All rights reserved. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/sched.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include <sound/pcm.h> 178c2ecf20Sopenharmony_ci#include <sound/ad1843.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * AD1843 bitfield definitions. All are named as in the AD1843 data 218c2ecf20Sopenharmony_ci * sheet, with ad1843_ prepended and individual bit numbers removed. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * E.g., bits LSS0 through LSS2 become ad1843_LSS. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Only the bitfields we need are defined. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct ad1843_bitfield { 298c2ecf20Sopenharmony_ci char reg; 308c2ecf20Sopenharmony_ci char lo_bit; 318c2ecf20Sopenharmony_ci char nbits; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct ad1843_bitfield 358c2ecf20Sopenharmony_ci ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ 368c2ecf20Sopenharmony_ci ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ 378c2ecf20Sopenharmony_ci ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ 388c2ecf20Sopenharmony_ci ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ 398c2ecf20Sopenharmony_ci ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ 408c2ecf20Sopenharmony_ci ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ 418c2ecf20Sopenharmony_ci ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ 428c2ecf20Sopenharmony_ci ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ 438c2ecf20Sopenharmony_ci ad1843_RD2M = { 3, 0, 5 }, /* Right DAC 2 Mix Gain/Atten */ 448c2ecf20Sopenharmony_ci ad1843_RD2MM = { 3, 7, 1 }, /* Right DAC 2 Mix Mute */ 458c2ecf20Sopenharmony_ci ad1843_LD2M = { 3, 8, 5 }, /* Left DAC 2 Mix Gain/Atten */ 468c2ecf20Sopenharmony_ci ad1843_LD2MM = { 3, 15, 1 }, /* Left DAC 2 Mix Mute */ 478c2ecf20Sopenharmony_ci ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ 488c2ecf20Sopenharmony_ci ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ 498c2ecf20Sopenharmony_ci ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ 508c2ecf20Sopenharmony_ci ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ 518c2ecf20Sopenharmony_ci ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ 528c2ecf20Sopenharmony_ci ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ 538c2ecf20Sopenharmony_ci ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ 548c2ecf20Sopenharmony_ci ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ 558c2ecf20Sopenharmony_ci ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ 568c2ecf20Sopenharmony_ci ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ 578c2ecf20Sopenharmony_ci ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ 588c2ecf20Sopenharmony_ci ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ 598c2ecf20Sopenharmony_ci ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ 608c2ecf20Sopenharmony_ci ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ 618c2ecf20Sopenharmony_ci ad1843_MPOM = { 8, 6, 1 }, /* Mono Output Mute */ 628c2ecf20Sopenharmony_ci ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ 638c2ecf20Sopenharmony_ci ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ 648c2ecf20Sopenharmony_ci ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ 658c2ecf20Sopenharmony_ci ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ 668c2ecf20Sopenharmony_ci ad1843_RDA2G = { 10, 0, 6 }, /* Right DAC2 Analog/Digital Gain */ 678c2ecf20Sopenharmony_ci ad1843_RDA2GM = { 10, 7, 1 }, /* Right DAC2 Analog Mute */ 688c2ecf20Sopenharmony_ci ad1843_LDA2G = { 10, 8, 6 }, /* Left DAC2 Analog/Digital Gain */ 698c2ecf20Sopenharmony_ci ad1843_LDA2GM = { 10, 15, 1 }, /* Left DAC2 Analog Mute */ 708c2ecf20Sopenharmony_ci ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ 718c2ecf20Sopenharmony_ci ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ 728c2ecf20Sopenharmony_ci ad1843_RDA2AM = { 12, 7, 1 }, /* Right DAC2 Digital Mute */ 738c2ecf20Sopenharmony_ci ad1843_LDA2AM = { 12, 15, 1 }, /* Left DAC2 Digital Mute */ 748c2ecf20Sopenharmony_ci ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ 758c2ecf20Sopenharmony_ci ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ 768c2ecf20Sopenharmony_ci ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ 778c2ecf20Sopenharmony_ci ad1843_DA2C = { 15, 10, 2 }, /* DAC2 Sample Rate Source */ 788c2ecf20Sopenharmony_ci ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ 798c2ecf20Sopenharmony_ci ad1843_C2C = { 20, 0, 16 }, /* Clock 2 Sample Rate Select */ 808c2ecf20Sopenharmony_ci ad1843_C3C = { 23, 0, 16 }, /* Clock 3 Sample Rate Select */ 818c2ecf20Sopenharmony_ci ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ 828c2ecf20Sopenharmony_ci ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ 838c2ecf20Sopenharmony_ci ad1843_DAMIX = { 25, 14, 1 }, /* DAC Digital Mix Enable */ 848c2ecf20Sopenharmony_ci ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ 858c2ecf20Sopenharmony_ci ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ 868c2ecf20Sopenharmony_ci ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ 878c2ecf20Sopenharmony_ci ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ 888c2ecf20Sopenharmony_ci ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ 898c2ecf20Sopenharmony_ci ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ 908c2ecf20Sopenharmony_ci ad1843_DA2F = { 26, 10, 2 }, /* DAC2 Data Format Select */ 918c2ecf20Sopenharmony_ci ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ 928c2ecf20Sopenharmony_ci ad1843_DA2SM = { 26, 15, 1 }, /* DAC2 Stereo/Mono Mode Select */ 938c2ecf20Sopenharmony_ci ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ 948c2ecf20Sopenharmony_ci ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ 958c2ecf20Sopenharmony_ci ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ 968c2ecf20Sopenharmony_ci ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ 978c2ecf20Sopenharmony_ci ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ 988c2ecf20Sopenharmony_ci ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ 998c2ecf20Sopenharmony_ci ad1843_DDMEN = { 27, 12, 1 }, /* DAC2 to DAC1 Mix Enable */ 1008c2ecf20Sopenharmony_ci ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ 1018c2ecf20Sopenharmony_ci ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ 1028c2ecf20Sopenharmony_ci ad1843_C3EN = { 28, 13, 1 }, /* Clock Generator 3 Enable */ 1038c2ecf20Sopenharmony_ci ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * The various registers of the AD1843 use three different formats for 1078c2ecf20Sopenharmony_ci * specifying gain. The ad1843_gain structure parameterizes the 1088c2ecf20Sopenharmony_ci * formats. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct ad1843_gain { 1128c2ecf20Sopenharmony_ci int negative; /* nonzero if gain is negative. */ 1138c2ecf20Sopenharmony_ci const struct ad1843_bitfield *lfield; 1148c2ecf20Sopenharmony_ci const struct ad1843_bitfield *rfield; 1158c2ecf20Sopenharmony_ci const struct ad1843_bitfield *lmute; 1168c2ecf20Sopenharmony_ci const struct ad1843_bitfield *rmute; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_RECLEV = { 1208c2ecf20Sopenharmony_ci .negative = 0, 1218c2ecf20Sopenharmony_ci .lfield = &ad1843_LIG, 1228c2ecf20Sopenharmony_ci .rfield = &ad1843_RIG 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_LINE = { 1258c2ecf20Sopenharmony_ci .negative = 1, 1268c2ecf20Sopenharmony_ci .lfield = &ad1843_LX1M, 1278c2ecf20Sopenharmony_ci .rfield = &ad1843_RX1M, 1288c2ecf20Sopenharmony_ci .lmute = &ad1843_LX1MM, 1298c2ecf20Sopenharmony_ci .rmute = &ad1843_RX1MM 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_LINE_2 = { 1328c2ecf20Sopenharmony_ci .negative = 1, 1338c2ecf20Sopenharmony_ci .lfield = &ad1843_LDA2G, 1348c2ecf20Sopenharmony_ci .rfield = &ad1843_RDA2G, 1358c2ecf20Sopenharmony_ci .lmute = &ad1843_LDA2GM, 1368c2ecf20Sopenharmony_ci .rmute = &ad1843_RDA2GM 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_MIC = { 1398c2ecf20Sopenharmony_ci .negative = 1, 1408c2ecf20Sopenharmony_ci .lfield = &ad1843_LMCM, 1418c2ecf20Sopenharmony_ci .rfield = &ad1843_RMCM, 1428c2ecf20Sopenharmony_ci .lmute = &ad1843_LMCMM, 1438c2ecf20Sopenharmony_ci .rmute = &ad1843_RMCMM 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_PCM_0 = { 1468c2ecf20Sopenharmony_ci .negative = 1, 1478c2ecf20Sopenharmony_ci .lfield = &ad1843_LDA1G, 1488c2ecf20Sopenharmony_ci .rfield = &ad1843_RDA1G, 1498c2ecf20Sopenharmony_ci .lmute = &ad1843_LDA1GM, 1508c2ecf20Sopenharmony_ci .rmute = &ad1843_RDA1GM 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_cistatic const struct ad1843_gain ad1843_gain_PCM_1 = { 1538c2ecf20Sopenharmony_ci .negative = 1, 1548c2ecf20Sopenharmony_ci .lfield = &ad1843_LD2M, 1558c2ecf20Sopenharmony_ci .rfield = &ad1843_RD2M, 1568c2ecf20Sopenharmony_ci .lmute = &ad1843_LD2MM, 1578c2ecf20Sopenharmony_ci .rmute = &ad1843_RD2MM 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct ad1843_gain *ad1843_gain[AD1843_GAIN_SIZE] = 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci &ad1843_gain_RECLEV, 1638c2ecf20Sopenharmony_ci &ad1843_gain_LINE, 1648c2ecf20Sopenharmony_ci &ad1843_gain_LINE_2, 1658c2ecf20Sopenharmony_ci &ad1843_gain_MIC, 1668c2ecf20Sopenharmony_ci &ad1843_gain_PCM_0, 1678c2ecf20Sopenharmony_ci &ad1843_gain_PCM_1, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* read the current value of an AD1843 bitfield. */ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int ad1843_read_bits(struct snd_ad1843 *ad1843, 1738c2ecf20Sopenharmony_ci const struct ad1843_bitfield *field) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci int w; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci w = ad1843->read(ad1843->chip, field->reg); 1788c2ecf20Sopenharmony_ci return w >> field->lo_bit & ((1 << field->nbits) - 1); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * write a new value to an AD1843 bitfield and return the old value. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int ad1843_write_bits(struct snd_ad1843 *ad1843, 1868c2ecf20Sopenharmony_ci const struct ad1843_bitfield *field, 1878c2ecf20Sopenharmony_ci int newval) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int w, mask, oldval, newbits; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci w = ad1843->read(ad1843->chip, field->reg); 1928c2ecf20Sopenharmony_ci mask = ((1 << field->nbits) - 1) << field->lo_bit; 1938c2ecf20Sopenharmony_ci oldval = (w & mask) >> field->lo_bit; 1948c2ecf20Sopenharmony_ci newbits = (newval << field->lo_bit) & mask; 1958c2ecf20Sopenharmony_ci w = (w & ~mask) | newbits; 1968c2ecf20Sopenharmony_ci ad1843->write(ad1843->chip, field->reg, w); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return oldval; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * ad1843_read_multi reads multiple bitfields from the same AD1843 2038c2ecf20Sopenharmony_ci * register. It uses a single read cycle to do it. (Reading the 2048c2ecf20Sopenharmony_ci * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 2058c2ecf20Sopenharmony_ci * microseconds.) 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Called like this. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * ad1843_read_multi(ad1843, nfields, 2108c2ecf20Sopenharmony_ci * &ad1843_FIELD1, &val1, 2118c2ecf20Sopenharmony_ci * &ad1843_FIELD2, &val2, ...); 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void ad1843_read_multi(struct snd_ad1843 *ad1843, int argcount, ...) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci va_list ap; 2178c2ecf20Sopenharmony_ci const struct ad1843_bitfield *fp; 2188c2ecf20Sopenharmony_ci int w = 0, mask, *value, reg = -1; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci va_start(ap, argcount); 2218c2ecf20Sopenharmony_ci while (--argcount >= 0) { 2228c2ecf20Sopenharmony_ci fp = va_arg(ap, const struct ad1843_bitfield *); 2238c2ecf20Sopenharmony_ci value = va_arg(ap, int *); 2248c2ecf20Sopenharmony_ci if (reg == -1) { 2258c2ecf20Sopenharmony_ci reg = fp->reg; 2268c2ecf20Sopenharmony_ci w = ad1843->read(ad1843->chip, reg); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci mask = (1 << fp->nbits) - 1; 2308c2ecf20Sopenharmony_ci *value = w >> fp->lo_bit & mask; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci va_end(ap); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* 2368c2ecf20Sopenharmony_ci * ad1843_write_multi stores multiple bitfields into the same AD1843 2378c2ecf20Sopenharmony_ci * register. It uses one read and one write cycle to do it. 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Called like this. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * ad1843_write_multi(ad1843, nfields, 2428c2ecf20Sopenharmony_ci * &ad1843_FIELD1, val1, 2438c2ecf20Sopenharmony_ci * &ad1843_FIELF2, val2, ...); 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci va_list ap; 2498c2ecf20Sopenharmony_ci int reg; 2508c2ecf20Sopenharmony_ci const struct ad1843_bitfield *fp; 2518c2ecf20Sopenharmony_ci int value; 2528c2ecf20Sopenharmony_ci int w, m, mask, bits; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci mask = 0; 2558c2ecf20Sopenharmony_ci bits = 0; 2568c2ecf20Sopenharmony_ci reg = -1; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci va_start(ap, argcount); 2598c2ecf20Sopenharmony_ci while (--argcount >= 0) { 2608c2ecf20Sopenharmony_ci fp = va_arg(ap, const struct ad1843_bitfield *); 2618c2ecf20Sopenharmony_ci value = va_arg(ap, int); 2628c2ecf20Sopenharmony_ci if (reg == -1) 2638c2ecf20Sopenharmony_ci reg = fp->reg; 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci WARN_ON(reg != fp->reg); 2668c2ecf20Sopenharmony_ci m = ((1 << fp->nbits) - 1) << fp->lo_bit; 2678c2ecf20Sopenharmony_ci mask |= m; 2688c2ecf20Sopenharmony_ci bits |= (value << fp->lo_bit) & m; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci va_end(ap); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (~mask & 0xFFFF) 2738c2ecf20Sopenharmony_ci w = ad1843->read(ad1843->chip, reg); 2748c2ecf20Sopenharmony_ci else 2758c2ecf20Sopenharmony_ci w = 0; 2768c2ecf20Sopenharmony_ci w = (w & ~mask) | bits; 2778c2ecf20Sopenharmony_ci ad1843->write(ad1843->chip, reg, w); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciint ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci const struct ad1843_gain *gp = ad1843_gain[id]; 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci ret = (1 << gp->lfield->nbits); 2868c2ecf20Sopenharmony_ci if (!gp->lmute) 2878c2ecf20Sopenharmony_ci ret -= 1; 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* 2928c2ecf20Sopenharmony_ci * ad1843_get_gain reads the specified register and extracts the gain value 2938c2ecf20Sopenharmony_ci * using the supplied gain type. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ciint ad1843_get_gain(struct snd_ad1843 *ad1843, int id) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int lg, rg, lm, rm; 2998c2ecf20Sopenharmony_ci const struct ad1843_gain *gp = ad1843_gain[id]; 3008c2ecf20Sopenharmony_ci unsigned short mask = (1 << gp->lfield->nbits) - 1; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ad1843_read_multi(ad1843, 2, gp->lfield, &lg, gp->rfield, &rg); 3038c2ecf20Sopenharmony_ci if (gp->negative) { 3048c2ecf20Sopenharmony_ci lg = mask - lg; 3058c2ecf20Sopenharmony_ci rg = mask - rg; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci if (gp->lmute) { 3088c2ecf20Sopenharmony_ci ad1843_read_multi(ad1843, 2, gp->lmute, &lm, gp->rmute, &rm); 3098c2ecf20Sopenharmony_ci if (lm) 3108c2ecf20Sopenharmony_ci lg = 0; 3118c2ecf20Sopenharmony_ci if (rm) 3128c2ecf20Sopenharmony_ci rg = 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci return lg << 0 | rg << 8; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * Set an audio channel's gain. 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Returns the new gain, which may be lower than the old gain. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciint ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci const struct ad1843_gain *gp = ad1843_gain[id]; 3268c2ecf20Sopenharmony_ci unsigned short mask = (1 << gp->lfield->nbits) - 1; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci int lg = (newval >> 0) & mask; 3298c2ecf20Sopenharmony_ci int rg = (newval >> 8) & mask; 3308c2ecf20Sopenharmony_ci int lm = (lg == 0) ? 1 : 0; 3318c2ecf20Sopenharmony_ci int rm = (rg == 0) ? 1 : 0; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (gp->negative) { 3348c2ecf20Sopenharmony_ci lg = mask - lg; 3358c2ecf20Sopenharmony_ci rg = mask - rg; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci if (gp->lmute) 3388c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, gp->lmute, lm, gp->rmute, rm); 3398c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, gp->lfield, lg, gp->rfield, rg); 3408c2ecf20Sopenharmony_ci return ad1843_get_gain(ad1843, id); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* Returns the current recording source */ 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ciint ad1843_get_recsrc(struct snd_ad1843 *ad1843) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci int val = ad1843_read_bits(ad1843, &ad1843_LSS); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (val < 0 || val > 2) { 3508c2ecf20Sopenharmony_ci val = 2; 3518c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, 3528c2ecf20Sopenharmony_ci &ad1843_LSS, val, &ad1843_RSS, val); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci return val; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* 3588c2ecf20Sopenharmony_ci * Set recording source. 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * Returns newsrc on success, -errno on failure. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciint ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci if (newsrc < 0 || newsrc > 2) 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, &ad1843_LSS, newsrc, &ad1843_RSS, newsrc); 3698c2ecf20Sopenharmony_ci return newsrc; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* Setup ad1843 for D/A conversion. */ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_civoid ad1843_setup_dac(struct snd_ad1843 *ad1843, 3758c2ecf20Sopenharmony_ci unsigned int id, 3768c2ecf20Sopenharmony_ci unsigned int framerate, 3778c2ecf20Sopenharmony_ci snd_pcm_format_t fmt, 3788c2ecf20Sopenharmony_ci unsigned int channels) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int ad_fmt = 0, ad_mode = 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci switch (fmt) { 3838c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 3848c2ecf20Sopenharmony_ci ad_fmt = 0; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 3878c2ecf20Sopenharmony_ci ad_fmt = 0; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 3908c2ecf20Sopenharmony_ci ad_fmt = 1; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_MU_LAW: 3938c2ecf20Sopenharmony_ci ad_fmt = 2; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_A_LAW: 3968c2ecf20Sopenharmony_ci ad_fmt = 3; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci switch (channels) { 4038c2ecf20Sopenharmony_ci case 2: 4048c2ecf20Sopenharmony_ci ad_mode = 0; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case 1: 4078c2ecf20Sopenharmony_ci ad_mode = 1; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci default: 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (id) { 4148c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_C2C, framerate); 4158c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, 4168c2ecf20Sopenharmony_ci &ad1843_DA2SM, ad_mode, 4178c2ecf20Sopenharmony_ci &ad1843_DA2F, ad_fmt); 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_C1C, framerate); 4208c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, 4218c2ecf20Sopenharmony_ci &ad1843_DA1SM, ad_mode, 4228c2ecf20Sopenharmony_ci &ad1843_DA1F, ad_fmt); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_civoid ad1843_shutdown_dac(struct snd_ad1843 *ad1843, unsigned int id) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci if (id) 4298c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_DA2F, 1); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_DA1F, 1); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_civoid ad1843_setup_adc(struct snd_ad1843 *ad1843, 4358c2ecf20Sopenharmony_ci unsigned int framerate, 4368c2ecf20Sopenharmony_ci snd_pcm_format_t fmt, 4378c2ecf20Sopenharmony_ci unsigned int channels) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci int da_fmt = 0; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci switch (fmt) { 4428c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: da_fmt = 0; break; 4438c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: da_fmt = 0; break; 4448c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: da_fmt = 1; break; 4458c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_MU_LAW: da_fmt = 2; break; 4468c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_A_LAW: da_fmt = 3; break; 4478c2ecf20Sopenharmony_ci default: break; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_C3C, framerate); 4518c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, 4528c2ecf20Sopenharmony_ci &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_civoid ad1843_shutdown_adc(struct snd_ad1843 *ad1843) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci /* nothing to do */ 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* 4618c2ecf20Sopenharmony_ci * Fully initialize the ad1843. As described in the AD1843 data 4628c2ecf20Sopenharmony_ci * sheet, section "START-UP SEQUENCE". The numbered comments are 4638c2ecf20Sopenharmony_ci * subsection headings from the data sheet. See the data sheet, pages 4648c2ecf20Sopenharmony_ci * 52-54, for more info. 4658c2ecf20Sopenharmony_ci * 4668c2ecf20Sopenharmony_ci * return 0 on success, -errno on failure. */ 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ciint ad1843_init(struct snd_ad1843 *ad1843) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci unsigned long later; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (ad1843_read_bits(ad1843, &ad1843_INIT) != 0) { 4738c2ecf20Sopenharmony_ci printk(KERN_ERR "ad1843: AD1843 won't initialize\n"); 4748c2ecf20Sopenharmony_ci return -EIO; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_SCF, 1); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* 4. Put the conversion resources into standby. */ 4808c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_PDNI, 0); 4818c2ecf20Sopenharmony_ci later = jiffies + msecs_to_jiffies(500); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci while (ad1843_read_bits(ad1843, &ad1843_PDNO)) { 4848c2ecf20Sopenharmony_ci if (time_after(jiffies, later)) { 4858c2ecf20Sopenharmony_ci printk(KERN_ERR 4868c2ecf20Sopenharmony_ci "ad1843: AD1843 won't power up\n"); 4878c2ecf20Sopenharmony_ci return -EIO; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci schedule_timeout_interruptible(5); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* 5. Power up the clock generators and enable clock output pins. */ 4938c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 3, 4948c2ecf20Sopenharmony_ci &ad1843_C1EN, 1, 4958c2ecf20Sopenharmony_ci &ad1843_C2EN, 1, 4968c2ecf20Sopenharmony_ci &ad1843_C3EN, 1); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* 6. Configure conversion resources while they are in standby. */ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* DAC1/2 use clock 1/2 as source, ADC uses clock 3. Always. */ 5018c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 4, 5028c2ecf20Sopenharmony_ci &ad1843_DA1C, 1, 5038c2ecf20Sopenharmony_ci &ad1843_DA2C, 2, 5048c2ecf20Sopenharmony_ci &ad1843_ADLC, 3, 5058c2ecf20Sopenharmony_ci &ad1843_ADRC, 3); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 7. Enable conversion resources. */ 5088c2ecf20Sopenharmony_ci ad1843_write_bits(ad1843, &ad1843_ADTLK, 1); 5098c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 7, 5108c2ecf20Sopenharmony_ci &ad1843_ANAEN, 1, 5118c2ecf20Sopenharmony_ci &ad1843_AAMEN, 1, 5128c2ecf20Sopenharmony_ci &ad1843_DA1EN, 1, 5138c2ecf20Sopenharmony_ci &ad1843_DA2EN, 1, 5148c2ecf20Sopenharmony_ci &ad1843_DDMEN, 1, 5158c2ecf20Sopenharmony_ci &ad1843_ADLEN, 1, 5168c2ecf20Sopenharmony_ci &ad1843_ADREN, 1); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* 8. Configure conversion resources while they are enabled. */ 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* set gain to 0 for all channels */ 5218c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_RECLEV, 0); 5228c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_LINE, 0); 5238c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_LINE_2, 0); 5248c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_MIC, 0); 5258c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_PCM_0, 0); 5268c2ecf20Sopenharmony_ci ad1843_set_gain(ad1843, AD1843_GAIN_PCM_1, 0); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Unmute all channels. */ 5298c2ecf20Sopenharmony_ci /* DAC1 */ 5308c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, &ad1843_LDA1GM, 0, &ad1843_RDA1GM, 0); 5318c2ecf20Sopenharmony_ci /* DAC2 */ 5328c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, &ad1843_LDA2GM, 0, &ad1843_RDA2GM, 0); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Set default recording source to Line In and set 5358c2ecf20Sopenharmony_ci * mic gain to +20 dB. 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci ad1843_set_recsrc(ad1843, 2); 5388c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* Set Speaker Out level to +/- 4V and unmute it. */ 5418c2ecf20Sopenharmony_ci ad1843_write_multi(ad1843, 3, 5428c2ecf20Sopenharmony_ci &ad1843_HPOS, 1, 5438c2ecf20Sopenharmony_ci &ad1843_HPOM, 0, 5448c2ecf20Sopenharmony_ci &ad1843_MPOM, 0); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci} 548