xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/zl38060.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Codec driver for Microsemi ZL38060 Connected Home Audio Processor.
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright(c) 2020 Sven Van Asbroeck
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun // The ZL38060 is very flexible and configurable. This driver implements only a
8*4882a593Smuzhiyun // tiny subset of the chip's possible configurations:
9*4882a593Smuzhiyun //
10*4882a593Smuzhiyun // - DSP block bypassed: DAI        routed straight to DACs
11*4882a593Smuzhiyun //                       microphone routed straight to DAI
12*4882a593Smuzhiyun // - chip's internal clock is driven by a 12 MHz external crystal
13*4882a593Smuzhiyun // - chip's DAI connected to CPU is I2S, and bit + frame clock master
14*4882a593Smuzhiyun // - chip must be strapped for "host boot": in this mode, firmware will be
15*4882a593Smuzhiyun //   provided by this driver.
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
18*4882a593Smuzhiyun #include <linux/gpio/driver.h>
19*4882a593Smuzhiyun #include <linux/property.h>
20*4882a593Smuzhiyun #include <linux/spi/spi.h>
21*4882a593Smuzhiyun #include <linux/regmap.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/ihex.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <sound/pcm_params.h>
26*4882a593Smuzhiyun #include <sound/core.h>
27*4882a593Smuzhiyun #include <sound/pcm.h>
28*4882a593Smuzhiyun #include <sound/soc.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define DRV_NAME		"zl38060"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define ZL38_RATES		(SNDRV_PCM_RATE_8000  |\
33*4882a593Smuzhiyun 				SNDRV_PCM_RATE_16000 |\
34*4882a593Smuzhiyun 				SNDRV_PCM_RATE_48000)
35*4882a593Smuzhiyun #define ZL38_FORMATS		SNDRV_PCM_FMTBIT_S16_LE
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define HBI_FIRMWARE_PAGE	0xFF
38*4882a593Smuzhiyun #define ZL38_MAX_RAW_XFER	0x100
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define REG_TDMA_CFG_CLK	0x0262
41*4882a593Smuzhiyun #define CFG_CLK_PCLK_SHIFT	4
42*4882a593Smuzhiyun #define CFG_CLK_PCLK_MASK	(0x7ff << CFG_CLK_PCLK_SHIFT)
43*4882a593Smuzhiyun #define CFG_CLK_PCLK(bits)	((bits - 1) << CFG_CLK_PCLK_SHIFT)
44*4882a593Smuzhiyun #define CFG_CLK_MASTER		BIT(15)
45*4882a593Smuzhiyun #define CFG_CLK_FSRATE_MASK	0x7
46*4882a593Smuzhiyun #define CFG_CLK_FSRATE_8KHZ	0x1
47*4882a593Smuzhiyun #define CFG_CLK_FSRATE_16KHZ	0x2
48*4882a593Smuzhiyun #define CFG_CLK_FSRATE_48KHZ	0x6
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define REG_CLK_CFG		0x0016
51*4882a593Smuzhiyun #define CLK_CFG_SOURCE_XTAL	BIT(15)
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define REG_CLK_STATUS		0x0014
54*4882a593Smuzhiyun #define CLK_STATUS_HWRST	BIT(0)
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define REG_PARAM_RESULT	0x0034
57*4882a593Smuzhiyun #define PARAM_RESULT_READY	0xD3D3
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define REG_PG255_BASE_HI	0x000C
60*4882a593Smuzhiyun #define REG_PG255_OFFS(addr)	((HBI_FIRMWARE_PAGE << 8) | (addr & 0xFF))
61*4882a593Smuzhiyun #define REG_FWR_EXEC		0x012C
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define REG_CMD			0x0032
64*4882a593Smuzhiyun #define REG_HW_REV		0x0020
65*4882a593Smuzhiyun #define REG_FW_PROD		0x0022
66*4882a593Smuzhiyun #define REG_FW_REV		0x0024
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define REG_SEMA_FLAGS		0x0006
69*4882a593Smuzhiyun #define SEMA_FLAGS_BOOT_CMD	BIT(0)
70*4882a593Smuzhiyun #define SEMA_FLAGS_APP_REBOOT	BIT(1)
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define REG_HW_REV		0x0020
73*4882a593Smuzhiyun #define REG_FW_PROD		0x0022
74*4882a593Smuzhiyun #define REG_FW_REV		0x0024
75*4882a593Smuzhiyun #define REG_GPIO_DIR		0x02DC
76*4882a593Smuzhiyun #define REG_GPIO_DAT		0x02DA
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #define BOOTCMD_LOAD_COMPLETE	0x000D
79*4882a593Smuzhiyun #define BOOTCMD_FW_GO		0x0008
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define FIRMWARE_MAJOR		2
82*4882a593Smuzhiyun #define FIRMWARE_MINOR		2
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun struct zl38_codec_priv {
85*4882a593Smuzhiyun 	struct device *dev;
86*4882a593Smuzhiyun 	struct regmap *regmap;
87*4882a593Smuzhiyun 	bool is_stream_in_use[2];
88*4882a593Smuzhiyun 	struct gpio_chip *gpio_chip;
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
zl38_fw_issue_command(struct regmap * regmap,u16 cmd)91*4882a593Smuzhiyun static int zl38_fw_issue_command(struct regmap *regmap, u16 cmd)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	unsigned int val;
94*4882a593Smuzhiyun 	int err;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	err = regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
97*4882a593Smuzhiyun 				       !(val & SEMA_FLAGS_BOOT_CMD), 10000,
98*4882a593Smuzhiyun 				       10000 * 100);
99*4882a593Smuzhiyun 	if (err)
100*4882a593Smuzhiyun 		return err;
101*4882a593Smuzhiyun 	err = regmap_write(regmap, REG_CMD, cmd);
102*4882a593Smuzhiyun 	if (err)
103*4882a593Smuzhiyun 		return err;
104*4882a593Smuzhiyun 	err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_BOOT_CMD,
105*4882a593Smuzhiyun 				 SEMA_FLAGS_BOOT_CMD);
106*4882a593Smuzhiyun 	if (err)
107*4882a593Smuzhiyun 		return err;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return regmap_read_poll_timeout(regmap, REG_CMD, val, !val, 10000,
110*4882a593Smuzhiyun 					10000 * 100);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
zl38_fw_go(struct regmap * regmap)113*4882a593Smuzhiyun static int zl38_fw_go(struct regmap *regmap)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	int err;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	err = zl38_fw_issue_command(regmap, BOOTCMD_LOAD_COMPLETE);
118*4882a593Smuzhiyun 	if (err)
119*4882a593Smuzhiyun 		return err;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return zl38_fw_issue_command(regmap, BOOTCMD_FW_GO);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
zl38_fw_enter_boot_mode(struct regmap * regmap)124*4882a593Smuzhiyun static int zl38_fw_enter_boot_mode(struct regmap *regmap)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	unsigned int val;
127*4882a593Smuzhiyun 	int err;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	err = regmap_update_bits(regmap, REG_CLK_STATUS, CLK_STATUS_HWRST,
130*4882a593Smuzhiyun 				 CLK_STATUS_HWRST);
131*4882a593Smuzhiyun 	if (err)
132*4882a593Smuzhiyun 		return err;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return regmap_read_poll_timeout(regmap, REG_PARAM_RESULT, val,
135*4882a593Smuzhiyun 					val == PARAM_RESULT_READY, 1000, 50000);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static int
zl38_fw_send_data(struct regmap * regmap,u32 addr,const void * data,u16 len)139*4882a593Smuzhiyun zl38_fw_send_data(struct regmap *regmap, u32 addr, const void *data, u16 len)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	__be32 addr_base = cpu_to_be32(addr & ~0xFF);
142*4882a593Smuzhiyun 	int err;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	err = regmap_raw_write(regmap, REG_PG255_BASE_HI, &addr_base,
145*4882a593Smuzhiyun 			       sizeof(addr_base));
146*4882a593Smuzhiyun 	if (err)
147*4882a593Smuzhiyun 		return err;
148*4882a593Smuzhiyun 	return regmap_raw_write(regmap, REG_PG255_OFFS(addr), data, len);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
zl38_fw_send_xaddr(struct regmap * regmap,const void * data)151*4882a593Smuzhiyun static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	/* execution address from ihex: 32-bit little endian.
154*4882a593Smuzhiyun 	 * device register expects 32-bit big endian.
155*4882a593Smuzhiyun 	 */
156*4882a593Smuzhiyun 	u32 addr = le32_to_cpup(data);
157*4882a593Smuzhiyun 	__be32 baddr = cpu_to_be32(addr);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return regmap_raw_write(regmap, REG_FWR_EXEC, &baddr, sizeof(baddr));
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
zl38_load_firmware(struct device * dev,struct regmap * regmap)162*4882a593Smuzhiyun static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	const struct ihex_binrec *rec;
165*4882a593Smuzhiyun 	const struct firmware *fw;
166*4882a593Smuzhiyun 	u32 addr;
167*4882a593Smuzhiyun 	u16 len;
168*4882a593Smuzhiyun 	int err;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/* how to get this firmware:
171*4882a593Smuzhiyun 	 * 1. request and download chip firmware from Microsemi
172*4882a593Smuzhiyun 	 *    (provided by Microsemi in srec format)
173*4882a593Smuzhiyun 	 * 2. convert downloaded firmware from srec to ihex. Simple tool:
174*4882a593Smuzhiyun 	 *    https://gitlab.com/TheSven73/s3-to-irec
175*4882a593Smuzhiyun 	 * 3. convert ihex to binary (.fw) using ihex2fw tool which is included
176*4882a593Smuzhiyun 	 *    with the Linux kernel sources
177*4882a593Smuzhiyun 	 */
178*4882a593Smuzhiyun 	err = request_ihex_firmware(&fw, "zl38060.fw", dev);
179*4882a593Smuzhiyun 	if (err)
180*4882a593Smuzhiyun 		return err;
181*4882a593Smuzhiyun 	err = zl38_fw_enter_boot_mode(regmap);
182*4882a593Smuzhiyun 	if (err)
183*4882a593Smuzhiyun 		goto out;
184*4882a593Smuzhiyun 	rec = (const struct ihex_binrec *)fw->data;
185*4882a593Smuzhiyun 	while (rec) {
186*4882a593Smuzhiyun 		addr = be32_to_cpu(rec->addr);
187*4882a593Smuzhiyun 		len = be16_to_cpu(rec->len);
188*4882a593Smuzhiyun 		if (addr) {
189*4882a593Smuzhiyun 			/* regular data ihex record */
190*4882a593Smuzhiyun 			err = zl38_fw_send_data(regmap, addr, rec->data, len);
191*4882a593Smuzhiyun 		} else if (len == 4) {
192*4882a593Smuzhiyun 			/* execution address ihex record */
193*4882a593Smuzhiyun 			err = zl38_fw_send_xaddr(regmap, rec->data);
194*4882a593Smuzhiyun 		} else {
195*4882a593Smuzhiyun 			err = -EINVAL;
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 		if (err)
198*4882a593Smuzhiyun 			goto out;
199*4882a593Smuzhiyun 		/* next ! */
200*4882a593Smuzhiyun 		rec = ihex_next_binrec(rec);
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 	err = zl38_fw_go(regmap);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun out:
205*4882a593Smuzhiyun 	release_firmware(fw);
206*4882a593Smuzhiyun 	return err;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 
zl38_software_reset(struct regmap * regmap)210*4882a593Smuzhiyun static int zl38_software_reset(struct regmap *regmap)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	unsigned int val;
213*4882a593Smuzhiyun 	int err;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_APP_REBOOT,
216*4882a593Smuzhiyun 				 SEMA_FLAGS_APP_REBOOT);
217*4882a593Smuzhiyun 	if (err)
218*4882a593Smuzhiyun 		return err;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/* wait for host bus interface to settle.
221*4882a593Smuzhiyun 	 * Not sure if this is required: Microsemi's vendor driver does this,
222*4882a593Smuzhiyun 	 * but the firmware manual does not mention it. Leave it in, there's
223*4882a593Smuzhiyun 	 * little downside, apart from a slower reset.
224*4882a593Smuzhiyun 	 */
225*4882a593Smuzhiyun 	msleep(50);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	return regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val,
228*4882a593Smuzhiyun 					!(val & SEMA_FLAGS_APP_REBOOT), 10000,
229*4882a593Smuzhiyun 					10000 * 100);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
zl38_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)232*4882a593Smuzhiyun static int zl38_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
235*4882a593Smuzhiyun 	int err;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
238*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
239*4882a593Smuzhiyun 		/* firmware default is normal i2s */
240*4882a593Smuzhiyun 		break;
241*4882a593Smuzhiyun 	default:
242*4882a593Smuzhiyun 		return -EINVAL;
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
246*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
247*4882a593Smuzhiyun 		/* firmware default is normal bitclock and frame */
248*4882a593Smuzhiyun 		break;
249*4882a593Smuzhiyun 	default:
250*4882a593Smuzhiyun 		return -EINVAL;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
254*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
255*4882a593Smuzhiyun 		/* always 32 bits per frame (= 16 bits/channel, 2 channels) */
256*4882a593Smuzhiyun 		err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
257*4882a593Smuzhiyun 					 CFG_CLK_MASTER | CFG_CLK_PCLK_MASK,
258*4882a593Smuzhiyun 					 CFG_CLK_MASTER | CFG_CLK_PCLK(32));
259*4882a593Smuzhiyun 		if (err)
260*4882a593Smuzhiyun 			return err;
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 	default:
263*4882a593Smuzhiyun 		return -EINVAL;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
zl38_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)269*4882a593Smuzhiyun static int zl38_hw_params(struct snd_pcm_substream *substream,
270*4882a593Smuzhiyun 			  struct snd_pcm_hw_params *params,
271*4882a593Smuzhiyun 			  struct snd_soc_dai *dai)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
274*4882a593Smuzhiyun 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
275*4882a593Smuzhiyun 	unsigned int fsrate;
276*4882a593Smuzhiyun 	int err;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* We cannot change hw_params while the dai is already in use - the
279*4882a593Smuzhiyun 	 * software reset will corrupt the audio. However, this is not required,
280*4882a593Smuzhiyun 	 * as the chip's TDM buses are fully symmetric, which mandates identical
281*4882a593Smuzhiyun 	 * rates, channels, and samplebits for record and playback.
282*4882a593Smuzhiyun 	 */
283*4882a593Smuzhiyun 	if (priv->is_stream_in_use[!tx])
284*4882a593Smuzhiyun 		goto skip_setup;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	switch (params_rate(params)) {
287*4882a593Smuzhiyun 	case 8000:
288*4882a593Smuzhiyun 		fsrate = CFG_CLK_FSRATE_8KHZ;
289*4882a593Smuzhiyun 		break;
290*4882a593Smuzhiyun 	case 16000:
291*4882a593Smuzhiyun 		fsrate = CFG_CLK_FSRATE_16KHZ;
292*4882a593Smuzhiyun 		break;
293*4882a593Smuzhiyun 	case 48000:
294*4882a593Smuzhiyun 		fsrate = CFG_CLK_FSRATE_48KHZ;
295*4882a593Smuzhiyun 		break;
296*4882a593Smuzhiyun 	default:
297*4882a593Smuzhiyun 		return -EINVAL;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK,
301*4882a593Smuzhiyun 				 CFG_CLK_FSRATE_MASK, fsrate);
302*4882a593Smuzhiyun 	if (err)
303*4882a593Smuzhiyun 		return err;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	/* chip requires a software reset to apply audio register changes */
306*4882a593Smuzhiyun 	err = zl38_software_reset(priv->regmap);
307*4882a593Smuzhiyun 	if (err)
308*4882a593Smuzhiyun 		return err;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun skip_setup:
311*4882a593Smuzhiyun 	priv->is_stream_in_use[tx] = true;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
zl38_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)316*4882a593Smuzhiyun static int zl38_hw_free(struct snd_pcm_substream *substream,
317*4882a593Smuzhiyun 			struct snd_soc_dai *dai)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai);
320*4882a593Smuzhiyun 	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	priv->is_stream_in_use[tx] = false;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	return 0;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun /* stereo bypass with no AEC */
328*4882a593Smuzhiyun static const struct reg_sequence cp_config_stereo_bypass[] = {
329*4882a593Smuzhiyun 	/* interconnects must be programmed first */
330*4882a593Smuzhiyun 	{ 0x0210, 0x0005 },	/* DAC1   in <= I2S1-L */
331*4882a593Smuzhiyun 	{ 0x0212, 0x0006 },	/* DAC2   in <= I2S1-R */
332*4882a593Smuzhiyun 	{ 0x0214, 0x0001 },	/* I2S1-L in <= MIC1   */
333*4882a593Smuzhiyun 	{ 0x0216, 0x0001 },	/* I2S1-R in <= MIC1   */
334*4882a593Smuzhiyun 	{ 0x0224, 0x0000 },	/* AEC-S  in <= n/a    */
335*4882a593Smuzhiyun 	{ 0x0226, 0x0000 },	/* AEC-R  in <= n/a    */
336*4882a593Smuzhiyun 	/* output enables must be programmed next */
337*4882a593Smuzhiyun 	{ 0x0202, 0x000F },	/* enable I2S1 + DAC   */
338*4882a593Smuzhiyun };
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun static const struct snd_soc_dai_ops zl38_dai_ops = {
341*4882a593Smuzhiyun 	.set_fmt = zl38_set_fmt,
342*4882a593Smuzhiyun 	.hw_params = zl38_hw_params,
343*4882a593Smuzhiyun 	.hw_free = zl38_hw_free,
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun static struct snd_soc_dai_driver zl38_dai = {
347*4882a593Smuzhiyun 	.name = "zl38060-tdma",
348*4882a593Smuzhiyun 	.playback = {
349*4882a593Smuzhiyun 		.stream_name = "Playback",
350*4882a593Smuzhiyun 		.channels_min = 2,
351*4882a593Smuzhiyun 		.channels_max = 2,
352*4882a593Smuzhiyun 		.rates = ZL38_RATES,
353*4882a593Smuzhiyun 		.formats = ZL38_FORMATS,
354*4882a593Smuzhiyun 	},
355*4882a593Smuzhiyun 	.capture = {
356*4882a593Smuzhiyun 		.stream_name = "Capture",
357*4882a593Smuzhiyun 		.channels_min = 2,
358*4882a593Smuzhiyun 		.channels_max = 2,
359*4882a593Smuzhiyun 		.rates = ZL38_RATES,
360*4882a593Smuzhiyun 		.formats = ZL38_FORMATS,
361*4882a593Smuzhiyun 	},
362*4882a593Smuzhiyun 	.ops = &zl38_dai_ops,
363*4882a593Smuzhiyun 	.symmetric_rates = 1,
364*4882a593Smuzhiyun 	.symmetric_samplebits = 1,
365*4882a593Smuzhiyun 	.symmetric_channels = 1,
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun static const struct snd_soc_dapm_widget zl38_dapm_widgets[] = {
369*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("DAC1"),
370*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("DAC2"),
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("DMICL"),
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun static const struct snd_soc_dapm_route zl38_dapm_routes[] = {
376*4882a593Smuzhiyun 	{ "DAC1",  NULL, "Playback" },
377*4882a593Smuzhiyun 	{ "DAC2",  NULL, "Playback" },
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	{ "Capture",  NULL, "DMICL" },
380*4882a593Smuzhiyun };
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun static const struct snd_soc_component_driver zl38_component_dev = {
383*4882a593Smuzhiyun 	.dapm_widgets		= zl38_dapm_widgets,
384*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(zl38_dapm_widgets),
385*4882a593Smuzhiyun 	.dapm_routes		= zl38_dapm_routes,
386*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(zl38_dapm_routes),
387*4882a593Smuzhiyun 	.endianness		= 1,
388*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
389*4882a593Smuzhiyun };
390*4882a593Smuzhiyun 
chip_gpio_set(struct gpio_chip * c,unsigned int offset,int val)391*4882a593Smuzhiyun static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	struct regmap *regmap = gpiochip_get_data(c);
394*4882a593Smuzhiyun 	unsigned int mask = BIT(offset);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
chip_gpio_get(struct gpio_chip * c,unsigned int offset)399*4882a593Smuzhiyun static int chip_gpio_get(struct gpio_chip *c, unsigned int offset)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	struct regmap *regmap = gpiochip_get_data(c);
402*4882a593Smuzhiyun 	unsigned int mask = BIT(offset);
403*4882a593Smuzhiyun 	unsigned int val;
404*4882a593Smuzhiyun 	int err;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	err = regmap_read(regmap, REG_GPIO_DAT, &val);
407*4882a593Smuzhiyun 	if (err)
408*4882a593Smuzhiyun 		return err;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	return !!(val & mask);
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
chip_direction_input(struct gpio_chip * c,unsigned int offset)413*4882a593Smuzhiyun static int chip_direction_input(struct gpio_chip *c, unsigned int offset)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct regmap *regmap = gpiochip_get_data(c);
416*4882a593Smuzhiyun 	unsigned int mask = BIT(offset);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return regmap_update_bits(regmap, REG_GPIO_DIR, mask, 0);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun static int
chip_direction_output(struct gpio_chip * c,unsigned int offset,int val)422*4882a593Smuzhiyun chip_direction_output(struct gpio_chip *c, unsigned int offset, int val)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct regmap *regmap = gpiochip_get_data(c);
425*4882a593Smuzhiyun 	unsigned int mask = BIT(offset);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	chip_gpio_set(c, offset, val);
428*4882a593Smuzhiyun 	return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun static const struct gpio_chip template_chip = {
432*4882a593Smuzhiyun 	.owner = THIS_MODULE,
433*4882a593Smuzhiyun 	.label = DRV_NAME,
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	.base = -1,
436*4882a593Smuzhiyun 	.ngpio = 14,
437*4882a593Smuzhiyun 	.direction_input = chip_direction_input,
438*4882a593Smuzhiyun 	.direction_output = chip_direction_output,
439*4882a593Smuzhiyun 	.get = chip_gpio_get,
440*4882a593Smuzhiyun 	.set = chip_gpio_set,
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	.can_sleep = true,
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun 
zl38_check_revision(struct device * dev,struct regmap * regmap)445*4882a593Smuzhiyun static int zl38_check_revision(struct device *dev, struct regmap *regmap)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	unsigned int hwrev, fwprod, fwrev;
448*4882a593Smuzhiyun 	int fw_major, fw_minor, fw_micro;
449*4882a593Smuzhiyun 	int err;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	err = regmap_read(regmap, REG_HW_REV, &hwrev);
452*4882a593Smuzhiyun 	if (err)
453*4882a593Smuzhiyun 		return err;
454*4882a593Smuzhiyun 	err = regmap_read(regmap, REG_FW_PROD, &fwprod);
455*4882a593Smuzhiyun 	if (err)
456*4882a593Smuzhiyun 		return err;
457*4882a593Smuzhiyun 	err = regmap_read(regmap, REG_FW_REV, &fwrev);
458*4882a593Smuzhiyun 	if (err)
459*4882a593Smuzhiyun 		return err;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	fw_major = (fwrev >> 12) & 0xF;
462*4882a593Smuzhiyun 	fw_minor = (fwrev >>  8) & 0xF;
463*4882a593Smuzhiyun 	fw_micro = fwrev & 0xFF;
464*4882a593Smuzhiyun 	dev_info(dev, "hw rev 0x%x, fw product code %d, firmware rev %d.%d.%d",
465*4882a593Smuzhiyun 		 hwrev & 0x1F, fwprod, fw_major, fw_minor, fw_micro);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	if (fw_major != FIRMWARE_MAJOR || fw_minor < FIRMWARE_MINOR) {
468*4882a593Smuzhiyun 		dev_err(dev, "unsupported firmware. driver supports %d.%d",
469*4882a593Smuzhiyun 			FIRMWARE_MAJOR, FIRMWARE_MINOR);
470*4882a593Smuzhiyun 		return -EINVAL;
471*4882a593Smuzhiyun 	}
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
zl38_bus_read(void * context,const void * reg_buf,size_t reg_size,void * val_buf,size_t val_size)476*4882a593Smuzhiyun static int zl38_bus_read(void *context,
477*4882a593Smuzhiyun 			 const void *reg_buf, size_t reg_size,
478*4882a593Smuzhiyun 			 void *val_buf, size_t val_size)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	struct spi_device *spi = context;
481*4882a593Smuzhiyun 	const u8 *reg_buf8 = reg_buf;
482*4882a593Smuzhiyun 	size_t len = 0;
483*4882a593Smuzhiyun 	u8 offs, page;
484*4882a593Smuzhiyun 	u8 txbuf[4];
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (reg_size != 2 || val_size > ZL38_MAX_RAW_XFER)
487*4882a593Smuzhiyun 		return -EINVAL;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	offs = reg_buf8[1] >> 1;
490*4882a593Smuzhiyun 	page = reg_buf8[0];
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (page) {
493*4882a593Smuzhiyun 		txbuf[len++] = 0xFE;
494*4882a593Smuzhiyun 		txbuf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
495*4882a593Smuzhiyun 		txbuf[len++] = offs;
496*4882a593Smuzhiyun 		txbuf[len++] = val_size / 2 - 1;
497*4882a593Smuzhiyun 	} else {
498*4882a593Smuzhiyun 		txbuf[len++] = offs | 0x80;
499*4882a593Smuzhiyun 		txbuf[len++] = val_size / 2 - 1;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	return spi_write_then_read(spi, txbuf, len, val_buf, val_size);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
zl38_bus_write(void * context,const void * data,size_t count)505*4882a593Smuzhiyun static int zl38_bus_write(void *context, const void *data, size_t count)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct spi_device *spi = context;
508*4882a593Smuzhiyun 	u8 buf[4 + ZL38_MAX_RAW_XFER];
509*4882a593Smuzhiyun 	size_t val_len, len = 0;
510*4882a593Smuzhiyun 	const u8 *data8 = data;
511*4882a593Smuzhiyun 	u8 offs, page;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	if (count > (2 + ZL38_MAX_RAW_XFER) || count < 4)
514*4882a593Smuzhiyun 		return -EINVAL;
515*4882a593Smuzhiyun 	val_len = count - 2;
516*4882a593Smuzhiyun 	offs = data8[1] >> 1;
517*4882a593Smuzhiyun 	page = data8[0];
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	if (page) {
520*4882a593Smuzhiyun 		buf[len++] = 0xFE;
521*4882a593Smuzhiyun 		buf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1;
522*4882a593Smuzhiyun 		buf[len++] = offs;
523*4882a593Smuzhiyun 		buf[len++] = (val_len / 2 - 1) | 0x80;
524*4882a593Smuzhiyun 	} else {
525*4882a593Smuzhiyun 		buf[len++] = offs | 0x80;
526*4882a593Smuzhiyun 		buf[len++] = (val_len / 2 - 1) | 0x80;
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 	memcpy(buf + len, data8 + 2, val_len);
529*4882a593Smuzhiyun 	len += val_len;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	return spi_write(spi, buf, len);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun static const struct regmap_bus zl38_regmap_bus = {
535*4882a593Smuzhiyun 	.read = zl38_bus_read,
536*4882a593Smuzhiyun 	.write = zl38_bus_write,
537*4882a593Smuzhiyun 	.max_raw_write = ZL38_MAX_RAW_XFER,
538*4882a593Smuzhiyun 	.max_raw_read = ZL38_MAX_RAW_XFER,
539*4882a593Smuzhiyun };
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun static const struct regmap_config zl38_regmap_conf = {
542*4882a593Smuzhiyun 	.reg_bits = 16,
543*4882a593Smuzhiyun 	.val_bits = 16,
544*4882a593Smuzhiyun 	.reg_stride = 2,
545*4882a593Smuzhiyun 	.use_single_read = true,
546*4882a593Smuzhiyun 	.use_single_write = true,
547*4882a593Smuzhiyun };
548*4882a593Smuzhiyun 
zl38_spi_probe(struct spi_device * spi)549*4882a593Smuzhiyun static int zl38_spi_probe(struct spi_device *spi)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun 	struct device *dev = &spi->dev;
552*4882a593Smuzhiyun 	struct zl38_codec_priv *priv;
553*4882a593Smuzhiyun 	struct gpio_desc *reset_gpio;
554*4882a593Smuzhiyun 	int err;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	/* get the chip to a known state by putting it in reset */
557*4882a593Smuzhiyun 	reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
558*4882a593Smuzhiyun 	if (IS_ERR(reset_gpio))
559*4882a593Smuzhiyun 		return PTR_ERR(reset_gpio);
560*4882a593Smuzhiyun 	if (reset_gpio) {
561*4882a593Smuzhiyun 		/* datasheet: need > 10us for a digital + analog reset */
562*4882a593Smuzhiyun 		usleep_range(15, 50);
563*4882a593Smuzhiyun 		/* take the chip out of reset */
564*4882a593Smuzhiyun 		gpiod_set_value_cansleep(reset_gpio, 0);
565*4882a593Smuzhiyun 		/* datasheet: need > 3ms for digital section to become stable */
566*4882a593Smuzhiyun 		usleep_range(3000, 10000);
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
570*4882a593Smuzhiyun 	if (!priv)
571*4882a593Smuzhiyun 		return -ENOMEM;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	priv->dev = dev;
574*4882a593Smuzhiyun 	dev_set_drvdata(dev, priv);
575*4882a593Smuzhiyun 	priv->regmap = devm_regmap_init(dev, &zl38_regmap_bus, spi,
576*4882a593Smuzhiyun 					&zl38_regmap_conf);
577*4882a593Smuzhiyun 	if (IS_ERR(priv->regmap))
578*4882a593Smuzhiyun 		return PTR_ERR(priv->regmap);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	err = zl38_load_firmware(dev, priv->regmap);
581*4882a593Smuzhiyun 	if (err)
582*4882a593Smuzhiyun 		return err;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	err = zl38_check_revision(dev, priv->regmap);
585*4882a593Smuzhiyun 	if (err)
586*4882a593Smuzhiyun 		return err;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	priv->gpio_chip = devm_kmemdup(dev, &template_chip,
589*4882a593Smuzhiyun 				       sizeof(template_chip), GFP_KERNEL);
590*4882a593Smuzhiyun 	if (!priv->gpio_chip)
591*4882a593Smuzhiyun 		return -ENOMEM;
592*4882a593Smuzhiyun #ifdef CONFIG_OF_GPIO
593*4882a593Smuzhiyun 	priv->gpio_chip->of_node = dev->of_node;
594*4882a593Smuzhiyun #endif
595*4882a593Smuzhiyun 	err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap);
596*4882a593Smuzhiyun 	if (err)
597*4882a593Smuzhiyun 		return err;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	/* setup the cross-point switch for stereo bypass */
600*4882a593Smuzhiyun 	err = regmap_multi_reg_write(priv->regmap, cp_config_stereo_bypass,
601*4882a593Smuzhiyun 				     ARRAY_SIZE(cp_config_stereo_bypass));
602*4882a593Smuzhiyun 	if (err)
603*4882a593Smuzhiyun 		return err;
604*4882a593Smuzhiyun 	/* setup for 12MHz crystal connected to the chip */
605*4882a593Smuzhiyun 	err = regmap_update_bits(priv->regmap, REG_CLK_CFG, CLK_CFG_SOURCE_XTAL,
606*4882a593Smuzhiyun 				 CLK_CFG_SOURCE_XTAL);
607*4882a593Smuzhiyun 	if (err)
608*4882a593Smuzhiyun 		return err;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	return devm_snd_soc_register_component(dev, &zl38_component_dev,
611*4882a593Smuzhiyun 					       &zl38_dai, 1);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun static const struct of_device_id zl38_dt_ids[] = {
615*4882a593Smuzhiyun 	{ .compatible = "mscc,zl38060", },
616*4882a593Smuzhiyun 	{ /* sentinel */ }
617*4882a593Smuzhiyun };
618*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, zl38_dt_ids);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun static const struct spi_device_id zl38_spi_ids[] = {
621*4882a593Smuzhiyun 	{ "zl38060", 0 },
622*4882a593Smuzhiyun 	{ /* sentinel */ }
623*4882a593Smuzhiyun };
624*4882a593Smuzhiyun MODULE_DEVICE_TABLE(spi, zl38_spi_ids);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun static struct spi_driver zl38060_spi_driver = {
627*4882a593Smuzhiyun 	.driver	= {
628*4882a593Smuzhiyun 		.name = DRV_NAME,
629*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(zl38_dt_ids),
630*4882a593Smuzhiyun 	},
631*4882a593Smuzhiyun 	.probe = zl38_spi_probe,
632*4882a593Smuzhiyun 	.id_table = zl38_spi_ids,
633*4882a593Smuzhiyun };
634*4882a593Smuzhiyun module_spi_driver(zl38060_spi_driver);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC ZL38060 driver");
637*4882a593Smuzhiyun MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
638*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
639