18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Routines for control of the CS8427 via i2c bus
48c2ecf20Sopenharmony_ci *  IEC958 (S/PDIF) receiver & transmitter by Cirrus Logic
58c2ecf20Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/bitrev.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
148c2ecf20Sopenharmony_ci#include <sound/core.h>
158c2ecf20Sopenharmony_ci#include <sound/control.h>
168c2ecf20Sopenharmony_ci#include <sound/pcm.h>
178c2ecf20Sopenharmony_ci#include <sound/cs8427.h>
188c2ecf20Sopenharmony_ci#include <sound/asoundef.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic void snd_cs8427_reset(struct snd_i2c_device *cs8427);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IEC958 (S/PDIF) receiver & transmitter by Cirrus Logic");
248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define CS8427_ADDR			(0x20>>1) /* fixed address */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct cs8427_stream {
298c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
308c2ecf20Sopenharmony_ci	char hw_status[24];		/* hardware status */
318c2ecf20Sopenharmony_ci	char def_status[24];		/* default status */
328c2ecf20Sopenharmony_ci	char pcm_status[24];		/* PCM private status */
338c2ecf20Sopenharmony_ci	char hw_udata[32];
348c2ecf20Sopenharmony_ci	struct snd_kcontrol *pcm_ctl;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct cs8427 {
388c2ecf20Sopenharmony_ci	unsigned char regmap[0x14];	/* map of first 1 + 13 registers */
398c2ecf20Sopenharmony_ci	unsigned int rate;
408c2ecf20Sopenharmony_ci	unsigned int reset_timeout;
418c2ecf20Sopenharmony_ci	struct cs8427_stream playback;
428c2ecf20Sopenharmony_ci	struct cs8427_stream capture;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciint snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
468c2ecf20Sopenharmony_ci			 unsigned char val)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	int err;
498c2ecf20Sopenharmony_ci	unsigned char buf[2];
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	buf[0] = reg & 0x7f;
528c2ecf20Sopenharmony_ci	buf[1] = val;
538c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, buf, 2)) != 2) {
548c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x "
558c2ecf20Sopenharmony_ci			   "to CS8427 (%i)\n", buf[0], buf[1], err);
568c2ecf20Sopenharmony_ci		return err < 0 ? err : -EIO;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_reg_write);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic int snd_cs8427_reg_read(struct snd_i2c_device *device, unsigned char reg)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	int err;
668c2ecf20Sopenharmony_ci	unsigned char buf;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, &reg, 1)) != 1) {
698c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to send register 0x%x byte "
708c2ecf20Sopenharmony_ci			   "to CS8427\n", reg);
718c2ecf20Sopenharmony_ci		return err < 0 ? err : -EIO;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci	if ((err = snd_i2c_readbytes(device, &buf, 1)) != 1) {
748c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to read register 0x%x byte "
758c2ecf20Sopenharmony_ci			   "from CS8427\n", reg);
768c2ecf20Sopenharmony_ci		return err < 0 ? err : -EIO;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	return buf;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int snd_cs8427_select_corudata(struct snd_i2c_device *device, int udata)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct cs8427 *chip = device->private_data;
848c2ecf20Sopenharmony_ci	int err;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	udata = udata ? CS8427_BSEL : 0;
878c2ecf20Sopenharmony_ci	if (udata != (chip->regmap[CS8427_REG_CSDATABUF] & udata)) {
888c2ecf20Sopenharmony_ci		chip->regmap[CS8427_REG_CSDATABUF] &= ~CS8427_BSEL;
898c2ecf20Sopenharmony_ci		chip->regmap[CS8427_REG_CSDATABUF] |= udata;
908c2ecf20Sopenharmony_ci		err = snd_cs8427_reg_write(device, CS8427_REG_CSDATABUF,
918c2ecf20Sopenharmony_ci					   chip->regmap[CS8427_REG_CSDATABUF]);
928c2ecf20Sopenharmony_ci		if (err < 0)
938c2ecf20Sopenharmony_ci			return err;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int snd_cs8427_send_corudata(struct snd_i2c_device *device,
998c2ecf20Sopenharmony_ci				    int udata,
1008c2ecf20Sopenharmony_ci				    unsigned char *ndata,
1018c2ecf20Sopenharmony_ci				    int count)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct cs8427 *chip = device->private_data;
1048c2ecf20Sopenharmony_ci	char *hw_data = udata ?
1058c2ecf20Sopenharmony_ci		chip->playback.hw_udata : chip->playback.hw_status;
1068c2ecf20Sopenharmony_ci	unsigned char data[32];
1078c2ecf20Sopenharmony_ci	int err, idx;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (!memcmp(hw_data, ndata, count))
1108c2ecf20Sopenharmony_ci		return 0;
1118c2ecf20Sopenharmony_ci	if ((err = snd_cs8427_select_corudata(device, udata)) < 0)
1128c2ecf20Sopenharmony_ci		return err;
1138c2ecf20Sopenharmony_ci	memcpy(hw_data, ndata, count);
1148c2ecf20Sopenharmony_ci	if (udata) {
1158c2ecf20Sopenharmony_ci		memset(data, 0, sizeof(data));
1168c2ecf20Sopenharmony_ci		if (memcmp(hw_data, data, count) == 0) {
1178c2ecf20Sopenharmony_ci			chip->regmap[CS8427_REG_UDATABUF] &= ~CS8427_UBMMASK;
1188c2ecf20Sopenharmony_ci			chip->regmap[CS8427_REG_UDATABUF] |= CS8427_UBMZEROS |
1198c2ecf20Sopenharmony_ci				CS8427_EFTUI;
1208c2ecf20Sopenharmony_ci			err = snd_cs8427_reg_write(device, CS8427_REG_UDATABUF,
1218c2ecf20Sopenharmony_ci						   chip->regmap[CS8427_REG_UDATABUF]);
1228c2ecf20Sopenharmony_ci			return err < 0 ? err : 0;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci	data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF;
1268c2ecf20Sopenharmony_ci	for (idx = 0; idx < count; idx++)
1278c2ecf20Sopenharmony_ci		data[idx + 1] = bitrev8(ndata[idx]);
1288c2ecf20Sopenharmony_ci	if (snd_i2c_sendbytes(device, data, count + 1) != count + 1)
1298c2ecf20Sopenharmony_ci		return -EIO;
1308c2ecf20Sopenharmony_ci	return 1;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void snd_cs8427_free(struct snd_i2c_device *device)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	kfree(device->private_data);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ciint snd_cs8427_init(struct snd_i2c_bus *bus,
1398c2ecf20Sopenharmony_ci		    struct snd_i2c_device *device)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	static unsigned char initvals1[] = {
1428c2ecf20Sopenharmony_ci	  CS8427_REG_CONTROL1 | CS8427_REG_AUTOINC,
1438c2ecf20Sopenharmony_ci	  /* CS8427_REG_CONTROL1: RMCK to OMCK, valid PCM audio, disable mutes,
1448c2ecf20Sopenharmony_ci	     TCBL=output */
1458c2ecf20Sopenharmony_ci	  CS8427_SWCLK | CS8427_TCBLDIR,
1468c2ecf20Sopenharmony_ci	  /* CS8427_REG_CONTROL2: hold last valid audio sample, RMCK=256*Fs,
1478c2ecf20Sopenharmony_ci	     normal stereo operation */
1488c2ecf20Sopenharmony_ci	  0x00,
1498c2ecf20Sopenharmony_ci	  /* CS8427_REG_DATAFLOW: output drivers normal operation, Tx<=serial,
1508c2ecf20Sopenharmony_ci	     Rx=>serial */
1518c2ecf20Sopenharmony_ci	  CS8427_TXDSERIAL | CS8427_SPDAES3RECEIVER,
1528c2ecf20Sopenharmony_ci	  /* CS8427_REG_CLOCKSOURCE: Run off, CMCK=256*Fs,
1538c2ecf20Sopenharmony_ci	     output time base = OMCK, input time base = recovered input clock,
1548c2ecf20Sopenharmony_ci	     recovered input clock source is ILRCK changed to AES3INPUT
1558c2ecf20Sopenharmony_ci	     (workaround, see snd_cs8427_reset) */
1568c2ecf20Sopenharmony_ci	  CS8427_RXDILRCK,
1578c2ecf20Sopenharmony_ci	  /* CS8427_REG_SERIALINPUT: Serial audio input port data format = I2S,
1588c2ecf20Sopenharmony_ci	     24-bit, 64*Fsi */
1598c2ecf20Sopenharmony_ci	  CS8427_SIDEL | CS8427_SILRPOL,
1608c2ecf20Sopenharmony_ci	  /* CS8427_REG_SERIALOUTPUT: Serial audio output port data format
1618c2ecf20Sopenharmony_ci	     = I2S, 24-bit, 64*Fsi */
1628c2ecf20Sopenharmony_ci	  CS8427_SODEL | CS8427_SOLRPOL,
1638c2ecf20Sopenharmony_ci	};
1648c2ecf20Sopenharmony_ci	static unsigned char initvals2[] = {
1658c2ecf20Sopenharmony_ci	  CS8427_REG_RECVERRMASK | CS8427_REG_AUTOINC,
1668c2ecf20Sopenharmony_ci	  /* CS8427_REG_RECVERRMASK: unmask the input PLL clock, V, confidence,
1678c2ecf20Sopenharmony_ci	     biphase, parity status bits */
1688c2ecf20Sopenharmony_ci	  /* CS8427_UNLOCK | CS8427_V | CS8427_CONF | CS8427_BIP | CS8427_PAR,*/
1698c2ecf20Sopenharmony_ci	  0xff, /* set everything */
1708c2ecf20Sopenharmony_ci	  /* CS8427_REG_CSDATABUF:
1718c2ecf20Sopenharmony_ci	     Registers 32-55 window to CS buffer
1728c2ecf20Sopenharmony_ci	     Inhibit D->E transfers from overwriting first 5 bytes of CS data.
1738c2ecf20Sopenharmony_ci	     Inhibit D->E transfers (all) of CS data.
1748c2ecf20Sopenharmony_ci	     Allow E->F transfer of CS data.
1758c2ecf20Sopenharmony_ci	     One byte mode; both A/B channels get same written CB data.
1768c2ecf20Sopenharmony_ci	     A channel info is output to chip's EMPH* pin. */
1778c2ecf20Sopenharmony_ci	  CS8427_CBMR | CS8427_DETCI,
1788c2ecf20Sopenharmony_ci	  /* CS8427_REG_UDATABUF:
1798c2ecf20Sopenharmony_ci	     Use internal buffer to transmit User (U) data.
1808c2ecf20Sopenharmony_ci	     Chip's U pin is an output.
1818c2ecf20Sopenharmony_ci	     Transmit all O's for user data.
1828c2ecf20Sopenharmony_ci	     Inhibit D->E transfers.
1838c2ecf20Sopenharmony_ci	     Inhibit E->F transfers. */
1848c2ecf20Sopenharmony_ci	  CS8427_UD | CS8427_EFTUI | CS8427_DETUI,
1858c2ecf20Sopenharmony_ci	};
1868c2ecf20Sopenharmony_ci	struct cs8427 *chip = device->private_data;
1878c2ecf20Sopenharmony_ci	int err;
1888c2ecf20Sopenharmony_ci	unsigned char buf[24];
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	snd_i2c_lock(bus);
1918c2ecf20Sopenharmony_ci	err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
1928c2ecf20Sopenharmony_ci	if (err != CS8427_VER8427A) {
1938c2ecf20Sopenharmony_ci		/* give second chance */
1948c2ecf20Sopenharmony_ci		snd_printk(KERN_WARNING "invalid CS8427 signature 0x%x: "
1958c2ecf20Sopenharmony_ci			   "let me try again...\n", err);
1968c2ecf20Sopenharmony_ci		err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci	if (err != CS8427_VER8427A) {
1998c2ecf20Sopenharmony_ci		snd_i2c_unlock(bus);
2008c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to find CS8427 signature "
2018c2ecf20Sopenharmony_ci			   "(expected 0x%x, read 0x%x),\n",
2028c2ecf20Sopenharmony_ci			   CS8427_VER8427A, err);
2038c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "   initialization is not completed\n");
2048c2ecf20Sopenharmony_ci		return -EFAULT;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	/* turn off run bit while making changes to configuration */
2078c2ecf20Sopenharmony_ci	err = snd_cs8427_reg_write(device, CS8427_REG_CLOCKSOURCE, 0x00);
2088c2ecf20Sopenharmony_ci	if (err < 0)
2098c2ecf20Sopenharmony_ci		goto __fail;
2108c2ecf20Sopenharmony_ci	/* send initial values */
2118c2ecf20Sopenharmony_ci	memcpy(chip->regmap + (initvals1[0] & 0x7f), initvals1 + 1, 6);
2128c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, initvals1, 7)) != 7) {
2138c2ecf20Sopenharmony_ci		err = err < 0 ? err : -EIO;
2148c2ecf20Sopenharmony_ci		goto __fail;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	/* Turn off CS8427 interrupt stuff that is not used in hardware */
2178c2ecf20Sopenharmony_ci	memset(buf, 0, 7);
2188c2ecf20Sopenharmony_ci	/* from address 9 to 15 */
2198c2ecf20Sopenharmony_ci	buf[0] = 9;	/* register */
2208c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, buf, 7)) != 7)
2218c2ecf20Sopenharmony_ci		goto __fail;
2228c2ecf20Sopenharmony_ci	/* send transfer initialization sequence */
2238c2ecf20Sopenharmony_ci	memcpy(chip->regmap + (initvals2[0] & 0x7f), initvals2 + 1, 3);
2248c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, initvals2, 4)) != 4) {
2258c2ecf20Sopenharmony_ci		err = err < 0 ? err : -EIO;
2268c2ecf20Sopenharmony_ci		goto __fail;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	/* write default channel status bytes */
2298c2ecf20Sopenharmony_ci	put_unaligned_le32(SNDRV_PCM_DEFAULT_CON_SPDIF, buf);
2308c2ecf20Sopenharmony_ci	memset(buf + 4, 0, 24 - 4);
2318c2ecf20Sopenharmony_ci	if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0)
2328c2ecf20Sopenharmony_ci		goto __fail;
2338c2ecf20Sopenharmony_ci	memcpy(chip->playback.def_status, buf, 24);
2348c2ecf20Sopenharmony_ci	memcpy(chip->playback.pcm_status, buf, 24);
2358c2ecf20Sopenharmony_ci	snd_i2c_unlock(bus);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* turn on run bit and rock'n'roll */
2388c2ecf20Sopenharmony_ci	snd_cs8427_reset(device);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return 0;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci__fail:
2438c2ecf20Sopenharmony_ci	snd_i2c_unlock(bus);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return err;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_init);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ciint snd_cs8427_create(struct snd_i2c_bus *bus,
2508c2ecf20Sopenharmony_ci		      unsigned char addr,
2518c2ecf20Sopenharmony_ci		      unsigned int reset_timeout,
2528c2ecf20Sopenharmony_ci		      struct snd_i2c_device **r_cs8427)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	int err;
2558c2ecf20Sopenharmony_ci	struct cs8427 *chip;
2568c2ecf20Sopenharmony_ci	struct snd_i2c_device *device;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7),
2598c2ecf20Sopenharmony_ci				    &device);
2608c2ecf20Sopenharmony_ci	if (err < 0)
2618c2ecf20Sopenharmony_ci		return err;
2628c2ecf20Sopenharmony_ci	chip = device->private_data = kzalloc(sizeof(*chip), GFP_KERNEL);
2638c2ecf20Sopenharmony_ci	if (chip == NULL) {
2648c2ecf20Sopenharmony_ci		snd_i2c_device_free(device);
2658c2ecf20Sopenharmony_ci		return -ENOMEM;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci	device->private_free = snd_cs8427_free;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (reset_timeout < 1)
2708c2ecf20Sopenharmony_ci		reset_timeout = 1;
2718c2ecf20Sopenharmony_ci	chip->reset_timeout = reset_timeout;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	err = snd_cs8427_init(bus, device);
2748c2ecf20Sopenharmony_ci	if (err)
2758c2ecf20Sopenharmony_ci		goto __fail;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci#if 0	// it's nice for read tests
2788c2ecf20Sopenharmony_ci	{
2798c2ecf20Sopenharmony_ci	char buf[128];
2808c2ecf20Sopenharmony_ci	int xx;
2818c2ecf20Sopenharmony_ci	buf[0] = 0x81;
2828c2ecf20Sopenharmony_ci	snd_i2c_sendbytes(device, buf, 1);
2838c2ecf20Sopenharmony_ci	snd_i2c_readbytes(device, buf, 127);
2848c2ecf20Sopenharmony_ci	for (xx = 0; xx < 127; xx++)
2858c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "reg[0x%x] = 0x%x\n", xx+1, buf[xx]);
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci#endif
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (r_cs8427)
2908c2ecf20Sopenharmony_ci		*r_cs8427 = device;
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci      __fail:
2948c2ecf20Sopenharmony_ci      	snd_i2c_device_free(device);
2958c2ecf20Sopenharmony_ci      	return err < 0 ? err : -EIO;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_create);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci/*
3018c2ecf20Sopenharmony_ci * Reset the chip using run bit, also lock PLL using ILRCK and
3028c2ecf20Sopenharmony_ci * put back AES3INPUT. This workaround is described in latest
3038c2ecf20Sopenharmony_ci * CS8427 datasheet, otherwise TXDSERIAL will not work.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_cistatic void snd_cs8427_reset(struct snd_i2c_device *cs8427)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct cs8427 *chip;
3088c2ecf20Sopenharmony_ci	unsigned long end_time;
3098c2ecf20Sopenharmony_ci	int data, aes3input = 0;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!cs8427))
3128c2ecf20Sopenharmony_ci		return;
3138c2ecf20Sopenharmony_ci	chip = cs8427->private_data;
3148c2ecf20Sopenharmony_ci	snd_i2c_lock(cs8427->bus);
3158c2ecf20Sopenharmony_ci	if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) ==
3168c2ecf20Sopenharmony_ci	    CS8427_RXDAES3INPUT)  /* AES3 bit is set */
3178c2ecf20Sopenharmony_ci		aes3input = 1;
3188c2ecf20Sopenharmony_ci	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK);
3198c2ecf20Sopenharmony_ci	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
3208c2ecf20Sopenharmony_ci			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
3218c2ecf20Sopenharmony_ci	udelay(200);
3228c2ecf20Sopenharmony_ci	chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RUN | CS8427_RXDILRCK;
3238c2ecf20Sopenharmony_ci	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
3248c2ecf20Sopenharmony_ci			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
3258c2ecf20Sopenharmony_ci	udelay(200);
3268c2ecf20Sopenharmony_ci	snd_i2c_unlock(cs8427->bus);
3278c2ecf20Sopenharmony_ci	end_time = jiffies + chip->reset_timeout;
3288c2ecf20Sopenharmony_ci	while (time_after_eq(end_time, jiffies)) {
3298c2ecf20Sopenharmony_ci		snd_i2c_lock(cs8427->bus);
3308c2ecf20Sopenharmony_ci		data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS);
3318c2ecf20Sopenharmony_ci		snd_i2c_unlock(cs8427->bus);
3328c2ecf20Sopenharmony_ci		if (!(data & CS8427_UNLOCK))
3338c2ecf20Sopenharmony_ci			break;
3348c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(1);
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci	snd_i2c_lock(cs8427->bus);
3378c2ecf20Sopenharmony_ci	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
3388c2ecf20Sopenharmony_ci	if (aes3input)
3398c2ecf20Sopenharmony_ci		chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT;
3408c2ecf20Sopenharmony_ci	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
3418c2ecf20Sopenharmony_ci			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
3428c2ecf20Sopenharmony_ci	snd_i2c_unlock(cs8427->bus);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int snd_cs8427_in_status_info(struct snd_kcontrol *kcontrol,
3468c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_info *uinfo)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3498c2ecf20Sopenharmony_ci	uinfo->count = 1;
3508c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
3518c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 255;
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int snd_cs8427_in_status_get(struct snd_kcontrol *kcontrol,
3568c2ecf20Sopenharmony_ci				    struct snd_ctl_elem_value *ucontrol)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct snd_i2c_device *device = snd_kcontrol_chip(kcontrol);
3598c2ecf20Sopenharmony_ci	int data;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	snd_i2c_lock(device->bus);
3628c2ecf20Sopenharmony_ci	data = snd_cs8427_reg_read(device, kcontrol->private_value);
3638c2ecf20Sopenharmony_ci	snd_i2c_unlock(device->bus);
3648c2ecf20Sopenharmony_ci	if (data < 0)
3658c2ecf20Sopenharmony_ci		return data;
3668c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = data;
3678c2ecf20Sopenharmony_ci	return 0;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int snd_cs8427_qsubcode_info(struct snd_kcontrol *kcontrol,
3718c2ecf20Sopenharmony_ci				    struct snd_ctl_elem_info *uinfo)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
3748c2ecf20Sopenharmony_ci	uinfo->count = 10;
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int snd_cs8427_qsubcode_get(struct snd_kcontrol *kcontrol,
3798c2ecf20Sopenharmony_ci				   struct snd_ctl_elem_value *ucontrol)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct snd_i2c_device *device = snd_kcontrol_chip(kcontrol);
3828c2ecf20Sopenharmony_ci	unsigned char reg = CS8427_REG_QSUBCODE;
3838c2ecf20Sopenharmony_ci	int err;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	snd_i2c_lock(device->bus);
3868c2ecf20Sopenharmony_ci	if ((err = snd_i2c_sendbytes(device, &reg, 1)) != 1) {
3878c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to send register 0x%x byte "
3888c2ecf20Sopenharmony_ci			   "to CS8427\n", reg);
3898c2ecf20Sopenharmony_ci		snd_i2c_unlock(device->bus);
3908c2ecf20Sopenharmony_ci		return err < 0 ? err : -EIO;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci	err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10);
3938c2ecf20Sopenharmony_ci	if (err != 10) {
3948c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "unable to read Q-subcode bytes "
3958c2ecf20Sopenharmony_ci			   "from CS8427\n");
3968c2ecf20Sopenharmony_ci		snd_i2c_unlock(device->bus);
3978c2ecf20Sopenharmony_ci		return err < 0 ? err : -EIO;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci	snd_i2c_unlock(device->bus);
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int snd_cs8427_spdif_info(struct snd_kcontrol *kcontrol,
4048c2ecf20Sopenharmony_ci				 struct snd_ctl_elem_info *uinfo)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
4078c2ecf20Sopenharmony_ci	uinfo->count = 1;
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int snd_cs8427_spdif_get(struct snd_kcontrol *kcontrol,
4128c2ecf20Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct snd_i2c_device *device = snd_kcontrol_chip(kcontrol);
4158c2ecf20Sopenharmony_ci	struct cs8427 *chip = device->private_data;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	snd_i2c_lock(device->bus);
4188c2ecf20Sopenharmony_ci	memcpy(ucontrol->value.iec958.status, chip->playback.def_status, 24);
4198c2ecf20Sopenharmony_ci	snd_i2c_unlock(device->bus);
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic int snd_cs8427_spdif_put(struct snd_kcontrol *kcontrol,
4248c2ecf20Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct snd_i2c_device *device = snd_kcontrol_chip(kcontrol);
4278c2ecf20Sopenharmony_ci	struct cs8427 *chip = device->private_data;
4288c2ecf20Sopenharmony_ci	unsigned char *status = kcontrol->private_value ?
4298c2ecf20Sopenharmony_ci		chip->playback.pcm_status : chip->playback.def_status;
4308c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = chip->playback.substream ?
4318c2ecf20Sopenharmony_ci		chip->playback.substream->runtime : NULL;
4328c2ecf20Sopenharmony_ci	int err, change;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	snd_i2c_lock(device->bus);
4358c2ecf20Sopenharmony_ci	change = memcmp(ucontrol->value.iec958.status, status, 24) != 0;
4368c2ecf20Sopenharmony_ci	memcpy(status, ucontrol->value.iec958.status, 24);
4378c2ecf20Sopenharmony_ci	if (change && (kcontrol->private_value ?
4388c2ecf20Sopenharmony_ci		       runtime != NULL : runtime == NULL)) {
4398c2ecf20Sopenharmony_ci		err = snd_cs8427_send_corudata(device, 0, status, 24);
4408c2ecf20Sopenharmony_ci		if (err < 0)
4418c2ecf20Sopenharmony_ci			change = err;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci	snd_i2c_unlock(device->bus);
4448c2ecf20Sopenharmony_ci	return change;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int snd_cs8427_spdif_mask_info(struct snd_kcontrol *kcontrol,
4488c2ecf20Sopenharmony_ci				      struct snd_ctl_elem_info *uinfo)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
4518c2ecf20Sopenharmony_ci	uinfo->count = 1;
4528c2ecf20Sopenharmony_ci	return 0;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic int snd_cs8427_spdif_mask_get(struct snd_kcontrol *kcontrol,
4568c2ecf20Sopenharmony_ci				      struct snd_ctl_elem_value *ucontrol)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	memset(ucontrol->value.iec958.status, 0xff, 24);
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_cs8427_iec958_controls[] = {
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
4658c2ecf20Sopenharmony_ci	.info =		snd_cs8427_in_status_info,
4668c2ecf20Sopenharmony_ci	.name =		"IEC958 CS8427 Input Status",
4678c2ecf20Sopenharmony_ci	.access =	(SNDRV_CTL_ELEM_ACCESS_READ |
4688c2ecf20Sopenharmony_ci			 SNDRV_CTL_ELEM_ACCESS_VOLATILE),
4698c2ecf20Sopenharmony_ci	.get =		snd_cs8427_in_status_get,
4708c2ecf20Sopenharmony_ci	.private_value = 15,
4718c2ecf20Sopenharmony_ci},
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
4748c2ecf20Sopenharmony_ci	.info =		snd_cs8427_in_status_info,
4758c2ecf20Sopenharmony_ci	.name =		"IEC958 CS8427 Error Status",
4768c2ecf20Sopenharmony_ci	.access =	(SNDRV_CTL_ELEM_ACCESS_READ |
4778c2ecf20Sopenharmony_ci			 SNDRV_CTL_ELEM_ACCESS_VOLATILE),
4788c2ecf20Sopenharmony_ci	.get =		snd_cs8427_in_status_get,
4798c2ecf20Sopenharmony_ci	.private_value = 16,
4808c2ecf20Sopenharmony_ci},
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
4838c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
4848c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
4858c2ecf20Sopenharmony_ci	.info =		snd_cs8427_spdif_mask_info,
4868c2ecf20Sopenharmony_ci	.get =		snd_cs8427_spdif_mask_get,
4878c2ecf20Sopenharmony_ci},
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
4908c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
4918c2ecf20Sopenharmony_ci	.info =		snd_cs8427_spdif_info,
4928c2ecf20Sopenharmony_ci	.get =		snd_cs8427_spdif_get,
4938c2ecf20Sopenharmony_ci	.put =		snd_cs8427_spdif_put,
4948c2ecf20Sopenharmony_ci	.private_value = 0
4958c2ecf20Sopenharmony_ci},
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	.access =	(SNDRV_CTL_ELEM_ACCESS_READWRITE |
4988c2ecf20Sopenharmony_ci			 SNDRV_CTL_ELEM_ACCESS_INACTIVE),
4998c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
5008c2ecf20Sopenharmony_ci	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
5018c2ecf20Sopenharmony_ci	.info =		snd_cs8427_spdif_info,
5028c2ecf20Sopenharmony_ci	.get =		snd_cs8427_spdif_get,
5038c2ecf20Sopenharmony_ci	.put =		snd_cs8427_spdif_put,
5048c2ecf20Sopenharmony_ci	.private_value = 1
5058c2ecf20Sopenharmony_ci},
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
5088c2ecf20Sopenharmony_ci	.info =		snd_cs8427_qsubcode_info,
5098c2ecf20Sopenharmony_ci	.name =		"IEC958 Q-subcode Capture Default",
5108c2ecf20Sopenharmony_ci	.access =	(SNDRV_CTL_ELEM_ACCESS_READ |
5118c2ecf20Sopenharmony_ci			 SNDRV_CTL_ELEM_ACCESS_VOLATILE),
5128c2ecf20Sopenharmony_ci	.get =		snd_cs8427_qsubcode_get
5138c2ecf20Sopenharmony_ci}};
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ciint snd_cs8427_iec958_build(struct snd_i2c_device *cs8427,
5168c2ecf20Sopenharmony_ci			    struct snd_pcm_substream *play_substream,
5178c2ecf20Sopenharmony_ci			    struct snd_pcm_substream *cap_substream)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct cs8427 *chip = cs8427->private_data;
5208c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
5218c2ecf20Sopenharmony_ci	unsigned int idx;
5228c2ecf20Sopenharmony_ci	int err;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!play_substream || !cap_substream))
5258c2ecf20Sopenharmony_ci		return -EINVAL;
5268c2ecf20Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(snd_cs8427_iec958_controls); idx++) {
5278c2ecf20Sopenharmony_ci		kctl = snd_ctl_new1(&snd_cs8427_iec958_controls[idx], cs8427);
5288c2ecf20Sopenharmony_ci		if (kctl == NULL)
5298c2ecf20Sopenharmony_ci			return -ENOMEM;
5308c2ecf20Sopenharmony_ci		kctl->id.device = play_substream->pcm->device;
5318c2ecf20Sopenharmony_ci		kctl->id.subdevice = play_substream->number;
5328c2ecf20Sopenharmony_ci		err = snd_ctl_add(cs8427->bus->card, kctl);
5338c2ecf20Sopenharmony_ci		if (err < 0)
5348c2ecf20Sopenharmony_ci			return err;
5358c2ecf20Sopenharmony_ci		if (! strcmp(kctl->id.name,
5368c2ecf20Sopenharmony_ci			     SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM)))
5378c2ecf20Sopenharmony_ci			chip->playback.pcm_ctl = kctl;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	chip->playback.substream = play_substream;
5418c2ecf20Sopenharmony_ci	chip->capture.substream = cap_substream;
5428c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!chip->playback.pcm_ctl))
5438c2ecf20Sopenharmony_ci		return -EIO;
5448c2ecf20Sopenharmony_ci	return 0;
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_iec958_build);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ciint snd_cs8427_iec958_active(struct snd_i2c_device *cs8427, int active)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct cs8427 *chip;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!cs8427))
5548c2ecf20Sopenharmony_ci		return -ENXIO;
5558c2ecf20Sopenharmony_ci	chip = cs8427->private_data;
5568c2ecf20Sopenharmony_ci	if (active) {
5578c2ecf20Sopenharmony_ci		memcpy(chip->playback.pcm_status,
5588c2ecf20Sopenharmony_ci		       chip->playback.def_status, 24);
5598c2ecf20Sopenharmony_ci		chip->playback.pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
5608c2ecf20Sopenharmony_ci	} else {
5618c2ecf20Sopenharmony_ci		chip->playback.pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	snd_ctl_notify(cs8427->bus->card,
5648c2ecf20Sopenharmony_ci		       SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
5658c2ecf20Sopenharmony_ci		       &chip->playback.pcm_ctl->id);
5668c2ecf20Sopenharmony_ci	return 0;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_iec958_active);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ciint snd_cs8427_iec958_pcm(struct snd_i2c_device *cs8427, unsigned int rate)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct cs8427 *chip;
5748c2ecf20Sopenharmony_ci	char *status;
5758c2ecf20Sopenharmony_ci	int err, reset;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!cs8427))
5788c2ecf20Sopenharmony_ci		return -ENXIO;
5798c2ecf20Sopenharmony_ci	chip = cs8427->private_data;
5808c2ecf20Sopenharmony_ci	status = chip->playback.pcm_status;
5818c2ecf20Sopenharmony_ci	snd_i2c_lock(cs8427->bus);
5828c2ecf20Sopenharmony_ci	if (status[0] & IEC958_AES0_PROFESSIONAL) {
5838c2ecf20Sopenharmony_ci		status[0] &= ~IEC958_AES0_PRO_FS;
5848c2ecf20Sopenharmony_ci		switch (rate) {
5858c2ecf20Sopenharmony_ci		case 32000: status[0] |= IEC958_AES0_PRO_FS_32000; break;
5868c2ecf20Sopenharmony_ci		case 44100: status[0] |= IEC958_AES0_PRO_FS_44100; break;
5878c2ecf20Sopenharmony_ci		case 48000: status[0] |= IEC958_AES0_PRO_FS_48000; break;
5888c2ecf20Sopenharmony_ci		default: status[0] |= IEC958_AES0_PRO_FS_NOTID; break;
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci	} else {
5918c2ecf20Sopenharmony_ci		status[3] &= ~IEC958_AES3_CON_FS;
5928c2ecf20Sopenharmony_ci		switch (rate) {
5938c2ecf20Sopenharmony_ci		case 32000: status[3] |= IEC958_AES3_CON_FS_32000; break;
5948c2ecf20Sopenharmony_ci		case 44100: status[3] |= IEC958_AES3_CON_FS_44100; break;
5958c2ecf20Sopenharmony_ci		case 48000: status[3] |= IEC958_AES3_CON_FS_48000; break;
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci	err = snd_cs8427_send_corudata(cs8427, 0, status, 24);
5998c2ecf20Sopenharmony_ci	if (err > 0)
6008c2ecf20Sopenharmony_ci		snd_ctl_notify(cs8427->bus->card,
6018c2ecf20Sopenharmony_ci			       SNDRV_CTL_EVENT_MASK_VALUE,
6028c2ecf20Sopenharmony_ci			       &chip->playback.pcm_ctl->id);
6038c2ecf20Sopenharmony_ci	reset = chip->rate != rate;
6048c2ecf20Sopenharmony_ci	chip->rate = rate;
6058c2ecf20Sopenharmony_ci	snd_i2c_unlock(cs8427->bus);
6068c2ecf20Sopenharmony_ci	if (reset)
6078c2ecf20Sopenharmony_ci		snd_cs8427_reset(cs8427);
6088c2ecf20Sopenharmony_ci	return err < 0 ? err : 0;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_cs8427_iec958_pcm);
612