xref: /openbmc/linux/sound/soc/codecs/wm0010.c (revision 36db6e8484ed455bbb320d89a119378897ae991c)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e3523e01SDimitris Papastamos /*
3e3523e01SDimitris Papastamos  * wm0010.c  --  WM0010 DSP Driver
4e3523e01SDimitris Papastamos  *
5e3523e01SDimitris Papastamos  * Copyright 2012 Wolfson Microelectronics PLC.
6e3523e01SDimitris Papastamos  *
7e3523e01SDimitris Papastamos  * Authors: Mark Brown <broonie@opensource.wolfsonmicro.com>
8e3523e01SDimitris Papastamos  *          Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
9e3523e01SDimitris Papastamos  *          Scott Ling <sl@opensource.wolfsonmicro.com>
10e3523e01SDimitris Papastamos  */
11e3523e01SDimitris Papastamos 
12e3523e01SDimitris Papastamos #include <linux/module.h>
13e3523e01SDimitris Papastamos #include <linux/moduleparam.h>
14fd8b9657SCharles Keepax #include <linux/interrupt.h>
15e3523e01SDimitris Papastamos #include <linux/irqreturn.h>
16e3523e01SDimitris Papastamos #include <linux/init.h>
17e3523e01SDimitris Papastamos #include <linux/spi/spi.h>
18e3523e01SDimitris Papastamos #include <linux/firmware.h>
19e3523e01SDimitris Papastamos #include <linux/delay.h>
20e3523e01SDimitris Papastamos #include <linux/fs.h>
21e3523e01SDimitris Papastamos #include <linux/gpio.h>
22e3523e01SDimitris Papastamos #include <linux/regulator/consumer.h>
23e3523e01SDimitris Papastamos #include <linux/mutex.h>
24e3523e01SDimitris Papastamos #include <linux/workqueue.h>
25e3523e01SDimitris Papastamos 
26e3523e01SDimitris Papastamos #include <sound/soc.h>
27e3523e01SDimitris Papastamos #include <sound/wm0010.h>
28e3523e01SDimitris Papastamos 
29e3523e01SDimitris Papastamos #define DEVICE_ID_WM0010	10
30e3523e01SDimitris Papastamos 
3168e1969eSScott Ling /* We only support v1 of the .dfw INFO record */
3268e1969eSScott Ling #define INFO_VERSION		1
3368e1969eSScott Ling 
34e3523e01SDimitris Papastamos enum dfw_cmd {
35e3523e01SDimitris Papastamos 	DFW_CMD_FUSE = 0x01,
36e3523e01SDimitris Papastamos 	DFW_CMD_CODE_HDR,
37e3523e01SDimitris Papastamos 	DFW_CMD_CODE_DATA,
38e3523e01SDimitris Papastamos 	DFW_CMD_PLL,
39e3523e01SDimitris Papastamos 	DFW_CMD_INFO = 0xff
40e3523e01SDimitris Papastamos };
41e3523e01SDimitris Papastamos 
42e3523e01SDimitris Papastamos struct dfw_binrec {
43e3523e01SDimitris Papastamos 	u8 command;
44e3523e01SDimitris Papastamos 	u32 length:24;
45e3523e01SDimitris Papastamos 	u32 address;
46681c896cSGustavo A. R. Silva 	uint8_t data[];
47e3523e01SDimitris Papastamos } __packed;
48e3523e01SDimitris Papastamos 
4968e1969eSScott Ling struct dfw_inforec {
5068e1969eSScott Ling 	u8 info_version;
5168e1969eSScott Ling 	u8 tool_major_version;
5268e1969eSScott Ling 	u8 tool_minor_version;
5368e1969eSScott Ling 	u8 dsp_target;
5468e1969eSScott Ling };
5568e1969eSScott Ling 
56e3523e01SDimitris Papastamos struct dfw_pllrec {
57e3523e01SDimitris Papastamos 	u8 command;
58e3523e01SDimitris Papastamos 	u32 length:24;
59e3523e01SDimitris Papastamos 	u32 address;
60e3523e01SDimitris Papastamos 	u32 clkctrl1;
61e3523e01SDimitris Papastamos 	u32 clkctrl2;
62e3523e01SDimitris Papastamos 	u32 clkctrl3;
63e3523e01SDimitris Papastamos 	u32 ldetctrl;
64e3523e01SDimitris Papastamos 	u32 uart_div;
65e3523e01SDimitris Papastamos 	u32 spi_div;
66e3523e01SDimitris Papastamos } __packed;
67e3523e01SDimitris Papastamos 
68e3523e01SDimitris Papastamos static struct pll_clock_map {
69e3523e01SDimitris Papastamos 	int max_sysclk;
70e3523e01SDimitris Papastamos 	int max_pll_spi_speed;
71e3523e01SDimitris Papastamos 	u32 pll_clkctrl1;
72e3523e01SDimitris Papastamos } pll_clock_map[] = {			   /* Dividers */
73e3523e01SDimitris Papastamos 	{ 22000000, 26000000, 0x00201f11 }, /* 2,32,2  */
74e3523e01SDimitris Papastamos 	{ 18000000, 26000000, 0x00203f21 }, /* 2,64,4  */
75e3523e01SDimitris Papastamos 	{ 14000000, 26000000, 0x00202620 }, /* 1,39,4  */
76e3523e01SDimitris Papastamos 	{ 10000000, 22000000, 0x00203120 }, /* 1,50,4  */
77e3523e01SDimitris Papastamos 	{  6500000, 22000000, 0x00204520 }, /* 1,70,4  */
78e3523e01SDimitris Papastamos 	{  5500000, 22000000, 0x00103f10 }, /* 1,64,2  */
79e3523e01SDimitris Papastamos };
80e3523e01SDimitris Papastamos 
81e3523e01SDimitris Papastamos enum wm0010_state {
82e3523e01SDimitris Papastamos 	WM0010_POWER_OFF,
83e3523e01SDimitris Papastamos 	WM0010_OUT_OF_RESET,
84e3523e01SDimitris Papastamos 	WM0010_BOOTROM,
85e3523e01SDimitris Papastamos 	WM0010_STAGE2,
86e3523e01SDimitris Papastamos 	WM0010_FIRMWARE,
87e3523e01SDimitris Papastamos };
88e3523e01SDimitris Papastamos 
89e3523e01SDimitris Papastamos struct wm0010_priv {
90b5311eedSKuninori Morimoto 	struct snd_soc_component *component;
91e3523e01SDimitris Papastamos 
92e3523e01SDimitris Papastamos 	struct mutex lock;
93e3523e01SDimitris Papastamos 	struct device *dev;
94e3523e01SDimitris Papastamos 
95e3523e01SDimitris Papastamos 	struct wm0010_pdata pdata;
96e3523e01SDimitris Papastamos 
97e3523e01SDimitris Papastamos 	int gpio_reset;
98e3523e01SDimitris Papastamos 	int gpio_reset_value;
99e3523e01SDimitris Papastamos 
100e3523e01SDimitris Papastamos 	struct regulator_bulk_data core_supplies[2];
101e3523e01SDimitris Papastamos 	struct regulator *dbvdd;
102e3523e01SDimitris Papastamos 
103e3523e01SDimitris Papastamos 	int sysclk;
104e3523e01SDimitris Papastamos 
105e3523e01SDimitris Papastamos 	enum wm0010_state state;
106e3523e01SDimitris Papastamos 	bool boot_failed;
107e3523e01SDimitris Papastamos 	bool ready;
108e3523e01SDimitris Papastamos 	bool pll_running;
109e3523e01SDimitris Papastamos 	int max_spi_freq;
110e3523e01SDimitris Papastamos 	int board_max_spi_speed;
111e3523e01SDimitris Papastamos 	u32 pll_clkctrl1;
112e3523e01SDimitris Papastamos 
113e3523e01SDimitris Papastamos 	spinlock_t irq_lock;
114e3523e01SDimitris Papastamos 	int irq;
115e3523e01SDimitris Papastamos 
116e3523e01SDimitris Papastamos 	struct completion boot_completion;
117e3523e01SDimitris Papastamos };
118e3523e01SDimitris Papastamos 
119e3523e01SDimitris Papastamos struct wm0010_spi_msg {
120e3523e01SDimitris Papastamos 	struct spi_message m;
121e3523e01SDimitris Papastamos 	struct spi_transfer t;
122e3523e01SDimitris Papastamos 	u8 *tx_buf;
123e3523e01SDimitris Papastamos 	u8 *rx_buf;
124e3523e01SDimitris Papastamos 	size_t len;
125e3523e01SDimitris Papastamos };
126e3523e01SDimitris Papastamos 
1271470bfacSMark Brown static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
1281470bfacSMark Brown SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0),
1291470bfacSMark Brown };
1301470bfacSMark Brown 
131e3523e01SDimitris Papastamos static const struct snd_soc_dapm_route wm0010_dapm_routes[] = {
1321549c34bSMark Brown 	{ "SDI2 Capture", NULL, "SDI1 Playback" },
1331549c34bSMark Brown 	{ "SDI1 Capture", NULL, "SDI2 Playback" },
1341470bfacSMark Brown 
1351470bfacSMark Brown 	{ "SDI1 Capture", NULL, "CLKIN" },
1361470bfacSMark Brown 	{ "SDI2 Capture", NULL, "CLKIN" },
1371470bfacSMark Brown 	{ "SDI1 Playback", NULL, "CLKIN" },
1381470bfacSMark Brown 	{ "SDI2 Playback", NULL, "CLKIN" },
139e3523e01SDimitris Papastamos };
140e3523e01SDimitris Papastamos 
wm0010_state_to_str(enum wm0010_state state)141e3523e01SDimitris Papastamos static const char *wm0010_state_to_str(enum wm0010_state state)
142e3523e01SDimitris Papastamos {
1435bca3969SFabian Frederick 	static const char * const state_to_str[] = {
144e3523e01SDimitris Papastamos 		"Power off",
145e3523e01SDimitris Papastamos 		"Out of reset",
146bf9d3237SMark Brown 		"Boot ROM",
147e3523e01SDimitris Papastamos 		"Stage2",
148e3523e01SDimitris Papastamos 		"Firmware"
149e3523e01SDimitris Papastamos 	};
150e3523e01SDimitris Papastamos 
151e3523e01SDimitris Papastamos 	if (state < 0 || state >= ARRAY_SIZE(state_to_str))
152e3523e01SDimitris Papastamos 		return "null";
153e3523e01SDimitris Papastamos 	return state_to_str[state];
154e3523e01SDimitris Papastamos }
155e3523e01SDimitris Papastamos 
156e3523e01SDimitris Papastamos /* Called with wm0010->lock held */
wm0010_halt(struct snd_soc_component * component)157b5311eedSKuninori Morimoto static void wm0010_halt(struct snd_soc_component *component)
158e3523e01SDimitris Papastamos {
159b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
160e3523e01SDimitris Papastamos 	unsigned long flags;
161e3523e01SDimitris Papastamos 	enum wm0010_state state;
162e3523e01SDimitris Papastamos 
163e3523e01SDimitris Papastamos 	/* Fetch the wm0010 state */
164e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
165e3523e01SDimitris Papastamos 	state = wm0010->state;
166e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
167e3523e01SDimitris Papastamos 
168e3523e01SDimitris Papastamos 	switch (state) {
169e3523e01SDimitris Papastamos 	case WM0010_POWER_OFF:
170e3523e01SDimitris Papastamos 		/* If there's nothing to do, bail out */
171e3523e01SDimitris Papastamos 		return;
172e3523e01SDimitris Papastamos 	case WM0010_OUT_OF_RESET:
173e3523e01SDimitris Papastamos 	case WM0010_BOOTROM:
174e3523e01SDimitris Papastamos 	case WM0010_STAGE2:
175e3523e01SDimitris Papastamos 	case WM0010_FIRMWARE:
176e3523e01SDimitris Papastamos 		/* Remember to put chip back into reset */
177fff00cbcSMark Brown 		gpio_set_value_cansleep(wm0010->gpio_reset,
178fff00cbcSMark Brown 					wm0010->gpio_reset_value);
179e3523e01SDimitris Papastamos 		/* Disable the regulators */
180e3523e01SDimitris Papastamos 		regulator_disable(wm0010->dbvdd);
181e3523e01SDimitris Papastamos 		regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
182e3523e01SDimitris Papastamos 				       wm0010->core_supplies);
183e3523e01SDimitris Papastamos 		break;
184e3523e01SDimitris Papastamos 	}
185e3523e01SDimitris Papastamos 
186e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
187e3523e01SDimitris Papastamos 	wm0010->state = WM0010_POWER_OFF;
188e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
189e3523e01SDimitris Papastamos }
190e3523e01SDimitris Papastamos 
191e3523e01SDimitris Papastamos struct wm0010_boot_xfer {
192e3523e01SDimitris Papastamos 	struct list_head list;
193b5311eedSKuninori Morimoto 	struct snd_soc_component *component;
194e3523e01SDimitris Papastamos 	struct completion *done;
195e3523e01SDimitris Papastamos 	struct spi_message m;
196e3523e01SDimitris Papastamos 	struct spi_transfer t;
197e3523e01SDimitris Papastamos };
198e3523e01SDimitris Papastamos 
199e3523e01SDimitris Papastamos /* Called with wm0010->lock held */
wm0010_mark_boot_failure(struct wm0010_priv * wm0010)200e3523e01SDimitris Papastamos static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
201e3523e01SDimitris Papastamos {
202e3523e01SDimitris Papastamos 	enum wm0010_state state;
203e3523e01SDimitris Papastamos 	unsigned long flags;
204e3523e01SDimitris Papastamos 
205e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
206e3523e01SDimitris Papastamos 	state = wm0010->state;
207e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
208e3523e01SDimitris Papastamos 
209e3523e01SDimitris Papastamos 	dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
210e3523e01SDimitris Papastamos 		wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
211e3523e01SDimitris Papastamos 
212e3523e01SDimitris Papastamos 	wm0010->boot_failed = true;
213e3523e01SDimitris Papastamos }
214e3523e01SDimitris Papastamos 
wm0010_boot_xfer_complete(void * data)215e3523e01SDimitris Papastamos static void wm0010_boot_xfer_complete(void *data)
216e3523e01SDimitris Papastamos {
217e3523e01SDimitris Papastamos 	struct wm0010_boot_xfer *xfer = data;
218b5311eedSKuninori Morimoto 	struct snd_soc_component *component = xfer->component;
219b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
220e3523e01SDimitris Papastamos 	u32 *out32 = xfer->t.rx_buf;
221e3523e01SDimitris Papastamos 	int i;
222e3523e01SDimitris Papastamos 
223e3523e01SDimitris Papastamos 	if (xfer->m.status != 0) {
224b5311eedSKuninori Morimoto 		dev_err(component->dev, "SPI transfer failed: %d\n",
225e3523e01SDimitris Papastamos 			xfer->m.status);
226e3523e01SDimitris Papastamos 		wm0010_mark_boot_failure(wm0010);
227e3523e01SDimitris Papastamos 		if (xfer->done)
228e3523e01SDimitris Papastamos 			complete(xfer->done);
229e3523e01SDimitris Papastamos 		return;
230e3523e01SDimitris Papastamos 	}
231e3523e01SDimitris Papastamos 
232e3523e01SDimitris Papastamos 	for (i = 0; i < xfer->t.len / 4; i++) {
233b5311eedSKuninori Morimoto 		dev_dbg(component->dev, "%d: %04x\n", i, out32[i]);
234e3523e01SDimitris Papastamos 
235e3523e01SDimitris Papastamos 		switch (be32_to_cpu(out32[i])) {
236e3523e01SDimitris Papastamos 		case 0xe0e0e0e0:
237b5311eedSKuninori Morimoto 			dev_err(component->dev,
238e3523e01SDimitris Papastamos 				"%d: ROM error reported in stage 2\n", i);
239e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
240e3523e01SDimitris Papastamos 			break;
241e3523e01SDimitris Papastamos 
242e3523e01SDimitris Papastamos 		case 0x55555555:
243f9baa0ccSScott Ling 			if (wm0010->state < WM0010_STAGE2)
244e3523e01SDimitris Papastamos 				break;
245b5311eedSKuninori Morimoto 			dev_err(component->dev,
246e3523e01SDimitris Papastamos 				"%d: ROM bootloader running in stage 2\n", i);
247e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
248e3523e01SDimitris Papastamos 			break;
249e3523e01SDimitris Papastamos 
250e3523e01SDimitris Papastamos 		case 0x0fed0000:
251b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "Stage2 loader running\n");
252e3523e01SDimitris Papastamos 			break;
253e3523e01SDimitris Papastamos 
254e3523e01SDimitris Papastamos 		case 0x0fed0007:
255b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "CODE_HDR packet received\n");
256e3523e01SDimitris Papastamos 			break;
257e3523e01SDimitris Papastamos 
258e3523e01SDimitris Papastamos 		case 0x0fed0008:
259b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "CODE_DATA packet received\n");
260e3523e01SDimitris Papastamos 			break;
261e3523e01SDimitris Papastamos 
262e3523e01SDimitris Papastamos 		case 0x0fed0009:
263b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "Download complete\n");
264e3523e01SDimitris Papastamos 			break;
265e3523e01SDimitris Papastamos 
266e3523e01SDimitris Papastamos 		case 0x0fed000c:
267b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "Application start\n");
268e3523e01SDimitris Papastamos 			break;
269e3523e01SDimitris Papastamos 
270e3523e01SDimitris Papastamos 		case 0x0fed000e:
271b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "PLL packet received\n");
272e3523e01SDimitris Papastamos 			wm0010->pll_running = true;
273e3523e01SDimitris Papastamos 			break;
274e3523e01SDimitris Papastamos 
275e3523e01SDimitris Papastamos 		case 0x0fed0025:
276b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports image too long\n");
277e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
278e3523e01SDimitris Papastamos 			break;
279e3523e01SDimitris Papastamos 
280e3523e01SDimitris Papastamos 		case 0x0fed002c:
281b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports bad SPI packet\n");
282e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
283e3523e01SDimitris Papastamos 			break;
284e3523e01SDimitris Papastamos 
285e3523e01SDimitris Papastamos 		case 0x0fed0031:
286b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports SPI read overflow\n");
287e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
288e3523e01SDimitris Papastamos 			break;
289e3523e01SDimitris Papastamos 
290e3523e01SDimitris Papastamos 		case 0x0fed0032:
291b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports SPI underclock\n");
292e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
293e3523e01SDimitris Papastamos 			break;
294e3523e01SDimitris Papastamos 
295e3523e01SDimitris Papastamos 		case 0x0fed0033:
296b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports bad header packet\n");
297e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
298e3523e01SDimitris Papastamos 			break;
299e3523e01SDimitris Papastamos 
300e3523e01SDimitris Papastamos 		case 0x0fed0034:
301b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports invalid packet type\n");
302e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
303e3523e01SDimitris Papastamos 			break;
304e3523e01SDimitris Papastamos 
305e3523e01SDimitris Papastamos 		case 0x0fed0035:
306b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports data before header error\n");
307e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
308e3523e01SDimitris Papastamos 			break;
309e3523e01SDimitris Papastamos 
310e3523e01SDimitris Papastamos 		case 0x0fed0038:
311b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports invalid PLL packet\n");
312e3523e01SDimitris Papastamos 			break;
313e3523e01SDimitris Papastamos 
314e3523e01SDimitris Papastamos 		case 0x0fed003a:
315b5311eedSKuninori Morimoto 			dev_err(component->dev, "Device reports packet alignment error\n");
316e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
317e3523e01SDimitris Papastamos 			break;
318e3523e01SDimitris Papastamos 
319e3523e01SDimitris Papastamos 		default:
320b5311eedSKuninori Morimoto 			dev_err(component->dev, "Unrecognised return 0x%x\n",
321e3523e01SDimitris Papastamos 			    be32_to_cpu(out32[i]));
322e3523e01SDimitris Papastamos 			wm0010_mark_boot_failure(wm0010);
323e3523e01SDimitris Papastamos 			break;
324e3523e01SDimitris Papastamos 		}
325e3523e01SDimitris Papastamos 
326e3523e01SDimitris Papastamos 		if (wm0010->boot_failed)
327e3523e01SDimitris Papastamos 			break;
328e3523e01SDimitris Papastamos 	}
329e3523e01SDimitris Papastamos 
330e3523e01SDimitris Papastamos 	if (xfer->done)
331e3523e01SDimitris Papastamos 		complete(xfer->done);
332e3523e01SDimitris Papastamos }
333e3523e01SDimitris Papastamos 
byte_swap_64(u64 * data_in,u64 * data_out,u32 len)334e3523e01SDimitris Papastamos static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
335e3523e01SDimitris Papastamos {
336e3523e01SDimitris Papastamos 	int i;
337e3523e01SDimitris Papastamos 
338e3523e01SDimitris Papastamos 	for (i = 0; i < len / 8; i++)
339e3523e01SDimitris Papastamos 		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
340e3523e01SDimitris Papastamos }
341e3523e01SDimitris Papastamos 
wm0010_firmware_load(const char * name,struct snd_soc_component * component)342b5311eedSKuninori Morimoto static int wm0010_firmware_load(const char *name, struct snd_soc_component *component)
343e3523e01SDimitris Papastamos {
344b5311eedSKuninori Morimoto 	struct spi_device *spi = to_spi_device(component->dev);
345b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
346e3523e01SDimitris Papastamos 	struct list_head xfer_list;
347e3523e01SDimitris Papastamos 	struct wm0010_boot_xfer *xfer;
348e3523e01SDimitris Papastamos 	int ret;
349093513b8SPierre-Louis Bossart 	DECLARE_COMPLETION_ONSTACK(done);
350e3523e01SDimitris Papastamos 	const struct firmware *fw;
351e3523e01SDimitris Papastamos 	const struct dfw_binrec *rec;
35268e1969eSScott Ling 	const struct dfw_inforec *inforec;
3538f7d52afSScott Ling 	u64 *img;
3548f7d52afSScott Ling 	u8 *out, dsp;
3558f7d52afSScott Ling 	u32 len, offset;
3568f7d52afSScott Ling 
3578f7d52afSScott Ling 	INIT_LIST_HEAD(&xfer_list);
3588f7d52afSScott Ling 
359b5311eedSKuninori Morimoto 	ret = request_firmware(&fw, name, component->dev);
3608f7d52afSScott Ling 	if (ret != 0) {
361b5311eedSKuninori Morimoto 		dev_err(component->dev, "Failed to request application(%s): %d\n",
3623e112af5SCharles Keepax 			name, ret);
3638f7d52afSScott Ling 		return ret;
3648f7d52afSScott Ling 	}
3658f7d52afSScott Ling 
3668f7d52afSScott Ling 	rec = (const struct dfw_binrec *)fw->data;
36768e1969eSScott Ling 	inforec = (const struct dfw_inforec *)rec->data;
3688f7d52afSScott Ling 	offset = 0;
36968e1969eSScott Ling 	dsp = inforec->dsp_target;
3708f7d52afSScott Ling 	wm0010->boot_failed = false;
371f5b3a563STakashi Iwai 	if (WARN_ON(!list_empty(&xfer_list)))
372f5b3a563STakashi Iwai 		return -EINVAL;
3738f7d52afSScott Ling 
3748f7d52afSScott Ling 	/* First record should be INFO */
3758f7d52afSScott Ling 	if (rec->command != DFW_CMD_INFO) {
376b5311eedSKuninori Morimoto 		dev_err(component->dev, "First record not INFO\r\n");
3778f7d52afSScott Ling 		ret = -EINVAL;
3788f7d52afSScott Ling 		goto abort;
3798f7d52afSScott Ling 	}
3808f7d52afSScott Ling 
38168e1969eSScott Ling 	if (inforec->info_version != INFO_VERSION) {
382b5311eedSKuninori Morimoto 		dev_err(component->dev,
38368e1969eSScott Ling 			"Unsupported version (%02d) of INFO record\r\n",
38468e1969eSScott Ling 			inforec->info_version);
38568e1969eSScott Ling 		ret = -EINVAL;
38668e1969eSScott Ling 		goto abort;
38768e1969eSScott Ling 	}
38868e1969eSScott Ling 
389b5311eedSKuninori Morimoto 	dev_dbg(component->dev, "Version v%02d INFO record found\r\n",
39068e1969eSScott Ling 		inforec->info_version);
39168e1969eSScott Ling 
3928f7d52afSScott Ling 	/* Check it's a DSP file */
3938f7d52afSScott Ling 	if (dsp != DEVICE_ID_WM0010) {
394b5311eedSKuninori Morimoto 		dev_err(component->dev, "Not a WM0010 firmware file.\r\n");
3958f7d52afSScott Ling 		ret = -EINVAL;
3968f7d52afSScott Ling 		goto abort;
3978f7d52afSScott Ling 	}
3988f7d52afSScott Ling 
3998f7d52afSScott Ling 	/* Skip the info record as we don't need to send it */
4008f7d52afSScott Ling 	offset += ((rec->length) + 8);
4018f7d52afSScott Ling 	rec = (void *)&rec->data[rec->length];
4028f7d52afSScott Ling 
4038f7d52afSScott Ling 	while (offset < fw->size) {
404b5311eedSKuninori Morimoto 		dev_dbg(component->dev,
4058f7d52afSScott Ling 			"Packet: command %d, data length = 0x%x\r\n",
4068f7d52afSScott Ling 			rec->command, rec->length);
4078f7d52afSScott Ling 		len = rec->length + 8;
4088f7d52afSScott Ling 
4094f8b1914SDimitris Papastamos 		xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
4104f8b1914SDimitris Papastamos 		if (!xfer) {
4114f8b1914SDimitris Papastamos 			ret = -ENOMEM;
4124f8b1914SDimitris Papastamos 			goto abort;
4134f8b1914SDimitris Papastamos 		}
4144f8b1914SDimitris Papastamos 
415b5311eedSKuninori Morimoto 		xfer->component = component;
4164f8b1914SDimitris Papastamos 		list_add_tail(&xfer->list, &xfer_list);
4174f8b1914SDimitris Papastamos 
418d4780eecSDimitris Papastamos 		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
4198f7d52afSScott Ling 		if (!out) {
4208f7d52afSScott Ling 			ret = -ENOMEM;
4218f7d52afSScott Ling 			goto abort1;
4228f7d52afSScott Ling 		}
4234f8b1914SDimitris Papastamos 		xfer->t.rx_buf = out;
4248f7d52afSScott Ling 
425d4780eecSDimitris Papastamos 		img = kzalloc(len, GFP_KERNEL | GFP_DMA);
4268f7d52afSScott Ling 		if (!img) {
4278f7d52afSScott Ling 			ret = -ENOMEM;
4288f7d52afSScott Ling 			goto abort1;
4298f7d52afSScott Ling 		}
4304f8b1914SDimitris Papastamos 		xfer->t.tx_buf = img;
4318f7d52afSScott Ling 
4328f7d52afSScott Ling 		byte_swap_64((u64 *)&rec->command, img, len);
4338f7d52afSScott Ling 
4348f7d52afSScott Ling 		spi_message_init(&xfer->m);
4358f7d52afSScott Ling 		xfer->m.complete = wm0010_boot_xfer_complete;
4368f7d52afSScott Ling 		xfer->m.context = xfer;
4378f7d52afSScott Ling 		xfer->t.len = len;
4388f7d52afSScott Ling 		xfer->t.bits_per_word = 8;
4398f7d52afSScott Ling 
4408f7d52afSScott Ling 		if (!wm0010->pll_running) {
4418f7d52afSScott Ling 			xfer->t.speed_hz = wm0010->sysclk / 6;
4428f7d52afSScott Ling 		} else {
4438f7d52afSScott Ling 			xfer->t.speed_hz = wm0010->max_spi_freq;
4448f7d52afSScott Ling 
4458f7d52afSScott Ling 			if (wm0010->board_max_spi_speed &&
4468f7d52afSScott Ling 			   (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
4478f7d52afSScott Ling 					xfer->t.speed_hz = wm0010->board_max_spi_speed;
4488f7d52afSScott Ling 		}
4498f7d52afSScott Ling 
4508f7d52afSScott Ling 		/* Store max usable spi frequency for later use */
4518f7d52afSScott Ling 		wm0010->max_spi_freq = xfer->t.speed_hz;
4528f7d52afSScott Ling 
4538f7d52afSScott Ling 		spi_message_add_tail(&xfer->t, &xfer->m);
4548f7d52afSScott Ling 
4558f7d52afSScott Ling 		offset += ((rec->length) + 8);
4568f7d52afSScott Ling 		rec = (void *)&rec->data[rec->length];
4578f7d52afSScott Ling 
4588f7d52afSScott Ling 		if (offset >= fw->size) {
459b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "All transfers scheduled\n");
4608f7d52afSScott Ling 			xfer->done = &done;
4618f7d52afSScott Ling 		}
4628f7d52afSScott Ling 
4638f7d52afSScott Ling 		ret = spi_async(spi, &xfer->m);
4648f7d52afSScott Ling 		if (ret != 0) {
465b5311eedSKuninori Morimoto 			dev_err(component->dev, "Write failed: %d\n", ret);
4668f7d52afSScott Ling 			goto abort1;
4678f7d52afSScott Ling 		}
4688f7d52afSScott Ling 
4698f7d52afSScott Ling 		if (wm0010->boot_failed) {
470b5311eedSKuninori Morimoto 			dev_dbg(component->dev, "Boot fail!\n");
4718f7d52afSScott Ling 			ret = -EINVAL;
4728f7d52afSScott Ling 			goto abort1;
4738f7d52afSScott Ling 		}
4748f7d52afSScott Ling 	}
4758f7d52afSScott Ling 
4768f7d52afSScott Ling 	wait_for_completion(&done);
4778f7d52afSScott Ling 
4788f7d52afSScott Ling 	ret = 0;
4798f7d52afSScott Ling 
4808f7d52afSScott Ling abort1:
4818f7d52afSScott Ling 	while (!list_empty(&xfer_list)) {
4828f7d52afSScott Ling 		xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
4838f7d52afSScott Ling 					list);
4848f7d52afSScott Ling 		kfree(xfer->t.rx_buf);
4858f7d52afSScott Ling 		kfree(xfer->t.tx_buf);
4868f7d52afSScott Ling 		list_del(&xfer->list);
4878f7d52afSScott Ling 		kfree(xfer);
4888f7d52afSScott Ling 	}
4898f7d52afSScott Ling 
4908f7d52afSScott Ling abort:
4918f7d52afSScott Ling 	release_firmware(fw);
4928f7d52afSScott Ling 	return ret;
4938f7d52afSScott Ling }
4948f7d52afSScott Ling 
wm0010_stage2_load(struct snd_soc_component * component)495b5311eedSKuninori Morimoto static int wm0010_stage2_load(struct snd_soc_component *component)
4963f5475dfSScott Ling {
497b5311eedSKuninori Morimoto 	struct spi_device *spi = to_spi_device(component->dev);
498b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
4993f5475dfSScott Ling 	const struct firmware *fw;
5003f5475dfSScott Ling 	struct spi_message m;
5013f5475dfSScott Ling 	struct spi_transfer t;
5023f5475dfSScott Ling 	u32 *img;
5033f5475dfSScott Ling 	u8 *out;
5043f5475dfSScott Ling 	int i;
5053f5475dfSScott Ling 	int ret = 0;
5063f5475dfSScott Ling 
507b5311eedSKuninori Morimoto 	ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev);
5083f5475dfSScott Ling 	if (ret != 0) {
509b5311eedSKuninori Morimoto 		dev_err(component->dev, "Failed to request stage2 loader: %d\n",
5103f5475dfSScott Ling 			ret);
5113f5475dfSScott Ling 		return ret;
5123f5475dfSScott Ling 	}
5133f5475dfSScott Ling 
514b5311eedSKuninori Morimoto 	dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
5153f5475dfSScott Ling 
5163f5475dfSScott Ling 	/* Copy to local buffer first as vmalloc causes problems for dma */
517c01db8b0SFuqian Huang 	img = kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA);
5183f5475dfSScott Ling 	if (!img) {
5193f5475dfSScott Ling 		ret = -ENOMEM;
5203f5475dfSScott Ling 		goto abort2;
5213f5475dfSScott Ling 	}
5223f5475dfSScott Ling 
523d4780eecSDimitris Papastamos 	out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
5243f5475dfSScott Ling 	if (!out) {
5253f5475dfSScott Ling 		ret = -ENOMEM;
5263f5475dfSScott Ling 		goto abort1;
5273f5475dfSScott Ling 	}
5283f5475dfSScott Ling 
5293f5475dfSScott Ling 	spi_message_init(&m);
5303f5475dfSScott Ling 	memset(&t, 0, sizeof(t));
5313f5475dfSScott Ling 	t.rx_buf = out;
5323f5475dfSScott Ling 	t.tx_buf = img;
5333f5475dfSScott Ling 	t.len = fw->size;
5343f5475dfSScott Ling 	t.bits_per_word = 8;
5353f5475dfSScott Ling 	t.speed_hz = wm0010->sysclk / 10;
5363f5475dfSScott Ling 	spi_message_add_tail(&t, &m);
5373f5475dfSScott Ling 
538b5311eedSKuninori Morimoto 	dev_dbg(component->dev, "Starting initial download at %dHz\n",
5393f5475dfSScott Ling 		t.speed_hz);
5403f5475dfSScott Ling 
5413f5475dfSScott Ling 	ret = spi_sync(spi, &m);
5423f5475dfSScott Ling 	if (ret != 0) {
543b5311eedSKuninori Morimoto 		dev_err(component->dev, "Initial download failed: %d\n", ret);
5443f5475dfSScott Ling 		goto abort;
5453f5475dfSScott Ling 	}
5463f5475dfSScott Ling 
5473f5475dfSScott Ling 	/* Look for errors from the boot ROM */
5483f5475dfSScott Ling 	for (i = 0; i < fw->size; i++) {
5493f5475dfSScott Ling 		if (out[i] != 0x55) {
550b5311eedSKuninori Morimoto 			dev_err(component->dev, "Boot ROM error: %x in %d\n",
5513f5475dfSScott Ling 				out[i], i);
5523f5475dfSScott Ling 			wm0010_mark_boot_failure(wm0010);
5533f5475dfSScott Ling 			ret = -EBUSY;
5543f5475dfSScott Ling 			goto abort;
5553f5475dfSScott Ling 		}
5563f5475dfSScott Ling 	}
5573f5475dfSScott Ling abort:
5583f5475dfSScott Ling 	kfree(out);
5593f5475dfSScott Ling abort1:
5603f5475dfSScott Ling 	kfree(img);
5613f5475dfSScott Ling abort2:
5623f5475dfSScott Ling 	release_firmware(fw);
5633f5475dfSScott Ling 
5643f5475dfSScott Ling 	return ret;
5653f5475dfSScott Ling }
5663f5475dfSScott Ling 
wm0010_boot(struct snd_soc_component * component)567b5311eedSKuninori Morimoto static int wm0010_boot(struct snd_soc_component *component)
5688f7d52afSScott Ling {
569b5311eedSKuninori Morimoto 	struct spi_device *spi = to_spi_device(component->dev);
570b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
5718f7d52afSScott Ling 	unsigned long flags;
5728f7d52afSScott Ling 	int ret;
573e3523e01SDimitris Papastamos 	struct spi_message m;
574e3523e01SDimitris Papastamos 	struct spi_transfer t;
575e3523e01SDimitris Papastamos 	struct dfw_pllrec pll_rec;
5763f5475dfSScott Ling 	u32 *p, len;
577e3523e01SDimitris Papastamos 	u64 *img_swap;
578e3523e01SDimitris Papastamos 	u8 *out;
579e3523e01SDimitris Papastamos 	int i;
580e3523e01SDimitris Papastamos 
581e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
582e3523e01SDimitris Papastamos 	if (wm0010->state != WM0010_POWER_OFF)
583e3523e01SDimitris Papastamos 		dev_warn(wm0010->dev, "DSP already powered up!\n");
584e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
585e3523e01SDimitris Papastamos 
586e3523e01SDimitris Papastamos 	if (wm0010->sysclk > 26000000) {
587b5311eedSKuninori Morimoto 		dev_err(component->dev, "Max DSP clock frequency is 26MHz\n");
588e3523e01SDimitris Papastamos 		ret = -ECANCELED;
589e3523e01SDimitris Papastamos 		goto err;
590e3523e01SDimitris Papastamos 	}
591e3523e01SDimitris Papastamos 
592e3523e01SDimitris Papastamos 	mutex_lock(&wm0010->lock);
593e3523e01SDimitris Papastamos 	wm0010->pll_running = false;
594e3523e01SDimitris Papastamos 
595b5311eedSKuninori Morimoto 	dev_dbg(component->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
596e3523e01SDimitris Papastamos 
597e3523e01SDimitris Papastamos 	ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
598e3523e01SDimitris Papastamos 				    wm0010->core_supplies);
599e3523e01SDimitris Papastamos 	if (ret != 0) {
600e3523e01SDimitris Papastamos 		dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
601e3523e01SDimitris Papastamos 			ret);
602e3523e01SDimitris Papastamos 		mutex_unlock(&wm0010->lock);
603e3523e01SDimitris Papastamos 		goto err;
604e3523e01SDimitris Papastamos 	}
605e3523e01SDimitris Papastamos 
606e3523e01SDimitris Papastamos 	ret = regulator_enable(wm0010->dbvdd);
607e3523e01SDimitris Papastamos 	if (ret != 0) {
608e3523e01SDimitris Papastamos 		dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
609e3523e01SDimitris Papastamos 		goto err_core;
610e3523e01SDimitris Papastamos 	}
611e3523e01SDimitris Papastamos 
612e3523e01SDimitris Papastamos 	/* Release reset */
613fff00cbcSMark Brown 	gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
614e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
615e3523e01SDimitris Papastamos 	wm0010->state = WM0010_OUT_OF_RESET;
616e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
617e3523e01SDimitris Papastamos 
618e3523e01SDimitris Papastamos 	if (!wait_for_completion_timeout(&wm0010->boot_completion,
619631fcab2SDimitris Papastamos 					 msecs_to_jiffies(20)))
620b5311eedSKuninori Morimoto 		dev_err(component->dev, "Failed to get interrupt from DSP\n");
621e3523e01SDimitris Papastamos 
622e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
623e3523e01SDimitris Papastamos 	wm0010->state = WM0010_BOOTROM;
624e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
625e3523e01SDimitris Papastamos 
626b5311eedSKuninori Morimoto 	ret = wm0010_stage2_load(component);
6273f5475dfSScott Ling 	if (ret)
628e3523e01SDimitris Papastamos 		goto abort;
629e3523e01SDimitris Papastamos 
630e3523e01SDimitris Papastamos 	if (!wait_for_completion_timeout(&wm0010->boot_completion,
631631fcab2SDimitris Papastamos 					 msecs_to_jiffies(20)))
632b5311eedSKuninori Morimoto 		dev_err(component->dev, "Failed to get interrupt from DSP loader.\n");
633e3523e01SDimitris Papastamos 
634e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
635e3523e01SDimitris Papastamos 	wm0010->state = WM0010_STAGE2;
636e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
637e3523e01SDimitris Papastamos 
638e3523e01SDimitris Papastamos 	/* Only initialise PLL if max_spi_freq initialised */
639e3523e01SDimitris Papastamos 	if (wm0010->max_spi_freq) {
640e3523e01SDimitris Papastamos 
641e3523e01SDimitris Papastamos 		/* Initialise a PLL record */
642e3523e01SDimitris Papastamos 		memset(&pll_rec, 0, sizeof(pll_rec));
643e3523e01SDimitris Papastamos 		pll_rec.command = DFW_CMD_PLL;
644e3523e01SDimitris Papastamos 		pll_rec.length = (sizeof(pll_rec) - 8);
645e3523e01SDimitris Papastamos 
646e3523e01SDimitris Papastamos 		/* On wm0010 only the CLKCTRL1 value is used */
647e3523e01SDimitris Papastamos 		pll_rec.clkctrl1 = wm0010->pll_clkctrl1;
648e3523e01SDimitris Papastamos 
6492e0192f1SWei Yongjun 		ret = -ENOMEM;
650e3523e01SDimitris Papastamos 		len = pll_rec.length + 8;
651d4780eecSDimitris Papastamos 		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
652316c85c3SMarkus Elfring 		if (!out)
653e3523e01SDimitris Papastamos 			goto abort;
654e3523e01SDimitris Papastamos 
655d4780eecSDimitris Papastamos 		img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA);
65684cbc75fSSachin Kamat 		if (!img_swap)
657f072f91aSSudip Mukherjee 			goto abort_out;
658e3523e01SDimitris Papastamos 
659e3523e01SDimitris Papastamos 		/* We need to re-order for 0010 */
660e3523e01SDimitris Papastamos 		byte_swap_64((u64 *)&pll_rec, img_swap, len);
661e3523e01SDimitris Papastamos 
662e3523e01SDimitris Papastamos 		spi_message_init(&m);
663e3523e01SDimitris Papastamos 		memset(&t, 0, sizeof(t));
664e3523e01SDimitris Papastamos 		t.rx_buf = out;
665e3523e01SDimitris Papastamos 		t.tx_buf = img_swap;
666e3523e01SDimitris Papastamos 		t.len = len;
667e3523e01SDimitris Papastamos 		t.bits_per_word = 8;
668e3523e01SDimitris Papastamos 		t.speed_hz = wm0010->sysclk / 6;
669e3523e01SDimitris Papastamos 		spi_message_add_tail(&t, &m);
670e3523e01SDimitris Papastamos 
671e3523e01SDimitris Papastamos 		ret = spi_sync(spi, &m);
672f072f91aSSudip Mukherjee 		if (ret) {
673b5311eedSKuninori Morimoto 			dev_err(component->dev, "First PLL write failed: %d\n", ret);
674f072f91aSSudip Mukherjee 			goto abort_swap;
675e3523e01SDimitris Papastamos 		}
676e3523e01SDimitris Papastamos 
677e3523e01SDimitris Papastamos 		/* Use a second send of the message to get the return status */
678e3523e01SDimitris Papastamos 		ret = spi_sync(spi, &m);
679f072f91aSSudip Mukherjee 		if (ret) {
680b5311eedSKuninori Morimoto 			dev_err(component->dev, "Second PLL write failed: %d\n", ret);
681f072f91aSSudip Mukherjee 			goto abort_swap;
682e3523e01SDimitris Papastamos 		}
683e3523e01SDimitris Papastamos 
684e3523e01SDimitris Papastamos 		p = (u32 *)out;
685e3523e01SDimitris Papastamos 
686e3523e01SDimitris Papastamos 		/* Look for PLL active code from the DSP */
687e3523e01SDimitris Papastamos 		for (i = 0; i < len / 4; i++) {
688e3523e01SDimitris Papastamos 			if (*p == 0x0e00ed0f) {
689b5311eedSKuninori Morimoto 				dev_dbg(component->dev, "PLL packet received\n");
690e3523e01SDimitris Papastamos 				wm0010->pll_running = true;
691e3523e01SDimitris Papastamos 				break;
692e3523e01SDimitris Papastamos 			}
693e3523e01SDimitris Papastamos 			p++;
694e3523e01SDimitris Papastamos 		}
695e3523e01SDimitris Papastamos 
696e3523e01SDimitris Papastamos 		kfree(img_swap);
697e3523e01SDimitris Papastamos 		kfree(out);
698e3523e01SDimitris Papastamos 	} else
699b5311eedSKuninori Morimoto 		dev_dbg(component->dev, "Not enabling DSP PLL.");
700e3523e01SDimitris Papastamos 
701b5311eedSKuninori Morimoto 	ret = wm0010_firmware_load("wm0010.dfw", component);
7028f7d52afSScott Ling 
7038f7d52afSScott Ling 	if (ret != 0)
704e3523e01SDimitris Papastamos 		goto abort;
705e3523e01SDimitris Papastamos 
706e3523e01SDimitris Papastamos 	spin_lock_irqsave(&wm0010->irq_lock, flags);
707e3523e01SDimitris Papastamos 	wm0010->state = WM0010_FIRMWARE;
708e3523e01SDimitris Papastamos 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
709e3523e01SDimitris Papastamos 
710e3523e01SDimitris Papastamos 	mutex_unlock(&wm0010->lock);
711e3523e01SDimitris Papastamos 
712e3523e01SDimitris Papastamos 	return 0;
713e3523e01SDimitris Papastamos 
714f072f91aSSudip Mukherjee abort_swap:
715f072f91aSSudip Mukherjee 	kfree(img_swap);
716f072f91aSSudip Mukherjee abort_out:
717f072f91aSSudip Mukherjee 	kfree(out);
718e3523e01SDimitris Papastamos abort:
719e3523e01SDimitris Papastamos 	/* Put the chip back into reset */
720b5311eedSKuninori Morimoto 	wm0010_halt(component);
721e3523e01SDimitris Papastamos 	mutex_unlock(&wm0010->lock);
722e3523e01SDimitris Papastamos 	return ret;
7234f3ad795SDan Carpenter 
724e3523e01SDimitris Papastamos err_core:
7254f3ad795SDan Carpenter 	mutex_unlock(&wm0010->lock);
726e3523e01SDimitris Papastamos 	regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
727e3523e01SDimitris Papastamos 			       wm0010->core_supplies);
728e3523e01SDimitris Papastamos err:
729e3523e01SDimitris Papastamos 	return ret;
730e3523e01SDimitris Papastamos }
731e3523e01SDimitris Papastamos 
wm0010_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)732b5311eedSKuninori Morimoto static int wm0010_set_bias_level(struct snd_soc_component *component,
733e3523e01SDimitris Papastamos 				 enum snd_soc_bias_level level)
734e3523e01SDimitris Papastamos {
735b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
736e3523e01SDimitris Papastamos 
737e3523e01SDimitris Papastamos 	switch (level) {
738e3523e01SDimitris Papastamos 	case SND_SOC_BIAS_ON:
739b5311eedSKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE)
740b5311eedSKuninori Morimoto 			wm0010_boot(component);
741e3523e01SDimitris Papastamos 		break;
742e3523e01SDimitris Papastamos 	case SND_SOC_BIAS_PREPARE:
743e3523e01SDimitris Papastamos 		break;
744e3523e01SDimitris Papastamos 	case SND_SOC_BIAS_STANDBY:
745b5311eedSKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_PREPARE) {
746e3523e01SDimitris Papastamos 			mutex_lock(&wm0010->lock);
747b5311eedSKuninori Morimoto 			wm0010_halt(component);
748e3523e01SDimitris Papastamos 			mutex_unlock(&wm0010->lock);
749e3523e01SDimitris Papastamos 		}
750e3523e01SDimitris Papastamos 		break;
751e3523e01SDimitris Papastamos 	case SND_SOC_BIAS_OFF:
752e3523e01SDimitris Papastamos 		break;
753e3523e01SDimitris Papastamos 	}
754e3523e01SDimitris Papastamos 
755e3523e01SDimitris Papastamos 	return 0;
756e3523e01SDimitris Papastamos }
757e3523e01SDimitris Papastamos 
wm0010_set_sysclk(struct snd_soc_component * component,int source,int clk_id,unsigned int freq,int dir)758b5311eedSKuninori Morimoto static int wm0010_set_sysclk(struct snd_soc_component *component, int source,
759e3523e01SDimitris Papastamos 			     int clk_id, unsigned int freq, int dir)
760e3523e01SDimitris Papastamos {
761b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
762e3523e01SDimitris Papastamos 	unsigned int i;
763e3523e01SDimitris Papastamos 
764e3523e01SDimitris Papastamos 	wm0010->sysclk = freq;
765e3523e01SDimitris Papastamos 
766e3523e01SDimitris Papastamos 	if (freq < pll_clock_map[ARRAY_SIZE(pll_clock_map)-1].max_sysclk) {
767e3523e01SDimitris Papastamos 		wm0010->max_spi_freq = 0;
768e3523e01SDimitris Papastamos 	} else {
769e3523e01SDimitris Papastamos 		for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++)
770c36c8909STakashi Iwai 			if (freq >= pll_clock_map[i].max_sysclk) {
771e3523e01SDimitris Papastamos 				wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
772e3523e01SDimitris Papastamos 				wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
773c36c8909STakashi Iwai 				break;
774c36c8909STakashi Iwai 			}
775e3523e01SDimitris Papastamos 	}
776e3523e01SDimitris Papastamos 
777e3523e01SDimitris Papastamos 	return 0;
778e3523e01SDimitris Papastamos }
779e3523e01SDimitris Papastamos 
780b5311eedSKuninori Morimoto static int wm0010_probe(struct snd_soc_component *component);
781e3523e01SDimitris Papastamos 
782b5311eedSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm0010 = {
783e3523e01SDimitris Papastamos 	.probe			= wm0010_probe,
784e3523e01SDimitris Papastamos 	.set_bias_level		= wm0010_set_bias_level,
785e3523e01SDimitris Papastamos 	.set_sysclk		= wm0010_set_sysclk,
7861470bfacSMark Brown 	.dapm_widgets		= wm0010_dapm_widgets,
7871470bfacSMark Brown 	.num_dapm_widgets	= ARRAY_SIZE(wm0010_dapm_widgets),
788e3523e01SDimitris Papastamos 	.dapm_routes		= wm0010_dapm_routes,
789e3523e01SDimitris Papastamos 	.num_dapm_routes	= ARRAY_SIZE(wm0010_dapm_routes),
790b5311eedSKuninori Morimoto 	.use_pmdown_time	= 1,
791b5311eedSKuninori Morimoto 	.endianness		= 1,
792e3523e01SDimitris Papastamos };
793e3523e01SDimitris Papastamos 
7946df31986SMark Brown #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
795e3523e01SDimitris Papastamos #define WM0010_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
796e3523e01SDimitris Papastamos 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
797e3523e01SDimitris Papastamos 			SNDRV_PCM_FMTBIT_S32_LE)
798e3523e01SDimitris Papastamos 
799e3523e01SDimitris Papastamos static struct snd_soc_dai_driver wm0010_dai[] = {
800e3523e01SDimitris Papastamos 	{
801e3523e01SDimitris Papastamos 		.name = "wm0010-sdi1",
802e3523e01SDimitris Papastamos 		.playback = {
803e3523e01SDimitris Papastamos 			.stream_name = "SDI1 Playback",
804e3523e01SDimitris Papastamos 			.channels_min = 1,
805e3523e01SDimitris Papastamos 			.channels_max = 2,
806e3523e01SDimitris Papastamos 			.rates = WM0010_RATES,
807e3523e01SDimitris Papastamos 			.formats = WM0010_FORMATS,
808e3523e01SDimitris Papastamos 		},
809e3523e01SDimitris Papastamos 		.capture = {
810e3523e01SDimitris Papastamos 			 .stream_name = "SDI1 Capture",
811e3523e01SDimitris Papastamos 			 .channels_min = 1,
812e3523e01SDimitris Papastamos 			 .channels_max = 2,
813e3523e01SDimitris Papastamos 			 .rates = WM0010_RATES,
814e3523e01SDimitris Papastamos 			 .formats = WM0010_FORMATS,
815e3523e01SDimitris Papastamos 		 },
816e3523e01SDimitris Papastamos 	},
817e3523e01SDimitris Papastamos 	{
818e3523e01SDimitris Papastamos 		.name = "wm0010-sdi2",
819e3523e01SDimitris Papastamos 		.playback = {
820e3523e01SDimitris Papastamos 			.stream_name = "SDI2 Playback",
821e3523e01SDimitris Papastamos 			.channels_min = 1,
822e3523e01SDimitris Papastamos 			.channels_max = 2,
823e3523e01SDimitris Papastamos 			.rates = WM0010_RATES,
824e3523e01SDimitris Papastamos 			.formats = WM0010_FORMATS,
825e3523e01SDimitris Papastamos 		},
826e3523e01SDimitris Papastamos 		.capture = {
827e3523e01SDimitris Papastamos 			 .stream_name = "SDI2 Capture",
828e3523e01SDimitris Papastamos 			 .channels_min = 1,
829e3523e01SDimitris Papastamos 			 .channels_max = 2,
830e3523e01SDimitris Papastamos 			 .rates = WM0010_RATES,
831e3523e01SDimitris Papastamos 			 .formats = WM0010_FORMATS,
832e3523e01SDimitris Papastamos 		 },
833e3523e01SDimitris Papastamos 	},
834e3523e01SDimitris Papastamos };
835e3523e01SDimitris Papastamos 
wm0010_irq(int irq,void * data)836e3523e01SDimitris Papastamos static irqreturn_t wm0010_irq(int irq, void *data)
837e3523e01SDimitris Papastamos {
838e3523e01SDimitris Papastamos 	struct wm0010_priv *wm0010 = data;
839e3523e01SDimitris Papastamos 
840e3523e01SDimitris Papastamos 	switch (wm0010->state) {
841e3523e01SDimitris Papastamos 	case WM0010_OUT_OF_RESET:
842e3523e01SDimitris Papastamos 	case WM0010_BOOTROM:
843e3523e01SDimitris Papastamos 	case WM0010_STAGE2:
844e3523e01SDimitris Papastamos 		spin_lock(&wm0010->irq_lock);
845e3523e01SDimitris Papastamos 		complete(&wm0010->boot_completion);
846e3523e01SDimitris Papastamos 		spin_unlock(&wm0010->irq_lock);
847e3523e01SDimitris Papastamos 		return IRQ_HANDLED;
848e3523e01SDimitris Papastamos 	default:
849e3523e01SDimitris Papastamos 		return IRQ_NONE;
850e3523e01SDimitris Papastamos 	}
851e3523e01SDimitris Papastamos 
852e3523e01SDimitris Papastamos 	return IRQ_NONE;
853e3523e01SDimitris Papastamos }
854e3523e01SDimitris Papastamos 
wm0010_probe(struct snd_soc_component * component)855b5311eedSKuninori Morimoto static int wm0010_probe(struct snd_soc_component *component)
856e3523e01SDimitris Papastamos {
857b5311eedSKuninori Morimoto 	struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
85832c50a31SMark Brown 
859b5311eedSKuninori Morimoto 	wm0010->component = component;
86032c50a31SMark Brown 
86132c50a31SMark Brown 	return 0;
86232c50a31SMark Brown }
86332c50a31SMark Brown 
wm0010_spi_probe(struct spi_device * spi)8647a79e94eSBill Pemberton static int wm0010_spi_probe(struct spi_device *spi)
86532c50a31SMark Brown {
866e3523e01SDimitris Papastamos 	unsigned long gpio_flags;
867e3523e01SDimitris Papastamos 	int ret;
868e3523e01SDimitris Papastamos 	int trigger;
869e3523e01SDimitris Papastamos 	int irq;
87032c50a31SMark Brown 	struct wm0010_priv *wm0010;
871e3523e01SDimitris Papastamos 
87232c50a31SMark Brown 	wm0010 = devm_kzalloc(&spi->dev, sizeof(*wm0010),
87332c50a31SMark Brown 			      GFP_KERNEL);
87432c50a31SMark Brown 	if (!wm0010)
87532c50a31SMark Brown 		return -ENOMEM;
87632c50a31SMark Brown 
87732c50a31SMark Brown 	mutex_init(&wm0010->lock);
87832c50a31SMark Brown 	spin_lock_init(&wm0010->irq_lock);
87932c50a31SMark Brown 
88032c50a31SMark Brown 	spi_set_drvdata(spi, wm0010);
88132c50a31SMark Brown 	wm0010->dev = &spi->dev;
88232c50a31SMark Brown 
88332c50a31SMark Brown 	if (dev_get_platdata(&spi->dev))
88432c50a31SMark Brown 		memcpy(&wm0010->pdata, dev_get_platdata(&spi->dev),
88532c50a31SMark Brown 		       sizeof(wm0010->pdata));
886e3523e01SDimitris Papastamos 
887e3523e01SDimitris Papastamos 	init_completion(&wm0010->boot_completion);
888e3523e01SDimitris Papastamos 
889e3523e01SDimitris Papastamos 	wm0010->core_supplies[0].supply = "AVDD";
890e3523e01SDimitris Papastamos 	wm0010->core_supplies[1].supply = "DCVDD";
891e3523e01SDimitris Papastamos 	ret = devm_regulator_bulk_get(wm0010->dev, ARRAY_SIZE(wm0010->core_supplies),
892e3523e01SDimitris Papastamos 				      wm0010->core_supplies);
893e3523e01SDimitris Papastamos 	if (ret != 0) {
894e3523e01SDimitris Papastamos 		dev_err(wm0010->dev, "Failed to obtain core supplies: %d\n",
895e3523e01SDimitris Papastamos 			ret);
896e3523e01SDimitris Papastamos 		return ret;
897e3523e01SDimitris Papastamos 	}
898e3523e01SDimitris Papastamos 
899e3523e01SDimitris Papastamos 	wm0010->dbvdd = devm_regulator_get(wm0010->dev, "DBVDD");
900e3523e01SDimitris Papastamos 	if (IS_ERR(wm0010->dbvdd)) {
901e3523e01SDimitris Papastamos 		ret = PTR_ERR(wm0010->dbvdd);
902e3523e01SDimitris Papastamos 		dev_err(wm0010->dev, "Failed to obtain DBVDD: %d\n", ret);
903e3523e01SDimitris Papastamos 		return ret;
904e3523e01SDimitris Papastamos 	}
905e3523e01SDimitris Papastamos 
906e3523e01SDimitris Papastamos 	if (wm0010->pdata.gpio_reset) {
907e3523e01SDimitris Papastamos 		wm0010->gpio_reset = wm0010->pdata.gpio_reset;
908e3523e01SDimitris Papastamos 
909e3523e01SDimitris Papastamos 		if (wm0010->pdata.reset_active_high)
910e3523e01SDimitris Papastamos 			wm0010->gpio_reset_value = 1;
911e3523e01SDimitris Papastamos 		else
912e3523e01SDimitris Papastamos 			wm0010->gpio_reset_value = 0;
913e3523e01SDimitris Papastamos 
914e3523e01SDimitris Papastamos 		if (wm0010->gpio_reset_value)
915e3523e01SDimitris Papastamos 			gpio_flags = GPIOF_OUT_INIT_HIGH;
916e3523e01SDimitris Papastamos 		else
917e3523e01SDimitris Papastamos 			gpio_flags = GPIOF_OUT_INIT_LOW;
918e3523e01SDimitris Papastamos 
919e3523e01SDimitris Papastamos 		ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset,
920e3523e01SDimitris Papastamos 					    gpio_flags, "wm0010 reset");
921e3523e01SDimitris Papastamos 		if (ret < 0) {
922e3523e01SDimitris Papastamos 			dev_err(wm0010->dev,
923e3523e01SDimitris Papastamos 				"Failed to request GPIO for DSP reset: %d\n",
924e3523e01SDimitris Papastamos 				ret);
925e3523e01SDimitris Papastamos 			return ret;
926e3523e01SDimitris Papastamos 		}
927e3523e01SDimitris Papastamos 	} else {
928e3523e01SDimitris Papastamos 		dev_err(wm0010->dev, "No reset GPIO configured\n");
92932c50a31SMark Brown 		return -EINVAL;
930e3523e01SDimitris Papastamos 	}
931e3523e01SDimitris Papastamos 
9329bb68444SMark Brown 	wm0010->state = WM0010_POWER_OFF;
9339bb68444SMark Brown 
934e3523e01SDimitris Papastamos 	irq = spi->irq;
935e3523e01SDimitris Papastamos 	if (wm0010->pdata.irq_flags)
936e3523e01SDimitris Papastamos 		trigger = wm0010->pdata.irq_flags;
937e3523e01SDimitris Papastamos 	else
938e3523e01SDimitris Papastamos 		trigger = IRQF_TRIGGER_FALLING;
939e3523e01SDimitris Papastamos 	trigger |= IRQF_ONESHOT;
940e3523e01SDimitris Papastamos 
941030e6ee2SAxel Lin 	ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger,
942e3523e01SDimitris Papastamos 				   "wm0010", wm0010);
94332c50a31SMark Brown 	if (ret) {
944e3523e01SDimitris Papastamos 		dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
945e3523e01SDimitris Papastamos 			irq, ret);
94632c50a31SMark Brown 		return ret;
94732c50a31SMark Brown 	}
948e3523e01SDimitris Papastamos 	wm0010->irq = irq;
949e3523e01SDimitris Papastamos 
950e684533bSCharles Keepax 	ret = irq_set_irq_wake(irq, 1);
951e684533bSCharles Keepax 	if (ret) {
952e684533bSCharles Keepax 		dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
953e684533bSCharles Keepax 			irq, ret);
954*a7025944SChristophe JAILLET 		goto free_irq;
955e684533bSCharles Keepax 	}
956e684533bSCharles Keepax 
957e3523e01SDimitris Papastamos 	if (spi->max_speed_hz)
958e3523e01SDimitris Papastamos 		wm0010->board_max_spi_speed = spi->max_speed_hz;
959e3523e01SDimitris Papastamos 	else
960e3523e01SDimitris Papastamos 		wm0010->board_max_spi_speed = 0;
961e3523e01SDimitris Papastamos 
962b5311eedSKuninori Morimoto 	ret = devm_snd_soc_register_component(&spi->dev,
963b5311eedSKuninori Morimoto 				     &soc_component_dev_wm0010, wm0010_dai,
964e3523e01SDimitris Papastamos 				     ARRAY_SIZE(wm0010_dai));
965e3523e01SDimitris Papastamos 	if (ret < 0)
966*a7025944SChristophe JAILLET 		goto disable_irq_wake;
967e3523e01SDimitris Papastamos 
968e3523e01SDimitris Papastamos 	return 0;
969*a7025944SChristophe JAILLET 
970*a7025944SChristophe JAILLET disable_irq_wake:
971*a7025944SChristophe JAILLET 	irq_set_irq_wake(wm0010->irq, 0);
972*a7025944SChristophe JAILLET 
973*a7025944SChristophe JAILLET free_irq:
974*a7025944SChristophe JAILLET 	if (wm0010->irq)
975*a7025944SChristophe JAILLET 		free_irq(wm0010->irq, wm0010);
976*a7025944SChristophe JAILLET 
977*a7025944SChristophe JAILLET 	return ret;
978e3523e01SDimitris Papastamos }
979e3523e01SDimitris Papastamos 
980a0386bbaSUwe Kleine-König static void wm0010_spi_remove(struct spi_device *spi)
981e3523e01SDimitris Papastamos {
982e3523e01SDimitris Papastamos 	struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
983e3523e01SDimitris Papastamos 
984fff00cbcSMark Brown 	gpio_set_value_cansleep(wm0010->gpio_reset,
985fff00cbcSMark Brown 				wm0010->gpio_reset_value);
986e3523e01SDimitris Papastamos 
987fd8b9657SCharles Keepax 	irq_set_irq_wake(wm0010->irq, 0);
988fd8b9657SCharles Keepax 
989e3523e01SDimitris Papastamos 	if (wm0010->irq)
990e3523e01SDimitris Papastamos 		free_irq(wm0010->irq, wm0010);
991e3523e01SDimitris Papastamos }
992e3523e01SDimitris Papastamos 
993e3523e01SDimitris Papastamos static struct spi_driver wm0010_spi_driver = {
994e3523e01SDimitris Papastamos 	.driver = {
995e3523e01SDimitris Papastamos 		.name	= "wm0010",
996e3523e01SDimitris Papastamos 	},
997e3523e01SDimitris Papastamos 	.probe		= wm0010_spi_probe,
9987a79e94eSBill Pemberton 	.remove		= wm0010_spi_remove,
999e3523e01SDimitris Papastamos };
1000e3523e01SDimitris Papastamos 
1001e3523e01SDimitris Papastamos module_spi_driver(wm0010_spi_driver);
1002e3523e01SDimitris Papastamos 
1003e3523e01SDimitris Papastamos MODULE_DESCRIPTION("ASoC WM0010 driver");
1004e3523e01SDimitris Papastamos MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1005e3523e01SDimitris Papastamos MODULE_LICENSE("GPL");
100660e07fa4SJuerg Haefliger 
100760e07fa4SJuerg Haefliger MODULE_FIRMWARE("wm0010.dfw");
100860e07fa4SJuerg Haefliger MODULE_FIRMWARE("wm0010_stage2.bin");
1009