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